If you're writing a custom
GtkObject or a custom subclass of some existing
object, you can register your own object arguments in the
class initialization function, at the same time you
register your object's signals. To do this, call gtk_object_add_arg_type()---here's
an example from GtkContainer:
gtk_object_add_arg_type("GtkContainer::border_width",
GTK_TYPE_ULONG,
GTK_ARG_READWRITE,
ARG_BORDER_WIDTH);
|
The first argument must be a static string constant,
because GTK+ does not copy it. It must also begin with
the name of your new class, separated from the name of
the argument by two colons (reminiscent of the C++ scope
operator). The second argument should be the type of the
argument; this can be any
GtkType GTK+ knows about.
The third argument contains one or more flags, defined in
gtk/gtkobject.h. The available
flags are:
-
GTK_ARG_READABLE
means the argument's value can be read, using gtk_object_getv().
-
GTK_ARG_WRITABLE
means the argument's value can be written, using gtk_object_set() or gtk_object_setv()
-
GTK_ARG_CONSTRUCT
means the argument should be initialized with a
default value. This applies to numeric and pointer
types; they are set to
0 or NULL,
respectively. (This happens within gtk_object_new() or gtk_widget_new(), which call
gtk_object_default_construct().)
-
GTK_ARG_CONSTRUCT_ONLY means the argument is
only used for object
construction; it cannot be read or written later.
That is, you can't use these arguments with gtk_object_set().
-
GTK_ARG_CHILD_ARG is
used by subclasses of
GtkContainer;
GtkContainer implements a specialized variation
on the argument system to permit setting the
attributes of child-container pairs (such as packing
flags for GtkBox---the
flags are not a property of the child or the
container, but of the pair). You will only use this
flag if you're writing a new type of container, or
some other kind of object with similar semantics.
-
GTK_ARG_READWRITE is
shorthand for
(GTK_ARG_READABLE | GTK_ARG_WRITABLE).
There are some limitations on which flags can be used.
-
All arguments must be either readable or
writable.
-
GTK_ARG_CONSTRUCT
arguments must be both readable and writable.
-
GTK_ARG_CONSTRUCT_ONLY arguments must be
writable.
-
GTK_ARG_CHILD_ARG
should not be used outside of container-style object
implementations; it is used internally by the GtkContainer child argument
functions.
The fourth and final argument to
gtk_object_add_arg_type() is an argument ID to be
used by the object subclass to identify this argument.
This can be any integer except
0, but it is customary to use a private
enumeration in the object implementation's .c file.
GtkObject has two class functions any subclass
with arguments must implement: one to get arguments
specific to the subclass, and one to set them. These
functions are passed the argument ID, so they know which
argument to get or set. Argument IDs reduce the need for
string comparisons, increasing the efficiency of argument
manipulation.
For example, GtkContainer
defines these functions:
static void gtk_container_get_arg(GtkObject* object,
GtkArg* arg,
guint arg_id);
static void gtk_container_set_arg(GtkObject* object,
GtkArg* arg,
guint arg_id);
|
It uses this enumeration to create its argument IDs:
enum {
ARG_0, /* Skip 0, an invalid argument ID */
ARG_BORDER_WIDTH,
ARG_RESIZE_MODE,
ARG_CHILD
};
|
It registers its arguments in
gtk_container_class_init() as follows:
gtk_object_add_arg_type("GtkContainer::border_width",
GTK_TYPE_ULONG,
GTK_ARG_READWRITE,
ARG_BORDER_WIDTH);
gtk_object_add_arg_type("GtkContainer::resize_mode",
GTK_TYPE_RESIZE_MODE,
GTK_ARG_READWRITE,
ARG_RESIZE_MODE);
gtk_object_add_arg_type("GtkContainer::child",
GTK_TYPE_WIDGET,
GTK_ARG_WRITABLE,
ARG_CHILD);
|
gtk_container_set_arg() and gtk_container_get_arg() are
installed in the class struct:
object_class->get_arg = gtk_container_get_arg;
object_class->set_arg = gtk_container_set_arg;
|
gtk_container_set_arg() and gtk_container_get_arg() are then
implemented like this:
static void
gtk_container_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id)
{
GtkContainer *container;
container = GTK_CONTAINER (object);
switch (arg_id)
{
case ARG_BORDER_WIDTH:
gtk_container_set_border_width (container, GTK_VALUE_ULONG (*arg));
break;
case ARG_RESIZE_MODE:
gtk_container_set_resize_mode (container, GTK_VALUE_ENUM (*arg));
break;
case ARG_CHILD:
gtk_container_add (container, GTK_WIDGET (GTK_VALUE_OBJECT (*arg)));
break;
default:
break;
}
}
static void
gtk_container_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id)
{
GtkContainer *container;
container = GTK_CONTAINER (object);
switch (arg_id)
{
case ARG_BORDER_WIDTH:
GTK_VALUE_ULONG (*arg) = container->border_width;
break;
case ARG_RESIZE_MODE:
GTK_VALUE_ENUM (*arg) = container->resize_mode;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
|
Notice that the type must be set to GTK_TYPE_INVALID if your subclass
doesn't understand the argument ID. This is used as an
error indicator; users who call
gtk_object_getv() will check for it.
If you flip back to page XXXX and have another look at
the GtkButton class
initialization function, you should now understand what
is going on with respect to object arguments.