packages feed

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:
 */