xfconf-4.8.0.0: C/demo.c
/*
* vim:ts=4:sw=4:
*/
#include <xfce4/xfconf-0/xfconf/xfconf.h>
#include <stdio.h>
#include <stdlib.h>
/* from xfconf/common/xfconf-common-private.h */
#include <dbus/dbus-glib.h>
#define XFCONF_TYPE_G_VALUE_ARRAY (dbus_g_type_get_collection("GPtrArray", G_TYPE_VALUE))
void
print_channels (void) {
gchar **channels = NULL;
gint i;
channels = xfconf_list_channels ();
for (i = 0; channels[i]; i++) {
g_print ("found channel [%s]\n", channels[i]);
}
g_strfreev (channels);
}
void
play_with_string (XfconfChannel *chan) {
const gchar *prop = "/String";
gchar *value;
value = xfconf_channel_get_string (chan, prop, "NA");
g_print ("%s is [%s]\n", prop, value);
g_free (value);
if (!xfconf_channel_set_string (chan, prop, "HelloWorld")) {
g_printerr ("ERROR: cannot set xfwm4 theme :(\n");
} else {
g_print ("Successfully tweak xfwm4 theme\n");
}
}
void
play_with_double (XfconfChannel *chan) {
const gchar *prop = "/Double";
gdouble value;
value = xfconf_channel_get_double (chan, prop, 0.0);
g_print ("%s is [%f]\n", prop, value);
if (!xfconf_channel_set_double (chan, prop, 3.3)) {
g_printerr ("ERROR: cannot set saturation :(\n");
} else {
g_print ("Successfully tweak saturation\n");
}
}
/* You can see in the following code that even if we set gvalues
* with xfconf_g_value_set_uint16, when we get them back from the
* xfconfd store, they are UINT and not uint16.
*
* ... this close our pseudo haskell bug :)
*/
void
play_with_uint16 (XfconfChannel* chan) {
const gchar *prop = "/UInt16";
GValue value = {0};
g_value_init(&value, XFCONF_TYPE_UINT16);
xfconf_g_value_set_uint16 (&value, 33);
if (!xfconf_channel_set_property (chan, prop, &value))
g_error ("cannot set uint16 value to 33\n");
g_value_unset(&value);
if (xfconf_channel_get_property (chan, prop, &value)) {
if (G_VALUE_HOLDS (&value, XFCONF_TYPE_UINT16)) {
guint16 x = xfconf_g_value_get_uint16 (&value);
g_print ("%s is an uint16: %u\n", prop, x);
} else if (G_VALUE_HOLDS (&value,G_TYPE_UINT)) {
guint x = g_value_get_uint (&value);
g_print ("%s is an uint: %u\n", prop, x);
} else {
g_error ("Unknown GValue type for our uint16\n");
}
} else {
g_error ("Cannot get UInt16 GValue !\n");
}
}
/* rinse and repeat */
void
play_with_int16 (XfconfChannel* chan) {
const gchar *prop = "/Int16";
GValue value = {0};
g_value_init(&value, XFCONF_TYPE_INT16);
xfconf_g_value_set_int16 (&value, -33);
if (!xfconf_channel_set_property (chan, prop, &value))
g_error ("cannot set int16 value to -33\n");
g_value_unset(&value);
if (xfconf_channel_get_property (chan, prop, &value)) {
if (G_VALUE_HOLDS (&value, XFCONF_TYPE_INT16)) {
gint16 x = xfconf_g_value_get_int16 (&value);
g_print ("%s is an int16: %d\n", prop, x);
} else if (G_VALUE_HOLDS (&value,G_TYPE_INT)) {
gint x = g_value_get_int (&value);
g_print ("%s is an int: %d\n", prop, x);
} else {
g_error ("Unknown GValue type for our int16\n");
}
} else {
g_error ("Cannot get Int16 GValue !\n");
}
}
GPtrArray *free_my_array (GPtrArray* array) {
unsigned int i;
if (!array)
return NULL;
for(i = 0; i < array->len; i++) {
GValue *gvalue = g_ptr_array_index(array, 0);
g_free(gvalue);
}
g_ptr_array_free(array, TRUE);
return NULL;
}
/* Does xfconfd free itself old arrays ??? */
void
play_with_arrays (XfconfChannel* chan) {
const gchar *prop = "/Array";
GValue *element0 = g_new0(GValue, 1);
GValue *element1 = g_new0(GValue, 1);
GPtrArray *array0 = g_ptr_array_sized_new(1);
GPtrArray *array1 = g_ptr_array_sized_new(1);
GValue box0 = {0};
GValue box1 = {0};
/* Set array value, first version */
g_value_init(element0, G_TYPE_STRING);
g_value_set_string(element0, "first item");
g_ptr_array_add(array0, element0);
g_value_init(&box0, XFCONF_TYPE_G_VALUE_ARRAY);
g_value_set_boxed(&box0, array0);
if (!xfconf_channel_set_property(chan, prop, &box0))
g_error("fail to set array0\n");
g_print("array0.len = %d\n", array0->len);
g_print("array1.len = %d\n", array1->len);
puts("Press any key to continue");
getc(stdin);
/* Set array value, second version */
g_value_init(element1, G_TYPE_STRING);
g_value_set_string(element1, "second item");
g_ptr_array_add(array1, element1);
g_value_init(&box1, XFCONF_TYPE_G_VALUE_ARRAY);
g_value_set_boxed(&box1, array1);
if (!xfconf_channel_set_property(chan, prop, &box1))
g_error("fail to set array1\n");
array0 = free_my_array (array0);
array1 = free_my_array (array1);
if (array0) {
GValue *element = g_ptr_array_index(array0, 0);
if (element)
g_print("array0[0] = %s\n", g_value_get_string(element));
}
g_print("array0.len = %d\n", array0 ? array0->len : 0);
g_print("array1.len = %d\n", array1 ? array1->len : 0);
g_print("conclusion: there is a memory leak when setting new arrays\n");
}
void
print_keys (gpointer data, gpointer user_data) {
gchar *key = data;
if (user_data != NULL) {
g_error ("have you forgotten to set user_data to NULL ?\n");
return;
} else {
g_print ("found %s\n", key);
}
}
void
strings_array_print_string(gchar ** strings)
{
int i;
if (strings == NULL) {
g_printerr("string array is NULL !\n");
return;
}
for (i = 0; ; i++) {
gchar *s = strings[i];
if (s == NULL) break;
g_print("strings2[%d] = %s\n", i, s);
}
}
/* Where you can admire the use of GOTOs and why xfconf string list are
* just another type of GPtrArray*
*/
void
play_with_string_list (XfconfChannel *chan) {
GHashTable* table = xfconf_channel_get_properties (chan,"/");
GList* list = g_hash_table_get_keys(table);
GValue* value;
g_list_foreach (list, &print_keys, NULL);
value = g_hash_table_lookup(table, "/Int");
if (value == NULL) {
g_error("GValue is void, aborting ...\n");
goto EXIT_STRING_LIST;
}
g_print ("/Int is %d\n", g_value_get_int(value));
g_print ("/Int has type [%s]\n", G_VALUE_TYPE_NAME(value));
value = g_hash_table_lookup(table, "/StringList");
g_print ("/StringList is [%s]\n", G_VALUE_TYPE_NAME(value));
g_print ("/StringList type id is [%u]\n", (guint)G_VALUE_TYPE(value));
if (G_VALUE_TYPE(value) == XFCONF_TYPE_G_VALUE_ARRAY)
g_print ("Yes, it is an (xfconf) array\n");
else
g_print("No, it is not an array, since arrays have type [%u]\n", (guint)G_TYPE_VALUE_ARRAY);
EXIT_STRING_LIST:
g_list_free(list);
g_hash_table_destroy(table);
}
/* Silly programmers WILL try to set string lists to an empty array.
*
* A bug in the Haskell xfconf appears when:
* 0) a string list property is intialized to some non-empty array;
* 1) the same property is then set to an empty array (via
* set_string_list or reset_property);
* 2) but the proprety ain't empty, it still holds the previous content.
*
* This function checks in C that xfconf_channel_reset_property
* correctly set an empty array.
*/
void
play_with_null_string_list (XfconfChannel *chan) {
const gchar prop[20] = "/StringList";
const gchar * const strings[] = { "one", "two", "three", NULL };
const gchar * const strings0[] = { NULL };
gchar **strings2 = NULL;
int ret;
g_print("Setting string array to:\n");
strings_array_print_string((gchar **)strings);
ret = xfconf_channel_set_string_list(chan, prop, strings);
if (ret == FALSE) {
g_print("Cannot set string array !\n");
}
g_print("Array retrieved is now:\n");
strings2 = xfconf_channel_get_string_list(chan, prop);
strings_array_print_string(strings2);
g_strfreev(strings2);
strings2 = NULL;
g_print("And now for something completely different ...\n");
g_print("... setting the property to an empty array !\n");
xfconf_channel_reset_property(chan, prop, FALSE);
g_print("retreived array is:\n");
strings2 = xfconf_channel_get_string_list(chan, prop);
strings_array_print_string(strings2);
ret = xfconf_channel_set_string_list(chan, prop, strings0);
if (ret == FALSE) {
g_print("Cannot set NULL string array !\n");
}
ret = xfconf_channel_set_string_list(chan, prop, NULL);
if (ret == FALSE) {
g_print("Cannot set NULL string array !\n");
}
}
/* when xfconf_channel_get_property returns false, the GValue* is
* uninitialized and we cannot unset it safely */
void
play_with_gvalue_bug (XfconfChannel* chan) {
GValue gvalue = {0};
const gchar* prop = "/notExisitingProperty";
xfconf_channel_get_property (chan, prop, &gvalue);
if (G_IS_VALUE(&gvalue))
g_print ("I've got a valid value !\n");
else
g_print ("unvalid gvalue !\n");
}
int
main (void) {
GError *error = NULL;
const gchar name[20] = "quickcheck";
/* init */
xfconf_init (&error);
if (error != NULL) {
g_printerr( "an error with code %d occured: %s\n",
error->code, error->message);
g_clear_error (&error);
return EXIT_FAILURE;
}
else
printf ("Hello world of xfconf !\n");
/* list channels */
/*print_channels ();*/
/* play with values get/set */
{
XfconfChannel *chan = xfconf_channel_get (name);
if (chan == NULL) {
g_critical("Failed to connect to \"%s\" channel\n", name);
return EXIT_FAILURE;
}
/* string */
/*play_with_string (chan);*/
/* double */
/*play_with_double (chan);*/
/* uint16 */
/*play_with_uint16 (chan);*/
/* uint16 */
/*play_with_int16 (chan);*/
/* StringList */
/*play_with_string_list (chan);*/
/* Array */
/*play_with_arrays (chan);*/
/* GValue bug */
/*play_with_gvalue_bug (chan);*/
/* Empty string array. */
play_with_null_string_list (chan);
}
xfconf_shutdown ();
return EXIT_SUCCESS;
}
/*
* vim:tabstop=4:
*/