/* * vim:ts=4:sw=4: */ #include #include #include /* from xfconf/common/xfconf-common-private.h */ #include #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: */