Author: kelnos Date: 2008-04-20 07:39:02 +0000 (Sun, 20 Apr 2008) New Revision: 26874
Modified: xfconf/trunk/common/xfconf-types.c xfconf/trunk/docs/spec/backend.txt xfconf/trunk/docs/spec/perchannel-xml.txt xfconf/trunk/xfconf/xfconf-channel.c Log: treat uint16/int16 as uint32/int32 when sending data over dbus annoyingly, dbus-glib doesn't support sending 16-bit signed or unsigned integers over the bus, since no 16-bit GTypes exist. the ability to expose custom GValue marshallers is not exposed in dbus-glib's API, so custom GTypes cannot be added. so, internally, we handle 16-bit values as if they were 32-bit values. the 16-bit types are kept so that the struct-related functions still work. Modified: xfconf/trunk/common/xfconf-types.c =================================================================== --- xfconf/trunk/common/xfconf-types.c 2008-04-20 07:38:50 UTC (rev 26873) +++ xfconf/trunk/common/xfconf-types.c 2008-04-20 07:39:02 UTC (rev 26874) @@ -21,13 +21,134 @@ #include <config.h> #endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + #include "xfconf/xfconf-types.h" #include "xfconf-alias.h" #include <gobject/gvaluecollector.h> +static void +gvalue_from_short(const GValue *src_value, + GValue *dest_value) +{ +#define HANDLE_TYPE(gtype_s, getter) \ + case G_TYPE_ ## gtype_s: \ + dest = (guint64)g_value_get_ ## getter(src_value); \ + break; + guint64 dest; /* use larger type so we can handle int16 & uint16 */ + + switch(G_VALUE_TYPE(src_value)) { + case G_TYPE_STRING: + dest = atoi(g_value_get_string(src_value)); + break; + case G_TYPE_BOOLEAN: + dest = g_value_get_boolean(src_value) == TRUE ? 1 : 0; + break; + HANDLE_TYPE(CHAR, char) + HANDLE_TYPE(UCHAR, uchar) + HANDLE_TYPE(INT, int) + HANDLE_TYPE(UINT, uint) + HANDLE_TYPE(LONG, long) + HANDLE_TYPE(ULONG, ulong) + HANDLE_TYPE(INT64, int64) + HANDLE_TYPE(UINT64, uint64) + HANDLE_TYPE(ENUM, enum) + HANDLE_TYPE(FLAGS, flags) + HANDLE_TYPE(FLOAT, float) + HANDLE_TYPE(DOUBLE, double) + default: + return; + } + + if(G_VALUE_TYPE(dest_value) == XFCONF_TYPE_UINT16) { + if(dest > USHRT_MAX) { + g_warning("Converting type \"%s\" to \"%s\" results in overflow", + G_VALUE_TYPE_NAME(src_value), + G_VALUE_TYPE_NAME(dest_value)); + } + xfconf_g_value_set_uint16(dest_value, (guint16)dest); + } else if(G_VALUE_TYPE(dest_value) == XFCONF_TYPE_INT16) { + if(dest > SHRT_MAX || dest < SHRT_MIN) { + g_warning("Converting type \"%s\" to \"%s\" results in overflow", + G_VALUE_TYPE_NAME(src_value), + G_VALUE_TYPE_NAME(dest_value)); + } + xfconf_g_value_set_int16(dest_value, (gint16)dest); + } +#undef HANDLE_TYPE +} + static void +short_from_gvalue(const GValue *src_value, + GValue *dest_value) +{ +#define HANDLE_TYPE(gtype_s, setter) \ + case G_TYPE_ ## gtype_s: \ + g_value_set_ ## setter(dest_value, src); \ + break; + + guint16 src; + gboolean is_signed = FALSE; + + if(G_VALUE_TYPE(src_value) == XFCONF_TYPE_UINT16) + src = xfconf_g_value_get_uint16(src_value); + else if(G_VALUE_TYPE(src_value) == XFCONF_TYPE_INT16) { + src = xfconf_g_value_get_int16(src_value); + is_signed = TRUE; + } else + return; + + switch(G_VALUE_TYPE(dest_value)) { + case G_TYPE_STRING: { + gchar *str = g_strdup_printf(is_signed ? "%d" : "%u", + is_signed ? (gint16)src : src); + g_value_set_string(dest_value, str); + g_free(str); + break; + } + case G_TYPE_BOOLEAN: + g_value_set_boolean(dest_value, src ? TRUE : FALSE); + break; + HANDLE_TYPE(CHAR, char) + HANDLE_TYPE(UCHAR, uchar) + HANDLE_TYPE(INT, int) + HANDLE_TYPE(UINT, uint) + HANDLE_TYPE(LONG, long) + HANDLE_TYPE(ULONG, ulong) + HANDLE_TYPE(INT64, int64) + HANDLE_TYPE(UINT64, uint64) + HANDLE_TYPE(ENUM, enum) + HANDLE_TYPE(FLAGS, flags) + HANDLE_TYPE(FLOAT, float) + HANDLE_TYPE(DOUBLE, double) + default: + return; + } +#undef HANDLE_TYPE +} + +static void +register_transforms(GType gtype) +{ + GType types[] = { + G_TYPE_CHAR, G_TYPE_UCHAR, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_UINT, + G_TYPE_LONG, G_TYPE_ULONG, G_TYPE_INT64, G_TYPE_UINT64, + G_TYPE_ENUM, G_TYPE_FLAGS, G_TYPE_FLOAT, G_TYPE_DOUBLE, + G_TYPE_STRING, G_TYPE_INVALID, + }; + gint i; + + for(i = 0; types[i] != G_TYPE_INVALID; ++i) { + g_value_register_transform_func(gtype, types[i], gvalue_from_short); + g_value_register_transform_func(types[i], gtype, short_from_gvalue); + } +} + +static void ushort_value_init(GValue *value) { value->data[0].v_int = 0; @@ -91,6 +212,7 @@ uint16_type = g_type_register_fundamental(g_type_fundamental_next(), "XfconfUint16", &info, &finfo, 0); + register_transforms(uint16_type); } return uint16_type; @@ -148,6 +270,7 @@ int16_type = g_type_register_fundamental(g_type_fundamental_next(), "XfconfInt16", &info, &finfo, 0); + register_transforms(int16_type); } return int16_type; Modified: xfconf/trunk/docs/spec/backend.txt =================================================================== --- xfconf/trunk/docs/spec/backend.txt 2008-04-20 07:38:50 UTC (rev 26873) +++ xfconf/trunk/docs/spec/backend.txt 2008-04-20 07:39:02 UTC (rev 26874) @@ -14,13 +14,11 @@ xfconf_channel_set_uint64()), users of the library can also set other, semi-arbitrary types, as well as array types. -So, the backend must, at minimum, be able to understand the following GTypes: +So, the backend must, be able to understand the following GTypes: G_TYPE_STRING G_TYPE_UCHAR G_TYPE_CHAR -XFCONF_TYPE_UINT16 -XFCONF_TYPE_INT16 G_TYPE_UINT G_TYPE_INT G_TYPE_UINT64 @@ -29,6 +27,12 @@ G_TYPE_DOUBLE G_TYPE_BOOLEAN +Note about 16-bit values: dbus-glib does not support sending 16-bit signed +and unsigned integers over D-Bus, even though libdbus does. For convenience, +libxfconf will take any 16-bit values it receives and convert them into +32-bit values before sending them to the daemon. From the daemon/backend +point of view, 16-bit values are simply not supported. + In addition, the backend must be able to handle arrays of arbitrary types from the above list. A single array may hold multiple values of the same type, or of different types. Because of this, an array is Modified: xfconf/trunk/docs/spec/perchannel-xml.txt =================================================================== --- xfconf/trunk/docs/spec/perchannel-xml.txt 2008-04-20 07:38:50 UTC (rev 26873) +++ xfconf/trunk/docs/spec/perchannel-xml.txt 2008-04-20 07:39:02 UTC (rev 26874) @@ -59,6 +59,9 @@ + type(string): The type of property. Must be one of: "string", "uchar", "char", "uint16", "int16", "uint", "int", "uint64", "int64", "float", "double", "bool", "array", or "empty" (required). + Note that due to a limitation in dbus-glib, uint16 and int16 aren't + actually used, but they are supported in the backend in case + support for 16-bit values becomes supported in the future. + value(string): The value of the property (required except for type="array" and type="empty"). + locked(userlist): A list of users/groups who cannot modify Modified: xfconf/trunk/xfconf/xfconf-channel.c =================================================================== --- xfconf/trunk/xfconf/xfconf-channel.c 2008-04-20 07:38:50 UTC (rev 26873) +++ xfconf/trunk/xfconf/xfconf-channel.c 2008-04-20 07:39:02 UTC (rev 26874) @@ -244,18 +244,84 @@ GValue *value) { DBusGProxy *proxy = _xfconf_get_dbus_g_proxy(); + GValue tmp_val = { 0, }, *val; gboolean ret; ERROR_DEFINE; + /* we support 2 ways of using this function: + * 1. |value| is unset, and we just take the property from xfconf + * and give it to the caller as-is, in the type xfconf gives + * 2. |value| is initialised, so we (try to) transform the value + * returned into the type the caller requested + */ + + if(G_VALUE_TYPE(value)) + val = &tmp_val; + else + val = value; + ret = xfconf_client_get_property(proxy, channel->channel_name, property, - value, ERROR); + val, ERROR); if(!ret) ERROR_CHECK; + if(ret && val == &tmp_val) { + if(!g_value_transform(val, value)) { + g_warning("Unable to tranform value of type \"%s\" to type \"%s\" for property %s", + G_VALUE_TYPE_NAME(val), G_VALUE_TYPE_NAME(value), + property); + g_value_unset(val); + return FALSE; + } + g_value_unset(val); + } + return ret; } +static GPtrArray * +xfconf_fixup_16bit_ints(GPtrArray *arr) +{ + GPtrArray *arr_new = NULL; + gint i; + for(i = 0; i < arr->len; ++i) { + GValue *v = g_ptr_array_index(arr, i); + + if(G_VALUE_TYPE(v) == XFCONF_TYPE_UINT16 + || G_VALUE_TYPE(v) == XFCONF_TYPE_INT16) + { + arr_new = g_ptr_array_sized_new(arr->len); + break; + } + } + + if(!arr_new) + return NULL; + + for(i = 0; i < arr->len; ++i) { + GValue *v_src, *v_dest; + + v_src = g_ptr_array_index(arr, i); + v_dest = g_new0(GValue, 1); + if(G_VALUE_TYPE(v_src) == XFCONF_TYPE_UINT16) { + g_value_init(v_dest, G_TYPE_UINT); + g_value_set_uint(v_dest, xfconf_g_value_get_uint16(v_src)); + } else if(G_VALUE_TYPE(v_src) == XFCONF_TYPE_INT16) { + g_value_init(v_dest, G_TYPE_INT); + g_value_set_int(v_dest, xfconf_g_value_get_int16(v_src)); + } else { + g_value_init(v_dest, G_VALUE_TYPE(v_src)); + g_value_copy(v_src, v_dest); + } + + g_ptr_array_add(arr_new, v_dest); + } + + return arr_new; +} + + /** * xfconf_channel_new: * @channel_name: A channel name. @@ -774,6 +840,13 @@ * Gets a property on @channel and stores it in @value. The caller is * responsible for calling g_value_unset() when finished with @value. * + * This function can be called with an initialized or uninitialized + * @value. If @value is initialized to a particular type, libxfconf + * will attempt to convert the value returned from the configuration + * store to that type if they don't match. If @value is uninitialized, + * The value in the configuration store will be returned in its native + * type. + * * Returns: %TRUE if the property was retrieved successfully, * %FALSE otherwise. **/ @@ -782,7 +855,7 @@ const gchar *property, GValue *value) { - GValue val1 = {0, }; + GValue val1 = { 0, }; gboolean ret; g_return_val_if_fail(XFCONF_IS_CHANNEL(channel) && property && value, @@ -818,17 +891,34 @@ const GValue *value) { DBusGProxy *proxy = _xfconf_get_dbus_g_proxy(); + GValue *val, tmp_val = { 0, }; gboolean ret; ERROR_DEFINE; g_return_val_if_fail(XFCONF_IS_CHANNEL(channel) && property && value, FALSE); + /* intercept uint16/int16 since dbus-glib doesn't know how to send + * them over the wire */ + if(G_VALUE_TYPE(value) == XFCONF_TYPE_UINT16) { + val = &tmp_val; + g_value_init(&tmp_val, G_TYPE_UINT); + g_value_set_uint(&tmp_val, xfconf_g_value_get_uint16(value)); + } else if(G_VALUE_TYPE(value) == XFCONF_TYPE_INT16) { + val = &tmp_val; + g_value_init(&tmp_val, G_TYPE_INT); + g_value_set_int(&tmp_val, xfconf_g_value_get_int16(value)); + } else + val = (GValue *)value; + ret = xfconf_client_set_property(proxy, channel->channel_name, property, - value, ERROR); + val, ERROR); if(!ret) ERROR_CHECK; + if(val == &tmp_val) + g_value_unset(&tmp_val); + return ret; } @@ -913,7 +1003,11 @@ val = g_ptr_array_index(arr, i); - if(G_VALUE_TYPE(val) != cur_value_type) { + /* special case: uint16/int16 are stored as uint/int */ + if(G_VALUE_TYPE(val) != cur_value_type + && !((G_VALUE_TYPE(val) == G_TYPE_UINT && cur_value_type == XFCONF_TYPE_UINT16) + || (G_VALUE_TYPE(val) == G_TYPE_INT && cur_value_type == XFCONF_TYPE_INT16))) + { #ifdef XFCONF_ENABLE_CHECKS g_warning("Value types don't match (%d != %d) at parameter %d", (int)G_VALUE_TYPE(val), (int)cur_value_type, i); @@ -948,11 +1042,13 @@ default: if(XFCONF_TYPE_UINT16 == cur_value_type) { + /* uint16 is stored as uint */ guint16 *__val_p = va_arg(var_args, guint16 *); - *__val_p = xfconf_g_value_get_uint16(val); + *__val_p = (guint16)g_value_get_uint(val); } else if(XFCONF_TYPE_INT16 == cur_value_type) { + /* int16 is stored as int */ gint16 *__val_p = va_arg(var_args, gint16 *); - *__val_p = xfconf_g_value_get_int16(val); + *__val_p = (gint16)g_value_get_int(val); } else if(G_TYPE_STRV == cur_value_type) { gchar ***__val_p = va_arg(var_args, gchar ***); *__val_p = g_value_dup_boxed(val); @@ -1129,16 +1225,18 @@ default: if(XFCONF_TYPE_UINT16 == cur_value_type) { + /* uint16 is stored as uint */ guint16 *__val = va_arg(var_args, guint16 *); val = g_new0(GValue, 1); - g_value_init(val, XFCONF_TYPE_UINT16); - xfconf_g_value_set_uint16(val, *__val); + g_value_init(val, G_TYPE_UINT); + g_value_set_uint(val, (guint)*__val); g_ptr_array_add(arr, val); } else if(XFCONF_TYPE_INT16 == cur_value_type) { + /* int16 is stored as int */ gint16 *__val = va_arg(var_args, gint16 *); val = g_new0(GValue, 1); - g_value_init(val, XFCONF_TYPE_INT16); - xfconf_g_value_set_int16(val, *__val); + g_value_init(val, G_TYPE_INT); + g_value_set_int(val, (gint)*__val); g_ptr_array_add(arr, val); } else if(G_TYPE_STRV == cur_value_type) { gchar **__val = va_arg(var_args, gchar **); @@ -1180,6 +1278,7 @@ GPtrArray *values) { DBusGProxy *proxy = _xfconf_get_dbus_g_proxy(); + GPtrArray *values_new = NULL; GValue val = { 0, }; gboolean ret; ERROR_DEFINE; @@ -1187,8 +1286,10 @@ g_return_val_if_fail(XFCONF_IS_CHANNEL(channel) && property && values, FALSE); + values_new = xfconf_fixup_16bit_ints(values); + g_value_init(&val, XFCONF_TYPE_G_VALUE_ARRAY); - g_value_set_static_boxed(&val, values); + g_value_set_static_boxed(&val, values_new ? values_new : values); ret = xfconf_client_set_property(proxy, channel->channel_name, property, &val, ERROR); @@ -1198,6 +1299,9 @@ g_value_unset(&val); + if(values_new) + xfconf_array_free(values_new); + return ret; } @@ -1486,11 +1590,13 @@ default: if(XFCONF_TYPE_UINT16 == member_types[i]) { - SET_STRUCT_VAL(guint16, XFCONF_TYPE_UINT16, - ALIGNOF_GUINT16, xfconf_g_value_get_uint16); + /* uint16 is stored as uint */ + SET_STRUCT_VAL(guint16, G_TYPE_UINT, + ALIGNOF_GUINT16, g_value_get_uint); } else if(XFCONF_TYPE_INT16 == member_types[i]) { - SET_STRUCT_VAL(gint16, XFCONF_TYPE_INT16, - ALIGNOF_GINT16, xfconf_g_value_get_int16); + /* int16 is stored as int */ + SET_STRUCT_VAL(gint16, G_TYPE_INT, + ALIGNOF_GINT16, g_value_get_int); } else { #ifdef XFCONF_ENABLE_CHECKS g_warning("Unable to handle value type %d (%s) when " \ @@ -1703,9 +1809,11 @@ default: if(XFCONF_TYPE_UINT16 == member_types[i]) { + /* _set_arrayv() will convert these */ GET_STRUCT_VAL(guint16, XFCONF_TYPE_UINT16, ALIGNOF_GUINT16, xfconf_g_value_set_uint16); } else if(XFCONF_TYPE_INT16 == member_types[i]) { + /* _set_arrayv() will convert these */ GET_STRUCT_VAL(gint16, XFCONF_TYPE_INT16, ALIGNOF_GINT16, xfconf_g_value_set_int16); } else { _______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org http://foo-projects.org/mailman/listinfo/xfce4-commits