source: trunk/third/gtk/docs/html/gtk_tut-30.html @ 14810

Revision 14810, 43.6 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14809, which included commits to RCS files with non-trunk default branches.
Line 
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
2<HTML>
3<HEAD>
4 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
5 <TITLE>GTK v1.2 Tutorial: Code Examples</TITLE>
6 <LINK HREF="gtk_tut-31.html" REL=next>
7 <LINK HREF="gtk_tut-29.html" REL=previous>
8 <LINK HREF="gtk_tut.html#toc30" REL=contents>
9</HEAD>
10<BODY BGCOLOR="#FFFFFF">
11<A HREF="gtk_tut-31.html">Next</A>
12<A HREF="gtk_tut-29.html">Previous</A>
13<A HREF="gtk_tut.html#toc30">Contents</A>
14<HR NOSHADE>
15<H2><A NAME="s30">30. Code Examples</A></H2>
16
17<P>Below are the code examples that are used in the above text
18which are not included in complete form elsewhere.
19<P>
20<H2><A NAME="ss30.1">30.1 Tictactoe</A>
21</H2>
22
23<H3>tictactoe.h</H3>
24
25<P>
26<BLOCKQUOTE><CODE>
27<PRE>
28/* example-start tictactoe tictactoe.h */
29
30/* GTK - The GIMP Toolkit
31 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
32 *
33 * This library is free software; you can redistribute it and/or
34 * modify it under the terms of the GNU Library General Public
35 * License as published by the Free Software Foundation; either
36 * version 2 of the License, or (at your option) any later version.
37 *
38 * This library is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41 * Library General Public License for more details.
42 *
43 * You should have received a copy of the GNU Library General Public
44 * License along with this library; if not, write to the
45 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
46 * Boston, MA 02111-1307, USA.
47 */
48#ifndef __TICTACTOE_H__
49#define __TICTACTOE_H__
50
51
52#include &lt;gdk/gdk.h>
53#include &lt;gtk/gtkvbox.h>
54
55
56#ifdef __cplusplus
57extern "C" {
58#endif /* __cplusplus */
59
60#define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
61#define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
62#define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
63
64
65typedef struct _Tictactoe       Tictactoe;
66typedef struct _TictactoeClass  TictactoeClass;
67
68struct _Tictactoe
69{
70  GtkVBox vbox;
71 
72  GtkWidget *buttons[3][3];
73};
74
75struct _TictactoeClass
76{
77  GtkVBoxClass parent_class;
78
79  void (* tictactoe) (Tictactoe *ttt);
80};
81
82guint          tictactoe_get_type        (void);
83GtkWidget*     tictactoe_new             (void);
84void           tictactoe_clear           (Tictactoe *ttt);
85
86#ifdef __cplusplus
87}
88#endif /* __cplusplus */
89
90#endif /* __TICTACTOE_H__ */
91
92/* example-end */
93</PRE>
94</CODE></BLOCKQUOTE>
95<P>
96<H3>tictactoe.c</H3>
97
98<P>
99<BLOCKQUOTE><CODE>
100<PRE>
101/* example-start tictactoe tictactoe.c */
102
103/* GTK - The GIMP Toolkit
104 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
105 *
106 * This library is free software; you can redistribute it and/or
107 * modify it under the terms of the GNU Library General Public
108 * License as published by the Free Software Foundation; either
109 * version 2 of the License, or (at your option) any later version.
110 *
111 * This library is distributed in the hope that it will be useful,
112 * but WITHOUT ANY WARRANTY; without even the implied warranty of
113 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
114 * Library General Public License for more details.
115 *
116 * You should have received a copy of the GNU Library General Public
117 * License along with this library; if not, write to the
118 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
119 * Boston, MA 02111-1307, USA.
120 */
121#include "gtk/gtksignal.h"
122#include "gtk/gtktable.h"
123#include "gtk/gtktogglebutton.h"
124#include "tictactoe.h"
125
126enum {
127  TICTACTOE_SIGNAL,
128  LAST_SIGNAL
129};
130
131static void tictactoe_class_init          (TictactoeClass *klass);
132static void tictactoe_init                (Tictactoe      *ttt);
133static void tictactoe_toggle              (GtkWidget *widget, Tictactoe *ttt);
134
135static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
136
137guint
138tictactoe_get_type ()
139{
140  static guint ttt_type = 0;
141
142  if (!ttt_type)
143    {
144      GtkTypeInfo ttt_info =
145      {
146        "Tictactoe",
147        sizeof (Tictactoe),
148        sizeof (TictactoeClass),
149        (GtkClassInitFunc) tictactoe_class_init,
150        (GtkObjectInitFunc) tictactoe_init,
151        (GtkArgSetFunc) NULL,
152        (GtkArgGetFunc) NULL
153      };
154
155      ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
156    }
157
158  return ttt_type;
159}
160
161static void
162tictactoe_class_init (TictactoeClass *class)
163{
164  GtkObjectClass *object_class;
165
166  object_class = (GtkObjectClass*) class;
167 
168  tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
169                                         GTK_RUN_FIRST,
170                                         object_class->type,
171                                         GTK_SIGNAL_OFFSET (TictactoeClass,
172                                                            tictactoe),
173                                         gtk_signal_default_marshaller,
174                                         GTK_TYPE_NONE, 0);
175
176
177  gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
178
179  class->tictactoe = NULL;
180}
181
182static void
183tictactoe_init (Tictactoe *ttt)
184{
185  GtkWidget *table;
186  gint i,j;
187 
188  table = gtk_table_new (3, 3, TRUE);
189  gtk_container_add (GTK_CONTAINER(ttt), table);
190  gtk_widget_show (table);
191
192  for (i=0;i&lt;3; i++)
193    for (j=0;j&lt;3; j++)
194      {
195        ttt->buttons[i][j] = gtk_toggle_button_new ();
196        gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
197                                   i, i+1, j, j+1);
198        gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
199                            GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
200        gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
201        gtk_widget_show (ttt->buttons[i][j]);
202      }
203}
204
205GtkWidget*
206tictactoe_new ()
207{
208  return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
209}
210
211void           
212tictactoe_clear (Tictactoe *ttt)
213{
214  int i,j;
215
216  for (i=0;i&lt;3;i++)
217    for (j=0;j&lt;3;j++)
218      {
219        gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
220        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
221                                     FALSE);
222        gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
223      }
224}
225
226static void
227tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
228{
229  int i,k;
230
231  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
232                             { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
233                             { 0, 1, 2 }, { 0, 1, 2 } };
234  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
235                             { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
236                             { 0, 1, 2 }, { 2, 1, 0 } };
237
238  int success, found;
239
240  for (k=0; k&lt;8; k++)
241    {
242      success = TRUE;
243      found = FALSE;
244
245      for (i=0;i&lt;3;i++)
246        {
247          success = success &amp;&amp;
248            GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
249          found = found ||
250            ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
251        }
252     
253      if (success &amp;&amp; found)
254        {
255          gtk_signal_emit (GTK_OBJECT (ttt),
256                           tictactoe_signals[TICTACTOE_SIGNAL]);
257          break;
258        }
259    }
260}
261
262/* example-end */
263</PRE>
264</CODE></BLOCKQUOTE>
265<P>
266<H3>ttt_test.c</H3>
267
268<P>
269<BLOCKQUOTE><CODE>
270<PRE>
271/* example-start tictactoe ttt_test.c */
272
273#include &lt;gtk/gtk.h>
274#include "tictactoe.h"
275
276void win( GtkWidget *widget,
277          gpointer   data )
278{
279  g_print ("Yay!\n");
280  tictactoe_clear (TICTACTOE (widget));
281}
282
283int main( int   argc,
284          char *argv[] )
285{
286  GtkWidget *window;
287  GtkWidget *ttt;
288 
289  gtk_init (&amp;argc, &amp;argv);
290
291  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
292 
293  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
294 
295  gtk_signal_connect (GTK_OBJECT (window), "destroy",
296                      GTK_SIGNAL_FUNC (gtk_exit), NULL);
297 
298  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
299
300  ttt = tictactoe_new ();
301 
302  gtk_container_add (GTK_CONTAINER (window), ttt);
303  gtk_widget_show (ttt);
304
305  gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
306                      GTK_SIGNAL_FUNC (win), NULL);
307
308  gtk_widget_show (window);
309 
310  gtk_main ();
311 
312  return 0;
313}
314
315/* example-end */
316</PRE>
317</CODE></BLOCKQUOTE>
318<P>
319<H2><A NAME="ss30.2">30.2 GtkDial</A>
320</H2>
321
322<H3>gtkdial.h</H3>
323
324<P>
325<BLOCKQUOTE><CODE>
326<PRE>
327/* example-start gtkdial gtkdial.h */
328
329/* GTK - The GIMP Toolkit
330 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
331 *
332 * This library is free software; you can redistribute it and/or
333 * modify it under the terms of the GNU Library General Public
334 * License as published by the Free Software Foundation; either
335 * version 2 of the License, or (at your option) any later version.
336 *
337 * This library is distributed in the hope that it will be useful,
338 * but WITHOUT ANY WARRANTY; without even the implied warranty of
339 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
340 * Library General Public License for more details.
341 *
342 * You should have received a copy of the GNU Library General Public
343 * License along with this library; if not, write to the
344 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
345 * Boston, MA 02111-1307, USA.
346 */
347#ifndef __GTK_DIAL_H__
348#define __GTK_DIAL_H__
349
350
351#include &lt;gdk/gdk.h>
352#include &lt;gtk/gtkadjustment.h>
353#include &lt;gtk/gtkwidget.h>
354
355
356#ifdef __cplusplus
357extern "C" {
358#endif /* __cplusplus */
359
360
361#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
362#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
363#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
364
365
366typedef struct _GtkDial        GtkDial;
367typedef struct _GtkDialClass   GtkDialClass;
368
369struct _GtkDial
370{
371  GtkWidget widget;
372
373  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
374  guint policy : 2;
375
376  /* Button currently pressed or 0 if none */
377  guint8 button;
378
379  /* Dimensions of dial components */
380  gint radius;
381  gint pointer_width;
382
383  /* ID of update timer, or 0 if none */
384  guint32 timer;
385
386  /* Current angle */
387  gfloat angle;
388  gfloat last_angle;
389
390  /* Old values from adjustment stored so we know when something changes */
391  gfloat old_value;
392  gfloat old_lower;
393  gfloat old_upper;
394
395  /* The adjustment object that stores the data for this dial */
396  GtkAdjustment *adjustment;
397};
398
399struct _GtkDialClass
400{
401  GtkWidgetClass parent_class;
402};
403
404
405GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
406guint          gtk_dial_get_type               (void);
407GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
408void           gtk_dial_set_update_policy      (GtkDial      *dial,
409                                                GtkUpdateType  policy);
410
411void           gtk_dial_set_adjustment         (GtkDial      *dial,
412                                                GtkAdjustment *adjustment);
413#ifdef __cplusplus
414}
415#endif /* __cplusplus */
416
417
418#endif /* __GTK_DIAL_H__ */
419/* example-end */
420</PRE>
421</CODE></BLOCKQUOTE>
422<P>
423<H3>gtkdial.c</H3>
424
425<P>
426<BLOCKQUOTE><CODE>
427<PRE>
428/* example-start gtkdial gtkdial.c */
429
430/* GTK - The GIMP Toolkit
431 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
432 *
433 * This library is free software; you can redistribute it and/or
434 * modify it under the terms of the GNU Library General Public
435 * License as published by the Free Software Foundation; either
436 * version 2 of the License, or (at your option) any later version.
437 *
438 * This library is distributed in the hope that it will be useful,
439 * but WITHOUT ANY WARRANTY; without even the implied warranty of
440 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
441 * Library General Public License for more details.
442 *
443 * You should have received a copy of the GNU Library General Public
444 * License along with this library; if not, write to the
445 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
446 * Boston, MA 02111-1307, USA.
447 */
448#include &lt;math.h>
449#include &lt;stdio.h>
450#include &lt;gtk/gtkmain.h>
451#include &lt;gtk/gtksignal.h>
452
453#include "gtkdial.h"
454
455#define SCROLL_DELAY_LENGTH  300
456#define DIAL_DEFAULT_SIZE 100
457
458/* Forward declarations */
459
460static void gtk_dial_class_init               (GtkDialClass    *klass);
461static void gtk_dial_init                     (GtkDial         *dial);
462static void gtk_dial_destroy                  (GtkObject        *object);
463static void gtk_dial_realize                  (GtkWidget        *widget);
464static void gtk_dial_size_request             (GtkWidget      *widget,
465                                               GtkRequisition *requisition);
466static void gtk_dial_size_allocate            (GtkWidget     *widget,
467                                               GtkAllocation *allocation);
468static gint gtk_dial_expose                   (GtkWidget        *widget,
469                                                GdkEventExpose   *event);
470static gint gtk_dial_button_press             (GtkWidget        *widget,
471                                                GdkEventButton   *event);
472static gint gtk_dial_button_release           (GtkWidget        *widget,
473                                                GdkEventButton   *event);
474static gint gtk_dial_motion_notify            (GtkWidget        *widget,
475                                                GdkEventMotion   *event);
476static gint gtk_dial_timer                    (GtkDial         *dial);
477
478static void gtk_dial_update_mouse             (GtkDial *dial, gint x, gint y);
479static void gtk_dial_update                   (GtkDial *dial);
480static void gtk_dial_adjustment_changed       (GtkAdjustment    *adjustment,
481                                                gpointer          data);
482static void gtk_dial_adjustment_value_changed (GtkAdjustment    *adjustment,
483                                                gpointer          data);
484
485/* Local data */
486
487static GtkWidgetClass *parent_class = NULL;
488
489guint
490gtk_dial_get_type ()
491{
492  static guint dial_type = 0;
493
494  if (!dial_type)
495    {
496      GtkTypeInfo dial_info =
497      {
498        "GtkDial",
499        sizeof (GtkDial),
500        sizeof (GtkDialClass),
501        (GtkClassInitFunc) gtk_dial_class_init,
502        (GtkObjectInitFunc) gtk_dial_init,
503        (GtkArgSetFunc) NULL,
504        (GtkArgGetFunc) NULL,
505      };
506
507      dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
508    }
509
510  return dial_type;
511}
512
513static void
514gtk_dial_class_init (GtkDialClass *class)
515{
516  GtkObjectClass *object_class;
517  GtkWidgetClass *widget_class;
518
519  object_class = (GtkObjectClass*) class;
520  widget_class = (GtkWidgetClass*) class;
521
522  parent_class = gtk_type_class (gtk_widget_get_type ());
523
524  object_class->destroy = gtk_dial_destroy;
525
526  widget_class->realize = gtk_dial_realize;
527  widget_class->expose_event = gtk_dial_expose;
528  widget_class->size_request = gtk_dial_size_request;
529  widget_class->size_allocate = gtk_dial_size_allocate;
530  widget_class->button_press_event = gtk_dial_button_press;
531  widget_class->button_release_event = gtk_dial_button_release;
532  widget_class->motion_notify_event = gtk_dial_motion_notify;
533}
534
535static void
536gtk_dial_init (GtkDial *dial)
537{
538  dial->button = 0;
539  dial->policy = GTK_UPDATE_CONTINUOUS;
540  dial->timer = 0;
541  dial->radius = 0;
542  dial->pointer_width = 0;
543  dial->angle = 0.0;
544  dial->old_value = 0.0;
545  dial->old_lower = 0.0;
546  dial->old_upper = 0.0;
547  dial->adjustment = NULL;
548}
549
550GtkWidget*
551gtk_dial_new (GtkAdjustment *adjustment)
552{
553  GtkDial *dial;
554
555  dial = gtk_type_new (gtk_dial_get_type ());
556
557  if (!adjustment)
558    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
559
560  gtk_dial_set_adjustment (dial, adjustment);
561
562  return GTK_WIDGET (dial);
563}
564
565static void
566gtk_dial_destroy (GtkObject *object)
567{
568  GtkDial *dial;
569
570  g_return_if_fail (object != NULL);
571  g_return_if_fail (GTK_IS_DIAL (object));
572
573  dial = GTK_DIAL (object);
574
575  if (dial->adjustment)
576    gtk_object_unref (GTK_OBJECT (dial->adjustment));
577
578  if (GTK_OBJECT_CLASS (parent_class)->destroy)
579    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
580}
581
582GtkAdjustment*
583gtk_dial_get_adjustment (GtkDial *dial)
584{
585  g_return_val_if_fail (dial != NULL, NULL);
586  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
587
588  return dial->adjustment;
589}
590
591void
592gtk_dial_set_update_policy (GtkDial      *dial,
593                             GtkUpdateType  policy)
594{
595  g_return_if_fail (dial != NULL);
596  g_return_if_fail (GTK_IS_DIAL (dial));
597
598  dial->policy = policy;
599}
600
601void
602gtk_dial_set_adjustment (GtkDial      *dial,
603                          GtkAdjustment *adjustment)
604{
605  g_return_if_fail (dial != NULL);
606  g_return_if_fail (GTK_IS_DIAL (dial));
607
608  if (dial->adjustment)
609    {
610      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
611      gtk_object_unref (GTK_OBJECT (dial->adjustment));
612    }
613
614  dial->adjustment = adjustment;
615  gtk_object_ref (GTK_OBJECT (dial->adjustment));
616
617  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
618                      (GtkSignalFunc) gtk_dial_adjustment_changed,
619                      (gpointer) dial);
620  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
621                      (GtkSignalFunc) gtk_dial_adjustment_value_changed,
622                      (gpointer) dial);
623
624  dial->old_value = adjustment->value;
625  dial->old_lower = adjustment->lower;
626  dial->old_upper = adjustment->upper;
627
628  gtk_dial_update (dial);
629}
630
631static void
632gtk_dial_realize (GtkWidget *widget)
633{
634  GtkDial *dial;
635  GdkWindowAttr attributes;
636  gint attributes_mask;
637
638  g_return_if_fail (widget != NULL);
639  g_return_if_fail (GTK_IS_DIAL (widget));
640
641  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
642  dial = GTK_DIAL (widget);
643
644  attributes.x = widget->allocation.x;
645  attributes.y = widget->allocation.y;
646  attributes.width = widget->allocation.width;
647  attributes.height = widget->allocation.height;
648  attributes.wclass = GDK_INPUT_OUTPUT;
649  attributes.window_type = GDK_WINDOW_CHILD;
650  attributes.event_mask = gtk_widget_get_events (widget) |
651    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
652    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
653    GDK_POINTER_MOTION_HINT_MASK;
654  attributes.visual = gtk_widget_get_visual (widget);
655  attributes.colormap = gtk_widget_get_colormap (widget);
656
657  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
658  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
659
660  widget->style = gtk_style_attach (widget->style, widget->window);
661
662  gdk_window_set_user_data (widget->window, widget);
663
664  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
665}
666
667static void
668gtk_dial_size_request (GtkWidget      *widget,
669                       GtkRequisition *requisition)
670{
671  requisition->width = DIAL_DEFAULT_SIZE;
672  requisition->height = DIAL_DEFAULT_SIZE;
673}
674
675static void
676gtk_dial_size_allocate (GtkWidget     *widget,
677                        GtkAllocation *allocation)
678{
679  GtkDial *dial;
680
681  g_return_if_fail (widget != NULL);
682  g_return_if_fail (GTK_IS_DIAL (widget));
683  g_return_if_fail (allocation != NULL);
684
685  widget->allocation = *allocation;
686  dial = GTK_DIAL (widget);
687
688  if (GTK_WIDGET_REALIZED (widget))
689    {
690
691      gdk_window_move_resize (widget->window,
692                              allocation->x, allocation->y,
693                              allocation->width, allocation->height);
694
695    }
696  dial->radius = MIN(allocation->width,allocation->height) * 0.45;
697  dial->pointer_width = dial->radius / 5;
698}
699
700static gint
701gtk_dial_expose (GtkWidget      *widget,
702                 GdkEventExpose *event)
703{
704  GtkDial *dial;
705  GdkPoint points[6];
706  gdouble s,c;
707  gdouble theta, last, increment;
708  GtkStyle      *blankstyle;
709  gint xc, yc;
710  gint upper, lower;
711  gint tick_length;
712  gint i, inc;
713
714  g_return_val_if_fail (widget != NULL, FALSE);
715  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
716  g_return_val_if_fail (event != NULL, FALSE);
717
718  if (event->count > 0)
719    return FALSE;
720 
721  dial = GTK_DIAL (widget);
722
723/*  gdk_window_clear_area (widget->window,
724                         0, 0,
725                         widget->allocation.width,
726                         widget->allocation.height);
727*/
728  xc = widget->allocation.width/2;
729  yc = widget->allocation.height/2;
730
731  upper = dial->adjustment->upper;
732  lower = dial->adjustment->lower;
733
734  /* Erase old pointer */
735
736  s = sin(dial->last_angle);
737  c = cos(dial->last_angle);
738  dial->last_angle = dial->angle;
739
740  points[0].x = xc + s*dial->pointer_width/2;
741  points[0].y = yc + c*dial->pointer_width/2;
742  points[1].x = xc + c*dial->radius;
743  points[1].y = yc - s*dial->radius;
744  points[2].x = xc - s*dial->pointer_width/2;
745  points[2].y = yc - c*dial->pointer_width/2;
746  points[3].x = xc - c*dial->radius/10;
747  points[3].y = yc + s*dial->radius/10;
748  points[4].x = points[0].x;
749  points[4].y = points[0].y;
750
751  blankstyle = gtk_style_new ();
752  blankstyle->bg_gc[GTK_STATE_NORMAL] =
753                widget->style->bg_gc[GTK_STATE_NORMAL];
754  blankstyle->dark_gc[GTK_STATE_NORMAL] =
755                widget->style->bg_gc[GTK_STATE_NORMAL];
756  blankstyle->light_gc[GTK_STATE_NORMAL] =
757                widget->style->bg_gc[GTK_STATE_NORMAL];
758  blankstyle->black_gc =
759                widget->style->bg_gc[GTK_STATE_NORMAL];
760
761  gtk_draw_polygon (blankstyle,
762                    widget->window,
763                    GTK_STATE_NORMAL,
764                    GTK_SHADOW_OUT,
765                    points, 5,
766                    FALSE);
767
768  gtk_style_unref(blankstyle);
769
770
771  /* Draw ticks */
772
773  if ((upper - lower) == 0)
774    return;
775
776  increment = (100*M_PI)/(dial->radius*dial->radius);
777
778  inc = (upper - lower);
779
780  while (inc &lt; 100) inc *=10;
781  while (inc >= 1000) inc /=10;
782  last = -1;
783
784  for (i=0; i&lt;=inc; i++)
785    {
786      theta = ((gfloat)i*M_PI/(18*inc/24.) - M_PI/6.);
787
788      if ((theta - last) &lt; (increment))
789        continue;     
790      last = theta;
791
792      s = sin(theta);
793      c = cos(theta);
794
795      tick_length = (i%(inc/10) == 0) ? dial->pointer_width : dial->pointer_width/2;
796
797      gdk_draw_line (widget->window,
798                     widget->style->fg_gc[widget->state],
799                     xc + c*(dial->radius - tick_length),
800                     yc - s*(dial->radius - tick_length),
801                     xc + c*dial->radius,
802                     yc - s*dial->radius);
803    }
804
805  /* Draw pointer */
806
807  s = sin(dial->angle);
808  c = cos(dial->angle);
809  dial->last_angle = dial->angle;
810
811  points[0].x = xc + s*dial->pointer_width/2;
812  points[0].y = yc + c*dial->pointer_width/2;
813  points[1].x = xc + c*dial->radius;
814  points[1].y = yc - s*dial->radius;
815  points[2].x = xc - s*dial->pointer_width/2;
816  points[2].y = yc - c*dial->pointer_width/2;
817  points[3].x = xc - c*dial->radius/10;
818  points[3].y = yc + s*dial->radius/10;
819  points[4].x = points[0].x;
820  points[4].y = points[0].y;
821
822
823  gtk_draw_polygon (widget->style,
824                    widget->window,
825                    GTK_STATE_NORMAL,
826                    GTK_SHADOW_OUT,
827                    points, 5,
828                    TRUE);
829
830  return FALSE;
831}
832
833static gint
834gtk_dial_button_press (GtkWidget      *widget,
835                       GdkEventButton *event)
836{
837  GtkDial *dial;
838  gint dx, dy;
839  double s, c;
840  double d_parallel;
841  double d_perpendicular;
842
843  g_return_val_if_fail (widget != NULL, FALSE);
844  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
845  g_return_val_if_fail (event != NULL, FALSE);
846
847  dial = GTK_DIAL (widget);
848
849  /* Determine if button press was within pointer region - we
850     do this by computing the parallel and perpendicular distance of
851     the point where the mouse was pressed from the line passing through
852     the pointer */
853 
854  dx = event->x - widget->allocation.width / 2;
855  dy = widget->allocation.height / 2 - event->y;
856 
857  s = sin(dial->angle);
858  c = cos(dial->angle);
859 
860  d_parallel = s*dy + c*dx;
861  d_perpendicular = fabs(s*dx - c*dy);
862 
863  if (!dial->button &amp;&amp;
864      (d_perpendicular &lt; dial->pointer_width/2) &amp;&amp;
865      (d_parallel > - dial->pointer_width))
866    {
867      gtk_grab_add (widget);
868
869      dial->button = event->button;
870
871      gtk_dial_update_mouse (dial, event->x, event->y);
872    }
873
874  return FALSE;
875}
876
877static gint
878gtk_dial_button_release (GtkWidget      *widget,
879                          GdkEventButton *event)
880{
881  GtkDial *dial;
882
883  g_return_val_if_fail (widget != NULL, FALSE);
884  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
885  g_return_val_if_fail (event != NULL, FALSE);
886
887  dial = GTK_DIAL (widget);
888
889  if (dial->button == event->button)
890    {
891      gtk_grab_remove (widget);
892
893      dial->button = 0;
894
895      if (dial->policy == GTK_UPDATE_DELAYED)
896        gtk_timeout_remove (dial->timer);
897     
898      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &amp;&amp;
899          (dial->old_value != dial->adjustment->value))
900        gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
901    }
902
903  return FALSE;
904}
905
906static gint
907gtk_dial_motion_notify (GtkWidget      *widget,
908                         GdkEventMotion *event)
909{
910  GtkDial *dial;
911  GdkModifierType mods;
912  gint x, y, mask;
913
914  g_return_val_if_fail (widget != NULL, FALSE);
915  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
916  g_return_val_if_fail (event != NULL, FALSE);
917
918  dial = GTK_DIAL (widget);
919
920  if (dial->button != 0)
921    {
922      x = event->x;
923      y = event->y;
924
925      if (event->is_hint || (event->window != widget->window))
926        gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
927
928      switch (dial->button)
929        {
930        case 1:
931          mask = GDK_BUTTON1_MASK;
932          break;
933        case 2:
934          mask = GDK_BUTTON2_MASK;
935          break;
936        case 3:
937          mask = GDK_BUTTON3_MASK;
938          break;
939        default:
940          mask = 0;
941          break;
942        }
943
944      if (mods &amp; mask)
945        gtk_dial_update_mouse (dial, x,y);
946    }
947
948  return FALSE;
949}
950
951static gint
952gtk_dial_timer (GtkDial *dial)
953{
954  g_return_val_if_fail (dial != NULL, FALSE);
955  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
956
957  if (dial->policy == GTK_UPDATE_DELAYED)
958    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
959
960  return FALSE;
961}
962
963static void
964gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
965{
966  gint xc, yc;
967  gfloat old_value;
968
969  g_return_if_fail (dial != NULL);
970  g_return_if_fail (GTK_IS_DIAL (dial));
971
972  xc = GTK_WIDGET(dial)->allocation.width / 2;
973  yc = GTK_WIDGET(dial)->allocation.height / 2;
974
975  old_value = dial->adjustment->value;
976  dial->angle = atan2(yc-y, x-xc);
977
978  if (dial->angle &lt; -M_PI/2.)
979    dial->angle += 2*M_PI;
980
981  if (dial->angle &lt; -M_PI/6)
982    dial->angle = -M_PI/6;
983
984  if (dial->angle > 7.*M_PI/6.)
985    dial->angle = 7.*M_PI/6.;
986
987  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
988    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
989
990  if (dial->adjustment->value != old_value)
991    {
992      if (dial->policy == GTK_UPDATE_CONTINUOUS)
993        {
994          gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
995        }
996      else
997        {
998          gtk_widget_draw (GTK_WIDGET(dial), NULL);
999
1000          if (dial->policy == GTK_UPDATE_DELAYED)
1001            {
1002              if (dial->timer)
1003                gtk_timeout_remove (dial->timer);
1004
1005              dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
1006                                             (GtkFunction) gtk_dial_timer,
1007                                             (gpointer) dial);
1008            }
1009        }
1010    }
1011}
1012
1013static void
1014gtk_dial_update (GtkDial *dial)
1015{
1016  gfloat new_value;
1017 
1018  g_return_if_fail (dial != NULL);
1019  g_return_if_fail (GTK_IS_DIAL (dial));
1020
1021  new_value = dial->adjustment->value;
1022 
1023  if (new_value &lt; dial->adjustment->lower)
1024    new_value = dial->adjustment->lower;
1025
1026  if (new_value > dial->adjustment->upper)
1027    new_value = dial->adjustment->upper;
1028
1029  if (new_value != dial->adjustment->value)
1030    {
1031      dial->adjustment->value = new_value;
1032      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
1033    }
1034
1035  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
1036    (dial->adjustment->upper - dial->adjustment->lower);
1037
1038  gtk_widget_draw (GTK_WIDGET(dial), NULL);
1039}
1040
1041static void
1042gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
1043                              gpointer       data)
1044{
1045  GtkDial *dial;
1046
1047  g_return_if_fail (adjustment != NULL);
1048  g_return_if_fail (data != NULL);
1049
1050  dial = GTK_DIAL (data);
1051
1052  if ((dial->old_value != adjustment->value) ||
1053      (dial->old_lower != adjustment->lower) ||
1054      (dial->old_upper != adjustment->upper))
1055    {
1056      gtk_dial_update (dial);
1057
1058      dial->old_value = adjustment->value;
1059      dial->old_lower = adjustment->lower;
1060      dial->old_upper = adjustment->upper;
1061    }
1062}
1063
1064static void
1065gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
1066                                    gpointer       data)
1067{
1068  GtkDial *dial;
1069
1070  g_return_if_fail (adjustment != NULL);
1071  g_return_if_fail (data != NULL);
1072
1073  dial = GTK_DIAL (data);
1074
1075  if (dial->old_value != adjustment->value)
1076    {
1077      gtk_dial_update (dial);
1078
1079      dial->old_value = adjustment->value;
1080    }
1081}
1082/* example-end */
1083</PRE>
1084</CODE></BLOCKQUOTE>
1085<P>
1086<H3>dial_test.c</H3>
1087
1088<P>
1089<BLOCKQUOTE><CODE>
1090<PRE>
1091#include &lt;stdio.h>
1092#include &lt;gtk/gtk.h>
1093#include "gtkdial.h"
1094
1095void value_changed( GtkAdjustment *adjustment,
1096                    GtkWidget     *label )
1097{
1098  char buffer[16];
1099
1100  sprintf(buffer,"%4.2f",adjustment->value);
1101  gtk_label_set (GTK_LABEL (label), buffer);
1102}
1103
1104int main( int   argc,
1105          char *argv[])
1106{
1107  GtkWidget *window;
1108  GtkAdjustment *adjustment;
1109  GtkWidget *dial;
1110  GtkWidget *frame;
1111  GtkWidget *vbox;
1112  GtkWidget *label;
1113 
1114  gtk_init (&amp;argc, &amp;argv);
1115
1116  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1117 
1118  gtk_window_set_title (GTK_WINDOW (window), "Dial");
1119 
1120  gtk_signal_connect (GTK_OBJECT (window), "destroy",
1121                      GTK_SIGNAL_FUNC (gtk_exit), NULL);
1122 
1123  gtk_container_border_width (GTK_CONTAINER (window), 10);
1124
1125  vbox = gtk_vbox_new (FALSE, 5);
1126  gtk_container_add (GTK_CONTAINER (window), vbox);
1127  gtk_widget_show(vbox);
1128
1129  frame = gtk_frame_new (NULL);
1130  gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN);
1131  gtk_container_add (GTK_CONTAINER (vbox), frame);
1132  gtk_widget_show (frame);
1133 
1134  adjustment = GTK_ADJUSTMENT(gtk_adjustment_new (0, 0, 100, 0.01, 0.1, 0));
1135 
1136  dial = gtk_dial_new(adjustment);
1137  gtk_dial_set_update_policy (GTK_DIAL(dial), GTK_UPDATE_DELAYED);
1138  /*  gtk_widget_set_usize (dial, 100, 100); */
1139 
1140  gtk_container_add (GTK_CONTAINER (frame), dial);
1141  gtk_widget_show (dial);
1142
1143  label = gtk_label_new("0.00");
1144  gtk_box_pack_end (GTK_BOX(vbox), label, 0, 0, 0);
1145  gtk_widget_show (label);
1146
1147  gtk_signal_connect (GTK_OBJECT(adjustment), "value_changed",
1148                      GTK_SIGNAL_FUNC (value_changed), label);
1149 
1150  gtk_widget_show (window);
1151 
1152  gtk_main ();
1153 
1154  return 0;
1155}
1156</PRE>
1157</CODE></BLOCKQUOTE>
1158<P>
1159<H2><A NAME="ss30.3">30.3 Scribble</A>
1160</H2>
1161
1162<P>
1163<H3>scribble-simple.c</H3>
1164
1165<P>
1166<BLOCKQUOTE><CODE>
1167<PRE>
1168/* example-start scribble-simple scribble-simple.c */
1169
1170/* GTK - The GIMP Toolkit
1171 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
1172 *
1173 * This library is free software; you can redistribute it and/or
1174 * modify it under the terms of the GNU Library General Public
1175 * License as published by the Free Software Foundation; either
1176 * version 2 of the License, or (at your option) any later version.
1177 *
1178 * This library is distributed in the hope that it will be useful,
1179 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1180 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1181 * Library General Public License for more details.
1182 *
1183 * You should have received a copy of the GNU Library General Public
1184 * License along with this library; if not, write to the
1185 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1186 * Boston, MA 02111-1307, USA.
1187 */
1188
1189#include &lt;gtk/gtk.h>
1190
1191/* Backing pixmap for drawing area */
1192static GdkPixmap *pixmap = NULL;
1193
1194/* Create a new backing pixmap of the appropriate size */
1195static gint configure_event( GtkWidget         *widget,
1196                             GdkEventConfigure *event )
1197{
1198  if (pixmap)
1199    gdk_pixmap_unref(pixmap);
1200
1201  pixmap = gdk_pixmap_new(widget->window,
1202                          widget->allocation.width,
1203                          widget->allocation.height,
1204                          -1);
1205  gdk_draw_rectangle (pixmap,
1206                      widget->style->white_gc,
1207                      TRUE,
1208                      0, 0,
1209                      widget->allocation.width,
1210                      widget->allocation.height);
1211
1212  return TRUE;
1213}
1214
1215/* Redraw the screen from the backing pixmap */
1216static gint expose_event( GtkWidget      *widget,
1217                          GdkEventExpose *event )
1218{
1219  gdk_draw_pixmap(widget->window,
1220                  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1221                  pixmap,
1222                  event->area.x, event->area.y,
1223                  event->area.x, event->area.y,
1224                  event->area.width, event->area.height);
1225
1226  return FALSE;
1227}
1228
1229/* Draw a rectangle on the screen */
1230static void draw_brush( GtkWidget *widget,
1231                        gdouble    x,
1232                        gdouble    y)
1233{
1234  GdkRectangle update_rect;
1235
1236  update_rect.x = x - 5;
1237  update_rect.y = y - 5;
1238  update_rect.width = 10;
1239  update_rect.height = 10;
1240  gdk_draw_rectangle (pixmap,
1241                      widget->style->black_gc,
1242                      TRUE,
1243                      update_rect.x, update_rect.y,
1244                      update_rect.width, update_rect.height);
1245  gtk_widget_draw (widget, &amp;update_rect);
1246}
1247
1248static gint button_press_event( GtkWidget      *widget,
1249                                GdkEventButton *event )
1250{
1251  if (event->button == 1 &amp;&amp; pixmap != NULL)
1252    draw_brush (widget, event->x, event->y);
1253
1254  return TRUE;
1255}
1256
1257static gint motion_notify_event( GtkWidget *widget,
1258                                 GdkEventMotion *event )
1259{
1260  int x, y;
1261  GdkModifierType state;
1262
1263  if (event->is_hint)
1264    gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
1265  else
1266    {
1267      x = event->x;
1268      y = event->y;
1269      state = event->state;
1270    }
1271   
1272  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
1273    draw_brush (widget, x, y);
1274 
1275  return TRUE;
1276}
1277
1278void quit ()
1279{
1280  gtk_exit (0);
1281}
1282
1283int main( int   argc,
1284          char *argv[] )
1285{
1286  GtkWidget *window;
1287  GtkWidget *drawing_area;
1288  GtkWidget *vbox;
1289
1290  GtkWidget *button;
1291
1292  gtk_init (&amp;argc, &amp;argv);
1293
1294  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1295  gtk_widget_set_name (window, "Test Input");
1296
1297  vbox = gtk_vbox_new (FALSE, 0);
1298  gtk_container_add (GTK_CONTAINER (window), vbox);
1299  gtk_widget_show (vbox);
1300
1301  gtk_signal_connect (GTK_OBJECT (window), "destroy",
1302                      GTK_SIGNAL_FUNC (quit), NULL);
1303
1304  /* Create the drawing area */
1305
1306  drawing_area = gtk_drawing_area_new ();
1307  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
1308  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
1309
1310  gtk_widget_show (drawing_area);
1311
1312  /* Signals used to handle backing pixmap */
1313
1314  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
1315                      (GtkSignalFunc) expose_event, NULL);
1316  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
1317                      (GtkSignalFunc) configure_event, NULL);
1318
1319  /* Event signals */
1320
1321  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
1322                      (GtkSignalFunc) motion_notify_event, NULL);
1323  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
1324                      (GtkSignalFunc) button_press_event, NULL);
1325
1326  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
1327                         | GDK_LEAVE_NOTIFY_MASK
1328                         | GDK_BUTTON_PRESS_MASK
1329                         | GDK_POINTER_MOTION_MASK
1330                         | GDK_POINTER_MOTION_HINT_MASK);
1331
1332  /* .. And a quit button */
1333  button = gtk_button_new_with_label ("Quit");
1334  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
1335
1336  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1337                             GTK_SIGNAL_FUNC (gtk_widget_destroy),
1338                             GTK_OBJECT (window));
1339  gtk_widget_show (button);
1340
1341  gtk_widget_show (window);
1342
1343  gtk_main ();
1344
1345  return 0;
1346}
1347/* example-end */
1348</PRE>
1349</CODE></BLOCKQUOTE>
1350<P>
1351<H3>scribble-xinput.c</H3>
1352
1353<P>
1354<BLOCKQUOTE><CODE>
1355<PRE>
1356/* example-start scribble-xinput scribble-xinput.c */
1357
1358/* GTK - The GIMP Toolkit
1359 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
1360 *
1361 * This library is free software; you can redistribute it and/or
1362 * modify it under the terms of the GNU Library General Public
1363 * License as published by the Free Software Foundation; either
1364 * version 2 of the License, or (at your option) any later version.
1365 *
1366 * This library is distributed in the hope that it will be useful,
1367 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1368 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1369 * Library General Public License for more details.
1370 *
1371 * You should have received a copy of the GNU Library General Public
1372 * License along with this library; if not, write to the
1373 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1374 * Boston, MA 02111-1307, USA.
1375 */
1376
1377#include &lt;gtk/gtk.h>
1378
1379/* Backing pixmap for drawing area */
1380static GdkPixmap *pixmap = NULL;
1381
1382/* Create a new backing pixmap of the appropriate size */
1383static gint
1384configure_event (GtkWidget *widget, GdkEventConfigure *event)
1385{
1386  if (pixmap)
1387     gdk_pixmap_unref(pixmap);
1388
1389  pixmap = gdk_pixmap_new(widget->window,
1390                          widget->allocation.width,
1391                          widget->allocation.height,
1392                          -1);
1393  gdk_draw_rectangle (pixmap,
1394                      widget->style->white_gc,
1395                      TRUE,
1396                      0, 0,
1397                      widget->allocation.width,
1398                      widget->allocation.height);
1399
1400  return TRUE;
1401}
1402
1403/* Redraw the screen from the backing pixmap */
1404static gint
1405expose_event (GtkWidget *widget, GdkEventExpose *event)
1406{
1407  gdk_draw_pixmap(widget->window,
1408                  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1409                  pixmap,
1410                  event->area.x, event->area.y,
1411                  event->area.x, event->area.y,
1412                  event->area.width, event->area.height);
1413
1414  return FALSE;
1415}
1416
1417/* Draw a rectangle on the screen, size depending on pressure,
1418   and color on the type of device */
1419static void
1420draw_brush (GtkWidget *widget, GdkInputSource source,
1421            gdouble x, gdouble y, gdouble pressure)
1422{
1423  GdkGC *gc;
1424  GdkRectangle update_rect;
1425
1426  switch (source)
1427    {
1428    case GDK_SOURCE_MOUSE:
1429      gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
1430      break;
1431    case GDK_SOURCE_PEN:
1432      gc = widget->style->black_gc;
1433      break;
1434    case GDK_SOURCE_ERASER:
1435      gc = widget->style->white_gc;
1436      break;
1437    default:
1438      gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
1439    }
1440
1441  update_rect.x = x - 10 * pressure;
1442  update_rect.y = y - 10 * pressure;
1443  update_rect.width = 20 * pressure;
1444  update_rect.height = 20 * pressure;
1445  gdk_draw_rectangle (pixmap, gc, TRUE,
1446                      update_rect.x, update_rect.y,
1447                      update_rect.width, update_rect.height);
1448  gtk_widget_draw (widget, &amp;update_rect);
1449}
1450
1451static void
1452print_button_press (guint32 deviceid)
1453{
1454  GList *tmp_list;
1455
1456  /* gdk_input_list_devices returns an internal list, so we shouldn't
1457     free it afterwards */
1458  tmp_list = gdk_input_list_devices();
1459
1460  while (tmp_list)
1461    {
1462      GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
1463
1464      if (info->deviceid == deviceid)
1465        {
1466          g_print("Button press on device '%s'\n", info->name);
1467          return;
1468        }
1469
1470      tmp_list = tmp_list->next;
1471    }
1472}
1473
1474static gint
1475button_press_event (GtkWidget *widget, GdkEventButton *event)
1476{
1477  print_button_press (event->deviceid);
1478 
1479  if (event->button == 1 &amp;&amp; pixmap != NULL)
1480    draw_brush (widget, event->source, event->x, event->y, event->pressure);
1481
1482  return TRUE;
1483}
1484
1485static gint
1486motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
1487{
1488  gdouble x, y;
1489  gdouble pressure;
1490  GdkModifierType state;
1491
1492  if (event->is_hint)
1493    gdk_input_window_get_pointer (event->window, event->deviceid,
1494                                  &amp;x, &amp;y, &amp;pressure,
1495                                  NULL, NULL, &amp;state);
1496  else
1497    {
1498      x = event->x;
1499      y = event->y;
1500      pressure = event->pressure;
1501      state = event->state;
1502    }
1503   
1504  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
1505    draw_brush (widget, event->source, x, y, pressure);
1506 
1507  return TRUE;
1508}
1509
1510void
1511input_dialog_destroy (GtkWidget *w, gpointer data)
1512{
1513  *((GtkWidget **)data) = NULL;
1514}
1515
1516void
1517create_input_dialog ()
1518{
1519  static GtkWidget *inputd = NULL;
1520
1521  if (!inputd)
1522    {
1523      inputd = gtk_input_dialog_new();
1524
1525      gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
1526                          (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
1527      gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
1528                                 "clicked",
1529                                 (GtkSignalFunc)gtk_widget_hide,
1530                                 GTK_OBJECT(inputd));
1531      gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
1532
1533      gtk_widget_show (inputd);
1534    }
1535  else
1536    {
1537      if (!GTK_WIDGET_MAPPED(inputd))
1538        gtk_widget_show(inputd);
1539      else
1540        gdk_window_raise(inputd->window);
1541    }
1542}
1543
1544void
1545quit ()
1546{
1547  gtk_exit (0);
1548}
1549
1550int
1551main (int argc, char *argv[])
1552{
1553  GtkWidget *window;
1554  GtkWidget *drawing_area;
1555  GtkWidget *vbox;
1556
1557  GtkWidget *button;
1558
1559  gtk_init (&amp;argc, &amp;argv);
1560
1561  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1562  gtk_widget_set_name (window, "Test Input");
1563
1564  vbox = gtk_vbox_new (FALSE, 0);
1565  gtk_container_add (GTK_CONTAINER (window), vbox);
1566  gtk_widget_show (vbox);
1567
1568  gtk_signal_connect (GTK_OBJECT (window), "destroy",
1569                      GTK_SIGNAL_FUNC (quit), NULL);
1570
1571  /* Create the drawing area */
1572
1573  drawing_area = gtk_drawing_area_new ();
1574  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
1575  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
1576
1577  gtk_widget_show (drawing_area);
1578
1579  /* Signals used to handle backing pixmap */
1580
1581  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
1582                      (GtkSignalFunc) expose_event, NULL);
1583  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
1584                      (GtkSignalFunc) configure_event, NULL);
1585
1586  /* Event signals */
1587
1588  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
1589                      (GtkSignalFunc) motion_notify_event, NULL);
1590  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
1591                      (GtkSignalFunc) button_press_event, NULL);
1592
1593  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
1594                         | GDK_LEAVE_NOTIFY_MASK
1595                         | GDK_BUTTON_PRESS_MASK
1596                         | GDK_POINTER_MOTION_MASK
1597                         | GDK_POINTER_MOTION_HINT_MASK);
1598
1599  /* The following call enables tracking and processing of extension
1600     events for the drawing area */
1601  gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
1602
1603  /* .. And some buttons */
1604  button = gtk_button_new_with_label ("Input Dialog");
1605  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
1606
1607  gtk_signal_connect (GTK_OBJECT (button), "clicked",
1608                      GTK_SIGNAL_FUNC (create_input_dialog), NULL);
1609  gtk_widget_show (button);
1610
1611  button = gtk_button_new_with_label ("Quit");
1612  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
1613
1614  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1615                             GTK_SIGNAL_FUNC (gtk_widget_destroy),
1616                             GTK_OBJECT (window));
1617  gtk_widget_show (button);
1618
1619  gtk_widget_show (window);
1620
1621  gtk_main ();
1622
1623  return 0;
1624}
1625/* example-end */
1626</PRE>
1627</CODE></BLOCKQUOTE>
1628<P>
1629<HR NOSHADE>
1630<A HREF="gtk_tut-31.html">Next</A>
1631<A HREF="gtk_tut-29.html">Previous</A>
1632<A HREF="gtk_tut.html#toc30">Contents</A>
1633</BODY>
1634</HTML>
Note: See TracBrowser for help on using the repository browser.