Using object arguments, one can discover at runtime what
attributes an object has, and then get or set their values.
This is very useful for people implementing GUI builders,
since some of the widget configuration dialogs can be
automated. Similarly, it makes it much easier to write GTK+
bindings for scripting languages. It can also be convenient
for programmers, since they can avoid writing all the
get/set functions---the
GnomeCanvas, for example, uses object arguments for
almost all of its API. Finally, object arguments may be
configurable via the gtkrc
configuration mechanism in a future version of GTK+, making
it possible for users to extensively customize GTK+
software.
Most commonly, arguments are used as an API to set
attributes of widgets. However, not all of the GTK+ API
has been exported via arguments, so it is not always
possible.
To set widget attributes, the most convenient interface
is gtk_object_set(). Here's an
example:
gtk_object_set(GTK_OBJECT(vbox),
"GtkContainer::border_width", (gulong) 10,
NULL);
|
The above code is identical in effect to:
gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
|
It's up to you which to use; it depends on the context.
Typically, you would use the argument mechanism if you
have a reason to, i.e. if you are using its dynamic,
runtime-oriented features. However, if you are setting
several attributes, it may be easier to type and read.
gtk_object_set() takes a GtkObject as the first
argument, followed by any number of key-value pairs. If a
key is not defined for the object you pass in, a runtime
error will be triggered. The list of key-value pairs must
be terminated with a NULL
key. When a GtkObject
registers itself with GTK+, it tells GTK+ what type of
value to expect after each key. For the aggregate
fundamental types
gtk_object_set() will expect more than one C
function argument after the key. For example, first a
signal function and then a user data pointer will be
expected after
GTK_TYPE_SIGNAL arguments. (Table 1 in the section
called GtkArg and the
Type System gives the types of the expected
arguments.)
It is permissible to leave off the object class portion
of an argument name---"GtkContainer::border_width" can be
simply "border_width":
gtk_object_set(GTK_OBJECT(vbox),
"border_width", (gulong) 10,
NULL);
|
If you do not specify the class name as part of the
argument name, GTK+ will start with the real type of the
object and look up the argument name in the argument
table for each superclass until it finds the right one
(GtkContainer in this case).
If you do specify the class name, GTK+ will only look for
the argument in the specified class's argument table.
Since gtk_object_set() uses C
variable argument lists, it has limited type safety. This
can be a real problem in your code. You may have noticed
the cast to gulong in the
sample call to
gtk_object_set(). The argument GtkContainer::border_width has type
GTK_TYPE_ULONG. GTK+ will
extract sizeof(gulong)
bytes from the argument list when it encounters this
argument. If you leave out the cast, C will probably pass
only sizeof(gint) bytes
to the function. As you might imagine, this causes memory
corruption on many platforms. A similar problem arises
with arguments of type
GTK_TYPE_DOUBLE; if you type 5 instead of 5.0, C will pass an integer to gtk_object_set(). These bugs are
very hard to find, once you introduce them.
gtk_object_set() is syntactic
sugar for a more fundamental function call, gtk_object_setv().
gtk_object_setv() takes a vector of GtkArg (gtk_object_set() converts each key-value
pair in its argument list to
GtkArg internally).
GtkArg args[1];
args[0].name = "GtkContainer::border_width";
args[0].type = GTK_TYPE_ULONG;
GTK_VALUE_ULONG(args[0]) = 10;
gtk_object_setv(GTK_OBJECT(button),
1,
args);
|
The second argument to
gtk_object_setv() is the length of the array of
GtkArg. gtk_object_set() is plainly easier to use
when you are typing the code in manually, but gtk_object_setv() can be passed a
dynamically-constructed argument array---which is
convenient if you're exporting GTK+ functionality to an
interpreted environment.
It is also possible to set object arguments when objects
are created. You can create most objects using the gtk_object_new() function, and most
widgets with the
gtk_widget_new() function. The routines take a GtkType as their first
argument, and create an object or widget of that type.
They then take a list of argument-value pairs, just as
gtk_object_set() does. There
are also gtk_object_newv() and
gtk_widget_newv() variants.