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

« back to all changes in this revision

Viewing changes to docs/tutorial/html/x2202.html

  • 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 HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
 
2
<HTML
 
3
><HEAD
 
4
><TITLE
 
5
>Creating a Composite widget</TITLE
 
6
><META
 
7
NAME="GENERATOR"
 
8
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
 
9
REL="HOME"
 
10
TITLE="GTK+ 2.0 Tutorial"
 
11
HREF="book1.html"><LINK
 
12
REL="UP"
 
13
TITLE="Writing Your Own Widgets"
 
14
HREF="c2182.html"><LINK
 
15
REL="PREVIOUS"
 
16
TITLE="The Anatomy Of A Widget"
 
17
HREF="x2191.html"><LINK
 
18
REL="NEXT"
 
19
TITLE="Creating a widget from scratch"
 
20
HREF="x2312.html"></HEAD
 
21
><BODY
 
22
CLASS="SECT1"
 
23
BGCOLOR="#FFFFFF"
 
24
TEXT="#000000"
 
25
LINK="#0000FF"
 
26
VLINK="#840084"
 
27
ALINK="#0000FF"
 
28
><DIV
 
29
CLASS="NAVHEADER"
 
30
><TABLE
 
31
SUMMARY="Header navigation table"
 
32
WIDTH="100%"
 
33
BORDER="0"
 
34
CELLPADDING="0"
 
35
CELLSPACING="0"
 
36
><TR
 
37
><TH
 
38
COLSPAN="3"
 
39
ALIGN="center"
 
40
>GTK+ 2.0 Tutorial</TH
 
41
></TR
 
42
><TR
 
43
><TD
 
44
WIDTH="10%"
 
45
ALIGN="left"
 
46
VALIGN="bottom"
 
47
><A
 
48
HREF="x2191.html"
 
49
ACCESSKEY="P"
 
50
>&#60;&#60;&#60; Previous</A
 
51
></TD
 
52
><TD
 
53
WIDTH="80%"
 
54
ALIGN="center"
 
55
VALIGN="bottom"
 
56
>Writing Your Own Widgets</TD
 
57
><TD
 
58
WIDTH="10%"
 
59
ALIGN="right"
 
60
VALIGN="bottom"
 
61
><A
 
62
HREF="x2312.html"
 
63
ACCESSKEY="N"
 
64
>Next &#62;&#62;&#62;</A
 
65
></TD
 
66
></TR
 
67
></TABLE
 
68
><HR
 
69
ALIGN="LEFT"
 
70
WIDTH="100%"></DIV
 
71
><DIV
 
72
CLASS="SECT1"
 
73
><H1
 
74
CLASS="SECT1"
 
75
><A
 
76
NAME="SEC-CREATINGACOMPOSITEWIDGET"
 
77
>Creating a Composite widget</A
 
78
></H1
 
79
><DIV
 
80
CLASS="SECT2"
 
81
><H2
 
82
CLASS="SECT2"
 
83
><A
 
84
NAME="AEN2204"
 
85
>Introduction</A
 
86
></H2
 
87
><P
 
88
>One type of widget that you may be interested in creating is a
 
89
widget that is merely an aggregate of other GTK widgets. This type of
 
90
widget does nothing that couldn't be done without creating new
 
91
widgets, but provides a convenient way of packaging user interface
 
92
elements for reuse. The FileSelection and ColorSelection widgets in
 
93
the standard distribution are examples of this type of widget.</P
 
94
><P
 
95
>The example widget that we'll create in this section is the Tictactoe
 
96
widget, a 3x3 array of toggle buttons which triggers a signal when all
 
97
three buttons in a row, column, or on one of the diagonals are
 
98
depressed. </P
 
99
><P
 
100
><I
 
101
CLASS="EMPHASIS"
 
102
>Note: the full source code for the Tictactoe example described
 
103
below is in the <A
 
104
HREF="a2903.html#SEC-TICTACTOE"
 
105
>Code Examples Appendix</A
 
106
></I
 
107
></P
 
108
><P
 
109
><SPAN
 
110
CLASS="INLINEMEDIAOBJECT"
 
111
><IMG
 
112
SRC="images/tictactoe.png"></SPAN
 
113
></P
 
114
></DIV
 
115
><DIV
 
116
CLASS="SECT2"
 
117
><H2
 
118
CLASS="SECT2"
 
119
><A
 
120
NAME="AEN2215"
 
121
>Choosing a parent class</A
 
122
></H2
 
123
><P
 
124
>The parent class for a composite widget is typically the container
 
125
class that holds all of the elements of the composite widget. For
 
126
example, the parent class of the FileSelection widget is the
 
127
Dialog class. Since our buttons will be arranged in a table, it
 
128
is natural to make our parent class the Table class.</P
 
129
></DIV
 
130
><DIV
 
131
CLASS="SECT2"
 
132
><H2
 
133
CLASS="SECT2"
 
134
><A
 
135
NAME="AEN2218"
 
136
>The header file</A
 
137
></H2
 
138
><P
 
139
>Each GObject class has a header file which declares the object and
 
140
class structures for that object, along with public functions. 
 
141
A couple of features are worth pointing out. To prevent duplicate
 
142
definitions, we wrap the entire header file in:</P
 
143
><TABLE
 
144
BORDER="0"
 
145
BGCOLOR="#E0E0E0"
 
146
WIDTH="100%"
 
147
><TR
 
148
><TD
 
149
><PRE
 
150
CLASS="PROGRAMLISTING"
 
151
>#ifndef __TICTACTOE_H__
 
152
#define __TICTACTOE_H__
 
153
.
 
154
.
 
155
.
 
156
#endif /* __TICTACTOE_H__ */</PRE
 
157
></TD
 
158
></TR
 
159
></TABLE
 
160
><P
 
161
>And to keep C++ programs that include the header file happy, in:</P
 
162
><TABLE
 
163
BORDER="0"
 
164
BGCOLOR="#E0E0E0"
 
165
WIDTH="100%"
 
166
><TR
 
167
><TD
 
168
><PRE
 
169
CLASS="PROGRAMLISTING"
 
170
>#include &#60;glib.h&#62;
 
171
 
 
172
G_BEGIN_DECLS
 
173
.
 
174
.
 
175
.
 
176
G_END_DECLS</PRE
 
177
></TD
 
178
></TR
 
179
></TABLE
 
180
><P
 
181
>Along with the functions and structures, we declare five standard
 
182
macros in our header file, <TT
 
183
CLASS="LITERAL"
 
184
>TICTACTOE_TYPE</TT
 
185
>,
 
186
<TT
 
187
CLASS="LITERAL"
 
188
>TICTACTOE(obj)</TT
 
189
>,
 
190
<TT
 
191
CLASS="LITERAL"
 
192
>TICTACTOE_CLASS(klass)</TT
 
193
>,
 
194
<TT
 
195
CLASS="LITERAL"
 
196
>IS_TICTACTOE(obj)</TT
 
197
>, and
 
198
<TT
 
199
CLASS="LITERAL"
 
200
>IS_TICTACTOE_CLASS(klass)</TT
 
201
>, which cast a
 
202
pointer into a pointer to the object or class structure, and check
 
203
if an object is a Tictactoe widget respectively.</P
 
204
></DIV
 
205
><DIV
 
206
CLASS="SECT2"
 
207
><H2
 
208
CLASS="SECT2"
 
209
><A
 
210
NAME="AEN2230"
 
211
>The <TT
 
212
CLASS="LITERAL"
 
213
>_get_type()</TT
 
214
> function</A
 
215
></H2
 
216
><P
 
217
>We now continue on to the implementation of our widget. A core
 
218
function for every object is the function
 
219
<TT
 
220
CLASS="LITERAL"
 
221
>WIDGETNAME_get_type()</TT
 
222
>. This function, when first called, tells
 
223
Glib about the new class, and gets an ID that uniquely identifies
 
224
the class. Upon subsequent calls, it just returns the ID.</P
 
225
><TABLE
 
226
BORDER="0"
 
227
BGCOLOR="#E0E0E0"
 
228
WIDTH="100%"
 
229
><TR
 
230
><TD
 
231
><PRE
 
232
CLASS="PROGRAMLISTING"
 
233
>GType
 
234
tictactoe_get_type (void)
 
235
{
 
236
  static GType ttt_type = 0;
 
237
 
 
238
  if (!ttt_type)
 
239
    {
 
240
      static const GTypeInfo ttt_info =
 
241
      {
 
242
        sizeof (TictactoeClass),
 
243
        NULL, /* base_init */
 
244
        NULL, /* base_finalize */
 
245
        (GClassInitFunc) tictactoe_class_init,
 
246
        NULL, /* class_finalize */
 
247
        NULL, /* class_data */
 
248
        sizeof (Tictactoe),
 
249
        0,    /* n_preallocs */
 
250
        (GInstanceInitFunc) tictactoe_init,
 
251
      };
 
252
 
 
253
      ttt_type = g_type_register_static (GTK_TYPE_TABLE,
 
254
                                         "Tictactoe",
 
255
                                         &#38;ttt_info,
 
256
                                         0);
 
257
    }
 
258
 
 
259
  return ttt_type;
 
260
}</PRE
 
261
></TD
 
262
></TR
 
263
></TABLE
 
264
><P
 
265
>The GTypeInfo structure has the following definition:</P
 
266
><TABLE
 
267
BORDER="0"
 
268
BGCOLOR="#E0E0E0"
 
269
WIDTH="100%"
 
270
><TR
 
271
><TD
 
272
><PRE
 
273
CLASS="PROGRAMLISTING"
 
274
>struct _GTypeInfo
 
275
{
 
276
  /* interface types, classed types, instantiated types */
 
277
  guint16                class_size;
 
278
   
 
279
  GBaseInitFunc          base_init;
 
280
  GBaseFinalizeFunc      base_finalize;
 
281
   
 
282
  /* classed types, instantiated types */
 
283
  GClassInitFunc         class_init;
 
284
  GClassFinalizeFunc     class_finalize;
 
285
  gconstpointer          class_data;
 
286
   
 
287
  /* instantiated types */
 
288
  guint16                instance_size;
 
289
  guint16                n_preallocs;
 
290
  GInstanceInitFunc      instance_init;
 
291
   
 
292
  /* value handling */
 
293
  const GTypeValueTable *value_table;
 
294
};</PRE
 
295
></TD
 
296
></TR
 
297
></TABLE
 
298
><P
 
299
>The important fields of this structure are pretty self-explanatory.
 
300
We'll ignore the <TT
 
301
CLASS="LITERAL"
 
302
>base_init</TT
 
303
> and
 
304
 <TT
 
305
CLASS="LITERAL"
 
306
>base_finalize</TT
 
307
> as well as the <TT
 
308
CLASS="LITERAL"
 
309
>value_table</TT
 
310
>
 
311
fields here. Once Glib has a correctly filled in copy of
 
312
this structure, it knows how to create objects of a particular type. </P
 
313
></DIV
 
314
><DIV
 
315
CLASS="SECT2"
 
316
><H2
 
317
CLASS="SECT2"
 
318
><A
 
319
NAME="AEN2242"
 
320
>The <TT
 
321
CLASS="LITERAL"
 
322
>_class_init()</TT
 
323
> function</A
 
324
></H2
 
325
><P
 
326
>The <TT
 
327
CLASS="LITERAL"
 
328
>WIDGETNAME_class_init()</TT
 
329
> function initializes the fields of
 
330
the widget's class structure, and sets up any signals for the
 
331
class. For our Tictactoe widget it looks like:</P
 
332
><TABLE
 
333
BORDER="0"
 
334
BGCOLOR="#E0E0E0"
 
335
WIDTH="100%"
 
336
><TR
 
337
><TD
 
338
><PRE
 
339
CLASS="PROGRAMLISTING"
 
340
>enum {
 
341
  TICTACTOE_SIGNAL,
 
342
  LAST_SIGNAL
 
343
};
 
344
 
 
345
 
 
346
static guint tictactoe_signals[LAST_SIGNAL] = { 0 };
 
347
 
 
348
static void
 
349
tictactoe_class_init (TictactoeClass *klass)
 
350
{
 
351
  tictactoe_signals[TICTACTOE_SIGNAL] =
 
352
    g_signal_new ("tictactoe",
 
353
                  G_TYPE_FROM_CLASS (klass),
 
354
                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 
355
                  G_STRUCT_OFFSET (TictactoeClass, tictactoe),
 
356
                  NULL, NULL,
 
357
                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 
358
}</PRE
 
359
></TD
 
360
></TR
 
361
></TABLE
 
362
><P
 
363
>Our widget has just one signal, the <TT
 
364
CLASS="LITERAL"
 
365
>tictactoe</TT
 
366
> signal that is
 
367
invoked when a row, column, or diagonal is completely filled in. Not
 
368
every composite widget needs signals, so if you are reading this for
 
369
the first time, you may want to skip to the next section now, as
 
370
things are going to get a bit complicated.</P
 
371
><P
 
372
>The function:</P
 
373
><TABLE
 
374
BORDER="0"
 
375
BGCOLOR="#E0E0E0"
 
376
WIDTH="100%"
 
377
><TR
 
378
><TD
 
379
><PRE
 
380
CLASS="PROGRAMLISTING"
 
381
>guint g_signal_new( const gchar         *signal_name,
 
382
                    GType                itype,
 
383
                    GSignalFlags         signal_flags,
 
384
                    guint                class_offset,
 
385
                    GSignalAccumulator  *accumulator,
 
386
                    gpointer             accu_data,
 
387
                    GSignalCMarshaller  *c_marshaller,
 
388
                    GType                return_type,
 
389
                    guint                n_params,
 
390
                    ...);</PRE
 
391
></TD
 
392
></TR
 
393
></TABLE
 
394
><P
 
395
>Creates a new signal. The parameters are:</P
 
396
><P
 
397
></P
 
398
><UL
 
399
><LI
 
400
><P
 
401
> <TT
 
402
CLASS="LITERAL"
 
403
>signal_name</TT
 
404
>: The name of the signal.</P
 
405
></LI
 
406
><LI
 
407
><P
 
408
> <TT
 
409
CLASS="LITERAL"
 
410
>itype</TT
 
411
>: The ID of the object that this signal applies
 
412
to. (It will also apply to that objects descendants.)</P
 
413
></LI
 
414
><LI
 
415
><P
 
416
> <TT
 
417
CLASS="LITERAL"
 
418
>signal_flags</TT
 
419
>: Whether the default handler runs before or after
 
420
user handlers and other flags. Usually this will be one of
 
421
<TT
 
422
CLASS="LITERAL"
 
423
>G_SIGNAL_RUN_FIRST</TT
 
424
> or <TT
 
425
CLASS="LITERAL"
 
426
>G_SIGNAL_RUN_LAST</TT
 
427
>,
 
428
although there are other possibilities. The flag
 
429
<TT
 
430
CLASS="LITERAL"
 
431
>G_SIGNAL_ACTION</TT
 
432
> specifies that no extra code needs to
 
433
run that performs special pre or post emission adjustments. This means that
 
434
the signal can also be emitted from object external code.</P
 
435
></LI
 
436
><LI
 
437
><P
 
438
> <TT
 
439
CLASS="LITERAL"
 
440
>class_offset</TT
 
441
>: The offset within the class structure of
 
442
a pointer to the default handler.</P
 
443
></LI
 
444
><LI
 
445
><P
 
446
> <TT
 
447
CLASS="LITERAL"
 
448
>accumulator</TT
 
449
>: For most classes this can
 
450
be set to NULL.</P
 
451
></LI
 
452
><LI
 
453
><P
 
454
> <TT
 
455
CLASS="LITERAL"
 
456
>accu_data</TT
 
457
>: User data that will be handed
 
458
to the accumulator function.</P
 
459
></LI
 
460
><LI
 
461
><P
 
462
> <TT
 
463
CLASS="LITERAL"
 
464
>c_marshaller</TT
 
465
>: A function that is used to invoke the signal
 
466
handler. For signal handlers that have no arguments other than the
 
467
object that emitted the signal and user data, we can use the
 
468
pre-supplied marshaller function <TT
 
469
CLASS="LITERAL"
 
470
>g_cclosure_marshal_VOID__VOID</TT
 
471
>.</P
 
472
></LI
 
473
><LI
 
474
><P
 
475
> <TT
 
476
CLASS="LITERAL"
 
477
>return_type</TT
 
478
>: The type of the return value.</P
 
479
></LI
 
480
><LI
 
481
><P
 
482
> <TT
 
483
CLASS="LITERAL"
 
484
>n_params</TT
 
485
>: The number of parameters of the signal handler
 
486
(other than the two default ones mentioned above)</P
 
487
></LI
 
488
><LI
 
489
><P
 
490
> <TT
 
491
CLASS="LITERAL"
 
492
>...</TT
 
493
>: The types of the parameters.</P
 
494
></LI
 
495
></UL
 
496
><P
 
497
>When specifying types, the following standard types can be used:</P
 
498
><TABLE
 
499
BORDER="0"
 
500
BGCOLOR="#E0E0E0"
 
501
WIDTH="100%"
 
502
><TR
 
503
><TD
 
504
><PRE
 
505
CLASS="PROGRAMLISTING"
 
506
>G_TYPE_INVALID
 
507
G_TYPE_NONE
 
508
G_TYPE_INTERFACE
 
509
G_TYPE_CHAR
 
510
G_TYPE_UCHAR
 
511
G_TYPE_BOOLEAN
 
512
G_TYPE_INT
 
513
G_TYPE_UINT
 
514
G_TYPE_LONG
 
515
G_TYPE_ULONG
 
516
G_TYPE_INT64
 
517
G_TYPE_UINT64
 
518
G_TYPE_ENUM
 
519
G_TYPE_FLAGS
 
520
G_TYPE_FLOAT
 
521
G_TYPE_DOUBLE
 
522
G_TYPE_STRING
 
523
G_TYPE_POINTER
 
524
G_TYPE_BOXED
 
525
G_TYPE_PARAM
 
526
G_TYPE_OBJECT</PRE
 
527
></TD
 
528
></TR
 
529
></TABLE
 
530
><P
 
531
><TT
 
532
CLASS="LITERAL"
 
533
>g_signal_new()</TT
 
534
> returns a unique integer identifier for the
 
535
signal, that we store in the <TT
 
536
CLASS="LITERAL"
 
537
>tictactoe_signals</TT
 
538
> array, which we
 
539
index using an enumeration. (Conventionally, the enumeration elements
 
540
are the signal name, uppercased, but here there would be a conflict
 
541
with the <TT
 
542
CLASS="LITERAL"
 
543
>TICTACTOE()</TT
 
544
> macro, so we called it <TT
 
545
CLASS="LITERAL"
 
546
>TICTACTOE_SIGNAL</TT
 
547
>
 
548
instead.</P
 
549
></DIV
 
550
><DIV
 
551
CLASS="SECT2"
 
552
><H2
 
553
CLASS="SECT2"
 
554
><A
 
555
NAME="AEN2295"
 
556
>The <TT
 
557
CLASS="LITERAL"
 
558
>_init()</TT
 
559
> function</A
 
560
></H2
 
561
><P
 
562
>Each class also needs a function to initialize the object
 
563
structure. Usually, this function has the fairly limited role of
 
564
setting the fields of the structure to default values. For composite
 
565
widgets, however, this function also creates the component widgets.</P
 
566
><TABLE
 
567
BORDER="0"
 
568
BGCOLOR="#E0E0E0"
 
569
WIDTH="100%"
 
570
><TR
 
571
><TD
 
572
><PRE
 
573
CLASS="PROGRAMLISTING"
 
574
>static void
 
575
tictactoe_init (Tictactoe *ttt)
 
576
{
 
577
  gint i,j;
 
578
 
 
579
  gtk_table_resize (GTK_TABLE (ttt), 3, 3);
 
580
  gtk_table_set_homogeneous (GTK_TABLE (ttt), TRUE);
 
581
 
 
582
  for (i=0;i&#60;3; i++)
 
583
    for (j=0;j&#60;3; j++)
 
584
      {
 
585
        ttt-&#62;buttons[i][j] = gtk_toggle_button_new ();
 
586
        gtk_table_attach_defaults (GTK_TABLE (ttt), ttt-&#62;buttons[i][j], 
 
587
                                   i, i+1, j, j+1);
 
588
        g_signal_connect (G_OBJECT (ttt-&#62;buttons[i][j]), "toggled",
 
589
                          G_CALLBACK (tictactoe_toggle), ttt);
 
590
        gtk_widget_set_size_request (ttt-&#62;buttons[i][j], 20, 20);
 
591
        gtk_widget_show (ttt-&#62;buttons[i][j]);
 
592
      }
 
593
}</PRE
 
594
></TD
 
595
></TR
 
596
></TABLE
 
597
></DIV
 
598
><DIV
 
599
CLASS="SECT2"
 
600
><H2
 
601
CLASS="SECT2"
 
602
><A
 
603
NAME="AEN2300"
 
604
>And the rest...</A
 
605
></H2
 
606
><P
 
607
>There is one more function that every object (except for abstract
 
608
classes like Bin that cannot be instantiated) needs to have - the
 
609
function that the user calls to create an object of that type. This is
 
610
conventionally called <TT
 
611
CLASS="LITERAL"
 
612
>OBJECTNAME_new()</TT
 
613
>. In some
 
614
widgets, though not for the Tictactoe widgets, this function takes
 
615
arguments, and does some setup based on the arguments. The other two
 
616
functions are specific to the Tictactoe widget. </P
 
617
><P
 
618
><TT
 
619
CLASS="LITERAL"
 
620
>tictactoe_clear()</TT
 
621
> is a public function that resets all the
 
622
buttons in the widget to the up position. Note the use of
 
623
<TT
 
624
CLASS="LITERAL"
 
625
>g_signal_handlers_block_matched()</TT
 
626
> to keep our signal handler for
 
627
button toggles from being triggered unnecessarily.</P
 
628
><P
 
629
><TT
 
630
CLASS="LITERAL"
 
631
>tictactoe_toggle()</TT
 
632
> is the signal handler that is invoked when the
 
633
user clicks on a button. It checks to see if there are any winning
 
634
combinations that involve the toggled button, and if so, emits
 
635
the "tictactoe" signal.</P
 
636
><TABLE
 
637
BORDER="0"
 
638
BGCOLOR="#E0E0E0"
 
639
WIDTH="100%"
 
640
><TR
 
641
><TD
 
642
><PRE
 
643
CLASS="PROGRAMLISTING"
 
644
>GtkWidget*
 
645
tictactoe_new (void)
 
646
{
 
647
  return GTK_WIDGET ( g_object_new (TICTACTOE_TYPE, NULL));
 
648
}
 
649
 
 
650
void           
 
651
tictactoe_clear (Tictactoe *ttt)
 
652
{
 
653
  int i,j;
 
654
 
 
655
  for (i=0;i&#60;3;i++)
 
656
    for (j=0;j&#60;3;j++)
 
657
      {
 
658
        g_signal_handlers_block_matched (G_OBJECT (ttt-&#62;buttons[i][j]),
 
659
                                         G_SIGNAL_MATCH_DATA,
 
660
                                         0, 0, NULL, NULL, ttt);
 
661
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt-&#62;buttons[i][j]),
 
662
                                     FALSE);
 
663
        g_signal_handlers_unblock_matched (G_OBJECT (ttt-&#62;buttons[i][j]),
 
664
                                           G_SIGNAL_MATCH_DATA,
 
665
                                           0, 0, NULL, NULL, ttt);
 
666
      }
 
667
}
 
668
 
 
669
static void
 
670
tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
 
671
{
 
672
  int i,k;
 
673
 
 
674
  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
 
675
                             { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
 
676
                             { 0, 1, 2 }, { 0, 1, 2 } };
 
677
  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
 
678
                             { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
 
679
                             { 0, 1, 2 }, { 2, 1, 0 } };
 
680
 
 
681
  int success, found;
 
682
 
 
683
  for (k=0; k&#60;8; k++)
 
684
    {
 
685
      success = TRUE;
 
686
      found = FALSE;
 
687
 
 
688
      for (i=0;i&#60;3;i++)
 
689
        {
 
690
          success = success &#38;&#38; 
 
691
            GTK_TOGGLE_BUTTON(ttt-&#62;buttons[rwins[k][i]][cwins[k][i]])-&#62;active;
 
692
          found = found ||
 
693
            ttt-&#62;buttons[rwins[k][i]][cwins[k][i]] == widget;
 
694
        }
 
695
      
 
696
      if (success &#38;&#38; found)
 
697
        {
 
698
          g_signal_emit (G_OBJECT (ttt), 
 
699
                         tictactoe_signals[TICTACTOE_SIGNAL], 0);
 
700
          break;
 
701
        }
 
702
    }
 
703
}</PRE
 
704
></TD
 
705
></TR
 
706
></TABLE
 
707
><P
 
708
>And finally, an example program using our Tictactoe widget:</P
 
709
><TABLE
 
710
BORDER="0"
 
711
BGCOLOR="#E0E0E0"
 
712
WIDTH="100%"
 
713
><TR
 
714
><TD
 
715
><PRE
 
716
CLASS="PROGRAMLISTING"
 
717
>#include &#60;gtk/gtk.h&#62;
 
718
#include "tictactoe.h"
 
719
 
 
720
/* Invoked when a row, column or diagonal is completed */
 
721
void
 
722
win (GtkWidget *widget, gpointer data)
 
723
{
 
724
  g_print ("Yay!\n");
 
725
  tictactoe_clear (TICTACTOE (widget));
 
726
}
 
727
 
 
728
int 
 
729
main (int argc, char *argv[])
 
730
{
 
731
  GtkWidget *window;
 
732
  GtkWidget *ttt;
 
733
  
 
734
  gtk_init (&#38;argc, &#38;argv);
 
735
 
 
736
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
737
  
 
738
  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
 
739
  
 
740
  g_signal_connect (G_OBJECT (window), "destroy",
 
741
                    G_CALLBACK (exit), NULL);
 
742
  
 
743
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
744
 
 
745
  /* Create a new Tictactoe widget */
 
746
  ttt = tictactoe_new ();
 
747
  gtk_container_add (GTK_CONTAINER (window), ttt);
 
748
  gtk_widget_show (ttt);
 
749
 
 
750
  /* And attach to its "tictactoe" signal */
 
751
  g_signal_connect (G_OBJECT (ttt), "tictactoe",
 
752
                    G_CALLBACK (win), NULL);
 
753
 
 
754
  gtk_widget_show (window);
 
755
  
 
756
  gtk_main ();
 
757
  
 
758
  return 0;
 
759
}</PRE
 
760
></TD
 
761
></TR
 
762
></TABLE
 
763
></DIV
 
764
></DIV
 
765
><DIV
 
766
CLASS="NAVFOOTER"
 
767
><HR
 
768
ALIGN="LEFT"
 
769
WIDTH="100%"><TABLE
 
770
SUMMARY="Footer navigation table"
 
771
WIDTH="100%"
 
772
BORDER="0"
 
773
CELLPADDING="0"
 
774
CELLSPACING="0"
 
775
><TR
 
776
><TD
 
777
WIDTH="33%"
 
778
ALIGN="left"
 
779
VALIGN="top"
 
780
><A
 
781
HREF="x2191.html"
 
782
ACCESSKEY="P"
 
783
>&#60;&#60;&#60; Previous</A
 
784
></TD
 
785
><TD
 
786
WIDTH="34%"
 
787
ALIGN="center"
 
788
VALIGN="top"
 
789
><A
 
790
HREF="book1.html"
 
791
ACCESSKEY="H"
 
792
>Home</A
 
793
></TD
 
794
><TD
 
795
WIDTH="33%"
 
796
ALIGN="right"
 
797
VALIGN="top"
 
798
><A
 
799
HREF="x2312.html"
 
800
ACCESSKEY="N"
 
801
>Next &#62;&#62;&#62;</A
 
802
></TD
 
803
></TR
 
804
><TR
 
805
><TD
 
806
WIDTH="33%"
 
807
ALIGN="left"
 
808
VALIGN="top"
 
809
>The Anatomy Of A Widget</TD
 
810
><TD
 
811
WIDTH="34%"
 
812
ALIGN="center"
 
813
VALIGN="top"
 
814
><A
 
815
HREF="c2182.html"
 
816
ACCESSKEY="U"
 
817
>Up</A
 
818
></TD
 
819
><TD
 
820
WIDTH="33%"
 
821
ALIGN="right"
 
822
VALIGN="top"
 
823
>Creating a widget from scratch</TD
 
824
></TR
 
825
></TABLE
 
826
></DIV
 
827
></BODY
 
828
></HTML
 
829
>
 
 
b'\\ No newline at end of file'