xfconf update - array and struct types

Brian J. Tarricone bjt23 at cornell.edu
Mon Oct 15 10:34:32 CEST 2007


Hey all,

I'm working on the libxfconf API and some changes to the xfconf daemon
and backend.  I think I've worked out a library API that I'm more or
less happy with -- it's incredibly flexible, but still very easy to use
if you just want to store simple values in the config store.

I've updated the API documentation, though I haven't committed any of
these changes to SVN (the client code is done but untested, and there
are still some required changes to the config backend before it'll
work properly).  See here:
http://foo-projects.org/~kelnos/xfconf/current/
The main important changes are in XfconfChannel.

If you just want to dive in and look at it, feel free to skip the
rest of this email.  Here's my detailed overview of the changes:

* Arbitrary scalar values.  I added
xfconf_channel_(get|set)_property(), which allows you to set properties
based on (somewhat) arbitrary GValues (the backend needs to support
them). The 'convenience API', as before, only lets you set string, int,
uint64, double, and boolean. If you want to set something a bit more
uncommon, like char, short, or float, you can use this API.

* Array values.  The 'string list' API is now just a special case of
the new, more general array API.  You can set array properties that
contain values of (if you want) mixed types.  There are two different
ways of doing this: via a varargs-style API (sorta like
dbus_message_get_args()), and a value-array API.  So you could do:

gint32 a = 93021;
gboolean b = FALSE;
gdouble c = 42.42;
xfconf_channel_set_array(channel, "/foo/bar",
                         G_TYPE_INT, &a,
                         G_TYPE_BOOLEAN, &b,
                         G_TYPE_DOUBLE, &c,
                         G_TYPE_INVALID);

or you can construct a GValueArray and use xfconf_channel_set_arrayv().

One thing that's lacking here is convenience API for arrays of the same
type, e.g.:

gint a[4] = { 1, 2, 3, 4 };
xfconf_channel_set_int_array(channel, "/foo/bar", a, 4);

Currently, doing that is annoying and has a lot of overhead:

GValueArray *arr = g_value_array_new(4);
GValue val = { 0, };
gint a[4] = { 1, 2, 3, 4 }, i;

for(i = 0; i < G_N_ELEMENTS(a); ++i) {
    g_value_init(&val, G_TYPE_INT);
    g_value_set_int(&val, a[i]);
    g_value_array_append(arr, &val);
    g_value_unset(&val);
}

xfconf_channel_set_arrayv(channel, "/foo/bar", arr);
g_value_array_free(arr);

... which seems like a bit much.  I'd rather not bloat the XfconfChannel
interface, though maybe there could be some separate helper functions,
like:

GValueArray *xfconf_value_array_from_int_array(gint *values,
                                               guint n_values);

I'd rather not unnecessarily bloat the library size if possible (though
right now it's only 38kB stripped, on my machine, anyway).

* Struct values.  This is built on top of the array value stuff, and I
think it's pretty cool.  Basically, you can pass the library a property
name, a struct, and a list of GTypes for the members, and it'll fill in
the struct from the config store (or save the struct values in the
config store). There's API to register "named structs" which basically
just has the library remember the struct layout for you so you don't
have to type it over and over if you use it a lot.  This is how we fix
our GdkColor/McsColor problem and leave the door open for a lot of
other uses.  It works like this:

/* from gdk */
typedef struct _GdkColor
{
    guint16 red;
    guint16 green;
    guint16 blue;
} GdkColor;

/* our app */
GdkColor color = { 0xe922, 0x594, 0x8fc8 };
xfconf_channel_set_struct(channel, "/foo/barcolor", &color,
                          XFCONF_TYPE_UINT16,
                          XFCONF_TYPE_UINT16,
                          XFCONF_TYPE_UINT16,
                          G_TYPE_INVALID);

... and that's all you have to do to store a GdkColor.  Retrieving it
works the same way.  I'd probably include some named structs by
default, including GdkColor, so you could do this:

/* from xfconf.h */
#define XFCONF_NAMED_STRUCT_GDKCOLOR  "Xfconf-GdkColor"

/* our app */
GdkColor color = { 0xe922, 0x594, 0x8fc8 };
xfconf_channel_set_named_struct(channel, "/foo/barcolor",
                                XFCONF_NAMED_STRUCT_GDKCOLOR, &color);

The cool thing is that none of the struct stuff requires the daemon or
backend to know anything about structs.  It just sees these as arrays
of values.  The client lib does all the validation to make sure the
struct layout matches the types of the array elements in the config
store.

There's one possible issue: struct member alignment.  Right now
libxfconf is placing values in the struct you pass it by taking into
account struct member alignment.  If you use the gcc extension
__attribute__((packed)) on your structs, this won't work, and you'll
get segfaults in your application if your structs would normally require
padding.  I'm tempted to just list that as a limitation and leave it
alone, since I think most of the time you'd use this libxfconf
functionality for normal aligned structs.  The only time you really use
packed structs is when you're using structs to represent some binary
file format on disk or a wire protocol on the network, or something
like that.

So, that's about it.  It's far past my bed time, so I should get to
sleep and work on this more tomorrow.  Comments, criticisms, and
suggestions would be most welcome; it would be good to know if people
think I'm going in the right direction, or if I'm getting to the point
where I'm overengineering things.

	-brian



More information about the Xfce4-dev mailing list