~canonical-dx-team/ubuntu/maverick/gtk+2.0/menuproxy

« back to all changes in this revision

Viewing changes to docs/tutorial/gtk-tut.sgml

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-05-04 12:24:25 UTC
  • mfrom: (1.1.21 upstream)
  • Revision ID: james.westby@ubuntu.com-20070504122425-0m8midgzrp40y8w2
Tags: 2.10.12-1ubuntu1
* Sync with Debian
* New upstream version:
  Fixed bugs:
  - 379414 file chooser warnings when changing path in the entry
  - 418585 GtkFileChooserDefault sizing code is not DPI independent
  - 419568 Crash in search if start with special letter
  - 435062 build dies with icon cache validation
  - 379399 Segfault to call gtk_print_operation_run twice.
  - 387889 cups backend has problems when there are too many printers
  - 418531 invalid read to gtkicontheme.c gtk_icon_theme_lookup_icon...
  - 423916 crash in color scheme code
  - 424042 Segmentation fault while quickly pressing Alt+arrows
  - 415260 Protect against negative indices when setting values in G...
  - 419171 XGetVisualInfo() may not set nxvisuals
  - 128852 Gdk cursors don't look good on win32
  - 344657 Ctrl-H doesn't toggle "Show Hidden Files" setting
  - 345345 PrintOperation::paginate is not emitted for class handler
  - 347567 GtkPrintOperation::end-print is not emitted if it's cance...
  - 369112 gtk_ui_manager_add_ui should accept unnamed separator
  - 392015 Selected menu item invisible on Windows Vista
  - 399253 MS-Windows Theme Bottom Tab placement rendering glitches
  - 399425 gtk_input_dialog_fill_axes() adds child to gtkscrolledwin...
  - 403251 [patch] little memory leak in GtkPrintJob
  - 403267 [patch] memory leak in GtkPageSetupUnixDialog
  - 403470 MS-Windows Theme tab placement other than on top leaks a ...
  - 404506 Windows system fonts that have multi-byte font names cann...
  - 405089 Incorrect window placement for GtkEventBox private window
  - 405515 Minor leak in gtkfilesystemmodel.c
  - 405539 gdk_pixbuf_save() for PNG saver can return FALSE without ...
  - 415681 gdk_window_clear_area includes an extra line and column o...
  - 418219 GtkRecentChooser should apply filter before sorting and c...
  - 418403 Scroll to printer after selecting it from settings
  - 421985 _gtk_print_operation_platform_backend_launch_preview
  - 421990 gtk_print_job_get_surface
  - 421993 gtk_print_operation_init
  - 423064 Conditional jump or move depends on uninitialised value(s...
  - 423722 Fix printing header in gtk-demo
  - 424168 gtk_print_operation_run on async preview
  - 425655 Don't install gtk+-unix-print-2.0.pc on non-UNIX platforms
  - 425786 GDK segfaults if XineramaQueryScreens fails
  - 428665 Lpr Backend gets stuck in infinite loop during gtk_enumer...
  - 429902 GtkPrintOperation leaks cairo contextes
  - 431997 First delay of GdkPixbufAnimationIter is wrong
  - 433242 Inconsistent scroll arrow position calculations
  - 433972 Placing gtk.Expander inside a gtk.TextView() changes gtk....
  - 434261 _gtk_toolbar_elide_underscores incorrectly handles some s...
  - 383354 ctrl-L should make 'Location' entry disappear
  - 418673 gtk_recent_manager_add_item
  - 429732 gtk_accel_group_finalize accesses invalid memory
  - 435028 WM_CLIENT_LEADER is wrong on the leader_window
  - 431067 Background of the header window is not updated
  - 338843 add recent files support inside the ui manager
  - 148535 add drop shadow to menus, tooltips, etc. under Windows XP
* debian/control.in:
  - Conflicts on ubuntulooks (<= 0.9.11-1)
* debian/patches/15_default-fallback-icon-theme.patch:
  - patch from Debian, fallback on gnome icon theme

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!doctype book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
 
2
<!notation PNG system "PNG">
 
3
<!entity % local.notation.class "| PNG">
 
4
]>
 
5
<book id="gtk-tut">
 
6
 
 
7
<bookinfo>
 
8
    <date>January 24th, 2003</date>
 
9
    <title>GTK+ 2.0 Tutorial</title>
 
10
    <authorgroup>
 
11
      <author>
 
12
        <firstname>Tony</firstname>
 
13
        <surname>Gale</surname>
 
14
      </author>
 
15
      <author>
 
16
        <firstname>Ian</firstname>
 
17
        <surname>Main</surname>
 
18
      </author>
 
19
      <author>
 
20
        <firstname>&amp; the GTK team</firstname>
 
21
      </author>
 
22
    </authorgroup>
 
23
    <abstract>
 
24
      <para>This is a tutorial on how to use GTK (the GIMP Toolkit) through its C
 
25
            interface.</para>
 
26
    </abstract>
 
27
  </bookinfo>
 
28
 
 
29
<toc></toc>
 
30
 
 
31
<!-- ***************************************************************** -->
 
32
<chapter id="ch-TutorialDownload">
 
33
<title>Tutorial Availability</title>
 
34
 
 
35
<para>A copy of this tutorial in SGML and HTML is distributed with each
 
36
source code release of GTK+. For binary distributions, please check with
 
37
your vendor.</para>
 
38
 
 
39
<para>A copy is available online for reference at <ulink 
 
40
url="http://www.gtk.org/tutorial/">http://www.gtk.org/tutorial</ulink>.</para>
 
41
 
 
42
<para>A packaged verion of this tutorial is available from
 
43
<ulink url="ftp://ftp.gtk.org/pub/gtk/tutorial/">
 
44
ftp://ftp.gtk.org/pub/gtk/tutorial</ulink> which contains the tutorial in
 
45
various different formats. This
 
46
package is primary for those people wanting to have the tutorial
 
47
available for offline reference and for printing.</para>
 
48
 
 
49
</chapter>
 
50
 
 
51
<!-- ***************************************************************** -->
 
52
<chapter id="ch-Introduction">
 
53
<title>Introduction</title>
 
54
 
 
55
<para>GTK (GIMP Toolkit) is a library for creating graphical user
 
56
interfaces. It is licensed using the LGPL license, so you can develop
 
57
open software, free software, or even commercial non-free software
 
58
using GTK without having to spend anything for licenses or royalties.</para>
 
59
 
 
60
<para>It's called the GIMP toolkit because it was originally written for
 
61
developing the GNU Image Manipulation Program (GIMP), but GTK has
 
62
now been used in a large number of software projects, including the
 
63
GNU Network Object Model Environment (GNOME) project. GTK is built on
 
64
top of GDK (GIMP Drawing Kit) which is basically a wrapper around the
 
65
low-level functions for accessing the underlying windowing functions
 
66
(Xlib in the case of the X windows system), and gdk-pixbuf, a library for
 
67
client-side image manipulation.</para>
 
68
 
 
69
<para>GTK is essentially an object oriented application programmers
 
70
interface (API). Although written completely in C, it is implemented
 
71
using the idea of classes and callback functions (pointers to
 
72
functions).</para>
 
73
 
 
74
<para>There is also a third component called GLib which contains a few
 
75
replacements for some standard calls, as well as some additional
 
76
functions for handling linked lists, etc. The replacement functions
 
77
are used to increase GTK's portability, as some of the functions
 
78
implemented here are not available or are nonstandard on other Unixes
 
79
such as g_strerror(). Some also contain enhancements to the libc
 
80
versions, such as g_malloc() that has enhanced debugging utilities.</para>
 
81
 
 
82
<para>In version 2.0, GLib has picked up the type system which forms the
 
83
foundation for GTK's class hierarchy, the signal system which is used
 
84
throughout GTK, a thread API which abstracts the different native thread APIs 
 
85
of the various platforms and a facility for loading modules.
 
86
</para>
 
87
 
 
88
<para>As the last component, GTK uses the Pango library for internationalized
 
89
text output.
 
90
</para>
 
91
 
 
92
<para>This tutorial describes the C interface to GTK. There are GTK
 
93
bindings for many other languages including C++, Guile, Perl, Python,
 
94
TOM, Ada95, Objective C, Free Pascal, Eiffel, Java and C#. If you intend to
 
95
use another language's bindings to GTK, look at that binding's
 
96
documentation first. In some cases that documentation may describe
 
97
some important conventions (which you should know first) and then
 
98
refer you back to this tutorial. There are also some cross-platform
 
99
APIs (such as wxWindows and V) which use GTK as one of their target
 
100
platforms; again, consult their documentation first.</para>
 
101
 
 
102
<para>If you're developing your GTK application in C++, a few extra notes
 
103
are in order. There's a C++ binding to GTK called GTK--, which
 
104
provides a more C++-like interface to GTK; you should probably look
 
105
into this instead. If you don't like that approach for whatever
 
106
reason, there are two alternatives for using GTK. First, you can use
 
107
only the C subset of C++ when interfacing with GTK and then use the C
 
108
interface as described in this tutorial. Second, you can use GTK and
 
109
C++ together by declaring all callbacks as static functions in C++
 
110
classes, and again calling GTK using its C interface. If you choose
 
111
this last approach, you can include as the callback's data value a
 
112
pointer to the object to be manipulated (the so-called "this" value).
 
113
Selecting between these options is simply a matter of preference,
 
114
since in all three approaches you get C++ and GTK. None of these
 
115
approaches requires the use of a specialized preprocessor, so no
 
116
matter what you choose you can use standard C++ with GTK.</para>
 
117
 
 
118
<para>This tutorial is an attempt to document as much as possible of GTK,
 
119
but it is by no means complete. This tutorial assumes a good
 
120
understanding of C, and how to create C programs. It would be a great
 
121
benefit for the reader to have previous X programming experience, but
 
122
it shouldn't be necessary. If you are learning GTK as your first
 
123
widget set, please comment on how you found this tutorial, and what
 
124
you had trouble with. There are also C++, Objective C, ADA, Guile and
 
125
other language bindings available, but I don't follow these.</para>
 
126
 
 
127
<para>This document is a "work in progress". Please look for updates on
 
128
<ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>.</para>
 
129
 
 
130
<para>I would very much like to hear of any problems you have learning GTK
 
131
from this document, and would appreciate input as to how it may be
 
132
improved. Please see the section on <link linkend="ch-Contributing">Contributing
 
133
</link> for further information.</para>
 
134
 
 
135
</chapter>
 
136
 
 
137
<!-- ***************************************************************** -->
 
138
<chapter id="ch-GettingStarted">
 
139
<title>Getting Started</title>
 
140
 
 
141
<para>The first thing to do, of course, is download the GTK source and
 
142
install it. You can always get the latest version from <ulink 
 
143
url="ftp://ftp.gtk.org/pub/gtk">ftp.gtk.org</ulink>. You can also view 
 
144
other sources of GTK information on
 
145
<ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>. GTK
 
146
uses GNU autoconf for configuration. Once untar'd, type 
 
147
<literal>./configure --help</literal> to see a list of options.</para>
 
148
 
 
149
<para>The GTK source distribution also contains the complete source to all
 
150
of the examples used in this tutorial, along with Makefiles to aid
 
151
compilation.</para>
 
152
 
 
153
<para>To begin our introduction to GTK, we'll start with the simplest
 
154
program possible. This program will create a 200x200 pixel window and
 
155
has no way of exiting except to be killed by using the shell.</para>
 
156
 
 
157
<para>
 
158
<inlinemediaobject>
 
159
<imageobject>
 
160
<imagedata fileref="images/base.png" format="png">
 
161
</imageobject>
 
162
</inlinemediaobject>
 
163
</para>
 
164
 
 
165
<programlisting role="C">
 
166
<!-- example-start base base.c -->
 
167
 
 
168
#include &lt;gtk/gtk.h&gt;
 
169
 
 
170
int main( int   argc,
 
171
          char *argv[] )
 
172
{
 
173
    GtkWidget *window;
 
174
    
 
175
    gtk_init (&amp;argc, &amp;argv);
 
176
    
 
177
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
178
    gtk_widget_show  (window);
 
179
    
 
180
    gtk_main ();
 
181
    
 
182
    return 0;
 
183
}
 
184
<!-- example-end -->
 
185
</programlisting>
 
186
 
 
187
<para>You can compile the above program with gcc using:</para>
 
188
<para><literallayout>
 
189
<literal>gcc base.c -o base `pkg-config --cflags --libs gtk+-2.0`</literal>
 
190
</literallayout></para>
 
191
 
 
192
<para>The meaning of the unusual compilation options is explained below in
 
193
<link linkend="sec-Compiling">Compiling Hello World</link>.</para>
 
194
 
 
195
<para>All programs will of course include <filename>gtk/gtk.h</filename> which 
 
196
declares the variables, functions, structures, etc. that will be used in your GTK
 
197
application.</para>
 
198
 
 
199
<para>The next line:</para>
 
200
 
 
201
<programlisting role="C">
 
202
gtk_init (&amp;argc, &amp;argv);
 
203
</programlisting>
 
204
 
 
205
<para>calls the function gtk_init(gint *argc, gchar ***argv) which will be called 
 
206
in all GTK applications. This sets up a few things for us such as the default visual 
 
207
and color map and then proceeds to call gdk_init(gint *argc, gchar ***argv). 
 
208
This function initializes the library for use, sets up default signal handlers, and 
 
209
checks the arguments passed to your application on the command line, looking for
 
210
one of the following:</para>
 
211
 
 
212
<itemizedlist spacing=Compact>
 
213
<listitem><simpara> <literal>--gtk-module</literal></simpara>
 
214
</listitem>
 
215
<listitem><simpara> <literal>--g-fatal-warnings</literal></simpara>
 
216
</listitem>
 
217
<listitem><simpara> <literal>--gtk-debug</literal></simpara>
 
218
</listitem>
 
219
<listitem><simpara> <literal>--gtk-no-debug</literal></simpara>
 
220
</listitem>
 
221
<listitem><simpara> <literal>--gdk-debug</literal></simpara>
 
222
</listitem>
 
223
<listitem><simpara> <literal>--gdk-no-debug</literal></simpara>
 
224
</listitem>
 
225
<listitem><simpara> <literal>--display</literal></simpara>
 
226
</listitem>
 
227
<listitem><simpara> <literal>--sync</literal></simpara>
 
228
</listitem>
 
229
<listitem><simpara> <literal>--name</literal></simpara>
 
230
</listitem>
 
231
<listitem><simpara> <literal>--class</literal></simpara>
 
232
</listitem>
 
233
</itemizedlist>
 
234
 
 
235
<para>It removes these from the argument list, leaving anything it does not
 
236
recognize for your application to parse or ignore. This creates a set
 
237
of standard arguments accepted by all GTK applications.</para>
 
238
 
 
239
<para>The next two lines of code create and display a window.</para>
 
240
 
 
241
<programlisting role="C">
 
242
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
243
  gtk_widget_show (window);
 
244
</programlisting>
 
245
 
 
246
<para>The <literal>GTK_WINDOW_TOPLEVEL</literal> argument specifies that we want the
 
247
window to undergo window manager decoration and placement. Rather than
 
248
create a window of 0x0 size, a window without children is set to
 
249
200x200 by default so you can still manipulate it.</para>
 
250
 
 
251
<para>The gtk_widget_show() function lets GTK know that we are done setting
 
252
the attributes of this widget, and that it can display it.</para>
 
253
 
 
254
<para>The last line enters the GTK main processing loop.</para>
 
255
 
 
256
<programlisting role="C">
 
257
  gtk_main ();
 
258
</programlisting>
 
259
 
 
260
<para>gtk_main() is another call you will see in every GTK application.
 
261
When control reaches this point, GTK will sleep waiting for X events
 
262
(such as button or key presses), timeouts, or file IO notifications to
 
263
occur. In our simple example, however, events are ignored.</para>
 
264
 
 
265
<!-- ----------------------------------------------------------------- -->
 
266
<sect1 id="sec-HelloWorld">
 
267
<title>Hello World in GTK</title>
 
268
 
 
269
<para>Now for a program with a widget (a button). It's the classic
 
270
hello world a la GTK.</para>
 
271
 
 
272
<para>
 
273
<inlinemediaobject>
 
274
<imageobject>
 
275
<imagedata fileref="images/helloworld.png" format="png">
 
276
</imageobject>
 
277
</inlinemediaobject>
 
278
</para>
 
279
 
 
280
<programlisting role="C">
 
281
<!-- example-start helloworld helloworld.c -->
 
282
 
 
283
#include &lt;gtk/gtk.h&gt;
 
284
 
 
285
/* This is a callback function. The data arguments are ignored
 
286
 * in this example. More on callbacks below. */
 
287
static void hello( GtkWidget *widget,
 
288
                   gpointer   data )
 
289
{
 
290
    g_print ("Hello World\n");
 
291
}
 
292
 
 
293
static gboolean delete_event( GtkWidget *widget,
 
294
                              GdkEvent  *event,
 
295
                              gpointer   data )
 
296
{
 
297
    /* If you return FALSE in the "delete_event" signal handler,
 
298
     * GTK will emit the "destroy" signal. Returning TRUE means
 
299
     * you don't want the window to be destroyed.
 
300
     * This is useful for popping up 'are you sure you want to quit?'
 
301
     * type dialogs. */
 
302
 
 
303
    g_print ("delete event occurred\n");
 
304
 
 
305
    /* Change TRUE to FALSE and the main window will be destroyed with
 
306
     * a "delete_event". */
 
307
 
 
308
    return TRUE;
 
309
}
 
310
 
 
311
/* Another callback */
 
312
static void destroy( GtkWidget *widget,
 
313
                     gpointer   data )
 
314
{
 
315
    gtk_main_quit ();
 
316
}
 
317
 
 
318
int main( int   argc,
 
319
          char *argv[] )
 
320
{
 
321
    /* GtkWidget is the storage type for widgets */
 
322
    GtkWidget *window;
 
323
    GtkWidget *button;
 
324
    
 
325
    /* This is called in all GTK applications. Arguments are parsed
 
326
     * from the command line and are returned to the application. */
 
327
    gtk_init (&amp;argc, &amp;argv);
 
328
    
 
329
    /* create a new window */
 
330
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
331
    
 
332
    /* When the window is given the "delete_event" signal (this is given
 
333
     * by the window manager, usually by the "close" option, or on the
 
334
     * titlebar), we ask it to call the delete_event () function
 
335
     * as defined above. The data passed to the callback
 
336
     * function is NULL and is ignored in the callback function. */
 
337
    g_signal_connect (G_OBJECT (window), "delete_event",
 
338
                      G_CALLBACK (delete_event), NULL);
 
339
    
 
340
    /* Here we connect the "destroy" event to a signal handler.  
 
341
     * This event occurs when we call gtk_widget_destroy() on the window,
 
342
     * or if we return FALSE in the "delete_event" callback. */
 
343
    g_signal_connect (G_OBJECT (window), "destroy",
 
344
                      G_CALLBACK (destroy), NULL);
 
345
    
 
346
    /* Sets the border width of the window. */
 
347
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
348
    
 
349
    /* Creates a new button with the label "Hello World". */
 
350
    button = gtk_button_new_with_label ("Hello World");
 
351
    
 
352
    /* When the button receives the "clicked" signal, it will call the
 
353
     * function hello() passing it NULL as its argument.  The hello()
 
354
     * function is defined above. */
 
355
    g_signal_connect (G_OBJECT (button), "clicked",
 
356
                      G_CALLBACK (hello), NULL);
 
357
    
 
358
    /* This will cause the window to be destroyed by calling
 
359
     * gtk_widget_destroy(window) when "clicked".  Again, the destroy
 
360
     * signal could come from here, or the window manager. */
 
361
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
362
                              G_CALLBACK (gtk_widget_destroy),
 
363
                              G_OBJECT (window));
 
364
    
 
365
    /* This packs the button into the window (a gtk container). */
 
366
    gtk_container_add (GTK_CONTAINER (window), button);
 
367
    
 
368
    /* The final step is to display this newly created widget. */
 
369
    gtk_widget_show (button);
 
370
    
 
371
    /* and the window */
 
372
    gtk_widget_show (window);
 
373
    
 
374
    /* All GTK applications must have a gtk_main(). Control ends here
 
375
     * and waits for an event to occur (like a key press or
 
376
     * mouse event). */
 
377
    gtk_main ();
 
378
    
 
379
    return 0;
 
380
}
 
381
<!-- example-end -->
 
382
</programlisting>
 
383
 
 
384
</sect1>
 
385
 
 
386
<!-- ----------------------------------------------------------------- -->
 
387
<sect1 id="sec-Compiling">
 
388
<title>Compiling Hello World</title>
 
389
 
 
390
<para>To compile use:</para>
 
391
 
 
392
<para><literallayout>
 
393
<literal>gcc -Wall -g helloworld.c -o helloworld `pkg-config --cflags gtk+-2.0` \</literal>
 
394
<literal>    `pkg-config --libs gtk+-2.0`</literal>
 
395
</literallayout></para>
 
396
 
 
397
<para>This uses the program <literal>pkg-config</literal>, which can be obtained from
 
398
<ulink url="http://www.freedesktop.org">www.freedesktop.org</ulink>. This program 
 
399
reads the <filename>.pc</filename> which comes with GTK to determine what 
 
400
compiler switches are needed to compile programs that use GTK. 
 
401
<literal>pkg-config --cflags gtk+-2.0</literal> will output a list of include
 
402
directories for the compiler to look in, and 
 
403
<literal>pkg-config --libs gtk+-2.0</literal>
 
404
will output the list of libraries for the compiler to link with and
 
405
the directories to find them in. In the above example they could have
 
406
been combined into a single instance, such as
 
407
<literal>pkg-config --cflags --libs gtk+-2.0</literal>.</para>
 
408
 
 
409
<para>Note that the type of single quote used in the compile command above
 
410
is significant.</para>
 
411
 
 
412
<para>The libraries that are usually linked in are:</para>
 
413
 
 
414
<itemizedlist>
 
415
<listitem><simpara>The GTK library (<literal>-lgtk</literal>), the widget library, 
 
416
based on top of GDK.</simpara>
 
417
</listitem>
 
418
 
 
419
<listitem><simpara>The GDK library (<literal>-lgdk</literal>), the Xlib wrapper.</simpara>
 
420
</listitem>
 
421
 
 
422
<listitem><simpara>The gdk-pixbuf library (<literal>-lgdk_pixbuf</literal>), the image 
 
423
manipulation library.</simpara>
 
424
</listitem>
 
425
 
 
426
<listitem><simpara>The Pango library (<literal>-lpango</literal>) for internationalized 
 
427
text.</simpara>
 
428
</listitem>
 
429
 
 
430
<listitem><simpara>The gobject library (<literal>-lgobject</literal>), containing the
 
431
type system on which GTK is based.</simpara>
 
432
</listitem>
 
433
 
 
434
<listitem><simpara>The gmodule library (<literal>-lgmodule</literal>), which is used 
 
435
to load run time extensions.</simpara>
 
436
</listitem>
 
437
 
 
438
<listitem><simpara>The GLib library (<literal>-lglib</literal>), containing miscellaneous
 
439
functions; only g_print() is used in this particular example. GTK is built on top
 
440
of GLib so you will always require this library. See the section on
 
441
<link linkend="ch-glib">GLib</link> for details.</simpara>
 
442
</listitem>
 
443
 
 
444
<listitem><simpara>The Xlib library (<literal>-lX11</literal>) which is used by GDK.</simpara>
 
445
</listitem>
 
446
 
 
447
<listitem><simpara>The Xext library (<literal>-lXext</literal>). This contains code 
 
448
for shared memory pixmaps and other X extensions.</simpara>
 
449
</listitem>
 
450
 
 
451
<listitem><simpara>The math library (<literal>-lm</literal>). This is used by GTK 
 
452
for various purposes.</simpara>
 
453
</listitem>
 
454
</itemizedlist>
 
455
 
 
456
</sect1>
 
457
 
 
458
<!-- ----------------------------------------------------------------- -->
 
459
<sect1 id="sec-TheoryOfSignalsAndCallbacks">
 
460
<title>Theory of Signals and Callbacks</title>
 
461
 
 
462
<note>
 
463
<para>In version 2.0, the signal system has been moved from GTK to GLib, therefore the
 
464
functions and types explained in this section have a "g_" prefix rather than a "gtk_" 
 
465
prefix. We won't go into details about the extensions which the GLib 2.0 signal system
 
466
has relative to the GTK 1.2 signal system.</para>
 
467
</note>
 
468
 
 
469
<para>Before we look in detail at <emphasis>helloworld</emphasis>, we'll discuss signals
 
470
and callbacks. GTK is an event driven toolkit, which means it will
 
471
sleep in gtk_main() until an event occurs and control is passed to the
 
472
appropriate function.</para>
 
473
 
 
474
<para>This passing of control is done using the idea of "signals". (Note
 
475
that these signals are not the same as the Unix system signals, and
 
476
are not implemented using them, although the terminology is almost
 
477
identical.) When an event occurs, such as the press of a mouse button,
 
478
the appropriate signal will be "emitted" by the widget that was
 
479
pressed.  This is how GTK does most of its useful work. There are
 
480
signals that all widgets inherit, such as "destroy", and there are
 
481
signals that are widget specific, such as "toggled" on a toggle
 
482
button.</para>
 
483
 
 
484
<para>To make a button perform an action, we set up a signal handler to
 
485
catch these signals and call the appropriate function. This is done by
 
486
using a function such as:</para>
 
487
 
 
488
<programlisting role="C">
 
489
gulong g_signal_connect( gpointer      *object,
 
490
                         const gchar   *name,
 
491
                         GCallback     func,
 
492
                         gpointer      func_data );
 
493
</programlisting>
 
494
 
 
495
<para>where the first argument is the widget which will be emitting the
 
496
signal, and the second the name of the signal you wish to catch. The
 
497
third is the function you wish to be called when it is caught, and the
 
498
fourth, the data you wish to have passed to this function.</para>
 
499
 
 
500
<para>The function specified in the third argument is called a "callback
 
501
function", and should generally be of the form</para>
 
502
 
 
503
<programlisting role="C">
 
504
void callback_func( GtkWidget *widget,
 
505
                    ... /* other signal arguments */
 
506
                    gpointer   callback_data );
 
507
</programlisting>
 
508
 
 
509
<para>where the first argument will be a pointer to the widget that emitted
 
510
the signal, and the last a pointer to the data given as the last
 
511
argument to the g_signal_connect() function as shown above.</para>
 
512
 
 
513
<para>Note that the above form for a signal callback function declaration is
 
514
only a general guide, as some widget specific signals generate
 
515
different calling parameters.</para>
 
516
 
 
517
<para>Another call used in the <emphasis>helloworld</emphasis> example, is:</para>
 
518
 
 
519
<programlisting role="C">
 
520
gulong g_signal_connect_swapped( gpointer     *object,
 
521
                                 const gchar  *name,
 
522
                                 GCallback    func,
 
523
                                 gpointer     *callback_data );
 
524
</programlisting>
 
525
 
 
526
<para>g_signal_connect_swapped() is the same as g_signal_connect() except
 
527
that the instance on which the signal is emitted and data will be swapped when
 
528
calling the handler. So when using this function to connect signals, the callback
 
529
should be of the form</para>
 
530
 
 
531
<programlisting role="C">
 
532
void callback_func( gpointer   callback_data,
 
533
                    ... /* other signal arguments */
 
534
                    GtkWidget *widget);
 
535
</programlisting>
 
536
 
 
537
<para>where the object is usually a widget. We usually don't setup callbacks
 
538
for g_signal_connect_swapped() however. They are usually used to call a
 
539
GTK function that accepts a single widget or object as an argument, when a signal
 
540
is emitted on some <emphasis>other</emphasis> object. In the 
 
541
<emphasis>helloworld</emphasis> example, we connect to the "clicked" signal
 
542
on the button, but call gtk_widget_destroy() on the window.</para>
 
543
 
 
544
<para>If your callbacks need additional data, use g_signal_connect() instead
 
545
of g_signal_connect_swapped().</para>
 
546
 
 
547
</sect1>
 
548
 
 
549
<!-- ----------------------------------------------------------------- -->
 
550
<sect1 id="sec-Events">
 
551
<title>Events</title>
 
552
 
 
553
<para>In addition to the signal mechanism described above, there is a set
 
554
of <emphasis>events</emphasis> that reflect the X event mechanism. Callbacks may
 
555
also be attached to these events. These events are:</para>
 
556
 
 
557
<itemizedlist spacing=Compact>
 
558
<listitem><simpara> event</simpara>
 
559
</listitem>
 
560
<listitem><simpara> button_press_event</simpara>
 
561
</listitem>
 
562
<listitem><simpara> button_release_event</simpara>
 
563
</listitem>
 
564
<listitem><simpara> scroll_event</simpara>
 
565
</listitem>
 
566
<listitem><simpara> motion_notify_event</simpara>
 
567
</listitem>
 
568
<listitem><simpara> delete_event</simpara>
 
569
</listitem>
 
570
<listitem><simpara> destroy_event</simpara>
 
571
</listitem>
 
572
<listitem><simpara> expose_event</simpara>
 
573
</listitem>
 
574
<listitem><simpara> key_press_event</simpara>
 
575
</listitem>
 
576
<listitem><simpara> key_release_event</simpara>
 
577
</listitem>
 
578
<listitem><simpara> enter_notify_event</simpara>
 
579
</listitem>
 
580
<listitem><simpara> leave_notify_event</simpara>
 
581
</listitem>
 
582
<listitem><simpara> configure_event</simpara>
 
583
</listitem>
 
584
<listitem><simpara> focus_in_event</simpara>
 
585
</listitem>
 
586
<listitem><simpara> focus_out_event</simpara>
 
587
</listitem>
 
588
<listitem><simpara> map_event</simpara>
 
589
</listitem>
 
590
<listitem><simpara> unmap_event</simpara>
 
591
</listitem>
 
592
<listitem><simpara> property_notify_event</simpara>
 
593
</listitem>
 
594
<listitem><simpara> selection_clear_event</simpara>
 
595
</listitem>
 
596
<listitem><simpara> selection_request_event</simpara>
 
597
</listitem>
 
598
<listitem><simpara> selection_notify_event</simpara>
 
599
</listitem>
 
600
<listitem><simpara> proximity_in_event</simpara>
 
601
</listitem>
 
602
<listitem><simpara> proximity_out_event</simpara>
 
603
</listitem>
 
604
<listitem><simpara> visibility_notify_event</simpara>
 
605
</listitem>
 
606
<listitem><simpara> client_event</simpara>
 
607
</listitem>
 
608
<listitem><simpara> no_expose_event</simpara>
 
609
</listitem>
 
610
<listitem><simpara> window_state_event</simpara>
 
611
</listitem>
 
612
</itemizedlist>
 
613
 
 
614
<para>In order to connect a callback function to one of these events you
 
615
use the function g_signal_connect(), as described above, using one of
 
616
the above event names as the <literal>name</literal> parameter. The callback
 
617
function for events has a slightly different form than that for
 
618
signals:</para>
 
619
 
 
620
<programlisting role="C">
 
621
gint callback_func( GtkWidget *widget,
 
622
                    GdkEvent  *event,
 
623
                    gpointer   callback_data );
 
624
</programlisting>
 
625
 
 
626
<para>GdkEvent is a C <literal>union</literal> structure whose type will depend upon 
 
627
which of the above events has occurred. In order for us to tell which event
 
628
has been issued each of the possible alternatives has a <literal>type</literal>
 
629
member that reflects the event being issued. The other components
 
630
of the event structure will depend upon the type of the
 
631
event. Possible values for the type are:</para>
 
632
 
 
633
<programlisting role="C">
 
634
  GDK_NOTHING
 
635
  GDK_DELETE
 
636
  GDK_DESTROY
 
637
  GDK_EXPOSE
 
638
  GDK_MOTION_NOTIFY
 
639
  GDK_BUTTON_PRESS
 
640
  GDK_2BUTTON_PRESS
 
641
  GDK_3BUTTON_PRESS
 
642
  GDK_BUTTON_RELEASE
 
643
  GDK_KEY_PRESS
 
644
  GDK_KEY_RELEASE
 
645
  GDK_ENTER_NOTIFY
 
646
  GDK_LEAVE_NOTIFY
 
647
  GDK_FOCUS_CHANGE
 
648
  GDK_CONFIGURE
 
649
  GDK_MAP
 
650
  GDK_UNMAP
 
651
  GDK_PROPERTY_NOTIFY
 
652
  GDK_SELECTION_CLEAR
 
653
  GDK_SELECTION_REQUEST
 
654
  GDK_SELECTION_NOTIFY
 
655
  GDK_PROXIMITY_IN
 
656
  GDK_PROXIMITY_OUT
 
657
  GDK_DRAG_ENTER
 
658
  GDK_DRAG_LEAVE
 
659
  GDK_DRAG_MOTION
 
660
  GDK_DRAG_STATUS
 
661
  GDK_DROP_START
 
662
  GDK_DROP_FINISHED
 
663
  GDK_CLIENT_EVENT
 
664
  GDK_VISIBILITY_NOTIFY
 
665
  GDK_NO_EXPOSE
 
666
  GDK_SCROLL
 
667
  GDK_WINDOW_STATE
 
668
  GDK_SETTING
 
669
</programlisting>
 
670
 
 
671
<para>So, to connect a callback function to one of these events we would use
 
672
something like:</para>
 
673
 
 
674
<programlisting role="C">
 
675
g_signal_connect (G_OBJECT (button), "button_press_event",
 
676
                  G_CALLBACK (button_press_callback), NULL);
 
677
</programlisting>
 
678
 
 
679
<para>This assumes that <literal>button</literal> is a Button widget. Now, when the
 
680
mouse is over the button and a mouse button is pressed, the function
 
681
button_press_callback() will be called. This function may be declared as:</para>
 
682
 
 
683
<programlisting role="C">
 
684
static gboolean button_press_callback( GtkWidget      *widget, 
 
685
                                       GdkEventButton *event,
 
686
                                       gpointer        data );
 
687
</programlisting>
 
688
 
 
689
<para>Note that we can declare the second argument as type
 
690
<literal>GdkEventButton</literal> as we know what type of event will occur for this
 
691
function to be called.</para>
 
692
 
 
693
<para>The value returned from this function indicates whether the event
 
694
should be propagated further by the GTK event handling
 
695
mechanism. Returning TRUE indicates that the event has been handled,
 
696
and that it should not propagate further. Returning FALSE continues
 
697
the normal event handling.  See the section on
 
698
<link linkend="ch-AdvancedEventsAndSignals">Advanced Event and Signal Handling</link> 
 
699
for more details on this propagation process.</para>
 
700
 
 
701
<para>For details on the GdkEvent data types, see the appendix entitled
 
702
<link linkend="app-GDKEventTypes">GDK Event Types</link>.</para>
 
703
 
 
704
<para>The GDK selection and drag-and-drop APIs also emit a number of events which
 
705
are reflected in GTK by the signals. See <link 
 
706
linkend="sec-SignalsOnSourceWidgets">Signals on the source widget</link> and <link 
 
707
linkend="sec-SignalsOnDestWidgets">Signals on the destination widget</link>
 
708
for details on the signatures of the callback functions for these signals:</para>
 
709
 
 
710
<itemizedlist spacing=Compact>
 
711
<listitem><simpara> selection_received</simpara>
 
712
</listitem>
 
713
<listitem><simpara> selection_get</simpara>
 
714
</listitem>
 
715
<listitem><simpara> drag_begin_event</simpara>
 
716
</listitem>
 
717
<listitem><simpara> drag_end_event</simpara>
 
718
</listitem>
 
719
<listitem><simpara> drag_data_delete</simpara>
 
720
</listitem>
 
721
<listitem><simpara> drag_motion</simpara>
 
722
</listitem>
 
723
<listitem><simpara> drag_drop</simpara>
 
724
</listitem>
 
725
<listitem><simpara> drag_data_get</simpara>
 
726
</listitem>
 
727
<listitem><simpara> drag_data_received</simpara>
 
728
</listitem>
 
729
</itemizedlist>
 
730
 
 
731
</sect1>
 
732
 
 
733
<!-- ----------------------------------------------------------------- -->
 
734
<sect1 id="sec-SteppingThroughHelloWorld">
 
735
<title>Stepping Through Hello World</title>
 
736
 
 
737
<para>Now that we know the theory behind this, let's clarify by walking
 
738
through the example <emphasis>helloworld</emphasis> program.</para>
 
739
 
 
740
<para>Here is the callback function that will be called when the button is
 
741
"clicked". We ignore both the widget and the data in this example, but
 
742
it is not hard to do things with them. The next example will use the
 
743
data argument to tell us which button was pressed.</para>
 
744
 
 
745
<programlisting role="C">
 
746
static void hello( GtkWidget *widget,
 
747
                   gpointer   data )
 
748
{
 
749
    g_print ("Hello World\n");
 
750
}
 
751
</programlisting>
 
752
 
 
753
<para>The next callback is a bit special. The "delete_event" occurs when the
 
754
window manager sends this event to the application. We have a choice
 
755
here as to what to do about these events. We can ignore them, make
 
756
some sort of response, or simply quit the application.</para>
 
757
 
 
758
<para>The value you return in this callback lets GTK know what action to
 
759
take.  By returning TRUE, we let it know that we don't want to have
 
760
the "destroy" signal emitted, keeping our application running. By
 
761
returning FALSE, we ask that "destroy" be emitted, which in turn will
 
762
call our "destroy" signal handler.</para>
 
763
 
 
764
 
 
765
<programlisting role="C">
 
766
static gboolean delete_event( GtkWidget *widget,
 
767
                              GdkEvent  *event,
 
768
                              gpointer   data )
 
769
{
 
770
    g_print ("delete event occurred\n");
 
771
 
 
772
    return TRUE; 
 
773
}
 
774
</programlisting>
 
775
 
 
776
<para>Here is another callback function which causes the program to quit by
 
777
calling gtk_main_quit(). This function tells GTK that it is to exit
 
778
from gtk_main when control is returned to it.</para>
 
779
 
 
780
<programlisting role="C">
 
781
static void destroy( GtkWidget *widget,
 
782
                     gpointer   data )
 
783
{
 
784
    gtk_main_quit ();
 
785
}
 
786
</programlisting>
 
787
 
 
788
<para>I assume you know about the main() function... yes, as with other
 
789
applications, all GTK applications will also have one of these.</para>
 
790
 
 
791
<programlisting role="C">
 
792
int main( int   argc,
 
793
          char *argv[] )
 
794
{
 
795
</programlisting>
 
796
 
 
797
<para>This next part declares pointers to a structure of type
 
798
GtkWidget. These are used below to create a window and a button.</para>
 
799
 
 
800
<programlisting role="C">
 
801
    GtkWidget *window;
 
802
    GtkWidget *button;
 
803
</programlisting>
 
804
 
 
805
<para>Here is our gtk_init() again. As before, this initializes the toolkit,
 
806
and parses the arguments found on the command line. Any argument it
 
807
recognizes from the command line, it removes from the list, and
 
808
modifies argc and argv to make it look like they never existed,
 
809
allowing your application to parse the remaining arguments.</para>
 
810
 
 
811
<programlisting role="C">
 
812
    gtk_init (&amp;argc, &amp;argv);
 
813
</programlisting>
 
814
 
 
815
<para>Create a new window. This is fairly straightforward. Memory is
 
816
allocated for the GtkWidget *window structure so it now points to a
 
817
valid structure. It sets up a new window, but it is not displayed
 
818
until we call gtk_widget_show(window) near the end of our program.</para>
 
819
 
 
820
<programlisting role="C">
 
821
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
822
</programlisting>
 
823
 
 
824
<para>Here are two examples of connecting a signal handler to an object, in
 
825
this case, the window. Here, the "delete_event" and "destroy" signals
 
826
are caught. The first is emitted when we use the window manager to
 
827
kill the window, or when we use the gtk_widget_destroy() call passing
 
828
in the window widget as the object to destroy. The second is emitted
 
829
when, in the "delete_event" handler, we return FALSE.
 
830
 
 
831
The <literal>G_OBJECT</literal> and <literal>G_CALLBACK</literal> are macros 
 
832
that perform type casting and checking for us, as well as aid the readability of
 
833
the code.</para>
 
834
 
 
835
<programlisting role="C">
 
836
    g_signal_connect (G_OBJECT (window), "delete_event",
 
837
                      G_CALLBACK (delete_event), NULL);
 
838
    g_signal_connect (G_OBJECT (window), "destroy",
 
839
                      G_CALLBACK (destroy), NULL);
 
840
</programlisting>
 
841
 
 
842
<para>This next function is used to set an attribute of a container object.
 
843
This just sets the window so it has a blank area along the inside of
 
844
it 10 pixels wide where no widgets will go. There are other similar
 
845
functions which we will look at in the section on
 
846
<link linkend="ch-SettingWidgetAttributes">Setting Widget Attributes</link></para>
 
847
 
 
848
<para>And again, <literal>GTK_CONTAINER</literal> is a macro to perform type casting.</para>
 
849
 
 
850
<programlisting role="C">
 
851
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
852
</programlisting>
 
853
 
 
854
<para>This call creates a new button. It allocates space for a new GtkWidget
 
855
structure in memory, initializes it, and makes the button pointer
 
856
point to it. It will have the label "Hello World" on it when
 
857
displayed.</para>
 
858
 
 
859
<programlisting role="C">
 
860
    button = gtk_button_new_with_label ("Hello World");
 
861
</programlisting>
 
862
 
 
863
<para>Here, we take this button, and make it do something useful. We attach
 
864
a signal handler to it so when it emits the "clicked" signal, our
 
865
hello() function is called. The data is ignored, so we simply pass in
 
866
NULL to the hello() callback function. Obviously, the "clicked" signal
 
867
is emitted when we click the button with our mouse pointer.</para>
 
868
 
 
869
<programlisting role="C">
 
870
    g_signal_connect (G_OBJECT (button), "clicked",
 
871
                      G_CALLBACK (hello), NULL);
 
872
</programlisting>
 
873
 
 
874
<para>We are also going to use this button to exit our program. This will
 
875
illustrate how the "destroy" signal may come from either the window
 
876
manager, or our program. When the button is "clicked", same as above,
 
877
it calls the first hello() callback function, and then this one in the
 
878
order they are set up. You may have as many callback functions as you
 
879
need, and all will be executed in the order you connected
 
880
them. Because the gtk_widget_destroy() function accepts only a
 
881
GtkWidget *widget as an argument, we use the g_signal_connect_swapped() 
 
882
function here instead of straight g_signal_connect().</para>
 
883
 
 
884
<programlisting role="C">
 
885
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
886
                              G_CALLBACK (gtk_widget_destroy),
 
887
                              G_OBJECT (window));
 
888
</programlisting>
 
889
 
 
890
<para>This is a packing call, which will be explained in depth later on in
 
891
<link linkend="ch-PackingWidgets">Packing Widgets</link>. But it is
 
892
fairly easy to understand. It simply tells GTK that the button is to
 
893
be placed in the window where it will be displayed. Note that a GTK
 
894
container can only contain one widget. There are other widgets, that
 
895
are described later, which are designed to layout multiple widgets in
 
896
various ways.
 
897
 </para>
 
898
 
 
899
<programlisting role="C">
 
900
    gtk_container_add (GTK_CONTAINER (window), button);
 
901
</programlisting>
 
902
 
 
903
<para>Now we have everything set up the way we want it to be. With all the
 
904
signal handlers in place, and the button placed in the window where it
 
905
should be, we ask GTK to "show" the widgets on the screen. The window
 
906
widget is shown last so the whole window will pop up at once rather
 
907
than seeing the window pop up, and then the button form inside of
 
908
it. Although with such a simple example, you'd never notice.</para>
 
909
 
 
910
<programlisting role="C">
 
911
    gtk_widget_show (button);
 
912
 
 
913
    gtk_widget_show (window);
 
914
</programlisting>
 
915
 
 
916
<para>And of course, we call gtk_main() which waits for events to come from
 
917
the X server and will call on the widgets to emit signals when these
 
918
events come.</para>
 
919
 
 
920
<programlisting role="C">
 
921
    gtk_main ();
 
922
</programlisting>
 
923
 
 
924
<para>And the final return. Control returns here after gtk_quit() is called.</para>
 
925
 
 
926
<programlisting role="C">
 
927
    return 0;
 
928
</programlisting>
 
929
 
 
930
<para>Now, when we click the mouse button on a GTK button, the widget emits
 
931
a "clicked" signal. In order for us to use this information, our
 
932
program sets up a signal handler to catch that signal, which
 
933
dispatches the function of our choice. In our example, when the button
 
934
we created is "clicked", the hello() function is called with a NULL
 
935
argument, and then the next handler for this signal is called. This
 
936
calls the gtk_widget_destroy() function, passing it the window widget
 
937
as its argument, destroying the window widget. This causes the window
 
938
to emit the "destroy" signal, which is caught, and calls our destroy()
 
939
callback function, which simply exits GTK.</para>
 
940
 
 
941
<para>Another course of events is to use the window manager to kill the
 
942
window, which will cause the "delete_event" to be emitted. This will
 
943
call our "delete_event" handler. If we return TRUE here, the window
 
944
will be left as is and nothing will happen. Returning FALSE will cause
 
945
GTK to emit the "destroy" signal which of course calls the "destroy"
 
946
callback, exiting GTK.</para>
 
947
 
 
948
</sect1>
 
949
</chapter>
 
950
 
 
951
<!-- ***************************************************************** -->
 
952
<chapter id="ch-MovingOn">
 
953
<title>Moving On</title>
 
954
 
 
955
<!-- ----------------------------------------------------------------- -->
 
956
<sect1 id="sec-DataTypes">
 
957
<title>Data Types</title>
 
958
 
 
959
<para>There are a few things you probably noticed in the previous examples
 
960
that need explaining. The gint, gchar, etc. that you see are typedefs
 
961
to int and char, respectively, that are part of the GLib system. This
 
962
is done to get around that nasty dependency on the size of simple data
 
963
types when doing calculations.</para>
 
964
 
 
965
<para>A good example is "gint32" which will be typedef'd to a 32 bit integer
 
966
for any given platform, whether it be the 64 bit alpha, or the 32 bit
 
967
i386. The typedefs are very straightforward and intuitive. They are
 
968
all defined in <filename>glib/glib.h</filename> (which gets included from 
 
969
<filename>gtk.h</filename>).</para>
 
970
 
 
971
<para>You'll also notice GTK's ability to use GtkWidget when the function
 
972
calls for a GtkObject. GTK is an object oriented design, and a widget
 
973
is an object.</para>
 
974
 
 
975
</sect1>
 
976
 
 
977
<!-- ----------------------------------------------------------------- -->
 
978
<sect1 id="sec-MoreOnSignalHandlers">
 
979
<title>More on Signal Handlers</title>
 
980
 
 
981
<para>Lets take another look at the g_signal_connect() declaration.</para>
 
982
 
 
983
<programlisting role="C">
 
984
gulong g_signal_connect( gpointer object,
 
985
                         const gchar *name,
 
986
                         GCallback func,
 
987
                         gpointer func_data );
 
988
</programlisting>
 
989
 
 
990
<para>Notice the gulong return value? This is a tag that identifies your
 
991
callback function. As stated above, you may have as many callbacks per
 
992
signal and per object as you need, and each will be executed in turn,
 
993
in the order they were attached.</para>
 
994
 
 
995
<para>This tag allows you to remove this callback from the list by using:</para>
 
996
 
 
997
<programlisting role="C">
 
998
void g_signal_handler_disconnect( gpointer object,
 
999
                                  gulong   id );
 
1000
</programlisting>
 
1001
 
 
1002
<para>So, by passing in the widget you wish to remove the handler from, and
 
1003
the tag returned by one of the signal_connect functions, you can
 
1004
disconnect a signal handler.</para>
 
1005
 
 
1006
<para>You can also temporarily disable signal handlers with the
 
1007
g_signal_handler_block() and g_signal_handler_unblock() family of
 
1008
functions.</para>
 
1009
 
 
1010
<programlisting role="C">
 
1011
void g_signal_handler_block( gpointer object,
 
1012
                             gulong   id );
 
1013
 
 
1014
void g_signal_handlers_block_by_func( gpointer  object,
 
1015
                                      GCallback func,
 
1016
                                      gpointer  data );
 
1017
 
 
1018
void g_signal_handler_unblock( gpointer object,
 
1019
                               gulong   id );
 
1020
 
 
1021
void g_signal_handlers_unblock_by_func( gpointer  object,
 
1022
                                        GCallback func,
 
1023
                                        gpointer  data );
 
1024
</programlisting>
 
1025
 
 
1026
</sect1>
 
1027
 
 
1028
<!-- ----------------------------------------------------------------- -->
 
1029
<sect1 id="sec-AnUpgradedHelloWorld">
 
1030
<title>An Upgraded Hello World</title>
 
1031
 
 
1032
<para>Let's take a look at a slightly improved <emphasis>helloworld</emphasis> with
 
1033
better examples of callbacks. This will also introduce us to our next
 
1034
topic, packing widgets.</para>
 
1035
 
 
1036
<para>
 
1037
<inlinemediaobject>
 
1038
<imageobject>
 
1039
<imagedata fileref="images/helloworld2.png" format="png">
 
1040
</imageobject>
 
1041
</inlinemediaobject>
 
1042
</para>
 
1043
 
 
1044
<programlisting role="C">
 
1045
<!-- example-start helloworld2 helloworld2.c -->
 
1046
 
 
1047
#include &lt;gtk/gtk.h&gt;
 
1048
 
 
1049
/* Our new improved callback.  The data passed to this function
 
1050
 * is printed to stdout. */
 
1051
static void callback( GtkWidget *widget,
 
1052
                      gpointer   data )
 
1053
{
 
1054
    g_print ("Hello again - %s was pressed\n", (gchar *) data);
 
1055
}
 
1056
 
 
1057
/* another callback */
 
1058
static gboolean delete_event( GtkWidget *widget,
 
1059
                              GdkEvent  *event,
 
1060
                              gpointer   data )
 
1061
{
 
1062
    gtk_main_quit ();
 
1063
    return FALSE;
 
1064
}
 
1065
 
 
1066
int main( int   argc,
 
1067
          char *argv[] )
 
1068
{
 
1069
    /* GtkWidget is the storage type for widgets */
 
1070
    GtkWidget *window;
 
1071
    GtkWidget *button;
 
1072
    GtkWidget *box1;
 
1073
 
 
1074
    /* This is called in all GTK applications. Arguments are parsed
 
1075
     * from the command line and are returned to the application. */
 
1076
    gtk_init (&amp;argc, &amp;argv);
 
1077
 
 
1078
    /* Create a new window */
 
1079
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
1080
 
 
1081
    /* This is a new call, which just sets the title of our
 
1082
     * new window to "Hello Buttons!" */
 
1083
    gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
 
1084
 
 
1085
    /* Here we just set a handler for delete_event that immediately
 
1086
     * exits GTK. */
 
1087
    g_signal_connect (G_OBJECT (window), "delete_event",
 
1088
                      G_CALLBACK (delete_event), NULL);
 
1089
 
 
1090
    /* Sets the border width of the window. */
 
1091
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
1092
 
 
1093
    /* We create a box to pack widgets into.  This is described in detail
 
1094
     * in the "packing" section. The box is not really visible, it
 
1095
     * is just used as a tool to arrange widgets. */
 
1096
    box1 = gtk_hbox_new (FALSE, 0);
 
1097
 
 
1098
    /* Put the box into the main window. */
 
1099
    gtk_container_add (GTK_CONTAINER (window), box1);
 
1100
 
 
1101
    /* Creates a new button with the label "Button 1". */
 
1102
    button = gtk_button_new_with_label ("Button 1");
 
1103
    
 
1104
    /* Now when the button is clicked, we call the "callback" function
 
1105
     * with a pointer to "button 1" as its argument */
 
1106
    g_signal_connect (G_OBJECT (button), "clicked",
 
1107
                      G_CALLBACK (callback), (gpointer) "button 1");
 
1108
 
 
1109
    /* Instead of gtk_container_add, we pack this button into the invisible
 
1110
     * box, which has been packed into the window. */
 
1111
    gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
 
1112
 
 
1113
    /* Always remember this step, this tells GTK that our preparation for
 
1114
     * this button is complete, and it can now be displayed. */
 
1115
    gtk_widget_show (button);
 
1116
 
 
1117
    /* Do these same steps again to create a second button */
 
1118
    button = gtk_button_new_with_label ("Button 2");
 
1119
 
 
1120
    /* Call the same callback function with a different argument,
 
1121
     * passing a pointer to "button 2" instead. */
 
1122
    g_signal_connect (G_OBJECT (button), "clicked",
 
1123
                      G_CALLBACK (callback), (gpointer) "button 2");
 
1124
 
 
1125
    gtk_box_pack_start(GTK_BOX (box1), button, TRUE, TRUE, 0);
 
1126
 
 
1127
    /* The order in which we show the buttons is not really important, but I
 
1128
     * recommend showing the window last, so it all pops up at once. */
 
1129
    gtk_widget_show (button);
 
1130
 
 
1131
    gtk_widget_show (box1);
 
1132
 
 
1133
    gtk_widget_show (window);
 
1134
    
 
1135
    /* Rest in gtk_main and wait for the fun to begin! */
 
1136
    gtk_main ();
 
1137
 
 
1138
    return 0;
 
1139
}
 
1140
<!-- example-end -->
 
1141
</programlisting>
 
1142
 
 
1143
<para>Compile this program using the same linking arguments as our first
 
1144
example.  You'll notice this time there is no easy way to exit the
 
1145
program, you have to use your window manager or command line to kill
 
1146
it. A good exercise for the reader would be to insert a third "Quit"
 
1147
button that will exit the program. You may also wish to play with the
 
1148
options to gtk_box_pack_start() while reading the next section.  Try
 
1149
resizing the window, and observe the behavior.</para>
 
1150
 
 
1151
</sect1>
 
1152
</chapter>
 
1153
 
 
1154
<!-- ***************************************************************** -->
 
1155
<chapter id="ch-PackingWidgets">
 
1156
<title>Packing Widgets</title>
 
1157
 
 
1158
<para>When creating an application, you'll want to put more than one widget
 
1159
inside a window. Our first <emphasis>helloworld</emphasis> example only used one
 
1160
widget so we could simply use a gtk_container_add() call to "pack" the
 
1161
widget into the window. But when you want to put more than one widget
 
1162
into a window, how do you control where that widget is positioned?
 
1163
This is where packing comes in.</para>
 
1164
 
 
1165
<!-- ----------------------------------------------------------------- -->
 
1166
<sect1 id="sec-TheoryOfPackingBoxes">
 
1167
<title>Theory of Packing Boxes</title>
 
1168
 
 
1169
<para>Most packing is done by creating boxes. These
 
1170
are invisible widget containers that we can pack our widgets into
 
1171
which come in two forms, a horizontal box, and a vertical box. When
 
1172
packing widgets into a horizontal box, the objects are inserted
 
1173
horizontally from left to right or right to left depending on the call
 
1174
used. In a vertical box, widgets are packed from top to bottom or vice
 
1175
versa. You may use any combination of boxes inside or beside other
 
1176
boxes to create the desired effect.</para>
 
1177
 
 
1178
<para>To create a new horizontal box, we use a call to gtk_hbox_new(), and
 
1179
for vertical boxes, gtk_vbox_new(). The gtk_box_pack_start() and
 
1180
gtk_box_pack_end() functions are used to place objects inside of these
 
1181
containers. The gtk_box_pack_start() function will start at the top
 
1182
and work its way down in a vbox, and pack left to right in an hbox.
 
1183
gtk_box_pack_end() will do the opposite, packing from bottom to top in
 
1184
a vbox, and right to left in an hbox. Using these functions allows us
 
1185
to right justify or left justify our widgets and may be mixed in any
 
1186
way to achieve the desired effect. We will use gtk_box_pack_start() in
 
1187
most of our examples. An object may be another container or a
 
1188
widget. In fact, many widgets are actually containers themselves,
 
1189
including the button, but we usually only use a label inside a button.</para>
 
1190
 
 
1191
<para>By using these calls, GTK knows where you want to place your widgets
 
1192
so it can do automatic resizing and other nifty things. There are also
 
1193
a number of options as to how your widgets should be packed. As you
 
1194
can imagine, this method gives us a quite a bit of flexibility when
 
1195
placing and creating widgets.</para>
 
1196
 
 
1197
</sect1>
 
1198
 
 
1199
<!-- ----------------------------------------------------------------- -->
 
1200
<sect1 id="sec-DetailsOfBoxes">
 
1201
<title>Details of Boxes</title>
 
1202
 
 
1203
<para>Because of this flexibility, packing boxes in GTK can be confusing at
 
1204
first. There are a lot of options, and it's not immediately obvious how
 
1205
they all fit together. In the end, however, there are basically five
 
1206
different styles.</para>
 
1207
 
 
1208
<para>
 
1209
<inlinemediaobject>
 
1210
<imageobject>
 
1211
<imagedata fileref="images/packbox1.png" format="png">
 
1212
</imageobject>
 
1213
</inlinemediaobject>
 
1214
</para>
 
1215
 
 
1216
<para>Each line contains one horizontal box (hbox) with several buttons. The
 
1217
call to gtk_box_pack is shorthand for the call to pack each of the
 
1218
buttons into the hbox. Each of the buttons is packed into the hbox the
 
1219
same way (i.e., same arguments to the gtk_box_pack_start() function).</para>
 
1220
 
 
1221
<para>This is the declaration of the gtk_box_pack_start() function.</para>
 
1222
 
 
1223
<programlisting role="C">
 
1224
void gtk_box_pack_start( GtkBox    *box,
 
1225
                         GtkWidget *child,
 
1226
                         gboolean   expand,
 
1227
                         gboolean   fill,
 
1228
                         guint      padding );
 
1229
</programlisting>
 
1230
 
 
1231
<para>The first argument is the box you are packing the object into, the
 
1232
second is the object. The objects will all be buttons for now, so
 
1233
we'll be packing buttons into boxes.</para>
 
1234
 
 
1235
<para>The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
 
1236
controls whether the widgets are laid out in the box to fill in all
 
1237
the extra space in the box so the box is expanded to fill the area
 
1238
allotted to it (TRUE); or the box is shrunk to just fit the widgets
 
1239
(FALSE). Setting expand to FALSE will allow you to do right and left
 
1240
justification of your widgets.  Otherwise, they will all expand to fit
 
1241
into the box, and the same effect could be achieved by using only one
 
1242
of gtk_box_pack_start() or gtk_box_pack_end().</para>
 
1243
 
 
1244
<para>The fill argument to the gtk_box_pack functions control whether the
 
1245
extra space is allocated to the objects themselves (TRUE), or as extra
 
1246
padding in the box around these objects (FALSE). It only has an effect
 
1247
if the expand argument is also TRUE.</para>
 
1248
 
 
1249
<para>When creating a new box, the function looks like this:</para>
 
1250
 
 
1251
<programlisting role="C">
 
1252
GtkWidget *gtk_hbox_new ( gboolean homogeneous,
 
1253
                          gint     spacing );
 
1254
</programlisting>
 
1255
 
 
1256
<para>The homogeneous argument to gtk_hbox_new() (and the same for
 
1257
gtk_vbox_new()) controls whether each object in the box has the same
 
1258
size (i.e., the same width in an hbox, or the same height in a
 
1259
vbox). If it is set, the gtk_box_pack() routines function essentially
 
1260
as if the <literal>expand</literal> argument was always turned on.</para>
 
1261
 
 
1262
<para>What's the difference between spacing (set when the box is created)
 
1263
and padding (set when elements are packed)? Spacing is added between
 
1264
objects, and padding is added on either side of an object. The
 
1265
following figure should make it clearer:</para>
 
1266
 
 
1267
<para>
 
1268
<inlinemediaobject>
 
1269
<imageobject>
 
1270
<imagedata fileref="images/packbox2.png" format="png">
 
1271
</imageobject>
 
1272
</inlinemediaobject>
 
1273
</para>
 
1274
 
 
1275
<para>Here is the code used to create the above images. I've commented it
 
1276
fairly heavily so I hope you won't have any problems following
 
1277
it. Compile it yourself and play with it.</para>
 
1278
 
 
1279
</sect1>
 
1280
 
 
1281
<!-- ----------------------------------------------------------------- -->
 
1282
<sect1 id="sec-PackingDemonstrationProgram">
 
1283
<title>Packing Demonstration Program</title>
 
1284
 
 
1285
<programlisting role="C">
 
1286
/* example-start packbox packbox.c */
 
1287
 
 
1288
#include &lt;stdio.h&gt;
 
1289
#include &lt;stdlib.h&gt;
 
1290
#include "gtk/gtk.h"
 
1291
 
 
1292
static gboolean delete_event( GtkWidget *widget,
 
1293
                              GdkEvent  *event,
 
1294
                              gpointer   data )
 
1295
{
 
1296
    gtk_main_quit ();
 
1297
    return FALSE;
 
1298
}
 
1299
 
 
1300
/* Make a new hbox filled with button-labels. Arguments for the 
 
1301
 * variables we're interested are passed in to this function. 
 
1302
 * We do not show the box, but do show everything inside. */
 
1303
static GtkWidget *make_box( gboolean homogeneous,
 
1304
                            gint     spacing,
 
1305
                            gboolean expand,
 
1306
                            gboolean fill,
 
1307
                            guint    padding ) 
 
1308
{
 
1309
    GtkWidget *box;
 
1310
    GtkWidget *button;
 
1311
    char padstr[80];
 
1312
    
 
1313
    /* Create a new hbox with the appropriate homogeneous
 
1314
     * and spacing settings */
 
1315
    box = gtk_hbox_new (homogeneous, spacing);
 
1316
    
 
1317
    /* Create a series of buttons with the appropriate settings */
 
1318
    button = gtk_button_new_with_label ("gtk_box_pack");
 
1319
    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
 
1320
    gtk_widget_show (button);
 
1321
    
 
1322
    button = gtk_button_new_with_label ("(box,");
 
1323
    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
 
1324
    gtk_widget_show (button);
 
1325
    
 
1326
    button = gtk_button_new_with_label ("button,");
 
1327
    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
 
1328
    gtk_widget_show (button);
 
1329
    
 
1330
    /* Create a button with the label depending on the value of
 
1331
     * expand. */
 
1332
    if (expand == TRUE)
 
1333
            button = gtk_button_new_with_label ("TRUE,");
 
1334
    else
 
1335
            button = gtk_button_new_with_label ("FALSE,");
 
1336
    
 
1337
    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
 
1338
    gtk_widget_show (button);
 
1339
    
 
1340
    /* This is the same as the button creation for "expand"
 
1341
     * above, but uses the shorthand form. */
 
1342
    button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
 
1343
    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
 
1344
    gtk_widget_show (button);
 
1345
    
 
1346
    sprintf (padstr, "%d);", padding);
 
1347
    
 
1348
    button = gtk_button_new_with_label (padstr);
 
1349
    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
 
1350
    gtk_widget_show (button);
 
1351
    
 
1352
    return box;
 
1353
}
 
1354
 
 
1355
int main( int   argc,
 
1356
          char *argv[]) 
 
1357
{
 
1358
    GtkWidget *window;
 
1359
    GtkWidget *button;
 
1360
    GtkWidget *box1;
 
1361
    GtkWidget *box2;
 
1362
    GtkWidget *separator;
 
1363
    GtkWidget *label;
 
1364
    GtkWidget *quitbox;
 
1365
    int which;
 
1366
    
 
1367
    /* Our init, don't forget this! :) */
 
1368
    gtk_init (&amp;argc, &amp;argv);
 
1369
    
 
1370
    if (argc != 2) {
 
1371
        fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
 
1372
        /* This just does cleanup in GTK and exits with an exit status of 1. */
 
1373
        exit (1);
 
1374
    }
 
1375
    
 
1376
    which = atoi (argv[1]);
 
1377
 
 
1378
    /* Create our window */
 
1379
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
1380
 
 
1381
    /* You should always remember to connect the delete_event signal
 
1382
     * to the main window. This is very important for proper intuitive
 
1383
     * behavior */
 
1384
    g_signal_connect (G_OBJECT (window), "delete_event",
 
1385
                      G_CALLBACK (delete_event), NULL);
 
1386
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
1387
    
 
1388
    /* We create a vertical box (vbox) to pack the horizontal boxes into.
 
1389
     * This allows us to stack the horizontal boxes filled with buttons one
 
1390
     * on top of the other in this vbox. */
 
1391
    box1 = gtk_vbox_new (FALSE, 0);
 
1392
    
 
1393
    /* which example to show. These correspond to the pictures above. */
 
1394
    switch (which) {
 
1395
    case 1:
 
1396
        /* create a new label. */
 
1397
        label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
 
1398
        
 
1399
        /* Align the label to the left side.  We'll discuss this function and 
 
1400
         * others in the section on Widget Attributes. */
 
1401
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
 
1402
 
 
1403
        /* Pack the label into the vertical box (vbox box1).  Remember that 
 
1404
         * widgets added to a vbox will be packed one on top of the other in
 
1405
         * order. */
 
1406
        gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
 
1407
        
 
1408
        /* Show the label */
 
1409
        gtk_widget_show (label);
 
1410
        
 
1411
        /* Call our make box function - homogeneous = FALSE, spacing = 0,
 
1412
         * expand = FALSE, fill = FALSE, padding = 0 */
 
1413
        box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
 
1414
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1415
        gtk_widget_show (box2);
 
1416
 
 
1417
        /* Call our make box function - homogeneous = FALSE, spacing = 0,
 
1418
         * expand = TRUE, fill = FALSE, padding = 0 */
 
1419
        box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
 
1420
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1421
        gtk_widget_show (box2);
 
1422
        
 
1423
        /* Args are: homogeneous, spacing, expand, fill, padding */
 
1424
        box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
 
1425
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1426
        gtk_widget_show (box2);
 
1427
        
 
1428
        /* Creates a separator, we'll learn more about these later, 
 
1429
         * but they are quite simple. */
 
1430
        separator = gtk_hseparator_new ();
 
1431
        
 
1432
        /* Pack the separator into the vbox. Remember each of these
 
1433
         * widgets is being packed into a vbox, so they'll be stacked
 
1434
         * vertically. */
 
1435
        gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
 
1436
        gtk_widget_show (separator);
 
1437
        
 
1438
        /* Create another new label, and show it. */
 
1439
        label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
 
1440
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
 
1441
        gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
 
1442
        gtk_widget_show (label);
 
1443
        
 
1444
        /* Args are: homogeneous, spacing, expand, fill, padding */
 
1445
        box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
 
1446
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1447
        gtk_widget_show (box2);
 
1448
        
 
1449
        /* Args are: homogeneous, spacing, expand, fill, padding */
 
1450
        box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
 
1451
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1452
        gtk_widget_show (box2);
 
1453
        
 
1454
        /* Another new separator. */
 
1455
        separator = gtk_hseparator_new ();
 
1456
        /* The last 3 arguments to gtk_box_pack_start are:
 
1457
         * expand, fill, padding. */
 
1458
        gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
 
1459
        gtk_widget_show (separator);
 
1460
        
 
1461
        break;
 
1462
 
 
1463
    case 2:
 
1464
 
 
1465
        /* Create a new label, remember box1 is a vbox as created 
 
1466
         * near the beginning of main() */
 
1467
        label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
 
1468
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
 
1469
        gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
 
1470
        gtk_widget_show (label);
 
1471
        
 
1472
        /* Args are: homogeneous, spacing, expand, fill, padding */
 
1473
        box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
 
1474
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1475
        gtk_widget_show (box2);
 
1476
        
 
1477
        /* Args are: homogeneous, spacing, expand, fill, padding */
 
1478
        box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
 
1479
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1480
        gtk_widget_show (box2);
 
1481
        
 
1482
        separator = gtk_hseparator_new ();
 
1483
        /* The last 3 arguments to gtk_box_pack_start are:
 
1484
         * expand, fill, padding. */
 
1485
        gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
 
1486
        gtk_widget_show (separator);
 
1487
        
 
1488
        label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
 
1489
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
 
1490
        gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
 
1491
        gtk_widget_show (label);
 
1492
        
 
1493
        /* Args are: homogeneous, spacing, expand, fill, padding */
 
1494
        box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
 
1495
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1496
        gtk_widget_show (box2);
 
1497
        
 
1498
        /* Args are: homogeneous, spacing, expand, fill, padding */
 
1499
        box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
 
1500
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1501
        gtk_widget_show (box2);
 
1502
        
 
1503
        separator = gtk_hseparator_new ();
 
1504
        /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
 
1505
        gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
 
1506
        gtk_widget_show (separator);
 
1507
        break;
 
1508
    
 
1509
    case 3:
 
1510
 
 
1511
        /* This demonstrates the ability to use gtk_box_pack_end() to
 
1512
         * right justify widgets. First, we create a new box as before. */
 
1513
        box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
 
1514
 
 
1515
        /* Create the label that will be put at the end. */
 
1516
        label = gtk_label_new ("end");
 
1517
        /* Pack it using gtk_box_pack_end(), so it is put on the right
 
1518
         * side of the hbox created in the make_box() call. */
 
1519
        gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
 
1520
        /* Show the label. */
 
1521
        gtk_widget_show (label);
 
1522
        
 
1523
        /* Pack box2 into box1 (the vbox remember ? :) */
 
1524
        gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
 
1525
        gtk_widget_show (box2);
 
1526
        
 
1527
        /* A separator for the bottom. */
 
1528
        separator = gtk_hseparator_new ();
 
1529
        /* This explicitly sets the separator to 400 pixels wide by 5 pixels
 
1530
         * high. This is so the hbox we created will also be 400 pixels wide,
 
1531
         * and the "end" label will be separated from the other labels in the
 
1532
         * hbox. Otherwise, all the widgets in the hbox would be packed as
 
1533
         * close together as possible. */
 
1534
        gtk_widget_set_size_request (separator, 400, 5);
 
1535
        /* pack the separator into the vbox (box1) created near the start 
 
1536
         * of main() */
 
1537
        gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
 
1538
        gtk_widget_show (separator);    
 
1539
    }
 
1540
    
 
1541
    /* Create another new hbox.. remember we can use as many as we need! */
 
1542
    quitbox = gtk_hbox_new (FALSE, 0);
 
1543
    
 
1544
    /* Our quit button. */
 
1545
    button = gtk_button_new_with_label ("Quit");
 
1546
    
 
1547
    /* Setup the signal to terminate the program when the button is clicked */
 
1548
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
1549
                              G_CALLBACK (gtk_main_quit),
 
1550
                              G_OBJECT (window));
 
1551
    /* Pack the button into the quitbox.
 
1552
     * The last 3 arguments to gtk_box_pack_start are:
 
1553
     * expand, fill, padding. */
 
1554
    gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
 
1555
    /* pack the quitbox into the vbox (box1) */
 
1556
    gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
 
1557
    
 
1558
    /* Pack the vbox (box1) which now contains all our widgets, into the
 
1559
     * main window. */
 
1560
    gtk_container_add (GTK_CONTAINER (window), box1);
 
1561
    
 
1562
    /* And show everything left */
 
1563
    gtk_widget_show (button);
 
1564
    gtk_widget_show (quitbox);
 
1565
    
 
1566
    gtk_widget_show (box1);
 
1567
    /* Showing the window last so everything pops up at once. */
 
1568
    gtk_widget_show (window);
 
1569
    
 
1570
    /* And of course, our main function. */
 
1571
    gtk_main ();
 
1572
 
 
1573
    /* Control returns here when gtk_main_quit() is called, but not when 
 
1574
     * exit() is used. */
 
1575
    
 
1576
    return 0;
 
1577
}
 
1578
<!-- example-end -->
 
1579
</programlisting>
 
1580
 
 
1581
</sect1>
 
1582
 
 
1583
<!-- ----------------------------------------------------------------- -->
 
1584
<sect1 id="sec-PackingUsingTables">
 
1585
<title>Packing Using Tables</title>
 
1586
 
 
1587
<para>Let's take a look at another way of packing - Tables. These can be
 
1588
extremely useful in certain situations.</para>
 
1589
 
 
1590
<para>Using tables, we create a grid that we can place widgets in. The
 
1591
widgets may take up as many spaces as we specify.</para>
 
1592
 
 
1593
<para>The first thing to look at, of course, is the gtk_table_new() function:</para>
 
1594
 
 
1595
<programlisting role="C">
 
1596
GtkWidget *gtk_table_new( guint    rows,
 
1597
                          guint    columns,
 
1598
                          gboolean homogeneous );
 
1599
</programlisting>
 
1600
 
 
1601
<para>The first argument is the number of rows to make in the table, while
 
1602
the second, obviously, is the number of columns.</para>
 
1603
 
 
1604
<para>The homogeneous argument has to do with how the table's boxes are
 
1605
sized. If homogeneous is TRUE, the table boxes are resized to the size
 
1606
of the largest widget in the table. If homogeneous is FALSE, the size
 
1607
of a table boxes is dictated by the tallest widget in its same row,
 
1608
and the widest widget in its column.</para>
 
1609
 
 
1610
<para>The rows and columns are laid out from 0 to n, where n was the number
 
1611
specified in the call to gtk_table_new. So, if you specify rows = 2
 
1612
and columns = 2, the layout would look something like this:</para>
 
1613
 
 
1614
<programlisting role="C">
 
1615
 0          1          2
 
1616
0+----------+----------+
 
1617
 |          |          |
 
1618
1+----------+----------+
 
1619
 |          |          |
 
1620
2+----------+----------+
 
1621
</programlisting>
 
1622
 
 
1623
<para>Note that the coordinate system starts in the upper left hand corner.
 
1624
To place a widget into a box, use the following function:</para>
 
1625
 
 
1626
<programlisting role="C">
 
1627
void gtk_table_attach( GtkTable         *table,
 
1628
                       GtkWidget        *child,
 
1629
                       guint            left_attach,
 
1630
                       guint            right_attach,
 
1631
                       guint            top_attach,
 
1632
                       guint            bottom_attach,
 
1633
                       GtkAttachOptions xoptions,
 
1634
                       GtkAttachOptions yoptions,
 
1635
                       guint            xpadding,
 
1636
                       guint            ypadding );
 
1637
</programlisting>
 
1638
 
 
1639
<para>The first argument ("table") is the table you've created and the
 
1640
second ("child") the widget you wish to place in the table.</para>
 
1641
 
 
1642
<para>The left and right attach arguments specify where to place the widget,
 
1643
and how many boxes to use. If you want a button in the lower right
 
1644
table entry of our 2x2 table, and want it to fill that entry <emphasis>only</emphasis>,
 
1645
left_attach would be = 1, right_attach = 2, top_attach = 1,
 
1646
bottom_attach = 2.</para>
 
1647
 
 
1648
<para>Now, if you wanted a widget to take up the whole top row of our 2x2
 
1649
table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
 
1650
bottom_attach = 1.</para>
 
1651
 
 
1652
<para>The xoptions and yoptions are used to specify packing options and may
 
1653
be bitwise OR'ed together to allow multiple options.</para>
 
1654
 
 
1655
<para>These options are:</para>
 
1656
 
 
1657
<variablelist>
 
1658
<varlistentry>
 
1659
<term><literal>GTK_FILL</literal></term>
 
1660
<listitem><para>If the table box is larger than the widget, and
 
1661
<literal>GTK_FILL</literal> is specified, the widget will expand to use all the room
 
1662
available.</para>
 
1663
</listitem>
 
1664
</varlistentry>
 
1665
 
 
1666
<varlistentry>
 
1667
<term><literal>GTK_SHRINK</literal></term>
 
1668
<listitem><para>If the table widget was allocated less space
 
1669
then was requested (usually by the user resizing the window), then the
 
1670
widgets would normally just be pushed off the bottom of the window and
 
1671
disappear. If <literal>GTK_SHRINK</literal> is specified, the widgets will shrink
 
1672
with the table.</para>
 
1673
</listitem>
 
1674
</varlistentry>
 
1675
 
 
1676
<varlistentry>
 
1677
<term><literal>GTK_EXPAND</literal></term>
 
1678
<listitem><para>This will cause the table to expand to use up
 
1679
any remaining space in the window.</para>
 
1680
</listitem>
 
1681
</varlistentry>
 
1682
</variablelist>
 
1683
 
 
1684
<para>Padding is just like in boxes, creating a clear area around the widget
 
1685
specified in pixels.</para>
 
1686
 
 
1687
<para>gtk_table_attach() has a <emphasis>lot</emphasis> of options.  
 
1688
So, there's a shortcut:</para>
 
1689
 
 
1690
<programlisting role="C">
 
1691
void gtk_table_attach_defaults( GtkTable  *table,
 
1692
                                GtkWidget *widget,
 
1693
                                guint      left_attach,
 
1694
                                guint      right_attach,
 
1695
                                guint      top_attach,
 
1696
                                guint      bottom_attach );
 
1697
</programlisting>
 
1698
 
 
1699
<para>The X and Y options default to <literal>GTK_FILL | GTK_EXPAND</literal>, 
 
1700
and X and Y padding are set to 0. The rest of the arguments are identical to the
 
1701
previous function.</para>
 
1702
 
 
1703
<para>We also have gtk_table_set_row_spacing() and
 
1704
gtk_table_set_col_spacing(). These places spacing between the rows at
 
1705
the specified row or column.</para>
 
1706
 
 
1707
<programlisting role="C">
 
1708
void gtk_table_set_row_spacing( GtkTable *table,
 
1709
                                guint     row,
 
1710
                                guint     spacing );
 
1711
</programlisting>
 
1712
 
 
1713
<para>and</para>
 
1714
 
 
1715
<programlisting role="C">
 
1716
void gtk_table_set_col_spacing ( GtkTable *table,
 
1717
                                 guint     column,
 
1718
                                 guint     spacing );
 
1719
</programlisting>
 
1720
 
 
1721
<para>Note that for columns, the space goes to the right of the column, and
 
1722
for rows, the space goes below the row.</para>
 
1723
 
 
1724
<para>You can also set a consistent spacing of all rows and/or columns with:</para>
 
1725
 
 
1726
<programlisting role="C">
 
1727
void gtk_table_set_row_spacings( GtkTable *table,
 
1728
                                 guint    spacing );
 
1729
</programlisting>
 
1730
 
 
1731
<para>And,</para>
 
1732
 
 
1733
<programlisting role="C">
 
1734
void gtk_table_set_col_spacings( GtkTable *table,
 
1735
                                 guint     spacing );
 
1736
</programlisting>
 
1737
 
 
1738
<para>Note that with these calls, the last row and last column do not get
 
1739
any spacing.</para>
 
1740
 
 
1741
</sect1>
 
1742
 
 
1743
<!-- ----------------------------------------------------------------- -->
 
1744
<sect1 id="sec-TablePackingExamples">
 
1745
<title>Table Packing Example</title>
 
1746
 
 
1747
<para>Here we make a window with three buttons in a 2x2 table.
 
1748
The first two buttons will be placed in the upper row.
 
1749
A third, quit button, is placed in the lower row, spanning both columns.
 
1750
Which means it should look something like this:</para>
 
1751
 
 
1752
<para>
 
1753
<inlinemediaobject>
 
1754
<imageobject>
 
1755
<imagedata fileref="images/table.png" format="png">
 
1756
</imageobject>
 
1757
</inlinemediaobject>
 
1758
</para>
 
1759
 
 
1760
<para>Here's the source code:</para>
 
1761
 
 
1762
<programlisting role="C">
 
1763
<!-- example-start table table.c -->
 
1764
 
 
1765
#include &lt;gtk/gtk.h&gt;
 
1766
 
 
1767
/* Our callback.
 
1768
 * The data passed to this function is printed to stdout */
 
1769
static void callback( GtkWidget *widget,
 
1770
                      gpointer   data )
 
1771
{
 
1772
    g_print ("Hello again - %s was pressed\n", (char *) data);
 
1773
}
 
1774
 
 
1775
/* This callback quits the program */
 
1776
static gboolean delete_event( GtkWidget *widget,
 
1777
                              GdkEvent  *event,
 
1778
                              gpointer   data )
 
1779
{
 
1780
    gtk_main_quit ();
 
1781
    return FALSE;
 
1782
}
 
1783
 
 
1784
int main( int   argc,
 
1785
          char *argv[] )
 
1786
{
 
1787
    GtkWidget *window;
 
1788
    GtkWidget *button;
 
1789
    GtkWidget *table;
 
1790
 
 
1791
    gtk_init (&amp;argc, &amp;argv);
 
1792
 
 
1793
    /* Create a new window */
 
1794
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
1795
 
 
1796
    /* Set the window title */
 
1797
    gtk_window_set_title (GTK_WINDOW (window), "Table");
 
1798
 
 
1799
    /* Set a handler for delete_event that immediately
 
1800
     * exits GTK. */
 
1801
    g_signal_connect (G_OBJECT (window), "delete_event",
 
1802
                      G_CALLBACK (delete_event), NULL);
 
1803
 
 
1804
    /* Sets the border width of the window. */
 
1805
    gtk_container_set_border_width (GTK_CONTAINER (window), 20);
 
1806
 
 
1807
    /* Create a 2x2 table */
 
1808
    table = gtk_table_new (2, 2, TRUE);
 
1809
 
 
1810
    /* Put the table in the main window */
 
1811
    gtk_container_add (GTK_CONTAINER (window), table);
 
1812
 
 
1813
    /* Create first button */
 
1814
    button = gtk_button_new_with_label ("button 1");
 
1815
 
 
1816
    /* When the button is clicked, we call the "callback" function
 
1817
     * with a pointer to "button 1" as its argument */
 
1818
    g_signal_connect (G_OBJECT (button), "clicked",
 
1819
                      G_CALLBACK (callback), (gpointer) "button 1");
 
1820
 
 
1821
 
 
1822
    /* Insert button 1 into the upper left quadrant of the table */
 
1823
    gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 0, 1);
 
1824
 
 
1825
    gtk_widget_show (button);
 
1826
 
 
1827
    /* Create second button */
 
1828
 
 
1829
    button = gtk_button_new_with_label ("button 2");
 
1830
 
 
1831
    /* When the button is clicked, we call the "callback" function
 
1832
     * with a pointer to "button 2" as its argument */
 
1833
    g_signal_connect (G_OBJECT (button), "clicked",
 
1834
                      G_CALLBACK (callback), (gpointer) "button 2");
 
1835
    /* Insert button 2 into the upper right quadrant of the table */
 
1836
    gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, 0, 1);
 
1837
 
 
1838
    gtk_widget_show (button);
 
1839
 
 
1840
    /* Create "Quit" button */
 
1841
    button = gtk_button_new_with_label ("Quit");
 
1842
 
 
1843
    /* When the button is clicked, we call the "delete_event" function
 
1844
     * and the program exits */
 
1845
    g_signal_connect (G_OBJECT (button), "clicked",
 
1846
                      G_CALLBACK (delete_event), NULL);
 
1847
 
 
1848
    /* Insert the quit button into the both 
 
1849
     * lower quadrants of the table */
 
1850
    gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 2, 1, 2);
 
1851
 
 
1852
    gtk_widget_show (button);
 
1853
 
 
1854
    gtk_widget_show (table);
 
1855
    gtk_widget_show (window);
 
1856
 
 
1857
    gtk_main ();
 
1858
 
 
1859
    return 0;
 
1860
}
 
1861
<!-- example-end -->
 
1862
</programlisting>
 
1863
 
 
1864
</sect1>
 
1865
</chapter>
 
1866
 
 
1867
<!-- ***************************************************************** -->
 
1868
<chapter id="ch-WidgetOverview">
 
1869
<title>Widget Overview</title>
 
1870
 
 
1871
<para>The general steps to creating a widget in GTK are:</para>
 
1872
<orderedlist>
 
1873
<listitem><simpara> gtk_*_new() - one of various functions to create a new widget.
 
1874
These are all detailed in this section.</simpara>
 
1875
</listitem>
 
1876
 
 
1877
<listitem><simpara> Connect all signals and events we wish to use to the
 
1878
appropriate handlers.</simpara>
 
1879
</listitem>
 
1880
 
 
1881
<listitem><simpara> Set the attributes of the widget.</simpara>
 
1882
</listitem>
 
1883
 
 
1884
<listitem><simpara> Pack the widget into a container using the appropriate call
 
1885
such as gtk_container_add() or gtk_box_pack_start().</simpara>
 
1886
</listitem>
 
1887
 
 
1888
<listitem><simpara> gtk_widget_show() the widget.</simpara>
 
1889
</listitem>
 
1890
</orderedlist>
 
1891
 
 
1892
<para>gtk_widget_show() lets GTK know that we are done setting the
 
1893
attributes of the widget, and it is ready to be displayed. You may
 
1894
also use gtk_widget_hide to make it disappear again. The order in
 
1895
which you show the widgets is not important, but I suggest showing the
 
1896
window last so the whole window pops up at once rather than seeing the
 
1897
individual widgets come up on the screen as they're formed. The
 
1898
children of a widget (a window is a widget too) will not be displayed
 
1899
until the window itself is shown using the gtk_widget_show() function.</para>
 
1900
 
 
1901
<!-- ----------------------------------------------------------------- -->
 
1902
<sect1 id="sec-Casting">
 
1903
<title>Casting</title>
 
1904
 
 
1905
<para>You'll notice as you go on that GTK uses a type casting system. This
 
1906
is always done using macros that both test the ability to cast the
 
1907
given item, and perform the cast. Some common ones you will see are:</para>
 
1908
 
 
1909
<programlisting role="C">
 
1910
  G_OBJECT (object)
 
1911
  GTK_WIDGET (widget)
 
1912
  GTK_OBJECT (object)
 
1913
  GTK_SIGNAL_FUNC (function)
 
1914
  GTK_CONTAINER (container)
 
1915
  GTK_WINDOW (window)
 
1916
  GTK_BOX (box)
 
1917
</programlisting>
 
1918
 
 
1919
<para>These are all used to cast arguments in functions. You'll see them in the
 
1920
examples, and can usually tell when to use them simply by looking at the
 
1921
function's declaration.</para>
 
1922
 
 
1923
<para>As you can see below in the class hierarchy, all GtkWidgets are
 
1924
derived from the GObject base class. This means you can use a widget
 
1925
in any place the function asks for an object - simply use the
 
1926
<literal>G_OBJECT()</literal> macro.</para>
 
1927
 
 
1928
<para>For example:</para>
 
1929
 
 
1930
<programlisting role="C">
 
1931
g_signal_connect( G_OBJECT (button), "clicked",
 
1932
                  G_CALLBACK (callback_function), callback_data);
 
1933
</programlisting>
 
1934
 
 
1935
<para>This casts the button into an object, and provides a cast for the
 
1936
function pointer to the callback.</para>
 
1937
 
 
1938
<para>Many widgets are also containers. If you look in the class hierarchy
 
1939
below, you'll notice that many widgets derive from the Container
 
1940
class. Any one of these widgets may be used with the
 
1941
<literal>GTK_CONTAINER</literal> macro to pass them to functions that ask for
 
1942
containers.</para>
 
1943
 
 
1944
<para>Unfortunately, these macros are not extensively covered in the
 
1945
tutorial, but I recommend taking a look through the GTK header
 
1946
files or the GTK API reference manual. It can be very educational. In fact, 
 
1947
it's not difficult to learn how a widget works just by looking at the 
 
1948
function declarations.</para>
 
1949
 
 
1950
</sect1>
 
1951
 
 
1952
<!-- ----------------------------------------------------------------- -->
 
1953
<sect1 id="sec-WidgetHierarchy">
 
1954
<title>Widget Hierarchy</title>
 
1955
 
 
1956
<para>For your reference, here is the class hierarchy tree used to implement 
 
1957
widgets. (Deprecated widgets and auxiliary classes have been omitted.)</para>
 
1958
 
 
1959
<programlisting role="C">
 
1960
GObject
 
1961
 |  
 
1962
 GtkObject
 
1963
  +GtkWidget
 
1964
  | +GtkMisc
 
1965
  | | +GtkLabel
 
1966
  | | | `GtkAccelLabel
 
1967
  | | +GtkArrow
 
1968
  | | `GtkImage
 
1969
  | +GtkContainer
 
1970
  | | +GtkBin
 
1971
  | | | +GtkAlignment
 
1972
  | | | +GtkFrame
 
1973
  | | | | `GtkAspectFrame
 
1974
  | | | +GtkButton
 
1975
  | | | | +GtkToggleButton
 
1976
  | | | | | `GtkCheckButton
 
1977
  | | | | |   `GtkRadioButton
 
1978
  | | | | `GtkOptionMenu
 
1979
  | | | +GtkItem
 
1980
  | | | | +GtkMenuItem
 
1981
  | | | |   +GtkCheckMenuItem
 
1982
  | | | |   | `GtkRadioMenuItem
 
1983
  | | | |   +GtkImageMenuItem
 
1984
  | | | |   +GtkSeparatorMenuItem
 
1985
  | | | |   `GtkTearoffMenuItem
 
1986
  | | | +GtkWindow
 
1987
  | | | | +GtkDialog
 
1988
  | | | | | +GtkColorSelectionDialog
 
1989
  | | | | | +GtkFileSelection
 
1990
  | | | | | +GtkFontSelectionDialog
 
1991
  | | | | | +GtkInputDialog
 
1992
  | | | | | `GtkMessageDialog
 
1993
  | | | | `GtkPlug
 
1994
  | | | +GtkEventBox
 
1995
  | | | +GtkHandleBox
 
1996
  | | | +GtkScrolledWindow
 
1997
  | | | `GtkViewport
 
1998
  | | +GtkBox
 
1999
  | | | +GtkButtonBox
 
2000
  | | | | +GtkHButtonBox
 
2001
  | | | | `GtkVButtonBox
 
2002
  | | | +GtkVBox
 
2003
  | | | | +GtkColorSelection
 
2004
  | | | | +GtkFontSelection
 
2005
  | | | | `GtkGammaCurve
 
2006
  | | | `GtkHBox
 
2007
  | | |   +GtkCombo
 
2008
  | | |   `GtkStatusbar
 
2009
  | | +GtkFixed
 
2010
  | | +GtkPaned
 
2011
  | | | +GtkHPaned
 
2012
  | | | `GtkVPaned
 
2013
  | | +GtkLayout
 
2014
  | | +GtkMenuShell
 
2015
  | | | +GtkMenuBar
 
2016
  | | | `GtkMenu
 
2017
  | | +GtkNotebook
 
2018
  | | +GtkSocket
 
2019
  | | +GtkTable
 
2020
  | | +GtkTextView
 
2021
  | | +GtkToolbar
 
2022
  | | `GtkTreeView
 
2023
  | +GtkCalendar
 
2024
  | +GtkDrawingArea
 
2025
  | | `GtkCurve
 
2026
  | +GtkEditable
 
2027
  | | +GtkEntry
 
2028
  | |   `GtkSpinButton
 
2029
  | +GtkRuler
 
2030
  | | +GtkHRuler
 
2031
  | | `GtkVRuler
 
2032
  | +GtkRange
 
2033
  | | +GtkScale
 
2034
  | | | +GtkHScale
 
2035
  | | | `GtkVScale
 
2036
  | | `GtkScrollbar
 
2037
  | |   +GtkHScrollbar
 
2038
  | |   `GtkVScrollbar
 
2039
  | +GtkSeparator
 
2040
  | | +GtkHSeparator
 
2041
  | | `GtkVSeparator
 
2042
  | +GtkInvisible
 
2043
  | +GtkPreview
 
2044
  | `GtkProgressBar
 
2045
  +GtkAdjustment
 
2046
  +GtkCellRenderer
 
2047
  | +GtkCellRendererPixbuf
 
2048
  | +GtkCellRendererText
 
2049
  | +GtkCellRendererToggle
 
2050
  +GtkItemFactory
 
2051
  +GtkTooltips
 
2052
  `GtkTreeViewColumn
 
2053
</programlisting>
 
2054
 
 
2055
</sect1>
 
2056
 
 
2057
<!-- ----------------------------------------------------------------- -->
 
2058
<sect1 id="sec-WidgetsWithoutWindows">
 
2059
<title>Widgets Without Windows</title>
 
2060
 
 
2061
<para>The following widgets do not have an associated window. If you want to
 
2062
capture events, you'll have to use the EventBox. See the section on
 
2063
the <link linkend="sec-EventBox">EventBox</link> widget.</para>
 
2064
 
 
2065
<programlisting role="C">
 
2066
GtkAlignment
 
2067
GtkArrow
 
2068
GtkBin
 
2069
GtkBox
 
2070
GtkButton
 
2071
GtkCheckButton
 
2072
GtkFixed
 
2073
GtkImage
 
2074
GtkLabel
 
2075
GtkMenuItem
 
2076
GtkNotebook
 
2077
GtkPaned
 
2078
GtkRadioButton
 
2079
GtkRange
 
2080
GtkScrolledWindow
 
2081
GtkSeparator
 
2082
GtkTable
 
2083
GtkToolbar
 
2084
GtkAspectFrame
 
2085
GtkFrame
 
2086
GtkVBox
 
2087
GtkHBox
 
2088
GtkVSeparator
 
2089
GtkHSeparator
 
2090
</programlisting>
 
2091
 
 
2092
<para>We'll further our exploration of GTK by examining each widget in turn,
 
2093
creating a few simple functions to display them. Another good source
 
2094
is the <literal>testgtk</literal> program that comes with GTK. It can be found in
 
2095
<filename>tests/testgtk.c</filename>.</para>
 
2096
 
 
2097
</sect1>
 
2098
</chapter>
 
2099
 
 
2100
<!-- ***************************************************************** -->
 
2101
<chapter id="ch-ButtonWidget">
 
2102
<title>The Button Widget</title>
 
2103
 
 
2104
<!-- ----------------------------------------------------------------- -->
 
2105
<sect1 id="sec-NormalButtons">
 
2106
<title>Normal Buttons</title>
 
2107
 
 
2108
<para>We've almost seen all there is to see of the button widget. It's
 
2109
pretty simple. There is however more than one way to create a button. You can
 
2110
use the gtk_button_new_with_label() or gtk_button_new_with_mnemonic() to create 
 
2111
a button with a label, use gtk_button_new_from_stock() to create a button
 
2112
containing the image and text from a stock item or use gtk_button_new() to
 
2113
create a blank button. It's then up to you to pack a label or pixmap into 
 
2114
this new button. To do this, create a new box, and then pack your objects into 
 
2115
this box using the usual gtk_box_pack_start(), and then use gtk_container_add() 
 
2116
to pack the box into the button.</para>
 
2117
 
 
2118
<para>Here's an example of using gtk_button_new() to create a button with a
 
2119
image and a label in it. I've broken up the code to create a box from the rest 
 
2120
so you can use it in your programs. There are further examples of using images 
 
2121
later in the tutorial.</para>
 
2122
 
 
2123
<para>
 
2124
<inlinemediaobject>
 
2125
<imageobject>
 
2126
<imagedata fileref="images/buttons.png" format="png">
 
2127
</imageobject>
 
2128
</inlinemediaobject>
 
2129
</para>
 
2130
 
 
2131
<programlisting role="C">
 
2132
<!-- example-start buttons buttons.c -->
 
2133
 
 
2134
#include &lt;stdlib.h&gt;
 
2135
#include &lt;gtk/gtk.h&gt;
 
2136
 
 
2137
/* Create a new hbox with an image and a label packed into it
 
2138
 * and return the box. */
 
2139
 
 
2140
static GtkWidget *xpm_label_box( gchar     *xpm_filename,
 
2141
                                 gchar     *label_text )
 
2142
{
 
2143
    GtkWidget *box;
 
2144
    GtkWidget *label;
 
2145
    GtkWidget *image;
 
2146
 
 
2147
    /* Create box for image and label */
 
2148
    box = gtk_hbox_new (FALSE, 0);
 
2149
    gtk_container_set_border_width (GTK_CONTAINER (box), 2);
 
2150
 
 
2151
    /* Now on to the image stuff */
 
2152
    image = gtk_image_new_from_file (xpm_filename);
 
2153
 
 
2154
    /* Create a label for the button */
 
2155
    label = gtk_label_new (label_text);
 
2156
 
 
2157
    /* Pack the image and label into the box */
 
2158
    gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 3);
 
2159
    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 3);
 
2160
 
 
2161
    gtk_widget_show (image);
 
2162
    gtk_widget_show (label);
 
2163
 
 
2164
    return box;
 
2165
}
 
2166
 
 
2167
/* Our usual callback function */
 
2168
static void callback( GtkWidget *widget,
 
2169
                      gpointer   data )
 
2170
{
 
2171
    g_print ("Hello again - %s was pressed\n", (char *) data);
 
2172
}
 
2173
 
 
2174
int main( int   argc,
 
2175
          char *argv[] )
 
2176
{
 
2177
    /* GtkWidget is the storage type for widgets */
 
2178
    GtkWidget *window;
 
2179
    GtkWidget *button;
 
2180
    GtkWidget *box;
 
2181
 
 
2182
    gtk_init (&amp;argc, &amp;argv);
 
2183
 
 
2184
    /* Create a new window */
 
2185
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
2186
 
 
2187
    gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
 
2188
 
 
2189
    /* It's a good idea to do this for all windows. */
 
2190
    g_signal_connect (G_OBJECT (window), "destroy",
 
2191
                      G_CALLBACK (gtk_main_quit), NULL);
 
2192
 
 
2193
    g_signal_connect (G_OBJECT (window), "delete_event",
 
2194
                      G_CALLBACK (gtk_main_quit), NULL);
 
2195
 
 
2196
    /* Sets the border width of the window. */
 
2197
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
2198
 
 
2199
    /* Create a new button */
 
2200
    button = gtk_button_new ();
 
2201
 
 
2202
    /* Connect the "clicked" signal of the button to our callback */
 
2203
    g_signal_connect (G_OBJECT (button), "clicked",
 
2204
                      G_CALLBACK (callback), (gpointer) "cool button");
 
2205
 
 
2206
    /* This calls our box creating function */
 
2207
    box = xpm_label_box ("info.xpm", "cool button");
 
2208
 
 
2209
    /* Pack and show all our widgets */
 
2210
    gtk_widget_show (box);
 
2211
 
 
2212
    gtk_container_add (GTK_CONTAINER (button), box);
 
2213
 
 
2214
    gtk_widget_show (button);
 
2215
 
 
2216
    gtk_container_add (GTK_CONTAINER (window), button);
 
2217
 
 
2218
    gtk_widget_show (window);
 
2219
 
 
2220
    /* Rest in gtk_main and wait for the fun to begin! */
 
2221
    gtk_main ();
 
2222
 
 
2223
    return 0;
 
2224
}
 
2225
<!-- example-end -->
 
2226
</programlisting>
 
2227
 
 
2228
<para>The xpm_label_box() function could be used to pack images and labels into
 
2229
any widget that can be a container.</para>
 
2230
 
 
2231
<para>The Button widget has the following signals:</para>
 
2232
 
 
2233
<itemizedlist>
 
2234
<listitem><simpara><literal>pressed</literal> - emitted when pointer button is pressed within
 
2235
Button widget</simpara>
 
2236
</listitem>
 
2237
<listitem><simpara><literal>released</literal> - emitted when pointer button is released within
 
2238
Button widget</simpara>
 
2239
</listitem>
 
2240
<listitem><simpara><literal>clicked</literal> - emitted when pointer button is pressed and then
 
2241
released within Button widget</simpara>
 
2242
</listitem>
 
2243
<listitem><simpara><literal>enter</literal> - emitted when pointer enters Button widget</simpara>
 
2244
</listitem>
 
2245
<listitem><simpara><literal>leave</literal> - emitted when pointer leaves Button widget</simpara>
 
2246
</listitem>
 
2247
</itemizedlist>
 
2248
 
 
2249
</sect1>
 
2250
 
 
2251
<!-- ----------------------------------------------------------------- -->
 
2252
<sect1 id="sec-ToggleButtons">
 
2253
<title>Toggle Buttons</title>
 
2254
 
 
2255
<para>Toggle buttons are derived from normal buttons and are very similar,
 
2256
except they will always be in one of two states, alternated by a
 
2257
click. They may be depressed, and when you click again, they will pop
 
2258
back up. Click again, and they will pop back down.</para>
 
2259
 
 
2260
<para>Toggle buttons are the basis for check buttons and radio buttons, as
 
2261
such, many of the calls used for toggle buttons are inherited by radio
 
2262
and check buttons. I will point these out when we come to them.</para>
 
2263
 
 
2264
<para>Creating a new toggle button:</para>
 
2265
 
 
2266
<programlisting role="C">
 
2267
GtkWidget *gtk_toggle_button_new( void );
 
2268
 
 
2269
GtkWidget *gtk_toggle_button_new_with_label( const gchar *label );
 
2270
 
 
2271
GtkWidget *gtk_toggle_button_new_with_mnemonic( const gchar *label );
 
2272
</programlisting>
 
2273
 
 
2274
<para>As you can imagine, these work identically to the normal button widget
 
2275
calls. The first creates a blank toggle button, and the last two, a
 
2276
button with a label widget already packed into it. The _mnemonic() variant
 
2277
additionally parses the label for '_'-prefixed mnemonic characters.</para>
 
2278
 
 
2279
<para>To retrieve the state of the toggle widget, including radio and check
 
2280
buttons, we use a construct as shown in our example below. This tests
 
2281
the state of the toggle button, by accessing the <literal>active</literal> field of the
 
2282
toggle widget's structure, after first using the
 
2283
<literal>GTK_TOGGLE_BUTTON</literal> macro to cast the widget pointer into a toggle
 
2284
widget pointer. The signal of interest to us emitted by toggle
 
2285
buttons (the toggle button, check button, and radio button widgets) is
 
2286
the "toggled" signal. To check the state of these buttons, set up a
 
2287
signal handler to catch the toggled signal, and access the structure
 
2288
to determine its state. The callback will look something like:</para>
 
2289
 
 
2290
<programlisting role="C">
 
2291
void toggle_button_callback (GtkWidget *widget, gpointer data)
 
2292
{
 
2293
    if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) 
 
2294
    {
 
2295
        /* If control reaches here, the toggle button is down */
 
2296
    
 
2297
    } else {
 
2298
    
 
2299
        /* If control reaches here, the toggle button is up */
 
2300
    }
 
2301
}
 
2302
</programlisting>
 
2303
 
 
2304
<para>To force the state of a toggle button, and its children, the radio and
 
2305
check buttons, use this function:</para>
 
2306
 
 
2307
<programlisting role="C">
 
2308
void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
 
2309
                                   gboolean        is_active );
 
2310
</programlisting>
 
2311
 
 
2312
<para>The above call can be used to set the state of the toggle button, and
 
2313
its children the radio and check buttons. Passing in your created
 
2314
button as the first argument, and a TRUE or FALSE for the second state
 
2315
argument to specify whether it should be down (depressed) or up
 
2316
(released). Default is up, or FALSE.</para>
 
2317
 
 
2318
<para>Note that when you use the gtk_toggle_button_set_active() function, and
 
2319
the state is actually changed, it causes the "clicked" and "toggled"
 
2320
signals to be emitted from the button.</para>
 
2321
 
 
2322
<programlisting role="C">
 
2323
gboolean gtk_toggle_button_get_active   (GtkToggleButton *toggle_button);
 
2324
</programlisting>
 
2325
 
 
2326
<para>This returns the current state of the toggle button as a boolean
 
2327
TRUE/FALSE value.</para>
 
2328
 
 
2329
</sect1>
 
2330
 
 
2331
<!-- ----------------------------------------------------------------- -->
 
2332
<sect1 id="sec-CheckButtons">
 
2333
<title>Check Buttons</title>
 
2334
 
 
2335
<para>Check buttons inherit many properties and functions from the the
 
2336
toggle buttons above, but look a little different. Rather than being
 
2337
buttons with text inside them, they are small squares with the text to
 
2338
the right of them. These are often used for toggling options on and
 
2339
off in applications.</para>
 
2340
 
 
2341
<para>The creation functions are similar to those of the normal button.</para>
 
2342
 
 
2343
<programlisting role="C">
 
2344
GtkWidget *gtk_check_button_new( void );
 
2345
 
 
2346
GtkWidget *gtk_check_button_new_with_label ( const gchar *label );
 
2347
 
 
2348
GtkWidget *gtk_check_button_new_with_mnemonic ( const gchar *label );
 
2349
</programlisting>
 
2350
 
 
2351
<para>The gtk_check_button_new_with_label() function creates a check button 
 
2352
with a label beside it.</para>
 
2353
 
 
2354
<para>Checking the state of the check button is identical to that of the
 
2355
toggle button.</para>
 
2356
 
 
2357
</sect1>
 
2358
 
 
2359
<!-- ----------------------------------------------------------------- -->
 
2360
<sect1 id="sec-RadioButtons">
 
2361
<title>Radio Buttons</title>
 
2362
 
 
2363
<para>Radio buttons are similar to check buttons except they are grouped so
 
2364
that only one may be selected/depressed at a time. This is good for
 
2365
places in your application where you need to select from a short list
 
2366
of options.</para>
 
2367
 
 
2368
<para>Creating a new radio button is done with one of these calls:</para>
 
2369
 
 
2370
<programlisting role="C">
 
2371
GtkWidget *gtk_radio_button_new( GSList *group );
 
2372
 
 
2373
GtkWidget *gtk_radio_button_new_from_widget( GtkRadioButton *group );
 
2374
 
 
2375
GtkWidget *gtk_radio_button_new_with_label( GSList *group,
 
2376
                                            const gchar  *label );
 
2377
 
 
2378
GtkWidget* gtk_radio_button_new_with_label_from_widget( GtkRadioButton *group,
 
2379
                                                        const gchar    *label );
 
2380
 
 
2381
GtkWidget *gtk_radio_button_new_with_mnemonic( GSList *group,
 
2382
                                               const gchar  *label );
 
2383
 
 
2384
GtkWidget *gtk_radio_button_new_with_mnemonic_from_widget( GtkRadioButton *group,
 
2385
                                                           const gchar  *label );
 
2386
 
 
2387
</programlisting>
 
2388
 
 
2389
<para>You'll notice the extra argument to these calls. They require a group
 
2390
to perform their duty properly. The first call to gtk_radio_button_new() or 
 
2391
gtk_radio_button_new_with_label() should pass NULL as the first argument. 
 
2392
Then create a group using:</para>
 
2393
 
 
2394
<programlisting role="C">
 
2395
GSList *gtk_radio_button_get_group( GtkRadioButton *radio_button );
 
2396
</programlisting>
 
2397
 
 
2398
<para>The important thing to remember is that gtk_radio_button_get_group() must be
 
2399
called for each new button added to the group, with the previous button passed 
 
2400
in as an argument. The result is then passed into the next call to 
 
2401
gtk_radio_button_new() or gtk_radio_button_new_with_label(). This allows a
 
2402
chain of buttons to be established. The example below should make this clear.</para>
 
2403
 
 
2404
<para>You can shorten this slightly by using the following syntax, which
 
2405
removes the need for a variable to hold the list of buttons:</para>
 
2406
 
 
2407
<programlisting role="C">
 
2408
     button2 = gtk_radio_button_new_with_label(
 
2409
                 gtk_radio_button_get_group (GTK_RADIO_BUTTON (button1)),
 
2410
                 "button2");
 
2411
</programlisting>
 
2412
 
 
2413
<para>
 
2414
The _from_widget() variants of the creation functions allow you to shorten this
 
2415
further, by omitting the gtk_radio_button_get_group() call. This form is used 
 
2416
in the example to create the third button:
 
2417
</para>
 
2418
 
 
2419
<programlisting role="C">
 
2420
     button2 = gtk_radio_button_new_with_label_from_widget(
 
2421
                 GTK_RADIO_BUTTON (button1), 
 
2422
                 "button2");
 
2423
</programlisting>
 
2424
 
 
2425
<para>It is also a good idea to explicitly set which button should be the
 
2426
default depressed button with:</para>
 
2427
 
 
2428
<programlisting role="C">
 
2429
void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
 
2430
                                   gboolean        state );
 
2431
</programlisting>
 
2432
 
 
2433
<para>This is described in the section on toggle buttons, and works in
 
2434
exactly the same way.  Once the radio buttons are grouped together,
 
2435
only one of the group may be active at a time. If the user clicks on
 
2436
one radio button, and then on another, the first radio button will
 
2437
first emit a "toggled" signal (to report becoming inactive), and then
 
2438
the second will emit its "toggled" signal (to report becoming active).</para>
 
2439
 
 
2440
<para>The following example creates a radio button group with three buttons.</para>
 
2441
 
 
2442
<para>
 
2443
<inlinemediaobject>
 
2444
<imageobject>
 
2445
<imagedata fileref="images/radiobuttons.png" format="png">
 
2446
</imageobject>
 
2447
</inlinemediaobject>
 
2448
</para>
 
2449
 
 
2450
<programlisting role="C">
 
2451
<!-- example-start radiobuttons radiobuttons.c -->
 
2452
 
 
2453
#include &lt;glib.h&gt;
 
2454
#include &lt;gtk/gtk.h&gt;
 
2455
 
 
2456
static gboolean close_application( GtkWidget *widget,
 
2457
                                   GdkEvent  *event,
 
2458
                                   gpointer   data )
 
2459
{
 
2460
  gtk_main_quit ();
 
2461
  return FALSE;
 
2462
}
 
2463
 
 
2464
int main( int   argc,
 
2465
          char *argv[] )
 
2466
{
 
2467
    GtkWidget *window = NULL;
 
2468
    GtkWidget *box1;
 
2469
    GtkWidget *box2;
 
2470
    GtkWidget *button;
 
2471
    GtkWidget *separator;
 
2472
    GSList *group;
 
2473
  
 
2474
    gtk_init (&amp;argc, &amp;argv);    
 
2475
      
 
2476
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
2477
  
 
2478
    g_signal_connect (G_OBJECT (window), "delete_event",
 
2479
                      G_CALLBACK (close_application),
 
2480
                      NULL);
 
2481
 
 
2482
    gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
 
2483
    gtk_container_set_border_width (GTK_CONTAINER (window), 0);
 
2484
 
 
2485
    box1 = gtk_vbox_new (FALSE, 0);
 
2486
    gtk_container_add (GTK_CONTAINER (window), box1);
 
2487
    gtk_widget_show (box1);
 
2488
 
 
2489
    box2 = gtk_vbox_new (FALSE, 10);
 
2490
    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
 
2491
    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
 
2492
    gtk_widget_show (box2);
 
2493
 
 
2494
    button = gtk_radio_button_new_with_label (NULL, "button1");
 
2495
    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
 
2496
    gtk_widget_show (button);
 
2497
 
 
2498
    group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
 
2499
    button = gtk_radio_button_new_with_label (group, "button2");
 
2500
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
 
2501
    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
 
2502
    gtk_widget_show (button);
 
2503
 
 
2504
    button = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (button),
 
2505
                                                          "button3");
 
2506
    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
 
2507
    gtk_widget_show (button);
 
2508
 
 
2509
    separator = gtk_hseparator_new ();
 
2510
    gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
 
2511
    gtk_widget_show (separator);
 
2512
 
 
2513
    box2 = gtk_vbox_new (FALSE, 10);
 
2514
    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
 
2515
    gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
 
2516
    gtk_widget_show (box2);
 
2517
 
 
2518
    button = gtk_button_new_with_label ("close");
 
2519
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
2520
                              G_CALLBACK (close_application),
 
2521
                              G_OBJECT (window));
 
2522
    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
 
2523
    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
2524
    gtk_widget_grab_default (button);
 
2525
    gtk_widget_show (button);
 
2526
    gtk_widget_show (window);
 
2527
     
 
2528
    gtk_main ();
 
2529
 
 
2530
    return 0;
 
2531
}
 
2532
<!-- example-end -->
 
2533
</programlisting>
 
2534
 
 
2535
</sect1>
 
2536
</chapter>
 
2537
 
 
2538
<!-- ***************************************************************** -->
 
2539
<chapter id="ch-Adjustments">
 
2540
<title>Adjustments</title>
 
2541
 
 
2542
<para>GTK has various widgets that can be visually adjusted by the user
 
2543
using the mouse or the keyboard, such as the range widgets, described
 
2544
in the <link linkend="ch-RangeWidgets">Range Widgets</link>
 
2545
section. There are also a few widgets that display some adjustable
 
2546
portion of a larger area of data, such as the text widget and the
 
2547
viewport widget.</para>
 
2548
 
 
2549
<para>Obviously, an application needs to be able to react to changes the
 
2550
user makes in range widgets. One way to do this would be to have each
 
2551
widget emit its own type of signal when its adjustment changes, and
 
2552
either pass the new value to the signal handler, or require it to look
 
2553
inside the widget's data structure in order to ascertain the value.
 
2554
But you may also want to connect the adjustments of several widgets
 
2555
together, so that adjusting one adjusts the others. The most obvious
 
2556
example of this is connecting a scrollbar to a panning viewport or a
 
2557
scrolling text area. If each widget has its own way of setting or
 
2558
getting the adjustment value, then the programmer may have to write
 
2559
their own signal handlers to translate between the output of one
 
2560
widget's signal and the "input" of another's adjustment setting
 
2561
function.</para>
 
2562
 
 
2563
<para>GTK solves this problem using the Adjustment object, which is not a
 
2564
widget but a way for widgets to store and pass adjustment information
 
2565
in an abstract and flexible form. The most obvious use of Adjustment
 
2566
is to store the configuration parameters and values of range widgets,
 
2567
such as scrollbars and scale controls. However, since Adjustments are
 
2568
derived from Object, they have some special powers beyond those of
 
2569
normal data structures. Most importantly, they can emit signals, just
 
2570
like widgets, and these signals can be used not only to allow your
 
2571
program to react to user input on adjustable widgets, but also to
 
2572
propagate adjustment values transparently between adjustable widgets.</para>
 
2573
 
 
2574
<para>You will see how adjustments fit in when you see the other widgets
 
2575
that incorporate them:
 
2576
<link linkend="sec-ProgressBars">Progress Bars</link>,
 
2577
<link linkend="sec-Viewports">Viewports</link>,
 
2578
<link linkend="sec-ScrolledWindows">Scrolled Windows</link>, and others.</para>
 
2579
 
 
2580
<!-- ----------------------------------------------------------------- -->
 
2581
<sect1 id="sec-CreatingAnAdjustment">
 
2582
<title>Creating an Adjustment</title>
 
2583
 
 
2584
<para>Many of the widgets which use adjustment objects do so automatically,
 
2585
but some cases will be shown in later examples where you may need to
 
2586
create one yourself. You create an adjustment using:</para>
 
2587
 
 
2588
<programlisting role="C">
 
2589
GtkObject *gtk_adjustment_new( gdouble value,
 
2590
                               gdouble lower,
 
2591
                               gdouble upper,
 
2592
                               gdouble step_increment,
 
2593
                               gdouble page_increment,
 
2594
                               gdouble page_size );
 
2595
</programlisting>
 
2596
 
 
2597
<para>The <literal>value</literal> argument is the initial value you want to give to the
 
2598
adjustment, usually corresponding to the topmost or leftmost position
 
2599
of an adjustable widget. The <literal>lower</literal> argument specifies the lowest
 
2600
value which the adjustment can hold. The <literal>step_increment</literal> argument
 
2601
specifies the "smaller" of the two increments by which the user can
 
2602
change the value, while the <literal>page_increment</literal> is the "larger" one.
 
2603
The <literal>page_size</literal> argument usually corresponds somehow to the visible
 
2604
area of a panning widget. The <literal>upper</literal> argument is used to represent
 
2605
the bottom most or right most coordinate in a panning widget's
 
2606
child. Therefore it is <emphasis>not</emphasis> always the largest number that
 
2607
<literal>value</literal> can take, since the <literal>page_size</literal> of such widgets is
 
2608
usually non-zero.</para>
 
2609
 
 
2610
</sect1>
 
2611
 
 
2612
<!-- ----------------------------------------------------------------- -->
 
2613
<sect1 id="sec-UsingAdjustments">
 
2614
<title>Using Adjustments the Easy Way</title>
 
2615
 
 
2616
<para>The adjustable widgets can be roughly divided into those which use and
 
2617
require specific units for these values and those which treat them as
 
2618
arbitrary numbers. The group which treats the values as arbitrary
 
2619
numbers includes the range widgets (scrollbars and scales, the
 
2620
progress bar widget, and the spin button widget). These widgets are
 
2621
all the widgets which are typically "adjusted" directly by the user
 
2622
with the mouse or keyboard. They will treat the <literal>lower</literal> and
 
2623
<literal>upper</literal> values of an adjustment as a range within which the user
 
2624
can manipulate the adjustment's <literal>value</literal>. By default, they will only
 
2625
modify the <literal>value</literal> of an adjustment.</para>
 
2626
 
 
2627
<para>The other group includes the text widget, the viewport widget, the
 
2628
compound list widget, and the scrolled window widget. All of these
 
2629
widgets use pixel values for their adjustments. These are also all
 
2630
widgets which are typically "adjusted" indirectly using scrollbars.
 
2631
While all widgets which use adjustments can either create their own
 
2632
adjustments or use ones you supply, you'll generally want to let this
 
2633
particular category of widgets create its own adjustments. Usually,
 
2634
they will eventually override all the values except the <literal>value</literal>
 
2635
itself in whatever adjustments you give them, but the results are, in
 
2636
general, undefined (meaning, you'll have to read the source code to
 
2637
find out, and it may be different from widget to widget).</para>
 
2638
 
 
2639
<para>Now, you're probably thinking, since text widgets and viewports insist
 
2640
on setting everything except the <literal>value</literal> of their adjustments,
 
2641
while scrollbars will <emphasis>only</emphasis> touch the adjustment's 
 
2642
<literal>value</literal>, if you <emphasis>share</emphasis> an adjustment
 
2643
object between a scrollbar and a text widget, manipulating the scrollbar will 
 
2644
automagically adjust the viewport widget?  Of course it will! Just like this:</para>
 
2645
 
 
2646
<programlisting role="C">
 
2647
  /* creates its own adjustments */
 
2648
  viewport = gtk_viewport_new (NULL, NULL);
 
2649
  /* uses the newly-created adjustment for the scrollbar as well */
 
2650
  vscrollbar = gtk_vscrollbar_new (gtk_viewport_get_vadjustment (viewport));
 
2651
</programlisting>
 
2652
 
 
2653
</sect1>
 
2654
 
 
2655
<!-- ----------------------------------------------------------------- -->
 
2656
<sect1 id="sec-AdjustmentInternals">
 
2657
<title>Adjustment Internals</title>
 
2658
 
 
2659
<para>Ok, you say, that's nice, but what if I want to create my own handlers
 
2660
to respond when the user adjusts a range widget or a spin button, and
 
2661
how do I get at the value of the adjustment in these handlers?  To
 
2662
answer these questions and more, let's start by taking a look at
 
2663
<literal>struct _GtkAdjustment</literal> itself:</para>
 
2664
 
 
2665
<programlisting role="C">
 
2666
struct _GtkAdjustment
 
2667
{
 
2668
  GtkObject parent_instance;
 
2669
  
 
2670
  gdouble lower;
 
2671
  gdouble upper;
 
2672
  gdouble value;
 
2673
  gdouble step_increment;
 
2674
  gdouble page_increment;
 
2675
  gdouble page_size;
 
2676
};
 
2677
</programlisting>
 
2678
 
 
2679
<para>If you don't like to poke directly at struct internals like a 
 
2680
<emphasis>real</emphasis> C programmer, you can use the following accessor to
 
2681
inspect the <literal>value</literal> of an adjustment:</para>
 
2682
 
 
2683
<programlisting role="C">
 
2684
gdouble gtk_adjustment_get_value( GtkAdjustment *adjustment);
 
2685
</programlisting>
 
2686
 
 
2687
<para>Since, when you set the <literal>value</literal> of an Adjustment, you generally
 
2688
want the change to be reflected by every widget that uses this
 
2689
adjustment, GTK provides this convenience function to do this:</para>
 
2690
 
 
2691
<programlisting role="C">
 
2692
void gtk_adjustment_set_value( GtkAdjustment *adjustment,
 
2693
                               gdouble       value );
 
2694
</programlisting>
 
2695
 
 
2696
<para>As mentioned earlier, Adjustment is a subclass of Object just
 
2697
like all the various widgets, and thus it is able to emit signals.
 
2698
This is, of course, why updates happen automagically when you share an
 
2699
adjustment object between a scrollbar and another adjustable widget;
 
2700
all adjustable widgets connect signal handlers to their adjustment's
 
2701
<literal>value_changed</literal> signal, as can your program. Here's the definition
 
2702
of this signal in <literal>struct _GtkAdjustmentClass</literal>:</para>
 
2703
 
 
2704
<programlisting role="C">
 
2705
  void (* value_changed) (GtkAdjustment *adjustment);
 
2706
</programlisting>
 
2707
 
 
2708
<para>The various widgets that use the Adjustment object will emit this
 
2709
signal on an adjustment whenever they change its value. This happens
 
2710
both when user input causes the slider to move on a range widget, as
 
2711
well as when the program explicitly changes the value with
 
2712
gtk_adjustment_set_value(). So, for example, if you have a scale
 
2713
widget, and you want to change the rotation of a picture whenever its
 
2714
value changes, you would create a callback like this:</para>
 
2715
 
 
2716
<programlisting role="C">
 
2717
void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
 
2718
{
 
2719
  set_picture_rotation (picture, gtk_adjustment_get_value (adj));
 
2720
...
 
2721
</programlisting>
 
2722
 
 
2723
<para>and connect it to the scale widget's adjustment like this:</para>
 
2724
 
 
2725
<programlisting role="C">
 
2726
g_signal_connect (G_OBJECT (adj), "value_changed",
 
2727
                  G_CALLBACK (cb_rotate_picture), (gpointer) picture);
 
2728
</programlisting>
 
2729
 
 
2730
<para>What about when a widget reconfigures the <literal>upper</literal> or <literal>lower</literal>
 
2731
fields of its adjustment, such as when a user adds more text to a text
 
2732
widget?  In this case, it emits the <literal>changed</literal> signal, which looks
 
2733
like this:</para>
 
2734
 
 
2735
<programlisting role="C">
 
2736
  void (* changed) (GtkAdjustment *adjustment);
 
2737
</programlisting>
 
2738
 
 
2739
<para>Range widgets typically connect a handler to this signal, which
 
2740
changes their appearance to reflect the change - for example, the size
 
2741
of the slider in a scrollbar will grow or shrink in inverse proportion
 
2742
to the difference between the <literal>lower</literal> and <literal>upper</literal> values of its
 
2743
adjustment.</para>
 
2744
 
 
2745
<para>You probably won't ever need to attach a handler to this signal,
 
2746
unless you're writing a new type of range widget.  However, if you
 
2747
change any of the values in a Adjustment directly, you should emit
 
2748
this signal on it to reconfigure whatever widgets are using it, like
 
2749
this:</para>
 
2750
 
 
2751
<programlisting role="C">
 
2752
g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
 
2753
</programlisting>
 
2754
 
 
2755
<para>Now go forth and adjust!</para>
 
2756
 
 
2757
</sect1>
 
2758
</chapter>
 
2759
 
 
2760
<!-- ***************************************************************** -->
 
2761
<chapter id="ch-RangeWidgets">
 
2762
<title>Range Widgets</title>
 
2763
 
 
2764
<para>The category of range widgets includes the ubiquitous scrollbar widget
 
2765
and the less common scale widget. Though these two types of widgets
 
2766
are generally used for different purposes, they are quite similar in
 
2767
function and implementation. All range widgets share a set of common
 
2768
graphic elements, each of which has its own X window and receives
 
2769
events. They all contain a "trough" and a "slider" (what is sometimes
 
2770
called a "thumbwheel" in other GUI environments). Dragging the slider
 
2771
with the pointer moves it back and forth within the trough, while
 
2772
clicking in the trough advances the slider towards the location of the
 
2773
click, either completely, or by a designated amount, depending on
 
2774
which mouse button is used.</para>
 
2775
 
 
2776
<para>As mentioned in <link linkend="ch-Adjustments">Adjustments</link> above,
 
2777
all range widgets are associated with an adjustment object, from which
 
2778
they calculate the length of the slider and its position within the
 
2779
trough. When the user manipulates the slider, the range widget will
 
2780
change the value of the adjustment.</para>
 
2781
 
 
2782
<!-- ----------------------------------------------------------------- -->
 
2783
<sect1 id="sec-ScrollbarWidgets">
 
2784
<title>Scrollbar Widgets</title>
 
2785
 
 
2786
<para>These are your standard, run-of-the-mill scrollbars. These should be
 
2787
used only for scrolling some other widget, such as a list, a text box,
 
2788
or a viewport (and it's generally easier to use the scrolled window
 
2789
widget in most cases).  For other purposes, you should use scale
 
2790
widgets, as they are friendlier and more featureful.</para>
 
2791
 
 
2792
<para>There are separate types for horizontal and vertical scrollbars.
 
2793
There really isn't much to say about these. You create them with the
 
2794
following functions:</para>
 
2795
 
 
2796
<programlisting role="C">
 
2797
GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
 
2798
 
 
2799
GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
 
2800
</programlisting>
 
2801
 
 
2802
<para>and that's about it (if you don't believe me, look in the header
 
2803
files!).  The <literal>adjustment</literal> argument can either be a pointer to an
 
2804
existing Adjustment, or NULL, in which case one will be created for
 
2805
you. Specifying NULL might actually be useful in this case, if you
 
2806
wish to pass the newly-created adjustment to the constructor function
 
2807
of some other widget which will configure it for you, such as a text
 
2808
widget.</para>
 
2809
 
 
2810
</sect1>
 
2811
 
 
2812
<!-- ----------------------------------------------------------------- -->
 
2813
<sect1 id="sec-ScaleWidgets">
 
2814
<title>Scale Widgets</title>
 
2815
 
 
2816
<para>Scale widgets are used to allow the user to visually select and
 
2817
manipulate a value within a specific range. You might want to use a
 
2818
scale widget, for example, to adjust the magnification level on a
 
2819
zoomed preview of a picture, or to control the brightness of a color,
 
2820
or to specify the number of minutes of inactivity before a screensaver
 
2821
takes over the screen.</para>
 
2822
 
 
2823
<!-- ----------------------------------------------------------------- -->
 
2824
<sect2>
 
2825
<title>Creating a Scale Widget</title>
 
2826
 
 
2827
<para>As with scrollbars, there are separate widget types for horizontal and
 
2828
vertical scale widgets. (Most programmers seem to favour horizontal
 
2829
scale widgets.) Since they work essentially the same way, there's no
 
2830
need to treat them separately here. The following functions create vertical and 
 
2831
horizontal scale widgets, respectively:</para>
 
2832
 
 
2833
<programlisting role="C">
 
2834
GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
 
2835
 
 
2836
GtkWidget *gtk_vscale_new_with_range( gdouble min,
 
2837
                                      gdouble max,
 
2838
                                      gdouble step );
 
2839
 
 
2840
GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
 
2841
 
 
2842
GtkWidget *gtk_hscale_new_with_range( gdouble min,
 
2843
                                      gdouble max,
 
2844
                                      gdouble step );
 
2845
</programlisting>
 
2846
 
 
2847
<para>The <literal>adjustment</literal> argument can either be an adjustment which has
 
2848
already been created with gtk_adjustment_new(), or NULL, in
 
2849
which case, an anonymous Adjustment is created with all of its
 
2850
values set to <literal>0.0</literal> (which isn't very useful in this case). 
 
2851
In order to avoid confusing yourself, you probably want to create your
 
2852
adjustment with a <literal>page_size</literal> of <literal>0.0</literal> so 
 
2853
that its <literal>upper</literal> value actually corresponds to the highest 
 
2854
value the user can select. The _new_with_range()�variants take care of creating
 
2855
a suitable adjustment. (If you're <emphasis>already</emphasis> thoroughly
 
2856
confused, read the section on <link linkend="ch-Adjustments">Adjustments</link> 
 
2857
again for an explanation of what exactly adjustments do and how to create and 
 
2858
manipulate them.)</para>
 
2859
 
 
2860
</sect2>
 
2861
 
 
2862
<!-- ----------------------------------------------------------------- -->
 
2863
<sect2>
 
2864
<title>Functions and Signals (well, functions, at least)</title>
 
2865
 
 
2866
<para>Scale widgets can display their current value as a number beside the
 
2867
trough. The default behaviour is to show the value, but you can change
 
2868
this with this function:</para>
 
2869
 
 
2870
<programlisting role="C">
 
2871
void gtk_scale_set_draw_value( GtkScale *scale,
 
2872
                               gboolean draw_value );
 
2873
</programlisting>
 
2874
 
 
2875
<para>As you might have guessed, <literal>draw_value</literal> is either <literal>TRUE</literal> or
 
2876
<literal>FALSE</literal>, with predictable consequences for either one.</para>
 
2877
 
 
2878
<para>The value displayed by a scale widget is rounded to one decimal point
 
2879
by default, as is the <literal>value</literal> field in its Adjustment. You can
 
2880
change this with:</para>
 
2881
 
 
2882
<programlisting role="C">
 
2883
void gtk_scale_set_digits( GtkScale *scale,
 
2884
                            gint     digits );
 
2885
</programlisting>
 
2886
 
 
2887
<para>where <literal>digits</literal> is the number of decimal places you want. You can
 
2888
set <literal>digits</literal> to anything you like, but no more than 13 decimal
 
2889
places will actually be drawn on screen.</para>
 
2890
 
 
2891
<para>Finally, the value can be drawn in different positions
 
2892
relative to the trough:</para>
 
2893
 
 
2894
<programlisting role="C">
 
2895
void gtk_scale_set_value_pos( GtkScale        *scale,
 
2896
                              GtkPositionType  pos );
 
2897
</programlisting>
 
2898
 
 
2899
<para>The argument <literal>pos</literal> is of type <literal>GtkPositionType</literal>,
 
2900
which can take one of the following values:</para>
 
2901
 
 
2902
<programlisting role="C">
 
2903
  GTK_POS_LEFT
 
2904
  GTK_POS_RIGHT
 
2905
  GTK_POS_TOP
 
2906
  GTK_POS_BOTTOM
 
2907
</programlisting>
 
2908
 
 
2909
<para>If you position the value on the "side" of the trough (e.g., on the
 
2910
top or bottom of a horizontal scale widget), then it will follow the
 
2911
slider up and down the trough.</para>
 
2912
 
 
2913
<para>All the preceding functions are defined in
 
2914
<literal>&lt;gtk/gtkscale.h&gt;</literal>. The header files for all GTK widgets
 
2915
are automatically included when you include
 
2916
<literal>&lt;gtk/gtk.h&gt;</literal>. But you should look over the header files
 
2917
of all widgets that interest you, in order to learn more about their functions
 
2918
and features.</para>
 
2919
 
 
2920
</sect2>
 
2921
</sect1>
 
2922
 
 
2923
<!-- ----------------------------------------------------------------- -->
 
2924
<sect1 id="sec-CommonRangeFunctions">
 
2925
<title>Common Range Functions</title>
 
2926
 
 
2927
<para>The Range widget class is fairly complicated internally, but, like
 
2928
all the "base class" widgets, most of its complexity is only
 
2929
interesting if you want to hack on it. Also, almost all of the
 
2930
functions and signals it defines are only really used in writing
 
2931
derived widgets. There are, however, a few useful functions that are
 
2932
defined in <literal>&lt;gtk/gtkrange.h&gt;</literal> and will work on all range
 
2933
widgets.</para>
 
2934
 
 
2935
<!-- ----------------------------------------------------------------- -->
 
2936
<sect2>
 
2937
<title>Setting the Update Policy</title>
 
2938
 
 
2939
<para>The "update policy" of a range widget defines at what points during
 
2940
user interaction it will change the <literal>value</literal> field of its
 
2941
Adjustment and emit the "value_changed" signal on this
 
2942
Adjustment. The update policies, defined in
 
2943
<literal>&lt;gtk/gtkenums.h&gt;</literal> as type <literal>enum GtkUpdateType</literal>,
 
2944
are:</para>
 
2945
 
 
2946
<variablelist>
 
2947
<varlistentry>
 
2948
<term><literal>GTK_UPDATE_CONTINUOUS</literal></term>
 
2949
<listitem><para>This is the default. The
 
2950
"value_changed" signal is emitted continuously, i.e., whenever the
 
2951
slider is moved by even the tiniest amount.</para>
 
2952
</listitem>
 
2953
</varlistentry>
 
2954
<varlistentry>
 
2955
<term><literal>GTK_UPDATE_DISCONTINUOUS</literal></term>
 
2956
<listitem><para>The "value_changed" signal is
 
2957
only emitted once the slider has stopped moving and the user has
 
2958
released the mouse button.</para>
 
2959
</listitem>
 
2960
</varlistentry>
 
2961
<varlistentry>
 
2962
<term><literal>GTK_UPDATE_DELAYED</literal></term>
 
2963
<listitem><para>The "value_changed" signal is emitted
 
2964
when the user releases the mouse button, or if the slider stops moving
 
2965
for a short period of time.</para>
 
2966
</listitem>
 
2967
</varlistentry>
 
2968
</variablelist>
 
2969
 
 
2970
<para>The update policy of a range widget can be set by casting it using the
 
2971
<literal>GTK_RANGE(widget)</literal> macro and passing it to this function:</para>
 
2972
 
 
2973
<programlisting role="C">
 
2974
void gtk_range_set_update_policy( GtkRange      *range,
 
2975
                                  GtkUpdateType  policy);
 
2976
</programlisting>
 
2977
 
 
2978
</sect2>
 
2979
 
 
2980
<!-- ----------------------------------------------------------------- -->
 
2981
<sect2>
 
2982
<title>Getting and Setting Adjustments</title>
 
2983
 
 
2984
<para>Getting and setting the adjustment for a range widget "on the fly" is
 
2985
done, predictably, with:</para>
 
2986
 
 
2987
<programlisting role="C">
 
2988
GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
 
2989
 
 
2990
void gtk_range_set_adjustment( GtkRange      *range,
 
2991
                               GtkAdjustment *adjustment );
 
2992
</programlisting>
 
2993
 
 
2994
<para><literal>gtk_range_get_adjustment()</literal> returns a pointer to the adjustment to
 
2995
which <literal>range</literal> is connected.</para>
 
2996
 
 
2997
<para><literal>gtk_range_set_adjustment()</literal> does absolutely nothing if you pass it
 
2998
the adjustment that <literal>range</literal> is already using, regardless of whether
 
2999
you changed any of its fields or not. If you pass it a new
 
3000
Adjustment, it will unreference the old one if it exists (possibly
 
3001
destroying it), connect the appropriate signals to the new one, and
 
3002
call the private function <literal>gtk_range_adjustment_changed()</literal>, which
 
3003
will (or at least, is supposed to...) recalculate the size and/or
 
3004
position of the slider and redraw if necessary. As mentioned in the
 
3005
section on adjustments, if you wish to reuse the same Adjustment,
 
3006
when you modify its values directly, you should emit the "changed"
 
3007
signal on it, like this:</para>
 
3008
 
 
3009
<programlisting role="C">
 
3010
g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
 
3011
</programlisting>
 
3012
 
 
3013
</sect2>
 
3014
</sect1>
 
3015
 
 
3016
<!-- ----------------------------------------------------------------- -->
 
3017
<sect1 id="sec-KeyAndMouseBindings">
 
3018
<title>Key and Mouse bindings</title>
 
3019
 
 
3020
<para>All of the GTK range widgets react to mouse clicks in more or less
 
3021
the same way. Clicking button-1 in the trough will cause its
 
3022
adjustment's <literal>page_increment</literal> to be added or subtracted from its
 
3023
<literal>value</literal>, and the slider to be moved accordingly. Clicking mouse
 
3024
button-2 in the trough will jump the slider to the point at which the
 
3025
button was clicked. Clicking button-3 in the trough of a range or any button on 
 
3026
a scrollbar's arrows will cause its adjustment's value to change by
 
3027
<literal>step_increment</literal> at a time.</para>
 
3028
 
 
3029
<para>Scrollbars are not focusable, thus have no key bindings. The key bindings
 
3030
for the other range widgets (which are, of course, only active when the widget 
 
3031
has focus) are do <emphasis>not</emphasis> differentiate between horizontal and 
 
3032
vertical range widgets.</para>
 
3033
 
 
3034
<para>All range widgets can be operated with the left, right, up and down arrow
 
3035
keys, as well as with the <literal>Page Up</literal> and <literal>Page Down</literal> 
 
3036
keys. The arrows move the slider up and down by <literal>step_increment</literal>, while
 
3037
<literal>Page Up</literal> and <literal>Page Down</literal> move it by 
 
3038
<literal>page_increment</literal>.</para>
 
3039
 
 
3040
<para>The user can also move the slider all the way to one end or the other
 
3041
of the trough using the keyboard. This is done with the <literal>Home</literal> 
 
3042
and <literal>End</literal> keys.</para>
 
3043
 
 
3044
</sect1>
 
3045
 
 
3046
<!-- ----------------------------------------------------------------- -->
 
3047
<sect1 id="sec-RangeWidgetsExample">
 
3048
<title>Example</title>
 
3049
 
 
3050
<para>This example is a somewhat modified version of the "range controls"
 
3051
test from <filename>testgtk.c</filename>. It basically puts up a window with three
 
3052
range widgets all connected to the same adjustment, and a couple of
 
3053
controls for adjusting some of the parameters mentioned above and in
 
3054
the section on adjustments, so you can see how they affect the way
 
3055
these widgets work for the user.</para>
 
3056
 
 
3057
<para>
 
3058
<inlinemediaobject>
 
3059
<imageobject>
 
3060
<imagedata fileref="images/rangewidgets.png" format="png">
 
3061
</imageobject>
 
3062
</inlinemediaobject>
 
3063
</para>
 
3064
 
 
3065
<programlisting role="C">
 
3066
<!-- example-start rangewidgets rangewidgets.c -->
 
3067
 
 
3068
#include &lt;gtk/gtk.h&gt;
 
3069
 
 
3070
GtkWidget *hscale, *vscale;
 
3071
 
 
3072
static void cb_pos_menu_select( GtkWidget       *item,
 
3073
                                GtkPositionType  pos )
 
3074
{
 
3075
    /* Set the value position on both scale widgets */
 
3076
    gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
 
3077
    gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
 
3078
}
 
3079
 
 
3080
static void cb_update_menu_select( GtkWidget     *item,
 
3081
                                   GtkUpdateType  policy )
 
3082
{
 
3083
    /* Set the update policy for both scale widgets */
 
3084
    gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
 
3085
    gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
 
3086
}
 
3087
 
 
3088
static void cb_digits_scale( GtkAdjustment *adj )
 
3089
{
 
3090
    /* Set the number of decimal places to which adj->value is rounded */
 
3091
    gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
 
3092
    gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
 
3093
}
 
3094
 
 
3095
static void cb_page_size( GtkAdjustment *get,
 
3096
                          GtkAdjustment *set )
 
3097
{
 
3098
    /* Set the page size and page increment size of the sample
 
3099
     * adjustment to the value specified by the "Page Size" scale */
 
3100
    set->page_size = get->value;
 
3101
    set->page_increment = get->value;
 
3102
 
 
3103
    /* This sets the adjustment and makes it emit the "changed" signal to 
 
3104
       reconfigure all the widgets that are attached to this signal.  */
 
3105
    gtk_adjustment_set_value (set, CLAMP (set->value,
 
3106
                                          set->lower,
 
3107
                                          (set->upper - set->page_size)));
 
3108
    g_signal_emit_by_name(G_OBJECT(set), "changed");
 
3109
}
 
3110
 
 
3111
static void cb_draw_value( GtkToggleButton *button )
 
3112
{
 
3113
    /* Turn the value display on the scale widgets off or on depending
 
3114
     *  on the state of the checkbutton */
 
3115
    gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
 
3116
    gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);  
 
3117
}
 
3118
 
 
3119
/* Convenience functions */
 
3120
 
 
3121
static GtkWidget *make_menu_item ( gchar     *name,
 
3122
                                   GCallback  callback,
 
3123
                                   gpointer   data )
 
3124
{
 
3125
    GtkWidget *item;
 
3126
  
 
3127
    item = gtk_menu_item_new_with_label (name);
 
3128
    g_signal_connect (G_OBJECT (item), "activate",
 
3129
                      callback, (gpointer) data);
 
3130
    gtk_widget_show (item);
 
3131
 
 
3132
    return item;
 
3133
}
 
3134
 
 
3135
static void scale_set_default_values( GtkScale *scale )
 
3136
{
 
3137
    gtk_range_set_update_policy (GTK_RANGE (scale),
 
3138
                                 GTK_UPDATE_CONTINUOUS);
 
3139
    gtk_scale_set_digits (scale, 1);
 
3140
    gtk_scale_set_value_pos (scale, GTK_POS_TOP);
 
3141
    gtk_scale_set_draw_value (scale, TRUE);
 
3142
}
 
3143
 
 
3144
/* makes the sample window */
 
3145
 
 
3146
static void create_range_controls( void )
 
3147
{
 
3148
    GtkWidget *window;
 
3149
    GtkWidget *box1, *box2, *box3;
 
3150
    GtkWidget *button;
 
3151
    GtkWidget *scrollbar;
 
3152
    GtkWidget *separator;
 
3153
    GtkWidget *opt, *menu, *item;
 
3154
    GtkWidget *label;
 
3155
    GtkWidget *scale;
 
3156
    GtkObject *adj1, *adj2;
 
3157
 
 
3158
    /* Standard window-creating stuff */
 
3159
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
3160
    g_signal_connect (G_OBJECT (window), "destroy",
 
3161
                      G_CALLBACK (gtk_main_quit),
 
3162
                      NULL);
 
3163
    gtk_window_set_title (GTK_WINDOW (window), "range controls");
 
3164
 
 
3165
    box1 = gtk_vbox_new (FALSE, 0);
 
3166
    gtk_container_add (GTK_CONTAINER (window), box1);
 
3167
    gtk_widget_show (box1);
 
3168
 
 
3169
    box2 = gtk_hbox_new (FALSE, 10);
 
3170
    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
 
3171
    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
 
3172
    gtk_widget_show (box2);
 
3173
 
 
3174
    /* value, lower, upper, step_increment, page_increment, page_size */
 
3175
    /* Note that the page_size value only makes a difference for
 
3176
     * scrollbar widgets, and the highest value you'll get is actually
 
3177
     * (upper - page_size). */
 
3178
    adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
 
3179
  
 
3180
    vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
 
3181
    scale_set_default_values (GTK_SCALE (vscale));
 
3182
    gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
 
3183
    gtk_widget_show (vscale);
 
3184
 
 
3185
    box3 = gtk_vbox_new (FALSE, 10);
 
3186
    gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
 
3187
    gtk_widget_show (box3);
 
3188
 
 
3189
    /* Reuse the same adjustment */
 
3190
    hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
 
3191
    gtk_widget_set_size_request (GTK_WIDGET (hscale), 200, -1);
 
3192
    scale_set_default_values (GTK_SCALE (hscale));
 
3193
    gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
 
3194
    gtk_widget_show (hscale);
 
3195
 
 
3196
    /* Reuse the same adjustment again */
 
3197
    scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
 
3198
    /* Notice how this causes the scales to always be updated
 
3199
     * continuously when the scrollbar is moved */
 
3200
    gtk_range_set_update_policy (GTK_RANGE (scrollbar), 
 
3201
                                 GTK_UPDATE_CONTINUOUS);
 
3202
    gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
 
3203
    gtk_widget_show (scrollbar);
 
3204
 
 
3205
    box2 = gtk_hbox_new (FALSE, 10);
 
3206
    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
 
3207
    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
 
3208
    gtk_widget_show (box2);
 
3209
 
 
3210
    /* A checkbutton to control whether the value is displayed or not */
 
3211
    button = gtk_check_button_new_with_label("Display value on scale widgets");
 
3212
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
 
3213
    g_signal_connect (G_OBJECT (button), "toggled",
 
3214
                      G_CALLBACK (cb_draw_value), NULL);
 
3215
    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
 
3216
    gtk_widget_show (button);
 
3217
  
 
3218
    box2 = gtk_hbox_new (FALSE, 10);
 
3219
    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
 
3220
 
 
3221
    /* An option menu to change the position of the value */
 
3222
    label = gtk_label_new ("Scale Value Position:");
 
3223
    gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
 
3224
    gtk_widget_show (label);
 
3225
  
 
3226
    opt = gtk_option_menu_new ();
 
3227
    menu = gtk_menu_new ();
 
3228
 
 
3229
    item = make_menu_item ("Top",
 
3230
                           G_CALLBACK (cb_pos_menu_select),
 
3231
                           GINT_TO_POINTER (GTK_POS_TOP));
 
3232
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
3233
  
 
3234
    item = make_menu_item ("Bottom", G_CALLBACK (cb_pos_menu_select), 
 
3235
                           GINT_TO_POINTER (GTK_POS_BOTTOM));
 
3236
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
3237
  
 
3238
    item = make_menu_item ("Left", G_CALLBACK (cb_pos_menu_select),
 
3239
                           GINT_TO_POINTER (GTK_POS_LEFT));
 
3240
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
3241
  
 
3242
    item = make_menu_item ("Right", G_CALLBACK (cb_pos_menu_select),
 
3243
                           GINT_TO_POINTER (GTK_POS_RIGHT));
 
3244
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
3245
  
 
3246
    gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
 
3247
    gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
 
3248
    gtk_widget_show (opt);
 
3249
 
 
3250
    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
 
3251
    gtk_widget_show (box2);
 
3252
 
 
3253
    box2 = gtk_hbox_new (FALSE, 10);
 
3254
    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
 
3255
 
 
3256
    /* Yet another option menu, this time for the update policy of the
 
3257
     * scale widgets */
 
3258
    label = gtk_label_new ("Scale Update Policy:");
 
3259
    gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
 
3260
    gtk_widget_show (label);
 
3261
  
 
3262
    opt = gtk_option_menu_new ();
 
3263
    menu = gtk_menu_new ();
 
3264
  
 
3265
    item = make_menu_item ("Continuous",
 
3266
                           G_CALLBACK (cb_update_menu_select),
 
3267
                           GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
 
3268
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
3269
  
 
3270
    item = make_menu_item ("Discontinuous",
 
3271
                           G_CALLBACK (cb_update_menu_select),
 
3272
                           GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
 
3273
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
3274
  
 
3275
    item = make_menu_item ("Delayed",
 
3276
                           G_CALLBACK (cb_update_menu_select),
 
3277
                           GINT_TO_POINTER (GTK_UPDATE_DELAYED));
 
3278
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
3279
  
 
3280
    gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
 
3281
    gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
 
3282
    gtk_widget_show (opt);
 
3283
  
 
3284
    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
 
3285
    gtk_widget_show (box2);
 
3286
 
 
3287
    box2 = gtk_hbox_new (FALSE, 10);
 
3288
    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
 
3289
  
 
3290
    /* An HScale widget for adjusting the number of digits on the
 
3291
     * sample scales. */
 
3292
    label = gtk_label_new ("Scale Digits:");
 
3293
    gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
 
3294
    gtk_widget_show (label);
 
3295
 
 
3296
    adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
 
3297
    g_signal_connect (G_OBJECT (adj2), "value_changed",
 
3298
                      G_CALLBACK (cb_digits_scale), NULL);
 
3299
    scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
 
3300
    gtk_scale_set_digits (GTK_SCALE (scale), 0);
 
3301
    gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
 
3302
    gtk_widget_show (scale);
 
3303
 
 
3304
    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
 
3305
    gtk_widget_show (box2);
 
3306
  
 
3307
    box2 = gtk_hbox_new (FALSE, 10);
 
3308
    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
 
3309
  
 
3310
    /* And, one last HScale widget for adjusting the page size of the
 
3311
     * scrollbar. */
 
3312
    label = gtk_label_new ("Scrollbar Page Size:");
 
3313
    gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
 
3314
    gtk_widget_show (label);
 
3315
 
 
3316
    adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
 
3317
    g_signal_connect (G_OBJECT (adj2), "value_changed",
 
3318
                      G_CALLBACK (cb_page_size), (gpointer) adj1);
 
3319
    scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
 
3320
    gtk_scale_set_digits (GTK_SCALE (scale), 0);
 
3321
    gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
 
3322
    gtk_widget_show (scale);
 
3323
 
 
3324
    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
 
3325
    gtk_widget_show (box2);
 
3326
 
 
3327
    separator = gtk_hseparator_new ();
 
3328
    gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
 
3329
    gtk_widget_show (separator);
 
3330
 
 
3331
    box2 = gtk_vbox_new (FALSE, 10);
 
3332
    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
 
3333
    gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
 
3334
    gtk_widget_show (box2);
 
3335
 
 
3336
    button = gtk_button_new_with_label ("Quit");
 
3337
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
3338
                              G_CALLBACK (gtk_main_quit),
 
3339
                              NULL);
 
3340
    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
 
3341
    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
3342
    gtk_widget_grab_default (button);
 
3343
    gtk_widget_show (button);
 
3344
 
 
3345
    gtk_widget_show (window);
 
3346
}
 
3347
 
 
3348
int main( int   argc,
 
3349
          char *argv[] )
 
3350
{
 
3351
    gtk_init (&amp;argc, &amp;argv);
 
3352
 
 
3353
    create_range_controls ();
 
3354
 
 
3355
    gtk_main ();
 
3356
 
 
3357
    return 0;
 
3358
}
 
3359
 
 
3360
<!-- example-end -->
 
3361
</programlisting>
 
3362
 
 
3363
<para>You will notice that the program does not call g_signal_connect()
 
3364
for the "delete_event", but only for the "destroy" signal. This will
 
3365
still perform the desired function, because an unhandled
 
3366
"delete_event" will result in a "destroy" signal being given to the
 
3367
window.</para>
 
3368
 
 
3369
</sect1>
 
3370
</chapter>
 
3371
 
 
3372
<!-- ***************************************************************** -->
 
3373
<chapter id="ch-MiscWidgets">
 
3374
<title>Miscellaneous Widgets</title>
 
3375
 
 
3376
<!-- ----------------------------------------------------------------- -->
 
3377
<sect1 id="sec-Labels">
 
3378
<title>Labels</title>
 
3379
 
 
3380
<para>Labels are used a lot in GTK, and are relatively simple. Labels emit
 
3381
no signals as they do not have an associated X window. If you need to
 
3382
catch signals, or do clipping, place it inside a <link linkend="sec-EventBox">
 
3383
EventBox</link> widget or a Button widget.</para>
 
3384
 
 
3385
<para>To create a new label, use:</para>
 
3386
 
 
3387
<programlisting role="C">
 
3388
GtkWidget *gtk_label_new( const char *str );
 
3389
 
 
3390
GtkWidget *gtk_label_new_with_mnemonic( const char *str );
 
3391
</programlisting>
 
3392
 
 
3393
<para>The sole argument is the string you wish the label to display.</para>
 
3394
 
 
3395
<para>To change the label's text after creation, use the function:</para>
 
3396
 
 
3397
<programlisting role="C">
 
3398
void gtk_label_set_text( GtkLabel   *label,
 
3399
                         const char *str );
 
3400
</programlisting>
 
3401
 
 
3402
<para>The first argument is the label you created previously (cast
 
3403
using the <literal>GTK_LABEL()</literal> macro), and the second is the new string.</para>
 
3404
 
 
3405
<para>The space needed for the new string will be automatically adjusted if
 
3406
needed. You can produce multi-line labels by putting line breaks in
 
3407
the label string.</para>
 
3408
 
 
3409
<para>To retrieve the current string, use:</para>
 
3410
 
 
3411
<programlisting role="C">
 
3412
const gchar* gtk_label_get_text( GtkLabel  *label );                    
 
3413
</programlisting>
 
3414
 
 
3415
<para>Do not free the returned string, as it is used internally by GTK.</para>
 
3416
 
 
3417
<para>The label text can be justified using:</para>
 
3418
 
 
3419
<programlisting role="C">
 
3420
void gtk_label_set_justify( GtkLabel         *label,
 
3421
                            GtkJustification  jtype );
 
3422
</programlisting>
 
3423
 
 
3424
<para>Values for <literal>jtype</literal> are:</para>
 
3425
<programlisting role="C">
 
3426
  GTK_JUSTIFY_LEFT
 
3427
  GTK_JUSTIFY_RIGHT
 
3428
  GTK_JUSTIFY_CENTER (the default)
 
3429
  GTK_JUSTIFY_FILL
 
3430
</programlisting>
 
3431
 
 
3432
<para>The label widget is also capable of line wrapping the text
 
3433
automatically. This can be activated using:</para>
 
3434
 
 
3435
<programlisting role="C">
 
3436
void gtk_label_set_line_wrap (GtkLabel *label,
 
3437
                              gboolean  wrap);
 
3438
</programlisting>
 
3439
 
 
3440
<para>The <literal>wrap</literal> argument takes a TRUE or FALSE value.</para>
 
3441
 
 
3442
<para>If you want your label underlined, then you can set a pattern on the
 
3443
label:</para>
 
3444
 
 
3445
<programlisting role="C">
 
3446
void       gtk_label_set_pattern   (GtkLabel          *label,
 
3447
                                    const gchar       *pattern);
 
3448
</programlisting>
 
3449
 
 
3450
<para>The pattern argument indicates how the underlining should look. It
 
3451
consists of a string of underscore and space characters. An underscore
 
3452
indicates that the corresponding character in the label should be
 
3453
underlined. For example, the string <literal>"__     __"</literal> would underline the
 
3454
first two characters and eight and ninth characters.</para>
 
3455
 
 
3456
<note><para>If you simply want to have an underlined accelerator ("mnemonic") 
 
3457
in your label, you should use gtk_label_new_with_mnemonic() or 
 
3458
gtk_label_set_text_with_mnemonic(), not gtk_label_set_pattern().</para>
 
3459
</note>
 
3460
 
 
3461
<para>Below is a short example to illustrate these functions. This example
 
3462
makes use of the Frame widget to better demonstrate the label
 
3463
styles. You can ignore this for now as the <link linkend="sec-Frames">Frame</link> 
 
3464
widget is explained later on.</para>
 
3465
 
 
3466
<para>In GTK+ 2.0, label texts can contain markup for font and other text attribute 
 
3467
changes, and labels may be selectable (for copy-and-paste). These advanced features
 
3468
won't be explained here.</para>
 
3469
 
 
3470
<para>
 
3471
<inlinemediaobject>
 
3472
<imageobject>
 
3473
<imagedata fileref="images/label.png" format="png">
 
3474
</imageobject>
 
3475
</inlinemediaobject>
 
3476
</para>
 
3477
 
 
3478
<programlisting role="C">
 
3479
<!-- example-start label label.c -->
 
3480
 
 
3481
#include &lt;gtk/gtk.h&gt;
 
3482
 
 
3483
int main( int   argc,
 
3484
          char *argv[] )
 
3485
{
 
3486
  static GtkWidget *window = NULL;
 
3487
  GtkWidget *hbox;
 
3488
  GtkWidget *vbox;
 
3489
  GtkWidget *frame;
 
3490
  GtkWidget *label;
 
3491
 
 
3492
  /* Initialise GTK */
 
3493
  gtk_init (&amp;argc, &amp;argv);
 
3494
 
 
3495
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
3496
  g_signal_connect (G_OBJECT (window), "destroy",
 
3497
                    G_CALLBACK (gtk_main_quit),
 
3498
                    NULL);
 
3499
 
 
3500
  gtk_window_set_title (GTK_WINDOW (window), "Label");
 
3501
  vbox = gtk_vbox_new (FALSE, 5);
 
3502
  hbox = gtk_hbox_new (FALSE, 5);
 
3503
  gtk_container_add (GTK_CONTAINER (window), hbox);
 
3504
  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
 
3505
  gtk_container_set_border_width (GTK_CONTAINER (window), 5);
 
3506
  
 
3507
  frame = gtk_frame_new ("Normal Label");
 
3508
  label = gtk_label_new ("This is a Normal label");
 
3509
  gtk_container_add (GTK_CONTAINER (frame), label);
 
3510
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3511
  
 
3512
  frame = gtk_frame_new ("Multi-line Label");
 
3513
  label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
 
3514
                         "Third line");
 
3515
  gtk_container_add (GTK_CONTAINER (frame), label);
 
3516
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3517
  
 
3518
  frame = gtk_frame_new ("Left Justified Label");
 
3519
  label = gtk_label_new ("This is a Left-Justified\n" \
 
3520
                         "Multi-line label.\nThird      line");
 
3521
  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
 
3522
  gtk_container_add (GTK_CONTAINER (frame), label);
 
3523
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3524
  
 
3525
  frame = gtk_frame_new ("Right Justified Label");
 
3526
  label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
 
3527
                         "Fourth line, (j/k)");
 
3528
  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
 
3529
  gtk_container_add (GTK_CONTAINER (frame), label);
 
3530
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3531
 
 
3532
  vbox = gtk_vbox_new (FALSE, 5);
 
3533
  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
 
3534
  frame = gtk_frame_new ("Line wrapped label");
 
3535
  label = gtk_label_new ("This is an example of a line-wrapped label.  It " \
 
3536
                         "should not be taking up the entire             " /* big space to test spacing */\
 
3537
                         "width allocated to it, but automatically " \
 
3538
                         "wraps the words to fit.  " \
 
3539
                         "The time has come, for all good men, to come to " \
 
3540
                         "the aid of their party.  " \
 
3541
                         "The sixth sheik's six sheep's sick.\n" \
 
3542
                         "     It supports multiple paragraphs correctly, " \
 
3543
                         "and  correctly   adds "\
 
3544
                         "many          extra  spaces. ");
 
3545
  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
3546
  gtk_container_add (GTK_CONTAINER (frame), label);
 
3547
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3548
  
 
3549
  frame = gtk_frame_new ("Filled, wrapped label");
 
3550
  label = gtk_label_new ("This is an example of a line-wrapped, filled label.  " \
 
3551
                         "It should be taking "\
 
3552
                         "up the entire              width allocated to it.  " \
 
3553
                         "Here is a sentence to prove "\
 
3554
                         "my point.  Here is another sentence. "\
 
3555
                         "Here comes the sun, do de do de do.\n"\
 
3556
                         "    This is a new paragraph.\n"\
 
3557
                         "    This is another newer, longer, better " \
 
3558
                         "paragraph.  It is coming to an end, "\
 
3559
                         "unfortunately.");
 
3560
  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
 
3561
  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
3562
  gtk_container_add (GTK_CONTAINER (frame), label);
 
3563
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3564
  
 
3565
  frame = gtk_frame_new ("Underlined label");
 
3566
  label = gtk_label_new ("This label is underlined!\n"
 
3567
                         "This one is underlined in quite a funky fashion");
 
3568
  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
 
3569
  gtk_label_set_pattern (GTK_LABEL (label),
 
3570
                         "_________________________ _ _________ _ ______     __ _______ ___");
 
3571
  gtk_container_add (GTK_CONTAINER (frame), label);
 
3572
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3573
  
 
3574
  gtk_widget_show_all (window);
 
3575
 
 
3576
  gtk_main ();
 
3577
  
 
3578
  return 0;
 
3579
}
 
3580
<!-- example-end -->
 
3581
</programlisting>
 
3582
 
 
3583
</sect1>
 
3584
 
 
3585
<!-- ----------------------------------------------------------------- -->
 
3586
<sect1 id="sec-Arrows">
 
3587
<title>Arrows</title>
 
3588
 
 
3589
<para>The Arrow widget draws an arrowhead, facing in a number of possible
 
3590
directions and having a number of possible styles. It can be very
 
3591
useful when placed on a button in many applications. Like the Label
 
3592
widget, it emits no signals.</para>
 
3593
 
 
3594
<para>There are only two functions for manipulating an Arrow widget:</para>
 
3595
 
 
3596
<programlisting role="C">
 
3597
GtkWidget *gtk_arrow_new( GtkArrowType   arrow_type,
 
3598
                          GtkShadowType  shadow_type );
 
3599
 
 
3600
void gtk_arrow_set( GtkArrow      *arrow,
 
3601
                    GtkArrowType   arrow_type,
 
3602
                    GtkShadowType  shadow_type );
 
3603
</programlisting>
 
3604
 
 
3605
<para>The first creates a new arrow widget with the indicated type and
 
3606
appearance. The second allows these values to be altered
 
3607
retrospectively. The <literal>arrow_type</literal> argument may take one of the
 
3608
following values:</para>
 
3609
 
 
3610
<programlisting role="C">
 
3611
  GTK_ARROW_UP
 
3612
  GTK_ARROW_DOWN
 
3613
  GTK_ARROW_LEFT
 
3614
  GTK_ARROW_RIGHT
 
3615
</programlisting>
 
3616
 
 
3617
<para>These values obviously indicate the direction in which the arrow will
 
3618
point. The <literal>shadow_type</literal> argument may take one of these values:</para>
 
3619
 
 
3620
<programlisting role="C">
 
3621
  GTK_SHADOW_IN
 
3622
  GTK_SHADOW_OUT (the default)
 
3623
  GTK_SHADOW_ETCHED_IN
 
3624
  GTK_SHADOW_ETCHED_OUT
 
3625
</programlisting>
 
3626
 
 
3627
<para>Here's a brief example to illustrate their use.</para>
 
3628
 
 
3629
<para>
 
3630
<inlinemediaobject>
 
3631
<imageobject>
 
3632
<imagedata fileref="images/arrow.png" format="png">
 
3633
</imageobject>
 
3634
</inlinemediaobject>
 
3635
</para>
 
3636
 
 
3637
<programlisting role="C">
 
3638
<!-- example-start arrow arrow.c -->
 
3639
 
 
3640
#include &lt;gtk/gtk.h&gt;
 
3641
 
 
3642
/* Create an Arrow widget with the specified parameters
 
3643
 * and pack it into a button */
 
3644
static GtkWidget *create_arrow_button( GtkArrowType  arrow_type,
 
3645
                                       GtkShadowType shadow_type )
 
3646
{
 
3647
  GtkWidget *button;
 
3648
  GtkWidget *arrow;
 
3649
 
 
3650
  button = gtk_button_new ();
 
3651
  arrow = gtk_arrow_new (arrow_type, shadow_type);
 
3652
 
 
3653
  gtk_container_add (GTK_CONTAINER (button), arrow);
 
3654
  
 
3655
  gtk_widget_show (button);
 
3656
  gtk_widget_show (arrow);
 
3657
 
 
3658
  return button;
 
3659
}
 
3660
 
 
3661
int main( int   argc,
 
3662
          char *argv[] )
 
3663
{
 
3664
  /* GtkWidget is the storage type for widgets */
 
3665
  GtkWidget *window;
 
3666
  GtkWidget *button;
 
3667
  GtkWidget *box;
 
3668
 
 
3669
  /* Initialize the toolkit */
 
3670
  gtk_init (&amp;argc, &amp;argv);
 
3671
 
 
3672
  /* Create a new window */
 
3673
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
3674
 
 
3675
  gtk_window_set_title (GTK_WINDOW (window), "Arrow Buttons");
 
3676
 
 
3677
  /* It's a good idea to do this for all windows. */
 
3678
  g_signal_connect (G_OBJECT (window), "destroy",
 
3679
                    G_CALLBACK (gtk_main_quit), NULL);
 
3680
 
 
3681
  /* Sets the border width of the window. */
 
3682
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
3683
 
 
3684
  /* Create a box to hold the arrows/buttons */
 
3685
  box = gtk_hbox_new (FALSE, 0);
 
3686
  gtk_container_set_border_width (GTK_CONTAINER (box), 2);
 
3687
  gtk_container_add (GTK_CONTAINER (window), box);
 
3688
 
 
3689
  /* Pack and show all our widgets */
 
3690
  gtk_widget_show (box);
 
3691
 
 
3692
  button = create_arrow_button (GTK_ARROW_UP, GTK_SHADOW_IN);
 
3693
  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
 
3694
 
 
3695
  button = create_arrow_button (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
 
3696
  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
 
3697
  
 
3698
  button = create_arrow_button (GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
 
3699
  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
 
3700
  
 
3701
  button = create_arrow_button (GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
 
3702
  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
 
3703
  
 
3704
  gtk_widget_show (window);
 
3705
  
 
3706
  /* Rest in gtk_main and wait for the fun to begin! */
 
3707
  gtk_main ();
 
3708
  
 
3709
  return 0;
 
3710
}
 
3711
<!-- example-end -->
 
3712
</programlisting>
 
3713
 
 
3714
</sect1>
 
3715
 
 
3716
<!-- ----------------------------------------------------------------- -->
 
3717
<sect1 id="sec-TheTooltipsObject">
 
3718
<title>The Tooltips Object</title>
 
3719
 
 
3720
<para>These are the little text strings that pop up when you leave your
 
3721
pointer over a button or other widget for a few seconds. They are easy
 
3722
to use, so I will just explain them without giving an example. If you
 
3723
want to see some code, take a look at the <filename>testgtk.c</filename> program
 
3724
distributed with GTK.</para>
 
3725
 
 
3726
<para>Widgets that do not receive events (widgets that do not have their
 
3727
own window) will not work with tooltips.</para>
 
3728
 
 
3729
<para>The first call you will use creates a new tooltip. You only need to do
 
3730
this once for a set of tooltips as the <literal>GtkTooltips</literal> object this
 
3731
function returns can be used to create multiple tooltips.</para>
 
3732
 
 
3733
<programlisting role="C">
 
3734
GtkTooltips *gtk_tooltips_new( void );
 
3735
</programlisting>
 
3736
 
 
3737
<para>Once you have created a new tooltip, and the widget you wish to use it
 
3738
on, simply use this call to set it:</para>
 
3739
 
 
3740
<programlisting role="C">
 
3741
void gtk_tooltips_set_tip( GtkTooltips *tooltips,
 
3742
                           GtkWidget   *widget,
 
3743
                           const gchar *tip_text,
 
3744
                           const gchar *tip_private );
 
3745
</programlisting>
 
3746
 
 
3747
<para>The first argument is the tooltip you've already created, followed by
 
3748
the widget you wish to have this tooltip pop up for, and the text you
 
3749
wish it to say. The last argument is a text string that can be used as
 
3750
an identifier when using GtkTipsQuery to implement context sensitive
 
3751
help. For now, you can set it to NULL.</para>
 
3752
 
 
3753
<!-- TODO: sort out what how to do the context sensitive help -->
 
3754
 
 
3755
<para>Here's a short example:</para>
 
3756
 
 
3757
<programlisting role="C">
 
3758
GtkTooltips *tooltips;
 
3759
GtkWidget *button;
 
3760
.
 
3761
.
 
3762
.
 
3763
tooltips = gtk_tooltips_new ();
 
3764
button = gtk_button_new_with_label ("button 1");
 
3765
.
 
3766
.
 
3767
.
 
3768
gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
 
3769
</programlisting>
 
3770
 
 
3771
<para>There are other calls that can be used with tooltips. I will just list
 
3772
them with a brief description of what they do.</para>
 
3773
 
 
3774
<programlisting role="C">
 
3775
void gtk_tooltips_enable( GtkTooltips *tooltips );
 
3776
</programlisting>
 
3777
 
 
3778
<para>Enable a disabled set of tooltips.</para>
 
3779
 
 
3780
<programlisting role="C">
 
3781
void gtk_tooltips_disable( GtkTooltips *tooltips );
 
3782
</programlisting>
 
3783
 
 
3784
<para>Disable an enabled set of tooltips.</para>
 
3785
 
 
3786
<para>And that's all the functions associated with tooltips. More than
 
3787
you'll ever want to know :-)</para>
 
3788
 
 
3789
</sect1>
 
3790
 
 
3791
<!-- ----------------------------------------------------------------- -->
 
3792
<sect1 id="sec-ProgressBars">
 
3793
<title>Progress Bars</title>
 
3794
 
 
3795
<para>Progress bars are used to show the status of an operation. They are
 
3796
pretty easy to use, as you will see with the code below. But first
 
3797
lets start out with the calls to create a new progress bar.</para>
 
3798
 
 
3799
<programlisting role="C">
 
3800
GtkWidget *gtk_progress_bar_new( void );
 
3801
</programlisting>
 
3802
 
 
3803
<para>Now that the progress bar has been created we can use it.</para>
 
3804
 
 
3805
<programlisting role="C">
 
3806
void gtk_progress_bar_set_fraction ( GtkProgressBar *pbar,
 
3807
                                     gdouble        fraction );
 
3808
</programlisting>
 
3809
 
 
3810
<para>The first argument is the progress bar you wish to operate on, and the
 
3811
second argument is the amount "completed", meaning the amount the
 
3812
progress bar has been filled from 0-100%. This is passed to the
 
3813
function as a real number ranging from 0 to 1.</para>
 
3814
 
 
3815
<para>GTK v1.2 has added new functionality to the progress bar that enables
 
3816
it to display its value in different ways, and to inform the user of
 
3817
its current value and its range.</para>
 
3818
 
 
3819
<para>A progress bar may be set to one of a number of orientations using the
 
3820
function</para>
 
3821
 
 
3822
<programlisting role="C">
 
3823
void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
 
3824
                                       GtkProgressBarOrientation orientation );
 
3825
</programlisting>
 
3826
 
 
3827
<para>The <literal>orientation</literal> argument may take one of the following
 
3828
values to indicate the direction in which the progress bar moves:</para>
 
3829
 
 
3830
<programlisting role="C">
 
3831
  GTK_PROGRESS_LEFT_TO_RIGHT
 
3832
  GTK_PROGRESS_RIGHT_TO_LEFT
 
3833
  GTK_PROGRESS_BOTTOM_TO_TOP
 
3834
  GTK_PROGRESS_TOP_TO_BOTTOM
 
3835
</programlisting>
 
3836
 
 
3837
<para>As well as indicating the amount of progress that has occured, the
 
3838
progress bar may be set to just indicate that there is some activity. 
 
3839
This can be useful in situations where progress cannot be measured against 
 
3840
a value range. The following function indicates that some progress has been 
 
3841
made.</para>
 
3842
 
 
3843
<programlisting role="C">
 
3844
void gtk_progress_bar_pulse ( GtkProgressBar *progress );
 
3845
</programlisting>
 
3846
 
 
3847
<para>The step size of the activity indicator is set using the following 
 
3848
function.</para>
 
3849
 
 
3850
<programlisting role="C">
 
3851
void gtk_progress_bar_set_pulse_step( GtkProgressBar *pbar,
 
3852
                                      gdouble         fraction );
 
3853
</programlisting>
 
3854
 
 
3855
<para>When not in activity mode, the progress bar can also display a
 
3856
configurable text string within its trough, using the following
 
3857
function.</para>
 
3858
 
 
3859
<programlisting role="C">
 
3860
void gtk_progress_bar_set_text( GtkProgressBar *progress,
 
3861
                                const gchar    *text );
 
3862
</programlisting>
 
3863
 
 
3864
<note><para>Note that gtk_progress_set_text() doesn't support the printf()-like formatting
 
3865
of the GTK+ 1.2 Progressbar.</para></note>
 
3866
 
 
3867
<para>You can turn off the display of the string by calling gtk_progess_bar_set_text()
 
3868
again with NULL as second argument.</para>
 
3869
 
 
3870
<para>The current text setting of a progressbar can be retrieved with the 
 
3871
following function. Do not free the returned string.</para>
 
3872
 
 
3873
<programlisting role="C">
 
3874
const gchar *gtk_progress_bar_get_text( GtkProgressBar *pbar );
 
3875
</programlisting>
 
3876
 
 
3877
<para>Progress Bars are usually used with timeouts or other such functions
 
3878
(see section on <link linkend="ch-Timeouts">Timeouts, I/O and Idle Functions</link>) 
 
3879
to give the illusion of multitasking. All will employ the
 
3880
gtk_progress_bar_set_fraction() or gtk_progress_bar_pulse() functions in the 
 
3881
same manner.</para>
 
3882
 
 
3883
<para>Here is an example of the progress bar, updated using timeouts. This
 
3884
code also shows you how to reset the Progress Bar.</para>
 
3885
 
 
3886
<para>
 
3887
<inlinemediaobject>
 
3888
<imageobject>
 
3889
<imagedata fileref="images/progressbar.png" format="png">
 
3890
</imageobject>
 
3891
</inlinemediaobject>
 
3892
</para>
 
3893
 
 
3894
<programlisting role="C">
 
3895
<!-- example-start progressbar progressbar.c -->
 
3896
 
 
3897
#include &lt;gtk/gtk.h&gt;
 
3898
 
 
3899
typedef struct _ProgressData {
 
3900
  GtkWidget *window;
 
3901
  GtkWidget *pbar;
 
3902
  int timer;
 
3903
  gboolean activity_mode;
 
3904
} ProgressData;
 
3905
 
 
3906
/* Update the value of the progress bar so that we get
 
3907
 * some movement */
 
3908
static gboolean progress_timeout( gpointer data )
 
3909
{
 
3910
  ProgressData *pdata = (ProgressData *)data;
 
3911
  gdouble new_val;
 
3912
  
 
3913
  if (pdata-&gt;activity_mode) 
 
3914
    gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata-&gt;pbar));
 
3915
  else 
 
3916
    {
 
3917
      /* Calculate the value of the progress bar using the
 
3918
       * value range set in the adjustment object */
 
3919
      
 
3920
      new_val = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (pdata-&gt;pbar)) + 0.01;
 
3921
      
 
3922
      if (new_val &gt; 1.0)
 
3923
        new_val = 0.0;
 
3924
      
 
3925
      /* Set the new value */
 
3926
      gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata-&gt;pbar), new_val);
 
3927
    }
 
3928
  
 
3929
  /* As this is a timeout function, return TRUE so that it
 
3930
   * continues to get called */
 
3931
  return TRUE;
 
3932
 
3933
 
 
3934
/* Callback that toggles the text display within the progress bar trough */
 
3935
static void toggle_show_text( GtkWidget    *widget,
 
3936
                              ProgressData *pdata )
 
3937
{
 
3938
  const gchar *text;
 
3939
  
 
3940
  text = gtk_progress_bar_get_text (GTK_PROGRESS_BAR (pdata-&gt;pbar));
 
3941
  if (text &amp;&amp; *text)
 
3942
    gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata-&gt;pbar), "");
 
3943
  else 
 
3944
    gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata-&gt;pbar), "some text");
 
3945
}
 
3946
 
 
3947
/* Callback that toggles the activity mode of the progress bar */
 
3948
static void toggle_activity_mode( GtkWidget    *widget,
 
3949
                                  ProgressData *pdata )
 
3950
{
 
3951
  pdata-&gt;activity_mode = !pdata-&gt;activity_mode;
 
3952
  if (pdata-&gt;activity_mode) 
 
3953
      gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata-&gt;pbar));
 
3954
  else
 
3955
      gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata-&gt;pbar), 0.0);
 
3956
}
 
3957
 
 
3958
 
 
3959
/* Callback that toggles the orientation of the progress bar */
 
3960
static void toggle_orientation( GtkWidget    *widget,
 
3961
                                ProgressData *pdata )
 
3962
{
 
3963
  switch (gtk_progress_bar_get_orientation (GTK_PROGRESS_BAR (pdata-&gt;pbar))) {
 
3964
  case GTK_PROGRESS_LEFT_TO_RIGHT:
 
3965
    gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata-&gt;pbar), 
 
3966
                                      GTK_PROGRESS_RIGHT_TO_LEFT);
 
3967
    break;
 
3968
  case GTK_PROGRESS_RIGHT_TO_LEFT:
 
3969
    gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata-&gt;pbar), 
 
3970
                                      GTK_PROGRESS_LEFT_TO_RIGHT);
 
3971
    break;
 
3972
  default:;
 
3973
    /* do nothing */
 
3974
  }
 
3975
}
 
3976
 
 
3977
 
 
3978
/* Clean up allocated memory and remove the timer */
 
3979
static void destroy_progress( GtkWidget    *widget,
 
3980
                              ProgressData *pdata)
 
3981
{
 
3982
    g_source_remove (pdata-&gt;timer);
 
3983
    pdata-&gt;timer = 0;
 
3984
    pdata-&gt;window = NULL;
 
3985
    g_free (pdata);
 
3986
    gtk_main_quit ();
 
3987
}
 
3988
 
 
3989
int main( int   argc,
 
3990
          char *argv[])
 
3991
{
 
3992
    ProgressData *pdata;
 
3993
    GtkWidget *align;
 
3994
    GtkWidget *separator;
 
3995
    GtkWidget *table;
 
3996
    GtkWidget *button;
 
3997
    GtkWidget *check;
 
3998
    GtkWidget *vbox;
 
3999
 
 
4000
    gtk_init (&amp;argc, &amp;argv);
 
4001
 
 
4002
    /* Allocate memory for the data that is passed to the callbacks */
 
4003
    pdata = g_malloc (sizeof (ProgressData));
 
4004
  
 
4005
    pdata-&gt;window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
4006
    gtk_window_set_resizable (GTK_WINDOW (pdata-&gt;window), TRUE);
 
4007
 
 
4008
    g_signal_connect (G_OBJECT (pdata-&gt;window), "destroy",
 
4009
                      G_CALLBACK (destroy_progress),
 
4010
                      (gpointer) pdata);
 
4011
    gtk_window_set_title (GTK_WINDOW (pdata-&gt;window), "GtkProgressBar");
 
4012
    gtk_container_set_border_width (GTK_CONTAINER (pdata-&gt;window), 0);
 
4013
 
 
4014
    vbox = gtk_vbox_new (FALSE, 5);
 
4015
    gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
 
4016
    gtk_container_add (GTK_CONTAINER (pdata-&gt;window), vbox);
 
4017
    gtk_widget_show (vbox);
 
4018
  
 
4019
    /* Create a centering alignment object */
 
4020
    align = gtk_alignment_new (0.5, 0.5, 0, 0);
 
4021
    gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
 
4022
    gtk_widget_show (align);
 
4023
 
 
4024
    /* Create the GtkProgressBar */
 
4025
    pdata-&gt;pbar = gtk_progress_bar_new ();
 
4026
    pdata-&gt;activity_mode = FALSE;
 
4027
 
 
4028
    gtk_container_add (GTK_CONTAINER (align), pdata-&gt;pbar);
 
4029
    gtk_widget_show (pdata-&gt;pbar);
 
4030
 
 
4031
    /* Add a timer callback to update the value of the progress bar */
 
4032
    pdata-&gt;timer = g_timeout_add (100, progress_timeout, pdata);
 
4033
 
 
4034
    separator = gtk_hseparator_new ();
 
4035
    gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
 
4036
    gtk_widget_show (separator);
 
4037
 
 
4038
    /* rows, columns, homogeneous */
 
4039
    table = gtk_table_new (2, 3, FALSE);
 
4040
    gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
 
4041
    gtk_widget_show (table);
 
4042
 
 
4043
    /* Add a check button to select displaying of the trough text */
 
4044
    check = gtk_check_button_new_with_label ("Show text");
 
4045
    gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
 
4046
                      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
 
4047
                      5, 5);
 
4048
    g_signal_connect (G_OBJECT (check), "clicked",
 
4049
                      G_CALLBACK (toggle_show_text),
 
4050
                      (gpointer) pdata);
 
4051
    gtk_widget_show (check);
 
4052
 
 
4053
    /* Add a check button to toggle activity mode */
 
4054
    check = gtk_check_button_new_with_label ("Activity mode");
 
4055
    gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
 
4056
                      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
 
4057
                      5, 5);
 
4058
    g_signal_connect (G_OBJECT (check), "clicked",
 
4059
                      G_CALLBACK (toggle_activity_mode),
 
4060
                      (gpointer) pdata);
 
4061
    gtk_widget_show (check);
 
4062
 
 
4063
    /* Add a check button to toggle orientation */
 
4064
    check = gtk_check_button_new_with_label ("Right to Left");
 
4065
    gtk_table_attach (GTK_TABLE (table), check, 0, 1, 2, 3,
 
4066
                      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
 
4067
                      5, 5);
 
4068
    g_signal_connect (G_OBJECT (check), "clicked",
 
4069
                      G_CALLBACK (toggle_orientation),
 
4070
                      (gpointer) pdata);
 
4071
    gtk_widget_show (check);
 
4072
 
 
4073
    /* Add a button to exit the program */
 
4074
    button = gtk_button_new_with_label ("close");
 
4075
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
4076
                              G_CALLBACK (gtk_widget_destroy),
 
4077
                              G_OBJECT (pdata-&gt;window));
 
4078
    gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
 
4079
 
 
4080
    /* This makes it so the button is the default. */
 
4081
    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
4082
 
 
4083
    /* This grabs this button to be the default button. Simply hitting
 
4084
     * the "Enter" key will cause this button to activate. */
 
4085
    gtk_widget_grab_default (button);
 
4086
    gtk_widget_show (button);
 
4087
 
 
4088
    gtk_widget_show (pdata-&gt;window);
 
4089
 
 
4090
    gtk_main ();
 
4091
    
 
4092
    return 0;
 
4093
}
 
4094
<!-- example-end -->
 
4095
</programlisting>
 
4096
 
 
4097
</sect1>
 
4098
 
 
4099
<!-- ----------------------------------------------------------------- -->
 
4100
<sect1 id="sec-Dialogs">
 
4101
<title>Dialogs</title>
 
4102
 
 
4103
<para>The Dialog widget is very simple, and is actually just a window with a
 
4104
few things pre-packed into it for you. The structure for a Dialog is:</para>
 
4105
 
 
4106
<programlisting role="C">
 
4107
struct GtkDialog
 
4108
{
 
4109
      GtkWindow window;
 
4110
    
 
4111
      GtkWidget *vbox;
 
4112
      GtkWidget *action_area;
 
4113
};
 
4114
</programlisting>
 
4115
 
 
4116
<para>So you see, it simply creates a window, and then packs a vbox into the
 
4117
top, which contains a separator and then an hbox called the
 
4118
"action_area".</para>
 
4119
 
 
4120
<para>The Dialog widget can be used for pop-up messages to the user, and
 
4121
other similar tasks. There are two functions to create a new Dialog.</para>
 
4122
 
 
4123
<programlisting role="C">
 
4124
GtkWidget *gtk_dialog_new( void );
 
4125
 
 
4126
GtkWidget *gtk_dialog_new_with_buttons( const gchar    *title,
 
4127
                                        GtkWindow      *parent,
 
4128
                                        GtkDialogFlags  flags, 
 
4129
                                        const gchar    *first_button_text,
 
4130
                                        ... );
 
4131
</programlisting>
 
4132
 
 
4133
<para>The first function will create an empty dialog, and it is now up to you to use
 
4134
 it. You could pack a button in the action_area by doing something like this:</para>
 
4135
 
 
4136
<programlisting role="C">
 
4137
    button = ...
 
4138
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
 
4139
                        button, TRUE, TRUE, 0);
 
4140
    gtk_widget_show (button);
 
4141
</programlisting>
 
4142
 
 
4143
<para>And you could add to the vbox area by packing, for instance, a label 
 
4144
in it, try something like this:</para>
 
4145
 
 
4146
<programlisting role="C">
 
4147
    label = gtk_label_new ("Dialogs are groovy");
 
4148
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
 
4149
                        label, TRUE, TRUE, 0);
 
4150
    gtk_widget_show (label);
 
4151
</programlisting>
 
4152
 
 
4153
<para>As an example in using the dialog box, you could put two buttons in
 
4154
the action_area, a Cancel button and an Ok button, and a label in the
 
4155
vbox area, asking the user a question or giving an error etc. Then
 
4156
you could attach a different signal to each of the buttons and perform
 
4157
the operation the user selects.</para>
 
4158
 
 
4159
<para>If the simple functionality provided by the default vertical and
 
4160
horizontal boxes in the two areas doesn't give you enough control for
 
4161
your application, then you can simply pack another layout widget into
 
4162
the boxes provided. For example, you could pack a table into the
 
4163
vertical box.</para>
 
4164
 
 
4165
<para>The more complicated _new_with_buttons() variant allows to set one or
 
4166
more of the following flags.</para>
 
4167
 
 
4168
<variablelist>
 
4169
<varlistentry>
 
4170
<term><literal>GTK_DIALOG_MODAL</literal></term>
 
4171
<listitem><para>make the dialog modal.
 
4172
</para></listitem>
 
4173
</varlistentry>
 
4174
<varlistentry>
 
4175
<term><literal>GTK_DIALOG_DESTROY_WITH_PARENT</literal></term>
 
4176
<listitem><para>ensures that the dialog window is destroyed together with the specified
 
4177
parent.</para></listitem>
 
4178
</varlistentry>
 
4179
<varlistentry>
 
4180
<term><literal>GTK_DIALOG_NO_SEPARATOR</literal></term>
 
4181
<listitem><para>omits the separator between the vbox and the action_area.
 
4182
</para></listitem>
 
4183
</varlistentry>
 
4184
</variablelist>
 
4185
</sect1>
 
4186
 
 
4187
<!-- ----------------------------------------------------------------- -->
 
4188
<sect1 id="sec-Rulers">
 
4189
<title>Rulers</title>
 
4190
 
 
4191
<para>Ruler widgets are used to indicate the location of the mouse pointer
 
4192
in a given window. A window can have a vertical ruler spanning across
 
4193
the height and a horizontal ruler spanning down the width. A small
 
4194
triangular indicator on the ruler shows the exact location of the
 
4195
pointer relative to the ruler.</para>
 
4196
 
 
4197
<para>A ruler must first be created. Horizontal and vertical rulers are
 
4198
created using</para>
 
4199
 
 
4200
<programlisting role="C">
 
4201
GtkWidget *gtk_hruler_new( void );    /* horizontal ruler */
 
4202
 
 
4203
GtkWidget *gtk_vruler_new( void );    /* vertical ruler   */
 
4204
</programlisting>
 
4205
 
 
4206
<para>Once a ruler is created, we can define the unit of measurement. Units
 
4207
of measure for rulers can be<literal>GTK_PIXELS</literal>, <literal>GTK_INCHES</literal> or
 
4208
<literal>GTK_CENTIMETERS</literal>. This is set using</para>
 
4209
 
 
4210
<programlisting role="C">
 
4211
void gtk_ruler_set_metric( GtkRuler      *ruler,
 
4212
                           GtkMetricType  metric );
 
4213
</programlisting>
 
4214
 
 
4215
<para>The default measure is <literal>GTK_PIXELS</literal>.</para>
 
4216
 
 
4217
<programlisting role="C">
 
4218
    gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
 
4219
</programlisting>
 
4220
 
 
4221
<para>Other important characteristics of a ruler are how to mark the units
 
4222
of scale and where the position indicator is initially placed. These
 
4223
are set for a ruler using</para>
 
4224
 
 
4225
<programlisting role="C">
 
4226
void gtk_ruler_set_range( GtkRuler *ruler,
 
4227
                          gdouble   lower,
 
4228
                          gdouble   upper,
 
4229
                          gdouble   position,
 
4230
                          gdouble   max_size );
 
4231
</programlisting>
 
4232
 
 
4233
<para>The lower and upper arguments define the extent of the ruler, and
 
4234
max_size is the largest possible number that will be displayed.
 
4235
Position defines the initial position of the pointer indicator within
 
4236
the ruler.</para>
 
4237
 
 
4238
<para>A vertical ruler can span an 800 pixel wide window thus</para>
 
4239
 
 
4240
<programlisting role="C">
 
4241
    gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
 
4242
</programlisting>
 
4243
 
 
4244
<para>The markings displayed on the ruler will be from 0 to 800, with a
 
4245
number for every 100 pixels. If instead we wanted the ruler to range
 
4246
from 7 to 16, we would code</para>
 
4247
 
 
4248
<programlisting role="C">
 
4249
    gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
 
4250
</programlisting>
 
4251
 
 
4252
<para>The indicator on the ruler is a small triangular mark that indicates
 
4253
the position of the pointer relative to the ruler. If the ruler is
 
4254
used to follow the mouse pointer, the motion_notify_event signal
 
4255
should be connected to the motion_notify_event method of the ruler.
 
4256
To follow all mouse movements within a window area, we would use</para>
 
4257
 
 
4258
<programlisting role="C">
 
4259
#define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)->x
 
4260
 
 
4261
    g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
 
4262
           G_CALLBACK (EVENT_METHOD (ruler, motion_notify_event)),
 
4263
           G_OBJECT (ruler));
 
4264
</programlisting>
 
4265
 
 
4266
<para>The following example creates a drawing area with a horizontal ruler
 
4267
above it and a vertical ruler to the left of it. The size of the
 
4268
drawing area is 600 pixels wide by 400 pixels high. The horizontal
 
4269
ruler spans from 7 to 13 with a mark every 100 pixels, while the
 
4270
vertical ruler spans from 0 to 400 with a mark every 100 pixels.
 
4271
Placement of the drawing area and the rulers is done using a table.</para>
 
4272
 
 
4273
<para>
 
4274
<inlinemediaobject>
 
4275
<imageobject>
 
4276
<imagedata fileref="images/rulers.png" format="png">
 
4277
</imageobject>
 
4278
</inlinemediaobject>
 
4279
</para>
 
4280
 
 
4281
<programlisting role="C">
 
4282
<!-- example-start rulers rulers.c -->
 
4283
 
 
4284
#include &lt;gtk/gtk.h&gt;
 
4285
 
 
4286
#define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)-&gt;x
 
4287
 
 
4288
#define XSIZE  600
 
4289
#define YSIZE  400
 
4290
 
 
4291
/* This routine gets control when the close button is clicked */
 
4292
static gboolean close_application( GtkWidget *widget,
 
4293
                                   GdkEvent  *event,
 
4294
                                   gpointer   data )
 
4295
{
 
4296
    gtk_main_quit ();
 
4297
    return FALSE;
 
4298
}
 
4299
 
 
4300
/* The main routine */
 
4301
int main( int   argc,
 
4302
          char *argv[] ) {
 
4303
    GtkWidget *window, *table, *area, *hrule, *vrule;
 
4304
 
 
4305
    /* Initialize GTK and create the main window */
 
4306
    gtk_init (&amp;argc, &amp;argv);
 
4307
 
 
4308
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
4309
    g_signal_connect (G_OBJECT (window), "delete_event",
 
4310
                      G_CALLBACK (close_application), NULL);
 
4311
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
4312
 
 
4313
    /* Create a table for placing the ruler and the drawing area */
 
4314
    table = gtk_table_new (3, 2, FALSE);
 
4315
    gtk_container_add (GTK_CONTAINER (window), table);
 
4316
 
 
4317
    area = gtk_drawing_area_new ();
 
4318
    gtk_widget_set_size_request (GTK_WIDGET (area), XSIZE, YSIZE);
 
4319
    gtk_table_attach (GTK_TABLE (table), area, 1, 2, 1, 2,
 
4320
                      GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
 
4321
    gtk_widget_set_events (area, GDK_POINTER_MOTION_MASK |
 
4322
                                 GDK_POINTER_MOTION_HINT_MASK);
 
4323
 
 
4324
    /* The horizontal ruler goes on top. As the mouse moves across the
 
4325
     * drawing area, a motion_notify_event is passed to the
 
4326
     * appropriate event handler for the ruler. */
 
4327
    hrule = gtk_hruler_new ();
 
4328
    gtk_ruler_set_metric (GTK_RULER (hrule), GTK_PIXELS);
 
4329
    gtk_ruler_set_range (GTK_RULER (hrule), 7, 13, 0, 20);
 
4330
    g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
 
4331
                              G_CALLBACK (EVENT_METHOD (hrule, motion_notify_event)),
 
4332
                              G_OBJECT (hrule));
 
4333
    gtk_table_attach (GTK_TABLE (table), hrule, 1, 2, 0, 1,
 
4334
                      GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0);
 
4335
    
 
4336
    /* The vertical ruler goes on the left. As the mouse moves across
 
4337
     * the drawing area, a motion_notify_event is passed to the
 
4338
     * appropriate event handler for the ruler. */
 
4339
    vrule = gtk_vruler_new ();
 
4340
    gtk_ruler_set_metric (GTK_RULER (vrule), GTK_PIXELS);
 
4341
    gtk_ruler_set_range (GTK_RULER (vrule), 0, YSIZE, 10, YSIZE );
 
4342
    g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
 
4343
                              G_CALLBACK (EVENT_METHOD (vrule, motion_notify_event)),
 
4344
                              G_OBJECT (vrule));
 
4345
    gtk_table_attach (GTK_TABLE (table), vrule, 0, 1, 1, 2,
 
4346
                      GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0);
 
4347
 
 
4348
    /* Now show everything */
 
4349
    gtk_widget_show (area);
 
4350
    gtk_widget_show (hrule);
 
4351
    gtk_widget_show (vrule);
 
4352
    gtk_widget_show (table);
 
4353
    gtk_widget_show (window);
 
4354
    gtk_main ();
 
4355
 
 
4356
    return 0;
 
4357
}
 
4358
<!-- example-end -->
 
4359
</programlisting>
 
4360
 
 
4361
</sect1>
 
4362
 
 
4363
<!-- ----------------------------------------------------------------- -->
 
4364
<sect1 id="sec-Statusbars">
 
4365
<title>Statusbars</title>
 
4366
 
 
4367
<para>Statusbars are simple widgets used to display a text message. They
 
4368
keep a stack of the messages pushed onto them, so that popping the
 
4369
current message will re-display the previous text message.</para>
 
4370
 
 
4371
<para>In order to allow different parts of an application to use the same
 
4372
statusbar to display messages, the statusbar widget issues Context
 
4373
Identifiers which are used to identify different "users". The message
 
4374
on top of the stack is the one displayed, no matter what context it is
 
4375
in. Messages are stacked in last-in-first-out order, not context
 
4376
identifier order.</para>
 
4377
 
 
4378
<para>A statusbar is created with a call to:</para>
 
4379
 
 
4380
<programlisting role="C">
 
4381
GtkWidget *gtk_statusbar_new( void );
 
4382
</programlisting>
 
4383
 
 
4384
<para>A new Context Identifier is requested using a call to the following 
 
4385
function with a short textual description of the context:</para>
 
4386
 
 
4387
<programlisting role="C">
 
4388
guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
 
4389
                                    const gchar  *context_description );
 
4390
</programlisting>
 
4391
 
 
4392
<para>There are three functions that can operate on statusbars:</para>
 
4393
 
 
4394
<programlisting role="C">
 
4395
guint gtk_statusbar_push( GtkStatusbar *statusbar,
 
4396
                          guint         context_id,
 
4397
                          const gchar  *text );
 
4398
 
 
4399
void gtk_statusbar_pop( GtkStatusbar *statusbar)
 
4400
                        guint         context_id );
 
4401
 
 
4402
void gtk_statusbar_remove( GtkStatusbar *statusbar,
 
4403
                           guint         context_id,
 
4404
                           guint         message_id ); 
 
4405
</programlisting>
 
4406
 
 
4407
<para>The first, gtk_statusbar_push(), is used to add a new message to the
 
4408
statusbar.  It returns a Message Identifier, which can be passed later
 
4409
to the function gtk_statusbar_remove to remove the message with the
 
4410
given Message and Context Identifiers from the statusbar's stack.</para>
 
4411
 
 
4412
<para>The function gtk_statusbar_pop() removes the message highest in the
 
4413
stack with the given Context Identifier.</para>
 
4414
 
 
4415
<para>In addition to messages, statusbars may also display a resize grip, which 
 
4416
can be dragged with the mouse to resize the toplevel window containing the statusbar,
 
4417
similar to dragging the window frame. The following functions control the display
 
4418
of the resize grip.</para>
 
4419
 
 
4420
<programlisting role="C">
 
4421
void     gtk_statusbar_set_has_resize_grip( GtkStatusbar *statusbar,
 
4422
                                            gboolean      setting );
 
4423
 
 
4424
gboolean gtk_statusbar_get_has_resize_grip( GtkStatusbar *statusbar );
 
4425
</programlisting>
 
4426
 
 
4427
<para>The following example creates a statusbar and two buttons, one for
 
4428
pushing items onto the statusbar, and one for popping the last item
 
4429
back off.</para>
 
4430
 
 
4431
<para>
 
4432
<inlinemediaobject>
 
4433
<imageobject>
 
4434
<imagedata fileref="images/statusbar.png" format="png">
 
4435
</imageobject>
 
4436
</inlinemediaobject>
 
4437
</para>
 
4438
 
 
4439
<programlisting role="C">
 
4440
<!-- example-start statusbar statusbar.c -->
 
4441
 
 
4442
#include &lt;stdlib.h&gt;
 
4443
#include &lt;gtk/gtk.h&gt;
 
4444
#include &lt;glib.h&gt;
 
4445
 
 
4446
GtkWidget *status_bar;
 
4447
 
 
4448
static void push_item( GtkWidget *widget,
 
4449
                       gpointer   data )
 
4450
{
 
4451
  static int count = 1;
 
4452
  gchar *buff;
 
4453
 
 
4454
  buff = g_strdup_printf ("Item %d", count++);
 
4455
  gtk_statusbar_push (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data), buff);
 
4456
  g_free (buff);
 
4457
}
 
4458
 
 
4459
static void pop_item( GtkWidget *widget,
 
4460
                      gpointer   data )
 
4461
{
 
4462
  gtk_statusbar_pop (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data));
 
4463
}
 
4464
 
 
4465
int main( int   argc,
 
4466
          char *argv[] )
 
4467
{
 
4468
 
 
4469
    GtkWidget *window;
 
4470
    GtkWidget *vbox;
 
4471
    GtkWidget *button;
 
4472
 
 
4473
    gint context_id;
 
4474
 
 
4475
    gtk_init (&amp;argc, &amp;argv);
 
4476
 
 
4477
    /* create a new window */
 
4478
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
4479
    gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
 
4480
    gtk_window_set_title (GTK_WINDOW (window), "GTK Statusbar Example");
 
4481
    g_signal_connect (G_OBJECT (window), "delete_event",
 
4482
                      G_CALLBACK (exit), NULL);
 
4483
 
 
4484
    vbox = gtk_vbox_new (FALSE, 1);
 
4485
    gtk_container_add (GTK_CONTAINER (window), vbox);
 
4486
    gtk_widget_show (vbox);
 
4487
          
 
4488
    status_bar = gtk_statusbar_new ();      
 
4489
    gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
 
4490
    gtk_widget_show (status_bar);
 
4491
 
 
4492
    context_id = gtk_statusbar_get_context_id(
 
4493
                          GTK_STATUSBAR (status_bar), "Statusbar example");
 
4494
 
 
4495
    button = gtk_button_new_with_label ("push item");
 
4496
    g_signal_connect (G_OBJECT (button), "clicked",
 
4497
                      G_CALLBACK (push_item), GINT_TO_POINTER (context_id));
 
4498
    gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
 
4499
    gtk_widget_show (button);              
 
4500
 
 
4501
    button = gtk_button_new_with_label ("pop last item");
 
4502
    g_signal_connect (G_OBJECT (button), "clicked",
 
4503
                      G_CALLBACK (pop_item), GINT_TO_POINTER (context_id));
 
4504
    gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
 
4505
    gtk_widget_show (button);
 
4506
 
 
4507
    /* always display the window as the last step so it all splashes on
 
4508
     * the screen at once. */
 
4509
    gtk_widget_show (window);
 
4510
 
 
4511
    gtk_main ();
 
4512
 
 
4513
    return 0;
 
4514
}
 
4515
<!-- example-end -->
 
4516
</programlisting>
 
4517
 
 
4518
</sect1>
 
4519
 
 
4520
<!-- ----------------------------------------------------------------- -->
 
4521
<sect1 id="sec-TextEntries">
 
4522
<title>Text Entries</title>
 
4523
 
 
4524
<para>The Entry widget allows text to be typed and displayed in a single line
 
4525
text box. The text may be set with function calls that allow new text
 
4526
to replace, prepend or append the current contents of the Entry widget.</para>
 
4527
 
 
4528
<para>Create a new Entry widget with the following function.</para>
 
4529
 
 
4530
<programlisting role="C">
 
4531
GtkWidget *gtk_entry_new( void );
 
4532
</programlisting>
 
4533
 
 
4534
<para>The next function alters the text which is currently
 
4535
within the Entry widget.</para>
 
4536
 
 
4537
<programlisting role="C">
 
4538
void gtk_entry_set_text( GtkEntry    *entry,
 
4539
                         const gchar *text );
 
4540
</programlisting>
 
4541
 
 
4542
<para>The function gtk_entry_set_text() sets the contents of the Entry widget,
 
4543
replacing the current contents. Note that the class Entry implements the Editable
 
4544
interface (yes, gobject supports Java-like interfaces) which contains some more
 
4545
functions for manipulating the contents.
 
4546
 </para>
 
4547
 
 
4548
<para>The contents of the Entry can be retrieved by using a call to the
 
4549
following function. This is useful in the callback functions described below.</para>
 
4550
 
 
4551
<programlisting role="C">
 
4552
const gchar *gtk_entry_get_text( GtkEntry *entry );
 
4553
</programlisting>
 
4554
 
 
4555
<para>The value returned by this function is used internally, and must not
 
4556
be freed using either free() or g_free().</para>
 
4557
 
 
4558
<para>If we don't want the contents of the Entry to be changed by someone typing
 
4559
into it, we can change its editable state.</para>
 
4560
 
 
4561
<programlisting role="C">
 
4562
void gtk_editable_set_editable( GtkEditable *entry,
 
4563
                                gboolean     editable );
 
4564
</programlisting>
 
4565
 
 
4566
<para>The function above allows us to toggle the editable state of the
 
4567
Entry widget by passing in a TRUE or FALSE value for the <literal>editable</literal>
 
4568
argument.</para>
 
4569
 
 
4570
<para>If we are using the Entry where we don't want the text entered to be
 
4571
visible, for example when a password is being entered, we can use the
 
4572
following function, which also takes a boolean flag.</para>
 
4573
 
 
4574
<programlisting role="C">
 
4575
void gtk_entry_set_visibility( GtkEntry *entry,
 
4576
                               gboolean  visible );
 
4577
</programlisting>
 
4578
 
 
4579
<para>A region of the text may be set as selected by using the following
 
4580
function. This would most often be used after setting some default
 
4581
text in an Entry, making it easy for the user to remove it.</para>
 
4582
 
 
4583
<programlisting role="C">
 
4584
void gtk_editable_select_region( GtkEditable *entry,
 
4585
                                 gint         start,
 
4586
                                 gint         end );
 
4587
</programlisting>
 
4588
 
 
4589
<para>If we want to catch when the user has entered text, we can connect to
 
4590
the <literal>activate</literal> or <literal>changed</literal> signal. Activate is raised when the
 
4591
user hits the enter key within the Entry widget. Changed is raised
 
4592
when the text changes at all, e.g., for every character entered or
 
4593
removed.</para>
 
4594
 
 
4595
<para>The following code is an example of using an Entry widget.</para>
 
4596
 
 
4597
<para>
 
4598
<inlinemediaobject>
 
4599
<imageobject>
 
4600
<imagedata fileref="images/entry.png" format="png">
 
4601
</imageobject>
 
4602
</inlinemediaobject>
 
4603
</para>
 
4604
 
 
4605
<programlisting role="C">
 
4606
<!-- example-start entry entry.c -->
 
4607
 
 
4608
#include &lt;stdio.h&gt;
 
4609
#include &lt;stdlib.h&gt;
 
4610
#include &lt;gtk/gtk.h&gt;
 
4611
 
 
4612
static void enter_callback( GtkWidget *widget,
 
4613
                            GtkWidget *entry )
 
4614
{
 
4615
  const gchar *entry_text;
 
4616
  entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
 
4617
  printf ("Entry contents: %s\n", entry_text);
 
4618
}
 
4619
 
 
4620
static void entry_toggle_editable( GtkWidget *checkbutton,
 
4621
                                   GtkWidget *entry )
 
4622
{
 
4623
  gtk_editable_set_editable (GTK_EDITABLE (entry),
 
4624
                             GTK_TOGGLE_BUTTON (checkbutton)-&gt;active);
 
4625
}
 
4626
 
 
4627
static void entry_toggle_visibility( GtkWidget *checkbutton,
 
4628
                                     GtkWidget *entry )
 
4629
{
 
4630
  gtk_entry_set_visibility (GTK_ENTRY (entry),
 
4631
                            GTK_TOGGLE_BUTTON (checkbutton)-&gt;active);
 
4632
}
 
4633
 
 
4634
int main( int   argc,
 
4635
          char *argv[] )
 
4636
{
 
4637
 
 
4638
    GtkWidget *window;
 
4639
    GtkWidget *vbox, *hbox;
 
4640
    GtkWidget *entry;
 
4641
    GtkWidget *button;
 
4642
    GtkWidget *check;
 
4643
    gint tmp_pos;
 
4644
 
 
4645
    gtk_init (&amp;argc, &amp;argv);
 
4646
 
 
4647
    /* create a new window */
 
4648
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
4649
    gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
 
4650
    gtk_window_set_title (GTK_WINDOW (window), "GTK Entry");
 
4651
    g_signal_connect (G_OBJECT (window), "destroy",
 
4652
                      G_CALLBACK (gtk_main_quit), NULL);
 
4653
    g_signal_connect_swapped (G_OBJECT (window), "delete_event",
 
4654
                              G_CALLBACK (gtk_widget_destroy), 
 
4655
                              G_OBJECT (window));
 
4656
 
 
4657
    vbox = gtk_vbox_new (FALSE, 0);
 
4658
    gtk_container_add (GTK_CONTAINER (window), vbox);
 
4659
    gtk_widget_show (vbox);
 
4660
 
 
4661
    entry = gtk_entry_new ();
 
4662
    gtk_entry_set_max_length (GTK_ENTRY (entry), 50);
 
4663
    g_signal_connect (G_OBJECT (entry), "activate",
 
4664
                      G_CALLBACK (enter_callback),
 
4665
                      (gpointer) entry);
 
4666
    gtk_entry_set_text (GTK_ENTRY (entry), "hello");
 
4667
    tmp_pos = GTK_ENTRY (entry)-&gt;text_length;
 
4668
    gtk_editable_insert_text (GTK_EDITABLE (entry), " world", -1, &amp;tmp_pos);
 
4669
    gtk_editable_select_region (GTK_EDITABLE (entry),
 
4670
                                0, GTK_ENTRY (entry)-&gt;text_length);
 
4671
    gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
 
4672
    gtk_widget_show (entry);
 
4673
 
 
4674
    hbox = gtk_hbox_new (FALSE, 0);
 
4675
    gtk_container_add (GTK_CONTAINER (vbox), hbox);
 
4676
    gtk_widget_show (hbox);
 
4677
                                  
 
4678
    check = gtk_check_button_new_with_label ("Editable");
 
4679
    gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
 
4680
    g_signal_connect (G_OBJECT (check), "toggled",
 
4681
                      G_CALLBACK (entry_toggle_editable), (gpointer) entry);
 
4682
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
 
4683
    gtk_widget_show (check);
 
4684
    
 
4685
    check = gtk_check_button_new_with_label ("Visible");
 
4686
    gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
 
4687
    g_signal_connect (G_OBJECT (check), "toggled",
 
4688
                      G_CALLBACK (entry_toggle_visibility), (gpointer) entry);
 
4689
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
 
4690
    gtk_widget_show (check);
 
4691
                                   
 
4692
    button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
 
4693
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
4694
                              G_CALLBACK (gtk_widget_destroy),
 
4695
                              G_OBJECT (window));
 
4696
    gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
 
4697
    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
4698
    gtk_widget_grab_default (button);
 
4699
    gtk_widget_show (button);
 
4700
    
 
4701
    gtk_widget_show (window);
 
4702
 
 
4703
    gtk_main();
 
4704
 
 
4705
    return 0;
 
4706
}
 
4707
<!-- example-end -->
 
4708
</programlisting>
 
4709
 
 
4710
</sect1>
 
4711
 
 
4712
<!-- ----------------------------------------------------------------- -->
 
4713
<sect1 id="sec-SpinButtons">
 
4714
<title>Spin Buttons</title>
 
4715
 
 
4716
<para>The Spin Button widget is generally used to allow the user to select a
 
4717
value from a range of numeric values. It consists of a text
 
4718
entry box with up and down arrow buttons attached to the
 
4719
side. Selecting one of the buttons causes the value to "spin" up and
 
4720
down the range of possible values. The entry box may also be edited
 
4721
directly to enter a specific value.</para>
 
4722
 
 
4723
<para>The Spin Button allows the value to have zero or a number of decimal
 
4724
places and to be incremented/decremented in configurable steps. The
 
4725
action of holding down one of the buttons optionally results in an
 
4726
acceleration of change in the value according to how long it is
 
4727
depressed.</para>
 
4728
 
 
4729
<para>The Spin Button uses an <link linkend="ch-Adjustments">Adjustment</link>
 
4730
object to hold information about the range of values that the spin
 
4731
button can take. This makes for a powerful Spin Button widget.</para>
 
4732
 
 
4733
<para>Recall that an adjustment widget is created with the following
 
4734
function, which illustrates the information that it holds:</para>
 
4735
 
 
4736
<programlisting role="C">
 
4737
GtkObject *gtk_adjustment_new( gdouble value,
 
4738
                               gdouble lower,
 
4739
                               gdouble upper,
 
4740
                               gdouble step_increment,
 
4741
                               gdouble page_increment,
 
4742
                               gdouble page_size );
 
4743
</programlisting>
 
4744
 
 
4745
<para>These attributes of an Adjustment are used by the Spin Button in the
 
4746
following way:</para>
 
4747
 
 
4748
<itemizedlist>
 
4749
<listitem><simpara> <literal>value</literal>: initial value for the Spin Button</simpara>
 
4750
</listitem>
 
4751
<listitem><simpara> <literal>lower</literal>: lower range value</simpara>
 
4752
</listitem>
 
4753
<listitem><simpara> <literal>upper</literal>: upper range value</simpara>
 
4754
</listitem>
 
4755
<listitem><simpara> <literal>step_increment</literal>: value to increment/decrement when pressing
 
4756
mouse button 1 on a button</simpara>
 
4757
</listitem>
 
4758
<listitem><simpara> <literal>page_increment</literal>: value to increment/decrement when pressing
 
4759
mouse button 2 on a button</simpara>
 
4760
</listitem>
 
4761
<listitem><simpara> <literal>page_size</literal>: unused</simpara>
 
4762
</listitem>
 
4763
</itemizedlist>
 
4764
 
 
4765
<para>Additionally, mouse button 3 can be used to jump directly to the
 
4766
<literal>upper</literal> or <literal>lower</literal> values when used to select one of the
 
4767
buttons. Lets look at how to create a Spin Button:</para>
 
4768
 
 
4769
<programlisting role="C">
 
4770
GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
 
4771
                                gdouble         climb_rate,
 
4772
                                guint          digits );
 
4773
</programlisting>
 
4774
 
 
4775
<para>The <literal>climb_rate</literal> argument take a value between 0.0 and 1.0 and
 
4776
indicates the amount of acceleration that the Spin Button has. The
 
4777
<literal>digits</literal> argument specifies the number of decimal places to which
 
4778
the value will be displayed.</para>
 
4779
 
 
4780
<para>A Spin Button can be reconfigured after creation using the following
 
4781
function:</para>
 
4782
 
 
4783
<programlisting role="C">
 
4784
void gtk_spin_button_configure( GtkSpinButton *spin_button,
 
4785
                                GtkAdjustment *adjustment,
 
4786
                                gdouble        climb_rate,
 
4787
                                guint          digits );
 
4788
</programlisting>
 
4789
 
 
4790
<para>The <literal>spin_button</literal> argument specifies the Spin Button widget that is
 
4791
to be reconfigured. The other arguments are as specified above.</para>
 
4792
 
 
4793
<para>The adjustment can be set and retrieved independantly using the
 
4794
following two functions:</para>
 
4795
 
 
4796
<programlisting role="C">
 
4797
void gtk_spin_button_set_adjustment( GtkSpinButton  *spin_button,
 
4798
                                     GtkAdjustment  *adjustment );
 
4799
 
 
4800
GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *spin_button );
 
4801
</programlisting>
 
4802
 
 
4803
<para>The number of decimal places can also be altered using:</para>
 
4804
 
 
4805
<programlisting role="C">
 
4806
void gtk_spin_button_set_digits( GtkSpinButton *spin_button,
 
4807
                                 guint          digits) ;
 
4808
</programlisting>
 
4809
 
 
4810
<para>The value that a Spin Button is currently displaying can be changed
 
4811
using the following function:</para>
 
4812
 
 
4813
<programlisting role="C">
 
4814
void gtk_spin_button_set_value( GtkSpinButton *spin_button,
 
4815
                                gdouble        value );
 
4816
</programlisting>
 
4817
 
 
4818
<para>The current value of a Spin Button can be retrieved as either a
 
4819
floating point or integer value with the following functions:</para>
 
4820
 
 
4821
<programlisting role="C">
 
4822
gdouble gtk_spin_button_get_value ( GtkSpinButton *spin_button );
 
4823
 
 
4824
gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );
 
4825
</programlisting>
 
4826
 
 
4827
<para>If you want to alter the value of a Spin Button relative to its current
 
4828
value, then the following function can be used:</para>
 
4829
 
 
4830
<programlisting role="C">
 
4831
void gtk_spin_button_spin( GtkSpinButton *spin_button,
 
4832
                           GtkSpinType    direction,
 
4833
                           gdouble        increment );
 
4834
</programlisting>
 
4835
 
 
4836
<para>The <literal>direction</literal> parameter can take one of the following values:</para>
 
4837
 
 
4838
<programlisting role="C">
 
4839
  GTK_SPIN_STEP_FORWARD
 
4840
  GTK_SPIN_STEP_BACKWARD
 
4841
  GTK_SPIN_PAGE_FORWARD
 
4842
  GTK_SPIN_PAGE_BACKWARD
 
4843
  GTK_SPIN_HOME
 
4844
  GTK_SPIN_END
 
4845
  GTK_SPIN_USER_DEFINED
 
4846
</programlisting>
 
4847
 
 
4848
<para>This function packs in quite a bit of functionality, which I will
 
4849
attempt to clearly explain. Many of these settings use values from the
 
4850
Adjustment object that is associated with a Spin Button.</para>
 
4851
 
 
4852
<para><literal>GTK_SPIN_STEP_FORWARD</literal> and <literal>GTK_SPIN_STEP_BACKWARD</literal> change the
 
4853
value of the Spin Button by the amount specified by <literal>increment</literal>,
 
4854
unless <literal>increment</literal> is equal to 0, in which case the value is
 
4855
changed by the value of <literal>step_increment</literal> in theAdjustment.</para>
 
4856
 
 
4857
<para><literal>GTK_SPIN_PAGE_FORWARD</literal> and <literal>GTK_SPIN_PAGE_BACKWARD</literal> simply
 
4858
alter the value of the Spin Button by <literal>increment</literal>.</para>
 
4859
 
 
4860
<para><literal>GTK_SPIN_HOME</literal> sets the value of the Spin Button to the bottom of
 
4861
the Adjustments range.</para>
 
4862
 
 
4863
<para><literal>GTK_SPIN_END</literal> sets the value of the Spin Button to the top of the
 
4864
Adjustments range.</para>
 
4865
 
 
4866
<para><literal>GTK_SPIN_USER_DEFINED</literal> simply alters the value of the Spin Button
 
4867
by the specified amount.</para>
 
4868
 
 
4869
<para>We move away from functions for setting and retreving the range attributes
 
4870
of the Spin Button now, and move onto functions that affect the
 
4871
appearance and behaviour of the Spin Button widget itself.</para>
 
4872
 
 
4873
<para>The first of these functions is used to constrain the text box of the
 
4874
Spin Button such that it may only contain a numeric value. This
 
4875
prevents a user from typing anything other than numeric values into
 
4876
the text box of a Spin Button:</para>
 
4877
 
 
4878
<programlisting role="C">
 
4879
void gtk_spin_button_set_numeric( GtkSpinButton *spin_button,
 
4880
                                  gboolean       numeric );
 
4881
</programlisting>
 
4882
 
 
4883
<para>You can set whether a Spin Button will wrap around between the upper
 
4884
and lower range values with the following function:</para>
 
4885
 
 
4886
<programlisting role="C">
 
4887
void gtk_spin_button_set_wrap( GtkSpinButton *spin_button,
 
4888
                               gboolean       wrap );
 
4889
</programlisting>
 
4890
 
 
4891
<para>You can set a Spin Button to round the value to the nearest
 
4892
<literal>step_increment</literal>, which is set within the Adjustment object used
 
4893
with the Spin Button. This is accomplished with the following
 
4894
function:</para>
 
4895
 
 
4896
<programlisting role="C">
 
4897
void gtk_spin_button_set_snap_to_ticks( GtkSpinButton  *spin_button,
 
4898
                                        gboolean        snap_to_ticks );
 
4899
</programlisting>
 
4900
 
 
4901
<para>The update policy of a Spin Button can be changed with the following
 
4902
function:</para>
 
4903
 
 
4904
<programlisting role="C">
 
4905
void gtk_spin_button_set_update_policy( GtkSpinButton  *spin_button,
 
4906
                                        GtkSpinButtonUpdatePolicy policy );
 
4907
</programlisting>
 
4908
 
 
4909
<para>The possible values of <literal>policy</literal> are either <literal>GTK_UPDATE_ALWAYS</literal> or
 
4910
<literal>GTK_UPDATE_IF_VALID</literal>.</para>
 
4911
 
 
4912
<para>These policies affect the behavior of a Spin Button when parsing
 
4913
inserted text and syncing its value with the values of the
 
4914
Adjustment.</para>
 
4915
 
 
4916
<para>In the case of <literal>GTK_UPDATE_IF_VALID</literal> the Spin Button only value
 
4917
gets changed if the text input is a numeric value that is within the
 
4918
range specified by the Adjustment. Otherwise the text is reset to the
 
4919
current value.</para>
 
4920
 
 
4921
<para>In case of <literal>GTK_UPDATE_ALWAYS</literal> we ignore errors while converting
 
4922
text into a numeric value.</para>
 
4923
 
 
4924
<para>Finally, you can explicitly request that a Spin Button update itself:</para>
 
4925
 
 
4926
<programlisting role="C">
 
4927
void gtk_spin_button_update( GtkSpinButton  *spin_button );
 
4928
</programlisting>
 
4929
 
 
4930
<para>It's example time again.</para>
 
4931
 
 
4932
<para>
 
4933
<inlinemediaobject>
 
4934
<imageobject>
 
4935
<imagedata fileref="images/spinbutton.png" format="png">
 
4936
</imageobject>
 
4937
</inlinemediaobject>
 
4938
</para>
 
4939
 
 
4940
<programlisting role="C">
 
4941
<!-- example-start spinbutton spinbutton.c -->
 
4942
 
 
4943
#include &lt;stdio.h&gt;
 
4944
#include &lt;gtk/gtk.h&gt;
 
4945
 
 
4946
static GtkWidget *spinner1;
 
4947
 
 
4948
static void toggle_snap( GtkWidget     *widget,
 
4949
                         GtkSpinButton *spin )
 
4950
{
 
4951
  gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)-&gt;active);
 
4952
}
 
4953
 
 
4954
static void toggle_numeric( GtkWidget *widget,
 
4955
                            GtkSpinButton *spin )
 
4956
{
 
4957
  gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)-&gt;active);
 
4958
}
 
4959
 
 
4960
static void change_digits( GtkWidget *widget,
 
4961
                           GtkSpinButton *spin )
 
4962
{
 
4963
  gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
 
4964
                              gtk_spin_button_get_value_as_int (spin));
 
4965
}
 
4966
 
 
4967
static void get_value( GtkWidget *widget,
 
4968
                       gpointer data )
 
4969
{
 
4970
  gchar *buf;
 
4971
  GtkLabel *label;
 
4972
  GtkSpinButton *spin;
 
4973
 
 
4974
  spin = GTK_SPIN_BUTTON (spinner1);
 
4975
  label = GTK_LABEL (g_object_get_data (G_OBJECT (widget), "user_data"));
 
4976
  if (GPOINTER_TO_INT (data) == 1)
 
4977
    buf = g_strdup_printf ("%d", gtk_spin_button_get_value_as_int (spin));
 
4978
  else
 
4979
    buf = g_strdup_printf ("%0.*f", spin-&gt;digits,
 
4980
                           gtk_spin_button_get_value (spin));
 
4981
  gtk_label_set_text (label, buf);
 
4982
  g_free (buf);
 
4983
}
 
4984
 
 
4985
 
 
4986
int main( int   argc,
 
4987
          char *argv[] )
 
4988
{
 
4989
  GtkWidget *window;
 
4990
  GtkWidget *frame;
 
4991
  GtkWidget *hbox;
 
4992
  GtkWidget *main_vbox;
 
4993
  GtkWidget *vbox;
 
4994
  GtkWidget *vbox2;
 
4995
  GtkWidget *spinner2;
 
4996
  GtkWidget *spinner;
 
4997
  GtkWidget *button;
 
4998
  GtkWidget *label;
 
4999
  GtkWidget *val_label;
 
5000
  GtkAdjustment *adj;
 
5001
 
 
5002
  /* Initialise GTK */
 
5003
  gtk_init (&amp;argc, &amp;argv);
 
5004
 
 
5005
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
5006
 
 
5007
  g_signal_connect (G_OBJECT (window), "destroy",
 
5008
                    G_CALLBACK (gtk_main_quit),
 
5009
                    NULL);
 
5010
 
 
5011
  gtk_window_set_title (GTK_WINDOW (window), "Spin Button");
 
5012
 
 
5013
  main_vbox = gtk_vbox_new (FALSE, 5);
 
5014
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
 
5015
  gtk_container_add (GTK_CONTAINER (window), main_vbox);
 
5016
  
 
5017
  frame = gtk_frame_new ("Not accelerated");
 
5018
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
 
5019
  
 
5020
  vbox = gtk_vbox_new (FALSE, 0);
 
5021
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 
5022
  gtk_container_add (GTK_CONTAINER (frame), vbox);
 
5023
  
 
5024
  /* Day, month, year spinners */
 
5025
  
 
5026
  hbox = gtk_hbox_new (FALSE, 0);
 
5027
  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
 
5028
  
 
5029
  vbox2 = gtk_vbox_new (FALSE, 0);
 
5030
  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
 
5031
  
 
5032
  label = gtk_label_new ("Day :");
 
5033
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
5034
  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
 
5035
  
 
5036
  adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
 
5037
                                              5.0, 0.0);
 
5038
  spinner = gtk_spin_button_new (adj, 0, 0);
 
5039
  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
 
5040
  gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
 
5041
  
 
5042
  vbox2 = gtk_vbox_new (FALSE, 0);
 
5043
  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
 
5044
  
 
5045
  label = gtk_label_new ("Month :");
 
5046
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
5047
  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
 
5048
  
 
5049
  adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
 
5050
                                              5.0, 0.0);
 
5051
  spinner = gtk_spin_button_new (adj, 0, 0);
 
5052
  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
 
5053
  gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
 
5054
  
 
5055
  vbox2 = gtk_vbox_new (FALSE, 0);
 
5056
  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
 
5057
  
 
5058
  label = gtk_label_new ("Year :");
 
5059
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
5060
  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
 
5061
  
 
5062
  adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
 
5063
                                              1.0, 100.0, 0.0);
 
5064
  spinner = gtk_spin_button_new (adj, 0, 0);
 
5065
  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
 
5066
  gtk_widget_set_size_request (spinner, 55, -1);
 
5067
  gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
 
5068
  
 
5069
  frame = gtk_frame_new ("Accelerated");
 
5070
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
 
5071
  
 
5072
  vbox = gtk_vbox_new (FALSE, 0);
 
5073
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 
5074
  gtk_container_add (GTK_CONTAINER (frame), vbox);
 
5075
  
 
5076
  hbox = gtk_hbox_new (FALSE, 0);
 
5077
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
 
5078
  
 
5079
  vbox2 = gtk_vbox_new (FALSE, 0);
 
5080
  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
 
5081
  
 
5082
  label = gtk_label_new ("Value :");
 
5083
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
5084
  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
 
5085
  
 
5086
  adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
 
5087
                                              0.5, 100.0, 0.0);
 
5088
  spinner1 = gtk_spin_button_new (adj, 1.0, 2);
 
5089
  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
 
5090
  gtk_widget_set_size_request (spinner1, 100, -1);
 
5091
  gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
 
5092
  
 
5093
  vbox2 = gtk_vbox_new (FALSE, 0);
 
5094
  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
 
5095
  
 
5096
  label = gtk_label_new ("Digits :");
 
5097
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
5098
  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
 
5099
  
 
5100
  adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
 
5101
  spinner2 = gtk_spin_button_new (adj, 0.0, 0);
 
5102
  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
 
5103
  g_signal_connect (G_OBJECT (adj), "value_changed",
 
5104
                    G_CALLBACK (change_digits),
 
5105
                    (gpointer) spinner2);
 
5106
  gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
 
5107
  
 
5108
  hbox = gtk_hbox_new (FALSE, 0);
 
5109
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
 
5110
  
 
5111
  button = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
 
5112
  g_signal_connect (G_OBJECT (button), "clicked",
 
5113
                    G_CALLBACK (toggle_snap),
 
5114
                    (gpointer) spinner1);
 
5115
  gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
 
5116
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
 
5117
  
 
5118
  button = gtk_check_button_new_with_label ("Numeric only input mode");
 
5119
  g_signal_connect (G_OBJECT (button), "clicked",
 
5120
                    G_CALLBACK (toggle_numeric),
 
5121
                    (gpointer) spinner1);
 
5122
  gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
 
5123
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
 
5124
  
 
5125
  val_label = gtk_label_new ("");
 
5126
  
 
5127
  hbox = gtk_hbox_new (FALSE, 0);
 
5128
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
 
5129
  button = gtk_button_new_with_label ("Value as Int");
 
5130
  g_object_set_data (G_OBJECT (button), "user_data", val_label);
 
5131
  g_signal_connect (G_OBJECT (button), "clicked",
 
5132
                    G_CALLBACK (get_value),
 
5133
                    GINT_TO_POINTER (1));
 
5134
  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
 
5135
  
 
5136
  button = gtk_button_new_with_label ("Value as Float");
 
5137
  g_object_set_data (G_OBJECT (button), "user_data", val_label);
 
5138
  g_signal_connect (G_OBJECT (button), "clicked",
 
5139
                    G_CALLBACK (get_value),
 
5140
                    GINT_TO_POINTER (2));
 
5141
  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
 
5142
  
 
5143
  gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
 
5144
  gtk_label_set_text (GTK_LABEL (val_label), "0");
 
5145
  
 
5146
  hbox = gtk_hbox_new (FALSE, 0);
 
5147
  gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
 
5148
  
 
5149
  button = gtk_button_new_with_label ("Close");
 
5150
  g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
5151
                            G_CALLBACK (gtk_widget_destroy),
 
5152
                            G_OBJECT (window));
 
5153
  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
 
5154
 
 
5155
  gtk_widget_show_all (window);
 
5156
 
 
5157
  /* Enter the event loop */
 
5158
  gtk_main ();
 
5159
    
 
5160
  return 0;
 
5161
}
 
5162
 
 
5163
<!-- example-end -->
 
5164
</programlisting>
 
5165
 
 
5166
</sect1>
 
5167
 
 
5168
<!-- ----------------------------------------------------------------- -->
 
5169
<sect1 id="sec-ComboBox">
 
5170
<title>Combo Box</title>
 
5171
 
 
5172
<para>The combo box is another fairly simple widget that is really just a
 
5173
collection of other widgets. From the user's point of view, the widget
 
5174
consists of a text entry box and a pull down menu from which the user
 
5175
can select one of a set of predefined entries. Alternatively, the user
 
5176
can type a different option directly into the text box.</para>
 
5177
 
 
5178
<para>The following extract from the structure that defines a Combo Box
 
5179
identifies several of the components:</para>
 
5180
 
 
5181
<programlisting role="C">
 
5182
struct _GtkCombo { 
 
5183
        GtkHBox hbox; 
 
5184
        GtkWidget *entry; 
 
5185
        GtkWidget *button;
 
5186
        GtkWidget *popup; 
 
5187
        GtkWidget *popwin; 
 
5188
        GtkWidget *list;
 
5189
        ...  };
 
5190
</programlisting>
 
5191
 
 
5192
<para>As you can see, the Combo Box has two principal parts that you really
 
5193
care about: an entry and a list.</para>
 
5194
 
 
5195
<para>First off, to create a combo box, use:</para>
 
5196
 
 
5197
<programlisting role="C">
 
5198
GtkWidget *gtk_combo_new( void );
 
5199
</programlisting>
 
5200
 
 
5201
<para>Now, if you want to set the string in the entry section of the combo
 
5202
box, this is done by manipulating the <literal>entry</literal> widget directly:</para>
 
5203
 
 
5204
<programlisting role="C">
 
5205
    gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), "My String.");
 
5206
</programlisting>
 
5207
 
 
5208
<para>To set the values in the popdown list, one uses the function:</para>
 
5209
 
 
5210
<programlisting role="C">
 
5211
void gtk_combo_set_popdown_strings( GtkCombo *combo,
 
5212
                                    GList    *strings );
 
5213
</programlisting>
 
5214
 
 
5215
<para>Before you can do this, you have to assemble a GList of the strings
 
5216
that you want. GList is a linked list implementation that is part of
 
5217
<link linkend="ch-GLib">GLib</link>, a library supporting GTK. For the
 
5218
moment, the quick and dirty explanation is that you need to set up a
 
5219
GList pointer, set it equal to NULL, then append strings to it with</para>
 
5220
 
 
5221
<programlisting role="C">
 
5222
GList *g_list_append( GList *glist, 
 
5223
                      gpointer data );
 
5224
</programlisting>
 
5225
 
 
5226
<para>It is important that you set the initial GList pointer to NULL. The
 
5227
value returned from the g_list_append() function must be used as the new
 
5228
pointer to the GList.</para>
 
5229
 
 
5230
<para>Here's a typical code segment for creating a set of options:</para>
 
5231
 
 
5232
<programlisting role="C">
 
5233
    GList *glist = NULL;
 
5234
 
 
5235
    glist = g_list_append (glist, "String 1");
 
5236
    glist = g_list_append (glist, "String 2");
 
5237
    glist = g_list_append (glist, "String 3"); 
 
5238
    glist = g_list_append (glist, "String 4");
 
5239
 
 
5240
    gtk_combo_set_popdown_strings (GTK_COMBO (combo), glist);
 
5241
    
 
5242
    /* can free glist now, combo takes a copy */
 
5243
</programlisting>
 
5244
 
 
5245
<para>The combo widget makes a copy of the strings passed to it in the glist
 
5246
structure. As a result, you need to make sure you free the memory used
 
5247
by the list if that is appropriate for your application.</para>
 
5248
 
 
5249
<para>At this point you have a working combo box that has been set up.
 
5250
There are a few aspects of its behavior that you can change. These
 
5251
are accomplished with the functions: </para>
 
5252
 
 
5253
<programlisting role="C">
 
5254
void gtk_combo_set_use_arrows( GtkCombo *combo,
 
5255
                               gboolean  val );
 
5256
 
 
5257
void gtk_combo_set_use_arrows_always( GtkCombo *combo,
 
5258
                                      gboolean  val );
 
5259
 
 
5260
void gtk_combo_set_case_sensitive( GtkCombo *combo,
 
5261
                                   gboolean  val );
 
5262
</programlisting>
 
5263
 
 
5264
<para>gtk_combo_set_use_arrows() lets the user change the value in the
 
5265
entry using the up/down arrow keys. This doesn't bring up the list, but
 
5266
rather replaces the current text in the entry with the next list entry
 
5267
(up or down, as your key choice indicates). It does this by searching
 
5268
in the list for the item corresponding to the current value in the
 
5269
entry and selecting the previous/next item accordingly. Usually in an
 
5270
entry the arrow keys are used to change focus (you can do that anyway
 
5271
using TAB). Note that when the current item is the last of the list
 
5272
and you press arrow-down it changes the focus (the same applies with
 
5273
the first item and arrow-up).</para>
 
5274
 
 
5275
<para>If the current value in the entry is not in the list, then the
 
5276
function of gtk_combo_set_use_arrows() is disabled.</para>
 
5277
 
 
5278
<para>gtk_combo_set_use_arrows_always() similarly allows the use the
 
5279
the up/down arrow keys to cycle through the choices in the dropdown
 
5280
list, except that it wraps around the values in the list, completely
 
5281
disabling the use of the up and down arrow keys for changing focus.</para>
 
5282
 
 
5283
<para>gtk_combo_set_case_sensitive() toggles whether or not GTK
 
5284
searches for entries in a case sensitive manner. This is used when the
 
5285
Combo widget is asked to find a value from the list using the current
 
5286
entry in the text box. This completion can be performed in either a
 
5287
case sensitive or insensitive manner, depending upon the use of this
 
5288
function. The Combo widget can also simply complete the current entry
 
5289
if the user presses the key combination MOD-1 and "Tab". MOD-1 is
 
5290
often mapped to the "Alt" key, by the <literal>xmodmap</literal> utility. Note,
 
5291
however that some window managers also use this key combination, which
 
5292
will override its use within GTK.</para>
 
5293
 
 
5294
<para>Now that we have a combo box, tailored to look and act how we want it,
 
5295
all that remains is being able to get data from the combo box. This is
 
5296
relatively straightforward. The majority of the time, all you are
 
5297
going to care about getting data from is the entry. The entry is
 
5298
accessed simply by <literal>GTK_ENTRY (GTK_COMBO (combo)->entry)</literal>. The
 
5299
two principal things that you are going to want to do with it are
 
5300
connect to the activate signal, which indicates that the user has
 
5301
pressed the Return or Enter key, and read the text. The first is
 
5302
accomplished using something like:</para>
 
5303
 
 
5304
<programlisting role="C">
 
5305
    g_signal_connect (G_OBJECT (GTK_COMBO (combo)->entry), "activate",
 
5306
                      G_CALLBACK (my_callback_function), (gpointer) my_data);
 
5307
</programlisting>
 
5308
 
 
5309
<para>Getting the text at any arbitrary time is accomplished by simply using
 
5310
the entry function:</para>
 
5311
 
 
5312
<programlisting role="C">
 
5313
gchar *gtk_entry_get_text( GtkEntry *entry );
 
5314
</programlisting>
 
5315
 
 
5316
<para>Such as:</para>
 
5317
 
 
5318
<programlisting role="C">
 
5319
    gchar *string;
 
5320
 
 
5321
    string = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (combo)->entry));
 
5322
</programlisting>
 
5323
 
 
5324
<para>That's about all there is to it. There is a function</para>
 
5325
 
 
5326
<programlisting role="C">
 
5327
void gtk_combo_disable_activate( GtkCombo *combo );
 
5328
</programlisting>
 
5329
 
 
5330
<para>that will disable the activate signal on the entry widget in the combo
 
5331
box. Personally, I can't think of why you'd want to use it, but it
 
5332
does exist.</para>
 
5333
 
 
5334
<!-- There is also a function to set the string on a particular item, void
 
5335
gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
 
5336
*item_value), but this requires that you have a pointer to the
 
5337
appropriate Item. Frankly, I have no idea how to do that.
 
5338
-->
 
5339
 
 
5340
</sect1>
 
5341
 
 
5342
<!-- ----------------------------------------------------------------- -->
 
5343
<sect1 id="sec-Calendar">
 
5344
<title>Calendar</title>
 
5345
 
 
5346
<para>The Calendar widget is an effective way to display and retrieve
 
5347
monthly date related information. It is a very simple widget to create
 
5348
and work with.</para>
 
5349
 
 
5350
<para>Creating a GtkCalendar widget is a simple as: </para>
 
5351
 
 
5352
<programlisting role="C">
 
5353
GtkWidget *gtk_calendar_new( void );
 
5354
</programlisting>
 
5355
 
 
5356
<para>There might be times where you need to change a lot of information
 
5357
within this widget and the following functions allow you to make
 
5358
multiple change to a Calendar widget without the user seeing multiple
 
5359
on-screen updates.</para>
 
5360
 
 
5361
<programlisting role="C">
 
5362
void gtk_calendar_freeze( GtkCalendar *Calendar );
 
5363
 
 
5364
void gtk_calendar_thaw( GtkCalendar *Calendar );
 
5365
</programlisting>
 
5366
 
 
5367
<para>They work just like the freeze/thaw functions of every other
 
5368
widget.</para>
 
5369
 
 
5370
<para>The Calendar widget has a few options that allow you to change the way
 
5371
the widget both looks and operates by using the function</para>
 
5372
 
 
5373
<programlisting role="C">
 
5374
void gtk_calendar_display_options( GtkCalendar               *calendar,
 
5375
                                   GtkCalendarDisplayOptions  flags );
 
5376
</programlisting>
 
5377
 
 
5378
<para>The <literal>flags</literal> argument can be formed by combining either of the
 
5379
following five options using the logical bitwise OR (|) operation:</para>
 
5380
 
 
5381
<variablelist>
 
5382
<varlistentry>
 
5383
<term><literal>GTK_CALENDAR_SHOW_HEADING</literal></term>
 
5384
<listitem><para>this option specifies that the month and year should be shown 
 
5385
when drawing the calendar.</para>
 
5386
</listitem>
 
5387
</varlistentry>
 
5388
<varlistentry>
 
5389
<term><literal>GTK_CALENDAR_SHOW_DAY_NAMES</literal></term>
 
5390
<listitem><para>this option specifies that the three letter descriptions should 
 
5391
be displayed for each day (eg Mon,Tue, etc.).</para>
 
5392
</listitem>
 
5393
</varlistentry>
 
5394
<varlistentry>
 
5395
<term><literal>GTK_CALENDAR_NO_MONTH_CHANGE</literal></term>
 
5396
<listitem><para>this option states that the user
 
5397
should not and can not change the currently displayed month. This can
 
5398
be good if you only need to display a particular month such as if you
 
5399
are displaying 12 calendar widgets for every month in a particular
 
5400
year.</para>
 
5401
</listitem>
 
5402
</varlistentry>
 
5403
<varlistentry>
 
5404
<term><literal>GTK_CALENDAR_SHOW_WEEK_NUMBERS</literal></term>
 
5405
<listitem><para>this option specifies that the
 
5406
number for each week should be displayed down the left side of the
 
5407
calendar. (eg. Jan 1 = Week 1,Dec 31 = Week 52).</para>
 
5408
</listitem>
 
5409
</varlistentry>
 
5410
<varlistentry>
 
5411
<term><literal>GTK_CALENDAR_WEEK_START_MONDAY</literal></term>
 
5412
<listitem><para>this option states that the
 
5413
calander week will start on Monday instead of Sunday which is the
 
5414
default. This only affects the order in which days are displayed from
 
5415
left to right.</para>
 
5416
</listitem>
 
5417
</varlistentry>
 
5418
</variablelist>
 
5419
 
 
5420
<para>The following functions are used to set the the currently displayed
 
5421
date:</para>
 
5422
 
 
5423
<programlisting role="C">
 
5424
gint gtk_calendar_select_month( GtkCalendar *calendar, 
 
5425
                                guint        month,
 
5426
                                guint        year );
 
5427
 
 
5428
void gtk_calendar_select_day( GtkCalendar *calendar,
 
5429
                              guint        day );
 
5430
</programlisting>
 
5431
 
 
5432
<para>The return value from <literal>gtk_calendar_select_month()</literal> is a boolean
 
5433
value indicating whether the selection was successful.</para>
 
5434
 
 
5435
<para>With <literal>gtk_calendar_select_day()</literal> the specified day number is
 
5436
selected within the current month, if that is possible. A
 
5437
<literal>day</literal> value of 0 will deselect any current selection.</para>
 
5438
 
 
5439
<para>In addition to having a day selected, any number of days in the month
 
5440
may be "marked". A marked day is highlighted within the calendar
 
5441
display. The following functions are provided to manipulate marked
 
5442
days:</para>
 
5443
 
 
5444
<programlisting role="C">
 
5445
gint gtk_calendar_mark_day( GtkCalendar *calendar,
 
5446
                            guint        day);
 
5447
 
 
5448
gint gtk_calendar_unmark_day( GtkCalendar *calendar,
 
5449
                              guint        day);
 
5450
 
 
5451
void gtk_calendar_clear_marks( GtkCalendar *calendar);
 
5452
</programlisting>
 
5453
 
 
5454
<para>The currently marked days are stored within an array within the
 
5455
GtkCalendar structure. This array is 31 elements long so to test
 
5456
whether a particular day is currently marked, you need to access the
 
5457
corresponding element of the array (don't forget in C that array
 
5458
elements are numbered 0 to n-1). For example:</para>
 
5459
 
 
5460
<programlisting role="C">
 
5461
    GtkCalendar *calendar;
 
5462
    calendar = gtk_calendar_new ();
 
5463
 
 
5464
    ...
 
5465
 
 
5466
    /* Is day 7 marked? */
 
5467
    if (calendar->marked_date[7-1])
 
5468
       /* day is marked */
 
5469
</programlisting>
 
5470
 
 
5471
<para>Note that marks are persistent across month and year changes.</para>
 
5472
 
 
5473
<para>The final Calendar widget function is used to retrieve the currently
 
5474
selected date, month and/or year.</para>
 
5475
 
 
5476
<programlisting role="C">
 
5477
void gtk_calendar_get_date( GtkCalendar *calendar, 
 
5478
                            guint       *year,
 
5479
                            guint       *month,
 
5480
                            guint       *day );
 
5481
</programlisting>
 
5482
 
 
5483
<para>This function requires you to pass the addresses of <literal>guint</literal>
 
5484
variables, into which the result will be placed. Passing <literal>NULL</literal> as
 
5485
a value will result in the corresponding value not being returned.</para>
 
5486
 
 
5487
<para>The Calendar widget can generate a number of signals indicating date
 
5488
selection and change. The names of these signals are self explanatory,
 
5489
and are:</para>
 
5490
 
 
5491
<itemizedlist>
 
5492
<listitem><simpara> <literal>month_changed</literal></simpara>
 
5493
</listitem>
 
5494
<listitem><simpara> <literal>day_selected</literal></simpara>
 
5495
</listitem>
 
5496
<listitem><simpara> <literal>day_selected_double_click</literal></simpara>
 
5497
</listitem>
 
5498
<listitem><simpara> <literal>prev_month</literal></simpara>
 
5499
</listitem>
 
5500
<listitem><simpara> <literal>next_month</literal></simpara>
 
5501
</listitem>
 
5502
<listitem><simpara> <literal>prev_year</literal></simpara>
 
5503
</listitem>
 
5504
<listitem><simpara> <literal>next_year</literal></simpara>
 
5505
</listitem>
 
5506
</itemizedlist>
 
5507
 
 
5508
<para>That just leaves us with the need to put all of this together into
 
5509
example code.</para>
 
5510
 
 
5511
<para>
 
5512
<inlinemediaobject>
 
5513
<imageobject>
 
5514
<imagedata fileref="images/calendar.png" format="png">
 
5515
</imageobject>
 
5516
</inlinemediaobject>
 
5517
</para>
 
5518
 
 
5519
<programlisting role="C">
 
5520
<!-- example-start calendar calendar.c -->
 
5521
/*
 
5522
 * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Gr�nlund
 
5523
 * Copyright (C) 2000 Tony Gale
 
5524
 *
 
5525
 * This program is free software; you can redistribute it and/or modify
 
5526
 * it under the terms of the GNU General Public License as published by
 
5527
 * the Free Software Foundation; either version 2 of the License, or
 
5528
 * (at your option) any later version.
 
5529
 *
 
5530
 * This program is distributed in the hope that it will be useful,
 
5531
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
5532
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
5533
 * GNU General Public License for more details.
 
5534
 *
 
5535
 * You should have received a copy of the GNU General Public License
 
5536
 * along with this program; if not, write to the Free Software
 
5537
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
5538
 */
 
5539
 
 
5540
#include &lt;stdio.h&gt;
 
5541
#include &lt;string.h&gt;
 
5542
#include &lt;gtk/gtk.h&gt;
 
5543
 
 
5544
#define DEF_PAD 10
 
5545
#define DEF_PAD_SMALL 5
 
5546
 
 
5547
#define TM_YEAR_BASE 1900
 
5548
 
 
5549
typedef struct _CalendarData {
 
5550
  GtkWidget *flag_checkboxes[5];
 
5551
  gboolean  settings[5];
 
5552
  GtkWidget *font_dialog;
 
5553
  GtkWidget *window;
 
5554
  GtkWidget *prev2_sig;
 
5555
  GtkWidget *prev_sig;
 
5556
  GtkWidget *last_sig;
 
5557
  GtkWidget *month;
 
5558
} CalendarData;
 
5559
 
 
5560
enum {
 
5561
  calendar_show_header,
 
5562
  calendar_show_days,
 
5563
  calendar_month_change, 
 
5564
  calendar_show_week,
 
5565
  calendar_monday_first
 
5566
};
 
5567
 
 
5568
/*
 
5569
 * GtkCalendar
 
5570
 */
 
5571
 
 
5572
static void calendar_date_to_string( CalendarData *data,
 
5573
                                     char         *buffer,
 
5574
                                     gint          buff_len )
 
5575
{
 
5576
  GDate date;
 
5577
  guint year, month, day;
 
5578
 
 
5579
  gtk_calendar_get_date (GTK_CALENDAR (data-&gt;window),
 
5580
                         &amp;year, &amp;month, &amp;day);
 
5581
  g_date_set_dmy (&amp;date, day, month + 1, year);
 
5582
  g_date_strftime (buffer, buff_len - 1, "%x", &amp;date);
 
5583
 
 
5584
}
 
5585
 
 
5586
static void calendar_set_signal_strings( char         *sig_str,
 
5587
                                         CalendarData *data )
 
5588
{
 
5589
  const gchar *prev_sig;
 
5590
 
 
5591
  prev_sig = gtk_label_get_text (GTK_LABEL (data-&gt;prev_sig));
 
5592
  gtk_label_set_text (GTK_LABEL (data-&gt;prev2_sig), prev_sig);
 
5593
 
 
5594
  prev_sig = gtk_label_get_text (GTK_LABEL (data-&gt;last_sig));
 
5595
  gtk_label_set_text (GTK_LABEL (data-&gt;prev_sig), prev_sig);
 
5596
  gtk_label_set_text (GTK_LABEL (data-&gt;last_sig), sig_str);
 
5597
}
 
5598
 
 
5599
static void calendar_month_changed( GtkWidget    *widget,
 
5600
                                    CalendarData *data )
 
5601
{
 
5602
  char buffer[256] = "month_changed: ";
 
5603
 
 
5604
  calendar_date_to_string (data, buffer + 15, 256 - 15);
 
5605
  calendar_set_signal_strings (buffer, data);
 
5606
}
 
5607
 
 
5608
static void calendar_day_selected( GtkWidget    *widget,
 
5609
                                   CalendarData *data )
 
5610
{
 
5611
  char buffer[256] = "day_selected: ";
 
5612
 
 
5613
  calendar_date_to_string (data, buffer + 14, 256 - 14);
 
5614
  calendar_set_signal_strings (buffer, data);
 
5615
}
 
5616
 
 
5617
static void calendar_day_selected_double_click ( GtkWidget    *widget,
 
5618
                                                 CalendarData *data )
 
5619
{
 
5620
  char buffer[256] = "day_selected_double_click: ";
 
5621
  guint day;
 
5622
 
 
5623
  calendar_date_to_string (data, buffer + 27, 256 - 27);
 
5624
  calendar_set_signal_strings (buffer, data);
 
5625
 
 
5626
  gtk_calendar_get_date (GTK_CALENDAR (data-&gt;window),
 
5627
                         NULL, NULL, &amp;day);
 
5628
 
 
5629
  if (GTK_CALENDAR (data-&gt;window)-&gt;marked_date[day-1] == 0) {
 
5630
    gtk_calendar_mark_day (GTK_CALENDAR (data-&gt;window), day);
 
5631
  } else { 
 
5632
    gtk_calendar_unmark_day (GTK_CALENDAR (data-&gt;window), day);
 
5633
  }
 
5634
}
 
5635
 
 
5636
static void calendar_prev_month( GtkWidget    *widget,
 
5637
                                 CalendarData *data )
 
5638
{
 
5639
  char buffer[256] = "prev_month: ";
 
5640
 
 
5641
  calendar_date_to_string (data, buffer + 12, 256 - 12);
 
5642
  calendar_set_signal_strings (buffer, data);
 
5643
}
 
5644
 
 
5645
static void calendar_next_month( GtkWidget    *widget,
 
5646
                                 CalendarData *data )
 
5647
{
 
5648
  char buffer[256] = "next_month: ";
 
5649
 
 
5650
  calendar_date_to_string (data, buffer + 12, 256 - 12);
 
5651
  calendar_set_signal_strings (buffer, data);
 
5652
}
 
5653
 
 
5654
static void calendar_prev_year( GtkWidget    *widget,
 
5655
                                CalendarData *data )
 
5656
{
 
5657
  char buffer[256] = "prev_year: ";
 
5658
 
 
5659
  calendar_date_to_string (data, buffer + 11, 256 - 11);
 
5660
  calendar_set_signal_strings (buffer, data);
 
5661
}
 
5662
 
 
5663
static void calendar_next_year( GtkWidget    *widget,
 
5664
                                CalendarData *data )
 
5665
{
 
5666
  char buffer[256] = "next_year: ";
 
5667
 
 
5668
  calendar_date_to_string (data, buffer + 11, 256 - 11);
 
5669
  calendar_set_signal_strings (buffer, data);
 
5670
}
 
5671
 
 
5672
 
 
5673
static void calendar_set_flags( CalendarData *calendar )
 
5674
{
 
5675
  gint i;
 
5676
  gint options = 0;
 
5677
  for (i = 0;i &lt; 5; i++) 
 
5678
    if (calendar-&gt;settings[i])
 
5679
      {
 
5680
        options = options + (1 &lt;&lt; i);
 
5681
      }
 
5682
  if (calendar-&gt;window)
 
5683
    gtk_calendar_display_options (GTK_CALENDAR (calendar-&gt;window), options);
 
5684
}
 
5685
 
 
5686
static void calendar_toggle_flag( GtkWidget    *toggle,
 
5687
                                  CalendarData *calendar)
 
5688
{
 
5689
  gint i;
 
5690
  gint j;
 
5691
  j = 0;
 
5692
  for (i = 0; i &lt; 5; i++)
 
5693
    if (calendar-&gt;flag_checkboxes[i] == toggle)
 
5694
      j = i;
 
5695
 
 
5696
  calendar-&gt;settings[j] = !calendar-&gt;settings[j];
 
5697
  calendar_set_flags (calendar);
 
5698
  
 
5699
}
 
5700
 
 
5701
static void calendar_font_selection_ok( GtkWidget    *button,
 
5702
                                        CalendarData *calendar )
 
5703
{
 
5704
  GtkRcStyle *style;
 
5705
  char *font_name;
 
5706
 
 
5707
  if (calendar-&gt;window)
 
5708
    {
 
5709
      font_name = gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG (calendar-&gt;font_dialog));
 
5710
      if (font_name) 
 
5711
        {
 
5712
          style = gtk_rc_style_new ();
 
5713
          pango_font_description_free (style-&gt;font_desc);
 
5714
          style-&gt;font_desc = pango_font_description_from_string (font_name);
 
5715
          gtk_widget_modify_style (calendar-&gt;window, style);
 
5716
          g_free (font_name);
 
5717
        }
 
5718
    }
 
5719
 
 
5720
  gtk_widget_destroy (calendar-&gt;font_dialog);
 
5721
}
 
5722
 
 
5723
static void calendar_select_font( GtkWidget    *button,
 
5724
                                  CalendarData *calendar )
 
5725
{
 
5726
  GtkWidget *window;
 
5727
 
 
5728
  if (!calendar-&gt;font_dialog) {
 
5729
    window = gtk_font_selection_dialog_new ("Font Selection Dialog");
 
5730
    g_return_if_fail (GTK_IS_FONT_SELECTION_DIALOG (window));
 
5731
    calendar-&gt;font_dialog = window;
 
5732
    
 
5733
    gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
 
5734
    
 
5735
    g_signal_connect (window, "destroy",
 
5736
                      G_CALLBACK (gtk_widget_destroyed),
 
5737
                      &amp;calendar-&gt;font_dialog);
 
5738
    
 
5739
    g_signal_connect (GTK_FONT_SELECTION_DIALOG (window)-&gt;ok_button,
 
5740
                      "clicked", G_CALLBACK (calendar_font_selection_ok),
 
5741
                      calendar);
 
5742
    g_signal_connect_swapped (GTK_FONT_SELECTION_DIALOG (window)-&gt;cancel_button,
 
5743
                             "clicked", G_CALLBACK (gtk_widget_destroy), 
 
5744
                             calendar-&gt;font_dialog);
 
5745
  }
 
5746
  window = calendar-&gt;font_dialog;
 
5747
  if (!GTK_WIDGET_VISIBLE (window))
 
5748
    gtk_widget_show (window);
 
5749
  else
 
5750
    gtk_widget_destroy (window);
 
5751
 
 
5752
}
 
5753
 
 
5754
static void create_calendar( void )
 
5755
{
 
5756
  GtkWidget *window;
 
5757
  GtkWidget *vbox, *vbox2, *vbox3;
 
5758
  GtkWidget *hbox;
 
5759
  GtkWidget *hbbox;
 
5760
  GtkWidget *calendar;
 
5761
  GtkWidget *toggle;
 
5762
  GtkWidget *button;
 
5763
  GtkWidget *frame;
 
5764
  GtkWidget *separator;
 
5765
  GtkWidget *label;
 
5766
  GtkWidget *bbox;
 
5767
  static CalendarData calendar_data;
 
5768
  gint i;
 
5769
  
 
5770
  struct {
 
5771
    char *label;
 
5772
  } flags[] =
 
5773
    {
 
5774
      { "Show Heading" },
 
5775
      { "Show Day Names" },
 
5776
      { "No Month Change" },
 
5777
      { "Show Week Numbers" },
 
5778
      { "Week Start Monday" }
 
5779
    };
 
5780
 
 
5781
  
 
5782
  calendar_data.window = NULL;
 
5783
  calendar_data.font_dialog = NULL;
 
5784
 
 
5785
  for (i = 0; i &lt; 5; i++) {
 
5786
    calendar_data.settings[i] = 0;
 
5787
  }
 
5788
 
 
5789
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
5790
  gtk_window_set_title (GTK_WINDOW (window), "GtkCalendar Example");
 
5791
  gtk_container_set_border_width (GTK_CONTAINER (window), 5);
 
5792
  g_signal_connect (window, "destroy",
 
5793
                    G_CALLBACK (gtk_main_quit),
 
5794
                    NULL);
 
5795
  g_signal_connect (window, "delete-event",
 
5796
                    G_CALLBACK (gtk_false),
 
5797
                    NULL);
 
5798
  gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
 
5799
 
 
5800
  vbox = gtk_vbox_new (FALSE, DEF_PAD);
 
5801
  gtk_container_add (GTK_CONTAINER (window), vbox);
 
5802
 
 
5803
  /*
 
5804
   * The top part of the window, Calendar, flags and fontsel.
 
5805
   */
 
5806
 
 
5807
  hbox = gtk_hbox_new (FALSE, DEF_PAD);
 
5808
  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, DEF_PAD);
 
5809
  hbbox = gtk_hbutton_box_new ();
 
5810
  gtk_box_pack_start (GTK_BOX (hbox), hbbox, FALSE, FALSE, DEF_PAD);
 
5811
  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_SPREAD);
 
5812
  gtk_box_set_spacing (GTK_BOX (hbbox), 5);
 
5813
 
 
5814
  /* Calendar widget */
 
5815
  frame = gtk_frame_new ("Calendar");
 
5816
  gtk_box_pack_start(GTK_BOX (hbbox), frame, FALSE, TRUE, DEF_PAD);
 
5817
  calendar=gtk_calendar_new ();
 
5818
  calendar_data.window = calendar;
 
5819
  calendar_set_flags (&amp;calendar_data);
 
5820
  gtk_calendar_mark_day (GTK_CALENDAR (calendar), 19);  
 
5821
  gtk_container_add (GTK_CONTAINER (frame), calendar);
 
5822
  g_signal_connect (calendar, "month_changed", 
 
5823
                    G_CALLBACK (calendar_month_changed),
 
5824
                    &amp;calendar_data);
 
5825
  g_signal_connect (calendar, "day_selected", 
 
5826
                    G_CALLBACK (calendar_day_selected),
 
5827
                    &amp;calendar_data);
 
5828
  g_signal_connect (calendar, "day_selected_double_click", 
 
5829
                    G_CALLBACK (calendar_day_selected_double_click),
 
5830
                    &amp;calendar_data);
 
5831
  g_signal_connect (calendar, "prev_month", 
 
5832
                    G_CALLBACK (calendar_prev_month),
 
5833
                    &amp;calendar_data);
 
5834
  g_signal_connect (calendar, "next_month", 
 
5835
                    G_CALLBACK (calendar_next_month),
 
5836
                    &amp;calendar_data);
 
5837
  g_signal_connect (calendar, "prev_year", 
 
5838
                    G_CALLBACK (calendar_prev_year),
 
5839
                    &amp;calendar_data);
 
5840
  g_signal_connect (calendar, "next_year", 
 
5841
                    G_CALLBACK (calendar_next_year),
 
5842
                    &amp;calendar_data);
 
5843
 
 
5844
 
 
5845
  separator = gtk_vseparator_new ();
 
5846
  gtk_box_pack_start (GTK_BOX (hbox), separator, FALSE, TRUE, 0);
 
5847
 
 
5848
  vbox2 = gtk_vbox_new (FALSE, DEF_PAD);
 
5849
  gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, DEF_PAD);
 
5850
  
 
5851
  /* Build the Right frame with the flags in */ 
 
5852
 
 
5853
  frame = gtk_frame_new ("Flags");
 
5854
  gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, DEF_PAD);
 
5855
  vbox3 = gtk_vbox_new (TRUE, DEF_PAD_SMALL);
 
5856
  gtk_container_add (GTK_CONTAINER (frame), vbox3);
 
5857
 
 
5858
  for (i = 0; i &lt; 5; i++)
 
5859
    {
 
5860
      toggle = gtk_check_button_new_with_label (flags[i].label);
 
5861
      g_signal_connect (toggle,
 
5862
                        "toggled",
 
5863
                        G_CALLBACK (calendar_toggle_flag),
 
5864
                        &amp;calendar_data);
 
5865
      gtk_box_pack_start (GTK_BOX (vbox3), toggle, TRUE, TRUE, 0);
 
5866
      calendar_data.flag_checkboxes[i] = toggle;
 
5867
    }
 
5868
  /* Build the right font-button */ 
 
5869
  button = gtk_button_new_with_label ("Font...");
 
5870
  g_signal_connect (button,
 
5871
                    "clicked",
 
5872
                    G_CALLBACK (calendar_select_font),
 
5873
                    &amp;calendar_data);
 
5874
  gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
 
5875
 
 
5876
  /*
 
5877
   *  Build the Signal-event part.
 
5878
   */
 
5879
 
 
5880
  frame = gtk_frame_new ("Signal events");
 
5881
  gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, DEF_PAD);
 
5882
 
 
5883
  vbox2 = gtk_vbox_new (TRUE, DEF_PAD_SMALL);
 
5884
  gtk_container_add (GTK_CONTAINER (frame), vbox2);
 
5885
  
 
5886
  hbox = gtk_hbox_new (FALSE, 3);
 
5887
  gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
 
5888
  label = gtk_label_new ("Signal:");
 
5889
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
5890
  calendar_data.last_sig = gtk_label_new ("");
 
5891
  gtk_box_pack_start (GTK_BOX (hbox), calendar_data.last_sig, FALSE, TRUE, 0);
 
5892
 
 
5893
  hbox = gtk_hbox_new (FALSE, 3);
 
5894
  gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
 
5895
  label = gtk_label_new ("Previous signal:");
 
5896
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
5897
  calendar_data.prev_sig = gtk_label_new ("");
 
5898
  gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev_sig, FALSE, TRUE, 0);
 
5899
 
 
5900
  hbox = gtk_hbox_new (FALSE, 3);
 
5901
  gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
 
5902
  label = gtk_label_new ("Second previous signal:");
 
5903
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
5904
  calendar_data.prev2_sig = gtk_label_new ("");
 
5905
  gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev2_sig, FALSE, TRUE, 0);
 
5906
 
 
5907
  bbox = gtk_hbutton_box_new ();
 
5908
  gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
 
5909
  gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
 
5910
 
 
5911
  button = gtk_button_new_with_label ("Close");
 
5912
  g_signal_connect (button, "clicked", 
 
5913
                    G_CALLBACK (gtk_main_quit), 
 
5914
                    NULL);
 
5915
  gtk_container_add (GTK_CONTAINER (bbox), button);
 
5916
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
5917
  gtk_widget_grab_default (button);
 
5918
 
 
5919
  gtk_widget_show_all (window);
 
5920
}
 
5921
 
 
5922
 
 
5923
int main (int   argc,
 
5924
          char *argv[])
 
5925
{
 
5926
  gtk_init (&amp;argc, &amp;argv);
 
5927
 
 
5928
  create_calendar ();
 
5929
 
 
5930
  gtk_main ();
 
5931
 
 
5932
  return 0;
 
5933
}
 
5934
<!-- example-end -->
 
5935
</programlisting>
 
5936
 
 
5937
</sect1>
 
5938
 
 
5939
<!-- ----------------------------------------------------------------- -->
 
5940
<sect1 id="sec-ColorSelection">
 
5941
<title>Color Selection</title>
 
5942
 
 
5943
<para>The color selection widget is, not surprisingly, a widget for
 
5944
interactive selection of colors. This composite widget lets the user
 
5945
select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
 
5946
Saturation, Value) triples.  This is done either by adjusting single
 
5947
values with sliders or entries, or by picking the desired color from a
 
5948
hue-saturation wheel/value bar.  Optionally, the opacity of the color
 
5949
can also be set.</para>
 
5950
 
 
5951
<para>The color selection widget currently emits only one signal,
 
5952
"color_changed", which is emitted whenever the current color in the
 
5953
widget changes, either when the user changes it or if it's set
 
5954
explicitly through gtk_color_selection_set_color().</para>
 
5955
 
 
5956
<para>Lets have a look at what the color selection widget has to offer
 
5957
us. The widget comes in two flavours: GtkColorSelection and
 
5958
GtkColorSelectionDialog.</para>
 
5959
 
 
5960
<programlisting role="C">
 
5961
GtkWidget *gtk_color_selection_new( void );
 
5962
</programlisting>
 
5963
        
 
5964
<para>You'll probably not be using this constructor directly. It creates an
 
5965
orphan ColorSelection widget which you'll have to parent
 
5966
yourself. The ColorSelection widget inherits from the VBox
 
5967
widget.</para>
 
5968
 
 
5969
<programlisting role="C">
 
5970
GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
 
5971
</programlisting>
 
5972
 
 
5973
<para>This is the most common color selection constructor. It creates a
 
5974
ColorSelectionDialog. It consists of a Frame containing a
 
5975
ColorSelection widget, an HSeparator and an HBox with three buttons,
 
5976
"Ok", "Cancel" and "Help". You can reach these buttons by accessing
 
5977
the "ok_button", "cancel_button" and "help_button" widgets in the
 
5978
ColorSelectionDialog structure,
 
5979
(i.e., <literal>GTK_COLOR_SELECTION_DIALOG (colorseldialog)->ok_button</literal>)).</para>
 
5980
 
 
5981
<programlisting role="C">
 
5982
void gtk_color_selection_set_has_opacity_control( GtkColorSelection *colorsel,
 
5983
                                                  gboolean           has_opacity );
 
5984
</programlisting>
 
5985
 
 
5986
<para>The color selection widget supports adjusting the opacity of a color
 
5987
(also known as the alpha channel). This is disabled by
 
5988
default. Calling this function with has_opacity set to TRUE enables
 
5989
opacity. Likewise, has_opacity set to FALSE will disable opacity.</para>
 
5990
 
 
5991
<programlisting role="C">
 
5992
void gtk_color_selection_set_current_color( GtkColorSelection *colorsel,
 
5993
                                            GdkColor          *color );
 
5994
 
 
5995
void gtk_color_selection_set_current_alpha( GtkColorSelection *colorsel,
 
5996
                                            guint16            alpha );
 
5997
</programlisting>
 
5998
 
 
5999
<para>You can set the current color explicitly by calling 
 
6000
gtk_color_selection_set_current_color() with a pointer to a GdkColor. 
 
6001
Setting the opacity (alpha channel) is done with 
 
6002
gtk_color_selection_set_current_alpha(). The alpha value should be between
 
6003
0 (fully transparent) and 65535 (fully opaque).
 
6004
</para>
 
6005
 
 
6006
<programlisting role="C">
 
6007
void gtk_color_selection_get_current_color( GtkColorSelection *colorsel,
 
6008
                                            GdkColor *color );
 
6009
 
 
6010
void gtk_color_selection_get_current_alpha( GtkColorSelection *colorsel,
 
6011
                                            guint16           *alpha );
 
6012
</programlisting>
 
6013
 
 
6014
<para>When you need to query the current color, typically when you've
 
6015
received a "color_changed" signal, you use these functions.</para>
 
6016
 
 
6017
<para><!-- Need to do a whole section on DnD - TRG
 
6018
Drag and drop
 
6019
-------------</para>
 
6020
 
 
6021
<para>The color sample areas (right under the hue-saturation wheel) supports
 
6022
drag and drop. The type of drag and drop is "application/x-color". The
 
6023
message data consists of an array of 4 (or 5 if opacity is enabled)
 
6024
gdouble values, where the value at position 0 is 0.0 (opacity on) or
 
6025
1.0 (opacity off) followed by the red, green and blue values at
 
6026
positions 1,2 and 3 respectively.  If opacity is enabled, the opacity
 
6027
is passed in the value at position 4.
 
6028
--></para>
 
6029
 
 
6030
<para>Here's a simple example demonstrating the use of the
 
6031
ColorSelectionDialog. The program displays a window containing a
 
6032
drawing area. Clicking on it opens a color selection dialog, and
 
6033
changing the color in the color selection dialog changes the
 
6034
background color.</para>
 
6035
 
 
6036
<para>
 
6037
<inlinemediaobject>
 
6038
<imageobject>
 
6039
<imagedata fileref="images/colorsel.png" format="png">
 
6040
</imageobject>
 
6041
</inlinemediaobject>
 
6042
</para>
 
6043
 
 
6044
<programlisting role="C">
 
6045
<!-- example-start colorsel colorsel.c -->
 
6046
 
 
6047
#include &lt;glib.h&gt;
 
6048
#include &lt;gdk/gdk.h&gt;
 
6049
#include &lt;gtk/gtk.h&gt;
 
6050
 
 
6051
GtkWidget *colorseldlg = NULL;
 
6052
GtkWidget *drawingarea = NULL;
 
6053
GdkColor color;
 
6054
 
 
6055
/* Color changed handler */
 
6056
 
 
6057
static void color_changed_cb( GtkWidget         *widget,
 
6058
                              GtkColorSelection *colorsel )
 
6059
{
 
6060
  GdkColor ncolor;
 
6061
 
 
6062
  gtk_color_selection_get_current_color (colorsel, &amp;ncolor);
 
6063
  gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &amp;ncolor);       
 
6064
}
 
6065
 
 
6066
/* Drawingarea event handler */
 
6067
 
 
6068
static gboolean area_event( GtkWidget *widget,
 
6069
                            GdkEvent  *event,
 
6070
                            gpointer   client_data )
 
6071
{
 
6072
  gint handled = FALSE;
 
6073
  gint response;
 
6074
  GtkColorSelection *colorsel;
 
6075
 
 
6076
  /* Check if we've received a button pressed event */
 
6077
 
 
6078
  if (event-&gt;type == GDK_BUTTON_PRESS)
 
6079
    {
 
6080
      handled = TRUE;
 
6081
 
 
6082
       /* Create color selection dialog */
 
6083
      if (colorseldlg == NULL)
 
6084
        colorseldlg = gtk_color_selection_dialog_new ("Select background color");
 
6085
 
 
6086
      /* Get the ColorSelection widget */
 
6087
      colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (colorseldlg)-&gt;colorsel);
 
6088
 
 
6089
      gtk_color_selection_set_previous_color (colorsel, &amp;color);
 
6090
      gtk_color_selection_set_current_color (colorsel, &amp;color);
 
6091
      gtk_color_selection_set_has_palette (colorsel, TRUE);
 
6092
 
 
6093
      /* Connect to the "color_changed" signal, set the client-data
 
6094
       * to the colorsel widget */
 
6095
      g_signal_connect (G_OBJECT (colorsel), "color_changed",
 
6096
                        G_CALLBACK (color_changed_cb), (gpointer) colorsel);
 
6097
 
 
6098
      /* Show the dialog */
 
6099
      response = gtk_dialog_run (GTK_DIALOG (colorseldlg));
 
6100
 
 
6101
      if (response == GTK_RESPONSE_OK)
 
6102
        gtk_color_selection_get_current_color (colorsel, &amp;color);
 
6103
      else 
 
6104
        gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &amp;color);
 
6105
 
 
6106
      gtk_widget_hide (colorseldlg);
 
6107
    }
 
6108
 
 
6109
  return handled;
 
6110
}
 
6111
 
 
6112
/* Close down and exit handler */
 
6113
 
 
6114
static gboolean destroy_window( GtkWidget *widget,
 
6115
                                GdkEvent  *event,
 
6116
                                gpointer   client_data )
 
6117
{
 
6118
  gtk_main_quit ();
 
6119
  return TRUE;
 
6120
}
 
6121
 
 
6122
/* Main */
 
6123
 
 
6124
gint main( gint   argc,
 
6125
           gchar *argv[] )
 
6126
{
 
6127
  GtkWidget *window;
 
6128
 
 
6129
  /* Initialize the toolkit, remove gtk-related commandline stuff */
 
6130
 
 
6131
  gtk_init (&amp;argc, &amp;argv);
 
6132
 
 
6133
  /* Create toplevel window, set title and policies */
 
6134
 
 
6135
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
6136
  gtk_window_set_title (GTK_WINDOW (window), "Color selection test");
 
6137
  gtk_window_set_policy (GTK_WINDOW (window), TRUE, TRUE, TRUE);
 
6138
 
 
6139
  /* Attach to the "delete" and "destroy" events so we can exit */
 
6140
 
 
6141
  g_signal_connect (GTK_OBJECT (window), "delete_event",
 
6142
                    GTK_SIGNAL_FUNC (destroy_window), (gpointer) window);
 
6143
  
 
6144
  /* Create drawingarea, set size and catch button events */
 
6145
 
 
6146
  drawingarea = gtk_drawing_area_new ();
 
6147
 
 
6148
  color.red = 0;
 
6149
  color.blue = 65535;
 
6150
  color.green = 0;
 
6151
  gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &amp;color);       
 
6152
 
 
6153
  gtk_widget_set_size_request (GTK_WIDGET (drawingarea), 200, 200);
 
6154
 
 
6155
  gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
 
6156
 
 
6157
  g_signal_connect (GTK_OBJECT (drawingarea), "event", 
 
6158
                    GTK_SIGNAL_FUNC (area_event), (gpointer) drawingarea);
 
6159
  
 
6160
  /* Add drawingarea to window, then show them both */
 
6161
 
 
6162
  gtk_container_add (GTK_CONTAINER (window), drawingarea);
 
6163
 
 
6164
  gtk_widget_show (drawingarea);
 
6165
  gtk_widget_show (window);
 
6166
  
 
6167
  /* Enter the gtk main loop (this never returns) */
 
6168
 
 
6169
  gtk_main ();
 
6170
 
 
6171
  /* Satisfy grumpy compilers */
 
6172
 
 
6173
  return 0;
 
6174
}
 
6175
<!-- example-end -->
 
6176
</programlisting>
 
6177
 
 
6178
</sect1>
 
6179
 
 
6180
<!-- ----------------------------------------------------------------- -->
 
6181
<sect1 id="sec-FileSelections">
 
6182
<title>File Selections</title>
 
6183
 
 
6184
<para>The file selection widget is a quick and simple way to display a File
 
6185
dialog box. It comes complete with Ok, Cancel, and Help buttons, a
 
6186
great way to cut down on programming time.</para>
 
6187
 
 
6188
<para>To create a new file selection box use:</para>
 
6189
 
 
6190
<programlisting role="C">
 
6191
GtkWidget *gtk_file_selection_new( const gchar *title );
 
6192
</programlisting>
 
6193
 
 
6194
<para>To set the filename, for example to bring up a specific directory, or
 
6195
give a default filename, use this function:</para>
 
6196
 
 
6197
<programlisting role="C">
 
6198
void gtk_file_selection_set_filename( GtkFileSelection *filesel,
 
6199
                                      const gchar      *filename );
 
6200
</programlisting>
 
6201
 
 
6202
<para>To grab the text that the user has entered or clicked on, use this 
 
6203
function:</para>
 
6204
 
 
6205
<programlisting role="C">
 
6206
gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
 
6207
</programlisting>
 
6208
 
 
6209
<para>There are also pointers to the widgets contained within the file 
 
6210
selection widget. These are:</para>
 
6211
 
 
6212
<programlisting role="C">
 
6213
  dir_list
 
6214
  file_list
 
6215
  selection_entry
 
6216
  selection_text
 
6217
  main_vbox
 
6218
  ok_button
 
6219
  cancel_button
 
6220
  help_button
 
6221
</programlisting>
 
6222
 
 
6223
<para>Most likely you will want to use the ok_button, cancel_button, and
 
6224
help_button pointers in signaling their use.</para>
 
6225
 
 
6226
<para>Included here is an example stolen from <filename>testgtk.c</filename>,
 
6227
modified to run on its own. As you will see, there is nothing much to creating a file
 
6228
selection widget. While in this example the Help button appears on the
 
6229
screen, it does nothing as there is not a signal attached to it.</para>
 
6230
 
 
6231
<para>
 
6232
<inlinemediaobject>
 
6233
<imageobject>
 
6234
<imagedata fileref="images/filesel.png" format="png">
 
6235
</imageobject>
 
6236
</inlinemediaobject>
 
6237
</para>
 
6238
 
 
6239
<programlisting role="C">
 
6240
<!-- example-start filesel filesel.c -->
 
6241
 
 
6242
#include &lt;gtk/gtk.h&gt;
 
6243
 
 
6244
/* Get the selected filename and print it to the console */
 
6245
static void file_ok_sel( GtkWidget        *w,
 
6246
                         GtkFileSelection *fs )
 
6247
{
 
6248
    g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
 
6249
}
 
6250
 
 
6251
int main( int   argc,
 
6252
          char *argv[] )
 
6253
{
 
6254
    GtkWidget *filew;
 
6255
    
 
6256
    gtk_init (&amp;argc, &amp;argv);
 
6257
    
 
6258
    /* Create a new file selection widget */
 
6259
    filew = gtk_file_selection_new ("File selection");
 
6260
    
 
6261
    g_signal_connect (G_OBJECT (filew), "destroy",
 
6262
                      G_CALLBACK (gtk_main_quit), NULL);
 
6263
    /* Connect the ok_button to file_ok_sel function */
 
6264
    g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)-&gt;ok_button),
 
6265
                      "clicked", G_CALLBACK (file_ok_sel), (gpointer) filew);
 
6266
    
 
6267
    /* Connect the cancel_button to destroy the widget */
 
6268
    g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (filew)-&gt;cancel_button),
 
6269
                              "clicked", G_CALLBACK (gtk_widget_destroy),
 
6270
                              G_OBJECT (filew));
 
6271
    
 
6272
    /* Lets set the filename, as if this were a save dialog, and we are giving
 
6273
     a default filename */
 
6274
    gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), 
 
6275
                                     "penguin.png");
 
6276
    
 
6277
    gtk_widget_show (filew);
 
6278
    gtk_main ();
 
6279
    return 0;
 
6280
}
 
6281
<!-- example-end -->
 
6282
</programlisting>
 
6283
 
 
6284
</sect1>
 
6285
</chapter>
 
6286
 
 
6287
<!-- ***************************************************************** -->
 
6288
<chapter id="ch-ContainerWidgets">
 
6289
<title>Container Widgets</title>
 
6290
 
 
6291
<!-- ----------------------------------------------------------------- -->   
 
6292
<sect1 id="sec-EventBox">
 
6293
<title>The EventBox</title>
 
6294
 
 
6295
<para>Some GTK widgets don't have associated X windows, so they just draw on
 
6296
their parents. Because of this, they cannot receive events and if they
 
6297
are incorrectly sized, they don't clip so you can get messy
 
6298
overwriting, etc. If you require more from these widgets, the EventBox
 
6299
is for you.</para>
 
6300
 
 
6301
<para>At first glance, the EventBox widget might appear to be totally
 
6302
useless. It draws nothing on the screen and responds to no
 
6303
events. However, it does serve a function - it provides an X window
 
6304
for its child widget. This is important as many GTK widgets do not
 
6305
have an associated X window. Not having an X window saves memory and
 
6306
improves performance, but also has some drawbacks. A widget without an
 
6307
X window cannot receive events, and does not perform any clipping on
 
6308
its contents. Although the name <emphasis>EventBox</emphasis> emphasizes the
 
6309
event-handling function, the widget can also be used for clipping.
 
6310
(and more, see the example below).</para>
 
6311
 
 
6312
<para>To create a new EventBox widget, use:</para>
 
6313
 
 
6314
<programlisting role="C">
 
6315
GtkWidget *gtk_event_box_new( void );
 
6316
</programlisting>
 
6317
 
 
6318
<para>A child widget can then be added to this EventBox:</para>
 
6319
 
 
6320
<programlisting role="C">
 
6321
    gtk_container_add (GTK_CONTAINER (event_box), child_widget);
 
6322
</programlisting>
 
6323
 
 
6324
<para>The following example demonstrates both uses of an EventBox - a label
 
6325
is created that is clipped to a small box, and set up so that a
 
6326
mouse-click on the label causes the program to exit. Resizing the
 
6327
window reveals varying amounts of the label.</para>
 
6328
 
 
6329
<para>
 
6330
<inlinemediaobject>
 
6331
<imageobject>
 
6332
<imagedata fileref="images/eventbox.png" format="png">
 
6333
</imageobject>
 
6334
</inlinemediaobject>
 
6335
</para>
 
6336
 
 
6337
<programlisting role="C">
 
6338
<!-- example-start eventbox eventbox.c -->
 
6339
 
 
6340
#include &lt;stdlib.h&gt;
 
6341
#include &lt;gtk/gtk.h&gt;
 
6342
 
 
6343
int main( int argc,
 
6344
          char *argv[] )
 
6345
{
 
6346
    GtkWidget *window;
 
6347
    GtkWidget *event_box;
 
6348
    GtkWidget *label;
 
6349
    
 
6350
    gtk_init (&amp;argc, &amp;argv);
 
6351
    
 
6352
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
6353
    
 
6354
    gtk_window_set_title (GTK_WINDOW (window), "Event Box");
 
6355
    
 
6356
    g_signal_connect (G_OBJECT (window), "destroy",
 
6357
                      G_CALLBACK (exit), NULL);
 
6358
    
 
6359
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
6360
    
 
6361
    /* Create an EventBox and add it to our toplevel window */
 
6362
    
 
6363
    event_box = gtk_event_box_new ();
 
6364
    gtk_container_add (GTK_CONTAINER (window), event_box);
 
6365
    gtk_widget_show (event_box);
 
6366
    
 
6367
    /* Create a long label */
 
6368
    
 
6369
    label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
 
6370
    gtk_container_add (GTK_CONTAINER (event_box), label);
 
6371
    gtk_widget_show (label);
 
6372
    
 
6373
    /* Clip it short. */
 
6374
    gtk_widget_set_size_request (label, 110, 20);
 
6375
    
 
6376
    /* And bind an action to it */
 
6377
    gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
 
6378
    g_signal_connect (G_OBJECT (event_box), "button_press_event",
 
6379
                      G_CALLBACK (exit), NULL);
 
6380
    
 
6381
    /* Yet one more thing you need an X window for ... */
 
6382
    
 
6383
    gtk_widget_realize (event_box);
 
6384
    gdk_window_set_cursor (event_box-&gt;window, gdk_cursor_new (GDK_HAND1));
 
6385
    
 
6386
    gtk_widget_show (window);
 
6387
    
 
6388
    gtk_main ();
 
6389
    
 
6390
    return 0;
 
6391
}
 
6392
<!-- example-end -->
 
6393
</programlisting>
 
6394
 
 
6395
</sect1>
 
6396
 
 
6397
<!-- ----------------------------------------------------------------- -->   
 
6398
<sect1 id="sec-TheAlignmentWidget">
 
6399
<title>The Alignment widget</title>
 
6400
 
 
6401
<para>The alignment widget allows you to place a widget within its window at
 
6402
a position and size relative to the size of the Alignment widget
 
6403
itself. For example, it can be very useful for centering a widget
 
6404
within the window.</para>
 
6405
 
 
6406
<para>There are only two functions associated with the Alignment widget:</para>
 
6407
 
 
6408
<programlisting role="C">
 
6409
GtkWidget* gtk_alignment_new( gfloat xalign,
 
6410
                              gfloat yalign,
 
6411
                              gfloat xscale,
 
6412
                              gfloat yscale );
 
6413
 
 
6414
void gtk_alignment_set( GtkAlignment *alignment,
 
6415
                        gfloat        xalign,
 
6416
                        gfloat        yalign,
 
6417
                        gfloat        xscale,
 
6418
                        gfloat        yscale );
 
6419
</programlisting>
 
6420
 
 
6421
<para>The first function creates a new Alignment widget with the specified
 
6422
parameters. The second function allows the alignment parameters of an
 
6423
exisiting Alignment widget to be altered.</para>
 
6424
 
 
6425
<para>All four alignment parameters are floating point numbers which can
 
6426
range from 0.0 to 1.0. The <literal>xalign</literal> and <literal>yalign</literal> arguments
 
6427
affect the position of the widget placed within the Alignment
 
6428
widget. The <literal>xscale</literal> and <literal>yscale</literal> arguments affect the amount of
 
6429
space allocated to the widget.</para>
 
6430
 
 
6431
<para>A child widget can be added to this Alignment widget using:</para>
 
6432
 
 
6433
<programlisting role="C">
 
6434
    gtk_container_add (GTK_CONTAINER (alignment), child_widget);
 
6435
</programlisting>
 
6436
 
 
6437
<para>For an example of using an Alignment widget, refer to the example for
 
6438
the <link linkend="sec-ProgressBars">Progress Bar</link> widget.</para>
 
6439
 
 
6440
</sect1>
 
6441
 
 
6442
<!-- ----------------------------------------------------------------- -->
 
6443
<sect1 id="sec-FixedContainer">
 
6444
<title>Fixed Container</title>
 
6445
 
 
6446
<para>The Fixed container allows you to place widgets at a fixed position
 
6447
within it's window, relative to it's upper left hand corner. The
 
6448
position of the widgets can be changed dynamically.</para>
 
6449
 
 
6450
<para>There are only a few functions associated with the fixed widget:</para>
 
6451
 
 
6452
<programlisting role="C">
 
6453
GtkWidget* gtk_fixed_new( void );
 
6454
 
 
6455
void gtk_fixed_put( GtkFixed  *fixed,
 
6456
                    GtkWidget *widget,
 
6457
                    gint       x,
 
6458
                    gint       y );
 
6459
 
 
6460
void gtk_fixed_move( GtkFixed  *fixed,
 
6461
                     GtkWidget *widget,
 
6462
                     gint       x,
 
6463
                     gint       y );
 
6464
</programlisting>
 
6465
 
 
6466
<para>The function gtk_fixed_new() allows you to create a new Fixed
 
6467
container.</para>
 
6468
 
 
6469
<para>gtk_fixed_put() places <literal>widget</literal> in the container <literal>fixed</literal> at
 
6470
the position specified by <literal>x</literal> and <literal>y</literal>.</para>
 
6471
 
 
6472
<para>gtk_fixed_move() allows the specified widget to be moved to a new
 
6473
position.</para>
 
6474
 
 
6475
<programlisting role="C">
 
6476
void gtk_fixed_set_has_window( GtkFixed  *fixed,
 
6477
                               gboolean   has_window );
 
6478
 
 
6479
gboolean gtk_fixed_get_has_window( GtkFixed *fixed );
 
6480
</programlisting>
 
6481
 
 
6482
<para>Normally, Fixed widgets don't have their own X window. Since this is
 
6483
different from the behaviour of Fixed widgets in earlier releases of GTK, 
 
6484
the function gtk_fixed_set_has_window() allows the creation of Fixed widgets 
 
6485
<emphasis>with</emphasis> their own window. It has to be called before
 
6486
realizing the widget.</para>
 
6487
 
 
6488
<para>The following example illustrates how to use the Fixed Container.</para>
 
6489
 
 
6490
<para>
 
6491
<inlinemediaobject>
 
6492
<imageobject>
 
6493
<imagedata fileref="images/fixed.png" format="png">
 
6494
</imageobject>
 
6495
</inlinemediaobject>
 
6496
</para>
 
6497
 
 
6498
<programlisting role="C">
 
6499
<!-- example-start fixed fixed.c -->
 
6500
 
 
6501
#include &lt;gtk/gtk.h&gt;
 
6502
 
 
6503
/* I'm going to be lazy and use some global variables to
 
6504
 * store the position of the widget within the fixed
 
6505
 * container */
 
6506
gint x = 50;
 
6507
gint y = 50;
 
6508
 
 
6509
/* This callback function moves the button to a new position
 
6510
 * in the Fixed container. */
 
6511
static void move_button( GtkWidget *widget,
 
6512
                         GtkWidget *fixed )
 
6513
{
 
6514
  x = (x + 30) % 300;
 
6515
  y = (y + 50) % 300;
 
6516
  gtk_fixed_move (GTK_FIXED (fixed), widget, x, y); 
 
6517
}
 
6518
 
 
6519
int main( int   argc,
 
6520
          char *argv[] )
 
6521
{
 
6522
  /* GtkWidget is the storage type for widgets */
 
6523
  GtkWidget *window;
 
6524
  GtkWidget *fixed;
 
6525
  GtkWidget *button;
 
6526
  gint i;
 
6527
 
 
6528
  /* Initialise GTK */
 
6529
  gtk_init (&amp;argc, &amp;argv);
 
6530
    
 
6531
  /* Create a new window */
 
6532
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
6533
  gtk_window_set_title (GTK_WINDOW (window), "Fixed Container");
 
6534
 
 
6535
  /* Here we connect the "destroy" event to a signal handler */ 
 
6536
  g_signal_connect (G_OBJECT (window), "destroy",
 
6537
                    G_CALLBACK (gtk_main_quit), NULL);
 
6538
 
 
6539
  /* Sets the border width of the window. */
 
6540
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
6541
 
 
6542
  /* Create a Fixed Container */
 
6543
  fixed = gtk_fixed_new ();
 
6544
  gtk_container_add (GTK_CONTAINER (window), fixed);
 
6545
  gtk_widget_show (fixed);
 
6546
  
 
6547
  for (i = 1 ; i &lt;= 3 ; i++) {
 
6548
    /* Creates a new button with the label "Press me" */
 
6549
    button = gtk_button_new_with_label ("Press me");
 
6550
  
 
6551
    /* When the button receives the "clicked" signal, it will call the
 
6552
     * function move_button() passing it the Fixed Container as its
 
6553
     * argument. */
 
6554
    g_signal_connect (G_OBJECT (button), "clicked",
 
6555
                      G_CALLBACK (move_button), (gpointer) fixed);
 
6556
  
 
6557
    /* This packs the button into the fixed containers window. */
 
6558
    gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50);
 
6559
  
 
6560
    /* The final step is to display this newly created widget. */
 
6561
    gtk_widget_show (button);
 
6562
  }
 
6563
 
 
6564
  /* Display the window */
 
6565
  gtk_widget_show (window);
 
6566
    
 
6567
  /* Enter the event loop */
 
6568
  gtk_main ();
 
6569
    
 
6570
  return 0;
 
6571
}
 
6572
<!-- example-end -->
 
6573
</programlisting>
 
6574
 
 
6575
</sect1>
 
6576
 
 
6577
<!-- ----------------------------------------------------------------- -->
 
6578
<sect1 id="sec-LayoutContainer">
 
6579
<title>Layout Container</title>
 
6580
 
 
6581
<para>The Layout container is similar to the Fixed container except that it
 
6582
implements an infinite (where infinity is less than 2^32) scrolling
 
6583
area. The X window system has a limitation where windows can be at
 
6584
most 32767 pixels wide or tall. The Layout container gets around this
 
6585
limitation by doing some exotic stuff using window and bit gravities,
 
6586
so that you can have smooth scrolling even when you have many child
 
6587
widgets in your scrolling area.</para>
 
6588
 
 
6589
<para>A Layout container is created using:</para>
 
6590
 
 
6591
<programlisting role="C">
 
6592
GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
 
6593
                           GtkAdjustment *vadjustment );
 
6594
</programlisting>
 
6595
 
 
6596
<para>As you can see, you can optionally specify the Adjustment objects that
 
6597
the Layout widget will use for its scrolling.</para>
 
6598
 
 
6599
<para>You can add and move widgets in the Layout container using the
 
6600
following two functions:</para>
 
6601
 
 
6602
<programlisting role="C">
 
6603
void gtk_layout_put( GtkLayout *layout,
 
6604
                     GtkWidget *widget,
 
6605
                     gint       x,
 
6606
                     gint       y );
 
6607
 
 
6608
void gtk_layout_move( GtkLayout *layout,
 
6609
                      GtkWidget *widget,
 
6610
                      gint       x,
 
6611
                      gint       y );
 
6612
</programlisting>
 
6613
 
 
6614
<para>The size of the Layout container can be set using the next function:</para>
 
6615
 
 
6616
<programlisting role="C">
 
6617
void gtk_layout_set_size( GtkLayout *layout,
 
6618
                          guint      width,
 
6619
                          guint      height );
 
6620
</programlisting>
 
6621
 
 
6622
<para>The final four functions for use with Layout widgets are for
 
6623
manipulating the horizontal and vertical adjustment widgets:</para>
 
6624
 
 
6625
<programlisting role="C">
 
6626
GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
 
6627
 
 
6628
GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
 
6629
 
 
6630
void gtk_layout_set_hadjustment( GtkLayout     *layout,
 
6631
                                 GtkAdjustment *adjustment );
 
6632
 
 
6633
void gtk_layout_set_vadjustment( GtkLayout     *layout,
 
6634
                                 GtkAdjustment *adjustment);
 
6635
</programlisting>
 
6636
 
 
6637
</sect1>
 
6638
 
 
6639
<!-- ----------------------------------------------------------------- -->
 
6640
<sect1 id="sec-Frames">
 
6641
<title>Frames</title>
 
6642
 
 
6643
<para>Frames can be used to enclose one or a group of widgets with a box
 
6644
which can optionally be labelled. The position of the label and the
 
6645
style of the box can be altered to suit.</para>
 
6646
 
 
6647
<para>A Frame can be created with the following function:</para>
 
6648
 
 
6649
<programlisting role="C">
 
6650
GtkWidget *gtk_frame_new( const gchar *label );
 
6651
</programlisting>
 
6652
 
 
6653
<para>The label is by default placed in the upper left hand corner of the
 
6654
frame. A value of NULL for the <literal>label</literal> argument will result in no
 
6655
label being displayed. The text of the label can be changed using the
 
6656
next function.</para>
 
6657
 
 
6658
<programlisting role="C">
 
6659
void gtk_frame_set_label( GtkFrame    *frame,
 
6660
                          const gchar *label );
 
6661
</programlisting>
 
6662
 
 
6663
<para>The position of the label can be changed using this function:</para>
 
6664
 
 
6665
<programlisting role="C">
 
6666
void gtk_frame_set_label_align( GtkFrame *frame,
 
6667
                                gfloat    xalign,
 
6668
                                gfloat    yalign );
 
6669
</programlisting>
 
6670
 
 
6671
<para><literal>xalign</literal> and <literal>yalign</literal> take values between 0.0 and 1.0. <literal>xalign</literal>
 
6672
indicates the position of the label along the top horizontal of the
 
6673
frame. <literal>yalign</literal> is not currently used. The default value of xalign
 
6674
is 0.0 which places the label at the left hand end of the frame.</para>
 
6675
 
 
6676
<para>The next function alters the style of the box that is used to outline
 
6677
the frame.</para>
 
6678
 
 
6679
<programlisting role="C">
 
6680
void gtk_frame_set_shadow_type( GtkFrame      *frame,
 
6681
                                GtkShadowType  type);
 
6682
</programlisting>
 
6683
 
 
6684
<para>The <literal>type</literal> argument can take one of the following values:</para>
 
6685
<programlisting role="C">
 
6686
  GTK_SHADOW_NONE
 
6687
  GTK_SHADOW_IN
 
6688
  GTK_SHADOW_OUT
 
6689
  GTK_SHADOW_ETCHED_IN (the default)
 
6690
  GTK_SHADOW_ETCHED_OUT
 
6691
</programlisting>
 
6692
 
 
6693
<para>The following code example illustrates the use of the Frame widget.</para>
 
6694
 
 
6695
<para>
 
6696
<inlinemediaobject>
 
6697
<imageobject>
 
6698
<imagedata fileref="images/frame.png" format="png">
 
6699
</imageobject>
 
6700
</inlinemediaobject>
 
6701
</para>
 
6702
 
 
6703
<programlisting role="C">
 
6704
<!-- example-start frame frame.c -->
 
6705
 
 
6706
#include &lt;gtk/gtk.h&gt;
 
6707
 
 
6708
int main( int   argc,
 
6709
          char *argv[] )
 
6710
{
 
6711
  /* GtkWidget is the storage type for widgets */
 
6712
  GtkWidget *window;
 
6713
  GtkWidget *frame;
 
6714
 
 
6715
  /* Initialise GTK */
 
6716
  gtk_init (&amp;argc, &amp;argv);
 
6717
    
 
6718
  /* Create a new window */
 
6719
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
6720
  gtk_window_set_title (GTK_WINDOW (window), "Frame Example");
 
6721
 
 
6722
  /* Here we connect the "destroy" event to a signal handler */ 
 
6723
  g_signal_connect (G_OBJECT (window), "destroy",
 
6724
                    G_CALLBACK (gtk_main_quit), NULL);
 
6725
 
 
6726
  gtk_widget_set_size_request (window, 300, 300);
 
6727
  /* Sets the border width of the window. */
 
6728
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
6729
 
 
6730
  /* Create a Frame */
 
6731
  frame = gtk_frame_new (NULL);
 
6732
  gtk_container_add (GTK_CONTAINER (window), frame);
 
6733
 
 
6734
  /* Set the frame's label */
 
6735
  gtk_frame_set_label (GTK_FRAME (frame), "GTK Frame Widget");
 
6736
 
 
6737
  /* Align the label at the right of the frame */
 
6738
  gtk_frame_set_label_align (GTK_FRAME (frame), 1.0, 0.0);
 
6739
 
 
6740
  /* Set the style of the frame */
 
6741
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
 
6742
 
 
6743
  gtk_widget_show (frame);
 
6744
  
 
6745
  /* Display the window */
 
6746
  gtk_widget_show (window);
 
6747
    
 
6748
  /* Enter the event loop */
 
6749
  gtk_main ();
 
6750
    
 
6751
  return 0;
 
6752
}
 
6753
<!-- example-end -->
 
6754
</programlisting>
 
6755
</sect1>
 
6756
 
 
6757
<!-- ----------------------------------------------------------------- -->   
 
6758
<sect1 id="sec-AspectFrames">
 
6759
<title>Aspect Frames</title>
 
6760
 
 
6761
<para>The aspect frame widget is like a frame widget, except that it also
 
6762
enforces the aspect ratio (that is, the ratio of the width to the
 
6763
height) of the child widget to have a certain value, adding extra
 
6764
space if necessary. This is useful, for instance, if you want to
 
6765
preview a larger image. The size of the preview should vary when the
 
6766
user resizes the window, but the aspect ratio needs to always match
 
6767
the original image.</para>
 
6768
  
 
6769
<para>To create a new aspect frame use:</para>
 
6770
 
 
6771
<programlisting role="C">
 
6772
GtkWidget *gtk_aspect_frame_new( const gchar *label,
 
6773
                                 gfloat       xalign,
 
6774
                                 gfloat       yalign,
 
6775
                                 gfloat       ratio,
 
6776
                                 gboolean     obey_child);
 
6777
</programlisting>
 
6778
   
 
6779
<para><literal>xalign</literal> and <literal>yalign</literal> specify alignment as with Alignment
 
6780
widgets. If <literal>obey_child</literal> is TRUE, the aspect ratio of a child
 
6781
widget will match the aspect ratio of the ideal size it requests.
 
6782
Otherwise, it is given by <literal>ratio</literal>.</para>
 
6783
   
 
6784
<para>To change the options of an existing aspect frame, you can use:</para>
 
6785
 
 
6786
<programlisting role="C">
 
6787
void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
 
6788
                           gfloat          xalign,
 
6789
                           gfloat          yalign,
 
6790
                           gfloat          ratio,
 
6791
                           gboolean        obey_child);
 
6792
</programlisting>
 
6793
   
 
6794
<para>As an example, the following program uses an AspectFrame to present a
 
6795
drawing area whose aspect ratio will always be 2:1, no matter how the
 
6796
user resizes the top-level window.</para>
 
6797
 
 
6798
<para>
 
6799
<inlinemediaobject>
 
6800
<imageobject>
 
6801
<imagedata fileref="images/aspectframe.png" format="png">
 
6802
</imageobject>
 
6803
</inlinemediaobject>
 
6804
</para>
 
6805
 
 
6806
<programlisting role="C">
 
6807
<!-- example-start aspectframe aspectframe.c -->
 
6808
 
 
6809
#include &lt;gtk/gtk.h&gt;
 
6810
   
 
6811
int main( int argc,
 
6812
          char *argv[] )
 
6813
{
 
6814
    GtkWidget *window;
 
6815
    GtkWidget *aspect_frame;
 
6816
    GtkWidget *drawing_area;
 
6817
    gtk_init (&amp;argc, &amp;argv);
 
6818
   
 
6819
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
6820
    gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
 
6821
    g_signal_connect (G_OBJECT (window), "destroy",
 
6822
                      G_CALLBACK (gtk_main_quit), NULL);
 
6823
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
6824
   
 
6825
    /* Create an aspect_frame and add it to our toplevel window */
 
6826
   
 
6827
    aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
 
6828
                                         0.5, /* center x */
 
6829
                                         0.5, /* center y */
 
6830
                                         2, /* xsize/ysize = 2 */
 
6831
                                         FALSE /* ignore child's aspect */);
 
6832
   
 
6833
    gtk_container_add (GTK_CONTAINER (window), aspect_frame);
 
6834
    gtk_widget_show (aspect_frame);
 
6835
   
 
6836
    /* Now add a child widget to the aspect frame */
 
6837
   
 
6838
    drawing_area = gtk_drawing_area_new ();
 
6839
   
 
6840
    /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
 
6841
     * window since we are forcing a 2x1 aspect ratio */
 
6842
    gtk_widget_set_size_request (drawing_area, 200, 200);
 
6843
    gtk_container_add (GTK_CONTAINER (aspect_frame), drawing_area);
 
6844
    gtk_widget_show (drawing_area);
 
6845
   
 
6846
    gtk_widget_show (window);
 
6847
    gtk_main ();
 
6848
    return 0;
 
6849
}
 
6850
<!-- example-end -->
 
6851
</programlisting>
 
6852
 
 
6853
</sect1>
 
6854
 
 
6855
<!-- ----------------------------------------------------------------- -->   
 
6856
<sect1 id="sec-PanedWindowWidgets">
 
6857
<title>Paned Window Widgets</title>
 
6858
 
 
6859
<para>The paned window widgets are useful when you want to divide an area
 
6860
into two parts, with the relative size of the two parts controlled by
 
6861
the user. A groove is drawn between the two portions with a handle
 
6862
that the user can drag to change the ratio. The division can either be
 
6863
horizontal (HPaned) or vertical (VPaned).</para>
 
6864
   
 
6865
<para>To create a new paned window, call one of:</para>
 
6866
 
 
6867
<programlisting role="C">
 
6868
GtkWidget *gtk_hpaned_new (void);
 
6869
 
 
6870
GtkWidget *gtk_vpaned_new (void);
 
6871
</programlisting>
 
6872
 
 
6873
<para>After creating the paned window widget, you need to add child widgets
 
6874
to its two halves. To do this, use the functions:</para>
 
6875
 
 
6876
<programlisting role="C">
 
6877
void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
 
6878
 
 
6879
void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
 
6880
</programlisting>
 
6881
 
 
6882
<para><literal>gtk_paned_add1()</literal> adds the child widget to the left or top half of
 
6883
the paned window. <literal>gtk_paned_add2()</literal> adds the child widget to the
 
6884
right or bottom half of the paned window.</para>
 
6885
 
 
6886
<para>As an example, we will create part of the user interface of an
 
6887
imaginary email program. A window is divided into two portions
 
6888
vertically, with the top portion being a list of email messages and
 
6889
the bottom portion the text of the email message. Most of the program
 
6890
is pretty straightforward. A couple of points to note: text can't be
 
6891
added to a Text widget until it is realized. This could be done by
 
6892
calling gtk_widget_realize(), but as a demonstration of an
 
6893
alternate technique, we connect a handler to the "realize" signal to
 
6894
add the text. Also, we need to add the <literal>GTK_SHRINK</literal> option to some
 
6895
of the items in the table containing the text window and its
 
6896
scrollbars, so that when the bottom portion is made smaller, the
 
6897
correct portions shrink instead of being pushed off the bottom of the
 
6898
window.</para>
 
6899
 
 
6900
<para>
 
6901
<inlinemediaobject>
 
6902
<imageobject>
 
6903
<imagedata fileref="images/paned.png" format="png">
 
6904
</imageobject>
 
6905
</inlinemediaobject>
 
6906
</para>
 
6907
 
 
6908
<programlisting role="C">
 
6909
<!-- example-start paned paned.c -->
 
6910
 
 
6911
#include &lt;stdio.h&gt;
 
6912
#include &lt;gtk/gtk.h&gt;
 
6913
   
 
6914
/* Create the list of "messages" */
 
6915
static GtkWidget *create_list( void )
 
6916
{
 
6917
 
 
6918
    GtkWidget *scrolled_window;
 
6919
    GtkWidget *tree_view;
 
6920
    GtkListStore *model;
 
6921
    GtkTreeIter iter;
 
6922
    GtkCellRenderer *cell;
 
6923
    GtkTreeViewColumn *column;
 
6924
 
 
6925
    int i;
 
6926
   
 
6927
    /* Create a new scrolled window, with scrollbars only if needed */
 
6928
    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 
6929
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
 
6930
                                    GTK_POLICY_AUTOMATIC, 
 
6931
                                    GTK_POLICY_AUTOMATIC);
 
6932
   
 
6933
    model = gtk_list_store_new (1, G_TYPE_STRING);
 
6934
    tree_view = gtk_tree_view_new ();
 
6935
    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), 
 
6936
                                           tree_view);
 
6937
    gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
 
6938
    gtk_widget_show (tree_view);
 
6939
   
 
6940
    /* Add some messages to the window */
 
6941
    for (i = 0; i &lt; 10; i++) {
 
6942
        gchar *msg = g_strdup_printf ("Message #%d", i);
 
6943
        gtk_list_store_append (GTK_LIST_STORE (model), &amp;iter);
 
6944
        gtk_list_store_set (GTK_LIST_STORE (model), 
 
6945
                            &amp;iter,
 
6946
                            0, msg,
 
6947
                            -1);
 
6948
        g_free (msg);
 
6949
    }
 
6950
   
 
6951
    cell = gtk_cell_renderer_text_new ();
 
6952
 
 
6953
    column = gtk_tree_view_column_new_with_attributes ("Messages",
 
6954
                                                       cell,
 
6955
                                                       "text", 0,
 
6956
                                                       NULL);
 
6957
  
 
6958
    gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
 
6959
                                 GTK_TREE_VIEW_COLUMN (column));
 
6960
 
 
6961
    return scrolled_window;
 
6962
}
 
6963
   
 
6964
/* Add some text to our text widget - this is a callback that is invoked
 
6965
when our window is realized. We could also force our window to be
 
6966
realized with gtk_widget_realize, but it would have to be part of
 
6967
a hierarchy first */
 
6968
 
 
6969
static void insert_text( GtkTextBuffer *buffer )
 
6970
{
 
6971
   GtkTextIter iter;
 
6972
 
 
6973
   gtk_text_buffer_get_iter_at_offset (buffer, &amp;iter, 0);
 
6974
 
 
6975
   gtk_text_buffer_insert (buffer, &amp;iter,   
 
6976
    "From: pathfinder@nasa.gov\n"
 
6977
    "To: mom@nasa.gov\n"
 
6978
    "Subject: Made it!\n"
 
6979
    "\n"
 
6980
    "We just got in this morning. The weather has been\n"
 
6981
    "great - clear but cold, and there are lots of fun sights.\n"
 
6982
    "Sojourner says hi. See you soon.\n"
 
6983
    " -Path\n", -1);
 
6984
}
 
6985
   
 
6986
/* Create a scrolled text area that displays a "message" */
 
6987
static GtkWidget *create_text( void )
 
6988
{
 
6989
   GtkWidget *scrolled_window;
 
6990
   GtkWidget *view;
 
6991
   GtkTextBuffer *buffer;
 
6992
 
 
6993
   view = gtk_text_view_new ();
 
6994
   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
 
6995
 
 
6996
   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 
6997
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
 
6998
                                   GTK_POLICY_AUTOMATIC,
 
6999
                                   GTK_POLICY_AUTOMATIC);
 
7000
 
 
7001
   gtk_container_add (GTK_CONTAINER (scrolled_window), view);
 
7002
   insert_text (buffer);
 
7003
 
 
7004
   gtk_widget_show_all (scrolled_window);
 
7005
 
 
7006
   return scrolled_window;
 
7007
}
 
7008
   
 
7009
int main( int   argc,
 
7010
          char *argv[] )
 
7011
{
 
7012
    GtkWidget *window;
 
7013
    GtkWidget *vpaned;
 
7014
    GtkWidget *list;
 
7015
    GtkWidget *text;
 
7016
 
 
7017
    gtk_init (&amp;argc, &amp;argv);
 
7018
   
 
7019
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
7020
    gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
 
7021
    g_signal_connect (G_OBJECT (window), "destroy",
 
7022
                      G_CALLBACK (gtk_main_quit), NULL);
 
7023
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
7024
    gtk_widget_set_size_request (GTK_WIDGET (window), 450, 400);
 
7025
 
 
7026
    /* create a vpaned widget and add it to our toplevel window */
 
7027
   
 
7028
    vpaned = gtk_vpaned_new ();
 
7029
    gtk_container_add (GTK_CONTAINER (window), vpaned);
 
7030
    gtk_widget_show (vpaned);
 
7031
   
 
7032
    /* Now create the contents of the two halves of the window */
 
7033
   
 
7034
    list = create_list ();
 
7035
    gtk_paned_add1 (GTK_PANED (vpaned), list);
 
7036
    gtk_widget_show (list);
 
7037
   
 
7038
    text = create_text ();
 
7039
    gtk_paned_add2 (GTK_PANED (vpaned), text);
 
7040
    gtk_widget_show (text);
 
7041
    gtk_widget_show (window);
 
7042
 
 
7043
    gtk_main ();
 
7044
 
 
7045
    return 0;
 
7046
}
 
7047
<!-- example-end -->
 
7048
</programlisting>
 
7049
 
 
7050
</sect1>
 
7051
 
 
7052
<!-- ----------------------------------------------------------------- -->
 
7053
<sect1 id="sec-Viewports">
 
7054
<title>Viewports</title>
 
7055
 
 
7056
<para>It is unlikely that you will ever need to use the Viewport widget
 
7057
directly. You are much more likely to use the
 
7058
<link linkend="sec-ScrolledWindows">Scrolled Window</link> widget which
 
7059
itself uses the Viewport.</para>
 
7060
 
 
7061
<para>A viewport widget allows you to place a larger widget within it such
 
7062
that you can view a part of it at a time. It uses
 
7063
<link linkend="ch-Adjustments">Adjustments</link> to define the area that
 
7064
is currently in view.</para>
 
7065
 
 
7066
<para>A Viewport is created with the function</para>
 
7067
 
 
7068
<programlisting role="C">
 
7069
GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
 
7070
                             GtkAdjustment *vadjustment );
 
7071
</programlisting>
 
7072
 
 
7073
<para>As you can see you can specify the horizontal and vertical Adjustments
 
7074
that the widget is to use when you create the widget. It will create
 
7075
its own if you pass NULL as the value of the arguments.</para>
 
7076
 
 
7077
<para>You can get and set the adjustments after the widget has been created
 
7078
using the following four functions:</para>
 
7079
 
 
7080
<programlisting role="C">
 
7081
GtkAdjustment *gtk_viewport_get_hadjustment( GtkViewport *viewport );
 
7082
 
 
7083
GtkAdjustment *gtk_viewport_get_vadjustment( GtkViewport *viewport );
 
7084
 
 
7085
void gtk_viewport_set_hadjustment( GtkViewport   *viewport,
 
7086
                                   GtkAdjustment *adjustment );
 
7087
 
 
7088
void gtk_viewport_set_vadjustment( GtkViewport   *viewport,
 
7089
                                   GtkAdjustment *adjustment );
 
7090
</programlisting>
 
7091
 
 
7092
<para>The only other viewport function is used to alter its appearance:</para>
 
7093
 
 
7094
<programlisting role="C">
 
7095
void gtk_viewport_set_shadow_type( GtkViewport   *viewport,
 
7096
                                   GtkShadowType  type );
 
7097
</programlisting>
 
7098
 
 
7099
<para>Possible values for the <literal>type</literal> parameter are:</para>
 
7100
<programlisting role="C">
 
7101
  GTK_SHADOW_NONE,
 
7102
  GTK_SHADOW_IN,
 
7103
  GTK_SHADOW_OUT,
 
7104
  GTK_SHADOW_ETCHED_IN,
 
7105
  GTK_SHADOW_ETCHED_OUT
 
7106
</programlisting>
 
7107
 
 
7108
</sect1>
 
7109
 
 
7110
<!-- ----------------------------------------------------------------- -->
 
7111
<sect1 id="sec-ScrolledWindows"
 
7112
<title>Scrolled Windows</title>
 
7113
 
 
7114
<para>Scrolled windows are used to create a scrollable area with another
 
7115
widget inside it. You may insert any type of widget into a scrolled
 
7116
window, and it will be accessible regardless of the size by using the
 
7117
scrollbars.</para>
 
7118
 
 
7119
<para>The following function is used to create a new scrolled window.</para>
 
7120
 
 
7121
<programlisting role="C">
 
7122
GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
 
7123
                                    GtkAdjustment *vadjustment );
 
7124
</programlisting>
 
7125
 
 
7126
<para>Where the first argument is the adjustment for the horizontal
 
7127
direction, and the second, the adjustment for the vertical direction.
 
7128
These are almost always set to NULL.</para>
 
7129
 
 
7130
<programlisting role="C">
 
7131
void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
 
7132
                                     GtkPolicyType      hscrollbar_policy,
 
7133
                                     GtkPolicyType      vscrollbar_policy );
 
7134
</programlisting>
 
7135
 
 
7136
<para>This sets the policy to be used with respect to the scrollbars.
 
7137
The first argument is the scrolled window you wish to change. The second
 
7138
sets the policy for the horizontal scrollbar, and the third the policy for 
 
7139
the vertical scrollbar.</para>
 
7140
 
 
7141
<para>The policy may be one of <literal>GTK_POLICY_AUTOMATIC</literal> or
 
7142
<literal>GTK_POLICY_ALWAYS</literal>. <literal>GTK_POLICY_AUTOMATIC</literal> will automatically
 
7143
decide whether you need scrollbars, whereas <literal>GTK_POLICY_ALWAYS</literal>
 
7144
will always leave the scrollbars there.</para>
 
7145
 
 
7146
<para>You can then place your object into the scrolled window using the
 
7147
following function.</para>
 
7148
 
 
7149
<programlisting role="C">
 
7150
void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
 
7151
                                            GtkWidget         *child);
 
7152
</programlisting>
 
7153
 
 
7154
<para>Here is a simple example that packs a table with 100 toggle buttons
 
7155
into a scrolled window. I've only commented on the parts that may be
 
7156
new to you.</para>
 
7157
 
 
7158
<para>
 
7159
<inlinemediaobject>
 
7160
<imageobject>
 
7161
<imagedata fileref="images/scrolledwin.png" format="png">
 
7162
</imageobject>
 
7163
</inlinemediaobject>
 
7164
</para>
 
7165
 
 
7166
<programlisting role="C">
 
7167
<!-- example-start scrolledwin scrolledwin.c -->
 
7168
 
 
7169
#include &lt;stdio.h&gt;
 
7170
#include &lt;gtk/gtk.h&gt;
 
7171
 
 
7172
static void destroy( GtkWidget *widget,
 
7173
                     gpointer   data )
 
7174
{
 
7175
    gtk_main_quit ();
 
7176
}
 
7177
 
 
7178
int main( int   argc,
 
7179
          char *argv[] )
 
7180
{
 
7181
    static GtkWidget *window;
 
7182
    GtkWidget *scrolled_window;
 
7183
    GtkWidget *table;
 
7184
    GtkWidget *button;
 
7185
    char buffer[32];
 
7186
    int i, j;
 
7187
    
 
7188
    gtk_init (&amp;argc, &amp;argv);
 
7189
    
 
7190
    /* Create a new dialog window for the scrolled window to be
 
7191
     * packed into.  */
 
7192
    window = gtk_dialog_new ();
 
7193
    g_signal_connect (G_OBJECT (window), "destroy",
 
7194
                      G_CALLBACK (destroy), NULL);
 
7195
    gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
 
7196
    gtk_container_set_border_width (GTK_CONTAINER (window), 0);
 
7197
    gtk_widget_set_size_request (window, 300, 300);
 
7198
    
 
7199
    /* create a new scrolled window. */
 
7200
    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 
7201
    
 
7202
    gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
 
7203
    
 
7204
    /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
 
7205
     * GTK_POLICY_AUTOMATIC will automatically decide whether you need
 
7206
     * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
 
7207
     * there.  The first one is the horizontal scrollbar, the second, 
 
7208
     * the vertical. */
 
7209
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
 
7210
                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
 
7211
    /* The dialog window is created with a vbox packed into it. */                                                              
 
7212
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)-&gt;vbox), scrolled_window, 
 
7213
                        TRUE, TRUE, 0);
 
7214
    gtk_widget_show (scrolled_window);
 
7215
    
 
7216
    /* create a table of 10 by 10 squares. */
 
7217
    table = gtk_table_new (10, 10, FALSE);
 
7218
    
 
7219
    /* set the spacing to 10 on x and 10 on y */
 
7220
    gtk_table_set_row_spacings (GTK_TABLE (table), 10);
 
7221
    gtk_table_set_col_spacings (GTK_TABLE (table), 10);
 
7222
    
 
7223
    /* pack the table into the scrolled window */
 
7224
    gtk_scrolled_window_add_with_viewport (
 
7225
                   GTK_SCROLLED_WINDOW (scrolled_window), table);
 
7226
    gtk_widget_show (table);
 
7227
    
 
7228
    /* this simply creates a grid of toggle buttons on the table
 
7229
     * to demonstrate the scrolled window. */
 
7230
    for (i = 0; i &lt; 10; i++)
 
7231
       for (j = 0; j &lt; 10; j++) {
 
7232
          sprintf (buffer, "button (%d,%d)\n", i, j);
 
7233
          button = gtk_toggle_button_new_with_label (buffer);
 
7234
          gtk_table_attach_defaults (GTK_TABLE (table), button,
 
7235
                                     i, i+1, j, j+1);
 
7236
          gtk_widget_show (button);
 
7237
       }
 
7238
    
 
7239
    /* Add a "close" button to the bottom of the dialog */
 
7240
    button = gtk_button_new_with_label ("close");
 
7241
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
7242
                              G_CALLBACK (gtk_widget_destroy),
 
7243
                              G_OBJECT (window));
 
7244
    
 
7245
    /* this makes it so the button is the default. */
 
7246
    
 
7247
    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
7248
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)-&gt;action_area), button, TRUE, TRUE, 0);
 
7249
    
 
7250
    /* This grabs this button to be the default button. Simply hitting
 
7251
     * the "Enter" key will cause this button to activate. */
 
7252
    gtk_widget_grab_default (button);
 
7253
    gtk_widget_show (button);
 
7254
    
 
7255
    gtk_widget_show (window);
 
7256
    
 
7257
    gtk_main();
 
7258
    
 
7259
    return 0;
 
7260
}
 
7261
<!-- example-end -->
 
7262
</programlisting>
 
7263
 
 
7264
<para>Try playing with resizing the window. You'll notice how the scrollbars
 
7265
react. You may also wish to use the gtk_widget_set_size_request() call to set
 
7266
the default size of the window or other widgets.</para>
 
7267
 
 
7268
</sect1>
 
7269
 
 
7270
<!-- ----------------------------------------------------------------- -->   
 
7271
<sect1 id="sec-ButtonBoxes">
 
7272
<title>Button Boxes</title>
 
7273
 
 
7274
<para>Button Boxes are a convenient way to quickly layout a group of
 
7275
buttons. They come in both horizontal and vertical flavours. You
 
7276
create a new Button Box with one of the following calls, which create
 
7277
a horizontal or vertical box, respectively:</para>
 
7278
 
 
7279
<programlisting role="C">
 
7280
GtkWidget *gtk_hbutton_box_new( void );
 
7281
 
 
7282
GtkWidget *gtk_vbutton_box_new( void );
 
7283
</programlisting>
 
7284
 
 
7285
<para>Buttons are added to a Button Box using the usual function:</para>
 
7286
 
 
7287
<programlisting role="C">
 
7288
    gtk_container_add (GTK_CONTAINER (button_box), child_widget);
 
7289
</programlisting>
 
7290
 
 
7291
<para>Here's an example that illustrates all the different layout settings
 
7292
for Button Boxes.</para>
 
7293
 
 
7294
<para>
 
7295
<inlinemediaobject>
 
7296
<imageobject>
 
7297
<imagedata fileref="images/buttonbox.png" format="png">
 
7298
</imageobject>
 
7299
</inlinemediaobject>
 
7300
</para>
 
7301
 
 
7302
<programlisting role="C">
 
7303
<!-- example-start buttonbox buttonbox.c -->
 
7304
 
 
7305
#include &lt;gtk/gtk.h&gt;
 
7306
 
 
7307
/* Create a Button Box with the specified parameters */
 
7308
static GtkWidget *create_bbox( gint  horizontal,
 
7309
                               char *title,
 
7310
                               gint  spacing,
 
7311
                               gint  child_w,
 
7312
                               gint  child_h,
 
7313
                               gint  layout )
 
7314
{
 
7315
  GtkWidget *frame;
 
7316
  GtkWidget *bbox;
 
7317
  GtkWidget *button;
 
7318
 
 
7319
  frame = gtk_frame_new (title);
 
7320
 
 
7321
  if (horizontal)
 
7322
    bbox = gtk_hbutton_box_new ();
 
7323
  else
 
7324
    bbox = gtk_vbutton_box_new ();
 
7325
 
 
7326
  gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
 
7327
  gtk_container_add (GTK_CONTAINER (frame), bbox);
 
7328
 
 
7329
  /* Set the appearance of the Button Box */
 
7330
  gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
 
7331
  gtk_box_set_spacing (GTK_BOX (bbox), spacing);
 
7332
  /*gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);*/
 
7333
 
 
7334
  button = gtk_button_new_from_stock (GTK_STOCK_OK);
 
7335
  gtk_container_add (GTK_CONTAINER (bbox), button);
 
7336
 
 
7337
  button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
 
7338
  gtk_container_add (GTK_CONTAINER (bbox), button);
 
7339
 
 
7340
  button = gtk_button_new_from_stock (GTK_STOCK_HELP);
 
7341
  gtk_container_add (GTK_CONTAINER (bbox), button);
 
7342
 
 
7343
  return frame;
 
7344
}
 
7345
 
 
7346
int main( int   argc,
 
7347
          char *argv[] )
 
7348
{
 
7349
  static GtkWidget* window = NULL;
 
7350
  GtkWidget *main_vbox;
 
7351
  GtkWidget *vbox;
 
7352
  GtkWidget *hbox;
 
7353
  GtkWidget *frame_horz;
 
7354
  GtkWidget *frame_vert;
 
7355
 
 
7356
  /* Initialize GTK */
 
7357
  gtk_init (&amp;argc, &amp;argv);
 
7358
 
 
7359
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
7360
  gtk_window_set_title (GTK_WINDOW (window), "Button Boxes");
 
7361
 
 
7362
  g_signal_connect (G_OBJECT (window), "destroy",
 
7363
                    G_CALLBACK (gtk_main_quit),
 
7364
                    NULL);
 
7365
 
 
7366
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
7367
 
 
7368
  main_vbox = gtk_vbox_new (FALSE, 0);
 
7369
  gtk_container_add (GTK_CONTAINER (window), main_vbox);
 
7370
 
 
7371
  frame_horz = gtk_frame_new ("Horizontal Button Boxes");
 
7372
  gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
 
7373
 
 
7374
  vbox = gtk_vbox_new (FALSE, 0);
 
7375
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
 
7376
  gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
 
7377
 
 
7378
  gtk_box_pack_start (GTK_BOX (vbox),
 
7379
           create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
 
7380
                      TRUE, TRUE, 0);
 
7381
 
 
7382
  gtk_box_pack_start (GTK_BOX (vbox),
 
7383
           create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
 
7384
                      TRUE, TRUE, 5);
 
7385
 
 
7386
  gtk_box_pack_start (GTK_BOX (vbox),
 
7387
           create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
 
7388
                      TRUE, TRUE, 5);
 
7389
 
 
7390
  gtk_box_pack_start (GTK_BOX (vbox),
 
7391
           create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
 
7392
                      TRUE, TRUE, 5);
 
7393
 
 
7394
  frame_vert = gtk_frame_new ("Vertical Button Boxes");
 
7395
  gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
 
7396
 
 
7397
  hbox = gtk_hbox_new (FALSE, 0);
 
7398
  gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
 
7399
  gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
 
7400
 
 
7401
  gtk_box_pack_start (GTK_BOX (hbox),
 
7402
           create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
 
7403
                      TRUE, TRUE, 0);
 
7404
 
 
7405
  gtk_box_pack_start (GTK_BOX (hbox),
 
7406
           create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
 
7407
                      TRUE, TRUE, 5);
 
7408
 
 
7409
  gtk_box_pack_start (GTK_BOX (hbox),
 
7410
           create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
 
7411
                      TRUE, TRUE, 5);
 
7412
 
 
7413
  gtk_box_pack_start (GTK_BOX (hbox),
 
7414
           create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
 
7415
                      TRUE, TRUE, 5);
 
7416
 
 
7417
  gtk_widget_show_all (window);
 
7418
 
 
7419
  /* Enter the event loop */
 
7420
  gtk_main ();
 
7421
    
 
7422
  return 0;
 
7423
}
 
7424
<!-- example-end -->
 
7425
</programlisting>
 
7426
 
 
7427
</sect1>
 
7428
 
 
7429
<!-- ----------------------------------------------------------------- -->   
 
7430
<sect1 id="sec-Toolbar">
 
7431
<title>Toolbar</title>
 
7432
 
 
7433
<para>Toolbars are usually used to group some number of widgets in order to
 
7434
simplify customization of their look and layout. Typically a toolbar
 
7435
consists of buttons with icons, labels and tooltips, but any other
 
7436
widget can also be put inside a toolbar. Finally, items can be
 
7437
arranged horizontally or vertically and buttons can be displayed with
 
7438
icons, labels, or both.</para>
 
7439
 
 
7440
<para>Creating a toolbar is (as one may already suspect) done with the
 
7441
following function:</para>
 
7442
 
 
7443
<programlisting role="C">
 
7444
GtkWidget *gtk_toolbar_new( void );
 
7445
</programlisting>
 
7446
 
 
7447
<para>After creating a toolbar one can append, prepend and insert items
 
7448
(that means simple text strings) or elements (that means any widget
 
7449
types) into the toolbar. To describe an item we need a label text, a
 
7450
tooltip text, a private tooltip text, an icon for the button and a
 
7451
callback function for it. For example, to append or prepend an item
 
7452
you may use the following functions:</para>
 
7453
 
 
7454
<programlisting role="C">
 
7455
GtkWidget *gtk_toolbar_append_item( GtkToolbar    *toolbar,
 
7456
                                    const char    *text,
 
7457
                                    const char    *tooltip_text,
 
7458
                                    const char    *tooltip_private_text,
 
7459
                                    GtkWidget     *icon,
 
7460
                                    GtkSignalFunc  callback,
 
7461
                                    gpointer       user_data );
 
7462
 
 
7463
GtkWidget *gtk_toolbar_prepend_item( GtkToolbar    *toolbar,
 
7464
                                     const char    *text,
 
7465
                                     const char    *tooltip_text,
 
7466
                                     const char    *tooltip_private_text,
 
7467
                                     GtkWidget     *icon,
 
7468
                                     GtkSignalFunc  callback,
 
7469
                                     gpointer       user_data );
 
7470
</programlisting>
 
7471
 
 
7472
<para>If you want to use gtk_toolbar_insert_item(), the only additional
 
7473
parameter which must be specified is the position in which the item
 
7474
should be inserted, thus:</para>
 
7475
 
 
7476
<programlisting role="C">
 
7477
GtkWidget *gtk_toolbar_insert_item( GtkToolbar    *toolbar,
 
7478
                                    const char    *text,
 
7479
                                    const char    *tooltip_text,
 
7480
                                    const char    *tooltip_private_text,
 
7481
                                    GtkWidget     *icon,
 
7482
                                    GtkSignalFunc  callback,
 
7483
                                    gpointer       user_data,
 
7484
                                    gint           position );
 
7485
</programlisting>
 
7486
 
 
7487
<para>To simplify adding spaces between toolbar items, you may use the
 
7488
following functions:</para>
 
7489
 
 
7490
<programlisting role="C">
 
7491
void gtk_toolbar_append_space( GtkToolbar *toolbar );
 
7492
 
 
7493
void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
 
7494
 
 
7495
void gtk_toolbar_insert_space( GtkToolbar *toolbar,
 
7496
                               gint        position );
 
7497
</programlisting>
 
7498
 
 
7499
<para>If it's required, the orientation of a toolbar and its style can be
 
7500
changed "on the fly" using the following functions:</para>
 
7501
 
 
7502
<programlisting role="C">
 
7503
void gtk_toolbar_set_orientation( GtkToolbar     *toolbar,
 
7504
                                  GtkOrientation  orientation );
 
7505
 
 
7506
void gtk_toolbar_set_style( GtkToolbar      *toolbar,
 
7507
                            GtkToolbarStyle  style );
 
7508
 
 
7509
void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
 
7510
                               gint        enable );
 
7511
</programlisting>
 
7512
 
 
7513
<para>Where <literal>orientation</literal> is one of <literal>GTK_ORIENTATION_HORIZONTAL</literal> or
 
7514
<literal>GTK_ORIENTATION_VERTICAL</literal>. The <literal>style</literal> is used to set
 
7515
appearance of the toolbar items by using one of
 
7516
<literal>GTK_TOOLBAR_ICONS</literal>, <literal>GTK_TOOLBAR_TEXT</literal>, or
 
7517
<literal>GTK_TOOLBAR_BOTH</literal>.</para>
 
7518
 
 
7519
<para>To show some other things that can be done with a toolbar, let's take
 
7520
the following program (we'll interrupt the listing with some
 
7521
additional explanations):</para>
 
7522
 
 
7523
<programlisting role="C">
 
7524
#include &lt;gtk/gtk.h&gt;
 
7525
 
 
7526
/* This function is connected to the Close button or
 
7527
 * closing the window from the WM */
 
7528
static gboolean delete_event( GtkWidget *widget,
 
7529
                              GdkEvent *event,
 
7530
                              gpointer data )
 
7531
{
 
7532
  gtk_main_quit ();
 
7533
  return FALSE;
 
7534
}
 
7535
</programlisting>
 
7536
 
 
7537
<para>The above beginning seems for sure familiar to you if it's not your first
 
7538
GTK program. There is one additional thing though, we include a nice XPM
 
7539
picture to serve as an icon for all of the buttons.</para>
 
7540
 
 
7541
<programlisting role="C">
 
7542
GtkWidget* close_button; /* This button will emit signal to close
 
7543
                          * application */
 
7544
GtkWidget* tooltips_button; /* to enable/disable tooltips */
 
7545
GtkWidget* text_button,
 
7546
         * icon_button,
 
7547
         * both_button; /* radio buttons for toolbar style */
 
7548
GtkWidget* entry; /* a text entry to show packing any widget into
 
7549
                   * toolbar */
 
7550
</programlisting>
 
7551
 
 
7552
<para>In fact not all of the above widgets are needed here, but to make things
 
7553
clearer I put them all together.</para>
 
7554
 
 
7555
<programlisting role="C">
 
7556
/* that's easy... when one of the buttons is toggled, we just
 
7557
 * check which one is active and set the style of the toolbar
 
7558
 * accordingly
 
7559
 * ATTENTION: our toolbar is passed as data to callback ! */
 
7560
static void radio_event( GtkWidget *widget,
 
7561
                         gpointer data )
 
7562
{
 
7563
  if (GTK_TOGGLE_BUTTON (text_button)->active) 
 
7564
    gtk_toolbar_set_style (GTK_TOOLBAR (data), GTK_TOOLBAR_TEXT);
 
7565
  else if (GTK_TOGGLE_BUTTON (icon_button)->active)
 
7566
    gtk_toolbar_set_style (GTK_TOOLBAR (data), GTK_TOOLBAR_ICONS);
 
7567
  else if (GTK_TOGGLE_BUTTON (both_button)->active)
 
7568
    gtk_toolbar_set_style (GTK_TOOLBAR (data), GTK_TOOLBAR_BOTH);
 
7569
}
 
7570
 
 
7571
/* even easier, just check given toggle button and enable/disable 
 
7572
 * tooltips */
 
7573
static void toggle_event( GtkWidget *widget,
 
7574
                          gpointer   data )
 
7575
{
 
7576
  gtk_toolbar_set_tooltips (GTK_TOOLBAR (data),
 
7577
                            GTK_TOGGLE_BUTTON (widget)->active );
 
7578
}
 
7579
</programlisting>
 
7580
 
 
7581
<para>The above are just two callback functions that will be called when
 
7582
one of the buttons on a toolbar is pressed. You should already be
 
7583
familiar with things like this if you've already used toggle buttons (and
 
7584
radio buttons).</para>
 
7585
 
 
7586
<programlisting role="C">
 
7587
int main (int argc, char *argv[])
 
7588
{
 
7589
  /* Here is our main window (a dialog) and a handle for the handlebox */
 
7590
  GtkWidget* dialog;
 
7591
  GtkWidget* handlebox;
 
7592
 
 
7593
  /* Ok, we need a toolbar, an icon with a mask (one for all of 
 
7594
     the buttons) and an icon widget to put this icon in (but 
 
7595
     we'll create a separate widget for each button) */
 
7596
  GtkWidget * toolbar;
 
7597
  GtkWidget * iconw;
 
7598
 
 
7599
  /* this is called in all GTK application. */
 
7600
  gtk_init (&amp;argc, &amp;argv);
 
7601
  
 
7602
  /* create a new window with a given title, and nice size */
 
7603
  dialog = gtk_dialog_new ();
 
7604
  gtk_window_set_title (GTK_WINDOW (dialog), "GTKToolbar Tutorial");
 
7605
  gtk_widget_set_size_request (GTK_WIDGET (dialog), 600, 300);
 
7606
  GTK_WINDOW (dialog)->allow_shrink = TRUE;
 
7607
 
 
7608
  /* typically we quit if someone tries to close us */
 
7609
  g_signal_connect (G_OBJECT (dialog), "delete_event",
 
7610
                    G_CALLBACK (delete_event), NULL);
 
7611
 
 
7612
  /* we need to realize the window because we use pixmaps for 
 
7613
   * items on the toolbar in the context of it */
 
7614
  gtk_widget_realize (dialog);
 
7615
 
 
7616
  /* to make it nice we'll put the toolbar into the handle box, 
 
7617
   * so that it can be detached from the main window */
 
7618
  handlebox = gtk_handle_box_new ();
 
7619
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
 
7620
                      handlebox, FALSE, FALSE, 5);
 
7621
</programlisting>
 
7622
 
 
7623
<para>The above should be similar to any other GTK application. Just
 
7624
initialization of GTK, creating the window, etc. There is only one
 
7625
thing that probably needs some explanation: a handle box. A handle box
 
7626
is just another box that can be used to pack widgets in to. The
 
7627
difference between it and typical boxes is that it can be detached
 
7628
from a parent window (or, in fact, the handle box remains in the
 
7629
parent, but it is reduced to a very small rectangle, while all of its
 
7630
contents are reparented to a new freely floating window). It is
 
7631
usually nice to have a detachable toolbar, so these two widgets occur
 
7632
together quite often.</para>
 
7633
 
 
7634
<programlisting role="C">
 
7635
  /* toolbar will be horizontal, with both icons and text, and
 
7636
   * with 5pxl spaces between items and finally, 
 
7637
   * we'll also put it into our handlebox */
 
7638
  toolbar = gtk_toolbar_new ();
 
7639
  gtk_toolbar_set_orientation (GTK_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
 
7640
  gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH);
 
7641
  gtk_container_set_border_width (GTK_CONTAINER (toolbar), 5);
 
7642
  gtk_toolbar_set_space_size (GTK_TOOLBAR (toolbar), 5);
 
7643
  gtk_container_add (GTK_CONTAINER (handlebox), toolbar);
 
7644
</programlisting>
 
7645
 
 
7646
<para>Well, what we do above is just a straightforward initialization of
 
7647
the toolbar widget.</para>
 
7648
 
 
7649
<programlisting role="C">
 
7650
  /* our first item is &lt;close&gt; button */
 
7651
  iconw = gtk_image_new_from_file ("gtk.xpm"); /* icon widget */
 
7652
  close_button = 
 
7653
    gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), /* our toolbar */
 
7654
                             "Close",               /* button label */
 
7655
                             "Closes this app",     /* this button's tooltip */
 
7656
                             "Private",             /* tooltip private info */
 
7657
                             iconw,                 /* icon widget */
 
7658
                             GTK_SIGNAL_FUNC (delete_event), /* a signal */
 
7659
                             NULL);
 
7660
  gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); /* space after item */
 
7661
</programlisting>
 
7662
 
 
7663
<para>In the above code you see the simplest case: adding a button to
 
7664
toolbar.  Just before appending a new item, we have to construct an
 
7665
image widget to serve as an icon for this item; this step will have
 
7666
to be repeated for each new item. Just after the item we also add a
 
7667
space, so the following items will not touch each other. As you see
 
7668
gtk_toolbar_append_item() returns a pointer to our newly created button
 
7669
widget, so that we can work with it in the normal way.</para>
 
7670
 
 
7671
<programlisting role="C">
 
7672
  /* now, let's make our radio buttons group... */
 
7673
  iconw = gtk_image_new_from_file ("gtk.xpm");
 
7674
  icon_button = gtk_toolbar_append_element (
 
7675
                    GTK_TOOLBAR (toolbar),
 
7676
                    GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */
 
7677
                    NULL,                          /* pointer to widget */
 
7678
                    "Icon",                        /* label */
 
7679
                    "Only icons in toolbar",       /* tooltip */
 
7680
                    "Private",                     /* tooltip private string */
 
7681
                    iconw,                         /* icon */
 
7682
                    GTK_SIGNAL_FUNC (radio_event), /* signal */
 
7683
                    toolbar);                      /* data for signal */
 
7684
  gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
 
7685
</programlisting>
 
7686
 
 
7687
<para>Here we begin creating a radio buttons group. To do this we use
 
7688
gtk_toolbar_append_element.  In fact, using this function one can also
 
7689
+add simple items or even spaces (type = <literal>GTK_TOOLBAR_CHILD_SPACE</literal>
 
7690
or +<literal>GTK_TOOLBAR_CHILD_BUTTON</literal>). In the above case we start
 
7691
creating a radio group. In creating other radio buttons for this group
 
7692
a pointer to the previous button in the group is required, so that a
 
7693
list of buttons can be easily constructed (see the section on <link
 
7694
linkend="sec-RadioButtons">Radio Buttons</link> earlier in this
 
7695
tutorial).</para>
 
7696
 
 
7697
<programlisting role="C">
 
7698
  /* following radio buttons refer to previous ones */
 
7699
  iconw = gtk_image_new_from_file ("gtk.xpm");
 
7700
  text_button = 
 
7701
    gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
 
7702
                                GTK_TOOLBAR_CHILD_RADIOBUTTON,
 
7703
                                icon_button,
 
7704
                                "Text",
 
7705
                                "Only texts in toolbar",
 
7706
                                "Private",
 
7707
                                iconw,
 
7708
                                GTK_SIGNAL_FUNC (radio_event),
 
7709
                                toolbar);
 
7710
  gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
 
7711
                                          
 
7712
  iconw = gtk_image_new_from_file ("gtk.xpm");
 
7713
  both_button = 
 
7714
    gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
 
7715
                                GTK_TOOLBAR_CHILD_RADIOBUTTON,
 
7716
                                text_button,
 
7717
                                "Both",
 
7718
                                "Icons and text in toolbar",
 
7719
                                "Private",
 
7720
                                iconw,
 
7721
                                GTK_SIGNAL_FUNC (radio_event),
 
7722
                                toolbar);
 
7723
  gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
 
7724
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (both_button), TRUE);
 
7725
</programlisting>
 
7726
 
 
7727
<para>In the end we have to set the state of one of the buttons manually
 
7728
(otherwise they all stay in active state, preventing us from switching
 
7729
between them).</para>
 
7730
 
 
7731
<programlisting role="C">
 
7732
  /* here we have just a simple toggle button */
 
7733
  iconw = gtk_image_new_from_file ("gtk.xpm");
 
7734
  tooltips_button = 
 
7735
    gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
 
7736
                                GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
 
7737
                                NULL,
 
7738
                                "Tooltips",
 
7739
                                "Toolbar with or without tips",
 
7740
                                "Private",
 
7741
                                iconw,
 
7742
                                GTK_SIGNAL_FUNC (toggle_event),
 
7743
                                toolbar);
 
7744
  gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
 
7745
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tooltips_button), TRUE);
 
7746
</programlisting>
 
7747
 
 
7748
<para>A toggle button can be created in the obvious way (if one knows how to create
 
7749
radio buttons already).</para>
 
7750
 
 
7751
<programlisting role="C">
 
7752
  /* to pack a widget into toolbar, we only have to 
 
7753
   * create it and append it with an appropriate tooltip */
 
7754
  entry = gtk_entry_new ();
 
7755
  gtk_toolbar_append_widget (GTK_TOOLBAR (toolbar), 
 
7756
                             entry, 
 
7757
                             "This is just an entry", 
 
7758
                             "Private");
 
7759
 
 
7760
  /* well, it isn't created within the toolbar, so we must still show it */
 
7761
  gtk_widget_show (entry);
 
7762
</programlisting>
 
7763
 
 
7764
<para>As you see, adding any kind of widget to a toolbar is simple. The
 
7765
one thing you have to remember is that this widget must be shown manually
 
7766
(contrary to other items which will be shown together with the toolbar).</para>
 
7767
 
 
7768
<programlisting role="C">
 
7769
  /* that's it ! let's show everything. */
 
7770
  gtk_widget_show (toolbar);
 
7771
  gtk_widget_show (handlebox);
 
7772
  gtk_widget_show (dialog);
 
7773
 
 
7774
  /* rest in gtk_main and wait for the fun to begin! */
 
7775
  gtk_main ();
 
7776
  
 
7777
  return 0;
 
7778
}
 
7779
</programlisting>
 
7780
 
 
7781
<para>So, here we are at the end of toolbar tutorial. Of course, to appreciate
 
7782
it in full you need also this nice XPM icon, so here it is:</para>
 
7783
 
 
7784
<programlisting role="C">
 
7785
/* XPM */
 
7786
static char * gtk_xpm[] = {
 
7787
"32 39 5 1",
 
7788
".      c none",
 
7789
"+      c black",
 
7790
"@      c #3070E0",
 
7791
"#      c #F05050",
 
7792
"$      c #35E035",
 
7793
"................+...............",
 
7794
"..............+++++.............",
 
7795
"............+++++@@++...........",
 
7796
"..........+++++@@@@@@++.........",
 
7797
"........++++@@@@@@@@@@++........",
 
7798
"......++++@@++++++++@@@++.......",
 
7799
".....+++@@@+++++++++++@@@++.....",
 
7800
"...+++@@@@+++@@@@@@++++@@@@+....",
 
7801
"..+++@@@@+++@@@@@@@@+++@@@@@++..",
 
7802
".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
 
7803
".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
 
7804
".+##++@@@@+++@@@+++++@@@@@@@@$@.",
 
7805
".+###++@@@@+++@@@+++@@@@@++$$$@.",
 
7806
".+####+++@@@+++++++@@@@@+@$$$$@.",
 
7807
".+#####+++@@@@+++@@@@++@$$$$$$+.",
 
7808
".+######++++@@@@@@@++@$$$$$$$$+.",
 
7809
".+#######+##+@@@@+++$$$$$$@@$$+.",
 
7810
".+###+++##+##+@@++@$$$$$$++$$$+.",
 
7811
".+###++++##+##+@@$$$$$$$@+@$$@+.",
 
7812
".+###++++++#+++@$$@+@$$@++$$$@+.",
 
7813
".+####+++++++#++$$@+@$$++$$$$+..",
 
7814
".++####++++++#++$$@+@$++@$$$$+..",
 
7815
".+#####+++++##++$$++@+++$$$$$+..",
 
7816
".++####+++##+#++$$+++++@$$$$$+..",
 
7817
".++####+++####++$$++++++@$$$@+..",
 
7818
".+#####++#####++$$+++@++++@$@+..",
 
7819
".+#####++#####++$$++@$$@+++$@@..",
 
7820
".++####++#####++$$++$$$$$+@$@++.",
 
7821
".++####++#####++$$++$$$$$$$$+++.",
 
7822
".+++####+#####++$$++$$$$$$$@+++.",
 
7823
"..+++#########+@$$+@$$$$$$+++...",
 
7824
"...+++########+@$$$$$$$$@+++....",
 
7825
".....+++######+@$$$$$$$+++......",
 
7826
"......+++#####+@$$$$$@++........",
 
7827
".......+++####+@$$$$+++.........",
 
7828
".........++###+$$$@++...........",
 
7829
"..........++##+$@+++............",
 
7830
"...........+++++++..............",
 
7831
".............++++..............."};
 
7832
</programlisting>
 
7833
 
 
7834
</sect1>
 
7835
 
 
7836
<!-- ----------------------------------------------------------------- -->
 
7837
<sect1 id="sec-Notebooks">
 
7838
<title>Notebooks</title>
 
7839
 
 
7840
<para>The NoteBook Widget is a collection of "pages" that overlap each
 
7841
other, each page contains different information with only one page
 
7842
visible at a time. This widget has become more common lately in GUI
 
7843
programming, and it is a good way to show blocks of similar
 
7844
information that warrant separation in their display.</para>
 
7845
 
 
7846
<para>The first function call you will need to know, as you can probably
 
7847
guess by now, is used to create a new notebook widget.</para>
 
7848
 
 
7849
<programlisting role="C">
 
7850
GtkWidget *gtk_notebook_new( void );
 
7851
</programlisting>
 
7852
 
 
7853
<para>Once the notebook has been created, there are a number of functions
 
7854
that operate on the notebook widget. Let's look at them individually.</para>
 
7855
 
 
7856
<para>The first one we will look at is how to position the page indicators.
 
7857
These page indicators or "tabs" as they are referred to, can be
 
7858
positioned in four ways: top, bottom, left, or right.</para>
 
7859
 
 
7860
<programlisting role="C">
 
7861
void gtk_notebook_set_tab_pos( GtkNotebook     *notebook,
 
7862
                               GtkPositionType  pos );
 
7863
</programlisting>
 
7864
 
 
7865
<para>GtkPositionType will be one of the following, which are pretty self
 
7866
explanatory:</para>
 
7867
<programlisting role="C">
 
7868
  GTK_POS_LEFT
 
7869
  GTK_POS_RIGHT
 
7870
  GTK_POS_TOP
 
7871
  GTK_POS_BOTTOM
 
7872
</programlisting>
 
7873
 
 
7874
<para><literal>GTK_POS_TOP</literal> is the default.</para>
 
7875
 
 
7876
<para>Next we will look at how to add pages to the notebook. There are three
 
7877
ways to add pages to the NoteBook. Let's look at the first two
 
7878
together as they are quite similar.</para>
 
7879
 
 
7880
<programlisting role="C">
 
7881
void gtk_notebook_append_page( GtkNotebook *notebook,
 
7882
                               GtkWidget   *child,
 
7883
                               GtkWidget   *tab_label );
 
7884
 
 
7885
void gtk_notebook_prepend_page( GtkNotebook *notebook,
 
7886
                                GtkWidget   *child,
 
7887
                                GtkWidget   *tab_label );
 
7888
</programlisting>
 
7889
 
 
7890
<para>These functions add pages to the notebook by inserting them from the
 
7891
back of the notebook (append), or the front of the notebook (prepend).
 
7892
<literal>child</literal> is the widget that is placed within the notebook page, and
 
7893
<literal>tab_label</literal> is the label for the page being added. The <literal>child</literal>
 
7894
widget must be created separately, and is typically a set of options
 
7895
setup witin one of the other container widgets, such as a table.</para>
 
7896
 
 
7897
<para>The final function for adding a page to the notebook contains all of
 
7898
the properties of the previous two, but it allows you to specify what
 
7899
position you want the page to be in the notebook.</para>
 
7900
 
 
7901
<programlisting role="C">
 
7902
void gtk_notebook_insert_page( GtkNotebook *notebook,
 
7903
                               GtkWidget   *child,
 
7904
                               GtkWidget   *tab_label,
 
7905
                               gint         position );
 
7906
</programlisting>
 
7907
 
 
7908
<para>The parameters are the same as _append_ and _prepend_ except it
 
7909
contains an extra parameter, <literal>position</literal>.  This parameter is used to
 
7910
specify what place this page will be inserted into the first page
 
7911
having position zero.</para>
 
7912
 
 
7913
<para>Now that we know how to add a page, lets see how we can remove a page
 
7914
from the notebook.</para>
 
7915
 
 
7916
<programlisting role="C">
 
7917
void gtk_notebook_remove_page( GtkNotebook *notebook,
 
7918
                               gint         page_num );
 
7919
</programlisting>
 
7920
 
 
7921
<para>This function takes the page specified by <literal>page_num</literal> and removes it
 
7922
from the widget pointed to by <literal>notebook</literal>.</para>
 
7923
 
 
7924
<para>To find out what the current page is in a notebook use the function:</para>
 
7925
 
 
7926
<programlisting role="C">
 
7927
gint gtk_notebook_get_current_page( GtkNotebook *notebook );
 
7928
</programlisting>
 
7929
 
 
7930
<para>These next two functions are simple calls to move the notebook page
 
7931
forward or backward. Simply provide the respective function call with
 
7932
the notebook widget you wish to operate on. Note: When the NoteBook is
 
7933
currently on the last page, and gtk_notebook_next_page() is called, the
 
7934
notebook will wrap back to the first page. Likewise, if the NoteBook
 
7935
is on the first page, and gtk_notebook_prev_page() is called, the
 
7936
notebook will wrap to the last page.</para>
 
7937
 
 
7938
<programlisting role="C">
 
7939
void gtk_notebook_next_page( GtkNoteBook *notebook );
 
7940
 
 
7941
void gtk_notebook_prev_page( GtkNoteBook *notebook );
 
7942
</programlisting>
 
7943
 
 
7944
<para>This next function sets the "active" page. If you wish the notebook to
 
7945
be opened to page 5 for example, you would use this function.  Without
 
7946
using this function, the notebook defaults to the first page.</para>
 
7947
 
 
7948
<programlisting role="C">
 
7949
void gtk_notebook_set_current_page( GtkNotebook *notebook,
 
7950
                                    gint         page_num );
 
7951
</programlisting>
 
7952
 
 
7953
<para>The next two functions add or remove the notebook page tabs and the
 
7954
notebook border respectively.</para>
 
7955
 
 
7956
<programlisting role="C">
 
7957
void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
 
7958
                                 gboolean     show_tabs );
 
7959
 
 
7960
void gtk_notebook_set_show_border( GtkNotebook *notebook,
 
7961
                                   gboolean     show_border );
 
7962
</programlisting>
 
7963
 
 
7964
<para>The next function is useful when the you have a large number of pages,
 
7965
and the tabs don't fit on the page. It allows the tabs to be scrolled
 
7966
through using two arrow buttons.</para>
 
7967
 
 
7968
<programlisting role="C">
 
7969
void gtk_notebook_set_scrollable( GtkNotebook *notebook,
 
7970
                                  gboolean     scrollable );
 
7971
</programlisting>
 
7972
 
 
7973
<para><literal>show_tabs</literal>, <literal>show_border</literal> and <literal>scrollable</literal> can be either
 
7974
TRUE or FALSE.</para>
 
7975
 
 
7976
<para>Now let's look at an example, it is expanded from the 
 
7977
<filename>testgtk.c</filename> code
 
7978
that comes with the GTK distribution. This small program creates a
 
7979
window with a notebook and six buttons. The notebook contains 11
 
7980
pages, added in three different ways, appended, inserted, and
 
7981
prepended. The buttons allow you rotate the tab positions, add/remove
 
7982
the tabs and border, remove a page, change pages in both a forward and
 
7983
backward manner, and exit the program.</para>
 
7984
 
 
7985
<para>
 
7986
<inlinemediaobject>
 
7987
<imageobject>
 
7988
<imagedata fileref="images/notebook.png" format="png">
 
7989
</imageobject>
 
7990
</inlinemediaobject>
 
7991
</para>
 
7992
 
 
7993
<programlisting role="C">
 
7994
<!-- example-start notebook notebook.c -->
 
7995
 
 
7996
#include &lt;stdio.h&gt;
 
7997
#include &lt;gtk/gtk.h&gt;
 
7998
 
 
7999
/* This function rotates the position of the tabs */
 
8000
static void rotate_book( GtkButton   *button,
 
8001
                         GtkNotebook *notebook )
 
8002
{
 
8003
    gtk_notebook_set_tab_pos (notebook, (notebook-&gt;tab_pos + 1) % 4);
 
8004
}
 
8005
 
 
8006
/* Add/Remove the page tabs and the borders */
 
8007
static void tabsborder_book( GtkButton   *button,
 
8008
                             GtkNotebook *notebook )
 
8009
{
 
8010
    gint tval = FALSE;
 
8011
    gint bval = FALSE;
 
8012
    if (notebook-&gt;show_tabs == 0)
 
8013
            tval = TRUE; 
 
8014
    if (notebook-&gt;show_border == 0)
 
8015
            bval = TRUE;
 
8016
    
 
8017
    gtk_notebook_set_show_tabs (notebook, tval);
 
8018
    gtk_notebook_set_show_border (notebook, bval);
 
8019
}
 
8020
 
 
8021
/* Remove a page from the notebook */
 
8022
static void remove_book( GtkButton   *button,
 
8023
                         GtkNotebook *notebook )
 
8024
{
 
8025
    gint page;
 
8026
    
 
8027
    page = gtk_notebook_get_current_page (notebook);
 
8028
    gtk_notebook_remove_page (notebook, page);
 
8029
    /* Need to refresh the widget -- 
 
8030
     This forces the widget to redraw itself. */
 
8031
    gtk_widget_queue_draw (GTK_WIDGET (notebook));
 
8032
}
 
8033
 
 
8034
static gboolean delete( GtkWidget *widget,
 
8035
                        GtkWidget *event,
 
8036
                        gpointer   data )
 
8037
{
 
8038
    gtk_main_quit ();
 
8039
    return FALSE;
 
8040
}
 
8041
 
 
8042
int main( int argc,
 
8043
          char *argv[] )
 
8044
{
 
8045
    GtkWidget *window;
 
8046
    GtkWidget *button;
 
8047
    GtkWidget *table;
 
8048
    GtkWidget *notebook;
 
8049
    GtkWidget *frame;
 
8050
    GtkWidget *label;
 
8051
    GtkWidget *checkbutton;
 
8052
    int i;
 
8053
    char bufferf[32];
 
8054
    char bufferl[32];
 
8055
    
 
8056
    gtk_init (&amp;argc, &amp;argv);
 
8057
    
 
8058
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
8059
    
 
8060
    g_signal_connect (G_OBJECT (window), "delete_event",
 
8061
                      G_CALLBACK (delete), NULL);
 
8062
    
 
8063
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
8064
 
 
8065
    table = gtk_table_new (3, 6, FALSE);
 
8066
    gtk_container_add (GTK_CONTAINER (window), table);
 
8067
    
 
8068
    /* Create a new notebook, place the position of the tabs */
 
8069
    notebook = gtk_notebook_new ();
 
8070
    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
 
8071
    gtk_table_attach_defaults (GTK_TABLE (table), notebook, 0, 6, 0, 1);
 
8072
    gtk_widget_show (notebook);
 
8073
    
 
8074
    /* Let's append a bunch of pages to the notebook */
 
8075
    for (i = 0; i &lt; 5; i++) {
 
8076
        sprintf(bufferf, "Append Frame %d", i + 1);
 
8077
        sprintf(bufferl, "Page %d", i + 1);
 
8078
        
 
8079
        frame = gtk_frame_new (bufferf);
 
8080
        gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
 
8081
        gtk_widget_set_size_request (frame, 100, 75);
 
8082
        gtk_widget_show (frame);
 
8083
        
 
8084
        label = gtk_label_new (bufferf);
 
8085
        gtk_container_add (GTK_CONTAINER (frame), label);
 
8086
        gtk_widget_show (label);
 
8087
        
 
8088
        label = gtk_label_new (bufferl);
 
8089
        gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
 
8090
    }
 
8091
      
 
8092
    /* Now let's add a page to a specific spot */
 
8093
    checkbutton = gtk_check_button_new_with_label ("Check me please!");
 
8094
    gtk_widget_set_size_request (checkbutton, 100, 75);
 
8095
    gtk_widget_show (checkbutton);
 
8096
   
 
8097
    label = gtk_label_new ("Add page");
 
8098
    gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
 
8099
    
 
8100
    /* Now finally let's prepend pages to the notebook */
 
8101
    for (i = 0; i &lt; 5; i++) {
 
8102
        sprintf (bufferf, "Prepend Frame %d", i + 1);
 
8103
        sprintf (bufferl, "PPage %d", i + 1);
 
8104
        
 
8105
        frame = gtk_frame_new (bufferf);
 
8106
        gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
 
8107
        gtk_widget_set_size_request (frame, 100, 75);
 
8108
        gtk_widget_show (frame);
 
8109
        
 
8110
        label = gtk_label_new (bufferf);
 
8111
        gtk_container_add (GTK_CONTAINER (frame), label);
 
8112
        gtk_widget_show (label);
 
8113
        
 
8114
        label = gtk_label_new (bufferl);
 
8115
        gtk_notebook_prepend_page (GTK_NOTEBOOK (notebook), frame, label);
 
8116
    }
 
8117
    
 
8118
    /* Set what page to start at (page 4) */
 
8119
    gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 3);
 
8120
 
 
8121
    /* Create a bunch of buttons */
 
8122
    button = gtk_button_new_with_label ("close");
 
8123
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
8124
                              G_CALLBACK (delete), NULL);
 
8125
    gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 1, 2);
 
8126
    gtk_widget_show (button);
 
8127
    
 
8128
    button = gtk_button_new_with_label ("next page");
 
8129
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
8130
                              G_CALLBACK (gtk_notebook_next_page),
 
8131
                              G_OBJECT (notebook));
 
8132
    gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, 1, 2);
 
8133
    gtk_widget_show (button);
 
8134
    
 
8135
    button = gtk_button_new_with_label ("prev page");
 
8136
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
8137
                              G_CALLBACK (gtk_notebook_prev_page),
 
8138
                              G_OBJECT (notebook));
 
8139
    gtk_table_attach_defaults (GTK_TABLE (table), button, 2, 3, 1, 2);
 
8140
    gtk_widget_show (button);
 
8141
    
 
8142
    button = gtk_button_new_with_label ("tab position");
 
8143
    g_signal_connect (G_OBJECT (button), "clicked",
 
8144
                      G_CALLBACK (rotate_book),
 
8145
                      (gpointer) notebook);
 
8146
    gtk_table_attach_defaults (GTK_TABLE (table), button, 3, 4, 1, 2);
 
8147
    gtk_widget_show (button);
 
8148
    
 
8149
    button = gtk_button_new_with_label ("tabs/border on/off");
 
8150
    g_signal_connect (G_OBJECT (button), "clicked",
 
8151
                      G_CALLBACK (tabsborder_book),
 
8152
                      (gpointer) notebook);
 
8153
    gtk_table_attach_defaults (GTK_TABLE (table), button, 4, 5, 1, 2);
 
8154
    gtk_widget_show (button);
 
8155
    
 
8156
    button = gtk_button_new_with_label ("remove page");
 
8157
    g_signal_connect (G_OBJECT (button), "clicked",
 
8158
                      G_CALLBACK (remove_book),
 
8159
                      (gpointer) notebook);
 
8160
    gtk_table_attach_defaults (GTK_TABLE (table), button, 5, 6, 1, 2);
 
8161
    gtk_widget_show (button);
 
8162
    
 
8163
    gtk_widget_show (table);
 
8164
    gtk_widget_show (window);
 
8165
    
 
8166
    gtk_main ();
 
8167
    
 
8168
    return 0;
 
8169
}
 
8170
<!-- example-end -->
 
8171
</programlisting>
 
8172
 
 
8173
<para>I hope this helps you on your way with creating notebooks for your
 
8174
GTK applications.</para>
 
8175
 
 
8176
</sect1>
 
8177
</chapter>
 
8178
 
 
8179
<!-- ***************************************************************** -->
 
8180
<chapter id="ch-MenuWidget">
 
8181
<title>Menu Widget</title>
 
8182
 
 
8183
<para>There are two ways to create menus: there's the easy way, and there's
 
8184
the hard way. Both have their uses, but you can usually use the
 
8185
Itemfactory (the easy way). The "hard" way is to create all the menus
 
8186
using the calls directly. The easy way is to use the gtk_item_factory
 
8187
calls. This is much simpler, but there are advantages and
 
8188
disadvantages to each approach.</para>
 
8189
 
 
8190
<para>The Itemfactory is much easier to use, and to add new menus to,
 
8191
although writing a few wrapper functions to create menus using the
 
8192
manual method could go a long way towards usability. With the
 
8193
Itemfactory, it is not possible to add images or the character '/' to
 
8194
the menus.</para>
 
8195
 
 
8196
<!-- ----------------------------------------------------------------- -->
 
8197
<sect1 id="sec-ManualMenuCreation">
 
8198
<title>Manual Menu Creation</title>
 
8199
 
 
8200
<para>In the true tradition of teaching, we'll show you the hard way
 
8201
first. <literal>:)</literal></para>
 
8202
 
 
8203
<para>There are three widgets that go into making a menubar and submenus:</para>
 
8204
 
 
8205
<itemizedlist>
 
8206
<listitem><simpara>a menu item, which is what the user wants to select, e.g.,
 
8207
"Save"</simpara>
 
8208
</listitem>
 
8209
<listitem><simpara>a menu, which acts as a container for the menu items, and</simpara>
 
8210
</listitem>
 
8211
<listitem><simpara>a menubar, which is a container for each of the individual
 
8212
menus.</simpara>
 
8213
</listitem>
 
8214
</itemizedlist>
 
8215
 
 
8216
<para>This is slightly complicated by the fact that menu item widgets are
 
8217
used for two different things. They are both the widgets that are
 
8218
packed into the menu, and the widget that is packed into the menubar,
 
8219
which, when selected, activates the menu.</para>
 
8220
 
 
8221
<para>Let's look at the functions that are used to create menus and
 
8222
menubars.  This first function is used to create a new menubar.</para>
 
8223
 
 
8224
<programlisting role="C">
 
8225
GtkWidget *gtk_menu_bar_new( void );
 
8226
</programlisting>
 
8227
 
 
8228
<para>This rather self explanatory function creates a new menubar. You use
 
8229
gtk_container_add() to pack this into a window, or the box_pack
 
8230
functions to pack it into a box - the same as buttons.</para>
 
8231
 
 
8232
<programlisting role="C">
 
8233
GtkWidget *gtk_menu_new( void );
 
8234
</programlisting>
 
8235
 
 
8236
<para>This function returns a pointer to a new menu; it is never actually
 
8237
shown (with gtk_widget_show()), it is just a container for the menu
 
8238
items. I hope this will become more clear when you look at the
 
8239
example below.</para>
 
8240
 
 
8241
<para>The next three calls are used to create menu items that are packed into
 
8242
the menu (and menubar).</para>
 
8243
 
 
8244
<programlisting role="C">
 
8245
GtkWidget *gtk_menu_item_new( void );
 
8246
 
 
8247
GtkWidget *gtk_menu_item_new_with_label( const char *label );
 
8248
 
 
8249
GtkWidget *gtk_menu_item_new_with_mnemnonic( const char *label );
 
8250
</programlisting>
 
8251
 
 
8252
<para>These calls are used to create the menu items that are to be
 
8253
displayed.  Remember to differentiate between a "menu" as created with
 
8254
gtk_menu_new() and a "menu item" as created by the gtk_menu_item_new()
 
8255
functions. The menu item will be an actual button with an associated
 
8256
action, whereas a menu will be a container holding menu items.</para>
 
8257
 
 
8258
<para>The gtk_menu_item_new_with_label() and gtk_menu_item_new() functions are just as
 
8259
you'd expect after reading about the buttons. One creates a new menu
 
8260
item with a label already packed into it, and the other just creates a
 
8261
blank menu item.</para>
 
8262
 
 
8263
<para>Once you've created a menu item you have to put it into a menu. This
 
8264
is done using the function gtk_menu_shelll_append. In order to capture when
 
8265
the item is selected by the user, we need to connect to the
 
8266
<literal>activate</literal> signal in the usual way. So, if we wanted to create a
 
8267
standard <literal>File</literal> menu, with the options <literal>Open</literal>, <literal>Save</literal>, and
 
8268
<literal>Quit</literal>, the code would look something like:</para>
 
8269
 
 
8270
<programlisting role="C">
 
8271
    file_menu = gtk_menu_new ();    /* Don't need to show menus */
 
8272
 
 
8273
    /* Create the menu items */
 
8274
    open_item = gtk_menu_item_new_with_label ("Open");
 
8275
    save_item = gtk_menu_item_new_with_label ("Save");
 
8276
    quit_item = gtk_menu_item_new_with_label ("Quit");
 
8277
 
 
8278
    /* Add them to the menu */
 
8279
    gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), open_item);
 
8280
    gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), save_item);
 
8281
    gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), quit_item);
 
8282
 
 
8283
    /* Attach the callback functions to the activate signal */
 
8284
    g_signal_connect_swapped (G_OBJECT (open_item), "activate",
 
8285
                              G_CALLBACK (menuitem_response),
 
8286
                              (gpointer) "file.open");
 
8287
    g_signal_connect_swapped (G_OBJECT (save_item), "activate",
 
8288
                              G_CALLBACK (menuitem_response),
 
8289
                              (gpointer) "file.save");
 
8290
 
 
8291
    /* We can attach the Quit menu item to our exit function */
 
8292
    g_signal_connect_swapped (G_OBJECT (quit_item), "activate",
 
8293
                              G_CALLBACK (destroy),
 
8294
                              (gpointer) "file.quit");
 
8295
 
 
8296
    /* We do need to show menu items */
 
8297
    gtk_widget_show (open_item);
 
8298
    gtk_widget_show (save_item);
 
8299
    gtk_widget_show (quit_item);
 
8300
</programlisting>
 
8301
 
 
8302
<para>At this point we have our menu. Now we need to create a menubar and a
 
8303
menu item for the <literal>File</literal> entry, to which we add our menu. The code
 
8304
looks like this:</para>
 
8305
 
 
8306
<programlisting role="C">
 
8307
    menu_bar = gtk_menu_bar_new ();
 
8308
    gtk_container_add (GTK_CONTAINER (window), menu_bar);
 
8309
    gtk_widget_show (menu_bar);
 
8310
 
 
8311
    file_item = gtk_menu_item_new_with_label ("File");
 
8312
    gtk_widget_show (file_item);
 
8313
</programlisting>
 
8314
 
 
8315
<para>Now we need to associate the menu with <literal>file_item</literal>. This is done
 
8316
with the function</para>
 
8317
 
 
8318
<programlisting role="C">
 
8319
void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
 
8320
                                GtkWidget   *submenu );
 
8321
</programlisting>
 
8322
 
 
8323
<para>So, our example would continue with</para>
 
8324
 
 
8325
<programlisting role="C">
 
8326
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);
 
8327
</programlisting>
 
8328
 
 
8329
<para>All that is left to do is to add the menu to the menubar, which is
 
8330
accomplished using the function</para>
 
8331
 
 
8332
<programlisting role="C">
 
8333
void gtk_menu_bar_append( GtkMenuBar *menu_bar,
 
8334
                          GtkWidget  *menu_item );
 
8335
</programlisting>
 
8336
 
 
8337
<para>which in our case looks like this:</para>
 
8338
 
 
8339
<programlisting role="C">
 
8340
    gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);
 
8341
</programlisting>
 
8342
 
 
8343
<para>If we wanted the menu right justified on the menubar, such as help
 
8344
menus often are, we can use the following function (again on
 
8345
<literal>file_item</literal> in the current example) before attaching it to the
 
8346
menubar.</para>
 
8347
 
 
8348
<programlisting role="C">
 
8349
void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
 
8350
</programlisting>
 
8351
 
 
8352
<para>Here is a summary of the steps needed to create a menu bar with menus
 
8353
attached:</para>
 
8354
 
 
8355
<itemizedlist>
 
8356
<listitem><simpara> Create a new menu using gtk_menu_new()</simpara>
 
8357
</listitem>
 
8358
 
 
8359
<listitem><simpara> Use multiple calls to gtk_menu_item_new() for each item you
 
8360
wish to have on your menu. And use gtk_menu_shell_append() to put each of
 
8361
these new items on to the menu.</simpara>
 
8362
</listitem>
 
8363
 
 
8364
<listitem><simpara> Create a menu item using gtk_menu_item_new(). This will be the
 
8365
root of the menu, the text appearing here will be on the menubar
 
8366
itself.</simpara>
 
8367
</listitem>
 
8368
 
 
8369
<listitem><simpara>Use gtk_menu_item_set_submenu() to attach the menu to the root
 
8370
menu item (the one created in the above step).</simpara>
 
8371
</listitem>
 
8372
 
 
8373
<listitem><simpara> Create a new menubar using gtk_menu_bar_new. This step only
 
8374
needs to be done once when creating a series of menus on one menu bar.</simpara>
 
8375
</listitem>
 
8376
 
 
8377
<listitem><simpara> Use gtk_menu_bar_append() to put the root menu onto the menubar.</simpara>
 
8378
</listitem>
 
8379
</itemizedlist>
 
8380
 
 
8381
<para>Creating a popup menu is nearly the same. The difference is that the
 
8382
menu is not posted "automatically" by a menubar, but explicitly by
 
8383
calling the function gtk_menu_popup() from a button-press event, for
 
8384
example.  Take these steps:</para>
 
8385
 
 
8386
<itemizedlist>
 
8387
<listitem><simpara>Create an event handling function. It needs to have the
 
8388
prototype</simpara>
 
8389
<programlisting role="C">
 
8390
static gboolean handler( GtkWidget *widget,
 
8391
                         GdkEvent  *event );
 
8392
</programlisting>
 
8393
<simpara>and it will use the event to find out where to pop up the menu.</simpara>
 
8394
</listitem>
 
8395
 
 
8396
<listitem><simpara>In the event handler, if the event is a mouse button press,
 
8397
treat <literal>event</literal> as a button event (which it is) and use it as
 
8398
shown in the sample code to pass information to gtk_menu_popup().</simpara>
 
8399
</listitem>
 
8400
 
 
8401
<listitem><simpara>Bind that event handler to a widget with</simpara>
 
8402
<programlisting role="C">
 
8403
    g_signal_connect_swapped (G_OBJECT (widget), "event",
 
8404
                              G_CALLBACK (handler),
 
8405
                              G_OBJECT (menu));
 
8406
</programlisting>
 
8407
<simpara>where <literal>widget</literal> is the widget you are binding to,
 
8408
<literal>handler</literal> is the handling function, and <literal>menu</literal> is a menu
 
8409
created with gtk_menu_new(). This can be a menu which is also posted
 
8410
by a menu bar, as shown in the sample code.</simpara>
 
8411
</listitem>
 
8412
</itemizedlist>
 
8413
 
 
8414
</sect1>
 
8415
 
 
8416
<!-- ----------------------------------------------------------------- -->
 
8417
<sect1 id="sec-ManualMenuExample">
 
8418
<title>Manual Menu Example</title>
 
8419
 
 
8420
<para>That should about do it. Let's take a look at an example to help clarify.</para>
 
8421
 
 
8422
<para>
 
8423
<inlinemediaobject>
 
8424
<imageobject>
 
8425
<imagedata fileref="images/menu.png" format="png">
 
8426
</imageobject>
 
8427
</inlinemediaobject>
 
8428
</para>
 
8429
 
 
8430
<programlisting role="C">
 
8431
<!-- example-start menu menu.c -->
 
8432
 
 
8433
#include &lt;stdio.h&gt;
 
8434
#include &lt;gtk/gtk.h&gt;
 
8435
 
 
8436
static gboolean button_press (GtkWidget *, GdkEvent *);
 
8437
static void menuitem_response (gchar *);
 
8438
 
 
8439
int main( int   argc,
 
8440
          char *argv[] )
 
8441
{
 
8442
 
 
8443
    GtkWidget *window;
 
8444
    GtkWidget *menu;
 
8445
    GtkWidget *menu_bar;
 
8446
    GtkWidget *root_menu;
 
8447
    GtkWidget *menu_items;
 
8448
    GtkWidget *vbox;
 
8449
    GtkWidget *button;
 
8450
    char buf[128];
 
8451
    int i;
 
8452
 
 
8453
    gtk_init (&amp;argc, &amp;argv);
 
8454
 
 
8455
    /* create a new window */
 
8456
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
8457
    gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
 
8458
    gtk_window_set_title (GTK_WINDOW (window), "GTK Menu Test");
 
8459
    g_signal_connect (G_OBJECT (window), "delete_event",
 
8460
                      G_CALLBACK (gtk_main_quit), NULL);
 
8461
 
 
8462
    /* Init the menu-widget, and remember -- never
 
8463
     * gtk_show_widget() the menu widget!! 
 
8464
     * This is the menu that holds the menu items, the one that
 
8465
     * will pop up when you click on the "Root Menu" in the app */
 
8466
    menu = gtk_menu_new ();
 
8467
 
 
8468
    /* Next we make a little loop that makes three menu-entries for "test-menu".
 
8469
     * Notice the call to gtk_menu_shell_append.  Here we are adding a list of
 
8470
     * menu items to our menu.  Normally, we'd also catch the "clicked"
 
8471
     * signal on each of the menu items and setup a callback for it,
 
8472
     * but it's omitted here to save space. */
 
8473
 
 
8474
    for (i = 0; i &lt; 3; i++)
 
8475
        {
 
8476
            /* Copy the names to the buf. */
 
8477
            sprintf (buf, "Test-undermenu - %d", i);
 
8478
 
 
8479
            /* Create a new menu-item with a name... */
 
8480
            menu_items = gtk_menu_item_new_with_label (buf);
 
8481
 
 
8482
            /* ...and add it to the menu. */
 
8483
            gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items);
 
8484
 
 
8485
            /* Do something interesting when the menuitem is selected */
 
8486
            g_signal_connect_swapped (G_OBJECT (menu_items), "activate",
 
8487
                                      G_CALLBACK (menuitem_response), 
 
8488
                                      (gpointer) g_strdup (buf));
 
8489
 
 
8490
            /* Show the widget */
 
8491
            gtk_widget_show (menu_items);
 
8492
        }
 
8493
 
 
8494
    /* This is the root menu, and will be the label
 
8495
     * displayed on the menu bar.  There won't be a signal handler attached,
 
8496
     * as it only pops up the rest of the menu when pressed. */
 
8497
    root_menu = gtk_menu_item_new_with_label ("Root Menu");
 
8498
 
 
8499
    gtk_widget_show (root_menu);
 
8500
 
 
8501
    /* Now we specify that we want our newly created "menu" to be the menu
 
8502
     * for the "root menu" */
 
8503
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
 
8504
 
 
8505
    /* A vbox to put a menu and a button in: */
 
8506
    vbox = gtk_vbox_new (FALSE, 0);
 
8507
    gtk_container_add (GTK_CONTAINER (window), vbox);
 
8508
    gtk_widget_show (vbox);
 
8509
 
 
8510
    /* Create a menu-bar to hold the menus and add it to our main window */
 
8511
    menu_bar = gtk_menu_bar_new ();
 
8512
    gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, FALSE, 2);
 
8513
    gtk_widget_show (menu_bar);
 
8514
 
 
8515
    /* Create a button to which to attach menu as a popup */
 
8516
    button = gtk_button_new_with_label ("press me");
 
8517
    g_signal_connect_swapped (G_OBJECT (button), "event",
 
8518
                              G_CALLBACK (button_press), 
 
8519
                              G_OBJECT (menu));
 
8520
    gtk_box_pack_end (GTK_BOX (vbox), button, TRUE, TRUE, 2);
 
8521
    gtk_widget_show (button);
 
8522
 
 
8523
    /* And finally we append the menu-item to the menu-bar -- this is the
 
8524
     * "root" menu-item I have been raving about =) */
 
8525
    gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), root_menu);
 
8526
 
 
8527
    /* always display the window as the last step so it all splashes on
 
8528
     * the screen at once. */
 
8529
    gtk_widget_show (window);
 
8530
 
 
8531
    gtk_main ();
 
8532
 
 
8533
    return 0;
 
8534
}
 
8535
 
 
8536
/* Respond to a button-press by posting a menu passed in as widget.
 
8537
 *
 
8538
 * Note that the "widget" argument is the menu being posted, NOT
 
8539
 * the button that was pressed.
 
8540
 */
 
8541
 
 
8542
static gboolean button_press( GtkWidget *widget,
 
8543
                              GdkEvent *event )
 
8544
{
 
8545
 
 
8546
    if (event-&gt;type == GDK_BUTTON_PRESS) {
 
8547
        GdkEventButton *bevent = (GdkEventButton *) event; 
 
8548
        gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
 
8549
                        bevent-&gt;button, bevent-&gt;time);
 
8550
        /* Tell calling code that we have handled this event; the buck
 
8551
         * stops here. */
 
8552
        return TRUE;
 
8553
    }
 
8554
 
 
8555
    /* Tell calling code that we have not handled this event; pass it on. */
 
8556
    return FALSE;
 
8557
}
 
8558
 
 
8559
 
 
8560
/* Print a string when a menu item is selected */
 
8561
 
 
8562
static void menuitem_response( gchar *string )
 
8563
{
 
8564
    printf ("%s\n", string);
 
8565
}
 
8566
<!-- example-end -->
 
8567
</programlisting>
 
8568
 
 
8569
<para>You may also set a menu item to be insensitive and, using an accelerator
 
8570
table, bind keys to menu functions.</para>
 
8571
 
 
8572
</sect1>
 
8573
 
 
8574
<!-- ----------------------------------------------------------------- -->
 
8575
<sect1 id="sec-UsingItemFactory">
 
8576
<title>Using ItemFactory</title>
 
8577
 
 
8578
<para>Now that we've shown you the hard way, here's how you do it using the
 
8579
gtk_item_factory calls.</para>
 
8580
 
 
8581
<para>ItemFactory creates a menu out of an array of ItemFactory entries. This 
 
8582
means you can define your menu in its simplest form and then create the
 
8583
menu/menubar widgets with a minimum of function calls.</para>
 
8584
 
 
8585
<!-- ----------------------------------------------------------------- -->
 
8586
<sect2 id="sec-ItemFactoryEntries">
 
8587
<title>ItemFactory entries</title>
 
8588
 
 
8589
<para>At the core of ItemFactory is the ItemFactoryEntry. This structure defines
 
8590
one menu item, and when an array of these entries is defined a whole
 
8591
menu is formed. The ItemFactory entry struct definition looks like this:</para>
 
8592
 
 
8593
<programlisting role="C">
 
8594
struct _GtkItemFactoryEntry
 
8595
{
 
8596
  gchar *path;
 
8597
  gchar *accelerator;
 
8598
 
 
8599
  GtkItemFactoryCallback callback;
 
8600
  guint                  callback_action;
 
8601
 
 
8602
  gchar          *item_type;
 
8603
};
 
8604
</programlisting>
 
8605
 
 
8606
<para>Each field defines part of the menu item.</para>
 
8607
 
 
8608
<para><literal>*path</literal> is a string which defines both the name and the
 
8609
path of a menu item, for example, "/File/Open" would be the name of a menu
 
8610
item which would come under the ItemFactory entry with path "/File". Note however
 
8611
that "/File/Open" would be displayed in the File menu as "Open". Also note
 
8612
since the forward slashes are used to define the path of the menu,
 
8613
they cannot be used as part of the name. A letter preceded by an underscore
 
8614
indicates an accelerator (shortcut) key once the menu is open.</para>
 
8615
 
 
8616
<para>
 
8617
<literal>*accelerator</literal> is a string that indicates a key combination
 
8618
that can be used as a shortcut to that menu item. The string can be made up
 
8619
of either a single character, or a combination of modifier keys with a single
 
8620
character. It is case insensitive.</para>
 
8621
 
 
8622
 
 
8623
<para>The available modifier keys are:</para>
 
8624
 
 
8625
<programlisting role="C">
 
8626
"&lt;ALT&gt;                             - alt
 
8627
"&lt;CTL&gt;" or "&lt;CTRL&gt;" or "&lt;CONTROL&gt;" - control
 
8628
"&lt;MOD1&gt;" to "&lt;MOD5&gt;"               - modn
 
8629
"&lt;SHFT&gt;" or "&lt;SHIFT&gt;"              - shift
 
8630
</programlisting>
 
8631
 
 
8632
<para>Examples:</para>
 
8633
<programlisting role="C">
 
8634
"&lt;ConTroL&gt;a"
 
8635
"&lt;SHFT&gt;&lt;ALT&gt;&lt;CONTROL&gt;X"
 
8636
</programlisting>
 
8637
 
 
8638
<para>
 
8639
<literal>callback</literal> is the function that is called when the menu item
 
8640
emits the "activate" signal. The form of the callback is described
 
8641
in the <link linkend="sec-ItemFactoryCallback">Callback Description</link>
 
8642
section.</para>
 
8643
 
 
8644
<para>
 
8645
The value of <literal>callback_action</literal> is passed to the callback
 
8646
function. It also affects the function prototype, as shown
 
8647
in the <link linkend="sec-ItemFactoryCallback">Callback Description</link>
 
8648
section.</para>
 
8649
 
 
8650
<para>
 
8651
<literal>item_type</literal> is a string that defines what type of widget is
 
8652
packed into the menu items container. It can be:</para>
 
8653
 
 
8654
<programlisting role="C">
 
8655
NULL or "" or "&lt;Item&gt;" - create a simple item
 
8656
"&lt;Title&gt;"              - create a title item
 
8657
"&lt;CheckItem&gt;"          - create a check item
 
8658
"&lt;ToggleItem&gt;"         - create a toggle item
 
8659
"&lt;RadioItem&gt;"          - create a (root) radio item
 
8660
"Path"                 - create a sister radio item
 
8661
"&lt;Tearoff&gt;"            - create a tearoff
 
8662
"&lt;Separator&gt;"          - create a separator
 
8663
"&lt;Branch&gt;"             - create an item to hold submenus (optional)
 
8664
"&lt;LastBranch&gt;"         - create a right justified branch
 
8665
"&lt;StockItem&gt;"          - create a simple item with a stock image. 
 
8666
                               see <filename>gtkstock.h</filename> for builtin stock items
 
8667
 
 
8668
</programlisting>
 
8669
 
 
8670
<para>Note that &lt;LastBranch&gt; is only useful for one submenu of
 
8671
a menubar.</para>
 
8672
 
 
8673
<!-- ----------------------------------------------------------------- -->
 
8674
<sect3 id="sec-ItemFactoryCallback">
 
8675
<title>Callback Description</title>
 
8676
 
 
8677
<para>
 
8678
The callback for an ItemFactory entry can take two forms. If
 
8679
<literal>callback_action</literal> is zero, it is of the following
 
8680
form:</para>
 
8681
 
 
8682
<programlisting role="C">
 
8683
void callback( void )
 
8684
</programlisting>
 
8685
 
 
8686
<para>otherwise it is of the form:</para>
 
8687
 
 
8688
<programlisting role="C">
 
8689
void callback( gpointer    callback_data,
 
8690
               guint       callback_action,
 
8691
               GtkWidget  *widget )
 
8692
</programlisting>
 
8693
 
 
8694
<para>
 
8695
<literal>callback_data</literal> is a pointer to an arbitrary piece of data and
 
8696
is set during the call to gtk_item_factory_create_items().</para>
 
8697
 
 
8698
<para>
 
8699
<literal>callback_action</literal> is the same value as
 
8700
<literal>callback_action</literal> in the ItemFactory entry.</para>
 
8701
 
 
8702
<para>
 
8703
<literal>*widget</literal> is a pointer to a menu item widget
 
8704
(described in <link linkend="sec-ManualMenuCreation">Manual Menu Creation</link>).
 
8705
</para>
 
8706
</sect3>
 
8707
 
 
8708
<!-- ----------------------------------------------------------------- -->
 
8709
<sect3 id="sec-ItemFactoryEntryExamples">
 
8710
<title>ItemFactory entry examples</title>
 
8711
 
 
8712
<para>Creating a simple menu item:</para>
 
8713
 
 
8714
<programlisting role="C">
 
8715
GtkItemFactoryEntry entry = {"/_File/_Open...", "&lt;CTRL&gt;O", print_hello,
 
8716
                                0, "&lt;Item&gt;"};
 
8717
</programlisting>
 
8718
 
 
8719
<para>This will define a new simple menu entry "/File/Open" (displayed as "Open"),
 
8720
under the menu entry "/File". It has the accelerator (shortcut) control+'O'
 
8721
that when clicked calls the function print_hello(). print_hello() is of
 
8722
the form <literal>void print_hello(void)</literal> since the callback_action
 
8723
field is zero. When displayed the 'O' in "Open" will be underlined and if the
 
8724
menu item is visible on the screen pressing 'O' will activate the item. Note
 
8725
that "File/_Open" could also have been used as the path instead of
 
8726
"/_File/_Open".</para>
 
8727
 
 
8728
<para>Creating an entry with a more complex callback:</para>
 
8729
 
 
8730
<programlisting role="C">
 
8731
GtkItemFactoryEntry entry = {"/_View/Display _FPS", NULL, print_state,
 
8732
                                7,"&lt;CheckItem&gt;"};
 
8733
</programlisting>
 
8734
 
 
8735
<para>This defines a new menu item displayed as "Display FPS" which is under
 
8736
the menu item "View". When clicked the function print_state() will be called.
 
8737
Since <literal>callback_action</literal> is not zero print_state() is of the
 
8738
form:</para>
 
8739
 
 
8740
<programlisting role="C">
 
8741
void print_state( gpointer    callback_data,
 
8742
                  guint       callback_action,
 
8743
                  GtkWidget  *widget )
 
8744
</programlisting>
 
8745
 
 
8746
<para>with <literal>callback_action</literal> equal to 7.</para>
 
8747
 
 
8748
<para>Creating a radio button set:</para>
 
8749
 
 
8750
<programlisting role="C">
 
8751
GtkItemFactoryEntry entry1 = {"/_View/_Low Resolution", NULL, change_resolution,
 
8752
                                1, "&lt;RadioButton&gt;"};
 
8753
GtkItemFactoryEntry entry2 = {"/_View/_High Resolution", NULL, change_resolution,
 
8754
                                2, "/View/Low Resolution"};
 
8755
</programlisting>
 
8756
 
 
8757
<para><literal>entry1</literal> defines a lone radio button that when toggled
 
8758
calls the function change_resolution() with the parameter
 
8759
<literal>callback_action</literal> equal to 1. change_resolution() is of
 
8760
the form:</para>
 
8761
 
 
8762
<programlisting role="C">
 
8763
void change_resolution(gpointer    callback_data,
 
8764
                       guint       callback_action,
 
8765
                       GtkWidget  *widget)
 
8766
</programlisting>
 
8767
 
 
8768
<para><literal>entry2</literal> defines a radio button that belongs to the
 
8769
radio group that entry1 belongs to. It calls the same function when toggled
 
8770
but with the parameter <literal>callback_action</literal> equal to 2. Note that
 
8771
the item_type of <literal>entry2</literal> is the path of entry1
 
8772
<emphasis>without</emphasis> the accelerators ('_'). If another radio button was
 
8773
required in the same group then it would be defined in the same way as
 
8774
<literal>entry2</literal> was with its <literal>item_type</literal> again
 
8775
equal to "/View/Low Resolution".</para>
 
8776
</sect3>
 
8777
 
 
8778
<!-- ----------------------------------------------------------------- -->
 
8779
<sect3 id="sec-ItemFactoryEntryArrays">
 
8780
<title>ItemFactoryEntry Arrays</title>
 
8781
 
 
8782
<para>An ItemFactoryEntry on it's own however isn't useful. An array of
 
8783
entries is what's required to define a menu. Below is an example of how
 
8784
you'd declare this array.</para>
 
8785
 
 
8786
<programlisting role="C">
 
8787
static GtkItemFactoryEntry entries[] = {
 
8788
  { "/_File",         NULL,      NULL,         0, "&lt;Branch&gt;" },
 
8789
  { "/File/tear1",    NULL,      NULL,         0, "&lt;Tearoff&gt;" },
 
8790
  { "/File/_New",     "&lt;CTRL&gt;N", new_file,     1, "&lt;Item&gt;" },
 
8791
  { "/File/_Open...", "&lt;CTRL&gt;O", open_file,    1, "&lt;Item&gt;" },
 
8792
  { "/File/sep1",     NULL,      NULL,         0, "&lt;Separator&gt;" },
 
8793
  { "/File/_Quit",    "&lt;CTRL&gt;Q", quit_program, 0, "&lt;StockItem&gt;", GTK_STOCK_QUIT } };
 
8794
</programlisting>
 
8795
</sect3>
 
8796
</sect2>
 
8797
 
 
8798
<!-- ----------------------------------------------------------------- -->
 
8799
<sect2 id="sec-ItemFactoryCreation">
 
8800
<title>Creating an ItemFactory</title>
 
8801
 
 
8802
<para>An array of GtkItemFactoryEntry items defines a menu. Once this
 
8803
array is defined then the item factory can be created. The function that
 
8804
does this is:</para>
 
8805
 
 
8806
<programlisting role="C">
 
8807
GtkItemFactory* gtk_item_factory_new( GtkType        container_type,
 
8808
                                      const gchar   *path,
 
8809
                                      GtkAccelGroup *accel_group );
 
8810
</programlisting>
 
8811
 
 
8812
<para><literal>container_type</literal> can be one of:</para>
 
8813
 
 
8814
<programlisting role="C">
 
8815
GTK_TYPE_MENU
 
8816
GTK_TYPE_MENU_BAR
 
8817
GTK_TYPE_OPTION_MENU
 
8818
</programlisting>
 
8819
 
 
8820
<para><literal>container_type</literal> defines what type of menu
 
8821
you want, so when you extract it later it is either a menu (for pop-ups
 
8822
for instance), a menu bar, or an option menu (like a combo box but with
 
8823
a menu of pull downs).</para>
 
8824
 
 
8825
<para><literal>path</literal> defines the path of the root of the menu.
 
8826
Basically it is a unique name for the root of the menu, it must be
 
8827
surrounded by "&lt;&gt;". This is important for the naming of the
 
8828
accelerators and should be unique. It should be unique both for each
 
8829
menu and between each program. For example in a program named 'foo', the
 
8830
main menu should be called "&lt;FooMain&gt;", and a pop-up menu
 
8831
"&lt;FooImagePopUp&gt;", or similar. What's important is that they're unique.</para>
 
8832
 
 
8833
<para><literal>accel_group</literal> is a pointer to a gtk_accel_group. The
 
8834
item factory sets up the accelerator table while generating menus. New
 
8835
accelerator groups are generated by gtk_accel_group_new().</para>
 
8836
 
 
8837
<para>But this is just the first step. To convert the array of GtkItemFactoryEntry
 
8838
information into widgets the following function is used:</para>
 
8839
 
 
8840
<programlisting role="C">
 
8841
void gtk_item_factory_create_items( GtkItemFactory      *ifactory,
 
8842
                                    guint                n_entries,
 
8843
                                    GtkItemFactoryEntry *entries,
 
8844
                                    gpointer             callback_data );
 
8845
</programlisting>
 
8846
 
 
8847
<para><literal>*ifactory</literal> a pointer to the above created item factory.</para>
 
8848
<para><literal>n_entries</literal> is the number of entries in the
 
8849
GtkItemFactoryEntry array.</para>
 
8850
<para><literal>*entries</literal> is a pointer to the GtkItemFactoryEntry array.</para>
 
8851
<para><literal>callback_data</literal> is what gets passed to all the callback functions
 
8852
for all the entries with callback_action != 0.</para>
 
8853
 
 
8854
<para>The accelerator group has now been formed, so you'll probably want
 
8855
to attach it to the window the menu is in:</para>
 
8856
 
 
8857
<programlisting role="C">
 
8858
void gtk_window_add_accel_group( GtkWindow     *window,
 
8859
                                 GtkAccelGroup *accel_group);
 
8860
</programlisting>
 
8861
</sect2>
 
8862
 
 
8863
<!-- ----------------------------------------------------------------- -->
 
8864
<sect2 id="sec-UsingMenuandItems">
 
8865
<title>Making use of the menu and its menu items</title>
 
8866
 
 
8867
<para>The last thing to do is make use of the menu. The following function
 
8868
extracts the relevant widgets from the ItemFactory:</para>
 
8869
 
 
8870
<programlisting role="C">
 
8871
GtkWidget* gtk_item_factory_get_widget( GtkItemFactory *ifactory,
 
8872
                                        const gchar    *path );
 
8873
</programlisting>
 
8874
 
 
8875
<para>For instance if an ItemFactory has two entries "/File" and "/File/New",
 
8876
using a path of "/File" would retrieve a <emphasis>menu</emphasis> widget from the
 
8877
ItemFactory. Using a path of "/File/New" would retrieve a
 
8878
<emphasis>menu item</emphasis> widget. This makes it possible to set the initial state
 
8879
of menu items. For example to set the default radio
 
8880
item to the one with the path "/Shape/Oval" then the following code would
 
8881
be used:</para>
 
8882
 
 
8883
<programlisting role="C">
 
8884
gtk_check_menu_item_set_active(
 
8885
        GTK_CHECK_MENU_ITEM (gtk_item_factory_get_item (item_factory, "/Shape/Oval")),
 
8886
        TRUE);
 
8887
</programlisting>
 
8888
 
 
8889
<para>Finally to retrieve the root of the menu use gtk_item_factory_get_item()
 
8890
with a path of "&lt;main&gt;" (or whatever path was used in
 
8891
gtk_item_factory_new()). In the case of the ItemFactory being created with
 
8892
type GTK_TYPE_MENU_BAR this returns a menu bar widget. With type GTK_TYPE_MENU
 
8893
a menu widget is returned. With type GTK_TYPE_OPTION_MENU an option menu
 
8894
widget is returned.</para>
 
8895
 
 
8896
<para><emphasis>Remember</emphasis> for an entry defined with path "/_File"
 
8897
the path here is actually "/File".</para>
 
8898
 
 
8899
<para>Now you have a menubar or menu which can be manipulated in the same
 
8900
way as shown in the
 
8901
<link linkend="sec-ManualMenuCreation">Manual Menu Creation</link>
 
8902
section.</para>
 
8903
</sect2>
 
8904
</sect1>
 
8905
 
 
8906
<!-- ----------------------------------------------------------------- -->
 
8907
<sect1 id="sec-ItemFactoryExample">
 
8908
<title>Item Factory Example</title>
 
8909
 
 
8910
<para>Here is an example using the GTK item factory.</para>
 
8911
 
 
8912
<programlisting role="C">
 
8913
<!-- example-start menu itemfactory.c -->
 
8914
 
 
8915
#include &lt;gtk/gtk.h&gt;
 
8916
 
 
8917
/* Obligatory basic callback */
 
8918
static void print_hello( GtkWidget *w,
 
8919
                         gpointer   data )
 
8920
{
 
8921
  g_message ("Hello, World!\n");
 
8922
}
 
8923
 
 
8924
/* For the check button */
 
8925
static void print_toggle( gpointer   callback_data,
 
8926
                          guint      callback_action,
 
8927
                          GtkWidget *menu_item )
 
8928
{
 
8929
   g_message ("Check button state - %d\n",
 
8930
              GTK_CHECK_MENU_ITEM (menu_item)-&gt;active);
 
8931
}
 
8932
 
 
8933
/* For the radio buttons */
 
8934
static void print_selected( gpointer   callback_data,
 
8935
                            guint      callback_action,
 
8936
                            GtkWidget *menu_item )
 
8937
{
 
8938
   if(GTK_CHECK_MENU_ITEM(menu_item)-&gt;active)
 
8939
     g_message ("Radio button %d selected\n", callback_action);
 
8940
}
 
8941
 
 
8942
/* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
 
8943
static GtkItemFactoryEntry menu_items[] = {
 
8944
  { "/_File",         NULL,         NULL,           0, "&lt;Branch&gt;" },
 
8945
  { "/File/_New",     "&lt;control&gt;N", print_hello,    0, "&lt;StockItem&gt;", GTK_STOCK_NEW },
 
8946
  { "/File/_Open",    "&lt;control&gt;O", print_hello,    0, "&lt;StockItem&gt;", GTK_STOCK_OPEN },
 
8947
  { "/File/_Save",    "&lt;control&gt;S", print_hello,    0, "&lt;StockItem&gt;", GTK_STOCK_SAVE },
 
8948
  { "/File/Save _As", NULL,         NULL,           0, "&lt;Item&gt;" },
 
8949
  { "/File/sep1",     NULL,         NULL,           0, "&lt;Separator&gt;" },
 
8950
  { "/File/_Quit",    "&lt;CTRL&gt;Q", gtk_main_quit, 0, "&lt;StockItem&gt;", GTK_STOCK_QUIT },
 
8951
  { "/_Options",      NULL,         NULL,           0, "&lt;Branch&gt;" },
 
8952
  { "/Options/tear",  NULL,         NULL,           0, "&lt;Tearoff&gt;" },
 
8953
  { "/Options/Check", NULL,         print_toggle,   1, "&lt;CheckItem&gt;" },
 
8954
  { "/Options/sep",   NULL,         NULL,           0, "&lt;Separator&gt;" },
 
8955
  { "/Options/Rad1",  NULL,         print_selected, 1, "&lt;RadioItem&gt;" },
 
8956
  { "/Options/Rad2",  NULL,         print_selected, 2, "/Options/Rad1" },
 
8957
  { "/Options/Rad3",  NULL,         print_selected, 3, "/Options/Rad1" },
 
8958
  { "/_Help",         NULL,         NULL,           0, "&lt;LastBranch&gt;" },
 
8959
  { "/_Help/About",   NULL,         NULL,           0, "&lt;Item&gt;" },
 
8960
};
 
8961
 
 
8962
static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
 
8963
 
 
8964
/* Returns a menubar widget made from the above menu */
 
8965
static GtkWidget *get_menubar_menu( GtkWidget  *window )
 
8966
{
 
8967
  GtkItemFactory *item_factory;
 
8968
  GtkAccelGroup *accel_group;
 
8969
 
 
8970
  /* Make an accelerator group (shortcut keys) */
 
8971
  accel_group = gtk_accel_group_new ();
 
8972
 
 
8973
  /* Make an ItemFactory (that makes a menubar) */
 
8974
  item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "&lt;main&gt;",
 
8975
                                       accel_group);
 
8976
 
 
8977
  /* This function generates the menu items. Pass the item factory,
 
8978
     the number of items in the array, the array itself, and any
 
8979
     callback data for the the menu items. */
 
8980
  gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
 
8981
 
 
8982
  /* Attach the new accelerator group to the window. */
 
8983
  gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
 
8984
 
 
8985
  /* Finally, return the actual menu bar created by the item factory. */
 
8986
  return gtk_item_factory_get_widget (item_factory, "&lt;main&gt;");
 
8987
}
 
8988
 
 
8989
/* Popup the menu when the popup button is pressed */
 
8990
static gboolean popup_cb( GtkWidget *widget,
 
8991
                          GdkEvent *event,
 
8992
                          GtkWidget *menu )
 
8993
{
 
8994
   GdkEventButton *bevent = (GdkEventButton *)event;
 
8995
  
 
8996
   /* Only take button presses */
 
8997
   if (event-&gt;type != GDK_BUTTON_PRESS)
 
8998
     return FALSE;
 
8999
  
 
9000
   /* Show the menu */
 
9001
   gtk_menu_popup (GTK_MENU(menu), NULL, NULL,
 
9002
                   NULL, NULL, bevent-&gt;button, bevent-&gt;time);
 
9003
  
 
9004
   return TRUE;
 
9005
}
 
9006
 
 
9007
/* Same as with get_menubar_menu() but just return a button with a signal to
 
9008
   call a popup menu */
 
9009
GtkWidget *get_popup_menu( void )
 
9010
{
 
9011
   GtkItemFactory *item_factory;
 
9012
   GtkWidget *button, *menu;
 
9013
  
 
9014
   /* Same as before but don't bother with the accelerators */
 
9015
   item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "&lt;main&gt;",
 
9016
                                        NULL);
 
9017
   gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
 
9018
   menu = gtk_item_factory_get_widget (item_factory, "&lt;main&gt;");
 
9019
  
 
9020
   /* Make a button to activate the popup menu */
 
9021
   button = gtk_button_new_with_label ("Popup");
 
9022
   /* Make the menu popup when clicked */
 
9023
   g_signal_connect (G_OBJECT(button),
 
9024
                     "event",
 
9025
                     G_CALLBACK(popup_cb),
 
9026
                     (gpointer) menu);
 
9027
 
 
9028
   return button;
 
9029
}
 
9030
 
 
9031
/* Same again but return an option menu */
 
9032
GtkWidget *get_option_menu( void )
 
9033
{
 
9034
   GtkItemFactory *item_factory;
 
9035
   GtkWidget *option_menu;
 
9036
  
 
9037
   /* Same again, not bothering with the accelerators */
 
9038
   item_factory = gtk_item_factory_new (GTK_TYPE_OPTION_MENU, "&lt;main&gt;",
 
9039
                                        NULL);
 
9040
   gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
 
9041
   option_menu = gtk_item_factory_get_widget (item_factory, "&lt;main&gt;");
 
9042
 
 
9043
   return option_menu;
 
9044
}
 
9045
 
 
9046
/* You have to start somewhere */
 
9047
int main( int argc,
 
9048
          char *argv[] )
 
9049
{
 
9050
  GtkWidget *window;
 
9051
  GtkWidget *main_vbox;
 
9052
  GtkWidget *menubar, *option_menu, *popup_button;
 
9053
 
 
9054
  /* Initialize GTK */
 
9055
  gtk_init (&amp;argc, &amp;argv);
 
9056
 
 
9057
  /* Make a window */
 
9058
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
9059
  g_signal_connect (G_OBJECT (window), "destroy",
 
9060
                    G_CALLBACK (gtk_main_quit),
 
9061
                    NULL);
 
9062
  gtk_window_set_title (GTK_WINDOW(window), "Item Factory");
 
9063
  gtk_widget_set_size_request (GTK_WIDGET(window), 300, 200);
 
9064
 
 
9065
  /* Make a vbox to put the three menus in */
 
9066
  main_vbox = gtk_vbox_new (FALSE, 1);
 
9067
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 1);
 
9068
  gtk_container_add (GTK_CONTAINER (window), main_vbox);
 
9069
 
 
9070
  /* Get the three types of menu */
 
9071
  /* Note: all three menus are separately created, so they are not the
 
9072
     same menu */
 
9073
  menubar = get_menubar_menu (window);
 
9074
  popup_button = get_popup_menu ();
 
9075
  option_menu = get_option_menu ();
 
9076
  
 
9077
  /* Pack it all together */
 
9078
  gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
 
9079
  gtk_box_pack_end (GTK_BOX (main_vbox), popup_button, FALSE, TRUE, 0);
 
9080
  gtk_box_pack_end (GTK_BOX (main_vbox), option_menu, FALSE, TRUE, 0);
 
9081
 
 
9082
  /* Show the widgets */
 
9083
  gtk_widget_show_all (window);
 
9084
  
 
9085
  /* Finished! */
 
9086
  gtk_main ();
 
9087
 
 
9088
  return 0;
 
9089
}
 
9090
<!-- example-end -->
 
9091
</programlisting>
 
9092
 
 
9093
</sect1>
 
9094
</chapter>
 
9095
 
 
9096
<!-- ***************************************************************** -->
 
9097
<chapter id="ch-UndocWidgets">
 
9098
<title>Undocumented Widgets</title>
 
9099
 
 
9100
<para>These all require authors! :) Please consider contributing to our
 
9101
tutorial.</para>
 
9102
 
 
9103
<para>If you must use one of these widgets that are undocumented, I strongly
 
9104
suggest you take a look at their respective header files in the GTK
 
9105
distribution. GTK's function names are very descriptive. Once you
 
9106
have an understanding of how things work, it's not difficult to figure
 
9107
out how to use a widget simply by looking at its function
 
9108
declarations. This, along with a few examples from others' code, and
 
9109
it should be no problem.</para>
 
9110
 
 
9111
<para>When you do come to understand all the functions of a new undocumented
 
9112
widget, please consider writing a tutorial on it so others may benefit
 
9113
from your time.</para>
 
9114
 
 
9115
<!-- ----------------------------------------------------------------- -->
 
9116
<sect1 id="sec-AccelLabel">
 
9117
<title>Accel Label</title>
 
9118
 
 
9119
<para></para>
 
9120
 
 
9121
</sect1>
 
9122
 
 
9123
<!-- ----------------------------------------------------------------- -->
 
9124
<sect1 id="sec-OptionMenu">
 
9125
<title>Option Menu</title>
 
9126
 
 
9127
<para></para>
 
9128
 
 
9129
</sect1>
 
9130
 
 
9131
<!-- ----------------------------------------------------------------- -->
 
9132
<sect1 id="sec-MenuItems">
 
9133
<title>Menu Items</title>
 
9134
 
 
9135
<para></para>
 
9136
 
 
9137
<sect2 id="sec-CheckMenuItem">
 
9138
<title>Check Menu Item</title>
 
9139
 
 
9140
<para></para>
 
9141
</sect2>
 
9142
 
 
9143
<sect2 id="sec-RadioMenuItem">
 
9144
<title>Radio Menu Item</title>
 
9145
 
 
9146
<para></para>
 
9147
</sect2>
 
9148
 
 
9149
<sect2 id="sec-SeparatorMenuItem">
 
9150
<title>Separator Menu Item</title>
 
9151
 
 
9152
<para></para>
 
9153
</sect2>
 
9154
 
 
9155
<sect2 id="sec-TearoffMenuItem">
 
9156
<title>Tearoff Menu Item</title>
 
9157
 
 
9158
<para></para>
 
9159
</sect2>
 
9160
</sect1>
 
9161
 
 
9162
<!-- ----------------------------------------------------------------- -->
 
9163
<sect1 id="sec-Curves">
 
9164
<title>Curves</title>
 
9165
 
 
9166
<para></para>
 
9167
 
 
9168
</sect1>
 
9169
 
 
9170
<!-- ----------------------------------------------------------------- -->
 
9171
<sect1 id="sec-DrawingArea">
 
9172
<title>Drawing Area</title>
 
9173
 
 
9174
<para></para>
 
9175
 
 
9176
</sect1>
 
9177
 
 
9178
<!-- ----------------------------------------------------------------- -->
 
9179
<sect1 id="sec-FontSelectionDialog">
 
9180
<title>Font Selection Dialog</title>
 
9181
 
 
9182
<para></para>
 
9183
 
 
9184
</sect1>
 
9185
 
 
9186
<!-- ----------------------------------------------------------------- -->
 
9187
<sect1 id="sec-MessageDialog">
 
9188
<title>Message Dialog</title>
 
9189
 
 
9190
<para></para>
 
9191
 
 
9192
</sect1>
 
9193
 
 
9194
<!-- ----------------------------------------------------------------- -->
 
9195
<sect1 id="sec-GammaCurve">
 
9196
<title>Gamma Curve</title>
 
9197
 
 
9198
<para></para>
 
9199
 
 
9200
</sect1>
 
9201
 
 
9202
<!-- ----------------------------------------------------------------- -->
 
9203
<sect1 id="sec-Image">
 
9204
<title>Image</title>
 
9205
 
 
9206
<para></para>
 
9207
 
 
9208
</sect1>
 
9209
 
 
9210
<!-- ----------------------------------------------------------------- -->
 
9211
<sect1 id="sec-PlugsAndSockets">
 
9212
<title>Plugs and Sockets</title>
 
9213
 
 
9214
<para></para>
 
9215
 
 
9216
</sect1>
 
9217
 
 
9218
<!-- ----------------------------------------------------------------- -->
 
9219
<sect1 id="sec-TreeView">
 
9220
<title>Tree View</title>
 
9221
 
 
9222
<para></para>
 
9223
 
 
9224
</sect1>
 
9225
 
 
9226
<!-- ----------------------------------------------------------------- -->
 
9227
<sect1 id="sec-TextView">
 
9228
<title>Text View</title>
 
9229
 
 
9230
<para></para>
 
9231
 
 
9232
</sect1>
 
9233
</chapter>
 
9234
 
 
9235
<!-- ***************************************************************** -->
 
9236
<chapter id="ch-SettingWidgetAttributes">
 
9237
<title>Setting Widget Attributes</title>
 
9238
 
 
9239
<para>This describes the functions used to operate on widgets. These can be
 
9240
used to set style, padding, size, etc.</para>
 
9241
 
 
9242
<para>(Maybe I should make a whole section on accelerators.)</para>
 
9243
 
 
9244
<programlisting role="C">
 
9245
void gtk_widget_activate( GtkWidget *widget );
 
9246
 
 
9247
void gtk_widget_set_name( GtkWidget *widget,
 
9248
                          gchar     *name );
 
9249
 
 
9250
gchar *gtk_widget_get_name( GtkWidget *widget );
 
9251
 
 
9252
void gtk_widget_set_sensitive( GtkWidget *widget,
 
9253
                               gboolean   sensitive );
 
9254
 
 
9255
void gtk_widget_set_style( GtkWidget *widget,
 
9256
                           GtkStyle  *style );
 
9257
                                           
 
9258
GtkStyle *gtk_widget_get_style( GtkWidget *widget );
 
9259
 
 
9260
GtkStyle *gtk_widget_get_default_style( void );
 
9261
 
 
9262
void gtk_widget_set_size_request( GtkWidget *widget,
 
9263
                                  gint       width,
 
9264
                                  gint       height );
 
9265
 
 
9266
void gtk_widget_grab_focus( GtkWidget *widget );
 
9267
 
 
9268
void gtk_widget_show( GtkWidget *widget );
 
9269
 
 
9270
void gtk_widget_hide( GtkWidget *widget );
 
9271
</programlisting>
 
9272
 
 
9273
</chapter>
 
9274
 
 
9275
<!-- ***************************************************************** -->
 
9276
<chapter id="ch-Timeouts">
 
9277
<title>Timeouts, IO and Idle Functions</title>
 
9278
 
 
9279
<!-- ----------------------------------------------------------------- -->
 
9280
<sect1 id="sec-Timeouts">
 
9281
<title>Timeouts</title>
 
9282
 
 
9283
<para>You may be wondering how you make GTK do useful work when in gtk_main.
 
9284
Well, you have several options. Using the following function you can
 
9285
create a timeout function that will be called every "interval"
 
9286
milliseconds.</para>
 
9287
 
 
9288
<programlisting role="C">
 
9289
gint g_timeout_add (guint32     interval,
 
9290
                    GtkFunction function,
 
9291
                    gpointer    data);
 
9292
</programlisting>
 
9293
 
 
9294
<para>The first argument is the number of milliseconds between calls to your
 
9295
function. The second argument is the function you wish to have called,
 
9296
and the third, the data passed to this callback function. The return
 
9297
value is an integer "tag" which may be used to stop the timeout by
 
9298
calling:</para>
 
9299
 
 
9300
<programlisting role="C">
 
9301
void g_source_remove (gint tag);
 
9302
</programlisting>
 
9303
 
 
9304
<para>You may also stop the timeout function by returning zero or FALSE from
 
9305
your callback function. Obviously this means if you want your function
 
9306
to continue to be called, it should return a non-zero value,
 
9307
i.e., TRUE.</para>
 
9308
 
 
9309
<para>The declaration of your callback should look something like this:</para>
 
9310
 
 
9311
<programlisting role="C">
 
9312
gint timeout_callback (gpointer data);
 
9313
</programlisting>
 
9314
 
 
9315
</sect1>
 
9316
 
 
9317
<!-- ----------------------------------------------------------------- -->
 
9318
<sect1 id="sec-MonitoringIO">
 
9319
<title>Monitoring IO</title>
 
9320
 
 
9321
<para>A nifty feature of GDK (the library that underlies GTK), is the
 
9322
ability to have it check for data on a file descriptor for you (as
 
9323
returned by open(2) or socket(2)). This is especially useful for
 
9324
networking applications. The function:</para>
 
9325
 
 
9326
<programlisting role="C">
 
9327
gint gdk_input_add( gint              source,
 
9328
                    GdkInputCondition condition,
 
9329
                    GdkInputFunction  function,
 
9330
                    gpointer          data );
 
9331
</programlisting>
 
9332
 
 
9333
<para>Where the first argument is the file descriptor you wish to have
 
9334
watched, and the second specifies what you want GDK to look for. This
 
9335
may be one of:</para>
 
9336
 
 
9337
<itemizedlist>
 
9338
<listitem><simpara><literal>GDK_INPUT_READ</literal> - Call your function when there is data
 
9339
ready for reading on your file descriptor.</simpara>
 
9340
</listitem>
 
9341
 
 
9342
<listitem><simpara><literal>GDK_INPUT_WRITE</literal> - Call your function when the file
 
9343
descriptor is ready for writing.</simpara>
 
9344
</listitem>
 
9345
</itemizedlist>
 
9346
 
 
9347
<para>As I'm sure you've figured out already, the third argument is the
 
9348
function you wish to have called when the above conditions are
 
9349
satisfied, and the fourth is the data to pass to this function.</para>
 
9350
 
 
9351
<para>The return value is a tag that may be used to stop GDK from monitoring
 
9352
this file descriptor using the following function.</para>
 
9353
 
 
9354
<programlisting role="C">
 
9355
void gdk_input_remove( gint tag );
 
9356
</programlisting>
 
9357
 
 
9358
<para>The callback function should be declared as:</para>
 
9359
 
 
9360
<programlisting role="C">
 
9361
void input_callback( gpointer          data,
 
9362
                     gint              source, 
 
9363
                     GdkInputCondition condition );
 
9364
</programlisting>
 
9365
 
 
9366
<para>Where <literal>source</literal> and <literal>condition</literal> are as specified above.</para>
 
9367
 
 
9368
</sect1>
 
9369
 
 
9370
<!-- ----------------------------------------------------------------- -->
 
9371
<sect1 id="sec-IdleFunctions">
 
9372
<title>Idle Functions</title>
 
9373
 
 
9374
<para><!-- TODO: Need to check on idle priorities - TRG -->
 
9375
What if you have a function which you want to be called when nothing
 
9376
else is happening ?</para>
 
9377
 
 
9378
<programlisting role="C">
 
9379
gint gtk_idle_add( GtkFunction function,
 
9380
                   gpointer    data );
 
9381
</programlisting>
 
9382
 
 
9383
<para>This causes GTK to call the specified function whenever nothing else
 
9384
is happening.</para>
 
9385
 
 
9386
<programlisting role="C">
 
9387
void gtk_idle_remove( gint tag );
 
9388
</programlisting>
 
9389
 
 
9390
<para>I won't explain the meaning of the arguments as they follow very much
 
9391
like the ones above. The function pointed to by the first argument to
 
9392
gtk_idle_add will be called whenever the opportunity arises. As with
 
9393
the others, returning FALSE will stop the idle function from being
 
9394
called.</para>
 
9395
 
 
9396
</sect1>
 
9397
</chapter>
 
9398
 
 
9399
<!-- ***************************************************************** -->
 
9400
<chapter id="ch-AdvancedEventsAndSignals">
 
9401
<title>Advanced Event and Signal Handling</title>
 
9402
 
 
9403
<!-- ----------------------------------------------------------------- -->
 
9404
<sect1 id="sec-SignalFunctions">
 
9405
<title>Signal Functions</title>
 
9406
 
 
9407
<!-- ----------------------------------------------------------------- -->
 
9408
<sect2>
 
9409
<title>Connecting and Disconnecting Signal Handlers</title>
 
9410
 
 
9411
<programlisting role="C">
 
9412
gulong g_signal_connect( GObject     *object,
 
9413
                         const gchar *name,
 
9414
                         GCallback    func,
 
9415
                         gpointer     func_data );
 
9416
 
 
9417
gulong g_signal_connect_after( GObject       *object,
 
9418
                               const gchar   *name,
 
9419
                               GCallback      func,
 
9420
                               gpointer       func_data );
 
9421
 
 
9422
gulong g_signal_connect_swapped( GObject       *object,
 
9423
                                 const gchar   *name,
 
9424
                                 GCallback      func,
 
9425
                                 GObject       *slot_object );
 
9426
 
 
9427
void g_signal_handler_disconnect( GObject *object,
 
9428
                                  gulong   handler_id );
 
9429
 
 
9430
void g_signal_handlers_disconnect_by_func( GObject   *object,
 
9431
                                           GCallback  func,
 
9432
                                           gpointer   data );
 
9433
</programlisting>
 
9434
 
 
9435
</sect2>
 
9436
 
 
9437
<!-- ----------------------------------------------------------------- -->
 
9438
<sect2>
 
9439
<title>Blocking and Unblocking Signal Handlers</title>
 
9440
 
 
9441
<programlisting role="C">
 
9442
void g_signal_handler_block( GObject *object,
 
9443
                             gulong   handler_id);
 
9444
 
 
9445
void g_signal_handlers_block_by_func( GObject   *object,
 
9446
                                      GCallback  func,
 
9447
                                      gpointer   data );
 
9448
 
 
9449
void g_signal_handler_unblock( GObject *object,
 
9450
                               gulong   handler_id );
 
9451
 
 
9452
void g_signal_handler_unblock_by_func( GObject   *object,
 
9453
                                       GCallback  func,
 
9454
                                       gpointer   data );
 
9455
</programlisting>
 
9456
 
 
9457
</sect2>
 
9458
 
 
9459
<!-- ----------------------------------------------------------------- -->
 
9460
<sect2>
 
9461
<title>Emitting and Stopping Signals</title>
 
9462
 
 
9463
<programlisting role="C">
 
9464
void g_signal_emit( GObject *object,
 
9465
                    guint      signal_id,
 
9466
                    ... );
 
9467
 
 
9468
void g_signal_emit_by_name( GObject     *object,
 
9469
                            const gchar *name,
 
9470
                            ... );
 
9471
 
 
9472
void g_signal_emitv( const GValue *instance_and_params,
 
9473
                     guint         signal_id,
 
9474
                     GQuark        detail,
 
9475
                     GValue       *return_value );
 
9476
 
 
9477
void g_signal_stop_emission( GObject *object,
 
9478
                             guint    signal_id,
 
9479
                             GQuark   detail );
 
9480
 
 
9481
void g_signal_stop_emission_by_name( GObject   *object,
 
9482
                                     const gchar *detailed_signal );
 
9483
</programlisting>
 
9484
 
 
9485
</sect2>
 
9486
</sect1>
 
9487
 
 
9488
<!-- ----------------------------------------------------------------- -->
 
9489
<sect1 id="sec-SignalEmissionAndPropagation">
 
9490
<title>Signal Emission and Propagation</title>
 
9491
 
 
9492
<para>Signal emission is the process whereby GTK runs all handlers for a
 
9493
specific object and signal.</para>
 
9494
 
 
9495
<para>First, note that the return value from a signal emission is the return
 
9496
value of the <emphasis>last</emphasis> handler executed. Since event signals are
 
9497
all of type <literal>GTK_RUN_LAST</literal>, this will be the default (GTK supplied)
 
9498
handler, unless you connect with gtk_signal_connect_after().</para>
 
9499
 
 
9500
<para>The way an event (say "button_press_event") is handled, is:</para>
 
9501
 
 
9502
<itemizedlist>
 
9503
<listitem><simpara>Start with the widget where the event occured.</simpara>
 
9504
</listitem>
 
9505
 
 
9506
<listitem><simpara>Emit the generic "event" signal. If that signal handler returns
 
9507
a value of TRUE, stop all processing.</simpara>
 
9508
</listitem>
 
9509
 
 
9510
<listitem><simpara>Otherwise, emit a specific, "button_press_event" signal. If that
 
9511
returns TRUE, stop all processing.</simpara>
 
9512
</listitem>
 
9513
 
 
9514
<listitem><simpara>Otherwise, go to the widget's parent, and repeat the above two
 
9515
steps.</simpara>
 
9516
</listitem>
 
9517
 
 
9518
<listitem><simpara>Continue until some signal handler returns TRUE, or until the
 
9519
top-level widget is reached.</simpara>
 
9520
</listitem>
 
9521
</itemizedlist>
 
9522
 
 
9523
<para>Some consequences of the above are:</para>
 
9524
 
 
9525
<itemizedlist>
 
9526
<listitem><simpara>Your handler's return value will have no effect if there is a
 
9527
default handler, unless you connect with gtk_signal_connect_after().</simpara>
 
9528
</listitem>
 
9529
 
 
9530
<listitem><simpara>To prevent the default handler from being run, you need to
 
9531
connect with gtk_signal_connect() and use
 
9532
gtk_signal_emit_stop_by_name() - the return value only affects whether
 
9533
the signal is propagated, not the current emission.</simpara>
 
9534
</listitem>
 
9535
</itemizedlist>
 
9536
 
 
9537
</sect1>
 
9538
</chapter>
 
9539
 
 
9540
<!-- continue GTK+ 2.0 review here -->
 
9541
 
 
9542
<!-- ***************************************************************** -->
 
9543
<chapter id="ch-ManagingSelections">
 
9544
<title>Managing Selections</title>
 
9545
 
 
9546
<!-- ----------------------------------------------------------------- -->
 
9547
<sect1 id="sec-SelectionsOverview">
 
9548
<title>Overview</title>
 
9549
 
 
9550
<para>One type of interprocess communication supported by X and GTK is
 
9551
<emphasis>selections</emphasis>. A selection identifies a chunk of data, for
 
9552
instance, a portion of text, selected by the user in some fashion, for
 
9553
instance, by dragging with the mouse. Only one application on a
 
9554
display (the <emphasis>owner</emphasis>) can own a particular selection at one
 
9555
time, so when a selection is claimed by one application, the previous
 
9556
owner must indicate to the user that selection has been
 
9557
relinquished. Other applications can request the contents of a
 
9558
selection in different forms, called <emphasis>targets</emphasis>. There can be
 
9559
any number of selections, but most X applications only handle one, the
 
9560
<emphasis>primary selection</emphasis>.</para>
 
9561
 
 
9562
<para>In most cases, it isn't necessary for a GTK application to deal with
 
9563
selections itself. The standard widgets, such as the Entry widget,
 
9564
already have the capability to claim the selection when appropriate
 
9565
(e.g., when the user drags over text), and to retrieve the contents of
 
9566
the selection owned by another widget or another application (e.g.,
 
9567
when the user clicks the second mouse button). However, there may be
 
9568
cases in which you want to give other widgets the ability to supply
 
9569
the selection, or you wish to retrieve targets not supported by
 
9570
default.</para>
 
9571
 
 
9572
<para>A fundamental concept needed to understand selection handling is that
 
9573
of the <emphasis>atom</emphasis>. An atom is an integer that uniquely identifies a
 
9574
string (on a certain display). Certain atoms are predefined by the X
 
9575
server, and in some cases there are constants in <literal>gtk.h</literal>
 
9576
corresponding to these atoms. For instance the constant
 
9577
<literal>GDK_PRIMARY_SELECTION</literal> corresponds to the string "PRIMARY".
 
9578
In other cases, you should use the functions
 
9579
<literal>gdk_atom_intern()</literal>, to get the atom corresponding to a string,
 
9580
and <literal>gdk_atom_name()</literal>, to get the name of an atom. Both
 
9581
selections and targets are identified by atoms.</para>
 
9582
 
 
9583
</sect1>
 
9584
<!-- ----------------------------------------------------------------- -->
 
9585
<sect1 id="sec-RetrievingTheSelection">
 
9586
<title>Retrieving the selection</title>
 
9587
 
 
9588
<para>Retrieving the selection is an asynchronous process. To start the
 
9589
process, you call:</para>
 
9590
 
 
9591
<programlisting role="C">
 
9592
gboolean gtk_selection_convert( GtkWidget *widget, 
 
9593
                                GdkAtom    selection, 
 
9594
                                GdkAtom    target,
 
9595
                                guint32    time );
 
9596
</programlisting>
 
9597
 
 
9598
<para>This <emphasis>converts</emphasis> the selection into the form specified by
 
9599
<literal>target</literal>. If at all possible, the time field should be the time
 
9600
from the event that triggered the selection. This helps make sure that
 
9601
events occur in the order that the user requested them. However, if it
 
9602
is not available (for instance, if the conversion was triggered by a
 
9603
"clicked" signal), then you can use the constant
 
9604
<literal>GDK_CURRENT_TIME</literal>.</para>
 
9605
 
 
9606
<para>When the selection owner responds to the request, a
 
9607
"selection_received" signal is sent to your application. The handler
 
9608
for this signal receives a pointer to a <literal>GtkSelectionData</literal>
 
9609
structure, which is defined as:</para>
 
9610
 
 
9611
<programlisting role="C">
 
9612
struct _GtkSelectionData
 
9613
{
 
9614
  GdkAtom selection;
 
9615
  GdkAtom target;
 
9616
  GdkAtom type;
 
9617
  gint    format;
 
9618
  guchar *data;
 
9619
  gint    length;
 
9620
};
 
9621
</programlisting>
 
9622
 
 
9623
<para><literal>selection</literal> and <literal>target</literal> are the values you gave in your
 
9624
<literal>gtk_selection_convert()</literal> call. <literal>type</literal> is an atom that
 
9625
identifies the type of data returned by the selection owner. Some
 
9626
possible values are "STRING", a string of latin-1 characters, "ATOM",
 
9627
a series of atoms, "INTEGER", an integer, etc. Most targets can only
 
9628
return one type. <literal>format</literal> gives the length of the units (for
 
9629
instance characters) in bits. Usually, you don't care about this when
 
9630
receiving data. <literal>data</literal> is a pointer to the returned data, and
 
9631
<literal>length</literal> gives the length of the returned data, in bytes. If
 
9632
<literal>length</literal> is negative, then an error occurred and the selection
 
9633
could not be retrieved. This might happen if no application owned the
 
9634
selection, or if you requested a target that the application didn't
 
9635
support. The buffer is actually guaranteed to be one byte longer than
 
9636
<literal>length</literal>; the extra byte will always be zero, so it isn't
 
9637
necessary to make a copy of strings just to nul-terminate them.</para>
 
9638
 
 
9639
<para>In the following example, we retrieve the special target "TARGETS",
 
9640
which is a list of all targets into which the selection can be
 
9641
converted.</para>
 
9642
 
 
9643
<programlisting role="C">
 
9644
<!-- example-start selection gettargets.c -->
 
9645
 
 
9646
#include &lt;stdlib.h&gt;
 
9647
#include &lt;gtk/gtk.h&gt;
 
9648
 
 
9649
static void selection_received( GtkWidget        *widget, 
 
9650
                                GtkSelectionData *selection_data, 
 
9651
                                gpointer          data );
 
9652
 
 
9653
/* Signal handler invoked when user clicks on the "Get Targets" button */
 
9654
static void get_targets( GtkWidget *widget,
 
9655
                         gpointer data )
 
9656
{
 
9657
  static GdkAtom targets_atom = GDK_NONE;
 
9658
  GtkWidget *window = (GtkWidget *)data;        
 
9659
 
 
9660
  /* Get the atom corresponding to the string "TARGETS" */
 
9661
  if (targets_atom == GDK_NONE)
 
9662
    targets_atom = gdk_atom_intern ("TARGETS", FALSE);
 
9663
 
 
9664
  /* And request the "TARGETS" target for the primary selection */
 
9665
  gtk_selection_convert (window, GDK_SELECTION_PRIMARY, targets_atom,
 
9666
                         GDK_CURRENT_TIME);
 
9667
}
 
9668
 
 
9669
/* Signal handler called when the selections owner returns the data */
 
9670
static void selection_received( GtkWidget        *widget,
 
9671
                                GtkSelectionData *selection_data, 
 
9672
                                gpointer          data )
 
9673
{
 
9674
  GdkAtom *atoms;
 
9675
  GList *item_list;
 
9676
  int i;
 
9677
 
 
9678
  /* **** IMPORTANT **** Check to see if retrieval succeeded  */
 
9679
  if (selection_data-&gt;length &lt; 0)
 
9680
    {
 
9681
      g_print ("Selection retrieval failed\n");
 
9682
      return;
 
9683
    }
 
9684
  /* Make sure we got the data in the expected form */
 
9685
  if (selection_data-&gt;type != GDK_SELECTION_TYPE_ATOM)
 
9686
    {
 
9687
      g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
 
9688
      return;
 
9689
    }
 
9690
  
 
9691
  /* Print out the atoms we received */
 
9692
  atoms = (GdkAtom *)selection_data-&gt;data;
 
9693
 
 
9694
  item_list = NULL;
 
9695
  for (i = 0; i &lt; selection_data-&gt;length / sizeof(GdkAtom); i++)
 
9696
    {
 
9697
      char *name;
 
9698
      name = gdk_atom_name (atoms[i]);
 
9699
      if (name != NULL)
 
9700
        g_print ("%s\n",name);
 
9701
      else
 
9702
        g_print ("(bad atom)\n");
 
9703
    }
 
9704
 
 
9705
  return;
 
9706
}
 
9707
 
 
9708
int main( int   argc,
 
9709
          char *argv[] )
 
9710
{
 
9711
  GtkWidget *window;
 
9712
  GtkWidget *button;
 
9713
  
 
9714
  gtk_init (&amp;argc, &amp;argv);
 
9715
 
 
9716
  /* Create the toplevel window */
 
9717
 
 
9718
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
9719
  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
 
9720
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
9721
 
 
9722
  g_signal_connect (G_OBJECT (window), "destroy",
 
9723
                    G_CALLBACK (exit), NULL);
 
9724
 
 
9725
  /* Create a button the user can click to get targets */
 
9726
 
 
9727
  button = gtk_button_new_with_label ("Get Targets");
 
9728
  gtk_container_add (GTK_CONTAINER (window), button);
 
9729
 
 
9730
  g_signal_connect (G_OBJECT (button), "clicked",
 
9731
                    G_CALLBACK (get_targets), (gpointer) window);
 
9732
  g_signal_connect (G_OBJECT (window), "selection_received",
 
9733
                    G_CALLBACK (selection_received), NULL);
 
9734
 
 
9735
  gtk_widget_show (button);
 
9736
  gtk_widget_show (window);
 
9737
  
 
9738
  gtk_main ();
 
9739
  
 
9740
  return 0;
 
9741
}
 
9742
<!-- example-end -->
 
9743
</programlisting>
 
9744
 
 
9745
</sect1>
 
9746
<!-- ----------------------------------------------------------------- -->
 
9747
<sect1 id="sec-SupplyingTheSelection">
 
9748
<title>Supplying the selection</title>
 
9749
 
 
9750
<para>Supplying the selection is a bit more complicated. You must register 
 
9751
handlers that will be called when your selection is requested. For
 
9752
each selection/target pair you will handle, you make a call to:</para>
 
9753
 
 
9754
<programlisting role="C">
 
9755
void gtk_selection_add_target( GtkWidget           *widget, 
 
9756
                               GdkAtom              selection,
 
9757
                               GdkAtom              target,
 
9758
                               guint                info );
 
9759
</programlisting>
 
9760
 
 
9761
<para><literal>widget</literal>, <literal>selection</literal>, and <literal>target</literal> identify the requests
 
9762
this handler will manage. When a request for a selection is received,
 
9763
the "selection_get" signal will be called. <literal>info</literal> can be used as an
 
9764
enumerator to identify the specific target within the callback function.</para>
 
9765
 
 
9766
<para>The callback function has the signature:</para>
 
9767
 
 
9768
<programlisting role="C">
 
9769
void  "selection_get"( GtkWidget          *widget,
 
9770
                       GtkSelectionData   *selection_data,
 
9771
                       guint               info,
 
9772
                       guint               time );
 
9773
</programlisting>
 
9774
 
 
9775
<para>The GtkSelectionData is the same as above, but this time, we're
 
9776
responsible for filling in the fields <literal>type</literal>, <literal>format</literal>,
 
9777
<literal>data</literal>, and <literal>length</literal>. (The <literal>format</literal> field is actually
 
9778
important here - the X server uses it to figure out whether the data
 
9779
needs to be byte-swapped or not. Usually it will be 8 - <emphasis>i.e.</emphasis> a
 
9780
character - or 32 - <emphasis>i.e.</emphasis> an integer.) This is done by calling the
 
9781
function:</para>
 
9782
 
 
9783
<programlisting role="C">
 
9784
void gtk_selection_data_set( GtkSelectionData *selection_data,
 
9785
                             GdkAtom           type,
 
9786
                             gint              format,
 
9787
                             guchar           *data,
 
9788
                             gint              length );
 
9789
</programlisting>
 
9790
 
 
9791
<para>This function takes care of properly making a copy of the data so that
 
9792
you don't have to worry about keeping it around. (You should not fill
 
9793
in the fields of the GtkSelectionData structure by hand.)</para>
 
9794
 
 
9795
<para>When prompted by the user, you claim ownership of the selection by
 
9796
calling:</para>
 
9797
 
 
9798
<programlisting role="C">
 
9799
gboolean gtk_selection_owner_set( GtkWidget *widget,
 
9800
                                  GdkAtom    selection,
 
9801
                                  guint32    time );
 
9802
</programlisting>
 
9803
 
 
9804
<para>If another application claims ownership of the selection, you will
 
9805
receive a "selection_clear_event".</para>
 
9806
 
 
9807
<para>As an example of supplying the selection, the following program adds
 
9808
selection functionality to a toggle button. When the toggle button is
 
9809
depressed, the program claims the primary selection. The only target
 
9810
supported (aside from certain targets like "TARGETS" supplied by GTK
 
9811
itself), is the "STRING" target. When this target is requested, a
 
9812
string representation of the time is returned.</para>
 
9813
 
 
9814
<programlisting role="C">
 
9815
<!-- example-start selection setselection.c -->
 
9816
 
 
9817
#include &lt;stdlib.h&gt;
 
9818
#include &lt;gtk/gtk.h&gt;
 
9819
#include &lt;time.h&gt;
 
9820
#include &lt;string.h&gt;
 
9821
 
 
9822
GtkWidget *selection_button;
 
9823
GtkWidget *selection_widget;
 
9824
 
 
9825
/* Callback when the user toggles the selection */
 
9826
static void selection_toggled( GtkWidget *widget,
 
9827
                               gint      *have_selection )
 
9828
{
 
9829
  if (GTK_TOGGLE_BUTTON (widget)-&gt;active)
 
9830
    {
 
9831
      *have_selection = gtk_selection_owner_set (selection_widget,
 
9832
                                                 GDK_SELECTION_PRIMARY,
 
9833
                                                 GDK_CURRENT_TIME);
 
9834
      /* if claiming the selection failed, we return the button to
 
9835
         the out state */
 
9836
      if (!*have_selection)
 
9837
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
 
9838
    }
 
9839
  else
 
9840
    {
 
9841
      if (*have_selection)
 
9842
        {
 
9843
          /* Before clearing the selection by setting the owner to NULL,
 
9844
             we check if we are the actual owner */
 
9845
          if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget-&gt;window)
 
9846
            gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
 
9847
                                     GDK_CURRENT_TIME);
 
9848
          *have_selection = FALSE;
 
9849
        }
 
9850
    }
 
9851
}
 
9852
 
 
9853
/* Called when another application claims the selection */
 
9854
static gboolean selection_clear( GtkWidget         *widget,
 
9855
                                 GdkEventSelection *event,
 
9856
                                 gint              *have_selection )
 
9857
{
 
9858
  *have_selection = FALSE;
 
9859
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (selection_button), FALSE);
 
9860
 
 
9861
  return TRUE;
 
9862
}
 
9863
 
 
9864
/* Supplies the current time as the selection. */
 
9865
static void selection_handle( GtkWidget        *widget, 
 
9866
                              GtkSelectionData *selection_data,
 
9867
                              guint             info,
 
9868
                              guint             time_stamp,
 
9869
                              gpointer          data )
 
9870
{
 
9871
  gchar *timestr;
 
9872
  time_t current_time;
 
9873
 
 
9874
  current_time = time (NULL);
 
9875
  timestr = asctime (localtime (&amp;current_time)); 
 
9876
  /* When we return a single string, it should not be null terminated.
 
9877
     That will be done for us */
 
9878
 
 
9879
  gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
 
9880
                          8, timestr, strlen (timestr));
 
9881
}
 
9882
 
 
9883
int main( int   argc,
 
9884
          char *argv[] )
 
9885
{
 
9886
  GtkWidget *window;
 
9887
 
 
9888
  static int have_selection = FALSE;
 
9889
  
 
9890
  gtk_init (&amp;argc, &amp;argv);
 
9891
 
 
9892
  /* Create the toplevel window */
 
9893
 
 
9894
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
9895
  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
 
9896
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
9897
 
 
9898
  g_signal_connect (G_OBJECT (window), "destroy",
 
9899
                    G_CALLBACK (exit), NULL);
 
9900
 
 
9901
  /* Create a toggle button to act as the selection */
 
9902
 
 
9903
  selection_widget = gtk_invisible_new ();
 
9904
  selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
 
9905
  gtk_container_add (GTK_CONTAINER (window), selection_button);
 
9906
  gtk_widget_show (selection_button);
 
9907
 
 
9908
  g_signal_connect (G_OBJECT (selection_button), "toggled",
 
9909
                    G_CALLBACK (selection_toggled), (gpointer) &amp;have_selection);
 
9910
  g_signal_connect (G_OBJECT (selection_widget), "selection_clear_event",
 
9911
                    G_CALLBACK (selection_clear), (gpointer) &amp;have_selection);
 
9912
 
 
9913
  gtk_selection_add_target (selection_widget,
 
9914
                            GDK_SELECTION_PRIMARY,
 
9915
                            GDK_SELECTION_TYPE_STRING,
 
9916
                            1);
 
9917
  g_signal_connect (G_OBJECT (selection_widget), "selection_get",
 
9918
                    G_CALLBACK (selection_handle), (gpointer) &amp;have_selection);
 
9919
 
 
9920
  gtk_widget_show (selection_button);
 
9921
  gtk_widget_show (window);
 
9922
  
 
9923
  gtk_main ();
 
9924
  
 
9925
  return 0;
 
9926
}
 
9927
<!-- example-end -->
 
9928
</programlisting>
 
9929
 
 
9930
</sect1>
 
9931
</chapter>
 
9932
 
 
9933
<!-- ***************************************************************** -->
 
9934
<chapter id="ch-DragAngDrop">
 
9935
<title>Drag-and-drop (DND)</title>
 
9936
 
 
9937
<para>GTK+ has a high level set of functions for doing inter-process
 
9938
communication via the drag-and-drop system. GTK+ can perform
 
9939
drag-and-drop on top of the low level Xdnd and Motif drag-and-drop
 
9940
protocols.</para>
 
9941
 
 
9942
<!-- ----------------------------------------------------------------- -->
 
9943
<sect1 id="sec-DragAndDropOverview">
 
9944
<title>Overview</title>
 
9945
 
 
9946
<para>An application capable of GTK+ drag-and-drop first defines and sets up
 
9947
the GTK+ widget(s) for drag-and-drop. Each widget can be a source
 
9948
and/or destination for drag-and-drop. Note that these GTK+ widgets must have
 
9949
an associated X Window, check using GTK_WIDGET_NO_WINDOW(widget)).</para>
 
9950
 
 
9951
<para>Source widgets can send out drag data, thus allowing the user to drag
 
9952
things off of them, while destination widgets can receive drag data.
 
9953
Drag-and-drop destinations can limit who they accept drag data from,
 
9954
e.g. the same application or any application (including itself).</para>
 
9955
 
 
9956
<para>Sending and receiving drop data makes use of GTK+ signals.
 
9957
Dropping an item to a destination widget requires both a data
 
9958
request (for the source widget) and data received signal handler (for
 
9959
the target widget). Additional signal handers can be connected if you
 
9960
want to know when a drag begins (at the very instant it starts), to
 
9961
when a drop is made, and when the entire drag-and-drop procedure has
 
9962
ended (successfully or not).</para>
 
9963
 
 
9964
<para>Your application will need to provide data for source widgets when
 
9965
requested, that involves having a drag data request signal handler. For
 
9966
destination widgets they will need a drop data received signal
 
9967
handler. </para>
 
9968
 
 
9969
<para>So a typical drag-and-drop cycle would look as follows:</para>
 
9970
<orderedlist>
 
9971
<listitem><simpara> Drag begins.</simpara>
 
9972
</listitem>
 
9973
<listitem><simpara> Drag data request (when a drop occurs).</simpara>
 
9974
</listitem>
 
9975
<listitem><simpara> Drop data received (may be on same or different
 
9976
application).</simpara>
 
9977
</listitem>
 
9978
<listitem><simpara> Drag data delete (if the drag was a move).</simpara>
 
9979
</listitem>
 
9980
<listitem><simpara> Drag-and-drop procedure done.</simpara>
 
9981
</listitem>
 
9982
</orderedlist>
 
9983
 
 
9984
<para>There are a few minor steps that go in between here and there, but we
 
9985
will get into detail about that later.</para>
 
9986
 
 
9987
</sect1>
 
9988
 
 
9989
<!-- ----------------------------------------------------------------- -->
 
9990
<sect1 id="sec-DragAndDropProperties">
 
9991
<title>Properties</title>
 
9992
 
 
9993
<para>Drag data has the following properties:</para>
 
9994
 
 
9995
<itemizedlist>
 
9996
<listitem><simpara> Drag action type (ie GDK_ACTION_COPY, GDK_ACTION_MOVE).</simpara>
 
9997
</listitem>
 
9998
 
 
9999
<listitem><simpara> Client specified arbitrary drag-and-drop type (a name and number pair).</simpara>
 
10000
</listitem>
 
10001
 
 
10002
<listitem><simpara> Sent and received data format type.</simpara>
 
10003
</listitem>
 
10004
</itemizedlist>
 
10005
 
 
10006
<para>Drag actions are quite obvious, they specify if the widget can
 
10007
drag with the specified action(s), e.g. GDK_ACTION_COPY and/or
 
10008
GDK_ACTION_MOVE. A GDK_ACTION_COPY would be a typical drag-and-drop
 
10009
without the source data being deleted while GDK_ACTION_MOVE would be
 
10010
just like GDK_ACTION_COPY but the source data will be 'suggested' to be
 
10011
deleted after the received signal handler is called. There are
 
10012
additional drag actions including GDK_ACTION_LINK which you may want to
 
10013
look into when you get to more advanced levels of drag-and-drop.</para>
 
10014
 
 
10015
<para>The client specified arbitrary drag-and-drop type is much more
 
10016
flexible, because your application will be defining and checking for
 
10017
that specifically. You will need to set up your destination widgets to
 
10018
receive certain drag-and-drop types by specifying a name and/or number.
 
10019
It would be more reliable to use a name since another application may
 
10020
just happen to use the same number for an entirely different
 
10021
meaning.</para>
 
10022
 
 
10023
<para>Sent and received data format types (<emphasis>selection
 
10024
target</emphasis>) come into play only in your request and received
 
10025
data handler functions. The term <emphasis>selection target</emphasis>
 
10026
is somewhat misleading. It is a term adapted from GTK+ selection
 
10027
(cut/copy and paste). What <emphasis>selection target</emphasis>
 
10028
actually means is the data's format type (i.e. GdkAtom, integer, or
 
10029
string) that being sent or received. Your request data handler function
 
10030
needs to specify the type (<emphasis>selection target</emphasis>) of
 
10031
data that it sends out and your received data handler needs to handle
 
10032
the type (<emphasis>selection target</emphasis>) of data
 
10033
received.</para>
 
10034
 
 
10035
</sect1>
 
10036
 
 
10037
<!-- ----------------------------------------------------------------- -->
 
10038
<sect1 id="sec-DragAndDropFunctions">
 
10039
<title>Functions</title>
 
10040
 
 
10041
<!-- ----------------------------------------------------------------- -->
 
10042
<sect2 id="sec-DNDSourceWidgets">
 
10043
<title>Setting up the source widget</title>
 
10044
 
 
10045
<para>The function <literal>gtk_drag_source_set()</literal> specifies a
 
10046
set of target types for a drag operation on a widget.</para>
 
10047
 
 
10048
<programlisting role="C">
 
10049
void gtk_drag_source_set( GtkWidget            *widget,
 
10050
                          GdkModifierType       start_button_mask,
 
10051
                          const GtkTargetEntry *targets,
 
10052
                          gint                  n_targets,
 
10053
                          GdkDragAction         actions );
 
10054
</programlisting>
 
10055
 
 
10056
<para>The parameters signify the following:</para>
 
10057
<itemizedlist>
 
10058
<listitem><simpara><literal>widget</literal> specifies the drag source
 
10059
widget</simpara>
 
10060
</listitem>
 
10061
<listitem><simpara><literal>start_button_mask</literal> specifies a
 
10062
bitmask of buttons that can start the drag (e.g. GDK_BUTTON1_MASK)</simpara>
 
10063
</listitem>
 
10064
<listitem><simpara><literal>targets</literal> specifies a table of
 
10065
target data types the drag will support</simpara>
 
10066
</listitem>
 
10067
<listitem><simpara><literal>n_targets</literal> specifies the number of
 
10068
targets above</simpara>
 
10069
</listitem>
 
10070
<listitem><simpara><literal>actions</literal> specifies a bitmask of
 
10071
possible actions for a drag from this window</simpara>
 
10072
</listitem>
 
10073
</itemizedlist>
 
10074
 
 
10075
<para>The <literal>targets</literal> parameter is an array of the
 
10076
following structure:</para>
 
10077
 
 
10078
<programlisting role="C">
 
10079
struct GtkTargetEntry {
 
10080
   gchar *target;
 
10081
   guint  flags;
 
10082
   guint  info;
 
10083
 };
 
10084
</programlisting>
 
10085
 
 
10086
<para>The fields specify a string representing the drag type, optional
 
10087
flags and application assigned integer identifier.</para>
 
10088
 
 
10089
<para>If a widget is no longer required to act as a source for
 
10090
drag-and-drop operations, the function
 
10091
<literal>gtk_drag_source_unset()</literal> can be used to remove a set
 
10092
of drag-and-drop target types.</para>
 
10093
 
 
10094
<programlisting role="C">
 
10095
void gtk_drag_source_unset( GtkWidget *widget );
 
10096
</programlisting>
 
10097
 
 
10098
</sect2>
 
10099
 
 
10100
<!-- ----------------------------------------------------------------- -->
 
10101
<sect2 id="sec-SignalsOnSourceWidgets">
 
10102
<title>Signals on the source widget:</title>
 
10103
 
 
10104
<para>The source widget is sent the following signals during a
 
10105
drag-and-drop operation.</para>
 
10106
 
 
10107
<table pgwide="1">
 
10108
<title>Source widget signals</title>
 
10109
<tgroup cols="2">
 
10110
<colspec colname="Name" colwidth="150">
 
10111
<colspec colname="Prototype">
 
10112
<tbody>
 
10113
<row>
 
10114
<entry align="left" valign="middle">drag_begin</entry>
 
10115
<entry align="left" valign="middle"><literal>void (*drag_begin)(GtkWidget *widget,
 
10116
GdkDragContext *dc, gpointer data)</literal></entry>
 
10117
</row>
 
10118
<row>
 
10119
<entry align="left" valign="middle">drag_motion</entry>
 
10120
<entry align="left" valign="middle"><literal>gboolean (*drag_motion)(GtkWidget *widget,
 
10121
GdkDragContext *dc, gint x, gint y, guint t, gpointer data)</literal></entry>
 
10122
</row>
 
10123
<row>
 
10124
<entry align="left" valign="middle">drag_data_get</entry>
 
10125
<entry align="left" valign="middle"><literal>void (*drag_data_get)(GtkWidget *widget,
 
10126
GdkDragContext *dc, GtkSelectionData *selection_data, guint info, guint t, gpointer data)</literal></entry>
 
10127
</row>
 
10128
<row>
 
10129
<entry align="left" valign="middle">drag_data_delete</entry>
 
10130
<entry align="left" valign="middle"><literal>void (*drag_data_delete)(GtkWidget *widget,
 
10131
GdkDragContext *dc, gpointer data)</literal></entry>
 
10132
</row>
 
10133
<row>
 
10134
<entry align="left" valign="middle">drag_drop</entry>
 
10135
<entry align="left" valign="middle"><literal>gboolean (*drag_drop)(GtkWidget *widget,
 
10136
GdkDragContext *dc, gint x, gint y, guint t, gpointer data)</literal></entry>
 
10137
</row>
 
10138
<row>
 
10139
<entry align="left" valign="middle">drag_end</entry>
 
10140
<entry align="left" valign="middle"><literal>void (*drag_end)(GtkWidget *widget,
 
10141
GdkDragContext *dc, gpointer data)</literal></entry>
 
10142
</row>
 
10143
</tbody>
 
10144
</tgroup>
 
10145
</table>
 
10146
 
 
10147
</sect2>
 
10148
 
 
10149
<!-- ----------------------------------------------------------------- -->
 
10150
<sect2 id="sec-DNDDestWidgets">
 
10151
<title>Setting up a destination widget:</title>
 
10152
 
 
10153
<para> <literal> gtk_drag_dest_set()</literal> specifies
 
10154
that this widget can receive drops and specifies what types of drops it
 
10155
can receive.</para>
 
10156
 
 
10157
<para> <literal> gtk_drag_dest_unset()</literal> specifies
 
10158
that the widget can no longer receive drops.</para>
 
10159
 
 
10160
<programlisting role="C">
 
10161
void gtk_drag_dest_set( GtkWidget            *widget,
 
10162
                        GtkDestDefaults       flags,
 
10163
                        const GtkTargetEntry *targets,
 
10164
                        gint                  n_targets,
 
10165
                        GdkDragAction         actions );
 
10166
 
 
10167
void gtk_drag_dest_unset( GtkWidget *widget );
 
10168
</programlisting>
 
10169
 
 
10170
</sect2>
 
10171
 
 
10172
<!-- ----------------------------------------------------------------- -->
 
10173
<sect2 id="sec-SignalsOnDestWidgets">
 
10174
<title>Signals on the destination widget:</title>
 
10175
 
 
10176
<para>The destination widget is sent the following signals during a
 
10177
drag-and-drop operation.</para>
 
10178
 
 
10179
<table pgwide="1">
 
10180
<title>Destination widget signals</title>
 
10181
<tgroup cols="2">
 
10182
<colspec colname="Name" colwidth="150">
 
10183
<colspec colname="Prototype">
 
10184
<tbody>
 
10185
<row>
 
10186
<entry align="left" valign="middle">drag_data_received</entry>
 
10187
<entry align="left" valign="middle"><literal>void (*drag_data_received)(GtkWidget *widget,
 
10188
GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t,
 
10189
gpointer data)</literal></entry>
 
10190
</row>
 
10191
</tbody>
 
10192
</tgroup>
 
10193
</table>
 
10194
 
 
10195
</sect2>
 
10196
</sect1>
 
10197
</chapter>
 
10198
 
 
10199
<!-- ***************************************************************** -->
 
10200
<chapter id="ch-GLib">
 
10201
<title>GLib</title>
 
10202
 
 
10203
<para>GLib is a lower-level library that provides many useful definitions
 
10204
and functions available for use when creating GDK and GTK
 
10205
applications. These include definitions for basic types and their
 
10206
limits, standard macros, type conversions, byte order, memory
 
10207
allocation, warnings and assertions, message logging, timers, string
 
10208
utilities, hook functions, a lexical scanner, dynamic loading of
 
10209
modules, and automatic string completion. A number of data structures
 
10210
(and their related operations) are also defined, including memory
 
10211
chunks, doubly-linked lists, singly-linked lists, hash tables, strings
 
10212
(which can grow dynamically), string chunks (groups of strings),
 
10213
arrays (which can grow in size as elements are added), balanced binary
 
10214
trees, N-ary trees, quarks (a two-way association of a string and a
 
10215
unique integer identifier), keyed data lists (lists of data elements
 
10216
accessible by a string or integer id), relations and tuples (tables of
 
10217
data which can be indexed on any number of fields), and caches.</para>
 
10218
 
 
10219
<para>A summary of some of GLib's capabilities follows; not every function,
 
10220
data structure, or operation is covered here.  For more complete
 
10221
information about the GLib routines, see the GLib documentation. One
 
10222
source of GLib documentation is <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>.</para>
 
10223
 
 
10224
<para>If you are using a language other than C, you should consult your
 
10225
language's binding documentation. In some cases your language may
 
10226
have equivalent functionality built-in, while in other cases it may
 
10227
not.</para>
 
10228
 
 
10229
<!-- ----------------------------------------------------------------- -->
 
10230
<sect1 id="sec-Definitions">
 
10231
<title>Definitions</title>
 
10232
 
 
10233
<para>Definitions for the extremes of many of the standard types are:</para>
 
10234
 
 
10235
<programlisting role="C">
 
10236
G_MINFLOAT
 
10237
G_MAXFLOAT
 
10238
G_MINDOUBLE
 
10239
G_MAXDOUBLE
 
10240
G_MINSHORT
 
10241
G_MAXSHORT
 
10242
G_MAXUSHORT
 
10243
G_MININT
 
10244
G_MAXINT
 
10245
G_MAXUINT
 
10246
G_MINLONG
 
10247
G_MAXLONG
 
10248
G_MAXULONG
 
10249
G_MININT64
 
10250
G_MAXINT64
 
10251
G_MAXUINT64
 
10252
</programlisting>
 
10253
 
 
10254
<para>Also, the following typedefs. The ones left unspecified are dynamically set
 
10255
depending on the architecture. Remember to avoid counting on the size of a
 
10256
pointer if you want to be portable! E.g., a pointer on an Alpha is 8
 
10257
bytes, but 4 on Intel 80x86 family CPUs.</para>
 
10258
 
 
10259
<programlisting role="C">
 
10260
char   gchar;
 
10261
short  gshort;
 
10262
long   glong;
 
10263
int    gint;
 
10264
int    gboolean;
 
10265
 
 
10266
unsigned char   guchar;
 
10267
unsigned short  gushort;
 
10268
unsigned long   gulong;
 
10269
unsigned int    guint;
 
10270
 
 
10271
float   gfloat;
 
10272
double  gdouble;
 
10273
 
 
10274
unsigned int  gsize;
 
10275
signed int    gssize;
 
10276
 
 
10277
void*       gpointer;
 
10278
const void* gconstpointer;
 
10279
 
 
10280
gint8
 
10281
guint8
 
10282
gint16
 
10283
guint16
 
10284
gint32
 
10285
guint32
 
10286
gint64
 
10287
guint64
 
10288
</programlisting>
 
10289
 
 
10290
</sect1>
 
10291
 
 
10292
<!-- ----------------------------------------------------------------- -->
 
10293
<sect1 id="sec-DoublyLinkedLists">
 
10294
<title>Doubly Linked Lists</title>
 
10295
 
 
10296
<para>The following functions are used to create, manage, and destroy
 
10297
standard doubly linked lists. Each element in the list contains a
 
10298
piece of data, together with pointers which link to the previous and
 
10299
next elements in the list. This enables easy movement in either
 
10300
direction through the list. The data item is of type "gpointer",
 
10301
which means the data can be a pointer to your real data or (through
 
10302
casting) a numeric value (but do not assume that int and gpointer have
 
10303
the same size!). These routines internally allocate list elements in
 
10304
blocks, which is more efficient than allocating elements individually.</para>
 
10305
 
 
10306
<para>There is no function to specifically create a list. Instead, simply
 
10307
create a variable of type GList* and set its value to NULL; NULL is
 
10308
considered to be the empty list.</para>
 
10309
 
 
10310
<para>To add elements to a list, use the g_list_append(), g_list_prepend(),
 
10311
g_list_insert(), or g_list_insert_sorted() routines. In all cases
 
10312
they accept a pointer to the beginning of the list, and return the
 
10313
(possibly changed) pointer to the beginning of the list. Thus, for
 
10314
all of the operations that add or remove elements, be sure to save the
 
10315
returned value!</para>
 
10316
 
 
10317
<programlisting role="C">
 
10318
GList *g_list_append( GList    *list,
 
10319
                      gpointer  data );
 
10320
</programlisting>
 
10321
 
 
10322
<para>This adds a new element (with value <literal>data</literal>) onto the end of the
 
10323
list.</para>
 
10324
  
 
10325
<programlisting role="C">
 
10326
GList *g_list_prepend( GList    *list,
 
10327
                       gpointer  data );
 
10328
</programlisting>
 
10329
 
 
10330
<para>This adds a new element (with value <literal>data</literal>) to the beginning of the
 
10331
list.</para>
 
10332
 
 
10333
<programlisting role="C">
 
10334
GList *g_list_insert( GList    *list,
 
10335
                      gpointer  data,
 
10336
                      gint      position );
 
10337
</programlisting>
 
10338
 
 
10339
<para>This inserts a new element (with value data) into the list at the
 
10340
given position. If position is 0, this is just like g_list_prepend();
 
10341
if position is less than 0, this is just like g_list_append().</para>
 
10342
 
 
10343
<programlisting role="C">
 
10344
GList *g_list_remove( GList    *list,
 
10345
                      gpointer  data );
 
10346
</programlisting>
 
10347
 
 
10348
<para>This removes the element in the list with the value <literal>data</literal>;
 
10349
if the element isn't there, the list is unchanged.</para>
 
10350
 
 
10351
<programlisting role="C">
 
10352
void g_list_free( GList *list );
 
10353
</programlisting>
 
10354
 
 
10355
<para>This frees all of the memory used by a GList. If the list elements
 
10356
refer to dynamically-allocated memory, then they should be freed
 
10357
first.</para>
 
10358
 
 
10359
<para>There are many other GLib functions that support doubly linked lists;
 
10360
see the glib documentation for more information.  Here are a few of
 
10361
the more useful functions' signatures:</para>
 
10362
 
 
10363
<programlisting role="C">  
 
10364
GList *g_list_remove_link( GList *list,
 
10365
                           GList *link );
 
10366
 
 
10367
GList *g_list_reverse( GList *list );
 
10368
 
 
10369
GList *g_list_nth( GList *list,
 
10370
                   gint   n );
 
10371
                           
 
10372
GList *g_list_find( GList    *list,
 
10373
                    gpointer  data );
 
10374
 
 
10375
GList *g_list_last( GList *list );
 
10376
 
 
10377
GList *g_list_first( GList *list );
 
10378
 
 
10379
gint g_list_length( GList *list );
 
10380
 
 
10381
void g_list_foreach( GList    *list,
 
10382
                     GFunc     func,
 
10383
                     gpointer  user_data );
 
10384
</programlisting>
 
10385
 
 
10386
</sect1>
 
10387
 
 
10388
<!-- ----------------------------------------------------------------- -->
 
10389
<sect1 id="sec-SinglyLinkedLists">
 
10390
<title>Singly Linked Lists</title>
 
10391
 
 
10392
<para>Many of the above functions for singly linked lists are identical to the
 
10393
above. Here is a list of some of their operations:</para>
 
10394
 
 
10395
<programlisting role="C">
 
10396
GSList *g_slist_append( GSList   *list,
 
10397
                        gpointer  data );
 
10398
                
 
10399
GSList *g_slist_prepend( GSList   *list,
 
10400
                         gpointer  data );
 
10401
                             
 
10402
GSList *g_slist_insert( GSList   *list,
 
10403
                        gpointer  data,
 
10404
                        gint      position );
 
10405
                             
 
10406
GSList *g_slist_remove( GSList   *list,
 
10407
                        gpointer  data );
 
10408
                             
 
10409
GSList *g_slist_remove_link( GSList *list,
 
10410
                             GSList *link );
 
10411
                             
 
10412
GSList *g_slist_reverse( GSList *list );
 
10413
 
 
10414
GSList *g_slist_nth( GSList *list,
 
10415
                     gint    n );
 
10416
                             
 
10417
GSList *g_slist_find( GSList   *list,
 
10418
                      gpointer  data );
 
10419
                             
 
10420
GSList *g_slist_last( GSList *list );
 
10421
 
 
10422
gint g_slist_length( GSList *list );
 
10423
 
 
10424
void g_slist_foreach( GSList   *list,
 
10425
                      GFunc     func,
 
10426
                      gpointer  user_data );
 
10427
        
 
10428
</programlisting>
 
10429
 
 
10430
</sect1>
 
10431
 
 
10432
<!-- ----------------------------------------------------------------- -->
 
10433
<sect1 id="sec-MemoryManagement">
 
10434
<title>Memory Management</title>
 
10435
 
 
10436
<programlisting role="C">
 
10437
gpointer g_malloc( gulong size );
 
10438
</programlisting>
 
10439
 
 
10440
<para>This is a replacement for malloc(). You do not need to check the return
 
10441
value as it is done for you in this function. If the memory allocation
 
10442
fails for whatever reasons, your applications will be terminated.</para>
 
10443
 
 
10444
<programlisting role="C">
 
10445
gpointer g_malloc0( gulong size );
 
10446
</programlisting>
 
10447
 
 
10448
<para>Same as above, but zeroes the memory before returning a pointer to it.</para>
 
10449
 
 
10450
<programlisting role="C">
 
10451
gpointer g_realloc( gpointer mem,
 
10452
                    gulong   size );
 
10453
</programlisting>
 
10454
 
 
10455
<para>Relocates "size" bytes of memory starting at "mem".  Obviously, the
 
10456
memory should have been previously allocated.</para>
 
10457
 
 
10458
<programlisting role="C">
 
10459
void g_free( gpointer mem );
 
10460
</programlisting>
 
10461
 
 
10462
<para>Frees memory. Easy one. If <literal>mem</literal> is NULL it simply returns.</para>
 
10463
 
 
10464
<programlisting role="C">
 
10465
void g_mem_profile( void );
 
10466
</programlisting>
 
10467
 
 
10468
<para>Dumps a profile of used memory, but requires that you add <literal>#define
 
10469
MEM_PROFILE</literal> to the top of glib/gmem.c and re-make and make install.</para>
 
10470
 
 
10471
<programlisting role="C">
 
10472
void g_mem_check( gpointer mem );
 
10473
</programlisting>
 
10474
 
 
10475
<para>Checks that a memory location is valid. Requires you add <literal>#define
 
10476
MEM_CHECK</literal> to the top of gmem.c and re-make and make install.</para>
 
10477
 
 
10478
</sect1>
 
10479
 
 
10480
<!-- ----------------------------------------------------------------- -->
 
10481
<sect1 id="sec-Timers">
 
10482
<title>Timers</title>
 
10483
 
 
10484
<para>Timer functions can be used to time operations (e.g., to see how much
 
10485
time has elapsed). First, you create a new timer with g_timer_new().
 
10486
You can then use g_timer_start() to start timing an operation,
 
10487
g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
 
10488
determine the elapsed time.</para>
 
10489
 
 
10490
<programlisting role="C">
 
10491
GTimer *g_timer_new( void );
 
10492
 
 
10493
void g_timer_destroy( GTimer *timer );
 
10494
 
 
10495
void g_timer_start( GTimer  *timer );
 
10496
 
 
10497
void g_timer_stop( GTimer  *timer );
 
10498
 
 
10499
void g_timer_reset( GTimer  *timer );
 
10500
 
 
10501
gdouble g_timer_elapsed( GTimer *timer,
 
10502
                         gulong *microseconds );
 
10503
</programlisting>
 
10504
 
 
10505
</sect1>
 
10506
 
 
10507
<!-- ----------------------------------------------------------------- -->
 
10508
<sect1 id="sec-StringHandling">
 
10509
<title>String Handling</title>
 
10510
 
 
10511
<para>GLib defines a new type called a GString, which is similar to a
 
10512
standard C string but one that grows automatically. Its string data
 
10513
is null-terminated. What this gives you is protection from buffer
 
10514
overflow programming errors within your program. This is a very
 
10515
important feature, and hence I recommend that you make use of
 
10516
GStrings. GString itself has a simple public definition:</para>
 
10517
 
 
10518
<programlisting role="C">
 
10519
struct GString 
 
10520
{
 
10521
  gchar *str; /* Points to the string's current \0-terminated value. */
 
10522
  gint len; /* Current length */
 
10523
};
 
10524
</programlisting>
 
10525
 
 
10526
<para>As you might expect, there are a number of operations you can do with
 
10527
a GString.</para>
 
10528
 
 
10529
<programlisting role="C">
 
10530
GString *g_string_new( gchar *init );
 
10531
</programlisting>
 
10532
 
 
10533
<para>This constructs a GString, copying the string value of <literal>init</literal>
 
10534
into the GString and returning a pointer to it. NULL may be given as
 
10535
the argument for an initially empty GString.</para>
 
10536
 
 
10537
<programlisting role="C">
 
10538
void g_string_free( GString *string,
 
10539
                    gint     free_segment );
 
10540
</programlisting>
 
10541
 
 
10542
<para>This frees the memory for the given GString. If <literal>free_segment</literal> is
 
10543
TRUE, then this also frees its character data.</para>
 
10544
 
 
10545
<programlisting role="C">            
 
10546
GString *g_string_assign( GString     *lval,
 
10547
                          const gchar *rval );
 
10548
</programlisting>
 
10549
 
 
10550
<para>This copies the characters from rval into lval, destroying the
 
10551
previous contents of lval. Note that lval will be lengthened as
 
10552
necessary to hold the string's contents, unlike the standard strcpy()
 
10553
function.</para>
 
10554
 
 
10555
<para>The rest of these functions should be relatively obvious (the _c
 
10556
versions accept a character instead of a string):</para>
 
10557
             
 
10558
<programlisting role="C">            
 
10559
GString *g_string_truncate( GString *string,
 
10560
                            gint     len );
 
10561
                             
 
10562
GString *g_string_append( GString *string,
 
10563
                          gchar   *val );
 
10564
                            
 
10565
GString *g_string_append_c( GString *string,
 
10566
                            gchar    c );
 
10567
        
 
10568
GString *g_string_prepend( GString *string,
 
10569
                           gchar   *val );
 
10570
                             
 
10571
GString *g_string_prepend_c( GString *string,
 
10572
                             gchar    c );
 
10573
        
 
10574
void g_string_sprintf( GString *string,
 
10575
                       gchar   *fmt,
 
10576
                       ...);
 
10577
        
 
10578
void g_string_sprintfa ( GString *string,
 
10579
                         gchar   *fmt,
 
10580
                         ... );
 
10581
</programlisting>
 
10582
 
 
10583
</sect1>
 
10584
 
 
10585
<!-- ----------------------------------------------------------------- -->
 
10586
<sect1 id="sec-UtilityAndErrorFunctions">
 
10587
<title>Utility and Error Functions</title>
 
10588
 
 
10589
<programlisting role="C">
 
10590
gchar *g_strdup( const gchar *str );
 
10591
</programlisting>
 
10592
 
 
10593
<para>Replacement strdup function.  Copies the original strings contents to
 
10594
newly allocated memory, and returns a pointer to it.</para>
 
10595
 
 
10596
<programlisting role="C">
 
10597
gchar *g_strerror( gint errnum );
 
10598
</programlisting>
 
10599
 
 
10600
<para>I recommend using this for all error messages.  It's much nicer, and more
 
10601
portable than perror() or others.  The output is usually of the form:</para>
 
10602
 
 
10603
<programlisting role="C">
 
10604
program name:function that failed:file or further description:strerror
 
10605
</programlisting>
 
10606
 
 
10607
<para>Here's an example of one such call used in our hello_world program:</para>
 
10608
 
 
10609
<programlisting role="C">
 
10610
g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
 
10611
</programlisting>
 
10612
 
 
10613
<programlisting role="C">
 
10614
void g_error( gchar *format, ... );
 
10615
</programlisting>
 
10616
 
 
10617
<para>Prints an error message. The format is just like printf, but it
 
10618
prepends "** ERROR **: " to your message, and exits the program.  
 
10619
Use only for fatal errors.</para>
 
10620
 
 
10621
<programlisting role="C">
 
10622
void g_warning( gchar *format, ... );
 
10623
</programlisting>
 
10624
 
 
10625
<para>Same as above, but prepends "** WARNING **: ", and does not exit the
 
10626
program.</para>
 
10627
 
 
10628
<programlisting role="C">
 
10629
void g_message( gchar *format, ... );
 
10630
</programlisting>
 
10631
 
 
10632
<para>Prints "message: " prepended to the string you pass in.</para>
 
10633
 
 
10634
<programlisting role="C">
 
10635
void g_print( gchar *format, ... );
 
10636
</programlisting>
 
10637
 
 
10638
<para>Replacement for printf().</para>
 
10639
 
 
10640
<para>And our last function:</para>
 
10641
 
 
10642
<programlisting role="C">
 
10643
gchar *g_strsignal( gint signum );
 
10644
</programlisting>
 
10645
 
 
10646
<para>Prints out the name of the Unix system signal given the signal number.
 
10647
Useful in generic signal handling functions.</para>
 
10648
 
 
10649
<para>All of the above are more or less just stolen from glib.h.  If anyone cares
 
10650
to document any function, just send me an email!</para>
 
10651
 
 
10652
</sect1>
 
10653
</chapter>
 
10654
 
 
10655
<!-- ***************************************************************** -->
 
10656
<chapter id="ch-GTKRCFiles">
 
10657
<title>GTK's rc Files</title>
 
10658
 
 
10659
<para>GTK has its own way of dealing with application defaults, by using rc
 
10660
files. These can be used to set the colors of just about any widget, and
 
10661
can also be used to tile pixmaps onto the background of some widgets.  </para>
 
10662
 
 
10663
<!-- ----------------------------------------------------------------- -->
 
10664
<sect1 id="sec-FunctionsForRCFiles">
 
10665
<title>Functions For rc Files</title>
 
10666
 
 
10667
<para>When your application starts, you should include a call to:</para>
 
10668
 
 
10669
<programlisting role="C">
 
10670
void gtk_rc_parse( char *filename );
 
10671
</programlisting>
 
10672
 
 
10673
<para>Passing in the filename of your rc file. This will cause GTK to parse
 
10674
this file, and use the style settings for the widget types defined
 
10675
there.</para>
 
10676
 
 
10677
<para>If you wish to have a special set of widgets that can take on a
 
10678
different style from others, or any other logical division of widgets,
 
10679
use a call to:</para>
 
10680
 
 
10681
<programlisting role="C">
 
10682
void gtk_widget_set_name( GtkWidget *widget,
 
10683
                          gchar     *name );
 
10684
</programlisting>
 
10685
 
 
10686
<para>Passing your newly created widget as the first argument, and the name
 
10687
you wish to give it as the second. This will allow you to change the
 
10688
attributes of this widget by name through the rc file.</para>
 
10689
 
 
10690
<para>If we use a call something like this:</para>
 
10691
 
 
10692
<programlisting role="C">
 
10693
button = gtk_button_new_with_label ("Special Button");
 
10694
gtk_widget_set_name (button, "special button");
 
10695
</programlisting>
 
10696
 
 
10697
<para>Then this button is given the name "special button" and may be addressed by
 
10698
name in the rc file as "special button.GtkButton".  [<--- Verify ME!]</para>
 
10699
 
 
10700
<para>The example rc file below, sets the properties of the main window, and lets
 
10701
all children of that main window inherit the style described by the "main
 
10702
button" style.  The code used in the application is:</para>
 
10703
 
 
10704
<programlisting role="C">
 
10705
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
10706
gtk_widget_set_name (window, "main window");
 
10707
</programlisting>
 
10708
 
 
10709
<para>And then the style is defined in the rc file using:</para>
 
10710
 
 
10711
<programlisting role="C">
 
10712
widget "main window.*GtkButton*" style "main_button"
 
10713
</programlisting>
 
10714
 
 
10715
<para>Which sets all the Button widgets in the "main window" to the
 
10716
"main_buttons" style as defined in the rc file.</para>
 
10717
 
 
10718
<para>As you can see, this is a fairly powerful and flexible system.  Use your
 
10719
imagination as to how best to take advantage of this.</para>
 
10720
 
 
10721
</sect1>
 
10722
 
 
10723
<!-- ----------------------------------------------------------------- -->
 
10724
<sect1 id="sec-GTKsRCFileFormat">
 
10725
<title>GTK's rc File Format</title>
 
10726
 
 
10727
<para>The format of the GTK file is illustrated in the example below. This is
 
10728
the testgtkrc file from the GTK distribution, but I've added a
 
10729
few comments and things. You may wish to include this explanation in
 
10730
your application to allow the user to fine tune his application.</para>
 
10731
 
 
10732
<para>There are several directives to change the attributes of a widget.</para>
 
10733
 
 
10734
<itemizedlist>
 
10735
<listitem><simpara>fg - Sets the foreground color of a widget.</simpara>
 
10736
</listitem>
 
10737
<listitem><simpara>bg - Sets the background color of a widget.</simpara>
 
10738
</listitem>
 
10739
<listitem><simpara>bg_pixmap - Sets the background of a widget to a tiled pixmap.</simpara>
 
10740
</listitem>
 
10741
<listitem><simpara>font - Sets the font to be used with the given widget.</simpara>
 
10742
</listitem>
 
10743
</itemizedlist>
 
10744
 
 
10745
<para>In addition to this, there are several states a widget can be in, and you
 
10746
can set different colors, pixmaps and fonts for each state. These states are:</para>
 
10747
 
 
10748
<itemizedlist>
 
10749
<listitem><simpara>NORMAL - The normal state of a widget, without the mouse over top of
 
10750
it, and not being pressed, etc.</simpara>
 
10751
</listitem>
 
10752
<listitem><simpara>PRELIGHT - When the mouse is over top of the widget, colors defined
 
10753
using this state will be in effect.</simpara>
 
10754
</listitem>
 
10755
<listitem><simpara>ACTIVE - When the widget is pressed or clicked it will be active, and
 
10756
the attributes assigned by this tag will be in effect.</simpara>
 
10757
</listitem>
 
10758
<listitem><simpara>INSENSITIVE - When a widget is set insensitive, and cannot be
 
10759
activated, it will take these attributes.</simpara>
 
10760
</listitem>
 
10761
<listitem><simpara>SELECTED - When an object is selected, it takes these attributes.</simpara>
 
10762
</listitem>
 
10763
</itemizedlist>
 
10764
 
 
10765
<para>When using the "fg" and "bg" keywords to set the colors of widgets, the
 
10766
format is:</para>
 
10767
 
 
10768
<programlisting role="C">
 
10769
fg[&lt;STATE>] = { Red, Green, Blue }
 
10770
</programlisting>
 
10771
 
 
10772
<para>Where STATE is one of the above states (PRELIGHT, ACTIVE, etc), and the Red,
 
10773
Green and Blue are values in the range of 0 - 1.0,  { 1.0, 1.0, 1.0 } being
 
10774
white. They must be in float form, or they will register as 0, so a straight 
 
10775
"1" will not work, it must be "1.0".  A straight "0" is fine because it 
 
10776
doesn't matter if it's not recognized.  Unrecognized values are set to 0.</para>
 
10777
 
 
10778
<para>bg_pixmap is very similar to the above, except the colors are replaced by a
 
10779
filename.</para>
 
10780
 
 
10781
<para>pixmap_path is a list of paths separated by ":"'s.  These paths will be
 
10782
searched for any pixmap you specify.</para>
 
10783
 
 
10784
<para>The font directive is simply:</para>
 
10785
 
 
10786
<programlisting role="C">
 
10787
font = "&lt;font name>"
 
10788
</programlisting>
 
10789
 
 
10790
<para>The only hard part is figuring out the font string. Using xfontsel or
 
10791
a similar utility should help.</para>
 
10792
 
 
10793
<para>The "widget_class" sets the style of a class of widgets. These classes are
 
10794
listed in the widget overview on the class hierarchy.</para>
 
10795
 
 
10796
<para>The "widget" directive sets a specifically named set of widgets to a
 
10797
given style, overriding any style set for the given widget class.
 
10798
These widgets are registered inside the application using the
 
10799
gtk_widget_set_name() call. This allows you to specify the attributes of a
 
10800
widget on a per widget basis, rather than setting the attributes of an
 
10801
entire widget class. I urge you to document any of these special widgets so
 
10802
users may customize them.</para>
 
10803
 
 
10804
<para>When the keyword <literal>parent</> is used as an attribute, the widget will take on
 
10805
the attributes of its parent in the application.</para>
 
10806
 
 
10807
<para>When defining a style, you may assign the attributes of a previously defined
 
10808
style to this new one.</para>
 
10809
 
 
10810
<programlisting role="C">
 
10811
style "main_button" = "button"
 
10812
{
 
10813
  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
 
10814
  bg[PRELIGHT] = { 0.75, 0, 0 }
 
10815
}
 
10816
</programlisting>
 
10817
 
 
10818
<para>This example takes the "button" style, and creates a new "main_button" style
 
10819
simply by changing the font and prelight background color of the "button"
 
10820
style.</para>
 
10821
 
 
10822
<para>Of course, many of these attributes don't apply to all widgets. It's a
 
10823
simple matter of common sense really. Anything that could apply, should.</para>
 
10824
 
 
10825
</sect1>
 
10826
 
 
10827
<!-- ----------------------------------------------------------------- -->
 
10828
<sect1 id="sec-ExampleRCFile">
 
10829
<title>Example rc file</title>
 
10830
 
 
10831
<programlisting role="C">
 
10832
# pixmap_path "&lt;dir 1>:&lt;dir 2>:&lt;dir 3>:..."
 
10833
#
 
10834
pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
 
10835
#
 
10836
# style &lt;name> [= &lt;name>]
 
10837
# {
 
10838
#   &lt;option>
 
10839
# }
 
10840
#
 
10841
# widget &lt;widget_set> style &lt;style_name>
 
10842
# widget_class &lt;widget_class_set> style &lt;style_name>
 
10843
 
 
10844
# Here is a list of all the possible states.  Note that some do not apply to
 
10845
# certain widgets.
 
10846
#
 
10847
# NORMAL - The normal state of a widget, without the mouse over top of
 
10848
# it, and not being pressed, etc.
 
10849
#
 
10850
# PRELIGHT - When the mouse is over top of the widget, colors defined
 
10851
# using this state will be in effect.
 
10852
#
 
10853
# ACTIVE - When the widget is pressed or clicked it will be active, and
 
10854
# the attributes assigned by this tag will be in effect.
 
10855
#
 
10856
# INSENSITIVE - When a widget is set insensitive, and cannot be
 
10857
# activated, it will take these attributes.
 
10858
#
 
10859
# SELECTED - When an object is selected, it takes these attributes.
 
10860
#
 
10861
# Given these states, we can set the attributes of the widgets in each of
 
10862
# these states using the following directives.
 
10863
#
 
10864
# fg - Sets the foreground color of a widget.
 
10865
# fg - Sets the background color of a widget.
 
10866
# bg_pixmap - Sets the background of a widget to a tiled pixmap.
 
10867
# font - Sets the font to be used with the given widget.
 
10868
#
 
10869
 
 
10870
# This sets a style called "button".  The name is not really important, as
 
10871
# it is assigned to the actual widgets at the bottom of the file.
 
10872
 
 
10873
style "window"
 
10874
{
 
10875
  #This sets the padding around the window to the pixmap specified.
 
10876
  #bg_pixmap[&lt;STATE>] = "&lt;pixmap filename>"
 
10877
  bg_pixmap[NORMAL] = "warning.xpm"
 
10878
}
 
10879
 
 
10880
style "scale"
 
10881
{
 
10882
  #Sets the foreground color (font color) to red when in the "NORMAL"
 
10883
  #state.
 
10884
  
 
10885
  fg[NORMAL] = { 1.0, 0, 0 }
 
10886
  
 
10887
  #Sets the background pixmap of this widget to that of its parent.
 
10888
  bg_pixmap[NORMAL] = "&lt;parent>"
 
10889
}
 
10890
 
 
10891
style "button"
 
10892
{
 
10893
  # This shows all the possible states for a button.  The only one that
 
10894
  # doesn't apply is the SELECTED state.
 
10895
  
 
10896
  fg[PRELIGHT] = { 0, 1.0, 1.0 }
 
10897
  bg[PRELIGHT] = { 0, 0, 1.0 }
 
10898
  bg[ACTIVE] = { 1.0, 0, 0 }
 
10899
  fg[ACTIVE] = { 0, 1.0, 0 }
 
10900
  bg[NORMAL] = { 1.0, 1.0, 0 }
 
10901
  fg[NORMAL] = { .99, 0, .99 }
 
10902
  bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
 
10903
  fg[INSENSITIVE] = { 1.0, 0, 1.0 }
 
10904
}
 
10905
 
 
10906
# In this example, we inherit the attributes of the "button" style and then
 
10907
# override the font and background color when prelit to create a new
 
10908
# "main_button" style.
 
10909
 
 
10910
style "main_button" = "button"
 
10911
{
 
10912
  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
 
10913
  bg[PRELIGHT] = { 0.75, 0, 0 }
 
10914
}
 
10915
 
 
10916
style "toggle_button" = "button"
 
10917
{
 
10918
  fg[NORMAL] = { 1.0, 0, 0 }
 
10919
  fg[ACTIVE] = { 1.0, 0, 0 }
 
10920
  
 
10921
  # This sets the background pixmap of the toggle_button to that of its
 
10922
  # parent widget (as defined in the application).
 
10923
  bg_pixmap[NORMAL] = "&lt;parent>"
 
10924
}
 
10925
 
 
10926
style "text"
 
10927
{
 
10928
  bg_pixmap[NORMAL] = "marble.xpm"
 
10929
  fg[NORMAL] = { 1.0, 1.0, 1.0 }
 
10930
}
 
10931
 
 
10932
style "ruler"
 
10933
{
 
10934
  font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
 
10935
}
 
10936
 
 
10937
# pixmap_path "~/.pixmaps"
 
10938
 
 
10939
# These set the widget types to use the styles defined above.
 
10940
# The widget types are listed in the class hierarchy, but could probably be
 
10941
# just listed in this document for the users reference.
 
10942
 
 
10943
widget_class "GtkWindow" style "window"
 
10944
widget_class "GtkDialog" style "window"
 
10945
widget_class "GtkFileSelection" style "window"
 
10946
widget_class "*Gtk*Scale" style "scale"
 
10947
widget_class "*GtkCheckButton*" style "toggle_button"
 
10948
widget_class "*GtkRadioButton*" style "toggle_button"
 
10949
widget_class "*GtkButton*" style "button"
 
10950
widget_class "*Ruler" style "ruler"
 
10951
widget_class "*GtkText" style "text"
 
10952
 
 
10953
# This sets all the buttons that are children of the "main window" to
 
10954
# the main_button style.  These must be documented to be taken advantage of.
 
10955
widget "main window.*GtkButton*" style "main_button"
 
10956
</programlisting>
 
10957
 
 
10958
</sect1>
 
10959
</chapter>
 
10960
 
 
10961
<!-- ***************************************************************** -->
 
10962
<chapter id="ch-WritingYourOwnWidgets">
 
10963
<title>Writing Your Own Widgets</title>
 
10964
 
 
10965
<!-- ----------------------------------------------------------------- -->
 
10966
<sect1 id="sec-WidgetsOverview">
 
10967
<title>Overview</title>
 
10968
 
 
10969
<para>Although the GTK distribution comes with many types of widgets that
 
10970
should cover most basic needs, there may come a time when you need to
 
10971
create your own new widget type. Since GTK uses widget inheritance
 
10972
extensively, and there is already a widget that is close to what you want,
 
10973
it is often possible to make a useful new widget type in
 
10974
just a few lines of code. But before starting work on a new widget, check
 
10975
around first to make sure that someone has not already written
 
10976
it. This will prevent duplication of effort and keep the number of
 
10977
GTK widgets out there to a minimum, which will help keep both the code
 
10978
and the interface of different applications consistent. As a flip side
 
10979
to this, once you finish your widget, announce it to the world so
 
10980
other people can benefit. The best place to do this is probably the
 
10981
<literal>gtk-list</literal>.</para>
 
10982
 
 
10983
<para>Complete sources for the example widgets are available at the place you 
 
10984
got this tutorial, or from:</para>
 
10985
 
 
10986
<para><ulink url="http://www.gtk.org/~otaylor/gtk/tutorial/">http://www.gtk.org/~otaylor/gtk/tutorial/</ulink></para>
 
10987
 
 
10988
 
 
10989
</sect1>
 
10990
 
 
10991
<!-- ----------------------------------------------------------------- -->
 
10992
<sect1 id="sec-TheAnatomyOfAWidget">
 
10993
<title>The Anatomy Of A Widget</title>
 
10994
 
 
10995
<para>In order to create a new widget, it is important to have an
 
10996
understanding of how GTK objects work. This section is just meant as a
 
10997
brief overview. See the reference documentation for the details. </para>
 
10998
 
 
10999
<para>GTK widgets are implemented in an object oriented fashion. However,
 
11000
they are implemented in standard C. This greatly improves portability
 
11001
and stability over using current generation C++ compilers; however,
 
11002
it does mean that the widget writer has to pay attention to some of
 
11003
the implementation details. The information common to all instances of
 
11004
one class of widgets (e.g., to all Button widgets) is stored in the 
 
11005
<emphasis>class structure</emphasis>. There is only one copy of this in
 
11006
which is stored information about the class's signals
 
11007
(which act like virtual functions in C). To support inheritance, the
 
11008
first field in the class structure must be a copy of the parent's
 
11009
class structure. The declaration of the class structure of GtkButtton
 
11010
looks like:</para>
 
11011
 
 
11012
<programlisting role="C">
 
11013
struct _GtkButtonClass
 
11014
{
 
11015
  GtkContainerClass parent_class;
 
11016
 
 
11017
  void (* pressed)  (GtkButton *button);
 
11018
  void (* released) (GtkButton *button);
 
11019
  void (* clicked)  (GtkButton *button);
 
11020
  void (* enter)    (GtkButton *button);
 
11021
  void (* leave)    (GtkButton *button);
 
11022
};
 
11023
</programlisting>
 
11024
 
 
11025
<para>When a button is treated as a container (for instance, when it is
 
11026
resized), its class structure can be cast to GtkContainerClass, and
 
11027
the relevant fields used to handle the signals.</para>
 
11028
 
 
11029
<para>There is also a structure for each widget that is created on a
 
11030
per-instance basis. This structure has fields to store information that
 
11031
is different for each instance of the widget. We'll call this
 
11032
structure the <emphasis>object structure</emphasis>. For the Button class, it looks
 
11033
like:</para>
 
11034
 
 
11035
<programlisting role="C">
 
11036
struct _GtkButton
 
11037
{
 
11038
  GtkContainer container;
 
11039
 
 
11040
  GtkWidget *child;
 
11041
 
 
11042
  guint in_button : 1;
 
11043
  guint button_down : 1;
 
11044
};
 
11045
</programlisting>
 
11046
 
 
11047
<para>Note that, similar to the class structure, the first field is the
 
11048
object structure of the parent class, so that this structure can be
 
11049
cast to the parent class' object structure as needed.</para>
 
11050
 
 
11051
</sect1>
 
11052
 
 
11053
<!-- ----------------------------------------------------------------- -->
 
11054
<sect1 id="sec-CreatingACompositeWidget">
 
11055
<title>Creating a Composite widget</title>
 
11056
 
 
11057
<!-- ----------------------------------------------------------------- -->
 
11058
<sect2>
 
11059
<title>Introduction</title>
 
11060
 
 
11061
<para>One type of widget that you may be interested in creating is a
 
11062
widget that is merely an aggregate of other GTK widgets. This type of
 
11063
widget does nothing that couldn't be done without creating new
 
11064
widgets, but provides a convenient way of packaging user interface
 
11065
elements for reuse. The FileSelection and ColorSelection widgets in
 
11066
the standard distribution are examples of this type of widget.</para>
 
11067
 
 
11068
<para>The example widget that we'll create in this section is the Tictactoe
 
11069
widget, a 3x3 array of toggle buttons which triggers a signal when all
 
11070
three buttons in a row, column, or on one of the diagonals are
 
11071
depressed. </para>
 
11072
 
 
11073
<para><emphasis>Note: the full source code for the Tictactoe example described
 
11074
below is in the <link linkend="sec-Tictactoe">Code Examples Appendix</link>
 
11075
</emphasis></para>
 
11076
 
 
11077
<para>
 
11078
<inlinemediaobject>
 
11079
<imageobject>
 
11080
<imagedata fileref="images/tictactoe.png" format="png">
 
11081
</imageobject>
 
11082
</inlinemediaobject>
 
11083
</para>
 
11084
 
 
11085
</sect2>
 
11086
 
 
11087
<!-- ----------------------------------------------------------------- -->
 
11088
<sect2>
 
11089
<title>Choosing a parent class</title>
 
11090
 
 
11091
<para>The parent class for a composite widget is typically the container
 
11092
class that holds all of the elements of the composite widget. For
 
11093
example, the parent class of the FileSelection widget is the
 
11094
Dialog class. Since our buttons will be arranged in a table, it
 
11095
is natural to make our parent class the Table class.</para>
 
11096
 
 
11097
</sect2>
 
11098
 
 
11099
<!-- ----------------------------------------------------------------- -->
 
11100
<sect2>
 
11101
<title>The header file</title>
 
11102
 
 
11103
<para>Each GObject class has a header file which declares the object and
 
11104
class structures for that object, along with public functions. 
 
11105
A couple of features are worth pointing out. To prevent duplicate
 
11106
definitions, we wrap the entire header file in:</para>
 
11107
 
 
11108
<programlisting role="C">
 
11109
#ifndef __TICTACTOE_H__
 
11110
#define __TICTACTOE_H__
 
11111
.
 
11112
.
 
11113
.
 
11114
#endif /* __TICTACTOE_H__ */
 
11115
</programlisting>
 
11116
 
 
11117
<para>And to keep C++ programs that include the header file happy, in:</para>
 
11118
 
 
11119
<programlisting role="C">
 
11120
#include &lt;glib.h&gt;
 
11121
 
 
11122
G_BEGIN_DECLS
 
11123
.
 
11124
.
 
11125
.
 
11126
G_END_DECLS
 
11127
</programlisting>
 
11128
 
 
11129
<para>Along with the functions and structures, we declare five standard
 
11130
macros in our header file, <literal>TICTACTOE_TYPE</literal>,
 
11131
<literal>TICTACTOE(obj)</literal>,
 
11132
<literal>TICTACTOE_CLASS(klass)</literal>,
 
11133
<literal>IS_TICTACTOE(obj)</literal>, and
 
11134
<literal>IS_TICTACTOE_CLASS(klass)</literal>, which cast a
 
11135
pointer into a pointer to the object or class structure, and check
 
11136
if an object is a Tictactoe widget respectively.</para>
 
11137
 
 
11138
</sect2>
 
11139
 
 
11140
<!-- ----------------------------------------------------------------- -->
 
11141
<sect2>
 
11142
<title>The <literal>_get_type()</literal> function</title>
 
11143
 
 
11144
<para>We now continue on to the implementation of our widget. A core
 
11145
function for every object is the function
 
11146
<literal>WIDGETNAME_get_type()</literal>. This function, when first called, tells
 
11147
Glib about the new class, and gets an ID that uniquely identifies
 
11148
the class. Upon subsequent calls, it just returns the ID.</para>
 
11149
 
 
11150
<programlisting role="C">
 
11151
GType
 
11152
tictactoe_get_type (void)
 
11153
{
 
11154
  static GType ttt_type = 0;
 
11155
 
 
11156
  if (!ttt_type)
 
11157
    {
 
11158
      static const GTypeInfo ttt_info =
 
11159
      {
 
11160
        sizeof (TictactoeClass),
 
11161
        NULL, /* base_init */
 
11162
        NULL, /* base_finalize */
 
11163
        (GClassInitFunc) tictactoe_class_init,
 
11164
        NULL, /* class_finalize */
 
11165
        NULL, /* class_data */
 
11166
        sizeof (Tictactoe),
 
11167
        0,    /* n_preallocs */
 
11168
        (GInstanceInitFunc) tictactoe_init,
 
11169
      };
 
11170
 
 
11171
      ttt_type = g_type_register_static (GTK_TYPE_TABLE,
 
11172
                                         "Tictactoe",
 
11173
                                         &amp;ttt_info,
 
11174
                                         0);
 
11175
    }
 
11176
 
 
11177
  return ttt_type;
 
11178
}
 
11179
</programlisting>
 
11180
 
 
11181
<para>The GTypeInfo structure has the following definition:</para>
 
11182
 
 
11183
<programlisting role="C">
 
11184
struct _GTypeInfo
 
11185
{
 
11186
  /* interface types, classed types, instantiated types */
 
11187
  guint16                class_size;
 
11188
   
 
11189
  GBaseInitFunc          base_init;
 
11190
  GBaseFinalizeFunc      base_finalize;
 
11191
   
 
11192
  /* classed types, instantiated types */
 
11193
  GClassInitFunc         class_init;
 
11194
  GClassFinalizeFunc     class_finalize;
 
11195
  gconstpointer          class_data;
 
11196
   
 
11197
  /* instantiated types */
 
11198
  guint16                instance_size;
 
11199
  guint16                n_preallocs;
 
11200
  GInstanceInitFunc      instance_init;
 
11201
   
 
11202
  /* value handling */
 
11203
  const GTypeValueTable *value_table;
 
11204
};
 
11205
</programlisting>
 
11206
 
 
11207
<para>The important fields of this structure are pretty self-explanatory.
 
11208
We'll ignore the <literal>base_init</literal> and
 
11209
 <literal>base_finalize</literal> as well as the <literal>value_table</literal>
 
11210
fields here. Once Glib has a correctly filled in copy of
 
11211
this structure, it knows how to create objects of a particular type. </para>
 
11212
 
 
11213
</sect2>
 
11214
 
 
11215
<!-- ----------------------------------------------------------------- -->
 
11216
<sect2>
 
11217
<title>The <literal>_class_init()</literal> function</title>
 
11218
 
 
11219
<para>The <literal>WIDGETNAME_class_init()</literal> function initializes the fields of
 
11220
the widget's class structure, and sets up any signals for the
 
11221
class. For our Tictactoe widget it looks like:</para>
 
11222
 
 
11223
<programlisting role="C">
 
11224
enum {
 
11225
  TICTACTOE_SIGNAL,
 
11226
  LAST_SIGNAL
 
11227
};
 
11228
 
 
11229
 
 
11230
static guint tictactoe_signals[LAST_SIGNAL] = { 0 };
 
11231
 
 
11232
static void
 
11233
tictactoe_class_init (TictactoeClass *klass)
 
11234
{
 
11235
  tictactoe_signals[TICTACTOE_SIGNAL] =
 
11236
    g_signal_new ("tictactoe",
 
11237
                  G_TYPE_FROM_CLASS (klass),
 
11238
                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 
11239
                  G_STRUCT_OFFSET (TictactoeClass, tictactoe),
 
11240
                  NULL, NULL,
 
11241
                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 
11242
}
 
11243
</programlisting>
 
11244
 
 
11245
<para>Our widget has just one signal, the <literal>tictactoe</literal> signal that is
 
11246
invoked when a row, column, or diagonal is completely filled in. Not
 
11247
every composite widget needs signals, so if you are reading this for
 
11248
the first time, you may want to skip to the next section now, as
 
11249
things are going to get a bit complicated.</para>
 
11250
 
 
11251
<para>The function:</para>
 
11252
 
 
11253
<programlisting role="C">
 
11254
guint g_signal_new( const gchar         *signal_name,
 
11255
                    GType                itype,
 
11256
                    GSignalFlags         signal_flags,
 
11257
                    guint                class_offset,
 
11258
                    GSignalAccumulator  *accumulator,
 
11259
                    gpointer             accu_data,
 
11260
                    GSignalCMarshaller  *c_marshaller,
 
11261
                    GType                return_type,
 
11262
                    guint                n_params,
 
11263
                    ...);
 
11264
</programlisting>
 
11265
 
 
11266
<para>Creates a new signal. The parameters are:</para>
 
11267
 
 
11268
<itemizedlist>
 
11269
<listitem><simpara> <literal>signal_name</literal>: The name of the signal.</simpara>
 
11270
</listitem>
 
11271
 
 
11272
<listitem><simpara> <literal>itype</literal>: The ID of the object that this signal applies
 
11273
to. (It will also apply to that objects descendants.)</simpara>
 
11274
</listitem>
 
11275
                                                                                
 
11276
<listitem><simpara> <literal>signal_flags</literal>: Whether the default handler runs before or after
 
11277
user handlers and other flags. Usually this will be one of
 
11278
<literal>G_SIGNAL_RUN_FIRST</literal> or <literal>G_SIGNAL_RUN_LAST</literal>,
 
11279
although there are other possibilities. The flag
 
11280
<literal>G_SIGNAL_ACTION</literal> specifies that no extra code needs to
 
11281
run that performs special pre or post emission adjustments. This means that
 
11282
the signal can also be emitted from object external code.</simpara>
 
11283
</listitem>
 
11284
 
 
11285
<listitem><simpara> <literal>class_offset</literal>: The offset within the class structure of
 
11286
a pointer to the default handler.</simpara>
 
11287
</listitem>
 
11288
 
 
11289
<listitem><simpara> <literal>accumulator</literal>: For most classes this can
 
11290
be set to NULL.</simpara></listitem>
 
11291
 
 
11292
<listitem><simpara> <literal>accu_data</literal>: User data that will be handed
 
11293
to the accumulator function.</simpara></listitem>
 
11294
 
 
11295
<listitem><simpara> <literal>c_marshaller</literal>: A function that is used to invoke the signal
 
11296
handler. For signal handlers that have no arguments other than the
 
11297
object that emitted the signal and user data, we can use the
 
11298
pre-supplied marshaller function <literal>g_cclosure_marshal_VOID__VOID</literal>.</simpara>
 
11299
</listitem>
 
11300
 
 
11301
<listitem><simpara> <literal>return_type</literal>: The type of the return value.</simpara>
 
11302
</listitem>
 
11303
 
 
11304
<listitem><simpara> <literal>n_params</literal>: The number of parameters of the signal handler
 
11305
(other than the two default ones mentioned above)</simpara>
 
11306
</listitem>
 
11307
 
 
11308
<listitem><simpara> <literal>...</literal>: The types of the parameters.</simpara>
 
11309
</listitem>
 
11310
</itemizedlist>
 
11311
 
 
11312
<para>When specifying types, the following standard types can be used:</para>
 
11313
 
 
11314
<programlisting role="C">
 
11315
G_TYPE_INVALID
 
11316
G_TYPE_NONE
 
11317
G_TYPE_INTERFACE
 
11318
G_TYPE_CHAR
 
11319
G_TYPE_UCHAR
 
11320
G_TYPE_BOOLEAN
 
11321
G_TYPE_INT
 
11322
G_TYPE_UINT
 
11323
G_TYPE_LONG
 
11324
G_TYPE_ULONG
 
11325
G_TYPE_INT64
 
11326
G_TYPE_UINT64
 
11327
G_TYPE_ENUM
 
11328
G_TYPE_FLAGS
 
11329
G_TYPE_FLOAT
 
11330
G_TYPE_DOUBLE
 
11331
G_TYPE_STRING
 
11332
G_TYPE_POINTER
 
11333
G_TYPE_BOXED
 
11334
G_TYPE_PARAM
 
11335
G_TYPE_OBJECT
 
11336
</programlisting>
 
11337
 
 
11338
<para><literal>g_signal_new()</literal> returns a unique integer identifier for the
 
11339
signal, that we store in the <literal>tictactoe_signals</literal> array, which we
 
11340
index using an enumeration. (Conventionally, the enumeration elements
 
11341
are the signal name, uppercased, but here there would be a conflict
 
11342
with the <literal>TICTACTOE()</literal> macro, so we called it <literal>TICTACTOE_SIGNAL</literal>
 
11343
instead.</para>
 
11344
 
 
11345
</sect2>
 
11346
 
 
11347
<!-- ----------------------------------------------------------------- -->
 
11348
<sect2>
 
11349
<title>The <literal>_init()</literal> function</title>
 
11350
 
 
11351
<para>Each class also needs a function to initialize the object
 
11352
structure. Usually, this function has the fairly limited role of
 
11353
setting the fields of the structure to default values. For composite
 
11354
widgets, however, this function also creates the component widgets.</para>
 
11355
 
 
11356
<programlisting role="C">
 
11357
static void
 
11358
tictactoe_init (Tictactoe *ttt)
 
11359
{
 
11360
  gint i,j;
 
11361
 
 
11362
  gtk_table_resize (GTK_TABLE (ttt), 3, 3);
 
11363
  gtk_table_set_homogeneous (GTK_TABLE (ttt), TRUE);
 
11364
 
 
11365
  for (i=0;i&lt;3; i++)
 
11366
    for (j=0;j&lt;3; j++)
 
11367
      {
 
11368
        ttt->buttons[i][j] = gtk_toggle_button_new ();
 
11369
        gtk_table_attach_defaults (GTK_TABLE (ttt), ttt->buttons[i][j], 
 
11370
                                   i, i+1, j, j+1);
 
11371
        g_signal_connect (G_OBJECT (ttt->buttons[i][j]), "toggled",
 
11372
                          G_CALLBACK (tictactoe_toggle), ttt);
 
11373
        gtk_widget_set_size_request (ttt->buttons[i][j], 20, 20);
 
11374
        gtk_widget_show (ttt->buttons[i][j]);
 
11375
      }
 
11376
}
 
11377
</programlisting>
 
11378
 
 
11379
</sect2>
 
11380
 
 
11381
<!-- ----------------------------------------------------------------- -->
 
11382
<sect2>
 
11383
<title>And the rest...</title>
 
11384
 
 
11385
<para>There is one more function that every object (except for abstract
 
11386
classes like Bin that cannot be instantiated) needs to have - the
 
11387
function that the user calls to create an object of that type. This is
 
11388
conventionally called <literal>OBJECTNAME_new()</literal>. In some
 
11389
widgets, though not for the Tictactoe widgets, this function takes
 
11390
arguments, and does some setup based on the arguments. The other two
 
11391
functions are specific to the Tictactoe widget. </para>
 
11392
 
 
11393
<para><literal>tictactoe_clear()</literal> is a public function that resets all the
 
11394
buttons in the widget to the up position. Note the use of
 
11395
<literal>g_signal_handlers_block_matched()</literal> to keep our signal handler for
 
11396
button toggles from being triggered unnecessarily.</para>
 
11397
 
 
11398
<para><literal>tictactoe_toggle()</literal> is the signal handler that is invoked when the
 
11399
user clicks on a button. It checks to see if there are any winning
 
11400
combinations that involve the toggled button, and if so, emits
 
11401
the "tictactoe" signal.</para>
 
11402
 
 
11403
<programlisting role="C">
 
11404
GtkWidget*
 
11405
tictactoe_new (void)
 
11406
{
 
11407
  return GTK_WIDGET ( g_object_new (TICTACTOE_TYPE, NULL));
 
11408
}
 
11409
 
 
11410
void           
 
11411
tictactoe_clear (Tictactoe *ttt)
 
11412
{
 
11413
  int i,j;
 
11414
 
 
11415
  for (i=0;i&lt;3;i++)
 
11416
    for (j=0;j&lt;3;j++)
 
11417
      {
 
11418
        g_signal_handlers_block_matched (G_OBJECT (ttt->buttons[i][j]),
 
11419
                                         G_SIGNAL_MATCH_DATA,
 
11420
                                         0, 0, NULL, NULL, ttt);
 
11421
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
 
11422
                                     FALSE);
 
11423
        g_signal_handlers_unblock_matched (G_OBJECT (ttt->buttons[i][j]),
 
11424
                                           G_SIGNAL_MATCH_DATA,
 
11425
                                           0, 0, NULL, NULL, ttt);
 
11426
      }
 
11427
}
 
11428
 
 
11429
static void
 
11430
tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
 
11431
{
 
11432
  int i,k;
 
11433
 
 
11434
  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
 
11435
                             { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
 
11436
                             { 0, 1, 2 }, { 0, 1, 2 } };
 
11437
  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
 
11438
                             { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
 
11439
                             { 0, 1, 2 }, { 2, 1, 0 } };
 
11440
 
 
11441
  int success, found;
 
11442
 
 
11443
  for (k=0; k&lt;8; k++)
 
11444
    {
 
11445
      success = TRUE;
 
11446
      found = FALSE;
 
11447
 
 
11448
      for (i=0;i&lt;3;i++)
 
11449
        {
 
11450
          success = success &amp;&amp; 
 
11451
            GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
 
11452
          found = found ||
 
11453
            ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
 
11454
        }
 
11455
      
 
11456
      if (success &amp;&amp; found)
 
11457
        {
 
11458
          g_signal_emit (G_OBJECT (ttt), 
 
11459
                         tictactoe_signals[TICTACTOE_SIGNAL], 0);
 
11460
          break;
 
11461
        }
 
11462
    }
 
11463
}
 
11464
</programlisting>
 
11465
 
 
11466
<para>And finally, an example program using our Tictactoe widget:</para>
 
11467
 
 
11468
<programlisting role="C">
 
11469
#include &lt;gtk/gtk.h&gt;
 
11470
#include "tictactoe.h"
 
11471
 
 
11472
/* Invoked when a row, column or diagonal is completed */
 
11473
void
 
11474
win (GtkWidget *widget, gpointer data)
 
11475
{
 
11476
  g_print ("Yay!\n");
 
11477
  tictactoe_clear (TICTACTOE (widget));
 
11478
}
 
11479
 
 
11480
int 
 
11481
main (int argc, char *argv[])
 
11482
{
 
11483
  GtkWidget *window;
 
11484
  GtkWidget *ttt;
 
11485
  
 
11486
  gtk_init (&amp;argc, &amp;argv);
 
11487
 
 
11488
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
11489
  
 
11490
  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
 
11491
  
 
11492
  g_signal_connect (G_OBJECT (window), "destroy",
 
11493
                    G_CALLBACK (exit), NULL);
 
11494
  
 
11495
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
11496
 
 
11497
  /* Create a new Tictactoe widget */
 
11498
  ttt = tictactoe_new ();
 
11499
  gtk_container_add (GTK_CONTAINER (window), ttt);
 
11500
  gtk_widget_show (ttt);
 
11501
 
 
11502
  /* And attach to its "tictactoe" signal */
 
11503
  g_signal_connect (G_OBJECT (ttt), "tictactoe",
 
11504
                    G_CALLBACK (win), NULL);
 
11505
 
 
11506
  gtk_widget_show (window);
 
11507
  
 
11508
  gtk_main ();
 
11509
  
 
11510
  return 0;
 
11511
}
 
11512
</programlisting>
 
11513
 
 
11514
</sect2>
 
11515
</sect1>
 
11516
 
 
11517
<!-- ----------------------------------------------------------------- -->
 
11518
<sect1 id="sec-CreatingAWidgetFromScratch">
 
11519
<title>Creating a widget from scratch</title>
 
11520
 
 
11521
<!-- ----------------------------------------------------------------- -->
 
11522
<sect2>
 
11523
<title>Introduction</title>
 
11524
 
 
11525
<para>In this section, we'll learn more about how widgets display themselves
 
11526
on the screen and interact with events. As an example of this, we'll
 
11527
create an analog dial widget with a pointer that the user can drag to
 
11528
set the value.</para>
 
11529
 
 
11530
<para>
 
11531
<inlinemediaobject>
 
11532
<imageobject>
 
11533
<imagedata fileref="images/gtkdial.png" format="png">
 
11534
</imageobject>
 
11535
</inlinemediaobject>
 
11536
</para>
 
11537
 
 
11538
</sect2>
 
11539
 
 
11540
<!-- ----------------------------------------------------------------- -->
 
11541
<sect2>
 
11542
<title>Displaying a widget on the screen</title>
 
11543
 
 
11544
<para>There are several steps that are involved in displaying on the screen.
 
11545
After the widget is created with a call to <literal>WIDGETNAME_new()</literal>,
 
11546
several more functions are needed:</para>
 
11547
 
 
11548
<itemizedlist>
 
11549
<listitem><simpara> <literal>WIDGETNAME_realize()</literal> is responsible for creating an X
 
11550
window for the widget if it has one.</simpara>
 
11551
</listitem>
 
11552
<listitem><simpara> <literal>WIDGETNAME_map()</literal> is invoked after the user calls
 
11553
<literal>gtk_widget_show()</literal>. It is responsible for making sure the widget
 
11554
is actually drawn on the screen (<emphasis>mapped</emphasis>). For a container class,
 
11555
it must also make calls to <literal>map()</literal> functions of any child widgets.</simpara>
 
11556
</listitem>
 
11557
<listitem><simpara> <literal>WIDGETNAME_draw()</literal> is invoked when <literal>gtk_widget_draw()</literal>
 
11558
is called for the widget or one of its ancestors. It makes the actual
 
11559
calls to the drawing functions to draw the widget on the screen. For
 
11560
container widgets, this function must make calls to
 
11561
<literal>gtk_widget_draw()</literal> for its child widgets.</simpara>
 
11562
</listitem>
 
11563
<listitem><simpara> <literal>WIDGETNAME_expose()</literal> is a handler for expose events for the
 
11564
widget. It makes the necessary calls to the drawing functions to draw
 
11565
the exposed portion on the screen. For container widgets, this
 
11566
function must generate expose events for its child widgets which don't
 
11567
have their own windows. (If they have their own windows, then X will
 
11568
generate the necessary expose events.)</simpara>
 
11569
</listitem>
 
11570
</itemizedlist>
 
11571
 
 
11572
<para>You might notice that the last two functions are quite similar - each
 
11573
is responsible for drawing the widget on the screen. In fact many
 
11574
types of widgets don't really care about the difference between the
 
11575
two. The default <literal>draw()</literal> function in the widget class simply
 
11576
generates a synthetic expose event for the redrawn area. However, some
 
11577
types of widgets can save work by distinguishing between the two
 
11578
functions. For instance, if a widget has multiple X windows, then
 
11579
since expose events identify the exposed window, it can redraw only
 
11580
the affected window, which is not possible for calls to <literal>draw()</literal>.</para>
 
11581
 
 
11582
<para>Container widgets, even if they don't care about the difference for
 
11583
themselves, can't simply use the default <literal>draw()</literal> function because
 
11584
their child widgets might care about the difference. However,
 
11585
it would be wasteful to duplicate the drawing code between the two
 
11586
functions. The convention is that such widgets have a function called
 
11587
<literal>WIDGETNAME_paint()</literal> that does the actual work of drawing the
 
11588
widget, that is then called by the <literal>draw()</literal> and <literal>expose()</literal>
 
11589
functions.</para>
 
11590
 
 
11591
<para>In our example approach, since the dial widget is not a container
 
11592
widget, and only has a single window, we can take the simplest
 
11593
approach and use the default <literal>draw()</literal> function and only implement
 
11594
an <literal>expose()</literal> function.</para>
 
11595
 
 
11596
</sect2>
 
11597
 
 
11598
<!-- ----------------------------------------------------------------- -->
 
11599
<sect2>
 
11600
<title>The origins of the Dial Widget</title>
 
11601
 
 
11602
<para>Just as all land animals are just variants on the first amphibian that
 
11603
crawled up out of the mud, GTK widgets tend to start off as variants
 
11604
of some other, previously written widget. Thus, although this section
 
11605
is entitled "Creating a Widget from Scratch", the Dial widget really
 
11606
began with the source code for the Range widget. This was picked as a
 
11607
starting point because it would be nice if our Dial had the same
 
11608
interface as the Scale widgets which are just specialized descendants
 
11609
of the Range widget. So, though the source code is presented below in
 
11610
finished form, it should not be implied that it was written, <emphasis>ab
 
11611
initio</emphasis> in this fashion. Also, if you aren't yet familiar with
 
11612
how scale widgets work from the application writer's point of view, it
 
11613
would be a good idea to look them over before continuing.</para>
 
11614
 
 
11615
</sect2>
 
11616
 
 
11617
<!-- ----------------------------------------------------------------- -->
 
11618
<sect2>
 
11619
<title>The Basics</title>
 
11620
 
 
11621
<para>Quite a bit of our widget should look pretty familiar from the
 
11622
Tictactoe widget. First, we have a header file:</para>
 
11623
 
 
11624
<programlisting role="C">
 
11625
/* GTK - The GIMP Toolkit
 
11626
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 
11627
 *
 
11628
 * This library is free software; you can redistribute it and/or
 
11629
 * modify it under the terms of the GNU Library General Public
 
11630
 * License as published by the Free Software Foundation; either
 
11631
 * version 2 of the License, or (at your option) any later version.
 
11632
 *
 
11633
 * This library is distributed in the hope that it will be useful,
 
11634
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11635
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11636
 * Library General Public License for more details.
 
11637
 *
 
11638
 * You should have received a copy of the GNU Library General Public
 
11639
 * License along with this library; if not, write to the Free
 
11640
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
11641
 */
 
11642
 
 
11643
#ifndef __GTK_DIAL_H__
 
11644
#define __GTK_DIAL_H__
 
11645
 
 
11646
#include &lt;gdk/gdk.h&gt;
 
11647
#include &lt;gtk/gtkadjustment.h&gt;
 
11648
#include &lt;gtk/gtkwidget.h&gt;
 
11649
 
 
11650
 
 
11651
#ifdef __cplusplus
 
11652
extern "C" {
 
11653
#endif /* __cplusplus */
 
11654
 
 
11655
 
 
11656
#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
 
11657
#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
 
11658
#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
 
11659
 
 
11660
 
 
11661
typedef struct _GtkDial        GtkDial;
 
11662
typedef struct _GtkDialClass   GtkDialClass;
 
11663
 
 
11664
struct _GtkDial
 
11665
{
 
11666
  GtkWidget widget;
 
11667
 
 
11668
  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
 
11669
  guint policy : 2;
 
11670
 
 
11671
  /* Button currently pressed or 0 if none */
 
11672
  guint8 button;
 
11673
 
 
11674
  /* Dimensions of dial components */
 
11675
  gint radius;
 
11676
  gint pointer_width;
 
11677
 
 
11678
  /* ID of update timer, or 0 if none */
 
11679
  guint32 timer;
 
11680
 
 
11681
  /* Current angle */
 
11682
  gfloat angle;
 
11683
 
 
11684
  /* Old values from adjustment stored so we know when something changes */
 
11685
  gfloat old_value;
 
11686
  gfloat old_lower;
 
11687
  gfloat old_upper;
 
11688
 
 
11689
  /* The adjustment object that stores the data for this dial */
 
11690
  GtkAdjustment *adjustment;
 
11691
};
 
11692
 
 
11693
struct _GtkDialClass
 
11694
{
 
11695
  GtkWidgetClass parent_class;
 
11696
};
 
11697
 
 
11698
 
 
11699
GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
 
11700
GtkType        gtk_dial_get_type               (void);
 
11701
GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
 
11702
void           gtk_dial_set_update_policy      (GtkDial      *dial,
 
11703
                                                GtkUpdateType  policy);
 
11704
 
 
11705
void           gtk_dial_set_adjustment         (GtkDial      *dial,
 
11706
                                                GtkAdjustment *adjustment);
 
11707
#ifdef __cplusplus
 
11708
}
 
11709
#endif /* __cplusplus */
 
11710
 
 
11711
 
 
11712
#endif /* __GTK_DIAL_H__ */
 
11713
</programlisting>
 
11714
 
 
11715
<para>Since there is quite a bit more going on in this widget than the last
 
11716
one, we have more fields in the data structure, but otherwise things
 
11717
are pretty similar.</para>
 
11718
 
 
11719
<para>Next, after including header files and declaring a few constants,
 
11720
we have some functions to provide information about the widget
 
11721
and initialize it:</para>
 
11722
 
 
11723
<programlisting role="C">
 
11724
#include &lt;math.h&gt;
 
11725
#include &lt;stdio.h&gt;
 
11726
#include &lt;gtk/gtkmain.h&gt;
 
11727
#include &lt;gtk/gtksignal.h&gt;
 
11728
 
 
11729
#include "gtkdial.h"
 
11730
 
 
11731
#define SCROLL_DELAY_LENGTH  300
 
11732
#define DIAL_DEFAULT_SIZE 100
 
11733
 
 
11734
/* Forward declarations */
 
11735
 
 
11736
[ omitted to save space ]
 
11737
 
 
11738
/* Local data */
 
11739
 
 
11740
static GtkWidgetClass *parent_class = NULL;
 
11741
 
 
11742
GtkType
 
11743
gtk_dial_get_type ()
 
11744
{
 
11745
  static GtkType dial_type = 0;
 
11746
 
 
11747
  if (!dial_type)
 
11748
    {
 
11749
      static const GtkTypeInfo dial_info =
 
11750
      {
 
11751
        "GtkDial",
 
11752
        sizeof (GtkDial),
 
11753
        sizeof (GtkDialClass),
 
11754
        (GtkClassInitFunc) gtk_dial_class_init,
 
11755
        (GtkObjectInitFunc) gtk_dial_init,
 
11756
        /* reserved_1 */ NULL,
 
11757
        /* reserved_1 */ NULL,
 
11758
        (GtkClassInitFunc) NULL
 
11759
      };
 
11760
 
 
11761
      dial_type = gtk_type_unique (GTK_TYPE_WIDGET, &amp;dial_info);
 
11762
    }
 
11763
 
 
11764
  return dial_type;
 
11765
}
 
11766
 
 
11767
static void
 
11768
gtk_dial_class_init (GtkDialClass *class)
 
11769
{
 
11770
  GtkObjectClass *object_class;
 
11771
  GtkWidgetClass *widget_class;
 
11772
 
 
11773
  object_class = (GtkObjectClass*) class;
 
11774
  widget_class = (GtkWidgetClass*) class;
 
11775
 
 
11776
  parent_class = gtk_type_class (gtk_widget_get_type ());
 
11777
 
 
11778
  object_class->destroy = gtk_dial_destroy;
 
11779
 
 
11780
  widget_class->realize = gtk_dial_realize;
 
11781
  widget_class->expose_event = gtk_dial_expose;
 
11782
  widget_class->size_request = gtk_dial_size_request;
 
11783
  widget_class->size_allocate = gtk_dial_size_allocate;
 
11784
  widget_class->button_press_event = gtk_dial_button_press;
 
11785
  widget_class->button_release_event = gtk_dial_button_release;
 
11786
  widget_class->motion_notify_event = gtk_dial_motion_notify;
 
11787
}
 
11788
 
 
11789
static void
 
11790
gtk_dial_init (GtkDial *dial)
 
11791
{
 
11792
  dial->button = 0;
 
11793
  dial->policy = GTK_UPDATE_CONTINUOUS;
 
11794
  dial->timer = 0;
 
11795
  dial->radius = 0;
 
11796
  dial->pointer_width = 0;
 
11797
  dial->angle = 0.0;
 
11798
  dial->old_value = 0.0;
 
11799
  dial->old_lower = 0.0;
 
11800
  dial->old_upper = 0.0;
 
11801
  dial->adjustment = NULL;
 
11802
}
 
11803
 
 
11804
GtkWidget*
 
11805
gtk_dial_new (GtkAdjustment *adjustment)
 
11806
{
 
11807
  GtkDial *dial;
 
11808
 
 
11809
  dial = gtk_type_new (gtk_dial_get_type ());
 
11810
 
 
11811
  if (!adjustment)
 
11812
    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
 
11813
 
 
11814
  gtk_dial_set_adjustment (dial, adjustment);
 
11815
 
 
11816
  return GTK_WIDGET (dial);
 
11817
}
 
11818
 
 
11819
static void
 
11820
gtk_dial_destroy (GtkObject *object)
 
11821
{
 
11822
  GtkDial *dial;
 
11823
 
 
11824
  g_return_if_fail (object != NULL);
 
11825
  g_return_if_fail (GTK_IS_DIAL (object));
 
11826
 
 
11827
  dial = GTK_DIAL (object);
 
11828
 
 
11829
  if (dial->adjustment)
 
11830
    gtk_object_unref (GTK_OBJECT (dial->adjustment));
 
11831
 
 
11832
  if (GTK_OBJECT_CLASS (parent_class)->destroy)
 
11833
    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 
11834
}
 
11835
</programlisting>
 
11836
 
 
11837
<para>Note that this <literal>init()</literal> function does less than for the Tictactoe
 
11838
widget, since this is not a composite widget, and the <literal>new()</literal>
 
11839
function does more, since it now has an argument. Also, note that when
 
11840
we store a pointer to the Adjustment object, we increment its
 
11841
reference count, (and correspondingly decrement it when we no longer
 
11842
use it) so that GTK can keep track of when it can be safely destroyed.</para>
 
11843
 
 
11844
<para>Also, there are a few function to manipulate the widget's options:</para>
 
11845
 
 
11846
<programlisting role="C">
 
11847
GtkAdjustment*
 
11848
gtk_dial_get_adjustment (GtkDial *dial)
 
11849
{
 
11850
  g_return_val_if_fail (dial != NULL, NULL);
 
11851
  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
 
11852
 
 
11853
  return dial->adjustment;
 
11854
}
 
11855
 
 
11856
void
 
11857
gtk_dial_set_update_policy (GtkDial      *dial,
 
11858
                             GtkUpdateType  policy)
 
11859
{
 
11860
  g_return_if_fail (dial != NULL);
 
11861
  g_return_if_fail (GTK_IS_DIAL (dial));
 
11862
 
 
11863
  dial->policy = policy;
 
11864
}
 
11865
 
 
11866
void
 
11867
gtk_dial_set_adjustment (GtkDial      *dial,
 
11868
                          GtkAdjustment *adjustment)
 
11869
{
 
11870
  g_return_if_fail (dial != NULL);
 
11871
  g_return_if_fail (GTK_IS_DIAL (dial));
 
11872
 
 
11873
  if (dial->adjustment)
 
11874
    {
 
11875
      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
 
11876
      gtk_object_unref (GTK_OBJECT (dial->adjustment));
 
11877
    }
 
11878
 
 
11879
  dial->adjustment = adjustment;
 
11880
  gtk_object_ref (GTK_OBJECT (dial->adjustment));
 
11881
 
 
11882
  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
 
11883
                      (GtkSignalFunc) gtk_dial_adjustment_changed,
 
11884
                      (gpointer) dial);
 
11885
  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
 
11886
                      (GtkSignalFunc) gtk_dial_adjustment_value_changed,
 
11887
                      (gpointer) dial);
 
11888
 
 
11889
  dial->old_value = adjustment->value;
 
11890
  dial->old_lower = adjustment->lower;
 
11891
  dial->old_upper = adjustment->upper;
 
11892
 
 
11893
  gtk_dial_update (dial);
 
11894
}
 
11895
</programlisting>
 
11896
 
 
11897
</sect2>
 
11898
 
 
11899
<!-- ----------------------------------------------------------------- -->
 
11900
<sect2>
 
11901
<title><literal>gtk_dial_realize()</literal></title>
 
11902
 
 
11903
<para>Now we come to some new types of functions. First, we have a function
 
11904
that does the work of creating the X window. Notice that a mask is
 
11905
passed to the function <literal>gdk_window_new()</literal> which specifies which fields of
 
11906
the GdkWindowAttr structure actually have data in them (the remaining
 
11907
fields will be given default values). Also worth noting is the way the
 
11908
event mask of the widget is created. We call
 
11909
<literal>gtk_widget_get_events()</literal> to retrieve the event mask that the user
 
11910
has specified for this widget (with <literal>gtk_widget_set_events()</literal>), and
 
11911
add the events that we are interested in ourselves.</para>
 
11912
 
 
11913
<para>After creating the window, we set its style and background, and put a
 
11914
pointer to the widget in the user data field of the GdkWindow. This
 
11915
last step allows GTK to dispatch events for this window to the correct
 
11916
widget.</para>
 
11917
 
 
11918
<programlisting role="C">
 
11919
static void
 
11920
gtk_dial_realize (GtkWidget *widget)
 
11921
{
 
11922
  GtkDial *dial;
 
11923
  GdkWindowAttr attributes;
 
11924
  gint attributes_mask;
 
11925
 
 
11926
  g_return_if_fail (widget != NULL);
 
11927
  g_return_if_fail (GTK_IS_DIAL (widget));
 
11928
 
 
11929
  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
11930
  dial = GTK_DIAL (widget);
 
11931
 
 
11932
  attributes.x = widget->allocation.x;
 
11933
  attributes.y = widget->allocation.y;
 
11934
  attributes.width = widget->allocation.width;
 
11935
  attributes.height = widget->allocation.height;
 
11936
  attributes.wclass = GDK_INPUT_OUTPUT;
 
11937
  attributes.window_type = GDK_WINDOW_CHILD;
 
11938
  attributes.event_mask = gtk_widget_get_events (widget) | 
 
11939
    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
 
11940
    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
 
11941
    GDK_POINTER_MOTION_HINT_MASK;
 
11942
  attributes.visual = gtk_widget_get_visual (widget);
 
11943
  attributes.colormap = gtk_widget_get_colormap (widget);
 
11944
 
 
11945
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
 
11946
  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
 
11947
 
 
11948
  widget->style = gtk_style_attach (widget->style, widget->window);
 
11949
 
 
11950
  gdk_window_set_user_data (widget->window, widget);
 
11951
 
 
11952
  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
 
11953
}
 
11954
</programlisting>
 
11955
 
 
11956
</sect2>
 
11957
 
 
11958
<!-- ----------------------------------------------------------------- -->
 
11959
<sect2>
 
11960
<title>Size negotiation</title>
 
11961
 
 
11962
<para>Before the first time that the window containing a widget is
 
11963
displayed, and whenever the layout of the window changes, GTK asks
 
11964
each child widget for its desired size. This request is handled by the
 
11965
function <literal>gtk_dial_size_request()</literal>. Since our widget isn't a
 
11966
container widget, and has no real constraints on its size, we just
 
11967
return a reasonable default value.</para>
 
11968
 
 
11969
<programlisting role="C">
 
11970
static void 
 
11971
gtk_dial_size_request (GtkWidget      *widget,
 
11972
                       GtkRequisition *requisition)
 
11973
{
 
11974
  requisition->width = DIAL_DEFAULT_SIZE;
 
11975
  requisition->height = DIAL_DEFAULT_SIZE;
 
11976
}
 
11977
</programlisting>
 
11978
 
 
11979
<para>After all the widgets have requested an ideal size, the layout of the
 
11980
window is computed and each child widget is notified of its actual
 
11981
size. Usually, this will be at least as large as the requested size,
 
11982
but if for instance the user has resized the window, it may
 
11983
occasionally be smaller than the requested size. The size notification
 
11984
is handled by the function <literal>gtk_dial_size_allocate()</literal>. Notice that
 
11985
as well as computing the sizes of some component pieces for future
 
11986
use, this routine also does the grunt work of moving the widget's X
 
11987
window into the new position and size.</para>
 
11988
 
 
11989
<programlisting role="C">
 
11990
static void
 
11991
gtk_dial_size_allocate (GtkWidget     *widget,
 
11992
                        GtkAllocation *allocation)
 
11993
{
 
11994
  GtkDial *dial;
 
11995
 
 
11996
  g_return_if_fail (widget != NULL);
 
11997
  g_return_if_fail (GTK_IS_DIAL (widget));
 
11998
  g_return_if_fail (allocation != NULL);
 
11999
 
 
12000
  widget->allocation = *allocation;
 
12001
  if (GTK_WIDGET_REALIZED (widget))
 
12002
    {
 
12003
      dial = GTK_DIAL (widget);
 
12004
 
 
12005
      gdk_window_move_resize (widget->window,
 
12006
                              allocation->x, allocation->y,
 
12007
                              allocation->width, allocation->height);
 
12008
 
 
12009
      dial->radius = MAX(allocation->width,allocation->height) * 0.45;
 
12010
      dial->pointer_width = dial->radius / 5;
 
12011
    }
 
12012
}
 
12013
</programlisting>
 
12014
 
 
12015
</sect2>
 
12016
 
 
12017
<!-- ----------------------------------------------------------------- -->
 
12018
<sect2>
 
12019
<title><literal>gtk_dial_expose()</literal></title>
 
12020
 
 
12021
<para>As mentioned above, all the drawing of this widget is done in the
 
12022
handler for expose events. There's not much to remark on here except
 
12023
the use of the function <literal>gtk_draw_polygon</literal> to draw the pointer with
 
12024
three dimensional shading according to the colors stored in the
 
12025
widget's style.</para>
 
12026
 
 
12027
<programlisting role="C">
 
12028
static gboolean
 
12029
gtk_dial_expose( GtkWidget      *widget,
 
12030
                 GdkEventExpose *event )
 
12031
{
 
12032
  GtkDial *dial;
 
12033
  GdkPoint points[3];
 
12034
  gdouble s,c;
 
12035
  gdouble theta;
 
12036
  gint xc, yc;
 
12037
  gint tick_length;
 
12038
  gint i;
 
12039
 
 
12040
  g_return_val_if_fail (widget != NULL, FALSE);
 
12041
  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
 
12042
  g_return_val_if_fail (event != NULL, FALSE);
 
12043
 
 
12044
  if (event->count > 0)
 
12045
    return FALSE;
 
12046
  
 
12047
  dial = GTK_DIAL (widget);
 
12048
 
 
12049
  gdk_window_clear_area (widget->window,
 
12050
                         0, 0,
 
12051
                         widget->allocation.width,
 
12052
                         widget->allocation.height);
 
12053
 
 
12054
  xc = widget->allocation.width/2;
 
12055
  yc = widget->allocation.height/2;
 
12056
 
 
12057
  /* Draw ticks */
 
12058
 
 
12059
  for (i=0; i<25; i++)
 
12060
    {
 
12061
      theta = (i*M_PI/18. - M_PI/6.);
 
12062
      s = sin(theta);
 
12063
      c = cos(theta);
 
12064
 
 
12065
      tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
 
12066
      
 
12067
      gdk_draw_line (widget->window,
 
12068
                     widget->style->fg_gc[widget->state],
 
12069
                     xc + c*(dial->radius - tick_length),
 
12070
                     yc - s*(dial->radius - tick_length),
 
12071
                     xc + c*dial->radius,
 
12072
                     yc - s*dial->radius);
 
12073
    }
 
12074
 
 
12075
  /* Draw pointer */
 
12076
 
 
12077
  s = sin(dial->angle);
 
12078
  c = cos(dial->angle);
 
12079
 
 
12080
 
 
12081
  points[0].x = xc + s*dial->pointer_width/2;
 
12082
  points[0].y = yc + c*dial->pointer_width/2;
 
12083
  points[1].x = xc + c*dial->radius;
 
12084
  points[1].y = yc - s*dial->radius;
 
12085
  points[2].x = xc - s*dial->pointer_width/2;
 
12086
  points[2].y = yc - c*dial->pointer_width/2;
 
12087
 
 
12088
  gtk_draw_polygon (widget->style,
 
12089
                    widget->window,
 
12090
                    GTK_STATE_NORMAL,
 
12091
                    GTK_SHADOW_OUT,
 
12092
                    points, 3,
 
12093
                    TRUE);
 
12094
  
 
12095
  return FALSE;
 
12096
}
 
12097
</programlisting>
 
12098
 
 
12099
</sect2>
 
12100
 
 
12101
<!-- ----------------------------------------------------------------- -->
 
12102
<sect2>
 
12103
<title>Event handling</title>
 
12104
 
 
12105
<para>The rest of the widget's code handles various types of events, and
 
12106
isn't too different from what would be found in many GTK
 
12107
applications. Two types of events can occur - either the user can
 
12108
click on the widget with the mouse and drag to move the pointer, or
 
12109
the value of the Adjustment object can change due to some external
 
12110
circumstance.</para>
 
12111
 
 
12112
<para>When the user clicks on the widget, we check to see if the click was
 
12113
appropriately near the pointer, and if so, store the button that the
 
12114
user clicked with in the <literal>button</literal> field of the widget
 
12115
structure, and grab all mouse events with a call to
 
12116
<literal>gtk_grab_add()</literal>. Subsequent motion of the mouse causes the
 
12117
value of the control to be recomputed (by the function
 
12118
<literal>gtk_dial_update_mouse</literal>). Depending on the policy that has been
 
12119
set, "value_changed" events are either generated instantly
 
12120
(<literal>GTK_UPDATE_CONTINUOUS</literal>), after a delay in a timer added with
 
12121
<literal>g_timeout_add()</literal> (<literal>GTK_UPDATE_DELAYED</literal>), or only when the
 
12122
button is released (<literal>GTK_UPDATE_DISCONTINUOUS</literal>).</para>
 
12123
 
 
12124
<programlisting role="C">
 
12125
static gboolean
 
12126
gtk_dial_button_press( GtkWidget      *widget,
 
12127
                       GdkEventButton *event )
 
12128
{
 
12129
  GtkDial *dial;
 
12130
  gint dx, dy;
 
12131
  double s, c;
 
12132
  double d_parallel;
 
12133
  double d_perpendicular;
 
12134
 
 
12135
  g_return_val_if_fail (widget != NULL, FALSE);
 
12136
  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
 
12137
  g_return_val_if_fail (event != NULL, FALSE);
 
12138
 
 
12139
  dial = GTK_DIAL (widget);
 
12140
 
 
12141
  /* Determine if button press was within pointer region - we 
 
12142
     do this by computing the parallel and perpendicular distance of
 
12143
     the point where the mouse was pressed from the line passing through
 
12144
     the pointer */
 
12145
  
 
12146
  dx = event->x - widget->allocation.width / 2;
 
12147
  dy = widget->allocation.height / 2 - event->y;
 
12148
  
 
12149
  s = sin(dial->angle);
 
12150
  c = cos(dial->angle);
 
12151
  
 
12152
  d_parallel = s*dy + c*dx;
 
12153
  d_perpendicular = fabs(s*dx - c*dy);
 
12154
  
 
12155
  if (!dial->button &&
 
12156
      (d_perpendicular < dial->pointer_width/2) &&
 
12157
      (d_parallel > - dial->pointer_width))
 
12158
    {
 
12159
      gtk_grab_add (widget);
 
12160
 
 
12161
      dial->button = event->button;
 
12162
 
 
12163
      gtk_dial_update_mouse (dial, event->x, event->y);
 
12164
    }
 
12165
 
 
12166
  return FALSE;
 
12167
}
 
12168
 
 
12169
static gboolean
 
12170
gtk_dial_button_release( GtkWidget      *widget,
 
12171
                         GdkEventButton *event )
 
12172
{
 
12173
  GtkDial *dial;
 
12174
 
 
12175
  g_return_val_if_fail (widget != NULL, FALSE);
 
12176
  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
 
12177
  g_return_val_if_fail (event != NULL, FALSE);
 
12178
 
 
12179
  dial = GTK_DIAL (widget);
 
12180
 
 
12181
  if (dial->button == event->button)
 
12182
    {
 
12183
      gtk_grab_remove (widget);
 
12184
 
 
12185
      dial->button = 0;
 
12186
 
 
12187
      if (dial->policy == GTK_UPDATE_DELAYED)
 
12188
        g_source_remove (dial->timer);
 
12189
      
 
12190
      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
 
12191
          (dial->old_value != dial->adjustment->value))
 
12192
        gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
 
12193
    }
 
12194
 
 
12195
  return FALSE;
 
12196
}
 
12197
 
 
12198
static gboolean
 
12199
gtk_dial_motion_notify( GtkWidget      *widget,
 
12200
                        GdkEventMotion *event )
 
12201
{
 
12202
  GtkDial *dial;
 
12203
  GdkModifierType mods;
 
12204
  gint x, y, mask;
 
12205
 
 
12206
  g_return_val_if_fail (widget != NULL, FALSE);
 
12207
  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
 
12208
  g_return_val_if_fail (event != NULL, FALSE);
 
12209
 
 
12210
  dial = GTK_DIAL (widget);
 
12211
 
 
12212
  if (dial->button != 0)
 
12213
    {
 
12214
      x = event->x;
 
12215
      y = event->y;
 
12216
 
 
12217
      if (event->is_hint || (event->window != widget->window))
 
12218
        gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
 
12219
 
 
12220
      switch (dial->button)
 
12221
        {
 
12222
        case 1:
 
12223
          mask = GDK_BUTTON1_MASK;
 
12224
          break;
 
12225
        case 2:
 
12226
          mask = GDK_BUTTON2_MASK;
 
12227
          break;
 
12228
        case 3:
 
12229
          mask = GDK_BUTTON3_MASK;
 
12230
          break;
 
12231
        default:
 
12232
          mask = 0;
 
12233
          break;
 
12234
        }
 
12235
 
 
12236
      if (mods & mask)
 
12237
        gtk_dial_update_mouse (dial, x,y);
 
12238
    }
 
12239
 
 
12240
  return FALSE;
 
12241
}
 
12242
 
 
12243
static gboolean
 
12244
gtk_dial_timer( GtkDial *dial )
 
12245
{
 
12246
  g_return_val_if_fail (dial != NULL, FALSE);
 
12247
  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
 
12248
 
 
12249
  if (dial->policy == GTK_UPDATE_DELAYED)
 
12250
    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
 
12251
 
 
12252
  return FALSE;
 
12253
}
 
12254
 
 
12255
static void
 
12256
gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
 
12257
{
 
12258
  gint xc, yc;
 
12259
  gfloat old_value;
 
12260
 
 
12261
  g_return_if_fail (dial != NULL);
 
12262
  g_return_if_fail (GTK_IS_DIAL (dial));
 
12263
 
 
12264
  xc = GTK_WIDGET(dial)->allocation.width / 2;
 
12265
  yc = GTK_WIDGET(dial)->allocation.height / 2;
 
12266
 
 
12267
  old_value = dial->adjustment->value;
 
12268
  dial->angle = atan2(yc-y, x-xc);
 
12269
 
 
12270
  if (dial->angle < -M_PI/2.)
 
12271
    dial->angle += 2*M_PI;
 
12272
 
 
12273
  if (dial->angle < -M_PI/6)
 
12274
    dial->angle = -M_PI/6;
 
12275
 
 
12276
  if (dial->angle > 7.*M_PI/6.)
 
12277
    dial->angle = 7.*M_PI/6.;
 
12278
 
 
12279
  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
 
12280
    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
 
12281
 
 
12282
  if (dial->adjustment->value != old_value)
 
12283
    {
 
12284
      if (dial->policy == GTK_UPDATE_CONTINUOUS)
 
12285
        {
 
12286
          gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
 
12287
        }
 
12288
      else
 
12289
        {
 
12290
          gtk_widget_draw (GTK_WIDGET(dial), NULL);
 
12291
 
 
12292
          if (dial->policy == GTK_UPDATE_DELAYED)
 
12293
            {
 
12294
              if (dial->timer)
 
12295
                g_source_remove (dial->timer);
 
12296
 
 
12297
              dial->timer = g_timeout_add (SCROLL_DELAY_LENGTH,
 
12298
                                           (GtkFunction) gtk_dial_timer,
 
12299
                                           (gpointer) dial);
 
12300
            }
 
12301
        }
 
12302
    }
 
12303
}
 
12304
</programlisting>
 
12305
 
 
12306
<para>Changes to the Adjustment by external means are communicated to our
 
12307
widget by the "changed" and "value_changed" signals. The handlers
 
12308
for these functions call <literal>gtk_dial_update()</literal> to validate the
 
12309
arguments, compute the new pointer angle, and redraw the widget (by
 
12310
calling <literal>gtk_widget_draw()</literal>).</para>
 
12311
 
 
12312
<programlisting role="C">
 
12313
static void
 
12314
gtk_dial_update (GtkDial *dial)
 
12315
{
 
12316
  gfloat new_value;
 
12317
  
 
12318
  g_return_if_fail (dial != NULL);
 
12319
  g_return_if_fail (GTK_IS_DIAL (dial));
 
12320
 
 
12321
  new_value = dial->adjustment->value;
 
12322
  
 
12323
  if (new_value < dial->adjustment->lower)
 
12324
    new_value = dial->adjustment->lower;
 
12325
 
 
12326
  if (new_value > dial->adjustment->upper)
 
12327
    new_value = dial->adjustment->upper;
 
12328
 
 
12329
  if (new_value != dial->adjustment->value)
 
12330
    {
 
12331
      dial->adjustment->value = new_value;
 
12332
      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
 
12333
    }
 
12334
 
 
12335
  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
 
12336
    (dial->adjustment->upper - dial->adjustment->lower);
 
12337
 
 
12338
  gtk_widget_draw (GTK_WIDGET(dial), NULL);
 
12339
}
 
12340
 
 
12341
static void
 
12342
gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
 
12343
                              gpointer       data)
 
12344
{
 
12345
  GtkDial *dial;
 
12346
 
 
12347
  g_return_if_fail (adjustment != NULL);
 
12348
  g_return_if_fail (data != NULL);
 
12349
 
 
12350
  dial = GTK_DIAL (data);
 
12351
 
 
12352
  if ((dial->old_value != adjustment->value) ||
 
12353
      (dial->old_lower != adjustment->lower) ||
 
12354
      (dial->old_upper != adjustment->upper))
 
12355
    {
 
12356
      gtk_dial_update (dial);
 
12357
 
 
12358
      dial->old_value = adjustment->value;
 
12359
      dial->old_lower = adjustment->lower;
 
12360
      dial->old_upper = adjustment->upper;
 
12361
    }
 
12362
}
 
12363
 
 
12364
static void
 
12365
gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
 
12366
                                    gpointer       data)
 
12367
{
 
12368
  GtkDial *dial;
 
12369
 
 
12370
  g_return_if_fail (adjustment != NULL);
 
12371
  g_return_if_fail (data != NULL);
 
12372
 
 
12373
  dial = GTK_DIAL (data);
 
12374
 
 
12375
  if (dial->old_value != adjustment->value)
 
12376
    {
 
12377
      gtk_dial_update (dial);
 
12378
 
 
12379
      dial->old_value = adjustment->value;
 
12380
    }
 
12381
}
 
12382
</programlisting>
 
12383
 
 
12384
</sect2>
 
12385
 
 
12386
<!-- ----------------------------------------------------------------- -->
 
12387
<sect2>
 
12388
<title>Possible Enhancements</title>
 
12389
 
 
12390
<para>The Dial widget as we've described it so far runs about 670 lines of
 
12391
code. Although that might sound like a fair bit, we've really
 
12392
accomplished quite a bit with that much code, especially since much of
 
12393
that length is headers and boilerplate. However, there are quite a few
 
12394
more enhancements that could be made to this widget:</para>
 
12395
 
 
12396
<itemizedlist>
 
12397
<listitem><simpara> If you try this widget out, you'll find that there is some
 
12398
flashing as the pointer is dragged around. This is because the entire
 
12399
widget is erased every time the pointer is moved before being
 
12400
redrawn. Often, the best way to handle this problem is to draw to an
 
12401
offscreen pixmap, then copy the final results onto the screen in one
 
12402
step. (The ProgressBar widget draws itself in this fashion.)</simpara>
 
12403
</listitem>
 
12404
 
 
12405
<listitem><simpara> The user should be able to use the up and down arrow keys to
 
12406
increase and decrease the value.</simpara>
 
12407
</listitem>
 
12408
 
 
12409
<listitem><simpara> It would be nice if the widget had buttons to increase and
 
12410
decrease the value in small or large steps. Although it would be
 
12411
possible to use embedded Button widgets for this, we would also like
 
12412
the buttons to auto-repeat when held down, as the arrows on a
 
12413
scrollbar do. Most of the code to implement this type of behavior can
 
12414
be found in the Range widget.</simpara>
 
12415
</listitem>
 
12416
 
 
12417
<listitem><simpara> The Dial widget could be made into a container widget with a
 
12418
single child widget positioned at the bottom between the buttons
 
12419
mentioned above. The user could then add their choice of a label or
 
12420
entry widget to display the current value of the dial.</simpara>
 
12421
</listitem>
 
12422
</itemizedlist>
 
12423
 
 
12424
</sect2>
 
12425
</sect1>
 
12426
 
 
12427
<!-- ----------------------------------------------------------------- -->
 
12428
<sect1 id="sec-LearningMore">
 
12429
<title>Learning More</title>
 
12430
 
 
12431
<para>Only a small part of the many details involved in creating widgets
 
12432
could be described above. If you want to write your own widgets, the
 
12433
best source of examples is the GTK source itself. Ask yourself some
 
12434
questions about the widget you want to write: IS it a Container
 
12435
widget? Does it have its own window? Is it a modification of an
 
12436
existing widget? Then find a similar widget, and start making changes.
 
12437
Good luck!</para>
 
12438
 
 
12439
</sect1>
 
12440
</chapter>
 
12441
 
 
12442
<!-- ***************************************************************** -->
 
12443
<chapter id="ch-Scribble">
 
12444
<title>Scribble, A Simple Example Drawing Program</title>
 
12445
 
 
12446
<!-- ----------------------------------------------------------------- -->
 
12447
<sect1 id="sec-ScribbleOverview">
 
12448
<title>Overview</title>
 
12449
 
 
12450
<para>In this section, we will build a simple drawing program. In the
 
12451
process, we will examine how to handle mouse events, how to draw in a
 
12452
window, and how to do drawing better by using a backing pixmap. After
 
12453
creating the simple drawing program, we will extend it by adding
 
12454
support for XInput devices, such as drawing tablets. GTK provides
 
12455
support routines which makes getting extended information, such as
 
12456
pressure and tilt, from such devices quite easy.</para>
 
12457
 
 
12458
<para>
 
12459
<inlinemediaobject>
 
12460
<imageobject>
 
12461
<imagedata fileref="images/scribble.png" format="png">
 
12462
</imageobject>
 
12463
</inlinemediaobject>
 
12464
</para>
 
12465
 
 
12466
</sect1>
 
12467
 
 
12468
<!-- ----------------------------------------------------------------- -->
 
12469
<sect1 id="sec-EventHandling">
 
12470
<title>Event Handling</title>
 
12471
 
 
12472
<para>The GTK signals we have already discussed are for high-level actions,
 
12473
such as a menu item being selected. However, sometimes it is useful to
 
12474
learn about lower-level occurrences, such as the mouse being moved, or
 
12475
a key being pressed. There are also GTK signals corresponding to these
 
12476
low-level <emphasis>events</emphasis>. The handlers for these signals have an
 
12477
extra parameter which is a pointer to a structure containing
 
12478
information about the event. For instance, motion event handlers are
 
12479
passed a pointer to a GdkEventMotion structure which looks (in part)
 
12480
like:</para>
 
12481
 
 
12482
<programlisting role="C">
 
12483
struct _GdkEventMotion
 
12484
{
 
12485
  GdkEventType type;
 
12486
  GdkWindow *window;
 
12487
  guint32 time;
 
12488
  gdouble x;
 
12489
  gdouble y;
 
12490
  ...
 
12491
  guint state;
 
12492
  ...
 
12493
};
 
12494
</programlisting>
 
12495
 
 
12496
<para><literal>type</literal> will be set to the event type, in this case
 
12497
<literal>GDK_MOTION_NOTIFY</literal>, window is the window in which the event
 
12498
occurred. <literal>x</literal> and <literal>y</literal> give the coordinates of the event.
 
12499
<literal>state</literal> specifies the modifier state when the event
 
12500
occurred (that is, it specifies which modifier keys and mouse buttons
 
12501
were pressed). It is the bitwise OR of some of the following:</para>
 
12502
 
 
12503
<programlisting role="C">
 
12504
GDK_SHIFT_MASK  
 
12505
GDK_LOCK_MASK   
 
12506
GDK_CONTROL_MASK
 
12507
GDK_MOD1_MASK   
 
12508
GDK_MOD2_MASK   
 
12509
GDK_MOD3_MASK   
 
12510
GDK_MOD4_MASK   
 
12511
GDK_MOD5_MASK   
 
12512
GDK_BUTTON1_MASK
 
12513
GDK_BUTTON2_MASK
 
12514
GDK_BUTTON3_MASK
 
12515
GDK_BUTTON4_MASK
 
12516
GDK_BUTTON5_MASK
 
12517
</programlisting>
 
12518
 
 
12519
<para>As for other signals, to determine what happens when an event occurs
 
12520
we call <literal>gtk_signal_connect()</literal>. But we also need let GTK
 
12521
know which events we want to be notified about. To do this, we call
 
12522
the function:</para>
 
12523
 
 
12524
<programlisting role="C">
 
12525
void gtk_widget_set_events (GtkWidget *widget,
 
12526
                            gint      events);
 
12527
</programlisting>
 
12528
 
 
12529
<para>The second field specifies the events we are interested in. It
 
12530
is the bitwise OR of constants that specify different types
 
12531
of events. For future reference the event types are:</para>
 
12532
 
 
12533
<programlisting role="C">
 
12534
GDK_EXPOSURE_MASK
 
12535
GDK_POINTER_MOTION_MASK
 
12536
GDK_POINTER_MOTION_HINT_MASK
 
12537
GDK_BUTTON_MOTION_MASK     
 
12538
GDK_BUTTON1_MOTION_MASK    
 
12539
GDK_BUTTON2_MOTION_MASK    
 
12540
GDK_BUTTON3_MOTION_MASK    
 
12541
GDK_BUTTON_PRESS_MASK      
 
12542
GDK_BUTTON_RELEASE_MASK    
 
12543
GDK_KEY_PRESS_MASK         
 
12544
GDK_KEY_RELEASE_MASK       
 
12545
GDK_ENTER_NOTIFY_MASK      
 
12546
GDK_LEAVE_NOTIFY_MASK      
 
12547
GDK_FOCUS_CHANGE_MASK      
 
12548
GDK_STRUCTURE_MASK         
 
12549
GDK_PROPERTY_CHANGE_MASK   
 
12550
GDK_PROXIMITY_IN_MASK      
 
12551
GDK_PROXIMITY_OUT_MASK     
 
12552
</programlisting>
 
12553
 
 
12554
<para>There are a few subtle points that have to be observed when calling
 
12555
<literal>gtk_widget_set_events()</literal>. First, it must be called before the X window
 
12556
for a GTK widget is created. In practical terms, this means you
 
12557
should call it immediately after creating the widget. Second, the
 
12558
widget must have an associated X window. For efficiency, many widget
 
12559
types do not have their own window, but draw in their parent's window.
 
12560
These widgets are:</para>
 
12561
 
 
12562
<programlisting role="C">
 
12563
GtkAlignment
 
12564
GtkArrow
 
12565
GtkBin
 
12566
GtkBox
 
12567
GtkImage
 
12568
GtkItem
 
12569
GtkLabel
 
12570
GtkPixmap
 
12571
GtkScrolledWindow
 
12572
GtkSeparator
 
12573
GtkTable
 
12574
GtkAspectFrame
 
12575
GtkFrame
 
12576
GtkVBox
 
12577
GtkHBox
 
12578
GtkVSeparator
 
12579
GtkHSeparator
 
12580
</programlisting>
 
12581
 
 
12582
<para>To capture events for these widgets, you need to use an EventBox
 
12583
widget. See the section on the <link linkend="sec-EventBox">EventBox</link> widget for details.</para>
 
12584
 
 
12585
<para>For our drawing program, we want to know when the mouse button is
 
12586
pressed and when the mouse is moved, so we specify
 
12587
<literal>GDK_POINTER_MOTION_MASK</literal> and <literal>GDK_BUTTON_PRESS_MASK</literal>. We also
 
12588
want to know when we need to redraw our window, so we specify
 
12589
<literal>GDK_EXPOSURE_MASK</literal>. Although we want to be notified via a
 
12590
Configure event when our window size changes, we don't have to specify
 
12591
the corresponding <literal>GDK_STRUCTURE_MASK</literal> flag, because it is
 
12592
automatically specified for all windows.</para>
 
12593
 
 
12594
<para>It turns out, however, that there is a problem with just specifying
 
12595
<literal>GDK_POINTER_MOTION_MASK</literal>. This will cause the server to add a new
 
12596
motion event to the event queue every time the user moves the mouse.
 
12597
Imagine that it takes us 0.1 seconds to handle a motion event, but the
 
12598
X server queues a new motion event every 0.05 seconds. We will soon
 
12599
get way behind the users drawing. If the user draws for 5 seconds,
 
12600
it will take us another 5 seconds to catch up after they release 
 
12601
the mouse button! What we would like is to only get one motion
 
12602
event for each event we process. The way to do this is to 
 
12603
specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>. </para>
 
12604
 
 
12605
<para>When we specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>, the server sends
 
12606
us a motion event the first time the pointer moves after entering
 
12607
our window, or after a button press or release event. Subsequent 
 
12608
motion events will be suppressed until we explicitly ask for
 
12609
the position of the pointer using the function:</para>
 
12610
 
 
12611
<programlisting role="C">
 
12612
GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
 
12613
                                          gint            *x,
 
12614
                                          gint            *y,
 
12615
                                          GdkModifierType *mask);
 
12616
</programlisting>
 
12617
 
 
12618
<para>(There is another function, <literal>gtk_widget_get_pointer()</literal> which
 
12619
has a simpler interface, but turns out not to be very useful, since
 
12620
it only retrieves the position of the mouse, not whether the buttons
 
12621
are pressed.)</para>
 
12622
 
 
12623
<para>The code to set the events for our window then looks like:</para>
 
12624
 
 
12625
<programlisting role="C">
 
12626
  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
 
12627
                      (GtkSignalFunc) expose_event, NULL);
 
12628
  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
 
12629
                      (GtkSignalFunc) configure_event, NULL);
 
12630
  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
 
12631
                      (GtkSignalFunc) motion_notify_event, NULL);
 
12632
  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
 
12633
                      (GtkSignalFunc) button_press_event, NULL);
 
12634
 
 
12635
  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
 
12636
                         | GDK_LEAVE_NOTIFY_MASK
 
12637
                         | GDK_BUTTON_PRESS_MASK
 
12638
                         | GDK_POINTER_MOTION_MASK
 
12639
                         | GDK_POINTER_MOTION_HINT_MASK);
 
12640
</programlisting>
 
12641
 
 
12642
<para>We'll save the "expose_event" and "configure_event" handlers for
 
12643
later. The "motion_notify_event" and "button_press_event" handlers
 
12644
are pretty simple:</para>
 
12645
 
 
12646
<programlisting role="C">
 
12647
static gboolean
 
12648
button_press_event( GtkWidget *widget, GdkEventButton *event )
 
12649
{
 
12650
  if (event->button == 1 &amp;&amp; pixmap != NULL)
 
12651
      draw_brush (widget, event->x, event->y);
 
12652
 
 
12653
  return TRUE;
 
12654
}
 
12655
 
 
12656
static gboolean
 
12657
motion_notify_event( GtkWidget *widget, GdkEventMotion *event )
 
12658
{
 
12659
  int x, y;
 
12660
  GdkModifierType state;
 
12661
 
 
12662
  if (event->is_hint)
 
12663
    gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
 
12664
  else
 
12665
    {
 
12666
      x = event->x;
 
12667
      y = event->y;
 
12668
      state = event->state;
 
12669
    }
 
12670
    
 
12671
  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
 
12672
    draw_brush (widget, x, y);
 
12673
  
 
12674
  return TRUE;
 
12675
}
 
12676
</programlisting>
 
12677
 
 
12678
</sect1>
 
12679
 
 
12680
<!-- ----------------------------------------------------------------- -->
 
12681
<sect1 id="sec-TheDrawingAreaWidget">
 
12682
<title>The DrawingArea Widget, And Drawing</title>
 
12683
 
 
12684
<para>We now turn to the process of drawing on the screen. The 
 
12685
widget we use for this is the DrawingArea widget. A drawing area
 
12686
widget is essentially an X window and nothing more. It is a blank
 
12687
canvas in which we can draw whatever we like. A drawing area
 
12688
is created using the call:</para>
 
12689
 
 
12690
<programlisting role="C">
 
12691
GtkWidget* gtk_drawing_area_new        (void);
 
12692
</programlisting>
 
12693
 
 
12694
<para>A default size for the widget can be specified by calling:</para>
 
12695
 
 
12696
<programlisting role="C">
 
12697
void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
 
12698
                                        gint                 width,
 
12699
                                        gint                 height);
 
12700
</programlisting>
 
12701
 
 
12702
<para>This default size can be overridden, as is true for all widgets,
 
12703
by calling <literal>gtk_widget_set_size_request()</literal>, and that, in turn, can
 
12704
be overridden if the user manually resizes the the window containing
 
12705
the drawing area.</para>
 
12706
 
 
12707
<para>It should be noted that when we create a DrawingArea widget, we are
 
12708
<emphasis>completely</emphasis> responsible for drawing the contents. If our
 
12709
window is obscured then uncovered, we get an exposure event and must
 
12710
redraw what was previously hidden.</para>
 
12711
 
 
12712
<para>Having to remember everything that was drawn on the screen so we
 
12713
can properly redraw it can, to say the least, be a nuisance. In
 
12714
addition, it can be visually distracting if portions of the
 
12715
window are cleared, then redrawn step by step. The solution to
 
12716
this problem is to use an offscreen <emphasis>backing pixmap</emphasis>.
 
12717
Instead of drawing directly to the screen, we draw to an image
 
12718
stored in server memory but not displayed, then when the image
 
12719
changes or new portions of the image are displayed, we copy the
 
12720
relevant portions onto the screen.</para>
 
12721
 
 
12722
<para>To create an offscreen pixmap, we call the function:</para>
 
12723
 
 
12724
<programlisting role="C">
 
12725
GdkPixmap* gdk_pixmap_new               (GdkWindow  *window,
 
12726
                                         gint        width,
 
12727
                                         gint        height,
 
12728
                                         gint        depth);
 
12729
</programlisting>
 
12730
 
 
12731
<para>The <literal>window</literal> parameter specifies a GDK window that this pixmap
 
12732
takes some of its properties from. <literal>width</literal> and <literal>height</literal>
 
12733
specify the size of the pixmap. <literal>depth</literal> specifies the <emphasis>color
 
12734
depth</emphasis>, that is the number of bits per pixel, for the new window.
 
12735
If the depth is specified as <literal>-1</literal>, it will match the depth
 
12736
of <literal>window</literal>.</para>
 
12737
 
 
12738
<para>We create the pixmap in our "configure_event" handler. This event
 
12739
is generated whenever the window changes size, including when it
 
12740
is originally created.</para>
 
12741
 
 
12742
<programlisting role="C">
 
12743
/* Backing pixmap for drawing area */
 
12744
static GdkPixmap *pixmap = NULL;
 
12745
 
 
12746
/* Create a new backing pixmap of the appropriate size */
 
12747
static gboolean
 
12748
configure_event( GtkWidget *widget, GdkEventConfigure *event )
 
12749
{
 
12750
  if (pixmap)
 
12751
    g_object_unref(pixmap);
 
12752
 
 
12753
  pixmap = gdk_pixmap_new(widget->window,
 
12754
                          widget->allocation.width,
 
12755
                          widget->allocation.height,
 
12756
                          -1);
 
12757
  gdk_draw_rectangle (pixmap,
 
12758
                      widget->style->white_gc,
 
12759
                      TRUE,
 
12760
                      0, 0,
 
12761
                      widget->allocation.width,
 
12762
                      widget->allocation.height);
 
12763
 
 
12764
  return TRUE;
 
12765
}
 
12766
</programlisting>
 
12767
 
 
12768
<para>The call to <literal>gdk_draw_rectangle()</literal> clears the pixmap
 
12769
initially to white. We'll say more about that in a moment.</para>
 
12770
 
 
12771
<para>Our exposure event handler then simply copies the relevant portion
 
12772
of the pixmap onto the screen (we determine the area we need
 
12773
to redraw by using the event->area field of the exposure event):</para>
 
12774
 
 
12775
<programlisting role="C">
 
12776
/* Redraw the screen from the backing pixmap */
 
12777
static gboolean
 
12778
expose_event( GtkWidget *widget, GdkEventExpose *event )
 
12779
{
 
12780
  gdk_draw_drawable(widget->window,
 
12781
                    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
 
12782
                    pixmap,
 
12783
                    event->area.x, event->area.y,
 
12784
                    event->area.x, event->area.y,
 
12785
                    event->area.width, event->area.height);
 
12786
 
 
12787
  return FALSE;
 
12788
}
 
12789
</programlisting>
 
12790
 
 
12791
<para>We've now seen how to keep the screen up to date with our pixmap, but
 
12792
how do we actually draw interesting stuff on our pixmap?  There are a
 
12793
large number of calls in GTK's GDK library for drawing on
 
12794
<emphasis>drawables</emphasis>. A drawable is simply something that can be drawn
 
12795
upon. It can be a window, a pixmap, or a bitmap (a black and white
 
12796
image).  We've already seen two such calls above,
 
12797
<literal>gdk_draw_rectangle()</literal> and <literal>gdk_draw_drawable()</literal>. The
 
12798
complete list is:</para>
 
12799
 
 
12800
<programlisting role="C">
 
12801
gdk_draw_point ()
 
12802
gdk_draw_line ()
 
12803
gdk_draw_rectangle ()
 
12804
gdk_draw_arc ()
 
12805
gdk_draw_polygon ()
 
12806
gdk_draw_pixmap ()
 
12807
gdk_draw_bitmap ()
 
12808
gdk_draw_image ()
 
12809
gdk_draw_points ()
 
12810
gdk_draw_segments ()
 
12811
gdk_draw_lines ()
 
12812
gdk_draw_pixbuf ()
 
12813
gdk_draw_glyphs ()
 
12814
gdk_draw_layout_line ()
 
12815
gdk_draw_layout ()
 
12816
gdk_draw_layout_line_with_colors ()
 
12817
gdk_draw_layout_with_colors ()
 
12818
gdk_draw_glyphs_transformed ()
 
12819
gdk_draw_glyphs_trapezoids ()
 
12820
</programlisting>
 
12821
 
 
12822
<para>See the reference documentation or the header file
 
12823
<literal>&lt;gdk/gdkdrawable.h&gt;</literal> for further details on these functions.
 
12824
These functions all share the same first two arguments. The first
 
12825
argument is the drawable to draw upon, the second argument is a
 
12826
<emphasis>graphics context</emphasis> (GC).</para>
 
12827
 
 
12828
<para>A graphics context encapsulates information about things such as
 
12829
foreground and background color and line width. GDK has a full set of
 
12830
functions for creating and modifying graphics contexts, but to keep
 
12831
things simple we'll just use predefined graphics contexts. Each widget
 
12832
has an associated style. (Which can be modified in a gtkrc file, see
 
12833
the section GTK's rc file.) This, among other things, stores a number
 
12834
of graphics contexts. Some examples of accessing these graphics
 
12835
contexts are:</para>
 
12836
 
 
12837
<programlisting role="C">
 
12838
widget->style->white_gc
 
12839
widget->style->black_gc
 
12840
widget->style->fg_gc[GTK_STATE_NORMAL]
 
12841
widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
 
12842
</programlisting>
 
12843
 
 
12844
<para>The fields <literal>fg_gc</literal>, <literal>bg_gc</literal>, <literal>dark_gc</literal>, and
 
12845
<literal>light_gc</literal> are indexed by a parameter of type
 
12846
<literal>GtkStateType</literal> which can take on the values:</para>
 
12847
 
 
12848
<programlisting role="C">
 
12849
GTK_STATE_NORMAL,
 
12850
GTK_STATE_ACTIVE,
 
12851
GTK_STATE_PRELIGHT,
 
12852
GTK_STATE_SELECTED,
 
12853
GTK_STATE_INSENSITIVE
 
12854
</programlisting>
 
12855
 
 
12856
<para>For instance, for <literal>GTK_STATE_SELECTED</literal> the default foreground
 
12857
color is white and the default background color, dark blue.</para>
 
12858
 
 
12859
<para>Our function <literal>draw_brush()</literal>, which does the actual drawing
 
12860
on the screen, is then:</para>
 
12861
 
 
12862
<programlisting role="C">
 
12863
/* Draw a rectangle on the screen */
 
12864
static void
 
12865
draw_brush (GtkWidget *widget, gdouble x, gdouble y)
 
12866
{
 
12867
  GdkRectangle update_rect;
 
12868
 
 
12869
  update_rect.x = x - 5;
 
12870
  update_rect.y = y - 5;
 
12871
  update_rect.width = 10;
 
12872
  update_rect.height = 10;
 
12873
  gdk_draw_rectangle (pixmap,
 
12874
                      widget->style->black_gc,
 
12875
                      TRUE,
 
12876
                      update_rect.x, update_rect.y,
 
12877
                      update_rect.width, update_rect.height);
 
12878
  gtk_widget_queue_draw_area (widget,                 
 
12879
                              update_rect.x, update_rect.y,
 
12880
                              update_rect.width, update_rect.height);
 
12881
}
 
12882
</programlisting>
 
12883
 
 
12884
<para>After we draw the rectangle representing the brush onto the pixmap,
 
12885
we call the function:</para>
 
12886
 
 
12887
<programlisting role="C">
 
12888
void       gtk_widget_queue_draw_area (GtkWidget           *widget,
 
12889
                                       gint                 x,
 
12890
                                       gint                 y,
 
12891
                                       gint                 width,
 
12892
                                       gint                 height)
 
12893
</programlisting>
 
12894
 
 
12895
<para>which notifies X that the area given by the <literal>x</literal>, 
 
12896
<literal>y</literal>, <literal>width</literal> and <literal>height</literal> parameters
 
12897
needs to be updated. X will eventually generate an expose event
 
12898
(possibly combining the areas passed in several calls to
 
12899
<literal>gtk_widget_queue_draw_area()</literal>) which will cause our expose event handler
 
12900
to copy the relevant portions to the screen.</para>
 
12901
 
 
12902
<para>We have now covered the entire drawing program except for a few
 
12903
mundane details like creating the main window.</para>
 
12904
 
 
12905
</sect1>
 
12906
 
 
12907
<!-- ----------------------------------------------------------------- -->
 
12908
<sect1 id="sec-AddingXInputSupport">
 
12909
<title>Adding XInput support</title>
 
12910
 
 
12911
<para>It is now possible to buy quite inexpensive input devices such 
 
12912
as drawing tablets, which allow drawing with a much greater
 
12913
ease of artistic expression than does a mouse. The simplest way
 
12914
to use such devices is simply as a replacement for the mouse,
 
12915
but that misses out many of the advantages of these devices,
 
12916
such as:</para>
 
12917
 
 
12918
<itemizedlist>
 
12919
<listitem><simpara> Pressure sensitivity</simpara>
 
12920
</listitem>
 
12921
<listitem><simpara> Tilt reporting</simpara>
 
12922
</listitem>
 
12923
<listitem><simpara> Sub-pixel positioning</simpara>
 
12924
</listitem>
 
12925
<listitem><simpara> Multiple inputs (for example, a stylus with a point and eraser)</simpara>
 
12926
</listitem>
 
12927
</itemizedlist>
 
12928
 
 
12929
<para>For information about the XInput extension, see the <ulink
 
12930
url="http://www.gtk.org/~otaylor/xinput/howto/index.html">XInput HOWTO</ulink>.</para>
 
12931
 
 
12932
<para>If we examine the full definition of, for example, the GdkEventMotion
 
12933
structure, we see that it has fields to support extended device
 
12934
information.</para>
 
12935
 
 
12936
<programlisting role="C">
 
12937
struct _GdkEventMotion
 
12938
{
 
12939
  GdkEventType type;
 
12940
  GdkWindow *window;
 
12941
  guint32 time;
 
12942
  gdouble x;
 
12943
  gdouble y;
 
12944
  gdouble pressure;
 
12945
  gdouble xtilt;
 
12946
  gdouble ytilt;
 
12947
  guint state;
 
12948
  gint16 is_hint;
 
12949
  GdkInputSource source;
 
12950
  guint32 deviceid;
 
12951
};
 
12952
</programlisting>
 
12953
 
 
12954
<para><literal>pressure</literal> gives the pressure as a floating point number between
 
12955
0 and 1. <literal>xtilt</literal> and <literal>ytilt</literal> can take on values between 
 
12956
-1 and 1, corresponding to the degree of tilt in each direction.
 
12957
<literal>source</literal> and <literal>deviceid</literal> specify the device for which the
 
12958
event occurred in two different ways. <literal>source</literal> gives some simple
 
12959
information about the type of device. It can take the enumeration
 
12960
values:</para>
 
12961
 
 
12962
<programlisting role="C">
 
12963
GDK_SOURCE_MOUSE
 
12964
GDK_SOURCE_PEN
 
12965
GDK_SOURCE_ERASER
 
12966
GDK_SOURCE_CURSOR
 
12967
</programlisting>
 
12968
 
 
12969
<para><literal>deviceid</literal> specifies a unique numeric ID for the device. This can
 
12970
be used to find out further information about the device using the
 
12971
<literal>gdk_input_list_devices()</literal> call (see below). The special value
 
12972
<literal>GDK_CORE_POINTER</literal> is used for the core pointer device. (Usually
 
12973
the mouse.)</para>
 
12974
 
 
12975
<!-- ----------------------------------------------------------------- -->
 
12976
<sect2>
 
12977
<title>Enabling extended device information</title>
 
12978
 
 
12979
<para>To let GTK know about our interest in the extended device information,
 
12980
we merely have to add a single line to our program:</para>
 
12981
 
 
12982
<programlisting role="C">
 
12983
gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
 
12984
</programlisting>
 
12985
 
 
12986
<para>By giving the value <literal>GDK_EXTENSION_EVENTS_CURSOR</literal> we say that
 
12987
we are interested in extension events, but only if we don't have
 
12988
to draw our own cursor. See the section <link
 
12989
linkend="sec-FurtherSophistications"> Further Sophistications </link> below
 
12990
for more information about drawing the cursor. We could also 
 
12991
give the values <literal>GDK_EXTENSION_EVENTS_ALL</literal> if we were willing 
 
12992
to draw our own cursor, or <literal>GDK_EXTENSION_EVENTS_NONE</literal> to revert
 
12993
back to the default condition.</para>
 
12994
 
 
12995
<para>This is not completely the end of the story however. By default,
 
12996
no extension devices are enabled. We need a mechanism to allow
 
12997
users to enable and configure their extension devices. GTK provides
 
12998
the InputDialog widget to automate this process. The following
 
12999
procedure manages an InputDialog widget. It creates the dialog if
 
13000
it isn't present, and raises it to the top otherwise.</para>
 
13001
 
 
13002
<programlisting role="C">
 
13003
void
 
13004
input_dialog_destroy (GtkWidget *w, gpointer data)
 
13005
{
 
13006
  *((GtkWidget **)data) = NULL;
 
13007
}
 
13008
 
 
13009
void
 
13010
create_input_dialog ()
 
13011
{
 
13012
  static GtkWidget *inputd = NULL;
 
13013
 
 
13014
  if (!inputd)
 
13015
    {
 
13016
      inputd = gtk_input_dialog_new();
 
13017
 
 
13018
      gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
 
13019
                          (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
 
13020
      gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
 
13021
                                 "clicked",
 
13022
                                 (GtkSignalFunc)gtk_widget_hide,
 
13023
                                 GTK_OBJECT(inputd));
 
13024
      gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
 
13025
 
 
13026
      gtk_widget_show (inputd);
 
13027
    }
 
13028
  else
 
13029
    {
 
13030
      if (!GTK_WIDGET_MAPPED(inputd))
 
13031
        gtk_widget_show(inputd);
 
13032
      else
 
13033
        gdk_window_raise(inputd->window);
 
13034
    }
 
13035
}
 
13036
</programlisting>
 
13037
 
 
13038
<para>(You might want to take note of the way we handle this dialog.  By
 
13039
connecting to the "destroy" signal, we make sure that we don't keep a
 
13040
pointer to dialog around after it is destroyed - that could lead to a
 
13041
segfault.)</para>
 
13042
 
 
13043
<para>The InputDialog has two buttons "Close" and "Save", which by default
 
13044
have no actions assigned to them. In the above function we make
 
13045
"Close" hide the dialog, hide the "Save" button, since we don't
 
13046
implement saving of XInput options in this program.</para>
 
13047
 
 
13048
</sect2>
 
13049
 
 
13050
<!-- ----------------------------------------------------------------- -->
 
13051
<sect2>
 
13052
<title>Using extended device information</title>
 
13053
 
 
13054
<para>Once we've enabled the device, we can just use the extended 
 
13055
device information in the extra fields of the event structures.
 
13056
In fact, it is always safe to use this information since these
 
13057
fields will have reasonable default values even when extended
 
13058
events are not enabled.</para>
 
13059
 
 
13060
<para>Once change we do have to make is to call
 
13061
<literal>gdk_input_window_get_pointer()</literal> instead of
 
13062
<literal>gdk_window_get_pointer</literal>. This is necessary because
 
13063
<literal>gdk_window_get_pointer</literal> doesn't return the extended device
 
13064
information.</para>
 
13065
 
 
13066
<programlisting role="C">
 
13067
void gdk_input_window_get_pointer( GdkWindow       *window,
 
13068
                                   guint32         deviceid,
 
13069
                                   gdouble         *x,
 
13070
                                   gdouble         *y,
 
13071
                                   gdouble         *pressure,
 
13072
                                   gdouble         *xtilt,
 
13073
                                   gdouble         *ytilt,
 
13074
                                   GdkModifierType *mask);
 
13075
</programlisting>
 
13076
 
 
13077
<para>When calling this function, we need to specify the device ID as
 
13078
well as the window. Usually, we'll get the device ID from the
 
13079
<literal>deviceid</literal> field of an event structure. Again, this function
 
13080
will return reasonable values when extension events are not
 
13081
enabled. (In this case, <literal>event->deviceid</literal> will have the value
 
13082
<literal>GDK_CORE_POINTER</literal>).</para>
 
13083
 
 
13084
<para>So the basic structure of our button-press and motion event handlers
 
13085
doesn't change much - we just need to add code to deal with the
 
13086
extended information.</para>
 
13087
 
 
13088
<programlisting role="C">
 
13089
static gboolean
 
13090
button_press_event( GtkWidget *widget, GdkEventButton *event )
 
13091
{
 
13092
  print_button_press (event->deviceid);
 
13093
  
 
13094
  if (event->button == 1 &amp;&amp; pixmap != NULL)
 
13095
    draw_brush (widget, event->source, event->x, event->y, event->pressure);
 
13096
 
 
13097
  return TRUE;
 
13098
}
 
13099
 
 
13100
static gboolean
 
13101
motion_notify_event( GtkWidget *widget, GdkEventMotion *event )
 
13102
{
 
13103
  gdouble x, y;
 
13104
  gdouble pressure;
 
13105
  GdkModifierType state;
 
13106
 
 
13107
  if (event->is_hint)
 
13108
    gdk_input_window_get_pointer (event->window, event->deviceid,
 
13109
                                  &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
 
13110
  else
 
13111
    {
 
13112
      x = event->x;
 
13113
      y = event->y;
 
13114
      pressure = event->pressure;
 
13115
      state = event->state;
 
13116
    }
 
13117
    
 
13118
  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
 
13119
    draw_brush (widget, event->source, x, y, pressure);
 
13120
  
 
13121
  return TRUE;
 
13122
}
 
13123
</programlisting>
 
13124
 
 
13125
<para>We also need to do something with the new information. Our new
 
13126
<literal>draw_brush()</literal> function draws with a different color for
 
13127
each <literal>event->source</literal> and changes the brush size depending
 
13128
on the pressure.</para>
 
13129
 
 
13130
<programlisting role="C">
 
13131
/* Draw a rectangle on the screen, size depending on pressure,
 
13132
   and color on the type of device */
 
13133
static void
 
13134
draw_brush (GtkWidget *widget, GdkInputSource source,
 
13135
            gdouble x, gdouble y, gdouble pressure)
 
13136
{
 
13137
  GdkGC *gc;
 
13138
  GdkRectangle update_rect;
 
13139
 
 
13140
  switch (source)
 
13141
    {
 
13142
    case GDK_SOURCE_MOUSE:
 
13143
      gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
 
13144
      break;
 
13145
    case GDK_SOURCE_PEN:
 
13146
      gc = widget->style->black_gc;
 
13147
      break;
 
13148
    case GDK_SOURCE_ERASER:
 
13149
      gc = widget->style->white_gc;
 
13150
      break;
 
13151
    default:
 
13152
      gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
 
13153
    }
 
13154
 
 
13155
  update_rect.x = x - 10 * pressure;
 
13156
  update_rect.y = y - 10 * pressure;
 
13157
  update_rect.width = 20 * pressure;
 
13158
  update_rect.height = 20 * pressure;
 
13159
  gdk_draw_rectangle (pixmap, gc, TRUE,
 
13160
                      update_rect.x, update_rect.y,
 
13161
                      update_rect.width, update_rect.height);
 
13162
  gtk_widget_draw (widget, &amp;update_rect);
 
13163
}
 
13164
</programlisting>
 
13165
 
 
13166
</sect2>
 
13167
 
 
13168
<!-- ----------------------------------------------------------------- -->
 
13169
<sect2>
 
13170
<title>Finding out more about a device</title>
 
13171
 
 
13172
<para>As an example of how to find out more about a device, our program
 
13173
will print the name of the device that generates each button
 
13174
press. To find out the name of a device, we call the function:</para>
 
13175
 
 
13176
<programlisting role="C">
 
13177
GList *gdk_input_list_devices               (void);
 
13178
</programlisting>
 
13179
 
 
13180
<para>which returns a GList (a linked list type from the GLib library)
 
13181
of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
 
13182
as:</para>
 
13183
 
 
13184
<programlisting role="C">
 
13185
struct _GdkDeviceInfo
 
13186
{
 
13187
  guint32 deviceid;
 
13188
  gchar *name;
 
13189
  GdkInputSource source;
 
13190
  GdkInputMode mode;
 
13191
  gint has_cursor;
 
13192
  gint num_axes;
 
13193
  GdkAxisUse *axes;
 
13194
  gint num_keys;
 
13195
  GdkDeviceKey *keys;
 
13196
};
 
13197
</programlisting>
 
13198
 
 
13199
<para>Most of these fields are configuration information that you can ignore
 
13200
unless you are implementing XInput configuration saving. The fieldwe
 
13201
are interested in here is <literal>name</literal> which is simply the name that X
 
13202
assigns to the device. The other field that isn't configuration
 
13203
information is <literal>has_cursor</literal>. If <literal>has_cursor</literal> is false, then we
 
13204
we need to draw our own cursor. But since we've specified
 
13205
<literal>GDK_EXTENSION_EVENTS_CURSOR</literal>, we don't have to worry about this.</para>
 
13206
 
 
13207
<para>Our <literal>print_button_press()</literal> function simply iterates through
 
13208
the returned list until it finds a match, then prints out
 
13209
the name of the device.</para>
 
13210
 
 
13211
<programlisting role="C">
 
13212
static void
 
13213
print_button_press (guint32 deviceid)
 
13214
{
 
13215
  GList *tmp_list;
 
13216
 
 
13217
  /* gdk_input_list_devices returns an internal list, so we shouldn't
 
13218
     free it afterwards */
 
13219
  tmp_list = gdk_input_list_devices();
 
13220
 
 
13221
  while (tmp_list)
 
13222
    {
 
13223
      GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
 
13224
 
 
13225
      if (info->deviceid == deviceid)
 
13226
        {
 
13227
          printf("Button press on device '%s'\n", info->name);
 
13228
          return;
 
13229
        }
 
13230
 
 
13231
      tmp_list = tmp_list->next;
 
13232
    }
 
13233
}
 
13234
</programlisting>
 
13235
 
 
13236
<para>That completes the changes to "XInputize" our program.</para>
 
13237
 
 
13238
</sect2>
 
13239
 
 
13240
<!-- ----------------------------------------------------------------- -->
 
13241
<sect2 id="sec-FurtherSophistications">
 
13242
<title>Further sophistications</title>
 
13243
 
 
13244
<para>Although our program now supports XInput quite well, it lacks some
 
13245
features we would want in a full-featured application. First, the user
 
13246
probably doesn't want to have to configure their device each time they
 
13247
run the program, so we should allow them to save the device
 
13248
configuration. This is done by iterating through the return of
 
13249
<literal>gdk_input_list_devices()</literal> and writing out the configuration to a
 
13250
file.</para>
 
13251
 
 
13252
<para>To restore the state next time the program is run, GDK provides
 
13253
functions to change device configuration:</para>
 
13254
 
 
13255
<programlisting role="C">
 
13256
gdk_input_set_extension_events()
 
13257
gdk_input_set_source()
 
13258
gdk_input_set_mode()
 
13259
gdk_input_set_axes()
 
13260
gdk_input_set_key()
 
13261
</programlisting>
 
13262
 
 
13263
<para>(The list returned from <literal>gdk_input_list_devices()</literal> should not be
 
13264
modified directly.) An example of doing this can be found in the
 
13265
drawing program gsumi. (Available from <ulink
 
13266
url="http://www.msc.cornell.edu/~otaylor/gsumi/">http://www.msc.cornell.edu/~otaylor/gsumi/</ulink>) Eventually, it
 
13267
would be nice to have a standard way of doing this for all
 
13268
applications. This probably belongs at a slightly higher level than
 
13269
GTK, perhaps in the GNOME library.</para>
 
13270
 
 
13271
<para>Another major omission that we have mentioned above is the lack of
 
13272
cursor drawing. Platforms other than XFree86 currently do not allow
 
13273
simultaneously using a device as both the core pointer and directly by
 
13274
an application. See the <ulink
 
13275
url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html">XInput-HOWTO</ulink> for more information about this. This means that
 
13276
applications that want to support the widest audience need to draw
 
13277
their own cursor.</para>
 
13278
 
 
13279
<para>An application that draws its own cursor needs to do two things:
 
13280
determine if the current device needs a cursor drawn or not, and
 
13281
determine if the current device is in proximity. (If the current
 
13282
device is a drawing tablet, it's a nice touch to make the cursor 
 
13283
disappear when the stylus is lifted from the tablet. When the
 
13284
device is touching the stylus, that is called "in proximity.")
 
13285
The first is done by searching the device list, as we did
 
13286
to find out the device name. The second is achieved by selecting
 
13287
"proximity_out" events. An example of drawing one's own cursor is
 
13288
found in the "testinput" program found in the GTK distribution.</para>
 
13289
 
 
13290
</sect2>
 
13291
 
 
13292
</sect1>
 
13293
</chapter>
 
13294
 
 
13295
<!-- ***************************************************************** -->
 
13296
<chapter id="ch-Tips">
 
13297
<title>Tips For Writing GTK Applications</title>
 
13298
 
 
13299
<para>This section is simply a gathering of wisdom, general style guidelines
 
13300
and hints to creating good GTK applications. Currently this section
 
13301
is very short, but I hope it will get longer in future editions of
 
13302
this tutorial.</para>
 
13303
 
 
13304
<para>Use GNU autoconf and automake! They are your friends :) Automake
 
13305
examines C files, determines how they depend on each other, and
 
13306
generates a Makefile so the files can be compiled in the correct
 
13307
order. Autoconf permits automatic configuration of software
 
13308
installation, handling a large number of system quirks to increase
 
13309
portability. I am planning to make a quick intro on them here.</para>
 
13310
 
 
13311
<para>When writing C code, use only C comments (beginning with "/*" and
 
13312
ending with "*/"), and don't use C++-style comments ("//").  Although
 
13313
many C compilers understand C++ comments, others don't, and the ANSI C
 
13314
standard does not require that C++-style comments be processed as
 
13315
comments.</para>
 
13316
 
 
13317
</chapter>
 
13318
 
 
13319
<!-- ***************************************************************** -->
 
13320
<chapter id="ch-Contributing">
 
13321
<title>Contributing</title>
 
13322
 
 
13323
<para>This document, like so much other great software out there, was
 
13324
created for free by volunteers.  If you are at all knowledgeable about
 
13325
any aspect of GTK that does not already have documentation, please
 
13326
consider contributing to this document.</para>
 
13327
 
 
13328
<para>If you do decide to contribute, please mail your text to Tony Gale,
 
13329
<literal><ulink url="mailto:gale@gtk.org">gale@gtk.org</ulink></literal>. Also, be aware that the entirety of this
 
13330
document is free, and any addition by you provide must also be
 
13331
free. That is, people may use any portion of your examples in their
 
13332
programs, and copies of this document may be distributed at will, etc.</para>
 
13333
 
 
13334
<para>Thank you.</para>
 
13335
 
 
13336
</chapter>
 
13337
 
 
13338
<!-- ***************************************************************** -->
 
13339
<chapter id="ch-Credits">
 
13340
<title>Credits</title>
 
13341
 
 
13342
<para>We would like to thank the following for their contributions to this text.</para>
 
13343
 
 
13344
<itemizedlist>
 
13345
<listitem><simpara>Bawer Dagdeviren, <literal><ulink url="mailto:chamele0n@geocities.com">chamele0n@geocities.com</ulink></literal> for the menus tutorial.</simpara>
 
13346
</listitem>
 
13347
 
 
13348
<listitem><simpara>Raph Levien, <literal><ulink url="mailto:raph@acm.org">raph@acm.org</ulink></literal>
 
13349
for hello world ala GTK, widget packing, and general all around wisdom.
 
13350
He's also generously donated a home for this tutorial.</simpara>
 
13351
</listitem>
 
13352
 
 
13353
<listitem><simpara>Peter Mattis, <literal><ulink url="mailto:petm@xcf.berkeley.edu">petm@xcf.berkeley.edu</ulink></literal> for the simplest GTK program.. 
 
13354
and the ability to make it :)</simpara>
 
13355
</listitem>
 
13356
 
 
13357
<listitem><simpara>Werner Koch <literal><ulink url="mailto:werner.koch@guug.de">werner.koch@guug.de</ulink></literal> for converting the original plain text to
 
13358
SGML, and the widget class hierarchy.</simpara>
 
13359
</listitem>
 
13360
 
 
13361
<listitem><simpara>Mark Crichton <literal><ulink
 
13362
url="mailto:crichton@expert.cc.purdue.edu">crichton@expert.cc.purdue.edu</ulink></literal> for the menu factory code,
 
13363
and the table packing tutorial.</simpara>
 
13364
</listitem>
 
13365
 
 
13366
<listitem><simpara>Owen Taylor <literal><ulink url="mailto:owt1@cornell.edu">owt1@cornell.edu</ulink></literal> for the EventBox widget section (and the
 
13367
patch to the distro).  He's also responsible for the selections code
 
13368
and tutorial, as well as the sections on writing your own GTK widgets,
 
13369
and the example application. Thanks a lot Owen for all you help!</simpara>
 
13370
</listitem>
 
13371
 
 
13372
<listitem><simpara>Mark VanderBoom <literal><ulink url="mailto:mvboom42@calvin.edu">mvboom42@calvin.edu</ulink></literal> for his wonderful work on the
 
13373
Notebook, Progress Bar, Dialogs, and File selection widgets.  Thanks a
 
13374
lot Mark!  You've been a great help.</simpara>
 
13375
</listitem>
 
13376
 
 
13377
<listitem><simpara>Tim Janik <literal><ulink url="mailto:timj@gtk.org">timj@gtk.org</ulink></literal> for his great job on the Lists
 
13378
Widget. His excellent work on automatically extracting the widget tree
 
13379
and signal information from GTK. Thanks Tim :)</simpara>
 
13380
</listitem>
 
13381
 
 
13382
<listitem><simpara>Rajat Datta <literal><ulink url="mailto:rajat@ix.netcom.com">rajat@ix.netcom.com</ulink>
 
13383
</literal> for the excellent job on the Pixmap
 
13384
tutorial.</simpara>
 
13385
</listitem>
 
13386
 
 
13387
<listitem><simpara>Michael K. Johnson <literal><ulink url="mailto:johnsonm@redhat.com">johnsonm@redhat.com</ulink></literal> for info and code for popup menus.</simpara>
 
13388
</listitem>
 
13389
 
 
13390
<listitem><simpara>David Huggins-Daines <literal><ulink
 
13391
url="mailto:bn711@freenet.carleton.ca">bn711@freenet.carleton.ca</ulink></literal> for the Range Widgets and Tree
 
13392
Widget sections.</simpara>
 
13393
</listitem>
 
13394
 
 
13395
<listitem><simpara>Stefan Mars <literal><ulink url="mailto:mars@lysator.liu.se">mars@lysator.liu.se</ulink></literal> for the CList section.</simpara>
 
13396
</listitem>
 
13397
 
 
13398
<listitem><simpara>David A. Wheeler <literal><ulink url="mailto:dwheeler@ida.org">dwheeler@ida.org</ulink></literal> for portions of the text on GLib
 
13399
and various tutorial fixups and improvements.
 
13400
The GLib text was in turn based on material developed by Damon Chaplin
 
13401
<literal><ulink url="mailto:DAChaplin@msn.com">DAChaplin@msn.com</ulink></literal></simpara>
 
13402
</listitem>
 
13403
 
 
13404
<listitem><simpara>David King for style checking the entire document.</simpara>
 
13405
</listitem>
 
13406
</itemizedlist>
 
13407
 
 
13408
<para>And to all of you who commented on and helped refine this document.</para>
 
13409
 
 
13410
<para>Thanks.</para>
 
13411
 
 
13412
</chapter>
 
13413
 
 
13414
<!-- ***************************************************************** -->
 
13415
<chapter id="ch-Copyright">
 
13416
<title>Tutorial Copyright and Permissions Notice</title>
 
13417
 
 
13418
<para>The GTK Tutorial is Copyright (C) 1997 Ian Main. </para>
 
13419
 
 
13420
<para>Copyright (C) 1998-2002 Tony Gale.</para>
 
13421
 
 
13422
<para>Permission is granted to make and distribute verbatim copies of this 
 
13423
manual provided the copyright notice and this permission notice are 
 
13424
preserved on all copies.</para>
 
13425
 
 
13426
<para>Permission is granted to copy and distribute modified versions of 
 
13427
this document under the conditions for verbatim copying, provided that 
 
13428
this copyright notice is included exactly as in the original,
 
13429
and that the entire resulting derived work is distributed under 
 
13430
the terms of a permission notice identical to this one.</para>
 
13431
 
 
13432
<para>Permission is granted to copy and distribute translations of this 
 
13433
document into another language, under the above conditions for modified 
 
13434
versions.</para>
 
13435
 
 
13436
<para>If you are intending to incorporate this document into a published 
 
13437
work, please contact the maintainer, and we will make an effort 
 
13438
to ensure that you have the most up to date information available.</para>
 
13439
 
 
13440
<para>There is no guarantee that this document lives up to its intended
 
13441
purpose.  This is simply provided as a free resource.  As such,
 
13442
the authors and maintainers of the information provided within can
 
13443
not make any guarantee that the information is even accurate.</para>
 
13444
 
 
13445
</chapter>
 
13446
 
 
13447
<!-- ***************************************************************** -->
 
13448
<!-- ***************************************************************** -->
 
13449
 
 
13450
<!-- ***************************************************************** -->
 
13451
<appendix id="app-GTKSignals">
 
13452
<title>GTK Signals</title>
 
13453
 
 
13454
<para>As GTK is an object oriented widget set, it has a hierarchy of
 
13455
inheritance. This inheritance mechanism applies for
 
13456
signals. Therefore, you should refer to the widget hierarchy tree when
 
13457
using the signals listed in this section.</para>
 
13458
 
 
13459
<!-- ----------------------------------------------------------------- -->
 
13460
<sect1 id="sec-GtkObject">
 
13461
<title>GtkObject</title>
 
13462
 
 
13463
<programlisting role="C">
 
13464
void GtkObject::destroy (GtkObject *,
 
13465
                         gpointer);
 
13466
</programlisting>
 
13467
 
 
13468
</sect1>
 
13469
 
 
13470
<!-- ----------------------------------------------------------------- -->
 
13471
<sect1 id="sec-GtkWidget">
 
13472
<title>GtkWidget</title>
 
13473
 
 
13474
<programlisting role="C">
 
13475
void GtkWidget::show    (GtkWidget *,
 
13476
                         gpointer);
 
13477
void GtkWidget::hide    (GtkWidget *,
 
13478
                         gpointer);
 
13479
void GtkWidget::map     (GtkWidget *,
 
13480
                         gpointer);
 
13481
void GtkWidget::unmap   (GtkWidget *,
 
13482
                         gpointer);
 
13483
void GtkWidget::realize (GtkWidget *,
 
13484
                         gpointer);
 
13485
void GtkWidget::unrealize       (GtkWidget *,
 
13486
                                 gpointer);
 
13487
void GtkWidget::draw    (GtkWidget *,
 
13488
                         ggpointer,
 
13489
                         gpointer);
 
13490
void GtkWidget::draw-focus      (GtkWidget *,
 
13491
                                 gpointer);
 
13492
void GtkWidget::draw-default    (GtkWidget *,
 
13493
                                 gpointer);
 
13494
void GtkWidget::size-request    (GtkWidget *,
 
13495
                                 ggpointer,
 
13496
                                 gpointer);
 
13497
void GtkWidget::size-allocate   (GtkWidget *,
 
13498
                                 ggpointer,
 
13499
                                 gpointer);
 
13500
void GtkWidget::state-changed   (GtkWidget *,
 
13501
                                 GtkStateType,
 
13502
                                 gpointer);
 
13503
void GtkWidget::parent-set      (GtkWidget *,
 
13504
                                 GtkObject *,
 
13505
                                 gpointer);
 
13506
void GtkWidget::style-set       (GtkWidget *,
 
13507
                                 GtkStyle *,
 
13508
                                 gpointer);
 
13509
void GtkWidget::add-accelerator (GtkWidget *,
 
13510
                                 gguint,
 
13511
                                 GtkAccelGroup *,
 
13512
                                 gguint,
 
13513
                                 GdkModifierType,
 
13514
                                 GtkAccelFlags,
 
13515
                                 gpointer);
 
13516
void GtkWidget::remove-accelerator      (GtkWidget *,
 
13517
                                         GtkAccelGroup *,
 
13518
                                         gguint,
 
13519
                                         GdkModifierType,
 
13520
                                         gpointer);
 
13521
gboolean GtkWidget::event       (GtkWidget *,
 
13522
                                 GdkEvent *,
 
13523
                                 gpointer);
 
13524
gboolean GtkWidget::button-press-event  (GtkWidget *,
 
13525
                                         GdkEvent *,
 
13526
                                         gpointer);
 
13527
gboolean GtkWidget::button-release-event        (GtkWidget *,
 
13528
                                                 GdkEvent *,
 
13529
                                                 gpointer);
 
13530
gboolean GtkWidget::motion-notify-event (GtkWidget *,
 
13531
                                         GdkEvent *,
 
13532
                                         gpointer);
 
13533
gboolean GtkWidget::delete-event        (GtkWidget *,
 
13534
                                         GdkEvent *,
 
13535
                                         gpointer);
 
13536
gboolean GtkWidget::destroy-event       (GtkWidget *,
 
13537
                                         GdkEvent *,
 
13538
                                         gpointer);
 
13539
gboolean GtkWidget::expose-event        (GtkWidget *,
 
13540
                                         GdkEvent *,
 
13541
                                         gpointer);
 
13542
gboolean GtkWidget::key-press-event     (GtkWidget *,
 
13543
                                         GdkEvent *,
 
13544
                                         gpointer);
 
13545
gboolean GtkWidget::key-release-event   (GtkWidget *,
 
13546
                                         GdkEvent *,
 
13547
                                         gpointer);
 
13548
gboolean GtkWidget::enter-notify-event  (GtkWidget *,
 
13549
                                         GdkEvent *,
 
13550
                                         gpointer);
 
13551
gboolean GtkWidget::leave-notify-event  (GtkWidget *,
 
13552
                                         GdkEvent *,
 
13553
                                         gpointer);
 
13554
gboolean GtkWidget::configure-event     (GtkWidget *,
 
13555
                                         GdkEvent *,
 
13556
                                         gpointer);
 
13557
gboolean GtkWidget::focus-in-event      (GtkWidget *,
 
13558
                                         GdkEvent *,
 
13559
                                         gpointer);
 
13560
gboolean GtkWidget::focus-out-event     (GtkWidget *,
 
13561
                                         GdkEvent *,
 
13562
                                         gpointer);
 
13563
gboolean GtkWidget::map-event   (GtkWidget *,
 
13564
                                 GdkEvent *,
 
13565
                                 gpointer);
 
13566
gboolean GtkWidget::unmap-event (GtkWidget *,
 
13567
                                 GdkEvent *,
 
13568
                                 gpointer);
 
13569
gboolean GtkWidget::property-notify-event       (GtkWidget *,
 
13570
                                                 GdkEvent *,
 
13571
                                                 gpointer);
 
13572
gboolean GtkWidget::selection-clear-event       (GtkWidget *,
 
13573
                                                 GdkEvent *,
 
13574
                                                 gpointer);
 
13575
gboolean GtkWidget::selection-request-event     (GtkWidget *,
 
13576
                                                 GdkEvent *,
 
13577
                                                 gpointer);
 
13578
gboolean GtkWidget::selection-notify-event      (GtkWidget *,
 
13579
                                                 GdkEvent *,
 
13580
                                                 gpointer);
 
13581
void GtkWidget::selection-get   (GtkWidget *,
 
13582
                                 GtkSelectionData *,
 
13583
                                 gguint,
 
13584
                                 gpointer);
 
13585
void GtkWidget::selection-received      (GtkWidget *,
 
13586
                                         GtkSelectionData *,
 
13587
                                         gguint,
 
13588
                                         gpointer);
 
13589
gboolean GtkWidget::proximity-in-event  (GtkWidget *,
 
13590
                                         GdkEvent *,
 
13591
                                         gpointer);
 
13592
gboolean GtkWidget::proximity-out-event (GtkWidget *,
 
13593
                                         GdkEvent *,
 
13594
                                         gpointer);
 
13595
void GtkWidget::drag-begin      (GtkWidget *,
 
13596
                                 GdkDragContext *,
 
13597
                                 gpointer);
 
13598
void GtkWidget::drag-end        (GtkWidget *,
 
13599
                                 GdkDragContext *,
 
13600
                                 gpointer);
 
13601
void GtkWidget::drag-data-delete        (GtkWidget *,
 
13602
                                         GdkDragContext *,
 
13603
                                         gpointer);
 
13604
void GtkWidget::drag-leave      (GtkWidget *,
 
13605
                                 GdkDragContext *,
 
13606
                                 gguint,
 
13607
                                 gpointer);
 
13608
gboolean GtkWidget::drag-motion (GtkWidget *,
 
13609
                                 GdkDragContext *,
 
13610
                                 ggint,
 
13611
                                 ggint,
 
13612
                                 gguint,
 
13613
                                 gpointer);
 
13614
gboolean GtkWidget::drag-drop   (GtkWidget *,
 
13615
                                 GdkDragContext *,
 
13616
                                 ggint,
 
13617
                                 ggint,
 
13618
                                 gguint,
 
13619
                                 gpointer);
 
13620
void GtkWidget::drag-data-get   (GtkWidget *,
 
13621
                                 GdkDragContext *,
 
13622
                                 GtkSelectionData *,
 
13623
                                 gguint,
 
13624
                                 gguint,
 
13625
                                 gpointer);
 
13626
void GtkWidget::drag-data-received      (GtkWidget *,
 
13627
                                         GdkDragContext *,
 
13628
                                         ggint,
 
13629
                                         ggint,
 
13630
                                         GtkSelectionData *,
 
13631
                                         gguint,
 
13632
                                         gguint,
 
13633
                                         gpointer);
 
13634
gboolean GtkWidget::client-event        (GtkWidget *,
 
13635
                                         GdkEvent *,
 
13636
                                         gpointer);
 
13637
gboolean GtkWidget::no-expose-event     (GtkWidget *,
 
13638
                                         GdkEvent *,
 
13639
                                         gpointer);
 
13640
gboolean GtkWidget::visibility-notify-event     (GtkWidget *,
 
13641
                                                 GdkEvent *,
 
13642
                                                 gpointer);
 
13643
void GtkWidget::debug-msg       (GtkWidget *,
 
13644
                                 GtkString *,
 
13645
                                 gpointer);
 
13646
</programlisting>
 
13647
 
 
13648
</sect1>
 
13649
 
 
13650
<!-- ----------------------------------------------------------------- -->
 
13651
<sect1 id="sec-GtkData">
 
13652
<title>GtkData</title>
 
13653
 
 
13654
<programlisting role="C">
 
13655
void GtkData::disconnect        (GtkData *,
 
13656
                                 gpointer);
 
13657
</programlisting>
 
13658
 
 
13659
</sect1>
 
13660
 
 
13661
<!-- ----------------------------------------------------------------- -->
 
13662
<sect1 id="sec-GtkContainer">
 
13663
<title>GtkContainer</title>
 
13664
 
 
13665
<programlisting role="C">
 
13666
void GtkContainer::add  (GtkContainer *,
 
13667
                         GtkWidget *,
 
13668
                         gpointer);
 
13669
void GtkContainer::remove       (GtkContainer *,
 
13670
                                 GtkWidget *,
 
13671
                                 gpointer);
 
13672
void GtkContainer::check-resize (GtkContainer *,
 
13673
                                 gpointer);
 
13674
GtkDirectionType GtkContainer::focus    (GtkContainer *,
 
13675
                                         GtkDirectionType,
 
13676
                                         gpointer);
 
13677
void GtkContainer::set-focus-child      (GtkContainer *,
 
13678
                                         GtkWidget *,
 
13679
                                         gpointer);
 
13680
</programlisting>
 
13681
 
 
13682
</sect1>
 
13683
 
 
13684
<!-- ----------------------------------------------------------------- -->
 
13685
<sect1 id="sec-GtkCalendar">
 
13686
<title>GtkCalendar</title>
 
13687
 
 
13688
<programlisting role="C">
 
13689
void GtkCalendar::month-changed (GtkCalendar *,
 
13690
                                 gpointer);
 
13691
void GtkCalendar::day-selected  (GtkCalendar *,
 
13692
                                 gpointer);
 
13693
void GtkCalendar::day-selected-double-click     (GtkCalendar *,
 
13694
                                                 gpointer);
 
13695
void GtkCalendar::prev-month    (GtkCalendar *,
 
13696
                                 gpointer);
 
13697
void GtkCalendar::next-month    (GtkCalendar *,
 
13698
                                 gpointer);
 
13699
void GtkCalendar::prev-year     (GtkCalendar *,
 
13700
                                 gpointer);
 
13701
void GtkCalendar::next-year     (GtkCalendar *,
 
13702
                                 gpointer);
 
13703
</programlisting>
 
13704
 
 
13705
</sect1>
 
13706
 
 
13707
<!-- ----------------------------------------------------------------- -->
 
13708
<sect1 id="sec-GtkEditable">
 
13709
<title>GtkEditable</title>
 
13710
 
 
13711
<programlisting role="C">
 
13712
void GtkEditable::changed       (GtkEditable *,
 
13713
                                 gpointer);
 
13714
void GtkEditable::insert-text   (GtkEditable *,
 
13715
                                 GtkString *,
 
13716
                                 ggint,
 
13717
                                 ggpointer,
 
13718
                                 gpointer);
 
13719
void GtkEditable::delete-text   (GtkEditable *,
 
13720
                                 ggint,
 
13721
                                 ggint,
 
13722
                                 gpointer);
 
13723
void GtkEditable::activate      (GtkEditable *,
 
13724
                                 gpointer);
 
13725
void GtkEditable::set-editable  (GtkEditable *,
 
13726
                                 gboolean,
 
13727
                                 gpointer);
 
13728
void GtkEditable::move-cursor   (GtkEditable *,
 
13729
                                 ggint,
 
13730
                                 ggint,
 
13731
                                 gpointer);
 
13732
void GtkEditable::move-word     (GtkEditable *,
 
13733
                                 ggint,
 
13734
                                 gpointer);
 
13735
void GtkEditable::move-page     (GtkEditable *,
 
13736
                                 ggint,
 
13737
                                 ggint,
 
13738
                                 gpointer);
 
13739
void GtkEditable::move-to-row   (GtkEditable *,
 
13740
                                 ggint,
 
13741
                                 gpointer);
 
13742
void GtkEditable::move-to-column        (GtkEditable *,
 
13743
                                         ggint,
 
13744
                                         gpointer);
 
13745
void GtkEditable::kill-char     (GtkEditable *,
 
13746
                                 ggint,
 
13747
                                 gpointer);
 
13748
void GtkEditable::kill-word     (GtkEditable *,
 
13749
                                 ggint,
 
13750
                                 gpointer);
 
13751
void GtkEditable::kill-line     (GtkEditable *,
 
13752
                                 ggint,
 
13753
                                 gpointer);
 
13754
void GtkEditable::cut-clipboard (GtkEditable *,
 
13755
                                 gpointer);
 
13756
void GtkEditable::copy-clipboard        (GtkEditable *,
 
13757
                                         gpointer);
 
13758
void GtkEditable::paste-clipboard       (GtkEditable *,
 
13759
                                         gpointer);
 
13760
</programlisting>
 
13761
 
 
13762
</sect1>
 
13763
 
 
13764
<!-- ----------------------------------------------------------------- -->
 
13765
<sect1 id="sec-GtkNotebook">
 
13766
<title>GtkNotebook</title>
 
13767
 
 
13768
<programlisting role="C">
 
13769
void GtkNotebook::switch-page   (GtkNotebook *,
 
13770
                                 ggpointer,
 
13771
                                 gguint,
 
13772
                                 gpointer);
 
13773
</programlisting>
 
13774
 
 
13775
</sect1>
 
13776
 
 
13777
<!-- ----------------------------------------------------------------- -->
 
13778
<sect1 id="sec-GtkList">
 
13779
<title>GtkList</title>
 
13780
 
 
13781
<programlisting role="C">
 
13782
void GtkList::selection-changed (GtkList *,
 
13783
                                 gpointer);
 
13784
void GtkList::select-child      (GtkList *,
 
13785
                                 GtkWidget *,
 
13786
                                 gpointer);
 
13787
void GtkList::unselect-child    (GtkList *,
 
13788
                                 GtkWidget *,
 
13789
                                 gpointer);
 
13790
</programlisting>
 
13791
 
 
13792
</sect1>
 
13793
 
 
13794
<!-- ----------------------------------------------------------------- -->
 
13795
<sect1 id="sec-GtkMenuShell">
 
13796
<title>GtkMenuShell</title>
 
13797
 
 
13798
<programlisting role="C">
 
13799
void GtkMenuShell::deactivate   (GtkMenuShell *,
 
13800
                                 gpointer);
 
13801
void GtkMenuShell::selection-done       (GtkMenuShell *,
 
13802
                                         gpointer);
 
13803
void GtkMenuShell::move-current (GtkMenuShell *,
 
13804
                                 GtkMenuDirectionType,
 
13805
                                 gpointer);
 
13806
void GtkMenuShell::activate-current     (GtkMenuShell *,
 
13807
                                         gboolean,
 
13808
                                         gpointer);
 
13809
void GtkMenuShell::cancel       (GtkMenuShell *,
 
13810
                                 gpointer);
 
13811
</programlisting>
 
13812
 
 
13813
</sect1>
 
13814
 
 
13815
<!-- ----------------------------------------------------------------- -->
 
13816
<sect1 id="sec-GtkToolbar">
 
13817
<title>GtkToolbar</title>
 
13818
 
 
13819
<programlisting role="C">
 
13820
void GtkToolbar::orientation-changed    (GtkToolbar *,
 
13821
                                         ggint,
 
13822
                                         gpointer);
 
13823
void GtkToolbar::style-changed  (GtkToolbar *,
 
13824
                                 ggint,
 
13825
                                 gpointer);
 
13826
</programlisting>
 
13827
 
 
13828
</sect1>
 
13829
 
 
13830
<!-- ----------------------------------------------------------------- -->
 
13831
<sect1 id="sec-GtkButton">
 
13832
<title>GtkButton</title>
 
13833
 
 
13834
<programlisting role="C">
 
13835
void GtkButton::pressed (GtkButton *,
 
13836
                         gpointer);
 
13837
void GtkButton::released        (GtkButton *,
 
13838
                                 gpointer);
 
13839
void GtkButton::clicked (GtkButton *,
 
13840
                         gpointer);
 
13841
void GtkButton::enter   (GtkButton *,
 
13842
                         gpointer);
 
13843
void GtkButton::leave   (GtkButton *,
 
13844
                         gpointer);
 
13845
</programlisting>
 
13846
 
 
13847
</sect1>
 
13848
 
 
13849
<!-- ----------------------------------------------------------------- -->
 
13850
<sect1 id="sec-GtkItem">
 
13851
<title>GtkItem</title>
 
13852
 
 
13853
<programlisting role="C">
 
13854
void GtkItem::select    (GtkItem *,
 
13855
                         gpointer);
 
13856
void GtkItem::deselect  (GtkItem *,
 
13857
                         gpointer);
 
13858
void GtkItem::toggle    (GtkItem *,
 
13859
                         gpointer);
 
13860
</programlisting>
 
13861
 
 
13862
</sect1>
 
13863
 
 
13864
<!-- ----------------------------------------------------------------- -->
 
13865
<sect1 id="sec-GtkWindow">
 
13866
<title>GtkWindow</title>
 
13867
 
 
13868
<programlisting role="C">
 
13869
void GtkWindow::set-focus       (GtkWindow *,
 
13870
                                 ggpointer,
 
13871
                                 gpointer);
 
13872
</programlisting>
 
13873
 
 
13874
</sect1>
 
13875
 
 
13876
<!-- ----------------------------------------------------------------- -->
 
13877
<sect1 id="sec-GtkHandleBox">
 
13878
<title>GtkHandleBox</title>
 
13879
 
 
13880
<programlisting role="C">
 
13881
void GtkHandleBox::child-attached       (GtkHandleBox *,
 
13882
                                         GtkWidget *,
 
13883
                                         gpointer);
 
13884
void GtkHandleBox::child-detached       (GtkHandleBox *,
 
13885
                                         GtkWidget *,
 
13886
                                         gpointer);
 
13887
</programlisting>
 
13888
 
 
13889
</sect1>
 
13890
 
 
13891
<!-- ----------------------------------------------------------------- -->
 
13892
<sect1 id="sec-GtkToggleButton">
 
13893
<title>GtkToggleButton</title>
 
13894
 
 
13895
<programlisting role="C">
 
13896
void GtkToggleButton::toggled   (GtkToggleButton *,
 
13897
                                 gpointer);
 
13898
</programlisting>
 
13899
 
 
13900
</sect1>
 
13901
 
 
13902
<!-- ----------------------------------------------------------------- -->
 
13903
<sect1 id="sec-GtkMenuItem">
 
13904
<title>GtkMenuItem</title>
 
13905
 
 
13906
<programlisting role="C">
 
13907
void GtkMenuItem::activate      (GtkMenuItem *,
 
13908
                                 gpointer);
 
13909
void GtkMenuItem::activate-item (GtkMenuItem *,
 
13910
                                 gpointer);
 
13911
</programlisting>
 
13912
 
 
13913
</sect1>
 
13914
 
 
13915
<!-- ----------------------------------------------------------------- -->
 
13916
<sect1 id="sec-GtkCheckMenuItem">
 
13917
<title>GtkCheckMenuItem</title>
 
13918
 
 
13919
<programlisting role="C">
 
13920
void GtkCheckMenuItem::toggled  (GtkCheckMenuItem *,
 
13921
                                 gpointer);
 
13922
</programlisting>
 
13923
 
 
13924
</sect1>
 
13925
 
 
13926
<!-- ----------------------------------------------------------------- -->
 
13927
<sect1 id="sec-GtkInputDialog">
 
13928
<title>GtkInputDialog</title>
 
13929
 
 
13930
<programlisting role="C">
 
13931
void GtkInputDialog::enable-device      (GtkInputDialog *,
 
13932
                                         ggint,
 
13933
                                         gpointer);
 
13934
void GtkInputDialog::disable-device     (GtkInputDialog *,
 
13935
                                         ggint,
 
13936
                                         gpointer);
 
13937
</programlisting>
 
13938
 
 
13939
</sect1>
 
13940
 
 
13941
<!-- ----------------------------------------------------------------- -->
 
13942
<sect1 id="sec-GtkColorSelection">
 
13943
<title>GtkColorSelection</title>
 
13944
 
 
13945
<programlisting role="C">
 
13946
void GtkColorSelection::color-changed   (GtkColorSelection *,
 
13947
                                         gpointer);
 
13948
</programlisting>
 
13949
 
 
13950
</sect1>
 
13951
 
 
13952
<!-- ----------------------------------------------------------------- -->
 
13953
<sect1 id="sec-GtkStatusBar">
 
13954
<title>GtkStatusBar</title>
 
13955
 
 
13956
<programlisting role="C">
 
13957
void GtkStatusbar::text-pushed  (GtkStatusbar *,
 
13958
                                 gguint,
 
13959
                                 GtkString *,
 
13960
                                 gpointer);
 
13961
void GtkStatusbar::text-popped  (GtkStatusbar *,
 
13962
                                 gguint,
 
13963
                                 GtkString *,
 
13964
                                 gpointer);
 
13965
</programlisting>
 
13966
 
 
13967
</sect1>
 
13968
 
 
13969
<!-- ----------------------------------------------------------------- -->
 
13970
<sect1 id="sec-GtkCurve">
 
13971
<title>GtkCurve</title>
 
13972
 
 
13973
<programlisting role="C">
 
13974
void GtkCurve::curve-type-changed       (GtkCurve *,
 
13975
                                         gpointer);
 
13976
</programlisting>
 
13977
 
 
13978
</sect1>
 
13979
 
 
13980
<!-- ----------------------------------------------------------------- -->
 
13981
<sect1 id="sec-GtkAdjustment">
 
13982
<title>GtkAdjustment</title>
 
13983
 
 
13984
<programlisting role="C">
 
13985
void GtkAdjustment::changed     (GtkAdjustment *,
 
13986
                                 gpointer);
 
13987
void GtkAdjustment::value-changed       (GtkAdjustment *,
 
13988
                                         gpointer);
 
13989
</programlisting>
 
13990
 
 
13991
</sect1>
 
13992
</appendix>
 
13993
 
 
13994
<!-- ***************************************************************** -->
 
13995
<appendix id="app-GDKEventTypes">
 
13996
<title>GDK Event Types</title>
 
13997
 
 
13998
<para>The following data types are passed into event handlers by GTK+. For
 
13999
each data type listed, the signals that use this data type are listed.</para>
 
14000
 
 
14001
<itemizedlist>
 
14002
<listitem><simpara>  GdkEvent</simpara>
 
14003
          <itemizedlist>
 
14004
          <listitem><simpara>drag_end_event</simpara>
 
14005
          </listitem>
 
14006
          </itemizedlist>
 
14007
</listitem>
 
14008
 
 
14009
<listitem><simpara>  GdkEventType<</simpara>
 
14010
</listitem>
 
14011
 
 
14012
<listitem><simpara>  GdkEventAny</simpara>
 
14013
          <itemizedlist>
 
14014
          <listitem><simpara>delete_event</simpara>
 
14015
          </listitem>
 
14016
          <listitem><simpara>destroy_event</simpara>
 
14017
          </listitem>
 
14018
          <listitem><simpara>map_event</simpara>
 
14019
          </listitem>
 
14020
          <listitem><simpara>unmap_event</simpara>
 
14021
          </listitem>
 
14022
          <listitem><simpara>no_expose_event</simpara>
 
14023
          </listitem>
 
14024
          </itemizedlist>
 
14025
</listitem>
 
14026
 
 
14027
<listitem><simpara>  GdkEventExpose</simpara>
 
14028
          <itemizedlist>
 
14029
          <listitem><simpara>expose_event</simpara>
 
14030
          </listitem>
 
14031
          </itemizedlist>
 
14032
</listitem>
 
14033
 
 
14034
<listitem><simpara>  GdkEventNoExpose</simpara>
 
14035
</listitem>
 
14036
 
 
14037
<listitem><simpara>  GdkEventVisibility</simpara>
 
14038
</listitem>
 
14039
 
 
14040
<listitem><simpara>  GdkEventMotion</simpara>
 
14041
          <itemizedlist>
 
14042
          <listitem><simpara>motion_notify_event</simpara>
 
14043
          </listitem>
 
14044
          </itemizedlist>
 
14045
</listitem>
 
14046
<listitem><simpara>  GdkEventButton</simpara>
 
14047
          <itemizedlist>
 
14048
          <listitem><simpara>button_press_event</simpara>
 
14049
          </listitem>
 
14050
          <listitem><simpara>button_release_event</simpara>
 
14051
          </listitem>
 
14052
          </itemizedlist>
 
14053
</listitem>
 
14054
 
 
14055
<listitem><simpara>  GdkEventKey</simpara>
 
14056
          <itemizedlist>
 
14057
          <listitem><simpara>key_press_event</simpara>
 
14058
          </listitem>
 
14059
          <listitem><simpara>key_release_event</simpara>
 
14060
          </listitem>
 
14061
          </itemizedlist>
 
14062
</listitem>
 
14063
 
 
14064
<listitem><simpara>  GdkEventCrossing</simpara>
 
14065
          <itemizedlist>
 
14066
          <listitem><simpara>enter_notify_event</simpara>
 
14067
          </listitem>
 
14068
          <listitem><simpara>leave_notify_event</simpara>
 
14069
          </listitem>
 
14070
          </itemizedlist>
 
14071
</listitem>
 
14072
 
 
14073
<listitem><simpara>  GdkEventFocus</simpara>
 
14074
          <itemizedlist>
 
14075
          <listitem><simpara>focus_in_event</simpara>
 
14076
          </listitem>
 
14077
          <listitem><simpara>focus_out_event</simpara>
 
14078
          </listitem>
 
14079
          </itemizedlist>
 
14080
</listitem>
 
14081
 
 
14082
<listitem><simpara>  GdkEventConfigure</simpara>
 
14083
          <itemizedlist>
 
14084
          <listitem><simpara>configure_event</simpara>
 
14085
          </listitem>
 
14086
          </itemizedlist>
 
14087
</listitem>
 
14088
 
 
14089
<listitem><simpara>  GdkEventProperty</simpara>
 
14090
          <itemizedlist>
 
14091
          <listitem><simpara>property_notify_event</simpara>
 
14092
          </listitem>
 
14093
          </itemizedlist>
 
14094
</listitem>
 
14095
 
 
14096
<listitem><simpara>  GdkEventSelection</simpara>
 
14097
          <itemizedlist>
 
14098
          <listitem><simpara>selection_clear_event</simpara>
 
14099
          </listitem>
 
14100
          <listitem><simpara>selection_request_event</simpara>
 
14101
          </listitem>
 
14102
          <listitem><simpara>selection_notify_event</simpara>
 
14103
          </listitem>
 
14104
          </itemizedlist>
 
14105
</listitem>
 
14106
 
 
14107
<listitem><simpara>  GdkEventProximity</simpara>
 
14108
          <itemizedlist>
 
14109
          <listitem><simpara>proximity_in_event</simpara>
 
14110
          </listitem>
 
14111
          <listitem><simpara>proximity_out_event</simpara>
 
14112
          </listitem>
 
14113
          </itemizedlist>
 
14114
</listitem>
 
14115
 
 
14116
<listitem><simpara>  GdkEventDragBegin</simpara>
 
14117
          <itemizedlist>
 
14118
          <listitem><simpara>drag_begin_event</simpara>
 
14119
          </listitem>
 
14120
          </itemizedlist>
 
14121
</listitem>
 
14122
 
 
14123
<listitem><simpara>  GdkEventDragRequest</simpara>
 
14124
          <itemizedlist>
 
14125
          <listitem><simpara>drag_request_event</simpara>
 
14126
          </listitem>
 
14127
          </itemizedlist>
 
14128
</listitem>
 
14129
 
 
14130
<listitem><simpara>  GdkEventDropEnter</simpara>
 
14131
          <itemizedlist>
 
14132
          <listitem><simpara>drop_enter_event</simpara>
 
14133
          </listitem>
 
14134
          </itemizedlist>
 
14135
</listitem>
 
14136
 
 
14137
<listitem><simpara>  GdkEventDropLeave</simpara>
 
14138
          <itemizedlist>
 
14139
          <listitem><simpara>drop_leave_event</simpara>
 
14140
          </listitem>
 
14141
          </itemizedlist>
 
14142
</listitem>
 
14143
 
 
14144
<listitem><simpara>  GdkEventDropDataAvailable</simpara>
 
14145
          <itemizedlist>
 
14146
          <listitem><simpara>drop_data_available_event</simpara>
 
14147
          </listitem>
 
14148
          </itemizedlist>
 
14149
</listitem>
 
14150
 
 
14151
<listitem><simpara>  GdkEventClient</simpara>
 
14152
          <itemizedlist>
 
14153
          <listitem><simpara>client_event</simpara>
 
14154
          </listitem>
 
14155
          </itemizedlist>
 
14156
</listitem>
 
14157
 
 
14158
<listitem><simpara>  GdkEventOther</simpara>
 
14159
          <itemizedlist>
 
14160
          <listitem><simpara>other_event</simpara>
 
14161
          </listitem>
 
14162
          </itemizedlist>
 
14163
</listitem>
 
14164
</itemizedlist>
 
14165
 
 
14166
<para>The data type <literal>GdkEventType</literal> is a special data type that is used by
 
14167
all the other data types as an indicator of the data type being passed
 
14168
to the signal handler. As you will see below, each of the event data
 
14169
structures has a member of this type. It is defined as an enumeration
 
14170
type as follows:</para>
 
14171
 
 
14172
<programlisting role="C">
 
14173
typedef enum
 
14174
{
 
14175
  GDK_NOTHING           = -1,
 
14176
  GDK_DELETE            = 0,
 
14177
  GDK_DESTROY           = 1,
 
14178
  GDK_EXPOSE            = 2,
 
14179
  GDK_MOTION_NOTIFY     = 3,
 
14180
  GDK_BUTTON_PRESS      = 4,
 
14181
  GDK_2BUTTON_PRESS     = 5,
 
14182
  GDK_3BUTTON_PRESS     = 6,
 
14183
  GDK_BUTTON_RELEASE    = 7,
 
14184
  GDK_KEY_PRESS         = 8,
 
14185
  GDK_KEY_RELEASE       = 9,
 
14186
  GDK_ENTER_NOTIFY      = 10,
 
14187
  GDK_LEAVE_NOTIFY      = 11,
 
14188
  GDK_FOCUS_CHANGE      = 12,
 
14189
  GDK_CONFIGURE         = 13,
 
14190
  GDK_MAP               = 14,
 
14191
  GDK_UNMAP             = 15,
 
14192
  GDK_PROPERTY_NOTIFY   = 16,
 
14193
  GDK_SELECTION_CLEAR   = 17,
 
14194
  GDK_SELECTION_REQUEST = 18,
 
14195
  GDK_SELECTION_NOTIFY  = 19,
 
14196
  GDK_PROXIMITY_IN      = 20,
 
14197
  GDK_PROXIMITY_OUT     = 21,
 
14198
  GDK_DRAG_BEGIN        = 22,
 
14199
  GDK_DRAG_REQUEST      = 23,
 
14200
  GDK_DROP_ENTER        = 24,
 
14201
  GDK_DROP_LEAVE        = 25,
 
14202
  GDK_DROP_DATA_AVAIL   = 26,
 
14203
  GDK_CLIENT_EVENT      = 27,
 
14204
  GDK_VISIBILITY_NOTIFY = 28,
 
14205
  GDK_NO_EXPOSE         = 29,
 
14206
  GDK_OTHER_EVENT       = 9999  /* Deprecated, use filters instead */
 
14207
} GdkEventType;
 
14208
</programlisting>
 
14209
 
 
14210
<para>The other event type that is different from the others is
 
14211
<literal>GdkEvent</literal> itself. This is a union of all the other
 
14212
data types, which allows it to be cast to a specific
 
14213
event data type within a signal handler.</para>
 
14214
 
 
14215
<!-- Just a big list for now, needs expanding upon - TRG -->
 
14216
<para>So, the event data types are defined as follows:</para>
 
14217
 
 
14218
<programlisting role="C">
 
14219
struct _GdkEventAny
 
14220
{
 
14221
  GdkEventType type;
 
14222
  GdkWindow *window;
 
14223
  gint8 send_event;
 
14224
};
 
14225
 
 
14226
struct _GdkEventExpose
 
14227
{
 
14228
  GdkEventType type;
 
14229
  GdkWindow *window;
 
14230
  gint8 send_event;
 
14231
  GdkRectangle area;
 
14232
  gint count; /* If non-zero, how many more events follow. */
 
14233
};
 
14234
 
 
14235
struct _GdkEventNoExpose
 
14236
{
 
14237
  GdkEventType type;
 
14238
  GdkWindow *window;
 
14239
  gint8 send_event;
 
14240
  /* XXX: does anyone need the X major_code or minor_code fields? */
 
14241
};
 
14242
 
 
14243
struct _GdkEventVisibility
 
14244
{
 
14245
  GdkEventType type;
 
14246
  GdkWindow *window;
 
14247
  gint8 send_event;
 
14248
  GdkVisibilityState state;
 
14249
};
 
14250
 
 
14251
struct _GdkEventMotion
 
14252
{
 
14253
  GdkEventType type;
 
14254
  GdkWindow *window;
 
14255
  gint8 send_event;
 
14256
  guint32 time;
 
14257
  gdouble x;
 
14258
  gdouble y;
 
14259
  gdouble pressure;
 
14260
  gdouble xtilt;
 
14261
  gdouble ytilt;
 
14262
  guint state;
 
14263
  gint16 is_hint;
 
14264
  GdkInputSource source;
 
14265
  guint32 deviceid;
 
14266
  gdouble x_root, y_root;
 
14267
};
 
14268
 
 
14269
struct _GdkEventButton
 
14270
{
 
14271
  GdkEventType type;
 
14272
  GdkWindow *window;
 
14273
  gint8 send_event;
 
14274
  guint32 time;
 
14275
  gdouble x;
 
14276
  gdouble y;
 
14277
  gdouble pressure;
 
14278
  gdouble xtilt;
 
14279
  gdouble ytilt;
 
14280
  guint state;
 
14281
  guint button;
 
14282
  GdkInputSource source;
 
14283
  guint32 deviceid;
 
14284
  gdouble x_root, y_root;
 
14285
};
 
14286
 
 
14287
struct _GdkEventKey
 
14288
{
 
14289
  GdkEventType type;
 
14290
  GdkWindow *window;
 
14291
  gint8 send_event;
 
14292
  guint32 time;
 
14293
  guint state;
 
14294
  guint keyval;
 
14295
  gint length;
 
14296
  gchar *string;
 
14297
};
 
14298
 
 
14299
struct _GdkEventCrossing
 
14300
{
 
14301
  GdkEventType type;
 
14302
  GdkWindow *window;
 
14303
  gint8 send_event;
 
14304
  GdkWindow *subwindow;
 
14305
  GdkNotifyType detail;
 
14306
};
 
14307
 
 
14308
struct _GdkEventFocus
 
14309
{
 
14310
  GdkEventType type;
 
14311
  GdkWindow *window;
 
14312
  gint8 send_event;
 
14313
  gint16 in;
 
14314
};
 
14315
 
 
14316
struct _GdkEventConfigure
 
14317
{
 
14318
  GdkEventType type;
 
14319
  GdkWindow *window;
 
14320
  gint8 send_event;
 
14321
  gint16 x, y;
 
14322
  gint16 width;
 
14323
  gint16 height;
 
14324
};
 
14325
 
 
14326
struct _GdkEventProperty
 
14327
{
 
14328
  GdkEventType type;
 
14329
  GdkWindow *window;
 
14330
  gint8 send_event;
 
14331
  GdkAtom atom;
 
14332
  guint32 time;
 
14333
  guint state;
 
14334
};
 
14335
 
 
14336
struct _GdkEventSelection
 
14337
{
 
14338
  GdkEventType type;
 
14339
  GdkWindow *window;
 
14340
  gint8 send_event;
 
14341
  GdkAtom selection;
 
14342
  GdkAtom target;
 
14343
  GdkAtom property;
 
14344
  guint32 requestor;
 
14345
  guint32 time;
 
14346
};
 
14347
 
 
14348
/* This event type will be used pretty rarely. It only is important
 
14349
   for XInput aware programs that are drawing their own cursor */
 
14350
 
 
14351
struct _GdkEventProximity
 
14352
{
 
14353
  GdkEventType type;
 
14354
  GdkWindow *window;
 
14355
  gint8 send_event;
 
14356
  guint32 time;
 
14357
  GdkInputSource source;
 
14358
  guint32 deviceid;
 
14359
};
 
14360
 
 
14361
struct _GdkEventDragRequest
 
14362
{
 
14363
  GdkEventType type;
 
14364
  GdkWindow *window;
 
14365
  gint8 send_event;
 
14366
  guint32 requestor;
 
14367
  union {
 
14368
    struct {
 
14369
      guint protocol_version:4;
 
14370
      guint sendreply:1;
 
14371
      guint willaccept:1;
 
14372
      guint delete_data:1; /* Do *not* delete if link is sent, only
 
14373
                              if data is sent */
 
14374
      guint senddata:1;
 
14375
      guint reserved:22;
 
14376
    } flags;
 
14377
    glong allflags;
 
14378
  } u;
 
14379
  guint8 isdrop; /* This gdk event can be generated by a couple of
 
14380
                    X events - this lets the app know whether the
 
14381
                    drop really occurred or we just set the data */
 
14382
 
 
14383
  GdkPoint drop_coords;
 
14384
  gchar *data_type;
 
14385
  guint32 timestamp;
 
14386
};
 
14387
 
 
14388
struct _GdkEventDragBegin
 
14389
{
 
14390
  GdkEventType type;
 
14391
  GdkWindow *window;
 
14392
  gint8 send_event;
 
14393
  union {
 
14394
    struct {
 
14395
      guint protocol_version:4;
 
14396
      guint reserved:28;
 
14397
    } flags;
 
14398
    glong allflags;
 
14399
  } u;
 
14400
};
 
14401
 
 
14402
struct _GdkEventDropEnter
 
14403
{
 
14404
  GdkEventType type;
 
14405
  GdkWindow *window;
 
14406
  gint8 send_event;
 
14407
  guint32 requestor;
 
14408
  union {
 
14409
    struct {
 
14410
      guint protocol_version:4;
 
14411
      guint sendreply:1;
 
14412
      guint extended_typelist:1;
 
14413
      guint reserved:26;
 
14414
    } flags;
 
14415
    glong allflags;
 
14416
  } u;
 
14417
};
 
14418
 
 
14419
struct _GdkEventDropLeave
 
14420
{
 
14421
  GdkEventType type;
 
14422
  GdkWindow *window;
 
14423
  gint8 send_event;
 
14424
  guint32 requestor;
 
14425
  union {
 
14426
    struct {
 
14427
      guint protocol_version:4;
 
14428
      guint reserved:28;
 
14429
    } flags;
 
14430
    glong allflags;
 
14431
  } u;
 
14432
};
 
14433
 
 
14434
struct _GdkEventDropDataAvailable
 
14435
{
 
14436
  GdkEventType type;
 
14437
  GdkWindow *window;
 
14438
  gint8 send_event;
 
14439
  guint32 requestor;
 
14440
  union {
 
14441
    struct {
 
14442
      guint protocol_version:4;
 
14443
      guint isdrop:1;
 
14444
      guint reserved:25;
 
14445
    } flags;
 
14446
    glong allflags;
 
14447
  } u;
 
14448
  gchar *data_type; /* MIME type */
 
14449
  gulong data_numbytes;
 
14450
  gpointer data;
 
14451
  guint32 timestamp;
 
14452
  GdkPoint coords;
 
14453
};
 
14454
 
 
14455
struct _GdkEventClient
 
14456
{
 
14457
  GdkEventType type;
 
14458
  GdkWindow *window;
 
14459
  gint8 send_event;
 
14460
  GdkAtom message_type;
 
14461
  gushort data_format;
 
14462
  union {
 
14463
    char b[20];
 
14464
    short s[10];
 
14465
    long l[5];
 
14466
  } data;
 
14467
};
 
14468
 
 
14469
struct _GdkEventOther
 
14470
{
 
14471
  GdkEventType type;
 
14472
  GdkWindow *window;
 
14473
  gint8 send_event;
 
14474
  GdkXEvent *xevent;
 
14475
};
 
14476
</programlisting>
 
14477
 
 
14478
</appendix>
 
14479
 
 
14480
<!-- ***************************************************************** -->
 
14481
<appendix id="app-CodeExamples">
 
14482
<title>Code Examples</title>
 
14483
 
 
14484
<para>Below are the code examples that are used in the above text
 
14485
which are not included in complete form elsewhere.</para>
 
14486
 
 
14487
<!-- ----------------------------------------------------------------- -->
 
14488
<sect1 id="sec-Tictactoe">
 
14489
<title>Tictactoe</title>
 
14490
<!-- ----------------------------------------------------------------- -->
 
14491
<sect2>
 
14492
<title>tictactoe.h</title>
 
14493
 
 
14494
<programlisting role="C">
 
14495
<!-- example-start tictactoe tictactoe.h -->
 
14496
/* GTK - The GIMP Toolkit
 
14497
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 
14498
 *
 
14499
 * This library is free software; you can redistribute it and/or
 
14500
 * modify it under the terms of the GNU Library General Public
 
14501
 * License as published by the Free Software Foundation; either
 
14502
 * version 2 of the License, or (at your option) any later version.
 
14503
 *
 
14504
 * This library is distributed in the hope that it will be useful,
 
14505
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14506
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14507
 * Library General Public License for more details.
 
14508
 *
 
14509
 * You should have received a copy of the GNU Library General Public
 
14510
 * License along with this library; if not, write to the
 
14511
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
14512
 * Boston, MA 02111-1307, USA.
 
14513
 */
 
14514
#ifndef __TICTACTOE_H__
 
14515
#define __TICTACTOE_H__
 
14516
 
 
14517
 
 
14518
#include &lt;glib.h&gt;
 
14519
#include &lt;glib-object.h&gt;
 
14520
#include &lt;gtk/gtktable.h&gt;
 
14521
 
 
14522
 
 
14523
G_BEGIN_DECLS
 
14524
 
 
14525
#define TICTACTOE_TYPE            (tictactoe_get_type ())
 
14526
#define TICTACTOE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TICTACTOE_TYPE, Tictactoe))
 
14527
#define TICTACTOE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TICTACTOE_TYPE, TictactoeClass))
 
14528
#define IS_TICTACTOE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TICTACTOE_TYPE))
 
14529
#define IS_TICTACTOE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TICTACTOE_TYPE))
 
14530
 
 
14531
 
 
14532
typedef struct _Tictactoe       Tictactoe;
 
14533
typedef struct _TictactoeClass  TictactoeClass;
 
14534
 
 
14535
struct _Tictactoe
 
14536
{
 
14537
  GtkTable table;
 
14538
  
 
14539
  GtkWidget *buttons[3][3];
 
14540
};
 
14541
 
 
14542
struct _TictactoeClass
 
14543
{
 
14544
  GtkTableClass parent_class;
 
14545
 
 
14546
  void (* tictactoe) (Tictactoe *ttt);
 
14547
};
 
14548
 
 
14549
GType          tictactoe_get_type        (void);
 
14550
GtkWidget*     tictactoe_new             (void);
 
14551
void           tictactoe_clear           (Tictactoe *ttt);
 
14552
 
 
14553
G_END_DECLS
 
14554
 
 
14555
#endif /* __TICTACTOE_H__ */
 
14556
 
 
14557
<!-- example-end -->
 
14558
</programlisting>
 
14559
 
 
14560
</sect2>
 
14561
 
 
14562
<!-- ----------------------------------------------------------------- -->
 
14563
<sect2>
 
14564
<title>tictactoe.c</title>
 
14565
 
 
14566
<programlisting role="C">
 
14567
<!-- example-start tictactoe tictactoe.c -->
 
14568
 
 
14569
/* GTK - The GIMP Toolkit
 
14570
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 
14571
 *
 
14572
 * This library is free software; you can redistribute it and/or
 
14573
 * modify it under the terms of the GNU Library General Public
 
14574
 * License as published by the Free Software Foundation; either
 
14575
 * version 2 of the License, or (at your option) any later version.
 
14576
 *
 
14577
 * This library is distributed in the hope that it will be useful,
 
14578
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14579
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14580
 * Library General Public License for more details.
 
14581
 *
 
14582
 * You should have received a copy of the GNU Library General Public
 
14583
 * License along with this library; if not, write to the
 
14584
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
14585
 * Boston, MA 02111-1307, USA.
 
14586
 */
 
14587
#include &lt;gtk/gtksignal.h&gt;
 
14588
#include &lt;gtk/gtktable.h&gt;
 
14589
#include &lt;gtk/gtktogglebutton.h&gt;
 
14590
#include "tictactoe.h"
 
14591
 
 
14592
enum {
 
14593
  TICTACTOE_SIGNAL,
 
14594
  LAST_SIGNAL
 
14595
};
 
14596
 
 
14597
static void tictactoe_class_init          (TictactoeClass *klass);
 
14598
static void tictactoe_init                (Tictactoe      *ttt);
 
14599
static void tictactoe_toggle              (GtkWidget *widget, Tictactoe *ttt);
 
14600
 
 
14601
static guint tictactoe_signals[LAST_SIGNAL] = { 0 };
 
14602
 
 
14603
GType
 
14604
tictactoe_get_type (void)
 
14605
{
 
14606
  static GType ttt_type = 0;
 
14607
 
 
14608
  if (!ttt_type)
 
14609
    {
 
14610
      static const GTypeInfo ttt_info =
 
14611
      {
 
14612
        sizeof (TictactoeClass),
 
14613
        NULL, /* base_init */
 
14614
        NULL, /* base_finalize */
 
14615
        (GClassInitFunc) tictactoe_class_init,
 
14616
        NULL, /* class_finalize */
 
14617
        NULL, /* class_data */
 
14618
        sizeof (Tictactoe),
 
14619
        0,
 
14620
        (GInstanceInitFunc) tictactoe_init,
 
14621
      };
 
14622
 
 
14623
      ttt_type = g_type_register_static (GTK_TYPE_TABLE, "Tictactoe", &amp;ttt_info, 0);
 
14624
    }
 
14625
 
 
14626
  return ttt_type;
 
14627
}
 
14628
 
 
14629
static void
 
14630
tictactoe_class_init (TictactoeClass *klass)
 
14631
{
 
14632
  
 
14633
  tictactoe_signals[TICTACTOE_SIGNAL] = g_signal_new ("tictactoe",
 
14634
                                         G_TYPE_FROM_CLASS (klass),
 
14635
                                         G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 
14636
                                         G_STRUCT_OFFSET (TictactoeClass, tictactoe),
 
14637
                                         NULL, 
 
14638
                                         NULL,                
 
14639
                                         g_cclosure_marshal_VOID__VOID,
 
14640
                                         G_TYPE_NONE, 0);
 
14641
 
 
14642
 
 
14643
}
 
14644
 
 
14645
static void
 
14646
tictactoe_init (Tictactoe *ttt)
 
14647
{
 
14648
  gint i,j;
 
14649
  
 
14650
  gtk_table_resize (GTK_TABLE (ttt), 3, 3);
 
14651
  gtk_table_set_homogeneous (GTK_TABLE (ttt), TRUE);
 
14652
 
 
14653
  for (i=0;i&lt;3; i++)
 
14654
    for (j=0;j&lt;3; j++)      {
 
14655
        ttt-&gt;buttons[i][j] = gtk_toggle_button_new ();
 
14656
        gtk_table_attach_defaults (GTK_TABLE (ttt), ttt-&gt;buttons[i][j], 
 
14657
                                   i, i+1, j, j+1);
 
14658
        g_signal_connect (G_OBJECT (ttt-&gt;buttons[i][j]), "toggled",
 
14659
                          G_CALLBACK (tictactoe_toggle), (gpointer) ttt);
 
14660
        gtk_widget_set_size_request (ttt-&gt;buttons[i][j], 20, 20);
 
14661
        gtk_widget_show (ttt-&gt;buttons[i][j]);
 
14662
      }
 
14663
}
 
14664
 
 
14665
GtkWidget*
 
14666
tictactoe_new ()
 
14667
{
 
14668
  return GTK_WIDGET (g_object_new (tictactoe_get_type (), NULL));
 
14669
}
 
14670
 
 
14671
void           
 
14672
tictactoe_clear (Tictactoe *ttt)
 
14673
{
 
14674
  int i,j;
 
14675
 
 
14676
  for (i = 0; i&lt;3; i++)
 
14677
    for (j = 0; j&lt;3; j++)
 
14678
      {
 
14679
        g_signal_handlers_block_matched (G_OBJECT (ttt-&gt;buttons[i][j]), 
 
14680
                                         G_SIGNAL_MATCH_DATA,
 
14681
                                         0, 0, NULL, NULL, ttt);
 
14682
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt-&gt;buttons[i][j]),
 
14683
                                      FALSE);
 
14684
        g_signal_handlers_unblock_matched (G_OBJECT (ttt->buttons[i][j]),
 
14685
                                           G_SIGNAL_MATCH_DATA,
 
14686
                                           0, 0, NULL, NULL, ttt);
 
14687
      }
 
14688
}
 
14689
 
 
14690
static void
 
14691
tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
 
14692
{
 
14693
  int i,k;
 
14694
 
 
14695
  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
 
14696
                             { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
 
14697
                             { 0, 1, 2 }, { 0, 1, 2 } };
 
14698
  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
 
14699
                             { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
 
14700
                             { 0, 1, 2 }, { 2, 1, 0 } };
 
14701
 
 
14702
  int success, found;
 
14703
 
 
14704
  for (k = 0; k&lt;8; k++)
 
14705
    {
 
14706
      success = TRUE;
 
14707
      found = FALSE;
 
14708
 
 
14709
      for (i = 0; i&lt;3; i++)
 
14710
        {
 
14711
          success = success &amp;&amp; 
 
14712
            GTK_TOGGLE_BUTTON (ttt-&gt;buttons[rwins[k][i]][cwins[k][i]])-&gt;active;
 
14713
          found = found ||
 
14714
            ttt-&gt;buttons[rwins[k][i]][cwins[k][i]] == widget;
 
14715
        }
 
14716
      
 
14717
      if (success &amp;&amp; found)
 
14718
        {
 
14719
          g_signal_emit (G_OBJECT (ttt), 
 
14720
                         tictactoe_signals[TICTACTOE_SIGNAL], 0);
 
14721
          break;
 
14722
        }
 
14723
    }
 
14724
}
 
14725
 
 
14726
<!-- example-end -->
 
14727
</programlisting>
 
14728
 
 
14729
</sect2>
 
14730
 
 
14731
<!-- ----------------------------------------------------------------- -->
 
14732
<sect2>
 
14733
<title>ttt_test.c</title>
 
14734
 
 
14735
<programlisting role="C">
 
14736
<!-- example-start tictactoe ttt_test.c -->
 
14737
 
 
14738
#include &lt;stdlib.h&gt;
 
14739
#include &lt;gtk/gtk.h&gt;
 
14740
#include "tictactoe.h"
 
14741
 
 
14742
void win( GtkWidget *widget,
 
14743
          gpointer   data )
 
14744
{
 
14745
  g_print ("Yay!\n");
 
14746
  tictactoe_clear (TICTACTOE (widget));
 
14747
}
 
14748
 
 
14749
int main( int   argc,
 
14750
          char *argv[] )
 
14751
{
 
14752
  GtkWidget *window;
 
14753
  GtkWidget *ttt;
 
14754
  
 
14755
  gtk_init (&amp;argc, &amp;argv);
 
14756
 
 
14757
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
14758
  
 
14759
  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
 
14760
  
 
14761
  g_signal_connect (G_OBJECT (window), "destroy",
 
14762
                    G_CALLBACK (exit), NULL);
 
14763
  
 
14764
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
14765
 
 
14766
  ttt = tictactoe_new ();
 
14767
  
 
14768
  gtk_container_add (GTK_CONTAINER (window), ttt);
 
14769
  gtk_widget_show (ttt);
 
14770
 
 
14771
  /* And attach to its "tictactoe" signal */
 
14772
  g_signal_connect (G_OBJECT (ttt), "tictactoe",
 
14773
                    G_CALLBACK (win), NULL);
 
14774
 
 
14775
  gtk_widget_show (window);
 
14776
  
 
14777
  gtk_main ();
 
14778
  
 
14779
  return 0;
 
14780
}
 
14781
 
 
14782
<!-- example-end -->
 
14783
</programlisting>
 
14784
 
 
14785
</sect2>
 
14786
</sect1>
 
14787
 
 
14788
<!-- ----------------------------------------------------------------- -->
 
14789
<sect1 id="sec-GtkDial">
 
14790
<title>GtkDial</title>
 
14791
 
 
14792
<!-- ----------------------------------------------------------------- -->
 
14793
<sect2>
 
14794
<title>gtkdial.h</title>
 
14795
 
 
14796
<programlisting role="C">
 
14797
<!-- example-start gtkdial gtkdial.h -->
 
14798
 
 
14799
/* GTK - The GIMP Toolkit
 
14800
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 
14801
 *
 
14802
 * This library is free software; you can redistribute it and/or
 
14803
 * modify it under the terms of the GNU Library General Public
 
14804
 * License as published by the Free Software Foundation; either
 
14805
 * version 2 of the License, or (at your option) any later version.
 
14806
 *
 
14807
 * This library is distributed in the hope that it will be useful,
 
14808
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14809
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14810
 * Library General Public License for more details.
 
14811
 *
 
14812
 * You should have received a copy of the GNU Library General Public
 
14813
 * License along with this library; if not, write to the
 
14814
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
14815
 * Boston, MA 02111-1307, USA.
 
14816
 */
 
14817
#ifndef __GTK_DIAL_H__
 
14818
#define __GTK_DIAL_H__
 
14819
 
 
14820
 
 
14821
#include &lt;gdk/gdk.h&gt;
 
14822
#include &lt;gtk/gtkadjustment.h&gt;
 
14823
#include &lt;gtk/gtkwidget.h&gt;
 
14824
 
 
14825
 
 
14826
#ifdef __cplusplus
 
14827
extern "C" {
 
14828
#endif /* __cplusplus */
 
14829
 
 
14830
 
 
14831
#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
 
14832
#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
 
14833
#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
 
14834
 
 
14835
 
 
14836
typedef struct _GtkDial        GtkDial;
 
14837
typedef struct _GtkDialClass   GtkDialClass;
 
14838
 
 
14839
struct _GtkDial
 
14840
{
 
14841
  GtkWidget widget;
 
14842
 
 
14843
  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
 
14844
  guint policy : 2;
 
14845
 
 
14846
  /* Button currently pressed or 0 if none */
 
14847
  guint8 button;
 
14848
 
 
14849
  /* Dimensions of dial components */
 
14850
  gint radius;
 
14851
  gint pointer_width;
 
14852
 
 
14853
  /* ID of update timer, or 0 if none */
 
14854
  guint32 timer;
 
14855
 
 
14856
  /* Current angle */
 
14857
  gfloat angle;
 
14858
  gfloat last_angle;
 
14859
 
 
14860
  /* Old values from adjustment stored so we know when something changes */
 
14861
  gfloat old_value;
 
14862
  gfloat old_lower;
 
14863
  gfloat old_upper;
 
14864
 
 
14865
  /* The adjustment object that stores the data for this dial */
 
14866
  GtkAdjustment *adjustment;
 
14867
};
 
14868
 
 
14869
struct _GtkDialClass
 
14870
{
 
14871
  GtkWidgetClass parent_class;
 
14872
};
 
14873
 
 
14874
 
 
14875
GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
 
14876
GtkType        gtk_dial_get_type               (void);
 
14877
GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
 
14878
void           gtk_dial_set_update_policy      (GtkDial      *dial,
 
14879
                                                GtkUpdateType  policy);
 
14880
 
 
14881
void           gtk_dial_set_adjustment         (GtkDial      *dial,
 
14882
                                                GtkAdjustment *adjustment);
 
14883
#ifdef __cplusplus
 
14884
}
 
14885
#endif /* __cplusplus */
 
14886
 
 
14887
 
 
14888
#endif /* __GTK_DIAL_H__ */
 
14889
<!-- example-end -->
 
14890
</programlisting>
 
14891
 
 
14892
</sect2>
 
14893
 
 
14894
<!-- ----------------------------------------------------------------- -->
 
14895
<sect2>
 
14896
<title>gtkdial.c</title>
 
14897
 
 
14898
<programlisting role="C">
 
14899
<!-- example-start gtkdial gtkdial.c -->
 
14900
 
 
14901
/* GTK - The GIMP Toolkit
 
14902
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 
14903
 *
 
14904
 * This library is free software; you can redistribute it and/or
 
14905
 * modify it under the terms of the GNU Library General Public
 
14906
 * License as published by the Free Software Foundation; either
 
14907
 * version 2 of the License, or (at your option) any later version.
 
14908
 *
 
14909
 * This library is distributed in the hope that it will be useful,
 
14910
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14911
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14912
 * Library General Public License for more details.
 
14913
 *
 
14914
 * You should have received a copy of the GNU Library General Public
 
14915
 * License along with this library; if not, write to the
 
14916
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
14917
 * Boston, MA 02111-1307, USA.
 
14918
 */
 
14919
#include &lt;math.h&gt;
 
14920
#include &lt;stdio.h&gt;
 
14921
#include &lt;gtk/gtkmain.h&gt;
 
14922
#include &lt;gtk/gtksignal.h&gt;
 
14923
 
 
14924
#include "gtkdial.h"
 
14925
 
 
14926
#define SCROLL_DELAY_LENGTH  300
 
14927
#define DIAL_DEFAULT_SIZE 100
 
14928
 
 
14929
/* Forward declarations */
 
14930
 
 
14931
static void gtk_dial_class_init               (GtkDialClass     *klass);
 
14932
static void gtk_dial_init                     (GtkDial          *dial);
 
14933
static void gtk_dial_destroy                  (GtkObject        *object);
 
14934
static void gtk_dial_realize                  (GtkWidget        *widget);
 
14935
static void gtk_dial_size_request             (GtkWidget        *widget,
 
14936
                                               GtkRequisition   *requisition);
 
14937
static void gtk_dial_size_allocate            (GtkWidget        *widget,
 
14938
                                               GtkAllocation    *allocation);
 
14939
static gboolean gtk_dial_expose               (GtkWidget        *widget,
 
14940
                                               GdkEventExpose   *event);
 
14941
static gboolean gtk_dial_button_press         (GtkWidget        *widget,
 
14942
                                               GdkEventButton   *event);
 
14943
static gboolean gtk_dial_button_release       (GtkWidget        *widget,
 
14944
                                               GdkEventButton   *event);
 
14945
static gboolean gtk_dial_motion_notify        (GtkWidget        *widget,
 
14946
                                               GdkEventMotion   *event);
 
14947
static gboolean gtk_dial_timer                (GtkDial          *dial);
 
14948
 
 
14949
static void gtk_dial_update_mouse             (GtkDial *dial, gint x, gint y);
 
14950
static void gtk_dial_update                   (GtkDial *dial);
 
14951
static void gtk_dial_adjustment_changed       (GtkAdjustment    *adjustment,
 
14952
                                                gpointer          data);
 
14953
static void gtk_dial_adjustment_value_changed (GtkAdjustment    *adjustment,
 
14954
                                                gpointer          data);
 
14955
 
 
14956
/* Local data */
 
14957
 
 
14958
static GtkWidgetClass *parent_class = NULL;
 
14959
 
 
14960
GType
 
14961
gtk_dial_get_type ()
 
14962
{
 
14963
  static GType dial_type = 0;
 
14964
 
 
14965
  if (!dial_type)
 
14966
    {
 
14967
      static const GTypeInfo dial_info =
 
14968
      {
 
14969
        sizeof (GtkDialClass),
 
14970
        NULL,
 
14971
        NULL,
 
14972
        (GClassInitFunc) gtk_dial_class_init,
 
14973
        NULL,
 
14974
        NULL,
 
14975
        sizeof (GtkDial),
 
14976
        0,
 
14977
        (GInstanceInitFunc) gtk_dial_init,
 
14978
      };
 
14979
 
 
14980
      dial_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkDial", &amp;dial_info, 0);
 
14981
    }
 
14982
 
 
14983
  return dial_type;
 
14984
}
 
14985
 
 
14986
static void
 
14987
gtk_dial_class_init (GtkDialClass *class)
 
14988
{
 
14989
  GtkObjectClass *object_class;
 
14990
  GtkWidgetClass *widget_class;
 
14991
 
 
14992
  object_class = (GtkObjectClass*) class;
 
14993
  widget_class = (GtkWidgetClass*) class;
 
14994
 
 
14995
  parent_class = gtk_type_class (gtk_widget_get_type ());
 
14996
 
 
14997
  object_class-&gt;destroy = gtk_dial_destroy;
 
14998
 
 
14999
  widget_class-&gt;realize = gtk_dial_realize;
 
15000
  widget_class-&gt;expose_event = gtk_dial_expose;
 
15001
  widget_class-&gt;size_request = gtk_dial_size_request;
 
15002
  widget_class-&gt;size_allocate = gtk_dial_size_allocate;
 
15003
  widget_class-&gt;button_press_event = gtk_dial_button_press;
 
15004
  widget_class-&gt;button_release_event = gtk_dial_button_release;
 
15005
  widget_class-&gt;motion_notify_event = gtk_dial_motion_notify;
 
15006
}
 
15007
 
 
15008
static void
 
15009
gtk_dial_init (GtkDial *dial)
 
15010
{
 
15011
  dial-&gt;button = 0;
 
15012
  dial-&gt;policy = GTK_UPDATE_CONTINUOUS;
 
15013
  dial-&gt;timer = 0;
 
15014
  dial-&gt;radius = 0;
 
15015
  dial-&gt;pointer_width = 0;
 
15016
  dial-&gt;angle = 0.0;
 
15017
  dial-&gt;old_value = 0.0;
 
15018
  dial-&gt;old_lower = 0.0;
 
15019
  dial-&gt;old_upper = 0.0;
 
15020
  dial-&gt;adjustment = NULL;
 
15021
}
 
15022
 
 
15023
GtkWidget*
 
15024
gtk_dial_new (GtkAdjustment *adjustment)
 
15025
{
 
15026
  GtkDial *dial;
 
15027
 
 
15028
  dial = g_object_new (gtk_dial_get_type (), NULL);
 
15029
 
 
15030
  if (!adjustment)
 
15031
    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
 
15032
 
 
15033
  gtk_dial_set_adjustment (dial, adjustment);
 
15034
 
 
15035
  return GTK_WIDGET (dial);
 
15036
}
 
15037
 
 
15038
static void
 
15039
gtk_dial_destroy (GtkObject *object)
 
15040
{
 
15041
  GtkDial *dial;
 
15042
 
 
15043
  g_return_if_fail (object != NULL);
 
15044
  g_return_if_fail (GTK_IS_DIAL (object));
 
15045
 
 
15046
  dial = GTK_DIAL (object);
 
15047
 
 
15048
  if (dial-&gt;adjustment)
 
15049
    {
 
15050
      g_object_unref (GTK_OBJECT (dial-&gt;adjustment));
 
15051
      dial-&gt;adjustment = NULL;
 
15052
    }
 
15053
 
 
15054
  if (GTK_OBJECT_CLASS (parent_class)-&gt;destroy)
 
15055
    (* GTK_OBJECT_CLASS (parent_class)-&gt;destroy) (object);
 
15056
}
 
15057
 
 
15058
GtkAdjustment*
 
15059
gtk_dial_get_adjustment (GtkDial *dial)
 
15060
{
 
15061
  g_return_val_if_fail (dial != NULL, NULL);
 
15062
  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
 
15063
 
 
15064
  return dial-&gt;adjustment;
 
15065
}
 
15066
 
 
15067
void
 
15068
gtk_dial_set_update_policy (GtkDial      *dial,
 
15069
                             GtkUpdateType  policy)
 
15070
{
 
15071
  g_return_if_fail (dial != NULL);
 
15072
  g_return_if_fail (GTK_IS_DIAL (dial));
 
15073
 
 
15074
  dial-&gt;policy = policy;
 
15075
}
 
15076
 
 
15077
void
 
15078
gtk_dial_set_adjustment (GtkDial      *dial,
 
15079
                          GtkAdjustment *adjustment)
 
15080
{
 
15081
  g_return_if_fail (dial != NULL);
 
15082
  g_return_if_fail (GTK_IS_DIAL (dial));
 
15083
 
 
15084
  if (dial-&gt;adjustment)
 
15085
    {
 
15086
      g_signal_handlers_disconnect_by_func (GTK_OBJECT (dial-&gt;adjustment), NULL, (gpointer) dial);
 
15087
      g_object_unref (GTK_OBJECT (dial-&gt;adjustment));
 
15088
    }
 
15089
 
 
15090
  dial-&gt;adjustment = adjustment;
 
15091
  g_object_ref (GTK_OBJECT (dial-&gt;adjustment));
 
15092
 
 
15093
  g_signal_connect (GTK_OBJECT (adjustment), "changed",
 
15094
                    GTK_SIGNAL_FUNC (gtk_dial_adjustment_changed),
 
15095
                    (gpointer) dial);
 
15096
  g_signal_connect (GTK_OBJECT (adjustment), "value_changed",
 
15097
                    GTK_SIGNAL_FUNC (gtk_dial_adjustment_value_changed),
 
15098
                    (gpointer) dial);
 
15099
 
 
15100
  dial-&gt;old_value = adjustment-&gt;value;
 
15101
  dial-&gt;old_lower = adjustment-&gt;lower;
 
15102
  dial-&gt;old_upper = adjustment-&gt;upper;
 
15103
 
 
15104
  gtk_dial_update (dial);
 
15105
}
 
15106
 
 
15107
static void
 
15108
gtk_dial_realize (GtkWidget *widget)
 
15109
{
 
15110
  GtkDial *dial;
 
15111
  GdkWindowAttr attributes;
 
15112
  gint attributes_mask;
 
15113
 
 
15114
  g_return_if_fail (widget != NULL);
 
15115
  g_return_if_fail (GTK_IS_DIAL (widget));
 
15116
 
 
15117
  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
15118
  dial = GTK_DIAL (widget);
 
15119
 
 
15120
  attributes.x = widget-&gt;allocation.x;
 
15121
  attributes.y = widget-&gt;allocation.y;
 
15122
  attributes.width = widget-&gt;allocation.width;
 
15123
  attributes.height = widget-&gt;allocation.height;
 
15124
  attributes.wclass = GDK_INPUT_OUTPUT;
 
15125
  attributes.window_type = GDK_WINDOW_CHILD;
 
15126
  attributes.event_mask = gtk_widget_get_events (widget) | 
 
15127
    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
 
15128
    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
 
15129
    GDK_POINTER_MOTION_HINT_MASK;
 
15130
  attributes.visual = gtk_widget_get_visual (widget);
 
15131
  attributes.colormap = gtk_widget_get_colormap (widget);
 
15132
 
 
15133
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
 
15134
  widget-&gt;window = gdk_window_new (widget-&gt;parent-&gt;window, &amp;attributes, attributes_mask);
 
15135
 
 
15136
  widget-&gt;style = gtk_style_attach (widget-&gt;style, widget-&gt;window);
 
15137
 
 
15138
  gdk_window_set_user_data (widget-&gt;window, widget);
 
15139
 
 
15140
  gtk_style_set_background (widget-&gt;style, widget-&gt;window, GTK_STATE_ACTIVE);
 
15141
}
 
15142
 
 
15143
static void 
 
15144
gtk_dial_size_request (GtkWidget      *widget,
 
15145
                       GtkRequisition *requisition)
 
15146
{
 
15147
  requisition-&gt;width = DIAL_DEFAULT_SIZE;
 
15148
  requisition-&gt;height = DIAL_DEFAULT_SIZE;
 
15149
}
 
15150
 
 
15151
static void
 
15152
gtk_dial_size_allocate (GtkWidget     *widget,
 
15153
                        GtkAllocation *allocation)
 
15154
{
 
15155
  GtkDial *dial;
 
15156
 
 
15157
  g_return_if_fail (widget != NULL);
 
15158
  g_return_if_fail (GTK_IS_DIAL (widget));
 
15159
  g_return_if_fail (allocation != NULL);
 
15160
 
 
15161
  widget-&gt;allocation = *allocation;
 
15162
  dial = GTK_DIAL (widget);
 
15163
 
 
15164
  if (GTK_WIDGET_REALIZED (widget))
 
15165
    {
 
15166
 
 
15167
      gdk_window_move_resize (widget-&gt;window,
 
15168
                              allocation-&gt;x, allocation-&gt;y,
 
15169
                              allocation-&gt;width, allocation-&gt;height);
 
15170
 
 
15171
    }
 
15172
  dial-&gt;radius = MIN (allocation-&gt;width, allocation-&gt;height) * 0.45;
 
15173
  dial-&gt;pointer_width = dial-&gt;radius / 5;
 
15174
}
 
15175
 
 
15176
static gboolean
 
15177
gtk_dial_expose( GtkWidget      *widget,
 
15178
                 GdkEventExpose *event )
 
15179
{
 
15180
  GtkDial *dial;
 
15181
  GdkPoint points[6];
 
15182
  gdouble s,c;
 
15183
  gdouble theta, last, increment;
 
15184
  GtkStyle      *blankstyle;
 
15185
  gint xc, yc;
 
15186
  gint upper, lower;
 
15187
  gint tick_length;
 
15188
  gint i, inc;
 
15189
 
 
15190
  g_return_val_if_fail (widget != NULL, FALSE);
 
15191
  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
 
15192
  g_return_val_if_fail (event != NULL, FALSE);
 
15193
 
 
15194
  if (event-&gt;count &gt; 0)
 
15195
    return FALSE;
 
15196
  
 
15197
  dial = GTK_DIAL (widget);
 
15198
 
 
15199
/*  gdk_window_clear_area (widget-&gt;window,
 
15200
                         0, 0,
 
15201
                         widget-&gt;allocation.width,
 
15202
                         widget-&gt;allocation.height);
 
15203
*/
 
15204
  xc = widget-&gt;allocation.width / 2;
 
15205
  yc = widget-&gt;allocation.height / 2;
 
15206
 
 
15207
  upper = dial-&gt;adjustment-&gt;upper;
 
15208
  lower = dial-&gt;adjustment-&gt;lower;
 
15209
 
 
15210
  /* Erase old pointer */
 
15211
 
 
15212
  s = sin (dial-&gt;last_angle);
 
15213
  c = cos (dial-&gt;last_angle);
 
15214
  dial-&gt;last_angle = dial-&gt;angle;
 
15215
 
 
15216
  points[0].x = xc + s*dial-&gt;pointer_width/2;
 
15217
  points[0].y = yc + c*dial-&gt;pointer_width/2;
 
15218
  points[1].x = xc + c*dial-&gt;radius;
 
15219
  points[1].y = yc - s*dial-&gt;radius;
 
15220
  points[2].x = xc - s*dial-&gt;pointer_width/2;
 
15221
  points[2].y = yc - c*dial-&gt;pointer_width/2;
 
15222
  points[3].x = xc - c*dial-&gt;radius/10;
 
15223
  points[3].y = yc + s*dial-&gt;radius/10;
 
15224
  points[4].x = points[0].x;
 
15225
  points[4].y = points[0].y;
 
15226
 
 
15227
  blankstyle = gtk_style_new ();
 
15228
  blankstyle-&gt;bg_gc[GTK_STATE_NORMAL] =
 
15229
                widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
 
15230
  blankstyle-&gt;dark_gc[GTK_STATE_NORMAL] =
 
15231
                widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
 
15232
  blankstyle-&gt;light_gc[GTK_STATE_NORMAL] =
 
15233
                widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
 
15234
  blankstyle-&gt;black_gc =
 
15235
                widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
 
15236
 
 
15237
  gtk_paint_polygon (blankstyle,
 
15238
                    widget-&gt;window,
 
15239
                    GTK_STATE_NORMAL,
 
15240
                    GTK_SHADOW_OUT,
 
15241
                    NULL,
 
15242
                    widget,
 
15243
                    NULL,
 
15244
                    points, 5,
 
15245
                    FALSE);
 
15246
 
 
15247
  g_object_unref (blankstyle);
 
15248
 
 
15249
 
 
15250
  /* Draw ticks */
 
15251
 
 
15252
  if ((upper - lower) == 0)
 
15253
    return FALSE;
 
15254
 
 
15255
  increment = (100*M_PI) / (dial-&gt;radius*dial-&gt;radius);
 
15256
 
 
15257
  inc = (upper - lower);
 
15258
 
 
15259
  while (inc &lt; 100) inc *= 10;
 
15260
  while (inc &gt;= 1000) inc /= 10;
 
15261
  last = -1;
 
15262
 
 
15263
  for (i = 0; i &lt;= inc; i++)
 
15264
    {
 
15265
      theta = ((gfloat)i*M_PI / (18*inc/24.) - M_PI/6.);
 
15266
 
 
15267
      if ((theta - last) &lt; (increment))
 
15268
        continue;     
 
15269
      last = theta;
 
15270
 
 
15271
      s = sin (theta);
 
15272
      c = cos (theta);
 
15273
 
 
15274
      tick_length = (i%(inc/10) == 0) ? dial-&gt;pointer_width : dial-&gt;pointer_width / 2;
 
15275
 
 
15276
      gdk_draw_line (widget-&gt;window,
 
15277
                     widget-&gt;style-&gt;fg_gc[widget-&gt;state],
 
15278
                     xc + c*(dial-&gt;radius - tick_length),
 
15279
                     yc - s*(dial-&gt;radius - tick_length),
 
15280
                     xc + c*dial-&gt;radius,
 
15281
                     yc - s*dial-&gt;radius);
 
15282
    }
 
15283
 
 
15284
  /* Draw pointer */
 
15285
 
 
15286
  s = sin (dial-&gt;angle);
 
15287
  c = cos (dial-&gt;angle);
 
15288
  dial-&gt;last_angle = dial-&gt;angle;
 
15289
 
 
15290
  points[0].x = xc + s*dial-&gt;pointer_width/2;
 
15291
  points[0].y = yc + c*dial-&gt;pointer_width/2;
 
15292
  points[1].x = xc + c*dial-&gt;radius;
 
15293
  points[1].y = yc - s*dial-&gt;radius;
 
15294
  points[2].x = xc - s*dial-&gt;pointer_width/2;
 
15295
  points[2].y = yc - c*dial-&gt;pointer_width/2;
 
15296
  points[3].x = xc - c*dial-&gt;radius/10;
 
15297
  points[3].y = yc + s*dial-&gt;radius/10;
 
15298
  points[4].x = points[0].x;
 
15299
  points[4].y = points[0].y;
 
15300
 
 
15301
 
 
15302
  gtk_paint_polygon (widget-&gt;style,
 
15303
                    widget-&gt;window,
 
15304
                    GTK_STATE_NORMAL,
 
15305
                    GTK_SHADOW_OUT,
 
15306
                    NULL,
 
15307
                    widget,
 
15308
                    NULL,
 
15309
                    points, 5,
 
15310
                    TRUE);
 
15311
 
 
15312
  return FALSE;
 
15313
}
 
15314
 
 
15315
static gboolean
 
15316
gtk_dial_button_press( GtkWidget      *widget,
 
15317
                       GdkEventButton *event )
 
15318
{
 
15319
  GtkDial *dial;
 
15320
  gint dx, dy;
 
15321
  double s, c;
 
15322
  double d_parallel;
 
15323
  double d_perpendicular;
 
15324
 
 
15325
  g_return_val_if_fail (widget != NULL, FALSE);
 
15326
  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
 
15327
  g_return_val_if_fail (event != NULL, FALSE);
 
15328
 
 
15329
  dial = GTK_DIAL (widget);
 
15330
 
 
15331
  /* Determine if button press was within pointer region - we 
 
15332
     do this by computing the parallel and perpendicular distance of
 
15333
     the point where the mouse was pressed from the line passing through
 
15334
     the pointer */
 
15335
  
 
15336
  dx = event-&gt;x - widget-&gt;allocation.width / 2;
 
15337
  dy = widget-&gt;allocation.height / 2 - event-&gt;y;
 
15338
  
 
15339
  s = sin (dial-&gt;angle);
 
15340
  c = cos (dial-&gt;angle);
 
15341
  
 
15342
  d_parallel = s*dy + c*dx;
 
15343
  d_perpendicular = fabs (s*dx - c*dy);
 
15344
  
 
15345
  if (!dial-&gt;button &amp;&amp;
 
15346
      (d_perpendicular &lt; dial-&gt;pointer_width/2) &amp;&amp;
 
15347
      (d_parallel &gt; - dial-&gt;pointer_width))
 
15348
    {
 
15349
      gtk_grab_add (widget);
 
15350
 
 
15351
      dial-&gt;button = event-&gt;button;
 
15352
 
 
15353
      gtk_dial_update_mouse (dial, event-&gt;x, event-&gt;y);
 
15354
    }
 
15355
 
 
15356
  return FALSE;
 
15357
}
 
15358
 
 
15359
static gboolean
 
15360
gtk_dial_button_release( GtkWidget      *widget,
 
15361
                         GdkEventButton *event )
 
15362
{
 
15363
  GtkDial *dial;
 
15364
 
 
15365
  g_return_val_if_fail (widget != NULL, FALSE);
 
15366
  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
 
15367
  g_return_val_if_fail (event != NULL, FALSE);
 
15368
 
 
15369
  dial = GTK_DIAL (widget);
 
15370
 
 
15371
  if (dial-&gt;button == event-&gt;button)
 
15372
    {
 
15373
      gtk_grab_remove (widget);
 
15374
 
 
15375
      dial-&gt;button = 0;
 
15376
 
 
15377
      if (dial-&gt;policy == GTK_UPDATE_DELAYED)
 
15378
        g_source_remove (dial-&gt;timer);
 
15379
      
 
15380
      if ((dial-&gt;policy != GTK_UPDATE_CONTINUOUS) &amp;&amp;
 
15381
          (dial-&gt;old_value != dial-&gt;adjustment-&gt;value))
 
15382
        g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
 
15383
    }
 
15384
 
 
15385
  return FALSE;
 
15386
}
 
15387
 
 
15388
static gboolean
 
15389
gtk_dial_motion_notify( GtkWidget      *widget,
 
15390
                        GdkEventMotion *event )
 
15391
{
 
15392
  GtkDial *dial;
 
15393
  GdkModifierType mods;
 
15394
  gint x, y, mask;
 
15395
 
 
15396
  g_return_val_if_fail (widget != NULL, FALSE);
 
15397
  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
 
15398
  g_return_val_if_fail (event != NULL, FALSE);
 
15399
 
 
15400
  dial = GTK_DIAL (widget);
 
15401
 
 
15402
  if (dial-&gt;button != 0)
 
15403
    {
 
15404
      x = event-&gt;x;
 
15405
      y = event-&gt;y;
 
15406
 
 
15407
      if (event-&gt;is_hint || (event-&gt;window != widget-&gt;window))
 
15408
        gdk_window_get_pointer (widget-&gt;window, &amp;x, &amp;y, &amp;mods);
 
15409
 
 
15410
      switch (dial-&gt;button)
 
15411
        {
 
15412
        case 1:
 
15413
          mask = GDK_BUTTON1_MASK;
 
15414
          break;
 
15415
        case 2:
 
15416
          mask = GDK_BUTTON2_MASK;
 
15417
          break;
 
15418
        case 3:
 
15419
          mask = GDK_BUTTON3_MASK;
 
15420
          break;
 
15421
        default:
 
15422
          mask = 0;
 
15423
          break;
 
15424
        }
 
15425
 
 
15426
      if (mods &amp; mask)
 
15427
        gtk_dial_update_mouse (dial, x,y);
 
15428
    }
 
15429
 
 
15430
  return FALSE;
 
15431
}
 
15432
 
 
15433
static gboolean
 
15434
gtk_dial_timer( GtkDial *dial )
 
15435
{
 
15436
  g_return_val_if_fail (dial != NULL, FALSE);
 
15437
  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
 
15438
 
 
15439
  if (dial-&gt;policy == GTK_UPDATE_DELAYED)
 
15440
    g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
 
15441
 
 
15442
  return FALSE;
 
15443
}
 
15444
 
 
15445
static void
 
15446
gtk_dial_update_mouse( GtkDial *dial, gint x, gint y )
 
15447
{
 
15448
  gint xc, yc;
 
15449
  gfloat old_value;
 
15450
 
 
15451
  g_return_if_fail (dial != NULL);
 
15452
  g_return_if_fail (GTK_IS_DIAL (dial));
 
15453
 
 
15454
  xc = GTK_WIDGET(dial)-&gt;allocation.width / 2;
 
15455
  yc = GTK_WIDGET(dial)-&gt;allocation.height / 2;
 
15456
 
 
15457
  old_value = dial-&gt;adjustment-&gt;value;
 
15458
  dial-&gt;angle = atan2(yc-y, x-xc);
 
15459
 
 
15460
  if (dial-&gt;angle &lt; -M_PI/2.)
 
15461
    dial-&gt;angle += 2*M_PI;
 
15462
 
 
15463
  if (dial-&gt;angle &lt; -M_PI/6)
 
15464
    dial-&gt;angle = -M_PI/6;
 
15465
 
 
15466
  if (dial-&gt;angle &gt; 7.*M_PI/6.)
 
15467
    dial-&gt;angle = 7.*M_PI/6.;
 
15468
 
 
15469
  dial-&gt;adjustment-&gt;value = dial-&gt;adjustment-&gt;lower + (7.*M_PI/6 - dial-&gt;angle) *
 
15470
    (dial-&gt;adjustment-&gt;upper - dial-&gt;adjustment-&gt;lower) / (4.*M_PI/3.);
 
15471
 
 
15472
  if (dial-&gt;adjustment-&gt;value != old_value)
 
15473
    {
 
15474
      if (dial-&gt;policy == GTK_UPDATE_CONTINUOUS)
 
15475
        {
 
15476
          g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
 
15477
        }
 
15478
      else
 
15479
        {
 
15480
          gtk_widget_queue_draw (GTK_WIDGET (dial));
 
15481
 
 
15482
          if (dial-&gt;policy == GTK_UPDATE_DELAYED)
 
15483
            {
 
15484
              if (dial-&gt;timer)
 
15485
                g_source_remove (dial-&gt;timer);
 
15486
 
 
15487
              dial-&gt;timer = g_timeout_add (SCROLL_DELAY_LENGTH,
 
15488
                                           (GtkFunction) gtk_dial_timer,
 
15489
                                           (gpointer) dial);
 
15490
            }
 
15491
        }
 
15492
    }
 
15493
}
 
15494
 
 
15495
static void
 
15496
gtk_dial_update (GtkDial *dial)
 
15497
{
 
15498
  gfloat new_value;
 
15499
  
 
15500
  g_return_if_fail (dial != NULL);
 
15501
  g_return_if_fail (GTK_IS_DIAL (dial));
 
15502
 
 
15503
  new_value = dial-&gt;adjustment-&gt;value;
 
15504
  
 
15505
  if (new_value &lt; dial-&gt;adjustment-&gt;lower)
 
15506
    new_value = dial-&gt;adjustment-&gt;lower;
 
15507
 
 
15508
  if (new_value &gt; dial-&gt;adjustment-&gt;upper)
 
15509
    new_value = dial-&gt;adjustment-&gt;upper;
 
15510
 
 
15511
  if (new_value != dial-&gt;adjustment-&gt;value)
 
15512
    {
 
15513
      dial-&gt;adjustment-&gt;value = new_value;
 
15514
      g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
 
15515
    }
 
15516
 
 
15517
  dial-&gt;angle = 7.*M_PI/6. - (new_value - dial-&gt;adjustment-&gt;lower) * 4.*M_PI/3. /
 
15518
    (dial-&gt;adjustment-&gt;upper - dial-&gt;adjustment-&gt;lower);
 
15519
 
 
15520
  gtk_widget_queue_draw (GTK_WIDGET (dial));
 
15521
}
 
15522
 
 
15523
static void
 
15524
gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
 
15525
                              gpointer       data)
 
15526
{
 
15527
  GtkDial *dial;
 
15528
 
 
15529
  g_return_if_fail (adjustment != NULL);
 
15530
  g_return_if_fail (data != NULL);
 
15531
 
 
15532
  dial = GTK_DIAL (data);
 
15533
 
 
15534
  if ((dial-&gt;old_value != adjustment-&gt;value) ||
 
15535
      (dial-&gt;old_lower != adjustment-&gt;lower) ||
 
15536
      (dial-&gt;old_upper != adjustment-&gt;upper))
 
15537
    {
 
15538
      gtk_dial_update (dial);
 
15539
 
 
15540
      dial-&gt;old_value = adjustment-&gt;value;
 
15541
      dial-&gt;old_lower = adjustment-&gt;lower;
 
15542
      dial-&gt;old_upper = adjustment-&gt;upper;
 
15543
    }
 
15544
}
 
15545
 
 
15546
static void
 
15547
gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
 
15548
                                    gpointer       data)
 
15549
{
 
15550
  GtkDial *dial;
 
15551
 
 
15552
  g_return_if_fail (adjustment != NULL);
 
15553
  g_return_if_fail (data != NULL);
 
15554
 
 
15555
  dial = GTK_DIAL (data);
 
15556
 
 
15557
  if (dial-&gt;old_value != adjustment-&gt;value)
 
15558
    {
 
15559
      gtk_dial_update (dial);
 
15560
 
 
15561
      dial-&gt;old_value = adjustment-&gt;value;
 
15562
    }
 
15563
}
 
15564
<!-- example-end -->
 
15565
</programlisting>
 
15566
 
 
15567
</sect2>
 
15568
 
 
15569
<!-- ----------------------------------------------------------------- -->
 
15570
<sect2>
 
15571
<title>dial_test.c</title>
 
15572
 
 
15573
<programlisting role="C">
 
15574
<!-- example-start gtkdial dial_test.c -->
 
15575
 
 
15576
#include &lt;stdio.h&gt;
 
15577
#include &lt;stdlib.h&gt;
 
15578
#include &lt;gtk/gtk.h&gt;
 
15579
#include "gtkdial.h"
 
15580
 
 
15581
void value_changed( GtkAdjustment *adjustment,
 
15582
                    GtkWidget     *label )
 
15583
{
 
15584
  char buffer[16];
 
15585
 
 
15586
  sprintf(buffer,"%4.2f",adjustment-&gt;value);
 
15587
  gtk_label_set_text (GTK_LABEL (label), buffer);
 
15588
}
 
15589
 
 
15590
int main( int   argc,
 
15591
          char *argv[])
 
15592
{
 
15593
  GtkWidget *window;
 
15594
  GtkAdjustment *adjustment;
 
15595
  GtkWidget *dial;
 
15596
  GtkWidget *frame;
 
15597
  GtkWidget *vbox;
 
15598
  GtkWidget *label;
 
15599
  
 
15600
  gtk_init (&amp;argc, &amp;argv);
 
15601
 
 
15602
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
15603
  
 
15604
  gtk_window_set_title (GTK_WINDOW (window), "Dial");
 
15605
  
 
15606
  g_signal_connect (G_OBJECT (window), "destroy",
 
15607
                    G_CALLBACK (exit), NULL);
 
15608
  
 
15609
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
15610
 
 
15611
  vbox = gtk_vbox_new (FALSE, 5);
 
15612
  gtk_container_add (GTK_CONTAINER (window), vbox);
 
15613
  gtk_widget_show (vbox);
 
15614
 
 
15615
  frame = gtk_frame_new (NULL);
 
15616
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
 
15617
  gtk_container_add (GTK_CONTAINER (vbox), frame);
 
15618
  gtk_widget_show (frame); 
 
15619
 
 
15620
  adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 100, 0.01, 0.1, 0));
 
15621
  
 
15622
  dial = gtk_dial_new (adjustment);
 
15623
  gtk_dial_set_update_policy (GTK_DIAL (dial), GTK_UPDATE_DELAYED);
 
15624
  /*  gtk_widget_set_size_request (dial, 100, 100); */
 
15625
  
 
15626
  gtk_container_add (GTK_CONTAINER (frame), dial);
 
15627
  gtk_widget_show (dial);
 
15628
 
 
15629
  label = gtk_label_new ("0.00");
 
15630
  gtk_box_pack_end (GTK_BOX (vbox), label, 0, 0, 0);
 
15631
  gtk_widget_show (label);
 
15632
 
 
15633
  g_signal_connect (G_OBJECT (adjustment), "value_changed",
 
15634
                    G_CALLBACK (value_changed), (gpointer) label);
 
15635
  
 
15636
  gtk_widget_show (window);
 
15637
  
 
15638
  gtk_main ();
 
15639
  
 
15640
  return 0;
 
15641
}
 
15642
<!-- example-end -->
 
15643
</programlisting>
 
15644
 
 
15645
</sect2>
 
15646
</sect1>
 
15647
 
 
15648
<!-- ----------------------------------------------------------------- -->
 
15649
<sect1 id="sec-Scribble">
 
15650
<title>Scribble</title>
 
15651
 
 
15652
<!-- ----------------------------------------------------------------- -->
 
15653
<sect2>
 
15654
<title>scribble-simple.c</title>
 
15655
 
 
15656
<programlisting role="C">
 
15657
<!-- example-start scribble-simple scribble-simple.c -->
 
15658
 
 
15659
/* GTK - The GIMP Toolkit
 
15660
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 
15661
 *
 
15662
 * This library is free software; you can redistribute it and/or
 
15663
 * modify it under the terms of the GNU Library General Public
 
15664
 * License as published by the Free Software Foundation; either
 
15665
 * version 2 of the License, or (at your option) any later version.
 
15666
 *
 
15667
 * This library is distributed in the hope that it will be useful,
 
15668
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15669
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15670
 * Library General Public License for more details.
 
15671
 *
 
15672
 * You should have received a copy of the GNU Library General Public
 
15673
 * License along with this library; if not, write to the
 
15674
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
15675
 * Boston, MA 02111-1307, USA.
 
15676
 */
 
15677
 
 
15678
#include &lt;stdlib.h&gt;
 
15679
#include &lt;gtk/gtk.h&gt;
 
15680
 
 
15681
/* Backing pixmap for drawing area */
 
15682
static GdkPixmap *pixmap = NULL;
 
15683
 
 
15684
/* Create a new backing pixmap of the appropriate size */
 
15685
static gboolean configure_event( GtkWidget         *widget,
 
15686
                                 GdkEventConfigure *event )
 
15687
{
 
15688
  if (pixmap)
 
15689
    g_object_unref (pixmap);
 
15690
 
 
15691
  pixmap = gdk_pixmap_new (widget-&gt;window,
 
15692
                           widget-&gt;allocation.width,
 
15693
                           widget-&gt;allocation.height,
 
15694
                           -1);
 
15695
  gdk_draw_rectangle (pixmap,
 
15696
                      widget-&gt;style-&gt;white_gc,
 
15697
                      TRUE,
 
15698
                      0, 0,
 
15699
                      widget-&gt;allocation.width,
 
15700
                      widget-&gt;allocation.height);
 
15701
 
 
15702
  return TRUE;
 
15703
}
 
15704
 
 
15705
/* Redraw the screen from the backing pixmap */
 
15706
static gboolean expose_event( GtkWidget      *widget,
 
15707
                              GdkEventExpose *event )
 
15708
{
 
15709
  gdk_draw_drawable (widget-&gt;window,
 
15710
                     widget-&gt;style-&gt;fg_gc[GTK_WIDGET_STATE (widget)],
 
15711
                     pixmap,
 
15712
                     event-&gt;area.x, event-&gt;area.y,
 
15713
                     event-&gt;area.x, event-&gt;area.y,
 
15714
                     event-&gt;area.width, event-&gt;area.height);
 
15715
 
 
15716
  return FALSE;
 
15717
}
 
15718
 
 
15719
/* Draw a rectangle on the screen */
 
15720
static void draw_brush( GtkWidget *widget,
 
15721
                        gdouble    x,
 
15722
                        gdouble    y)
 
15723
{
 
15724
  GdkRectangle update_rect;
 
15725
 
 
15726
  update_rect.x = x - 5;
 
15727
  update_rect.y = y - 5;
 
15728
  update_rect.width = 10;
 
15729
  update_rect.height = 10;
 
15730
  gdk_draw_rectangle (pixmap,
 
15731
                      widget-&gt;style-&gt;black_gc,
 
15732
                      TRUE,
 
15733
                      update_rect.x, update_rect.y,
 
15734
                      update_rect.width, update_rect.height);
 
15735
  gtk_widget_queue_draw_area (widget, 
 
15736
                              update_rect.x, update_rect.y,
 
15737
                              update_rect.width, update_rect.height);
 
15738
}
 
15739
 
 
15740
static gboolean button_press_event( GtkWidget      *widget,
 
15741
                                    GdkEventButton *event )
 
15742
{
 
15743
  if (event-&gt;button == 1 &amp;&amp; pixmap != NULL)
 
15744
    draw_brush (widget, event-&gt;x, event-&gt;y);
 
15745
 
 
15746
  return TRUE;
 
15747
}
 
15748
 
 
15749
static gboolean motion_notify_event( GtkWidget *widget,
 
15750
                                     GdkEventMotion *event )
 
15751
{
 
15752
  int x, y;
 
15753
  GdkModifierType state;
 
15754
 
 
15755
  if (event-&gt;is_hint)
 
15756
    gdk_window_get_pointer (event-&gt;window, &amp;x, &amp;y, &amp;state);
 
15757
  else
 
15758
    {
 
15759
      x = event-&gt;x;
 
15760
      y = event-&gt;y;
 
15761
      state = event-&gt;state;
 
15762
    }
 
15763
    
 
15764
  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
 
15765
    draw_brush (widget, x, y);
 
15766
  
 
15767
  return TRUE;
 
15768
}
 
15769
 
 
15770
void quit ()
 
15771
{
 
15772
  exit (0);
 
15773
}
 
15774
 
 
15775
int main( int   argc, 
 
15776
          char *argv[] )
 
15777
{
 
15778
  GtkWidget *window;
 
15779
  GtkWidget *drawing_area;
 
15780
  GtkWidget *vbox;
 
15781
 
 
15782
  GtkWidget *button;
 
15783
 
 
15784
  gtk_init (&amp;argc, &amp;argv);
 
15785
 
 
15786
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
15787
  gtk_widget_set_name (window, "Test Input");
 
15788
 
 
15789
  vbox = gtk_vbox_new (FALSE, 0);
 
15790
  gtk_container_add (GTK_CONTAINER (window), vbox);
 
15791
  gtk_widget_show (vbox);
 
15792
 
 
15793
  g_signal_connect (G_OBJECT (window), "destroy",
 
15794
                    G_CALLBACK (quit), NULL);
 
15795
 
 
15796
  /* Create the drawing area */
 
15797
 
 
15798
  drawing_area = gtk_drawing_area_new ();
 
15799
  gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200);
 
15800
  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
 
15801
 
 
15802
  gtk_widget_show (drawing_area);
 
15803
 
 
15804
  /* Signals used to handle backing pixmap */
 
15805
 
 
15806
  g_signal_connect (G_OBJECT (drawing_area), "expose_event",
 
15807
                    G_CALLBACK (expose_event), NULL);
 
15808
  g_signal_connect (G_OBJECT (drawing_area),"configure_event",
 
15809
                    G_CALLBACK (configure_event), NULL);
 
15810
 
 
15811
  /* Event signals */
 
15812
 
 
15813
  g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
 
15814
                    G_CALLBACK (motion_notify_event), NULL);
 
15815
  g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
 
15816
                    G_CALLBACK (button_press_event), NULL);
 
15817
 
 
15818
  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
 
15819
                         | GDK_LEAVE_NOTIFY_MASK
 
15820
                         | GDK_BUTTON_PRESS_MASK
 
15821
                         | GDK_POINTER_MOTION_MASK
 
15822
                         | GDK_POINTER_MOTION_HINT_MASK);
 
15823
 
 
15824
  /* .. And a quit button */
 
15825
  button = gtk_button_new_with_label ("Quit");
 
15826
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
 
15827
 
 
15828
  g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
15829
                            G_CALLBACK (gtk_widget_destroy),
 
15830
                            G_OBJECT (window));
 
15831
  gtk_widget_show (button);
 
15832
 
 
15833
  gtk_widget_show (window);
 
15834
 
 
15835
  gtk_main ();
 
15836
 
 
15837
  return 0;
 
15838
}
 
15839
<!-- example-end -->
 
15840
</programlisting>
 
15841
 
 
15842
</sect2>
 
15843
 
 
15844
<!-- ----------------------------------------------------------------- -->
 
15845
<sect2>
 
15846
<title>scribble-xinput.c</title>
 
15847
 
 
15848
<programlisting role="C">
 
15849
<!-- example-start scribble-xinput scribble-xinput.c -->
 
15850
 
 
15851
/* GTK - The GIMP Toolkit
 
15852
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 
15853
 *
 
15854
 * This library is free software; you can redistribute it and/or
 
15855
 * modify it under the terms of the GNU Library General Public
 
15856
 * License as published by the Free Software Foundation; either
 
15857
 * version 2 of the License, or (at your option) any later version.
 
15858
 *
 
15859
 * This library is distributed in the hope that it will be useful,
 
15860
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15861
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15862
 * Library General Public License for more details.
 
15863
 *
 
15864
 * You should have received a copy of the GNU Library General Public
 
15865
 * License along with this library; if not, write to the
 
15866
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
15867
 * Boston, MA 02111-1307, USA.
 
15868
 */
 
15869
 
 
15870
#include &lt;gtk/gtk.h&gt;
 
15871
 
 
15872
/* Backing pixmap for drawing area */
 
15873
static GdkPixmap *pixmap = NULL;
 
15874
 
 
15875
/* Create a new backing pixmap of the appropriate size */
 
15876
static gboolean
 
15877
configure_event (GtkWidget *widget, GdkEventConfigure *event)
 
15878
{
 
15879
  if (pixmap)
 
15880
     g_object_unref (pixmap);
 
15881
 
 
15882
  pixmap = gdk_pixmap_new (widget-&gt;window,
 
15883
                           widget-&gt;allocation.width,
 
15884
                           widget-&gt;allocation.height,
 
15885
                           -1);
 
15886
  gdk_draw_rectangle (pixmap,
 
15887
                      widget-&gt;style-&gt;white_gc,
 
15888
                      TRUE,
 
15889
                      0, 0,
 
15890
                      widget-&gt;allocation.width,
 
15891
                      widget-&gt;allocation.height);
 
15892
 
 
15893
  return TRUE;
 
15894
}
 
15895
 
 
15896
/* Redraw the screen from the backing pixmap */
 
15897
static gboolean
 
15898
expose_event (GtkWidget *widget, GdkEventExpose *event)
 
15899
{
 
15900
  gdk_draw_drawable (widget-&gt;window,
 
15901
                     widget-&gt;style-&gt;fg_gc[GTK_WIDGET_STATE (widget)],
 
15902
                     pixmap,
 
15903
                     event-&gt;area.x, event-&gt;area.y,
 
15904
                     event-&gt;area.x, event-&gt;area.y,
 
15905
                     event-&gt;area.width, event-&gt;area.height);
 
15906
 
 
15907
  return FALSE;
 
15908
}
 
15909
 
 
15910
/* Draw a rectangle on the screen, size depending on pressure,
 
15911
   and color on the type of device */
 
15912
static void
 
15913
draw_brush (GtkWidget *widget, GdkInputSource source,
 
15914
            gdouble x, gdouble y, gdouble pressure)
 
15915
{
 
15916
  GdkGC *gc;
 
15917
  GdkRectangle update_rect;
 
15918
 
 
15919
  switch (source)
 
15920
    {
 
15921
    case GDK_SOURCE_MOUSE:
 
15922
      gc = widget-&gt;style-&gt;dark_gc[GTK_WIDGET_STATE (widget)];
 
15923
      break;
 
15924
    case GDK_SOURCE_PEN:
 
15925
      gc = widget-&gt;style-&gt;black_gc;
 
15926
      break;
 
15927
    case GDK_SOURCE_ERASER:
 
15928
      gc = widget-&gt;style-&gt;white_gc;
 
15929
      break;
 
15930
    default:
 
15931
      gc = widget-&gt;style-&gt;light_gc[GTK_WIDGET_STATE (widget)];
 
15932
    }
 
15933
 
 
15934
  update_rect.x = x - 10 * pressure;
 
15935
  update_rect.y = y - 10 * pressure;
 
15936
  update_rect.width = 20 * pressure;
 
15937
  update_rect.height = 20 * pressure;
 
15938
  gdk_draw_rectangle (pixmap, gc, TRUE,
 
15939
                      update_rect.x, update_rect.y,
 
15940
                      update_rect.width, update_rect.height);
 
15941
  gtk_widget_queue_draw_area (widget, 
 
15942
                      update_rect.x, update_rect.y,
 
15943
                      update_rect.width, update_rect.height);
 
15944
}
 
15945
 
 
15946
static void
 
15947
print_button_press (GdkDevice *device)
 
15948
{
 
15949
  g_print ("Button press on device '%s'\n", device-&gt;name);
 
15950
}
 
15951
 
 
15952
static gboolean
 
15953
button_press_event (GtkWidget *widget, GdkEventButton *event)
 
15954
{
 
15955
  print_button_press (event-&gt;device);
 
15956
  
 
15957
  if (event-&gt;button == 1 &amp;&amp; pixmap != NULL) {
 
15958
    gdouble pressure;
 
15959
    gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &amp;pressure);
 
15960
    draw_brush (widget, event-&gt;device-&gt;source, event-&gt;x, event-&gt;y, pressure);
 
15961
  }
 
15962
 
 
15963
  return TRUE;
 
15964
}
 
15965
 
 
15966
static gboolean
 
15967
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
 
15968
{
 
15969
  gdouble x, y;
 
15970
  gdouble pressure;
 
15971
  GdkModifierType state;
 
15972
 
 
15973
  if (event-&gt;is_hint) 
 
15974
    {
 
15975
      gdk_device_get_state (event-&gt;device, event-&gt;window, NULL, &amp;state);
 
15976
      gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_X, &amp;x);
 
15977
      gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_Y, &amp;y);
 
15978
      gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &amp;pressure);
 
15979
    }
 
15980
  else
 
15981
    {
 
15982
      x = event-&gt;x;
 
15983
      y = event-&gt;y;
 
15984
      gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &amp;pressure);
 
15985
      state = event-&gt;state;
 
15986
    }
 
15987
    
 
15988
  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
 
15989
    draw_brush (widget, event-&gt;device-&gt;source, x, y, pressure);
 
15990
  
 
15991
  return TRUE;
 
15992
}
 
15993
 
 
15994
void
 
15995
input_dialog_destroy (GtkWidget *w, gpointer data)
 
15996
{
 
15997
  *((GtkWidget **)data) = NULL;
 
15998
}
 
15999
 
 
16000
void
 
16001
create_input_dialog ()
 
16002
{
 
16003
  static GtkWidget *inputd = NULL;
 
16004
 
 
16005
  if (!inputd)
 
16006
    {
 
16007
      inputd = gtk_input_dialog_new();
 
16008
 
 
16009
      g_signal_connect (G_OBJECT (inputd), "destroy",
 
16010
                        G_CALLBACK (input_dialog_destroy), (gpointer) &amp;inputd);
 
16011
      g_signal_connect_swapped (G_OBJECT (GTK_INPUT_DIALOG (inputd)-&gt;close_button),
 
16012
                                "clicked",
 
16013
                                G_CALLBACK (gtk_widget_hide),
 
16014
                                G_OBJECT (inputd));
 
16015
      gtk_widget_hide (GTK_INPUT_DIALOG (inputd)-&gt;save_button);
 
16016
 
 
16017
      gtk_widget_show (inputd);
 
16018
    }
 
16019
  else
 
16020
    {
 
16021
      if (!GTK_WIDGET_MAPPED (inputd))
 
16022
        gtk_widget_show (inputd);
 
16023
      else
 
16024
        gdk_window_raise (inputd-&gt;window);
 
16025
    }
 
16026
}
 
16027
 
 
16028
void
 
16029
int
 
16030
main (int argc, char *argv[])
 
16031
{
 
16032
  GtkWidget *window;
 
16033
  GtkWidget *drawing_area;
 
16034
  GtkWidget *vbox;
 
16035
 
 
16036
  GtkWidget *button;
 
16037
 
 
16038
  gtk_init (&amp;argc, &amp;argv);
 
16039
 
 
16040
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
16041
  gtk_widget_set_name (window, "Test Input");
 
16042
 
 
16043
  vbox = gtk_vbox_new (FALSE, 0);
 
16044
  gtk_container_add (GTK_CONTAINER (window), vbox);
 
16045
  gtk_widget_show (vbox);
 
16046
 
 
16047
  g_signal_connect (G_OBJECT (window), "destroy",
 
16048
                    G_CALLBACK (gtk_main_quit), NULL);
 
16049
 
 
16050
  /* Create the drawing area */
 
16051
 
 
16052
  drawing_area = gtk_drawing_area_new ();
 
16053
  gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200);
 
16054
  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
 
16055
 
 
16056
  gtk_widget_show (drawing_area);
 
16057
 
 
16058
  /* Signals used to handle backing pixmap */
 
16059
 
 
16060
  g_signal_connect (G_OBJECT (drawing_area), "expose_event",
 
16061
                    G_CALLBACK (expose_event), NULL);
 
16062
  g_signal_connect (G_OBJECT(drawing_area),"configure_event",
 
16063
                    G_CALLBACK (configure_event), NULL);
 
16064
 
 
16065
  /* Event signals */
 
16066
 
 
16067
  g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
 
16068
                    G_CALLBACK (motion_notify_event), NULL);
 
16069
  g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
 
16070
                    G_CALLBACK (button_press_event), NULL);
 
16071
 
 
16072
  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
 
16073
                         | GDK_LEAVE_NOTIFY_MASK
 
16074
                         | GDK_BUTTON_PRESS_MASK
 
16075
                         | GDK_POINTER_MOTION_MASK
 
16076
                         | GDK_POINTER_MOTION_HINT_MASK);
 
16077
 
 
16078
  /* The following call enables tracking and processing of extension
 
16079
     events for the drawing area */
 
16080
  gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
 
16081
 
 
16082
  /* .. And some buttons */
 
16083
  button = gtk_button_new_with_label ("Input Dialog");
 
16084
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
 
16085
 
 
16086
  g_signal_connect (G_OBJECT (button), "clicked",
 
16087
                    G_CALLBACK (create_input_dialog), NULL);
 
16088
  gtk_widget_show (button);
 
16089
 
 
16090
  button = gtk_button_new_with_label ("Quit");
 
16091
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
 
16092
 
 
16093
  g_signal_connect_swapped (G_OBJECT (button), "clicked",
 
16094
                            G_CALLBACK (gtk_widget_destroy),
 
16095
                            G_OBJECT (window));
 
16096
  gtk_widget_show (button);
 
16097
 
 
16098
  gtk_widget_show (window);
 
16099
 
 
16100
  gtk_main ();
 
16101
 
 
16102
  return 0;
 
16103
}
 
16104
<!-- example-end -->
 
16105
</programlisting>
 
16106
 
 
16107
</sect2>
 
16108
</sect1>
 
16109
 
 
16110
</appendix>
 
16111
</book>