From d021cfae6695f0f44102edf758abfc42e2f3c093 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 3 Sep 2003 02:08:25 +0000 Subject: 2003-09-01 Havoc Pennington * glib/dbus-gparser.c: implement * glib/dbus-gobject.c: start implementing skeletons support * configure.in: when disabling checks/assert, also define G_DISABLE_ASSERT and G_DISABLE_CHECKS --- glib/dbus-gobject.c | 780 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 780 insertions(+) create mode 100644 glib/dbus-gobject.c (limited to 'glib/dbus-gobject.c') diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c new file mode 100644 index 00000000..aa53265b --- /dev/null +++ b/glib/dbus-gobject.c @@ -0,0 +1,780 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gobject.c Exporting a GObject remotely + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "dbus-glib.h" +#include "dbus-gtest.h" +#include + +/** + * @addtogroup DBusGLibInternals + * @{ + */ + +static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT; +static GHashTable *info_hash = NULL; + +static char* +javacaps_to_uscore (const char *caps) +{ + const char *p; + GString *str; + + str = g_string_new (NULL); + p = caps; + while (*p) + { + if (g_ascii_isupper (*p)) + { + if (str->len > 0 && + (str->len < 2 || str->str[str->len-2] != '_')) + g_string_append_c (str, '_'); + g_string_append_c (str, g_ascii_tolower (*p)); + } + else + { + g_string_append_c (str, *p); + } + ++p; + } + + return g_string_free (str, FALSE); +} + +static char* +uscore_to_javacaps (const char *uscore) +{ + const char *p; + GString *str; + gboolean last_was_uscore; + + last_was_uscore = TRUE; + + str = g_string_new (NULL); + p = uscore; + while (*p) + { + if (*p == '-' || *p == '_') + { + last_was_uscore = TRUE; + } + else + { + if (last_was_uscore) + { + g_string_append_c (str, g_ascii_toupper (*p)); + last_was_uscore = FALSE; + } + else + g_string_append_c (str, *p); + } + ++p; + } + + return g_string_free (str, FALSE); +} + +static void +gobject_unregister_function (DBusConnection *connection, + void *user_data) +{ + GObject *object; + + object = G_OBJECT (user_data); + + +} + +static int +gtype_to_dbus_type (GType type) +{ + switch (type) + { + case G_TYPE_CHAR: + case G_TYPE_UCHAR: + return DBUS_TYPE_BYTE; + + case G_TYPE_BOOLEAN: + return DBUS_TYPE_BOOLEAN; + + /* long gets cut to 32 bits so the remote API is consistent + * on all architectures + */ + + case G_TYPE_LONG: + case G_TYPE_INT: + return DBUS_TYPE_INT32; + case G_TYPE_ULONG: + case G_TYPE_UINT: + return DBUS_TYPE_UINT32; + + case G_TYPE_INT64: + return DBUS_TYPE_INT64; + + case G_TYPE_UINT64: + return DBUS_TYPE_UINT64; + + case G_TYPE_FLOAT: + case G_TYPE_DOUBLE: + return DBUS_TYPE_DOUBLE; + + case G_TYPE_STRING: + return DBUS_TYPE_STRING; + + default: + return DBUS_TYPE_INVALID; + } +} + +static const char * +dbus_type_to_string (int type) +{ + switch (type) + { + case DBUS_TYPE_INVALID: + return "invalid"; + case DBUS_TYPE_NIL: + return "nil"; + case DBUS_TYPE_BOOLEAN: + return "boolean"; + case DBUS_TYPE_INT32: + return "int32"; + case DBUS_TYPE_UINT32: + return "uint32"; + case DBUS_TYPE_DOUBLE: + return "double"; + case DBUS_TYPE_STRING: + return "string"; + case DBUS_TYPE_NAMED: + return "named"; + case DBUS_TYPE_ARRAY: + return "array"; + case DBUS_TYPE_DICT: + return "dict"; + default: + return "unknown"; + } +} + +static DBusHandlerResult +handle_introspect (DBusConnection *connection, + DBusMessage *message, + GObject *object) +{ + GString *xml; + GParamSpec **specs; + unsigned int n_specs; + unsigned int i; + GType last_type; + DBusMessage *ret; + + xml = g_string_new (NULL); + + g_string_append (xml, "\n"); + + last_type = G_TYPE_INVALID; + + specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), + &n_specs); + + i = 0; + while (i < n_specs) + { + GParamSpec *spec = specs[i]; + gboolean can_set; + gboolean can_get; + char *s; + int dbus_type; + + dbus_type = gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec)); + if (dbus_type == DBUS_TYPE_INVALID) + goto next; + + if (spec->owner_type != last_type) + { + if (last_type != G_TYPE_INVALID) + g_string_append (xml, " \n"); + + + /* FIXME what should the namespace on the interface be in + * general? should people be able to set it for their + * objects? + */ + + g_string_append (xml, " owner_type)); + g_string_append (xml, "\">\n"); + + last_type = spec->owner_type; + } + + can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 && + (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); + + can_get = (spec->flags & G_PARAM_READABLE) != 0; + + s = uscore_to_javacaps (spec->name); + + if (can_set) + { + g_string_append (xml, " \n"); + + g_string_append (xml, " \n"); + } + + if (can_get) + { + g_string_append (xml, " \n"); + + g_string_append (xml, " \n"); + } + + g_free (s); + + next: + ++i; + } + + if (last_type != G_TYPE_INVALID) + g_string_append (xml, " \n"); + + g_free (specs); + + /* Close the XML, and send it to the requesting app */ + + g_string_append (xml, "\n"); + + ret = dbus_message_new_method_return (message); + if (ret == NULL) + g_error ("out of memory"); + + dbus_message_append_args (message, + DBUS_TYPE_STRING, xml->str, + DBUS_TYPE_INVALID); + + dbus_connection_send (connection, message, NULL); + dbus_message_unref (message); + + g_string_free (xml, TRUE); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusMessage* +set_object_property (DBusConnection *connection, + DBusMessage *message, + GObject *object, + GParamSpec *pspec) +{ + GValue value; + DBusMessageIter iter; + int type; + gboolean can_set; + DBusMessage *ret; + + dbus_message_iter_init (message, &iter); + type = dbus_message_get_type (message); + + can_set = TRUE; + switch (type) + { + case DBUS_TYPE_BYTE: + { + unsigned char b; + + b = dbus_message_iter_get_byte (&iter); + + g_value_init (&value, G_TYPE_UCHAR); + + g_value_set_uchar (&value, b); + } + break; + case DBUS_TYPE_BOOLEAN: + { + gboolean b; + + b = dbus_message_iter_get_boolean (&iter); + + g_value_init (&value, G_TYPE_BOOLEAN); + + g_value_set_boolean (&value, b); + } + break; + case DBUS_TYPE_INT32: + { + gint32 i; + + i = dbus_message_iter_get_int32 (&iter); + + g_value_init (&value, G_TYPE_INT); + + g_value_set_int (&value, i); + } + break; + case DBUS_TYPE_UINT32: + { + guint32 i; + + i = dbus_message_iter_get_uint32 (&iter); + + g_value_init (&value, G_TYPE_UINT); + + g_value_set_uint (&value, i); + } + break; + case DBUS_TYPE_INT64: + { + gint64 i; + + i = dbus_message_iter_get_int64 (&iter); + + g_value_init (&value, G_TYPE_INT64); + + g_value_set_int64 (&value, i); + } + break; + case DBUS_TYPE_UINT64: + { + guint64 i; + + i = dbus_message_iter_get_uint64 (&iter); + + g_value_init (&value, G_TYPE_UINT64); + + g_value_set_uint64 (&value, i); + } + break; + case DBUS_TYPE_DOUBLE: + { + double d; + + d = dbus_message_iter_get_double (&iter); + + g_value_init (&value, G_TYPE_DOUBLE); + + g_value_set_double (&value, d); + } + break; + case DBUS_TYPE_STRING: + { + char *s; + + /* FIXME use a const string accessor */ + + s = dbus_message_iter_get_string (&iter); + + g_value_init (&value, G_TYPE_STRING); + + g_value_set_string (&value, s); + + g_free (s); + } + break; + + /* FIXME array and other types, especially byte array + * converted to G_TYPE_STRING + */ + + default: + can_set = FALSE; + break; + } + + /* The g_object_set_property() will transform some types, e.g. it + * will let you use a uchar to set an int property etc. Note that + * any error in value range or value conversion will just + * g_warning(). These GObject skels are not for secure applications. + */ + + if (can_set) + { + g_object_set_property (object, + pspec->name, + &value); + + ret = dbus_message_new_method_return (message); + if (ret == NULL) + g_error ("out of memory"); + + g_value_unset (&value); + } + else + { + ret = dbus_message_new_error (message, + DBUS_ERROR_INVALID_ARGS, + "Argument's D-BUS type can't be converted to a GType"); + if (ret == NULL) + g_error ("out of memory"); + } + + return ret; +} + +static DBusMessage* +get_object_property (DBusConnection *connection, + DBusMessage *message, + GObject *object, + GParamSpec *pspec) +{ + GType value_type; + gboolean can_get; + DBusMessage *ret; + GValue value; + DBusMessageIter iter; + + value_type = G_PARAM_SPEC_VALUE_TYPE (pspec); + + ret = dbus_message_new_method_return (message); + if (ret == NULL) + g_error ("out of memory"); + + can_get = TRUE; + g_value_init (&value, value_type); + g_object_get_property (object, pspec->name, &value); + + value_type = G_VALUE_TYPE (&value); + + dbus_message_append_iter_init (message, &iter); + + switch (value_type) + { + case G_TYPE_CHAR: + dbus_message_iter_append_byte (&iter, + g_value_get_char (&value)); + break; + case G_TYPE_UCHAR: + dbus_message_iter_append_byte (&iter, + g_value_get_uchar (&value)); + break; + case G_TYPE_BOOLEAN: + dbus_message_iter_append_boolean (&iter, + g_value_get_boolean (&value)); + break; + case G_TYPE_INT: + dbus_message_iter_append_int32 (&iter, + g_value_get_int (&value)); + break; + case G_TYPE_UINT: + dbus_message_iter_append_uint32 (&iter, + g_value_get_uint (&value)); + break; + /* long gets cut to 32 bits so the remote API is consistent + * on all architectures + */ + case G_TYPE_LONG: + dbus_message_iter_append_int32 (&iter, + g_value_get_long (&value)); + break; + case G_TYPE_ULONG: + dbus_message_iter_append_uint32 (&iter, + g_value_get_ulong (&value)); + break; + case G_TYPE_INT64: + dbus_message_iter_append_int64 (&iter, + g_value_get_int64 (&value)); + break; + case G_TYPE_UINT64: + dbus_message_iter_append_uint64 (&iter, + g_value_get_uint64 (&value)); + break; + case G_TYPE_FLOAT: + dbus_message_iter_append_double (&iter, + g_value_get_float (&value)); + break; + case G_TYPE_DOUBLE: + dbus_message_iter_append_double (&iter, + g_value_get_double (&value)); + break; + case G_TYPE_STRING: + /* FIXME, the GValue string may not be valid UTF-8 */ + dbus_message_iter_append_string (&iter, + g_value_get_string (&value)); + break; + default: + can_get = FALSE; + break; + } + + g_value_unset (&value); + + if (!can_get) + { + dbus_message_unref (ret); + ret = dbus_message_new_error (message, + DBUS_ERROR_UNKNOWN_METHOD, + "Can't convert GType of object property to a D-BUS type"); + } + + return ret; +} + +static DBusHandlerResult +gobject_message_function (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + const DBusGObjectInfo *info; + GParamSpec *pspec; + GObject *object; + const char *member; + gboolean setter; + gboolean getter; + char *s; + + object = G_OBJECT (user_data); + + if (dbus_message_is_method_call (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE, + "Introspect")) + return handle_introspect (connection, message, object); + + member = dbus_message_get_member (message); + + /* Try the metainfo, which lets us invoke methods */ + + g_static_mutex_lock (&info_hash_mutex); + /* FIXME this needs to walk up the inheritance tree, not + * just look at the most-derived class + */ + info = g_hash_table_lookup (info_hash, + G_OBJECT_GET_CLASS (object)); + g_static_mutex_unlock (&info_hash_mutex); + + if (info != NULL) + { + + + + } + + /* If no metainfo, we can still do properties and signals + * via standard GLib introspection + */ + setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't'); + getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't'); + + if (!(setter || getter)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + s = javacaps_to_uscore (&member[3]); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), + s); + + g_free (s); + + if (pspec != NULL) + { + DBusMessage *ret; + + if (setter) + { + ret = set_object_property (connection, message, + object, pspec); + } + else if (getter) + { + ret = get_object_property (connection, message, + object, pspec); + } + else + { + g_assert_not_reached (); + ret = NULL; + } + + g_assert (ret != NULL); + + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusObjectPathVTable gobject_dbus_vtable = { + gobject_unregister_function, + gobject_message_function, + NULL +}; + +/** @} */ /* end of internals */ + +/** + * @addtogroup DBusGLib + * @{ + */ + +/** + * Install introspection information about the given object class + * sufficient to allow methods on the object to be invoked by name. + * The introspection information is normally generated by + * dbus-glib-tool, then this function is called in the + * class_init() for the object class. + * + * Once introspection information has been installed, instances of the + * object registered with dbus_connection_register_gobject() can have + * their methods invoked remotely. + * + * @param object_class class struct of the object + * @param info introspection data generated by dbus-glib-tool + */ +void +dbus_gobject_class_install_info (GObjectClass *object_class, + const DBusGObjectInfo *info) +{ + g_return_if_fail (G_IS_OBJECT_CLASS (object_class)); + + g_static_mutex_lock (&info_hash_mutex); + + if (info_hash == NULL) + { + info_hash = g_hash_table_new (NULL, NULL); /* direct hash */ + } + + g_hash_table_replace (info_hash, object_class, (void*) info); + + g_static_mutex_unlock (&info_hash_mutex); +} + +static char** +split_path (const char *path) +{ + int len; + char **split; + int n_components; + int i, j, comp; + + len = strlen (path); + + n_components = 0; + i = 0; + while (i < len) + { + if (path[i] == '/') + n_components += 1; + ++i; + } + + split = g_new0 (char*, n_components + 1); + + comp = 0; + i = 0; + while (i < len) + { + if (path[i] == '/') + ++i; + j = i; + + while (j < len && path[j] != '/') + ++j; + + /* Now [i, j) is the path component */ + g_assert (i < j); + g_assert (path[i] != '/'); + g_assert (j == len || path[j] == '/'); + + split[comp] = g_strndup (&path[i], j - i + 1); + + split[comp][j-i] = '\0'; + + ++comp; + i = j; + } + g_assert (i == len); + + return split; +} + +/** + * Registers a GObject at the given path. Properties, methods, and signals + * of the object can then be accessed remotely. Methods are only available + * if method introspection data has been added to the object's class + * with g_object_class_install_info(). + * + * The registration will be cancelled if either the DBusConnection or + * the GObject gets finalized. + * + * @param connection the D-BUS connection + * @param at_path the path where the object will live (the object's name) + * @param object the object + */ +void +dbus_connection_register_gobject (DBusConnection *connection, + const char *at_path, + GObject *object) +{ + char **split; + + g_return_if_fail (connection != NULL); + g_return_if_fail (at_path != NULL); + g_return_if_fail (G_IS_OBJECT (object)); + + split = split_path (at_path); + + if (!dbus_connection_register_object_path (connection, + (const char**) split, + &gobject_dbus_vtable, + object)) + g_error ("Failed to register GObject with DBusConnection"); + + g_strfreev (split); + + /* FIXME set up memory management (so we break the + * registration if object or connection vanishes) + */ +} + +/** @} */ /* end of public API */ + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusGLibInternals + * Unit test for GLib GObject integration ("skeletons") + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gobject_test (const char *test_data_dir) +{ + static struct { const char *javacaps; const char *uscore; } name_pairs[] = { + { "setFoo", "set_foo" }, + { "foo", "foo" }, + { "getFooBar", "get_foo_bar" }, + { "Hello", "hello" }, + { "frobateUIHandler", "frobate_ui_handler" } + }; + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ -- cgit From 636be6f92d4d8effd392ad1f894738849ec7af76 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 4 Sep 2003 00:21:36 +0000 Subject: 2003-09-03 Havoc Pennington * test/glib/Makefile.am: add this with random glib-linked test programs * glib/Makefile.am: remove the random test programs from here, leave only the unit tests * glib/dbus-gobject.c (_dbus_gobject_test): add test for uscore/javacaps conversion, and fix (get_object_property, set_object_property): change to .NET convention for mapping props to methods, set_FooBar/get_FooBar, since one language has such a convention we may as well copy it. Plus real methods in either getFooBar or get_foo_bar style won't collide with this convention. --- glib/dbus-gobject.c | 63 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 14 deletions(-) (limited to 'glib/dbus-gobject.c') diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index aa53265b..b0f6c139 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -35,7 +35,7 @@ static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT; static GHashTable *info_hash = NULL; static char* -javacaps_to_uscore (const char *caps) +wincaps_to_uscore (const char *caps) { const char *p; GString *str; @@ -62,7 +62,7 @@ javacaps_to_uscore (const char *caps) } static char* -uscore_to_javacaps (const char *uscore) +uscore_to_wincaps (const char *uscore) { const char *p; GString *str; @@ -233,11 +233,11 @@ handle_introspect (DBusConnection *connection, can_get = (spec->flags & G_PARAM_READABLE) != 0; - s = uscore_to_javacaps (spec->name); + s = uscore_to_wincaps (spec->name); if (can_set) { - g_string_append (xml, " \n"); @@ -248,7 +248,7 @@ handle_introspect (DBusConnection *connection, if (can_get) { - g_string_append (xml, " \n"); @@ -578,13 +578,13 @@ gobject_message_function (DBusConnection *connection, /* If no metainfo, we can still do properties and signals * via standard GLib introspection */ - setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't'); - getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't'); + setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't' && member[3] == '_'); + getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't' && member[3] == '_'); if (!(setter || getter)) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - s = javacaps_to_uscore (&member[3]); + s = wincaps_to_uscore (&member[4]); pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), s); @@ -757,6 +757,7 @@ dbus_connection_register_gobject (DBusConnection *connection, /** @} */ /* end of public API */ #ifdef DBUS_BUILD_TESTS +#include /** * @ingroup DBusGLibInternals @@ -766,14 +767,48 @@ dbus_connection_register_gobject (DBusConnection *connection, dbus_bool_t _dbus_gobject_test (const char *test_data_dir) { - static struct { const char *javacaps; const char *uscore; } name_pairs[] = { - { "setFoo", "set_foo" }, - { "foo", "foo" }, - { "getFooBar", "get_foo_bar" }, - { "Hello", "hello" }, - { "frobateUIHandler", "frobate_ui_handler" } + int i; + static struct { const char *wincaps; const char *uscore; } name_pairs[] = { + { "SetFoo", "set_foo" }, + { "Foo", "foo" }, + { "GetFooBar", "get_foo_bar" }, + { "Hello", "hello" } + + /* Impossible-to-handle cases */ + /* { "FrobateUIHandler", "frobate_ui_handler" } */ }; + i = 0; + while (i < (int) G_N_ELEMENTS (name_pairs)) + { + char *uscore; + char *wincaps; + + uscore = wincaps_to_uscore (name_pairs[i].wincaps); + wincaps = uscore_to_wincaps (name_pairs[i].uscore); + + if (strcmp (uscore, name_pairs[i].uscore) != 0) + { + g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n", + name_pairs[i].wincaps, name_pairs[i].uscore, + uscore); + exit (1); + } + + if (strcmp (wincaps, name_pairs[i].wincaps) != 0) + { + g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n", + name_pairs[i].uscore, name_pairs[i].wincaps, + wincaps); + exit (1); + } + + g_free (uscore); + g_free (wincaps); + + ++i; + } + return TRUE; } -- cgit From 583994cb3b7f5562fb7b8c37b4cb0d5af78e4ce2 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 17 Sep 2003 03:52:07 +0000 Subject: 2003-09-15 Havoc Pennington * dbus/dbus-pending-call.c: add the get/set object data boilerplate as for DBusConnection, etc. Use generic object data for the notify callback. * glib/dbus-gparser.c (parse_node): parse child nodes * tools/dbus-viewer.c: more hacking on the dbus-viewer * glib/dbus-gutils.c (_dbus_gutils_split_path): add a file to contain functions shared between the convenience lib and the installed lib * glib/Makefile.am (libdbus_glib_1_la_LDFLAGS): add -export-symbols-regex to the GLib library * dbus/dbus-object-tree.c (_dbus_object_tree_dispatch_and_unlock): fix the locking in here, and add a default handler for Introspect() that just returns sub-nodes. 2003-09-14 Havoc Pennington * glib/dbus-gthread.c (dbus_g_thread_init): rename to make g_foo rather than gfoo consistent * glib/dbus-gproxy.h: delete for now, move contents to dbus-glib.h, because the include files don't work right since we aren't in the dbus/ subdir. * glib/dbus-gproxy.c (dbus_gproxy_send): finish implementing (dbus_gproxy_end_call): finish (dbus_gproxy_begin_call): finish * glib/dbus-gmain.c (dbus_set_g_error): new * glib/dbus-gobject.c (handle_introspect): include information about child nodes in the introspection * dbus/dbus-connection.c (dbus_connection_list_registered): new function to help in implementation of introspection * dbus/dbus-object-tree.c (_dbus_object_tree_list_registered_and_unlock): new function 2003-09-12 Havoc Pennington * glib/dbus-gidl.h: add common base class for all the foo_info types * tools/dbus-viewer.c: add GTK-based introspection UI thingy similar to kdcop * test/Makefile.am: try test srcdir -ef . in addition to test srcdir = ., one of them should work (yeah lame) * glib/Makefile.am: build the "idl" parser stuff as a convenience library * glib/dbus-gparser.h: make description_load routines return NodeInfo* not Parser* * Makefile.am (SUBDIRS): build test dir after all library dirs * configure.in: add GTK+ detection --- glib/dbus-gobject.c | 89 +++++++++++++++++++---------------------------------- 1 file changed, 32 insertions(+), 57 deletions(-) (limited to 'glib/dbus-gobject.c') diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index b0f6c139..6e65770f 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -24,6 +24,7 @@ #include #include "dbus-glib.h" #include "dbus-gtest.h" +#include "dbus-gutils.h" #include /** @@ -102,6 +103,7 @@ gobject_unregister_function (DBusConnection *connection, object = G_OBJECT (user_data); + /* FIXME */ } @@ -187,6 +189,15 @@ handle_introspect (DBusConnection *connection, unsigned int i; GType last_type; DBusMessage *ret; + char **path; + char **children; + + if (!dbus_message_get_path_decomposed (message, &path)) + g_error ("Out of memory"); + + if (!dbus_connection_list_registered (connection, (const char**) path, + &children)) + g_error ("Out of memory"); xml = g_string_new (NULL); @@ -268,13 +279,23 @@ handle_introspect (DBusConnection *connection, g_free (specs); + /* Append child nodes */ + + i = 0; + while (children[i]) + { + g_string_append_printf (xml, " \n", + children[i]); + ++i; + } + /* Close the XML, and send it to the requesting app */ g_string_append (xml, "\n"); ret = dbus_message_new_method_return (message); if (ret == NULL) - g_error ("out of memory"); + g_error ("Out of memory"); dbus_message_append_args (message, DBUS_TYPE_STRING, xml->str, @@ -285,6 +306,9 @@ handle_introspect (DBusConnection *connection, g_string_free (xml, TRUE); + dbus_free_string_array (path); + dbus_free_string_array (children); + return DBUS_HANDLER_RESULT_HANDLED; } @@ -642,15 +666,15 @@ static DBusObjectPathVTable gobject_dbus_vtable = { * class_init() for the object class. * * Once introspection information has been installed, instances of the - * object registered with dbus_connection_register_gobject() can have + * object registered with dbus_connection_register_g_object() can have * their methods invoked remotely. * * @param object_class class struct of the object * @param info introspection data generated by dbus-glib-tool */ void -dbus_gobject_class_install_info (GObjectClass *object_class, - const DBusGObjectInfo *info) +dbus_g_object_class_install_info (GObjectClass *object_class, + const DBusGObjectInfo *info) { g_return_if_fail (G_IS_OBJECT_CLASS (object_class)); @@ -666,55 +690,6 @@ dbus_gobject_class_install_info (GObjectClass *object_class, g_static_mutex_unlock (&info_hash_mutex); } -static char** -split_path (const char *path) -{ - int len; - char **split; - int n_components; - int i, j, comp; - - len = strlen (path); - - n_components = 0; - i = 0; - while (i < len) - { - if (path[i] == '/') - n_components += 1; - ++i; - } - - split = g_new0 (char*, n_components + 1); - - comp = 0; - i = 0; - while (i < len) - { - if (path[i] == '/') - ++i; - j = i; - - while (j < len && path[j] != '/') - ++j; - - /* Now [i, j) is the path component */ - g_assert (i < j); - g_assert (path[i] != '/'); - g_assert (j == len || path[j] == '/'); - - split[comp] = g_strndup (&path[i], j - i + 1); - - split[comp][j-i] = '\0'; - - ++comp; - i = j; - } - g_assert (i == len); - - return split; -} - /** * Registers a GObject at the given path. Properties, methods, and signals * of the object can then be accessed remotely. Methods are only available @@ -729,9 +704,9 @@ split_path (const char *path) * @param object the object */ void -dbus_connection_register_gobject (DBusConnection *connection, - const char *at_path, - GObject *object) +dbus_connection_register_g_object (DBusConnection *connection, + const char *at_path, + GObject *object) { char **split; @@ -739,7 +714,7 @@ dbus_connection_register_gobject (DBusConnection *connection, g_return_if_fail (at_path != NULL); g_return_if_fail (G_IS_OBJECT (object)); - split = split_path (at_path); + split = _dbus_gutils_split_path (at_path); if (!dbus_connection_register_object_path (connection, (const char**) split, -- cgit