diff options
-rw-r--r-- | dbus/dbus-binding-tool-glib.c | 48 | ||||
-rw-r--r-- | dbus/dbus-glib.h | 2 | ||||
-rw-r--r-- | dbus/dbus-gobject.c | 412 | ||||
-rw-r--r-- | test/core/Makefile.am | 4 | ||||
-rw-r--r-- | test/core/my-object.c | 853 | ||||
-rw-r--r-- | test/core/my-object.h | 118 | ||||
-rw-r--r-- | test/core/test-dbus-glib.c | 286 | ||||
-rw-r--r-- | test/core/test-service-glib.c | 832 | ||||
-rw-r--r-- | test/core/test-service-glib.xml | 7 |
9 files changed, 1664 insertions, 898 deletions
diff --git a/dbus/dbus-binding-tool-glib.c b/dbus/dbus-binding-tool-glib.c index adede27..7e280f6 100644 --- a/dbus/dbus-binding-tool-glib.c +++ b/dbus/dbus-binding-tool-glib.c @@ -38,6 +38,10 @@ #include <string.h> #include <unistd.h> +/* Remember to grep for ->format_version in the code if you change this, + * most changes should be in dbus-gobject.c. */ +#define FORMAT_VERSION 1 + #define MARSHAL_PREFIX "dbus_glib_marshal_" typedef struct @@ -489,10 +493,9 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) /* Information about the object. */ - if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n", - channel, error, data->prefix)) - goto io_lose; - WRITE_OR_LOSE (" 0,\n"); + if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = { %d,\n", + channel, error, data->prefix, FORMAT_VERSION)) + goto io_lose; if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, data->prefix)) goto io_lose; if (!write_printf_to_iochannel (" %d,\n", channel, error, data->count)) @@ -736,13 +739,36 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) for (tmp = properties; tmp != NULL; tmp = g_slist_next (tmp)) { PropertyInfo *prop; - - prop = tmp->data; - - g_string_append (data->property_blob, interface_info_get_name (interface)); - g_string_append_c (data->property_blob, '\0'); - g_string_append (data->property_blob, property_info_get_name (prop)); - g_string_append_c (data->property_blob, '\0'); + PropertyAccessFlags access_flags; + const char *access_string; + char *uscored; + + prop = tmp->data; + + access_flags = property_info_get_access (prop); + if ((access_flags & PROPERTY_READ) && (access_flags & PROPERTY_WRITE)) + access_string = "readwrite"; + else if (access_flags & PROPERTY_READ) + access_string = "read"; + else if (access_flags & PROPERTY_WRITE) + access_string = "write"; + else + continue; + + /* We append both in the blob so we have to malloc() less when processing + * properties */ + uscored = _dbus_gutils_wincaps_to_uscore (property_info_get_name (prop)); + + g_string_append (data->property_blob, interface_info_get_name (interface)); + g_string_append_c (data->property_blob, '\0'); + g_string_append (data->property_blob, property_info_get_name (prop)); + g_string_append_c (data->property_blob, '\0'); + g_string_append (data->property_blob, uscored); + g_string_append_c (data->property_blob, '\0'); + g_string_append (data->property_blob, access_string); + g_string_append_c (data->property_blob, '\0'); + + g_free (uscored); } } return TRUE; diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h index 664e89f..a3a3597 100644 --- a/dbus/dbus-glib.h +++ b/dbus/dbus-glib.h @@ -150,6 +150,8 @@ struct _DBusGObjectInfo const char *exported_properties; }; +void dbus_glib_global_set_disable_legacy_property_access (void); + void dbus_g_object_type_install_info (GType object_type, const DBusGObjectInfo *info); diff --git a/dbus/dbus-gobject.c b/dbus/dbus-gobject.c index ec93ad4..1755f2c 100644 --- a/dbus/dbus-gobject.c +++ b/dbus/dbus-gobject.c @@ -42,9 +42,28 @@ typedef struct } DBusGErrorInfo; static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT; +/* See comments in check_property_access */ +static gboolean disable_legacy_property_access = FALSE; static GHashTable *marshal_table = NULL; static GData *error_metadata = NULL; +/* Ugly yes - but we have to accept strings from both formats */ +static gboolean +compare_strings_ignoring_uscore_vs_dash (const char *a, const char *b) +{ + guint i; + + for (i = 0; a[i] && b[i]; i++) + { + if ((a[i] == '-' && b[i] == '_') + || (a[i] == '_' && b[i] == '-')) + continue; + if (a[i] != b[i]) + return FALSE; + } + return (a[i] == '\0') && (b[i] == '\0'); +} + static char* uscore_to_wincaps (const char *uscore) { @@ -270,7 +289,7 @@ method_output_signature_from_object_info (const DBusGObjectInfo *object, } static const char * -propsig_iterate (const char *data, const char **iface, const char **name) +signal_iterate (const char *data, const char **iface, const char **name) { *iface = data; @@ -280,6 +299,108 @@ propsig_iterate (const char *data, const char **iface, const char **name) return string_table_next (data); } +static const char * +property_iterate (const char *data, + int format_version, + const char **iface, + const char **exported_name, + const char **name_uscored, + const char **access_type) +{ + *iface = data; + + data = string_table_next (data); + *exported_name = data; + + data = string_table_next (data); + if (format_version == 1) + { + *name_uscored = data; + data = string_table_next (data); + *access_type = data; + return string_table_next (data); + } + else + { + /* This tells the caller they need to compute it */ + *name_uscored = NULL; + /* We don't know here, however note that we will still check against the + * readable/writable flags from GObject's metadata. + */ + *access_type = "readwrite"; + return data; + } +} + +/** + * property_info_from_object_info: + * @object: introspection data + * @interface_name: (allow-none): Expected interface name, or %NULL for any + * @property_name: Expected property name (can use "-" or "_" as separator) + * @access_type: (out): Can be one of "read", "write", "readwrite" + * + * Look up property introspection data for the given interface/name pair. + * + * Returns: %TRUE if property was found + */ +static gboolean +property_info_from_object_info (const DBusGObjectInfo *object, + const char *interface_name, + const char *property_name, + const char **access_type) +{ + const char *properties_iter; + + properties_iter = object->exported_properties; + while (properties_iter != NULL && *properties_iter) + { + const char *cur_interface_name; + const char *cur_property_name; + const char *cur_uscore_property_name; + const char *cur_access_type; + + + properties_iter = property_iterate (properties_iter, object->format_version, + &cur_interface_name, &cur_property_name, + &cur_uscore_property_name, &cur_access_type); + + if (interface_name && strcmp (interface_name, cur_interface_name) != 0) + continue; + + /* This big pile of ugly is necessary to support the matrix resulting from multiplying + * (v0 data, v1 data) * (FooBar, foo-bar) + * In v1 data we have both forms of string, so we do a comparison against both without + * having to malloc. + * For v0 data, we need to reconstruct the foo-bar form. + * + * Adding to the complexity is that we *also* have to ignore the distinction between + * '-' and '_', because g_object_{get,set} does. + */ + /* First, compare against the primary property name - no malloc required */ + if (!compare_strings_ignoring_uscore_vs_dash (property_name, cur_property_name)) + { + if (cur_uscore_property_name != NULL + && !compare_strings_ignoring_uscore_vs_dash (property_name, cur_uscore_property_name)) + continue; + else + { + /* v0 metadata, construct uscore */ + char *tmp_uscored; + gboolean matches; + tmp_uscored = _dbus_gutils_wincaps_to_uscore (cur_property_name); + matches = compare_strings_ignoring_uscore_vs_dash (property_name, tmp_uscored); + g_free (tmp_uscored); + if (!matches) + continue; + } + } + + *access_type = cur_access_type; + return TRUE; + } + return FALSE; +} + static GQuark dbus_g_object_type_dbus_metadata_quark (void) { @@ -290,11 +411,17 @@ dbus_g_object_type_dbus_metadata_quark (void) return quark; } -static GList * -lookup_object_info (GObject *object) +/* Iterator function should return FALSE to stop iteration, TRUE to continue */ +typedef gboolean (*ForeachObjectInfoFn) (const DBusGObjectInfo *info, + GType gtype, + gpointer user_data); + +static void +foreach_object_info (GObject *object, + ForeachObjectInfoFn callback, + gpointer user_data) { GType *interfaces, *p; - GList *info_list = NULL; const DBusGObjectInfo *info; GType classtype; @@ -304,7 +431,10 @@ lookup_object_info (GObject *object) { info = g_type_get_qdata (*p, dbus_g_object_type_dbus_metadata_quark ()); if (info != NULL && info->format_version >= 0) - info_list = g_list_prepend (info_list, (gpointer) info); + { + if (!callback (info, *p, user_data)) + break; + } } g_free (interfaces); @@ -313,16 +443,85 @@ lookup_object_info (GObject *object) { info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ()); if (info != NULL && info->format_version >= 0) - info_list = g_list_prepend (info_list, (gpointer) info); + { + if (!callback (info, classtype, user_data)) + break; + } } - /* if needed only: - return g_list_reverse (info_list); - */ - +} + +static gboolean +lookup_object_info_cb (const DBusGObjectInfo *info, + GType gtype, + gpointer user_data) +{ + GList **list = (GList **) user_data; + + *list = g_list_prepend (*list, (gpointer) info); + return TRUE; +} + +static GList * +lookup_object_info (GObject *object) +{ + GList *info_list = NULL; + + foreach_object_info (object, lookup_object_info_cb, &info_list); + return info_list; } +typedef struct { + const char *iface; + const DBusGObjectInfo *info; + gboolean fallback; + GType iface_type; +} LookupObjectInfoByIfaceData; + +static gboolean +lookup_object_info_by_iface_cb (const DBusGObjectInfo *info, + GType gtype, + gpointer user_data) +{ + LookupObjectInfoByIfaceData *lookup_data = (LookupObjectInfoByIfaceData *) user_data; + + /* If interface is not specified, choose the first info */ + if (lookup_data->fallback && (!lookup_data->iface || strlen (lookup_data->iface) == 0)) + { + lookup_data->info = info; + lookup_data->iface_type = gtype; + } + else if (info->exported_properties && !strcmp (info->exported_properties, lookup_data->iface)) + { + lookup_data->info = info; + lookup_data->iface_type = gtype; + } + + return !lookup_data->info; +} + +static const DBusGObjectInfo * +lookup_object_info_by_iface (GObject *object, + const char *iface, + gboolean fallback, + GType *out_iface_type) +{ + LookupObjectInfoByIfaceData data; + + data.iface = iface; + data.info = NULL; + data.fallback = fallback; + data.iface_type = 0; + + foreach_object_info (object, lookup_object_info_by_iface_cb, &data); + + if (out_iface_type && data.info) + *out_iface_type = data.iface_type; + + return data.info; +} + static void gobject_unregister_function (DBusConnection *connection, void *user_data) @@ -443,30 +642,41 @@ write_interface (gpointer key, gpointer val, gpointer user_data) for (; properties; properties = properties->next) { + const char *iface; const char *propname; + const char *propname_uscore; + const char *access_type; GParamSpec *spec; char *dbus_type; gboolean can_set; gboolean can_get; char *s; - propname = properties->data; spec = NULL; - s = _dbus_gutils_wincaps_to_uscore (propname); + property_iterate (properties->data, object_info->format_version, &iface, &propname, &propname_uscore, &access_type); - spec = g_object_class_find_property (g_type_class_peek (data->gtype), s); + if (!propname_uscore) + { + char *s = _dbus_gutils_wincaps_to_uscore (propname); + spec = g_object_class_find_property (g_type_class_peek (data->gtype), s); + g_free (s); + } + else + { + spec = g_object_class_find_property (g_type_class_peek (data->gtype), propname_uscore); + } g_assert (spec != NULL); - g_free (s); - + dbus_type = _dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec)); g_assert (dbus_type != NULL); - - can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 && - (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); - + + can_set = strcmp (access_type, "readwrite") == 0 + && ((spec->flags & G_PARAM_WRITABLE) != 0 + && (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); + can_get = (spec->flags & G_PARAM_READABLE) != 0; - + if (can_set || can_get) { g_string_append_printf (xml, " <property name=\"%s\" ", propname); @@ -486,10 +696,8 @@ write_interface (gpointer key, gpointer val, gpointer user_data) g_string_append (xml, "\"/>\n"); } - - g_free (dbus_type); - g_string_append (xml, " </property>\n"); + g_free (dbus_type); } g_slist_free (values->properties); @@ -556,7 +764,7 @@ introspect_interfaces (GObject *object, GString *xml) const char *iface; const char *signame; - propsig = propsig_iterate (propsig, &iface, &signame); + propsig = signal_iterate (propsig, &iface, &signame); values = lookup_values (interfaces, iface); values->signals = g_slist_prepend (values->signals, (gpointer) signame); @@ -567,13 +775,15 @@ introspect_interfaces (GObject *object, GString *xml) { const char *iface; const char *propname; + const char *propname_uscore; + const char *access_type; - propsig = propsig_iterate (propsig, &iface, &propname); + propsig = property_iterate (propsig, info->format_version, &iface, &propname, &propname_uscore, &access_type); values = lookup_values (interfaces, iface); - values->properties = g_slist_prepend (values->properties, (gpointer) propname); + values->properties = g_slist_prepend (values->properties, (gpointer)iface); } - + memset (&data, 0, sizeof (data)); data.xml = xml; data.gtype = G_TYPE_FROM_INSTANCE (object); @@ -1271,6 +1481,70 @@ invoke_object_method (GObject *object, goto done; } +static gboolean +check_property_access (DBusConnection *connection, + DBusMessage *message, + GObject *object, + const char *wincaps_propiface, + const char *requested_propname, + const char *uscore_propname, + gboolean is_set) +{ + const DBusGObjectInfo *object_info; + const char *access_type; + DBusMessage *ret; + + if (!is_set && !disable_legacy_property_access) + return TRUE; + + object_info = lookup_object_info_by_iface (object, wincaps_propiface, TRUE, NULL); + if (!object_info) + { + ret = dbus_message_new_error_printf (message, + DBUS_ERROR_ACCESS_DENIED, + "Interface \"%s\" isn't exported (or may not exist), can't access property \"%s\"", + wincaps_propiface, + requested_propname); + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + return FALSE; + } + + /* Try both forms of property names: "foo_bar" or "FooBar"; for historical + * reasons we accept both. + */ + if (object_info + && !(property_info_from_object_info (object_info, wincaps_propiface, requested_propname, &access_type) + || property_info_from_object_info (object_info, wincaps_propiface, uscore_propname, &access_type))) + { + ret = dbus_message_new_error_printf (message, + DBUS_ERROR_ACCESS_DENIED, + "Property \"%s\" of interface \"%s\" isn't exported (or may not exist)", + requested_propname, + wincaps_propiface); + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + return FALSE; + } + + if (strcmp (access_type, "readwrite") == 0) + return TRUE; + else if (is_set ? strcmp (access_type, "read") == 0 + : strcmp (access_type, "write") == 0) + { + ret = dbus_message_new_error_printf (message, + DBUS_ERROR_ACCESS_DENIED, + "Property \"%s\" of interface \"%s\" is not %s", + requested_propname, + wincaps_propiface, + is_set ? "settable" : "readable"); + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + return FALSE; + } + return TRUE; +} + static DBusHandlerResult gobject_message_function (DBusConnection *connection, DBusMessage *message, @@ -1281,8 +1555,8 @@ gobject_message_function (DBusConnection *connection, gboolean setter; gboolean getter; char *s; - const char *wincaps_propname; - /* const char *wincaps_propiface; */ + const char *requested_propname; + const char *wincaps_propiface; DBusMessageIter iter; const DBusGMethodInfo *method; const DBusGObjectInfo *object_info; @@ -1299,7 +1573,8 @@ gobject_message_function (DBusConnection *connection, return invoke_object_method (object, object_info, method, connection, message); /* If no metainfo, we can still do properties and signals - * via standard GLib introspection + * via standard GLib introspection. Note we do now check + * property access against the metainfo if available. */ getter = FALSE; setter = FALSE; @@ -1322,10 +1597,8 @@ gobject_message_function (DBusConnection *connection, g_warning ("Property get or set does not have an interface string as first arg\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - /* We never use the interface name; if we did, we'd need to - * remember that it can be empty string for "pick one for me" - */ - /* dbus_message_iter_get_basic (&iter, &wincaps_propiface); */ + + dbus_message_iter_get_basic (&iter, &wincaps_propiface); dbus_message_iter_next (&iter); if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) @@ -1333,13 +1606,19 @@ gobject_message_function (DBusConnection *connection, g_warning ("Property get or set does not have a property name string as second arg\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - dbus_message_iter_get_basic (&iter, &wincaps_propname); + + dbus_message_iter_get_basic (&iter, &requested_propname); dbus_message_iter_next (&iter); - - s = _dbus_gutils_wincaps_to_uscore (wincaps_propname); - pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), - s); + s = _dbus_gutils_wincaps_to_uscore (requested_propname); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), s); + + if (!check_property_access (connection, message, object, wincaps_propiface, requested_propname, s, setter)) + { + g_free (s); + return DBUS_HANDLER_RESULT_HANDLED; + } g_free (s); @@ -1364,11 +1643,6 @@ gobject_message_function (DBusConnection *connection, ret = get_object_property (connection, message, object, pspec); } - else - { - g_assert_not_reached (); - ret = NULL; - } g_assert (ret != NULL); @@ -1379,6 +1653,16 @@ gobject_message_function (DBusConnection *connection, dbus_message_unref (ret); return DBUS_HANDLER_RESULT_HANDLED; } + else + { + DBusMessage *ret; + + ret = dbus_message_new_error_printf (message, + DBUS_ERROR_INVALID_ARGS, + "No such property %s", requested_propname); + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1497,8 +1781,8 @@ export_signals (DBusGConnection *connection, const GList *info_list, GObject *ob GClosure *closure; char *s; - sigdata = propsig_iterate (sigdata, &iface, &signame); - + sigdata = signal_iterate (sigdata, &iface, &signame); + s = _dbus_gutils_wincaps_to_uscore (signame); id = g_signal_lookup (s, gtype); @@ -1657,6 +1941,32 @@ dbus_g_error_info_free (gpointer p) */ /** + * dbus_glib_global_set_disable_legacy_property_access: + * + * Historically, DBus-GLib allowed read/write access to any property + * regardless of the access flags specified in the introspection XML, + * and regardless of the DBus interface given. + * + * As of version 0.88, DBus-GLib by default allows read-only access to + * every GObject property of an object exported to the bus, regardless + * of whether or not the property is listed in the type info installed + * with dbus_g_object_type_install_info() and regardless of whether + * the correct interface is specified. Write access is denied. + * + * After calling this method, it will be required that the property is + * exported on the given interface, and even read-only access will be + * checked. This method changes behavior globally for the entire + * process. + * + * Since: 0.88 + */ +void +dbus_glib_global_set_disable_legacy_property_access (void) +{ + disable_legacy_property_access = TRUE; +} + +/** * dbus_g_object_type_install_info: * @object_type: #GType for the object * @info: introspection data generated by #dbus-glib-tool @@ -2310,23 +2620,23 @@ _dbus_gobject_test (const char *test_data_dir) sigdata = dbus_glib_internal_test_object_info.exported_signals; g_assert (*sigdata != '\0'); - sigdata = propsig_iterate (sigdata, &iface, &signame); + sigdata = signal_iterate (sigdata, &iface, &signame); g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.MyObject")); g_assert (!strcmp (signame, "Frobnicate")); g_assert (*sigdata != '\0'); - sigdata = propsig_iterate (sigdata, &iface, &signame); + sigdata = signal_iterate (sigdata, &iface, &signame); g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject")); g_assert (!strcmp (signame, "Sig0")); g_assert (*sigdata != '\0'); - sigdata = propsig_iterate (sigdata, &iface, &signame); + sigdata = signal_iterate (sigdata, &iface, &signame); g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject")); g_assert (!strcmp (signame, "Sig1")); g_assert (*sigdata != '\0'); - sigdata = propsig_iterate (sigdata, &iface, &signame); + sigdata = signal_iterate (sigdata, &iface, &signame); g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject")); g_assert (!strcmp (signame, "Sig2")); g_assert (*sigdata == '\0'); - + i = 0; while (i < (int) G_N_ELEMENTS (name_pairs)) diff --git a/test/core/Makefile.am b/test/core/Makefile.am index 7ffda78..6216afe 100644 --- a/test/core/Makefile.am +++ b/test/core/Makefile.am @@ -50,7 +50,9 @@ BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h my-object- test_service_glib_SOURCES= \ my-object-marshal.c \ - test-service-glib.c + my-object.c \ + my-object.h \ + test-service-glib.c test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/dbus/dbus-binding-tool $(top_builddir)/dbus/dbus-binding-tool --prefix=my_object --mode=glib-server --output=test-service-glib-glue.h $(srcdir)/test-service-glib.xml diff --git a/test/core/my-object.c b/test/core/my-object.c new file mode 100644 index 0000000..a633b05 --- /dev/null +++ b/test/core/my-object.c @@ -0,0 +1,853 @@ +#include <config.h> +#include <string.h> +#include <glib/gi18n.h> +#include <glib-object.h> +#include "my-object.h" +#include "my-object-marshal.h" + +#include "test-service-glib-glue.h" + +/* Properties */ +enum +{ + PROP_0, + PROP_THIS_IS_A_STRING, + PROP_NO_TOUCHING, + PROP_SUPER_STUDLY, + PROP_SHOULD_BE_HIDDEN +}; + +enum +{ + FROBNICATE, + SIG0, + SIG1, + SIG2, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(MyObject, my_object, G_TYPE_OBJECT) + +static void +my_object_finalize (GObject *object) +{ + MyObject *mobject = MY_OBJECT (object); + + g_free (mobject->this_is_a_string); + + (G_OBJECT_CLASS (my_object_parent_class)->finalize) (object); +} + +static void +my_object_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MyObject *mobject; + + mobject = MY_OBJECT (object); + + switch (prop_id) + { + case PROP_THIS_IS_A_STRING: + g_free (mobject->this_is_a_string); + mobject->this_is_a_string = g_value_dup_string (value); + break; + + case PROP_NO_TOUCHING: + mobject->notouching = g_value_get_uint (value); + break; + + case PROP_SUPER_STUDLY: + mobject->super_studly = g_value_get_double (value); + break; + + case PROP_SHOULD_BE_HIDDEN: + mobject->should_be_hidden = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +my_object_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MyObject *mobject; + + mobject = MY_OBJECT (object); + + switch (prop_id) + { + case PROP_THIS_IS_A_STRING: + g_value_set_string (value, mobject->this_is_a_string); + break; + + case PROP_NO_TOUCHING: + g_value_set_uint (value, mobject->notouching); + break; + + case PROP_SUPER_STUDLY: + g_value_set_double (value, mobject->super_studly); + break; + + case PROP_SHOULD_BE_HIDDEN: + g_value_set_boolean (value, mobject->should_be_hidden); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +my_object_init (MyObject *obj) +{ + obj->val = 0; + obj->notouching = 42; +} + +static void +my_object_class_init (MyObjectClass *mobject_class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (mobject_class); + + dbus_g_object_type_install_info (MY_TYPE_OBJECT, + &dbus_glib_my_object_object_info); + + gobject_class->finalize = my_object_finalize; + gobject_class->set_property = my_object_set_property; + gobject_class->get_property = my_object_get_property; + + g_object_class_install_property (gobject_class, + PROP_THIS_IS_A_STRING, + g_param_spec_string ("this_is_a_string", + _("Sample string"), + _("Example of a string property"), + "default value", + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_NO_TOUCHING, + g_param_spec_uint ("no_touching", + _("Don't touch"), + _("Example of a readonly property (for export)"), + 0, 100, 42, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_SUPER_STUDLY, + g_param_spec_double ("super-studly", + _("In Studly Caps"), + _("Example of a StudlyCaps property"), + 0, 256, 128, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_SHOULD_BE_HIDDEN, + g_param_spec_boolean ("should-be-hidden", + _("A non-exported property"), + _("Example of a property we don't want exported"), + FALSE, + G_PARAM_READWRITE)); + + signals[FROBNICATE] = + g_signal_new ("frobnicate", + G_OBJECT_CLASS_TYPE (mobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + + signals[SIG0] = + g_signal_new ("sig0", + G_OBJECT_CLASS_TYPE (mobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + my_object_marshal_VOID__STRING_INT_STRING, + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING); + + signals[SIG1] = + g_signal_new ("sig1", + G_OBJECT_CLASS_TYPE (mobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + my_object_marshal_VOID__STRING_BOXED, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VALUE); + + signals[SIG2] = + g_signal_new ("sig2", + G_OBJECT_CLASS_TYPE (mobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, DBUS_TYPE_G_STRING_STRING_HASHTABLE); +} + +GQuark +my_object_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("my_object_error"); + + return quark; +} + +/* This should really be standard. */ +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GType +my_object_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) + { + static const GEnumValue values[] = + { + + ENUM_ENTRY (MY_OBJECT_ERROR_FOO, "Foo"), + ENUM_ENTRY (MY_OBJECT_ERROR_BAR, "Bar"), + ENUM_ENTRY (MY_OBJECT_ERROR_MULTI_WORD, "Multi-word"), + { 0, 0, 0 } + }; + + etype = g_enum_register_static ("MyObjectError", values); + } + + return etype; +} + +gboolean +my_object_do_nothing (MyObject *obj, GError **error) +{ + return TRUE; +} + +gboolean +my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error) +{ + *ret = x +1; + return TRUE; +} + +gint32 +my_object_increment_retval (MyObject *obj, gint32 x) +{ + return x + 1; +} + +gint32 +my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error) +{ + if (x + 1 > 10) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "%s", + "x is bigger than 9"); + return FALSE; + } + return x + 1; +} + +gboolean +my_object_throw_error (MyObject *obj, GError **error) +{ + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "%s", + "this method always loses"); + return FALSE; +} + +gboolean +my_object_throw_not_supported (MyObject *obj, GError **error) +{ + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_NOT_SUPPORTED, + "%s", + "this method always loses"); + return FALSE; +} + +gboolean +my_object_throw_error_multi_word (MyObject *obj, GError **error) +{ + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_MULTI_WORD, + "%s", + "this method's error has a hyphen"); + return FALSE; +} + +gboolean +my_object_throw_unregistered_error (MyObject *obj, GError **error) +{ + /* Unregistered errors shouldn't cause a dbus abort. See + * https://bugzilla.redhat.com/show_bug.cgi?id=581794 + */ + g_set_error (error, 0, 0, + "%s", + "this method always loses more"); + return FALSE; +} + + +gboolean +my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error) +{ + *ret = g_ascii_strup (str, -1); + return TRUE; +} + +gboolean +my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error) +{ + *d_ret = trouble + (x * 2); + *str_ret = g_ascii_strup (str, -1); + return TRUE; +} + +gboolean +my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, const char **arg5, GError **error) +{ + *arg0 = 42; + *arg1 = g_strdup ("42"); + *arg2 = -67; + *arg3 = 2; + *arg4 = 26; + *arg5 = "hello world"; /* Annotation specifies as const */ + return TRUE; +} + +gboolean +my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error) +{ + GValue valstr = {0, }; + + g_value_init (&valstr, G_TYPE_STRING); + if (!g_value_transform (value, &valstr)) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "couldn't transform value"); + return FALSE; + } + *ret = g_value_dup_string (&valstr); + g_value_unset (&valstr); + return TRUE; +} + +gboolean +my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error) +{ + if (str[0] == '\0' || !g_ascii_isdigit (str[0])) { + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, str); + } else { + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, (int) g_ascii_strtoull (str, NULL, 10)); + } + return TRUE; +} + +gboolean +my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error) +{ + *len_ret = array->len; + return TRUE; +} + +gboolean +my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **ret, GError **error) +{ + guint32 val; + GArray *array; + + array = g_array_new (FALSE, TRUE, sizeof (guint32)); + + while (reqlen > 0) { + val = 42; + g_array_append_val (array, val); + val = 26; + g_array_append_val (array, val); + reqlen--; + } + val = 2; + g_array_append_val (array, val); + *ret = array; + return TRUE; +} + +gboolean +my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error) +{ + int len; + int i; + + len = g_strv_length ((char**) in); + + *out = g_new0 (char *, len + 1); + for (i = 0; i < len; i++) + { + (*out)[i] = g_ascii_strup (in[i], -1); + } + (*out)[i] = NULL; + + return TRUE; +} + +static void +hash_foreach_stringify (gpointer key, gpointer val, gpointer user_data) +{ + const char *keystr = key; + const GValue *value = val; + GValue *sval; + GHashTable *ret = user_data; + + sval = g_new0 (GValue, 1); + g_value_init (sval, G_TYPE_STRING); + if (!g_value_transform (value, sval)) + g_assert_not_reached (); + + g_hash_table_insert (ret, g_strdup (keystr), sval); +} + +static void +unset_and_free_gvalue (gpointer val) +{ + g_value_unset (val); + g_free (val); +} + +gboolean +my_object_many_stringify (MyObject *obj, GHashTable /* char * -> GValue * */ *vals, GHashTable /* char * -> GValue * */ **ret, GError **error) +{ + *ret = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, unset_and_free_gvalue); + g_hash_table_foreach (vals, hash_foreach_stringify, *ret); + return TRUE; +} + +gboolean +my_object_rec_arrays (MyObject *obj, GPtrArray *in, GPtrArray **ret, GError **error) +{ + char **strs; + GArray *ints; + guint v_UINT; + + if (in->len != 2) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid array len"); + return FALSE; + } + + strs = g_ptr_array_index (in, 0); + if (!*strs || strcmp (*strs, "foo")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 0"); + return FALSE; + } + strs++; + if (!*strs || strcmp (*strs, "bar")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 1"); + return FALSE; + } + strs++; + if (*strs) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string array len in pos 0"); + return FALSE; + } + strs = g_ptr_array_index (in, 1); + if (!*strs || strcmp (*strs, "baz")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 0"); + return FALSE; + } + strs++; + if (!*strs || strcmp (*strs, "whee")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 1"); + return FALSE; + } + strs++; + if (!*strs || strcmp (*strs, "moo")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 2"); + return FALSE; + } + strs++; + if (*strs) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string array len in pos 1"); + return FALSE; + } + + *ret = g_ptr_array_new (); + + ints = g_array_new (TRUE, TRUE, sizeof (guint)); + v_UINT = 10; + g_array_append_val (ints, v_UINT); + v_UINT = 42; + g_array_append_val (ints, v_UINT); + v_UINT = 27; + g_array_append_val (ints, v_UINT); + g_ptr_array_add (*ret, ints); + + ints = g_array_new (TRUE, TRUE, sizeof (guint)); + v_UINT = 30; + g_array_append_val (ints, v_UINT); + g_ptr_array_add (*ret, ints); + return TRUE; +} + +gboolean +my_object_objpath (MyObject *obj, const char *incoming, const char **outgoing, GError **error) +{ + if (strcmp (incoming, "/org/freedesktop/DBus/GLib/Tests/MyTestObject")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid incoming object"); + return FALSE; + } + *outgoing = "/org/freedesktop/DBus/GLib/Tests/MyTestObject2"; + return TRUE; +} + +gboolean +my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error) +{ + *objs = g_ptr_array_new (); + + g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject")); + g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject2")); + + return TRUE; +} + +static void +hash_foreach (gpointer key, gpointer val, gpointer user_data) +{ + const char *keystr = key; + const char *valstr = val; + guint *count = user_data; + + *count += (strlen (keystr) + strlen (valstr)); + g_print ("%s -> %s\n", keystr, valstr); +} + +gboolean +my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error) +{ + *len = 0; + g_hash_table_foreach (table, hash_foreach, len); + return TRUE; +} + +gboolean +my_object_send_car (MyObject *obj, GValueArray *invals, GValueArray **outvals, GError **error) +{ + if (invals->n_values != 3 + || G_VALUE_TYPE (g_value_array_get_nth (invals, 0)) != G_TYPE_STRING + || G_VALUE_TYPE (g_value_array_get_nth (invals, 1)) != G_TYPE_UINT + || G_VALUE_TYPE (g_value_array_get_nth (invals, 2)) != G_TYPE_VALUE) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid incoming values"); + return FALSE; + } + *outvals = g_value_array_new (2); + g_value_array_append (*outvals, NULL); + g_value_init (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), G_TYPE_UINT); + g_value_set_uint (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), + g_value_get_uint (g_value_array_get_nth (invals, 1)) + 1); + g_value_array_append (*outvals, NULL); + g_value_init (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), DBUS_TYPE_G_OBJECT_PATH); + g_value_set_boxed (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), + g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject2")); + return TRUE; +} + +gboolean +my_object_get_hash (MyObject *obj, GHashTable **ret, GError **error) +{ + GHashTable *table; + + table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (table, "foo", "bar"); + g_hash_table_insert (table, "baz", "whee"); + g_hash_table_insert (table, "cow", "crack"); + *ret = table; + return TRUE; +} + +gboolean +my_object_increment_val (MyObject *obj, GError **error) +{ + obj->val++; + return TRUE; +} + +gboolean +my_object_get_val (MyObject *obj, guint *ret, GError **error) +{ + *ret = obj->val; + return TRUE; +} + +gboolean +my_object_get_value (MyObject *obj, guint *ret, GError **error) +{ + *ret = obj->val; + return TRUE; +} + +gboolean +my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **error) +{ + GType t; + t = G_VALUE_TYPE(variant); + g_value_init (ret, t); + g_value_copy (variant, ret); + + return TRUE; +} + +gboolean +my_object_echo_signature (MyObject *obj, const gchar *in, gchar **out, GError **error) +{ + *out = g_strdup (in); + return TRUE; +} + +gboolean +my_object_process_variant_of_array_of_ints123 (MyObject *obj, GValue *variant, GError **error) +{ + GArray *array; + int i; + int j; + + j = 0; + + array = (GArray *)g_value_get_boxed (variant); + + for (i = 0; i <= 2; i++) + { + j = g_array_index (array, int, i); + if (j != i + 1) + goto error; + } + + return TRUE; + +error: + *error = g_error_new (MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "Error decoding a variant of type ai (i + 1 = %i, j = %i)", + i, j + 1); + return FALSE; +} + + +typedef struct _HashAndString HashAndString; + +struct _HashAndString +{ + GHashTable *hash; + gchar* string; +}; + +static void +hash_foreach_prepend_string (gpointer key, gpointer val, gpointer user_data) +{ + HashAndString *data = (HashAndString*) user_data; + gchar *in = (gchar*) val; + g_hash_table_insert (data->hash, g_strdup ((gchar*) key), + g_strjoin (" ", data->string, in, NULL)); +} + + +static void +hash_foreach_mangle_dict_of_strings (gpointer key, gpointer val, gpointer user_data) +{ + GHashTable *out = (GHashTable*) user_data; + GHashTable *in_dict = (GHashTable *) val; + HashAndString *data = g_new0 (HashAndString, 1); + + data->string = (gchar*) key; + data->hash = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + g_hash_table_foreach (in_dict, hash_foreach_prepend_string, data); + + g_hash_table_insert(out, g_strdup ((gchar*) key), data->hash); +} + +gboolean +my_object_dict_of_dicts (MyObject *obj, GHashTable *in, + GHashTable **out, GError **error) +{ + *out = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_hash_table_destroy); + g_hash_table_foreach (in, hash_foreach_mangle_dict_of_strings, *out); + return TRUE; +} + +void +my_object_dict_of_sigs (MyObject *obj, + GHashTable *dict, + DBusGMethodInvocation *context) +{ + dbus_g_method_return (context, dict); +} + +void +my_object_dict_of_objs (MyObject *obj, + GHashTable *dict, + DBusGMethodInvocation *context) +{ + dbus_g_method_return (context, dict); +} + +gboolean +my_object_emit_frobnicate (MyObject *obj, GError **error) +{ + g_signal_emit (obj, signals[FROBNICATE], 0, 42); + return TRUE; +} + +gboolean +my_object_emit_signals (MyObject *obj, GError **error) +{ + GValue val = {0, }; + + g_signal_emit (obj, signals[SIG0], 0, "foo", 22, "moo"); + + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, "bar"); + g_signal_emit (obj, signals[SIG1], 0, "baz", &val); + g_value_unset (&val); + + return TRUE; +} + +gboolean +my_object_emit_signal2 (MyObject *obj, GError **error) +{ + GHashTable *table; + + table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (table, "baz", "cow"); + g_hash_table_insert (table, "bar", "foo"); + g_signal_emit (obj, signals[SIG2], 0, table); + g_hash_table_destroy (table); + return TRUE; +} + +typedef struct { + gint32 x; + DBusGMethodInvocation *context; +} IncrementData; + +static gboolean +do_async_increment (IncrementData *data) +{ + gint32 newx = data->x + 1; + dbus_g_method_return (data->context, newx); + g_free (data); + return FALSE; +} + +void +my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *context) +{ + IncrementData *data = g_new0 (IncrementData, 1); + data->x = x; + data->context = context; + g_idle_add ((GSourceFunc)do_async_increment, data); +} + +static gboolean +do_async_error (IncrementData *data) +{ + GError *error; + error = g_error_new (MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "%s", + "this method always loses"); + dbus_g_method_return_error (data->context, error); + g_free (data); + return FALSE; +} + +void +my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context) +{ + IncrementData *data = g_new0(IncrementData, 1); + data->context = context; + g_idle_add ((GSourceFunc)do_async_error, data); +} + +extern GMainLoop *loop; + +gboolean +my_object_terminate (MyObject *obj, GError **error) +{ + g_main_loop_quit (loop); + return TRUE; +} + +void +my_object_unsafe_disable_legacy_property_access (MyObject *obj) +{ + dbus_glib_global_set_disable_legacy_property_access (); +} diff --git a/test/core/my-object.h b/test/core/my-object.h new file mode 100644 index 0000000..28f8704 --- /dev/null +++ b/test/core/my-object.h @@ -0,0 +1,118 @@ +#ifndef __MY_OBJECT_H__ +#define __MY_OBJECT_H__ + +#include <glib-object.h> +#include <dbus/dbus-glib.h> + +typedef struct MyObject MyObject; +typedef struct MyObjectClass MyObjectClass; + +GType my_object_get_type (void); + +struct MyObject +{ + GObject parent; + char *this_is_a_string; + guint notouching; + guint val; + gdouble super_studly; + gboolean should_be_hidden; +}; + +struct MyObjectClass +{ + GObjectClass parent; +}; + +#define MY_TYPE_OBJECT (my_object_get_type ()) +#define MY_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MY_TYPE_OBJECT, MyObject)) +#define MY_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MY_TYPE_OBJECT, MyObjectClass)) +#define MY_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MY_TYPE_OBJECT)) +#define MY_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_TYPE_OBJECT)) +#define MY_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MY_TYPE_OBJECT, MyObjectClass)) + +typedef enum +{ + MY_OBJECT_ERROR_FOO, + MY_OBJECT_ERROR_BAR, + MY_OBJECT_ERROR_MULTI_WORD +} MyObjectError; + +#define MY_OBJECT_ERROR (my_object_error_quark ()) +#define MY_TYPE_ERROR (my_object_error_get_type ()) + +GQuark my_object_error_quark (void); +GType my_object_error_get_type (void); + +gboolean my_object_do_nothing (MyObject *obj, GError **error); + +gboolean my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error); + +gint32 my_object_increment_retval (MyObject *obj, gint32 x); + +gint32 my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error); + +gboolean my_object_throw_error (MyObject *obj, GError **error); +gboolean my_object_throw_not_supported (MyObject *obj, GError **error); +gboolean my_object_throw_error_multi_word (MyObject *obj, GError **error); +gboolean my_object_throw_unregistered_error (MyObject *obj, GError **error); + +gboolean my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error); + +gboolean my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error); + +gboolean my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, const char **arg5, GError **error); + +gboolean my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error); +gboolean my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **array, GError **error); + +gboolean my_object_many_stringify (MyObject *obj, GHashTable *vals, GHashTable **ret, GError **error); + +gboolean my_object_rec_arrays (MyObject *obj, GPtrArray *in, GPtrArray **ret, GError **error); + +gboolean my_object_objpath (MyObject *obj, const char *in, const char **arg1, GError **error); + +gboolean my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error); + +gboolean my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error); +gboolean my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error); + +gboolean my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error); + +gboolean my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error); + +gboolean my_object_send_car (MyObject *obj, GValueArray *invals, GValueArray **outvals, GError **error); + +gboolean my_object_get_hash (MyObject *obj, GHashTable **table, GError **error); + +gboolean my_object_increment_val (MyObject *obj, GError **error); + +gboolean my_object_get_val (MyObject *obj, guint *ret, GError **error); + +gboolean my_object_get_value (MyObject *obj, guint *ret, GError **error); + +gboolean my_object_emit_signals (MyObject *obj, GError **error); +gboolean my_object_emit_signal2 (MyObject *obj, GError **error); + +gboolean my_object_emit_frobnicate (MyObject *obj, GError **error); + +gboolean my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **error); +gboolean my_object_echo_signature (MyObject *obj, const gchar *in, gchar **out, GError **error); + +gboolean my_object_process_variant_of_array_of_ints123 (MyObject *obj, GValue *variant, GError **error); + +gboolean my_object_dict_of_dicts (MyObject *obj, GHashTable *dict, GHashTable **ret, GError **error); + +void my_object_dict_of_sigs (MyObject *obj, GHashTable *dict, DBusGMethodInvocation *ctx); + +void my_object_dict_of_objs (MyObject *obj, GHashTable *dict, DBusGMethodInvocation *ctx); + +gboolean my_object_terminate (MyObject *obj, GError **error); + +void my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *context); + +void my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context); + +void my_object_unsafe_disable_legacy_property_access (MyObject *obj); + +#endif diff --git a/test/core/test-dbus-glib.c b/test/core/test-dbus-glib.c index f32b2d4..d78ce58 100644 --- a/test/core/test-dbus-glib.c +++ b/test/core/test-dbus-glib.c @@ -268,7 +268,6 @@ increment_async_cb (DBusGProxy *proxy, guint val, GError *error, gpointer data) g_source_remove (exit_timeout); } - static void lose (const char *str, ...) { @@ -313,6 +312,7 @@ main (int argc, char **argv) DBusGProxy *driver; DBusGProxy *proxy; DBusGProxy *proxy2; + DBusGProxy *property_proxy; char **name_list; guint name_list_len; guint i; @@ -1577,7 +1577,10 @@ main (int argc, char **argv) node = description_load_from_string (v_STRING_2, strlen (v_STRING_2), &error); if (!node) - lose_gerror ("Failed to parse introspection data: %s", error); + { + g_printerr ("===\n%s\n===\n", v_STRING_2); + lose_gerror ("Failed to parse introspection data: %s", error); + } found_introspectable = FALSE; found_properties = FALSE; @@ -1595,9 +1598,10 @@ main (int argc, char **argv) { GSList *elt; gboolean found_manyargs; - + gboolean found_no_touching = FALSE; + found_myobject = TRUE; - + found_manyargs = FALSE; for (elt = interface_info_get_methods (iface); elt; elt = elt->next) { @@ -1612,6 +1616,23 @@ main (int argc, char **argv) } if (!found_manyargs) lose ("Missing method org.freedesktop.DBus.GLib.Tests.MyObject.ManyArgs"); + for (elt = interface_info_get_properties (iface); elt; elt = elt->next) + { + PropertyInfo *prop = elt->data; + + if (strcmp (property_info_get_name (prop), "no-touching") == 0) + { + if (property_info_get_access (prop) != PROPERTY_READ) + lose ("property no-touching had incorrect access %d", property_info_get_access (prop)); + else + { + found_no_touching = TRUE; + break; + } + } + } + if (!found_no_touching) + lose ("didn't find property \"no-touching\" in org.freedesktop.DBus.GLib.Tests.MyObject"); } else if (!found_fooobject && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.GLib.Tests.FooObject") == 0) found_fooobject = TRUE; @@ -1623,7 +1644,262 @@ main (int argc, char **argv) lose ("Missing interface"); } g_free (v_STRING_2); - + + /* Properties tests */ + property_proxy = dbus_g_proxy_new_from_proxy (proxy, DBUS_INTERFACE_PROPERTIES, NULL); + g_object_unref (proxy); + proxy = NULL; + + g_print ("Calling GetProperty (1)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "this_is_a_string", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_STRING)); + g_assert (!strcmp (g_value_get_string (&value), "")); + g_value_unset (&value); + } + + g_print ("Calling SetProperty (1)\n"); + { + GValue value = {0,}; + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, "testing value"); + if (!dbus_g_proxy_call (property_proxy, "Set", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "this_is_a_string", + G_TYPE_VALUE, &value, G_TYPE_INVALID, G_TYPE_INVALID)) + lose_gerror ("Failed to complete SetProperty call", error); + g_value_unset (&value); + } + + g_print ("Calling GetProperty of read-only property\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "no-touching", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty no-touching call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_UINT)); + g_assert (g_value_get_uint (&value) == 42); + g_value_unset (&value); + } + + g_print ("Calling SetProperty (1)\n"); + { + GValue value = {0,}; + g_value_init (&value, G_TYPE_UINT); + g_value_set_uint (&value, 40); + if (dbus_g_proxy_call (property_proxy, "Set", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "no-touching", + G_TYPE_VALUE, &value, G_TYPE_INVALID, G_TYPE_INVALID)) + lose ("Unexpected success from SetProperty call for read-only value \"no-touching\""); + g_clear_error (&error); + g_value_unset (&value); + } + + g_print ("Calling GetProperty of read-only property (again)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "no-touching", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_UINT)); + g_assert (g_value_get_uint (&value) == 42); + g_value_unset (&value); + } + + g_print ("Calling GetProperty (2)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "this_is_a_string", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_STRING)); + g_assert (!strcmp (g_value_get_string (&value), "testing value")); + g_value_unset (&value); + } + + g_print ("Calling GetProperty: SuperStudly\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "SuperStudly", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)); + g_value_unset (&value); + } + + g_print ("Calling GetProperty: super-studly\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "super-studly", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)); + g_value_unset (&value); + } + + g_print ("Calling GetProperty: super_studly\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "super_studly", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)); + g_value_unset (&value); + } + + g_print ("Calling GetProperty on unknown property\n"); + { + GValue value = {0,}; + if (dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "SomeUnknownProperty", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose ("Unexpected success for GetProperty call of unknown property"); + + g_clear_error (&error); + } + + /* These two are expected to pass unless we call disable_legacy_property_access */ + + g_print ("Calling GetProperty on not-exported property (legacy enabled)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed GetProperty call of \"should-be-hidden\" property", error); + g_assert (G_VALUE_HOLDS_BOOLEAN (&value)); + g_assert (g_value_get_boolean (&value) == FALSE); + g_value_unset (&value); + } + + g_print ("Calling GetProperty on not-exported property (legacy enabled)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "ShouldBeHidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed GetProperty call of \"ShouldBeHidden\" property", error); + + g_value_unset (&value); + } + + g_print ("Calling SetProperty on not-exported property (legacy enabled)\n"); + { + GValue value = {0,}; + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, TRUE); + if (dbus_g_proxy_call (property_proxy, "Set", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_VALUE, &value, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose ("Unexpected success from SetProperty call of \"should-be-hidden\" property"); + g_value_unset (&value); + g_clear_error (&error); + } + + g_print ("Calling GetProperty on not-exported property (legacy enabled)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed GetProperty call of \"should-be-hidden\" property", error); + g_assert (G_VALUE_HOLDS_BOOLEAN (&value)); + g_assert (g_value_get_boolean (&value) == FALSE); + g_value_unset (&value); + } + + /* Now, call disable_legacy_property_access */ + + g_assert (proxy == NULL); + proxy = dbus_g_proxy_new_for_name_owner (connection, + "org.freedesktop.DBus.GLib.TestService", + "/org/freedesktop/DBus/GLib/Tests/MyTestObject", + "org.freedesktop.DBus.GLib.Tests.MyObject", + &error); + + if (!dbus_g_proxy_call (proxy, "UnsafeDisableLegacyPropertyAccess", &error, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose_gerror ("Failed to invoke UnsafeDisableLegacyPropertyAccess", error); + + g_object_unref (proxy); + proxy = NULL; + + g_print ("Calling GetProperty on not-exported property (legacy *disabled*)\n"); + { + GValue value = {0,}; + if (dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose ("Unexpected success from GetProperty call of \"should-be-hidden\" property"); + g_clear_error (&error); + } + + g_print ("Calling GetProperty on not-exported property (legacy *disabled*)\n"); + { + GValue value = {0,}; + if (dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "ShouldBeHidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose ("Unexpected success from GetProperty call of \"ShouldBeHidden\" property"); + g_clear_error (&error); + } + + g_print ("Calling SetProperty on not-exported property (legacy *disabled*)\n"); + { + GValue value = {0,}; + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, FALSE); + if (dbus_g_proxy_call (property_proxy, "Set", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_VALUE, &value, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose ("Unexpected success from SetProperty call of \"should-be-hidden\" property"); + g_value_unset (&value); + g_clear_error (&error); + } + + g_object_unref (property_proxy); + property_proxy = NULL; test_terminate_proxy1 = dbus_g_proxy_new_for_name_owner (connection, "org.freedesktop.DBus.GLib.TestService", diff --git a/test/core/test-service-glib.c b/test/core/test-service-glib.c index 222db17..bb9157e 100644 --- a/test/core/test-service-glib.c +++ b/test/core/test-service-glib.c @@ -10,837 +10,12 @@ #include <glib/gi18n.h> #include <glib-object.h> #include <glib/gquark.h> -#include "my-object-marshal.h" -typedef struct MyObject MyObject; -typedef struct MyObjectClass MyObjectClass; - -GType my_object_get_type (void); - -struct MyObject -{ - GObject parent; - char *this_is_a_string; - guint val; -}; - -struct MyObjectClass -{ - GObjectClass parent; -}; - -#define MY_TYPE_OBJECT (my_object_get_type ()) -#define MY_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MY_TYPE_OBJECT, MyObject)) -#define MY_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MY_TYPE_OBJECT, MyObjectClass)) -#define MY_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MY_TYPE_OBJECT)) -#define MY_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_TYPE_OBJECT)) -#define MY_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MY_TYPE_OBJECT, MyObjectClass)) - -G_DEFINE_TYPE(MyObject, my_object, G_TYPE_OBJECT) - -typedef enum -{ - MY_OBJECT_ERROR_FOO, - MY_OBJECT_ERROR_BAR -} MyObjectError; - -#define MY_OBJECT_ERROR (my_object_error_quark ()) - -#define MY_TYPE_ERROR (my_object_error_get_type ()) - -gboolean my_object_do_nothing (MyObject *obj, GError **error); - -gboolean my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error); - -gint32 my_object_increment_retval (MyObject *obj, gint32 x); - -gint32 my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error); - -gboolean my_object_throw_error (MyObject *obj, GError **error); - -gboolean my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error); - -gboolean my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error); - -gboolean my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, const char **arg5, GError **error); - -gboolean my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error); -gboolean my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **array, GError **error); - -gboolean my_object_many_stringify (MyObject *obj, GHashTable *vals, GHashTable **ret, GError **error); - -gboolean my_object_rec_arrays (MyObject *obj, GPtrArray *in, GPtrArray **ret, GError **error); - -gboolean my_object_objpath (MyObject *obj, const char *in, const char **arg1, GError **error); - -gboolean my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error); - -gboolean my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error); -gboolean my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error); - -gboolean my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error); - -gboolean my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error); - -gboolean my_object_send_car (MyObject *obj, GValueArray *invals, GValueArray **outvals, GError **error); - -gboolean my_object_get_hash (MyObject *obj, GHashTable **table, GError **error); - -gboolean my_object_increment_val (MyObject *obj, GError **error); - -gboolean my_object_get_val (MyObject *obj, guint *ret, GError **error); - -gboolean my_object_get_value (MyObject *obj, guint *ret, GError **error); - -gboolean my_object_emit_signals (MyObject *obj, GError **error); -gboolean my_object_emit_signal2 (MyObject *obj, GError **error); - -gboolean my_object_emit_frobnicate (MyObject *obj, GError **error); - -gboolean my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **error); - -gboolean my_object_process_variant_of_array_of_ints123 (MyObject *obj, GValue *variant, GError **error); - -gboolean my_object_dict_of_dicts (MyObject *obj, GHashTable *dict, GHashTable **ret, GError **error); - -gboolean my_object_terminate (MyObject *obj, GError **error); - -void my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *context); - -void my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context); - -#include "test-service-glib-glue.h" - -GQuark my_object_error_quark (void); - -GType my_object_error_get_type (void); - -/* Properties */ -enum -{ - PROP_0, - PROP_THIS_IS_A_STRING -}; - -enum -{ - FROBNICATE, - SIG0, - SIG1, - SIG2, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static void -my_object_finalize (GObject *object) -{ - MyObject *mobject = MY_OBJECT (object); - - g_free (mobject->this_is_a_string); - - (G_OBJECT_CLASS (my_object_parent_class)->finalize) (object); -} - -static void -my_object_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MyObject *mobject; - - mobject = MY_OBJECT (object); - - switch (prop_id) - { - case PROP_THIS_IS_A_STRING: - g_free (mobject->this_is_a_string); - mobject->this_is_a_string = g_value_dup_string (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -my_object_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MyObject *mobject; - - mobject = MY_OBJECT (object); - - switch (prop_id) - { - case PROP_THIS_IS_A_STRING: - g_value_set_string (value, mobject->this_is_a_string); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -my_object_init (MyObject *obj) -{ - obj->val = 0; -} - -static void -my_object_class_init (MyObjectClass *mobject_class) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (mobject_class); - - gobject_class->finalize = my_object_finalize; - gobject_class->set_property = my_object_set_property; - gobject_class->get_property = my_object_get_property; - - g_object_class_install_property (gobject_class, - PROP_THIS_IS_A_STRING, - g_param_spec_string ("this_is_a_string", - _("Sample string"), - _("Example of a string property"), - "default value", - G_PARAM_READWRITE)); - signals[FROBNICATE] = - g_signal_new ("frobnicate", - G_OBJECT_CLASS_TYPE (mobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - signals[SIG0] = - g_signal_new ("sig0", - G_OBJECT_CLASS_TYPE (mobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - my_object_marshal_VOID__STRING_INT_STRING, - G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING); - - signals[SIG1] = - g_signal_new ("sig1", - G_OBJECT_CLASS_TYPE (mobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - my_object_marshal_VOID__STRING_BOXED, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VALUE); - - signals[SIG2] = - g_signal_new ("sig2", - G_OBJECT_CLASS_TYPE (mobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, DBUS_TYPE_G_STRING_STRING_HASHTABLE); -} - -GQuark -my_object_error_quark (void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string ("my_object_error"); - - return quark; -} - -/* This should really be standard. */ -#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } - -GType -my_object_error_get_type (void) -{ - static GType etype = 0; - - if (etype == 0) - { - static const GEnumValue values[] = - { - - ENUM_ENTRY (MY_OBJECT_ERROR_FOO, "Foo"), - ENUM_ENTRY (MY_OBJECT_ERROR_BAR, "Bar"), - { 0, 0, 0 } - }; - - etype = g_enum_register_static ("MyObjectError", values); - } - - return etype; -} +#include "my-object.h" static GObject *obj; static GObject *obj2; - -gboolean -my_object_do_nothing (MyObject *obj, GError **error) -{ - return TRUE; -} - -gboolean -my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error) -{ - *ret = x +1; - return TRUE; -} - -gint32 -my_object_increment_retval (MyObject *obj, gint32 x) -{ - return x + 1; -} - -gint32 -my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error) -{ - if (x + 1 > 10) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "%s", - "x is bigger than 9"); - return FALSE; - } - return x + 1; -} - -gboolean -my_object_throw_error (MyObject *obj, GError **error) -{ - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "%s", - "this method always loses"); - return FALSE; -} - -gboolean -my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error) -{ - *ret = g_ascii_strup (str, -1); - return TRUE; -} - -gboolean -my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error) -{ - *d_ret = trouble + (x * 2); - *str_ret = g_ascii_strup (str, -1); - return TRUE; -} - -gboolean -my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, const char **arg5, GError **error) -{ - *arg0 = 42; - *arg1 = g_strdup ("42"); - *arg2 = -67; - *arg3 = 2; - *arg4 = 26; - *arg5 = "hello world"; /* Annotation specifies as const */ - return TRUE; -} - -gboolean -my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error) -{ - GValue valstr = {0, }; - - g_value_init (&valstr, G_TYPE_STRING); - if (!g_value_transform (value, &valstr)) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "couldn't transform value"); - return FALSE; - } - *ret = g_value_dup_string (&valstr); - g_value_unset (&valstr); - return TRUE; -} - -gboolean -my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error) -{ - if (str[0] == '\0' || !g_ascii_isdigit (str[0])) { - g_value_init (value, G_TYPE_STRING); - g_value_set_string (value, str); - } else { - g_value_init (value, G_TYPE_INT); - g_value_set_int (value, (int) g_ascii_strtoull (str, NULL, 10)); - } - return TRUE; -} - -gboolean -my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error) -{ - *len_ret = array->len; - return TRUE; -} - -gboolean -my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **ret, GError **error) -{ - guint32 val; - GArray *array; - - array = g_array_new (FALSE, TRUE, sizeof (guint32)); - - while (reqlen > 0) { - val = 42; - g_array_append_val (array, val); - val = 26; - g_array_append_val (array, val); - reqlen--; - } - val = 2; - g_array_append_val (array, val); - *ret = array; - return TRUE; -} - -gboolean -my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error) -{ - int len; - int i; - - len = g_strv_length ((char**) in); - - *out = g_new0 (char *, len + 1); - for (i = 0; i < len; i++) - { - (*out)[i] = g_ascii_strup (in[i], -1); - } - (*out)[i] = NULL; - - return TRUE; -} - -static void -hash_foreach_stringify (gpointer key, gpointer val, gpointer user_data) -{ - const char *keystr = key; - const GValue *value = val; - GValue *sval; - GHashTable *ret = user_data; - - sval = g_new0 (GValue, 1); - g_value_init (sval, G_TYPE_STRING); - if (!g_value_transform (value, sval)) - g_assert_not_reached (); - - g_hash_table_insert (ret, g_strdup (keystr), sval); -} - -static void -unset_and_free_gvalue (gpointer val) -{ - g_value_unset (val); - g_free (val); -} - -gboolean -my_object_many_stringify (MyObject *obj, GHashTable /* char * -> GValue * */ *vals, GHashTable /* char * -> GValue * */ **ret, GError **error) -{ - *ret = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, unset_and_free_gvalue); - g_hash_table_foreach (vals, hash_foreach_stringify, *ret); - return TRUE; -} - -gboolean -my_object_rec_arrays (MyObject *obj, GPtrArray *in, GPtrArray **ret, GError **error) -{ - char **strs; - GArray *ints; - guint v_UINT; - - if (in->len != 2) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid array len"); - return FALSE; - } - - strs = g_ptr_array_index (in, 0); - if (!*strs || strcmp (*strs, "foo")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 0"); - return FALSE; - } - strs++; - if (!*strs || strcmp (*strs, "bar")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 1"); - return FALSE; - } - strs++; - if (*strs) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string array len in pos 0"); - return FALSE; - } - strs = g_ptr_array_index (in, 1); - if (!*strs || strcmp (*strs, "baz")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 0"); - return FALSE; - } - strs++; - if (!*strs || strcmp (*strs, "whee")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 1"); - return FALSE; - } - strs++; - if (!*strs || strcmp (*strs, "moo")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 2"); - return FALSE; - } - strs++; - if (*strs) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string array len in pos 1"); - return FALSE; - } - - *ret = g_ptr_array_new (); - - ints = g_array_new (TRUE, TRUE, sizeof (guint)); - v_UINT = 10; - g_array_append_val (ints, v_UINT); - v_UINT = 42; - g_array_append_val (ints, v_UINT); - v_UINT = 27; - g_array_append_val (ints, v_UINT); - g_ptr_array_add (*ret, ints); - - ints = g_array_new (TRUE, TRUE, sizeof (guint)); - v_UINT = 30; - g_array_append_val (ints, v_UINT); - g_ptr_array_add (*ret, ints); - return TRUE; -} - -gboolean -my_object_objpath (MyObject *obj, const char *incoming, const char **outgoing, GError **error) -{ - if (strcmp (incoming, "/org/freedesktop/DBus/GLib/Tests/MyTestObject")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid incoming object"); - return FALSE; - } - *outgoing = "/org/freedesktop/DBus/GLib/Tests/MyTestObject2"; - return TRUE; -} - -gboolean -my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error) -{ - *objs = g_ptr_array_new (); - - g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject")); - g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject2")); - - return TRUE; -} - -static void -hash_foreach (gpointer key, gpointer val, gpointer user_data) -{ - const char *keystr = key; - const char *valstr = val; - guint *count = user_data; - - *count += (strlen (keystr) + strlen (valstr)); - g_print ("%s -> %s\n", keystr, valstr); -} - -gboolean -my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error) -{ - *len = 0; - g_hash_table_foreach (table, hash_foreach, len); - return TRUE; -} - -gboolean -my_object_send_car (MyObject *obj, GValueArray *invals, GValueArray **outvals, GError **error) -{ - if (invals->n_values != 3 - || G_VALUE_TYPE (g_value_array_get_nth (invals, 0)) != G_TYPE_STRING - || G_VALUE_TYPE (g_value_array_get_nth (invals, 1)) != G_TYPE_UINT - || G_VALUE_TYPE (g_value_array_get_nth (invals, 2)) != G_TYPE_VALUE) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid incoming values"); - return FALSE; - } - *outvals = g_value_array_new (2); - g_value_array_append (*outvals, NULL); - g_value_init (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), G_TYPE_UINT); - g_value_set_uint (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), - g_value_get_uint (g_value_array_get_nth (invals, 1)) + 1); - g_value_array_append (*outvals, NULL); - g_value_init (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), DBUS_TYPE_G_OBJECT_PATH); - g_value_set_boxed (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), - g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject2")); - return TRUE; -} - -gboolean -my_object_get_hash (MyObject *obj, GHashTable **ret, GError **error) -{ - GHashTable *table; - - table = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (table, "foo", "bar"); - g_hash_table_insert (table, "baz", "whee"); - g_hash_table_insert (table, "cow", "crack"); - *ret = table; - return TRUE; -} - -gboolean -my_object_increment_val (MyObject *obj, GError **error) -{ - obj->val++; - return TRUE; -} - -gboolean -my_object_get_val (MyObject *obj, guint *ret, GError **error) -{ - *ret = obj->val; - return TRUE; -} - -gboolean -my_object_get_value (MyObject *obj, guint *ret, GError **error) -{ - *ret = obj->val; - return TRUE; -} - -gboolean -my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **error) -{ - GType t; - t = G_VALUE_TYPE(variant); - g_value_init (ret, t); - g_value_copy (variant, ret); - - return TRUE; -} - -gboolean -my_object_process_variant_of_array_of_ints123 (MyObject *obj, GValue *variant, GError **error) -{ - GArray *array; - int i; - int j; - - j = 0; - - array = (GArray *)g_value_get_boxed (variant); - - for (i = 0; i <= 2; i++) - { - j = g_array_index (array, int, i); - if (j != i + 1) - goto error; - } - - return TRUE; - -error: - *error = g_error_new (MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "Error decoding a variant of type ai (i + 1 = %i, j = %i)", - i, j + 1); - return FALSE; -} - - -typedef struct _HashAndString HashAndString; - -struct _HashAndString -{ - GHashTable *hash; - gchar* string; -}; - -static void -hash_foreach_prepend_string (gpointer key, gpointer val, gpointer user_data) -{ - HashAndString *data = (HashAndString*) user_data; - gchar *in = (gchar*) val; - g_hash_table_insert (data->hash, g_strdup ((gchar*) key), - g_strjoin (" ", data->string, in, NULL)); -} - - -static void -hash_foreach_mangle_dict_of_strings (gpointer key, gpointer val, gpointer user_data) -{ - GHashTable *out = (GHashTable*) user_data; - GHashTable *in_dict = (GHashTable *) val; - HashAndString *data = g_new0 (HashAndString, 1); - - data->string = (gchar*) key; - data->hash = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - g_hash_table_foreach (in_dict, hash_foreach_prepend_string, data); - - g_hash_table_insert(out, g_strdup ((gchar*) key), data->hash); -} - -gboolean -my_object_dict_of_dicts (MyObject *obj, GHashTable *in, - GHashTable **out, GError **error) -{ - *out = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_hash_table_destroy); - g_hash_table_foreach (in, hash_foreach_mangle_dict_of_strings, *out); - return TRUE; -} - -gboolean -my_object_emit_frobnicate (MyObject *obj, GError **error) -{ - g_signal_emit (obj, signals[FROBNICATE], 0, 42); - return TRUE; -} - -gboolean -my_object_emit_signals (MyObject *obj, GError **error) -{ - GValue val = {0, }; - - g_signal_emit (obj, signals[SIG0], 0, "foo", 22, "moo"); - - g_value_init (&val, G_TYPE_STRING); - g_value_set_string (&val, "bar"); - g_signal_emit (obj, signals[SIG1], 0, "baz", &val); - g_value_unset (&val); - - return TRUE; -} - -gboolean -my_object_emit_signal2 (MyObject *obj, GError **error) -{ - GHashTable *table; - - table = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (table, "baz", "cow"); - g_hash_table_insert (table, "bar", "foo"); - g_signal_emit (obj, signals[SIG2], 0, table); - g_hash_table_destroy (table); - return TRUE; -} - -typedef struct { - gint32 x; - DBusGMethodInvocation *context; -} IncrementData; - -static gboolean -do_async_increment (IncrementData *data) -{ - gint32 newx = data->x + 1; - dbus_g_method_return (data->context, newx); - g_free (data); - return FALSE; -} - -void -my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *context) -{ - IncrementData *data = g_new0 (IncrementData, 1); - data->x = x; - data->context = context; - g_idle_add ((GSourceFunc)do_async_increment, data); -} - -static gboolean -do_async_error (IncrementData *data) -{ - GError *error; - error = g_error_new (MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "%s", - "this method always loses"); - dbus_g_method_return_error (data->context, error); - g_free (data); - return FALSE; -} - -void -my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context) -{ - IncrementData *data = g_new0(IncrementData, 1); - data->context = context; - g_idle_add ((GSourceFunc)do_async_error, data); -} - - -static GMainLoop *loop; - -gboolean -my_object_terminate (MyObject *obj, GError **error) -{ - g_main_loop_quit (loop); - return TRUE; -} +GMainLoop *loop; #define TEST_SERVICE_NAME "org.freedesktop.DBus.GLib.TestService" @@ -855,9 +30,6 @@ main (int argc, char **argv) g_type_init (); g_thread_init (NULL); dbus_g_thread_init (); - dbus_g_object_type_install_info (MY_TYPE_OBJECT, - &dbus_glib_my_object_object_info); - dbus_g_error_domain_register (MY_OBJECT_ERROR, NULL, MY_TYPE_ERROR); diff --git a/test/core/test-service-glib.xml b/test/core/test-service-glib.xml index fca02af..be262d6 100644 --- a/test/core/test-service-glib.xml +++ b/test/core/test-service-glib.xml @@ -2,6 +2,10 @@ <node name="/org/freedesktop/DBus/GLib/Tests/MyTestObject"> <interface name="org.freedesktop.DBus.GLib.Tests.MyObject"> + <property name="this_is_a_string" type="s" access="readwrite"/> + <property name="no-touching" type="u" access="read"/> + <property name="SuperStudly" type="d" access="readwrite"/> + <method name="DoNothing"> </method> @@ -145,6 +149,9 @@ <method name="EmitFrobnicate"> </method> + <method name="UnsafeDisableLegacyPropertyAccess"> + </method> + <!-- Export signals --> <signal name="Frobnicate"/> |