Blame docs/tutorial/html/x2200.html

Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>Creating a Composite widget
Packit 98cdb6
>
Packit 98cdb6
NAME="GENERATOR"
Packit 98cdb6
CONTENT="Modular DocBook HTML Stylesheet Version 1.79">
Packit 98cdb6
REL="HOME"
Packit 98cdb6
TITLE="GTK+ 2.0 Tutorial"
Packit 98cdb6
HREF="book1.html">
Packit 98cdb6
REL="UP"
Packit 98cdb6
TITLE="Writing Your Own Widgets"
Packit 98cdb6
HREF="c2180.html">
Packit 98cdb6
REL="PREVIOUS"
Packit 98cdb6
TITLE="The Anatomy Of A Widget"
Packit 98cdb6
HREF="x2189.html">
Packit 98cdb6
REL="NEXT"
Packit 98cdb6
TITLE="Creating a widget from scratch"
Packit 98cdb6
HREF="x2310.html">
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT1"
Packit 98cdb6
BGCOLOR="#FFFFFF"
Packit 98cdb6
TEXT="#000000"
Packit 98cdb6
LINK="#0000FF"
Packit 98cdb6
VLINK="#840084"
Packit 98cdb6
ALINK="#0000FF"
Packit 98cdb6
>
Packit 98cdb6
CLASS="NAVHEADER"
Packit 98cdb6
>
Packit 98cdb6
SUMMARY="Header navigation table"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
BORDER="0"
Packit 98cdb6
CELLPADDING="0"
Packit 98cdb6
CELLSPACING="0"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
COLSPAN="3"
Packit 98cdb6
ALIGN="center"
Packit 98cdb6
>GTK+ 2.0 Tutorial
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
WIDTH="10%"
Packit 98cdb6
ALIGN="left"
Packit 98cdb6
VALIGN="bottom"
Packit 98cdb6
>
Packit 98cdb6
HREF="x2189.html"
Packit 98cdb6
ACCESSKEY="P"
Packit 98cdb6
><<< Previous
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
WIDTH="80%"
Packit 98cdb6
ALIGN="center"
Packit 98cdb6
VALIGN="bottom"
Packit 98cdb6
>Writing Your Own Widgets
Packit 98cdb6
>
Packit 98cdb6
WIDTH="10%"
Packit 98cdb6
ALIGN="right"
Packit 98cdb6
VALIGN="bottom"
Packit 98cdb6
>
Packit 98cdb6
HREF="x2310.html"
Packit 98cdb6
ACCESSKEY="N"
Packit 98cdb6
>Next >>>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
ALIGN="LEFT"
Packit 98cdb6
WIDTH="100%">
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT1"
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT1"
Packit 98cdb6
>
Packit 98cdb6
NAME="SEC-CREATINGACOMPOSITEWIDGET"
Packit 98cdb6
>Creating a Composite widget
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
NAME="AEN2202"
Packit 98cdb6
>Introduction
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>One type of widget that you may be interested in creating is a
Packit 98cdb6
widget that is merely an aggregate of other GTK widgets. This type of
Packit 98cdb6
widget does nothing that couldn't be done without creating new
Packit 98cdb6
widgets, but provides a convenient way of packaging user interface
Packit 98cdb6
elements for reuse. The FileSelection and ColorSelection widgets in
Packit 98cdb6
the standard distribution are examples of this type of widget.
Packit 98cdb6
>
Packit 98cdb6
>The example widget that we'll create in this section is the Tictactoe
Packit 98cdb6
widget, a 3x3 array of toggle buttons which triggers a signal when all
Packit 98cdb6
three buttons in a row, column, or on one of the diagonals are
Packit 98cdb6
depressed. 
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="EMPHASIS"
Packit 98cdb6
>Note: the full source code for the Tictactoe example described
Packit 98cdb6
below is in the 
Packit 98cdb6
HREF="a2901.html#SEC-TICTACTOE"
Packit 98cdb6
>Code Examples Appendix
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="INLINEMEDIAOBJECT"
Packit 98cdb6
>
Packit 98cdb6
SRC="images/tictactoe.png">
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
NAME="AEN2213"
Packit 98cdb6
>Choosing a parent class
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>The parent class for a composite widget is typically the container
Packit 98cdb6
class that holds all of the elements of the composite widget. For
Packit 98cdb6
example, the parent class of the FileSelection widget is the
Packit 98cdb6
Dialog class. Since our buttons will be arranged in a table, it
Packit 98cdb6
is natural to make our parent class the Table class.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
NAME="AEN2216"
Packit 98cdb6
>The header file
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>Each GObject class has a header file which declares the object and
Packit 98cdb6
class structures for that object, along with public functions. 
Packit 98cdb6
A couple of features are worth pointing out. To prevent duplicate
Packit 98cdb6
definitions, we wrap the entire header file in:
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>#ifndef __TICTACTOE_H__
Packit 98cdb6
#define __TICTACTOE_H__
Packit 98cdb6
.
Packit 98cdb6
.
Packit 98cdb6
.
Packit 98cdb6
#endif /* __TICTACTOE_H__ */
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>And to keep C++ programs that include the header file happy, in:
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>#include <glib.h>
Packit 98cdb6
Packit 98cdb6
G_BEGIN_DECLS
Packit 98cdb6
.
Packit 98cdb6
.
Packit 98cdb6
.
Packit 98cdb6
G_END_DECLS
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>Along with the functions and structures, we declare five standard
Packit 98cdb6
macros in our header file, 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>TICTACTOE_TYPE
Packit 98cdb6
>,
Packit 98cdb6
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>TICTACTOE(obj)
Packit 98cdb6
>,
Packit 98cdb6
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>TICTACTOE_CLASS(klass)
Packit 98cdb6
>,
Packit 98cdb6
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>IS_TICTACTOE(obj)
Packit 98cdb6
>, and
Packit 98cdb6
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>IS_TICTACTOE_CLASS(klass)
Packit 98cdb6
>, which cast a
Packit 98cdb6
pointer into a pointer to the object or class structure, and check
Packit 98cdb6
if an object is a Tictactoe widget respectively.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
NAME="AEN2228"
Packit 98cdb6
>The 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>_get_type()
Packit 98cdb6
> function
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>We now continue on to the implementation of our widget. A core
Packit 98cdb6
function for every object is the function
Packit 98cdb6
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>WIDGETNAME_get_type()
Packit 98cdb6
>. This function, when first called, tells
Packit 98cdb6
Glib about the new class, and gets an ID that uniquely identifies
Packit 98cdb6
the class. Upon subsequent calls, it just returns the ID.
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>GType
Packit 98cdb6
tictactoe_get_type (void)
Packit 98cdb6
{
Packit 98cdb6
  static GType ttt_type = 0;
Packit 98cdb6
Packit 98cdb6
  if (!ttt_type)
Packit 98cdb6
    {
Packit 98cdb6
      const GTypeInfo ttt_info =
Packit 98cdb6
      {
Packit 98cdb6
	sizeof (TictactoeClass),
Packit 98cdb6
	NULL, /* base_init */
Packit 98cdb6
	NULL, /* base_finalize */
Packit 98cdb6
	(GClassInitFunc) tictactoe_class_init,
Packit 98cdb6
	NULL, /* class_finalize */
Packit 98cdb6
	NULL, /* class_data */
Packit 98cdb6
	sizeof (Tictactoe),
Packit 98cdb6
	0,    /* n_preallocs */
Packit 98cdb6
	(GInstanceInitFunc) tictactoe_init,
Packit 98cdb6
      };
Packit 98cdb6
Packit 98cdb6
      ttt_type = g_type_register_static (GTK_TYPE_TABLE,
Packit 98cdb6
                                         "Tictactoe",
Packit 98cdb6
                                         &ttt_info,
Packit 98cdb6
                                         0);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return ttt_type;
Packit 98cdb6
}
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>The GTypeInfo structure has the following definition:
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>struct _GTypeInfo
Packit 98cdb6
{
Packit 98cdb6
  /* interface types, classed types, instantiated types */
Packit 98cdb6
  guint16                class_size;
Packit 98cdb6
   
Packit 98cdb6
  GBaseInitFunc          base_init;
Packit 98cdb6
  GBaseFinalizeFunc      base_finalize;
Packit 98cdb6
   
Packit 98cdb6
  /* classed types, instantiated types */
Packit 98cdb6
  GClassInitFunc         class_init;
Packit 98cdb6
  GClassFinalizeFunc     class_finalize;
Packit 98cdb6
  gconstpointer          class_data;
Packit 98cdb6
   
Packit 98cdb6
  /* instantiated types */
Packit 98cdb6
  guint16                instance_size;
Packit 98cdb6
  guint16                n_preallocs;
Packit 98cdb6
  GInstanceInitFunc      instance_init;
Packit 98cdb6
   
Packit 98cdb6
  /* value handling */
Packit 98cdb6
  const GTypeValueTable *value_table;
Packit 98cdb6
};
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>The important fields of this structure are pretty self-explanatory.
Packit 98cdb6
We'll ignore the 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>base_init
Packit 98cdb6
> and
Packit 98cdb6
 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>base_finalize
Packit 98cdb6
> as well as the 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>value_table
Packit 98cdb6
>
Packit 98cdb6
fields here. Once Glib has a correctly filled in copy of
Packit 98cdb6
this structure, it knows how to create objects of a particular type. 
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
NAME="AEN2240"
Packit 98cdb6
>The 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>_class_init()
Packit 98cdb6
> function
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>The 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>WIDGETNAME_class_init()
Packit 98cdb6
> function initializes the fields of
Packit 98cdb6
the widget's class structure, and sets up any signals for the
Packit 98cdb6
class. For our Tictactoe widget it looks like:
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>enum {
Packit 98cdb6
  TICTACTOE_SIGNAL,
Packit 98cdb6
  LAST_SIGNAL
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
static guint tictactoe_signals[LAST_SIGNAL] = { 0 };
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
tictactoe_class_init (TictactoeClass *klass)
Packit 98cdb6
{
Packit 98cdb6
  tictactoe_signals[TICTACTOE_SIGNAL] =
Packit 98cdb6
    g_signal_new ("tictactoe",
Packit 98cdb6
                  G_TYPE_FROM_CLASS (klass),
Packit 98cdb6
                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
Packit 98cdb6
                  G_STRUCT_OFFSET (TictactoeClass, tictactoe),
Packit 98cdb6
                  NULL, NULL,
Packit 98cdb6
                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
Packit 98cdb6
}
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>Our widget has just one signal, the 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>tictactoe
Packit 98cdb6
> signal that is
Packit 98cdb6
invoked when a row, column, or diagonal is completely filled in. Not
Packit 98cdb6
every composite widget needs signals, so if you are reading this for
Packit 98cdb6
the first time, you may want to skip to the next section now, as
Packit 98cdb6
things are going to get a bit complicated.
Packit 98cdb6
>
Packit 98cdb6
>The function:
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>guint g_signal_new( const gchar         *signal_name,
Packit 98cdb6
                    GType                itype,
Packit 98cdb6
                    GSignalFlags         signal_flags,
Packit 98cdb6
                    guint                class_offset,
Packit 98cdb6
                    GSignalAccumulator  *accumulator,
Packit 98cdb6
                    gpointer             accu_data,
Packit 98cdb6
                    GSignalCMarshaller  *c_marshaller,
Packit 98cdb6
                    GType                return_type,
Packit 98cdb6
                    guint                n_params,
Packit 98cdb6
                    ...);
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>Creates a new signal. The parameters are:
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>signal_name
Packit 98cdb6
>: The name of the signal.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>itype
Packit 98cdb6
>: The ID of the object that this signal applies
Packit 98cdb6
to. (It will also apply to that objects descendants.)
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>signal_flags
Packit 98cdb6
>: Whether the default handler runs before or after
Packit 98cdb6
user handlers and other flags. Usually this will be one of
Packit 98cdb6
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>G_SIGNAL_RUN_FIRST
Packit 98cdb6
> or 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>G_SIGNAL_RUN_LAST
Packit 98cdb6
>,
Packit 98cdb6
although there are other possibilities. The flag
Packit 98cdb6
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>G_SIGNAL_ACTION
Packit 98cdb6
> specifies that no extra code needs to
Packit 98cdb6
run that performs special pre or post emission adjustments. This means that
Packit 98cdb6
the signal can also be emitted from object external code.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>class_offset
Packit 98cdb6
>: The offset within the class structure of
Packit 98cdb6
a pointer to the default handler.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>accumulator
Packit 98cdb6
>: For most classes this can
Packit 98cdb6
be set to NULL.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>accu_data
Packit 98cdb6
>: User data that will be handed
Packit 98cdb6
to the accumulator function.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>c_marshaller
Packit 98cdb6
>: A function that is used to invoke the signal
Packit 98cdb6
handler. For signal handlers that have no arguments other than the
Packit 98cdb6
object that emitted the signal and user data, we can use the
Packit 98cdb6
pre-supplied marshaller function 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>g_cclosure_marshal_VOID__VOID
Packit 98cdb6
>.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>return_type
Packit 98cdb6
>: The type of the return value.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>n_params
Packit 98cdb6
>: The number of parameters of the signal handler
Packit 98cdb6
(other than the two default ones mentioned above)
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
> 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>...
Packit 98cdb6
>: The types of the parameters.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>When specifying types, the following standard types can be used:
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>G_TYPE_INVALID
Packit 98cdb6
G_TYPE_NONE
Packit 98cdb6
G_TYPE_INTERFACE
Packit 98cdb6
G_TYPE_CHAR
Packit 98cdb6
G_TYPE_UCHAR
Packit 98cdb6
G_TYPE_BOOLEAN
Packit 98cdb6
G_TYPE_INT
Packit 98cdb6
G_TYPE_UINT
Packit 98cdb6
G_TYPE_LONG
Packit 98cdb6
G_TYPE_ULONG
Packit 98cdb6
G_TYPE_INT64
Packit 98cdb6
G_TYPE_UINT64
Packit 98cdb6
G_TYPE_ENUM
Packit 98cdb6
G_TYPE_FLAGS
Packit 98cdb6
G_TYPE_FLOAT
Packit 98cdb6
G_TYPE_DOUBLE
Packit 98cdb6
G_TYPE_STRING
Packit 98cdb6
G_TYPE_POINTER
Packit 98cdb6
G_TYPE_BOXED
Packit 98cdb6
G_TYPE_PARAM
Packit 98cdb6
G_TYPE_OBJECT
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>g_signal_new()
Packit 98cdb6
> returns a unique integer identifier for the
Packit 98cdb6
signal, that we store in the 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>tictactoe_signals
Packit 98cdb6
> array, which we
Packit 98cdb6
index using an enumeration. (Conventionally, the enumeration elements
Packit 98cdb6
are the signal name, uppercased, but here there would be a conflict
Packit 98cdb6
with the 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>TICTACTOE()
Packit 98cdb6
> macro, so we called it 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>TICTACTOE_SIGNAL
Packit 98cdb6
>
Packit 98cdb6
instead.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
NAME="AEN2293"
Packit 98cdb6
>The 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>_init()
Packit 98cdb6
> function
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>Each class also needs a function to initialize the object
Packit 98cdb6
structure. Usually, this function has the fairly limited role of
Packit 98cdb6
setting the fields of the structure to default values. For composite
Packit 98cdb6
widgets, however, this function also creates the component widgets.
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>static void
Packit 98cdb6
tictactoe_init (Tictactoe *ttt)
Packit 98cdb6
{
Packit 98cdb6
  gint i,j;
Packit 98cdb6
Packit 98cdb6
  gtk_table_resize (GTK_TABLE (ttt), 3, 3);
Packit 98cdb6
  gtk_table_set_homogeneous (GTK_TABLE (ttt), TRUE);
Packit 98cdb6
Packit 98cdb6
  for (i=0;i<3; i++)
Packit 98cdb6
    for (j=0;j<3; j++)
Packit 98cdb6
      {
Packit 98cdb6
	ttt->buttons[i][j] = gtk_toggle_button_new ();
Packit 98cdb6
	gtk_table_attach_defaults (GTK_TABLE (ttt), ttt->buttons[i][j], 
Packit 98cdb6
				   i, i+1, j, j+1);
Packit 98cdb6
	g_signal_connect (ttt->buttons[i][j], "toggled",
Packit 98cdb6
			  G_CALLBACK (tictactoe_toggle), ttt);
Packit 98cdb6
	gtk_widget_set_size_request (ttt->buttons[i][j], 20, 20);
Packit 98cdb6
	gtk_widget_show (ttt->buttons[i][j]);
Packit 98cdb6
      }
Packit 98cdb6
}
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
CLASS="SECT2"
Packit 98cdb6
>
Packit 98cdb6
NAME="AEN2298"
Packit 98cdb6
>And the rest...
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>There is one more function that every object (except for abstract
Packit 98cdb6
classes like Bin that cannot be instantiated) needs to have - the
Packit 98cdb6
function that the user calls to create an object of that type. This is
Packit 98cdb6
conventionally called 
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>OBJECTNAME_new()
Packit 98cdb6
>. In some
Packit 98cdb6
widgets, though not for the Tictactoe widgets, this function takes
Packit 98cdb6
arguments, and does some setup based on the arguments. The other two
Packit 98cdb6
functions are specific to the Tictactoe widget. 
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>tictactoe_clear()
Packit 98cdb6
> is a public function that resets all the
Packit 98cdb6
buttons in the widget to the up position. Note the use of
Packit 98cdb6
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>g_signal_handlers_block_matched()
Packit 98cdb6
> to keep our signal handler for
Packit 98cdb6
button toggles from being triggered unnecessarily.
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="LITERAL"
Packit 98cdb6
>tictactoe_toggle()
Packit 98cdb6
> is the signal handler that is invoked when the
Packit 98cdb6
user clicks on a button. It checks to see if there are any winning
Packit 98cdb6
combinations that involve the toggled button, and if so, emits
Packit 98cdb6
the "tictactoe" signal.
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>GtkWidget*
Packit 98cdb6
tictactoe_new (void)
Packit 98cdb6
{
Packit 98cdb6
  return GTK_WIDGET ( g_object_new (TICTACTOE_TYPE, NULL));
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
void	       
Packit 98cdb6
tictactoe_clear (Tictactoe *ttt)
Packit 98cdb6
{
Packit 98cdb6
  int i,j;
Packit 98cdb6
Packit 98cdb6
  for (i=0;i<3;i++)
Packit 98cdb6
    for (j=0;j<3;j++)
Packit 98cdb6
      {
Packit 98cdb6
	g_signal_handlers_block_matched (G_OBJECT (ttt->buttons[i][j]),
Packit 98cdb6
                                         G_SIGNAL_MATCH_DATA,
Packit 98cdb6
                                         0, 0, NULL, NULL, ttt);
Packit 98cdb6
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
Packit 98cdb6
				     FALSE);
Packit 98cdb6
	g_signal_handlers_unblock_matched (G_OBJECT (ttt->buttons[i][j]),
Packit 98cdb6
                                           G_SIGNAL_MATCH_DATA,
Packit 98cdb6
                                           0, 0, NULL, NULL, ttt);
Packit 98cdb6
      }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
Packit 98cdb6
{
Packit 98cdb6
  int i,k;
Packit 98cdb6
Packit 98cdb6
  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
Packit 98cdb6
			     { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
Packit 98cdb6
			     { 0, 1, 2 }, { 0, 1, 2 } };
Packit 98cdb6
  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
Packit 98cdb6
			     { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
Packit 98cdb6
			     { 0, 1, 2 }, { 2, 1, 0 } };
Packit 98cdb6
Packit 98cdb6
  int success, found;
Packit 98cdb6
Packit 98cdb6
  for (k=0; k<8; k++)
Packit 98cdb6
    {
Packit 98cdb6
      success = TRUE;
Packit 98cdb6
      found = FALSE;
Packit 98cdb6
Packit 98cdb6
      for (i=0;i<3;i++)
Packit 98cdb6
	{
Packit 98cdb6
	  success = success && 
Packit 98cdb6
	    GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
Packit 98cdb6
	  found = found ||
Packit 98cdb6
	    ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
Packit 98cdb6
	}
Packit 98cdb6
      
Packit 98cdb6
      if (success && found)
Packit 98cdb6
	{
Packit 98cdb6
	  g_signal_emit (ttt, 
Packit 98cdb6
			 tictactoe_signals[TICTACTOE_SIGNAL], 0);
Packit 98cdb6
	  break;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>And finally, an example program using our Tictactoe widget:
Packit 98cdb6
>
Packit 98cdb6
BORDER="0"
Packit 98cdb6
BGCOLOR="#E0E0E0"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="PROGRAMLISTING"
Packit 98cdb6
>#include <gtk/gtk.h>
Packit 98cdb6
#include "tictactoe.h"
Packit 98cdb6
Packit 98cdb6
/* Invoked when a row, column or diagonal is completed */
Packit 98cdb6
void
Packit 98cdb6
win (GtkWidget *widget, gpointer data)
Packit 98cdb6
{
Packit 98cdb6
  g_print ("Yay!\n");
Packit 98cdb6
  tictactoe_clear (TICTACTOE (widget));
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
int 
Packit 98cdb6
main (int argc, char *argv[])
Packit 98cdb6
{
Packit 98cdb6
  GtkWidget *window;
Packit 98cdb6
  GtkWidget *ttt;
Packit 98cdb6
  
Packit 98cdb6
  gtk_init (&argc, &argv);
Packit 98cdb6
Packit 98cdb6
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit 98cdb6
  
Packit 98cdb6
  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
Packit 98cdb6
  
Packit 98cdb6
  g_signal_connect (window, "destroy",
Packit 98cdb6
                    G_CALLBACK (exit), NULL);
Packit 98cdb6
  
Packit 98cdb6
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
Packit 98cdb6
Packit 98cdb6
  /* Create a new Tictactoe widget */
Packit 98cdb6
  ttt = tictactoe_new ();
Packit 98cdb6
  gtk_container_add (GTK_CONTAINER (window), ttt);
Packit 98cdb6
  gtk_widget_show (ttt);
Packit 98cdb6
Packit 98cdb6
  /* And attach to its "tictactoe" signal */
Packit 98cdb6
  g_signal_connect (ttt, "tictactoe",
Packit 98cdb6
                    G_CALLBACK (win), NULL);
Packit 98cdb6
Packit 98cdb6
  gtk_widget_show (window);
Packit 98cdb6
  
Packit 98cdb6
  gtk_main ();
Packit 98cdb6
  
Packit 98cdb6
  return 0;
Packit 98cdb6
}
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
CLASS="NAVFOOTER"
Packit 98cdb6
>
Packit 98cdb6
ALIGN="LEFT"
Packit 98cdb6
WIDTH="100%">
Packit 98cdb6
SUMMARY="Footer navigation table"
Packit 98cdb6
WIDTH="100%"
Packit 98cdb6
BORDER="0"
Packit 98cdb6
CELLPADDING="0"
Packit 98cdb6
CELLSPACING="0"
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
WIDTH="33%"
Packit 98cdb6
ALIGN="left"
Packit 98cdb6
VALIGN="top"
Packit 98cdb6
>
Packit 98cdb6
HREF="x2189.html"
Packit 98cdb6
ACCESSKEY="P"
Packit 98cdb6
><<< Previous
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
WIDTH="34%"
Packit 98cdb6
ALIGN="center"
Packit 98cdb6
VALIGN="top"
Packit 98cdb6
>
Packit 98cdb6
HREF="book1.html"
Packit 98cdb6
ACCESSKEY="H"
Packit 98cdb6
>Home
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
WIDTH="33%"
Packit 98cdb6
ALIGN="right"
Packit 98cdb6
VALIGN="top"
Packit 98cdb6
>
Packit 98cdb6
HREF="x2310.html"
Packit 98cdb6
ACCESSKEY="N"
Packit 98cdb6
>Next >>>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
WIDTH="33%"
Packit 98cdb6
ALIGN="left"
Packit 98cdb6
VALIGN="top"
Packit 98cdb6
>The Anatomy Of A Widget
Packit 98cdb6
>
Packit 98cdb6
WIDTH="34%"
Packit 98cdb6
ALIGN="center"
Packit 98cdb6
VALIGN="top"
Packit 98cdb6
>
Packit 98cdb6
HREF="c2180.html"
Packit 98cdb6
ACCESSKEY="U"
Packit 98cdb6
>Up
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
WIDTH="33%"
Packit 98cdb6
ALIGN="right"
Packit 98cdb6
VALIGN="top"
Packit 98cdb6
>Creating a widget from scratch
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>
Packit 98cdb6
>