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 --- ChangeLog | 66 ++++++++++++ Makefile.am | 2 +- configure.in | 30 ++++++ dbus/dbus-connection-internal.h | 5 +- dbus/dbus-connection.c | 28 ++++- dbus/dbus-connection.h | 3 + dbus/dbus-internals.h | 3 +- dbus/dbus-object-tree.c | 164 ++++++++++++++++++++++++++--- dbus/dbus-object-tree.h | 4 +- dbus/dbus-pending-call.c | 171 ++++++++++++++++++++++++++---- dbus/dbus-pending-call.h | 11 +- dbus/dbus-threads.c | 1 + doc/TODO | 4 + glib/Makefile.am | 29 ++++-- glib/dbus-gidl.c | 226 ++++++++++++++++++++++++++++++---------- glib/dbus-gidl.h | 26 ++++- glib/dbus-glib.h | 71 +++++++++++-- glib/dbus-gloader-expat.c | 19 ++-- glib/dbus-gmain.c | 41 ++++++++ glib/dbus-gobject.c | 89 ++++++---------- glib/dbus-gparser.c | 8 ++ glib/dbus-gparser.h | 10 +- glib/dbus-gproxy.c | 101 +++++++++++++++--- glib/dbus-gtest.c | 4 + glib/dbus-gtest.h | 1 + glib/dbus-gthread.c | 2 +- test/Makefile.am | 2 +- test/glib/test-profile.c | 2 +- test/glib/test-thread-client.c | 2 +- test/glib/test-thread-server.c | 2 +- tools/Makefile.am | 18 +++- 31 files changed, 944 insertions(+), 201 deletions(-) diff --git a/ChangeLog b/ChangeLog index a4dba23f..caa4a754 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,69 @@ +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 + 2003-09-07 Havoc Pennington * Make Doxygen contented. diff --git a/Makefile.am b/Makefile.am index 7384af0d..5bb5ae6a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ if DBUS_USE_MCS endif -SUBDIRS=dbus bus test doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) tools +SUBDIRS=dbus bus doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) test tools pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = dbus-1.pc $(GLIB_PC) diff --git a/configure.in b/configure.in index c403fd8c..e81a8d6a 100644 --- a/configure.in +++ b/configure.in @@ -24,6 +24,7 @@ AC_HEADER_STDC AC_ARG_ENABLE(qt, [ --enable-qt enable Qt-friendly client library],enable_qt=$enableval,enable_qt=auto) AC_ARG_ENABLE(glib, [ --enable-glib enable GLib-friendly client library],enable_glib=$enableval,enable_glib=auto) +AC_ARG_ENABLE(gtk, [ --enable-gtk enable GTK-requiring executables],enable_gtk=$enableval,enable_gtk=auto) AC_ARG_ENABLE(tests, [ --enable-tests enable unit test code],enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE) AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no) AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE) @@ -577,6 +578,34 @@ DBUS_GLIB_TOOL_LIBS=$XML_LIBS AC_SUBST(DBUS_GLIB_TOOL_CFLAGS) AC_SUBST(DBUS_GLIB_TOOL_LIBS) +# GTK detection +if test x$have_glib = xno ; then + AC_MSG_WARN([Can't use GTK+ since GLib not enabled]) + have_gtk=no +else + PKG_CHECK_MODULES(DBUS_GTK, gtk+-2.0, have_gtk=yes, have_gtk=no) +fi + +if test x$have_gtk = xno ; then + AC_MSG_WARN([GTK+ development libraries not found]) +fi + +if test x$enable_gtk = xyes; then + if test x$have_gtk = xno; then + AC_MSG_ERROR([GTK+ explicitly required, and GTK+ development libraries not found]) + fi +fi + +if test x$enable_gtk = xno; then + have_gtk=no; +fi + +AM_CONDITIONAL(HAVE_GTK, test x$have_gtk = xyes) + +dnl Gtk flags +AC_SUBST(DBUS_GTK_CFLAGS) +AC_SUBST(DBUS_GTK_LIBS) + # Qt detection have_qt=no AC_MSG_CHECKING([for qglobal.h]) @@ -885,6 +914,7 @@ echo " Building checks: ${enable_checks} Building Qt bindings: ${have_qt} Building GLib bindings: ${have_glib} + Building GTK+ tools: ${have_gtk} Building X11 code: ${enable_x11} Building documentation: ${enable_docs} Using XML parser: ${with_xml} diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 5a04dece..b19ab636 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -30,6 +30,7 @@ #include #include #include +#include DBUS_BEGIN_DECLS; @@ -104,9 +105,9 @@ struct DBusPendingCall { DBusAtomic refcount; /**< reference count */ + DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ + DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */ - void *user_data; /**< user data for function */ - DBusFreeFunction free_user_data; /**< free the user data */ DBusConnection *connection; /**< Connections we're associated with */ DBusMessage *reply; /**< Reply (after we've received it) */ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index bab6ffd8..b55f270c 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -3101,7 +3101,6 @@ dbus_connection_register_object_path (DBusConnection *connection, * path. You can use this to establish a default message handling * policy for a whole "subdirectory." * - * * @param connection the connection * @param path #NULL-terminated array of path elements * @param vtable the virtual table @@ -3136,6 +3135,7 @@ dbus_connection_register_fallback (DBusConnection *connection, /** * Unregisters the handler registered with exactly the given path. * It's a bug to call this function for a path that isn't registered. + * Can unregister both fallback paths and object paths. * * @param connection the connection * @param path the #NULL-terminated array of path elements @@ -3154,6 +3154,32 @@ dbus_connection_unregister_object_path (DBusConnection *connection, path); } +/** + * Lists the registered fallback handlers and object path handlers at + * the given parent_path. The returned array should be freed with + * dbus_free_string_array(). + * + * @param connection the connection + * @param parent_path the path to list the child handlers of + * @param child_entries returns #NULL-terminated array of children + * @returns #FALSE if no memory to allocate the child entries + */ +dbus_bool_t +dbus_connection_list_registered (DBusConnection *connection, + const char **parent_path, + char ***child_entries) +{ + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (parent_path != NULL, FALSE); + _dbus_return_val_if_fail (child_entries != NULL, FALSE); + + CONNECTION_LOCK (connection); + + return _dbus_object_tree_list_registered_and_unlock (connection->objects, + parent_path, + child_entries); +} + static DBusDataSlotAllocator slot_allocator; _DBUS_DEFINE_GLOBAL_LOCK (connection_slots); diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index abc88056..a4212c74 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -240,6 +240,9 @@ dbus_bool_t dbus_connection_register_fallback (DBusConnection void dbus_connection_unregister_object_path (DBusConnection *connection, const char **path); +dbus_bool_t dbus_connection_list_registered (DBusConnection *connection, + const char **parent_path, + char ***child_entries); DBUS_END_DECLS; diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 06a011e3..b3010355 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -230,13 +230,14 @@ extern int _dbus_current_generation; _DBUS_DECLARE_GLOBAL_LOCK (list); _DBUS_DECLARE_GLOBAL_LOCK (connection_slots); +_DBUS_DECLARE_GLOBAL_LOCK (pending_call_slots); _DBUS_DECLARE_GLOBAL_LOCK (server_slots); _DBUS_DECLARE_GLOBAL_LOCK (message_slots); _DBUS_DECLARE_GLOBAL_LOCK (atomic); _DBUS_DECLARE_GLOBAL_LOCK (bus); _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs); _DBUS_DECLARE_GLOBAL_LOCK (system_users); -#define _DBUS_N_GLOBAL_LOCKS (8) +#define _DBUS_N_GLOBAL_LOCKS (9) dbus_bool_t _dbus_threads_init_debug (void); diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index 9922dec4..07d3ae59 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -25,6 +25,7 @@ #include "dbus-internals.h" #include "dbus-hash.h" #include "dbus-protocol.h" +#include "dbus-string.h" #include #include @@ -34,13 +35,7 @@ * @brief DBusObjectTree is used by DBusConnection to track the object tree * * Types and functions related to DBusObjectTree. These - * are all internal. - * - * @todo this is totally broken, because of the following case: - * /foo, /foo/bar, /foo/baz - * if we then receive a message to /foo/baz we need to hand it - * to /foo/baz and /foo but not /foo/bar. So we should be - * using a real tree structure as with GConfListeners. + * are all library-internal. * * @{ */ @@ -542,6 +537,101 @@ _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree) tree->root = NULL; } +static dbus_bool_t +_dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree, + const char **parent_path, + char ***child_entries) +{ + DBusObjectSubtree *subtree; + char **retval; + + _dbus_assert (parent_path != NULL); + _dbus_assert (child_entries != NULL); + + *child_entries = NULL; + + subtree = find_subtree (tree, parent_path, NULL); + if (subtree == NULL) + { + retval = dbus_new0 (char *, 1); + if (retval == NULL) + goto out; + } + else + { + int i; + retval = dbus_new0 (char*, subtree->n_subtrees + 1); + if (retval == NULL) + goto out; + i = 0; + while (i < subtree->n_subtrees) + { + retval[i] = _dbus_strdup (subtree->subtrees[i]->name); + if (retval[i] == NULL) + { + dbus_free_string_array (retval); + retval = NULL; + goto out; + } + ++i; + } + } + + out: + + *child_entries = retval; + return retval != NULL; +} + +static DBusHandlerResult +handle_default_introspect_unlocked (DBusObjectTree *tree, + DBusMessage *message, + const char **path) +{ + DBusString xml; + DBusHandlerResult result; + char **children; + int i; + + if (!dbus_message_is_method_call (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE, + "Introspect")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!_dbus_string_init (&xml)) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + + children = NULL; + if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children)) + goto out; + + if (!_dbus_string_append (&xml, "\n")) + goto out; + + i = 0; + while (children[i] != NULL) + { + if (!_dbus_string_append_printf (&xml, " \n", + children[i])) + goto out; + + ++i; + } + + if (!_dbus_string_append (&xml, "\n")) + goto out; + + result = DBUS_HANDLER_RESULT_HANDLED; + + out: + _dbus_string_free (&xml); + dbus_free_string_array (children); + + return result; +} + /** * Tries to dispatch a message by directing it to handler for the * object path listed in the message header, if any. Messages are @@ -572,12 +662,23 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, path = NULL; if (!dbus_message_get_path_decomposed (message, &path)) { +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_unlock (tree->connection); + _dbus_verbose ("No memory to get decomposed path\n"); + return DBUS_HANDLER_RESULT_NEED_MEMORY; } if (path == NULL) { +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_unlock (tree->connection); + _dbus_verbose ("No path field in message\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -649,30 +750,40 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, message, user_data); - if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) - goto free_and_return; - #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif _dbus_connection_lock (tree->connection); + + if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + goto free_and_return; } link = next; } + free_and_return: + + if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + { + /* This hardcoded default handler does a minimal Introspect() + */ + result = handle_default_introspect_unlocked (tree, message, + (const char**) path); + } + #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif _dbus_connection_unlock (tree->connection); - - free_and_return: + while (list != NULL) { link = _dbus_list_get_first_link (&list); _dbus_object_subtree_unref (link->data); _dbus_list_remove_link (&list, link); } + dbus_free_string_array (path); return result; @@ -770,6 +881,35 @@ _dbus_object_subtree_unref (DBusObjectSubtree *subtree) } } +/** + * Lists the registered fallback handlers and object path handlers at + * the given parent_path. The returned array should be freed with + * dbus_free_string_array(). + * + * @param connection the connection + * @param parent_path the path to list the child handlers of + * @param child_entries returns #NULL-terminated array of children + * @returns #FALSE if no memory to allocate the child entries + */ +dbus_bool_t +_dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, + const char **parent_path, + char ***child_entries) +{ + dbus_bool_t result; + + result = _dbus_object_tree_list_registered_unlocked (tree, + parent_path, + child_entries); + +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_unlock (tree->connection); + + return result; +} + /** @} */ #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h index 21d8b5f1..bf34d972 100644 --- a/dbus/dbus-object-tree.h +++ b/dbus/dbus-object-tree.h @@ -44,7 +44,9 @@ DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree DBusMessage *message); void _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree); - +dbus_bool_t _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, + const char **parent_path, + char ***child_entries); DBUS_END_DECLS; #endif /* DBUS_OBJECT_TREE_H */ diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c index 2b6021e9..dad444e3 100644 --- a/dbus/dbus-pending-call.c +++ b/dbus/dbus-pending-call.c @@ -38,6 +38,8 @@ * @{ */ +static dbus_int32_t notify_user_data_slot = -1; + /** * Creates a new pending reply object. * @@ -58,11 +60,17 @@ _dbus_pending_call_new (DBusConnection *connection, if (timeout_milliseconds == -1) timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; + + if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot)) + return NULL; pending = dbus_new (DBusPendingCall, 1); if (pending == NULL) - return NULL; + { + dbus_pending_call_free_data_slot (¬ify_user_data_slot); + return NULL; + } timeout = _dbus_timeout_new (timeout_milliseconds, timeout_handler, @@ -70,6 +78,7 @@ _dbus_pending_call_new (DBusConnection *connection, if (timeout == NULL) { + dbus_pending_call_free_data_slot (¬ify_user_data_slot); dbus_free (pending); return NULL; } @@ -77,6 +86,8 @@ _dbus_pending_call_new (DBusConnection *connection, pending->refcount.value = 1; pending->connection = connection; pending->timeout = timeout; + + _dbus_data_slot_list_init (&pending->slot_list); return pending; } @@ -94,7 +105,13 @@ _dbus_pending_call_notify (DBusPendingCall *pending) pending->completed = TRUE; if (pending->function) - (* pending->function) (pending, pending->user_data); + { + void *user_data; + user_data = dbus_pending_call_get_data (pending, + notify_user_data_slot); + + (* pending->function) (pending, user_data); + } } /** @} */ @@ -154,9 +171,8 @@ dbus_pending_call_unref (DBusPendingCall *pending) _dbus_assert (!pending->timeout_added); /* this assumes we aren't holding connection lock... */ - if (pending->free_user_data) - (* pending->free_user_data) (pending->user_data); - + _dbus_data_slot_list_free (&pending->slot_list); + if (pending->timeout != NULL) _dbus_timeout_unref (pending->timeout); @@ -174,6 +190,8 @@ dbus_pending_call_unref (DBusPendingCall *pending) } dbus_free (pending); + + dbus_pending_call_free_data_slot (¬ify_user_data_slot); } } @@ -185,28 +203,24 @@ dbus_pending_call_unref (DBusPendingCall *pending) * @param function notifier function * @param user_data data to pass to notifier function * @param free_user_data function to free the user data - * + * @returns #FALSE if not enough memory */ -void +dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall *pending, DBusPendingCallNotifyFunction function, void *user_data, DBusFreeFunction free_user_data) { - DBusFreeFunction old_free_func; - void *old_user_data; - - _dbus_return_if_fail (pending != NULL); + _dbus_return_val_if_fail (pending != NULL, FALSE); - old_free_func = pending->free_user_data; - old_user_data = pending->user_data; - - pending->user_data = user_data; - pending->free_user_data = free_user_data; + /* could invoke application code! */ + if (!dbus_pending_call_set_data (pending, notify_user_data_slot, + user_data, free_user_data)) + return FALSE; + pending->function = function; - if (old_free_func) - (* old_free_func) (old_user_data); + return TRUE; } /** @@ -230,9 +244,10 @@ dbus_pending_call_cancel (DBusPendingCall *pending) * Checks whether the pending call has received a reply * yet, or not. * + * @todo not thread safe? I guess it has to lock though it sucks + * * @param pending the pending call - * @returns #TRUE if a reply has been received - */ + * @returns #TRUE if a reply has been received */ dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending) { @@ -245,6 +260,9 @@ dbus_pending_call_get_completed (DBusPendingCall *pending) * have to keep a reference count on the pending call (or add one * to the message). * + * @todo not thread safe? I guess it has to lock though it sucks + * @todo maybe to make this threadsafe, it should be steal_reply(), i.e. only one thread can ever get the message + * * @param pending the pending call * @returns the reply message or #NULL. */ @@ -260,6 +278,9 @@ dbus_pending_call_get_reply (DBusPendingCall *pending) * main loop or process other messages, it simply waits for the reply * in question. * + * If the pending call is already completed, this function returns + * immediately. + * * @todo when you start blocking, the timeout is reset, but it should * really only use time remaining since the pending call was created. * @@ -269,6 +290,9 @@ void dbus_pending_call_block (DBusPendingCall *pending) { DBusMessage *message; + + if (dbus_pending_call_get_completed (pending)) + return; message = _dbus_connection_block_for_reply (pending->connection, pending->reply_serial, @@ -279,6 +303,113 @@ dbus_pending_call_block (DBusPendingCall *pending) dbus_message_unref (message); } +static DBusDataSlotAllocator slot_allocator; +_DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots); + +/** + * Allocates an integer ID to be used for storing application-specific + * data on any DBusPendingCall. The allocated ID may then be used + * with dbus_pending_call_set_data() and dbus_pending_call_get_data(). + * The passed-in slot must be initialized to -1, and is filled in + * with the slot ID. If the passed-in slot is not -1, it's assumed + * to be already allocated, and its refcount is incremented. + * + * The allocated slot is global, i.e. all DBusPendingCall objects will + * have a slot with the given integer ID reserved. + * + * @param slot_p address of a global variable storing the slot + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p) +{ + return _dbus_data_slot_allocator_alloc (&slot_allocator, + _DBUS_LOCK_NAME (pending_call_slots), + slot_p); +} + +/** + * Deallocates a global ID for #DBusPendingCall data slots. + * dbus_pending_call_get_data() and dbus_pending_call_set_data() may + * no longer be used with this slot. Existing data stored on existing + * DBusPendingCall objects will be freed when the #DBusPendingCall is + * finalized, but may not be retrieved (and may only be replaced if + * someone else reallocates the slot). When the refcount on the + * passed-in slot reaches 0, it is set to -1. + * + * @param slot_p address storing the slot to deallocate + */ +void +dbus_pending_call_free_data_slot (dbus_int32_t *slot_p) +{ + _dbus_return_if_fail (*slot_p >= 0); + + _dbus_data_slot_allocator_free (&slot_allocator, slot_p); +} + +/** + * Stores a pointer on a #DBusPendingCall, along + * with an optional function to be used for freeing + * the data when the data is set again, or when + * the pending call is finalized. The slot number + * must have been allocated with dbus_pending_call_allocate_data_slot(). + * + * @param pending the pending_call + * @param slot the slot number + * @param data the data to store + * @param free_data_func finalizer function for the data + * @returns #TRUE if there was enough memory to store the data + */ +dbus_bool_t +dbus_pending_call_set_data (DBusPendingCall *pending, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func) +{ + DBusFreeFunction old_free_func; + void *old_data; + dbus_bool_t retval; + + _dbus_return_val_if_fail (pending != NULL, FALSE); + _dbus_return_val_if_fail (slot >= 0, FALSE); + + retval = _dbus_data_slot_list_set (&slot_allocator, + &pending->slot_list, + slot, data, free_data_func, + &old_free_func, &old_data); + + if (retval) + { + if (old_free_func) + (* old_free_func) (old_data); + } + + return retval; +} + +/** + * Retrieves data previously set with dbus_pending_call_set_data(). + * The slot must still be allocated (must not have been freed). + * + * @param pending the pending_call + * @param slot the slot to get data from + * @returns the data, or #NULL if not found + */ +void* +dbus_pending_call_get_data (DBusPendingCall *pending, + dbus_int32_t slot) +{ + void *res; + + _dbus_return_val_if_fail (pending != NULL, NULL); + + res = _dbus_data_slot_list_get (&slot_allocator, + &pending->slot_list, + slot); + + return res; +} + /** @} */ #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h index 81af872f..4f1e92c0 100644 --- a/dbus/dbus-pending-call.h +++ b/dbus/dbus-pending-call.h @@ -35,7 +35,7 @@ DBUS_BEGIN_DECLS; void dbus_pending_call_ref (DBusPendingCall *pending); void dbus_pending_call_unref (DBusPendingCall *pending); -void dbus_pending_call_set_notify (DBusPendingCall *pending, +dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall *pending, DBusPendingCallNotifyFunction function, void *user_data, DBusFreeFunction free_user_data); @@ -44,6 +44,15 @@ dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pen DBusMessage* dbus_pending_call_get_reply (DBusPendingCall *pending); void dbus_pending_call_block (DBusPendingCall *pending); +dbus_bool_t dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p); +void dbus_pending_call_free_data_slot (dbus_int32_t *slot_p); +dbus_bool_t dbus_pending_call_set_data (DBusPendingCall *pending, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func); +void* dbus_pending_call_get_data (DBusPendingCall *pending, + dbus_int32_t slot); + DBUS_END_DECLS; #endif /* DBUS_PENDING_CALL_H */ diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index c5ce638f..2170c465 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -223,6 +223,7 @@ init_global_locks (void) #define LOCK_ADDR(name) (& _dbus_lock_##name) LOCK_ADDR (list), LOCK_ADDR (connection_slots), + LOCK_ADDR (pending_call_slots), LOCK_ADDR (server_slots), LOCK_ADDR (message_slots), LOCK_ADDR (atomic), diff --git a/doc/TODO b/doc/TODO index 6b308d39..5c2b149c 100644 --- a/doc/TODO +++ b/doc/TODO @@ -82,3 +82,7 @@ - Nuke the org.freedesktop.Broadcast service; instead, just broadcast messages of type signal + + - I don't want to introduce DBusObject, but refcounting and object + data could still be factored out into an internal "base class" + perhaps. diff --git a/glib/Makefile.am b/glib/Makefile.am index 65d71cfd..a45aa593 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -5,8 +5,7 @@ dbusincludedir=$(includedir)/dbus-1.0/dbus lib_LTLIBRARIES=libdbus-glib-1.la dbusinclude_HEADERS= \ - dbus-glib.h \ - dbus-gproxy.h + dbus-glib.h libdbus_glib_1_la_SOURCES = \ dbus-gmain.c \ @@ -14,23 +13,36 @@ libdbus_glib_1_la_SOURCES = \ dbus-gproxy.c \ dbus-gtest.c \ dbus-gtest.h \ - dbus-gthread.c + dbus-gthread.c \ + dbus-gutils.c \ + dbus-gutils.h libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la +## don't export symbols that start with "_" (we use this +## convention for internal symbols) +libdbus_glib_1_la_LDFLAGS= -export-symbols-regex "^[^_].*" -bin_PROGRAMS=dbus-glib-tool +# convenience lib used here and by dbus-viewer +noinst_LTLIBRARIES=libdbus-gtool.la -dbus_glib_tool_SOURCES = \ +libdbus_gtool_la_SOURCES = \ dbus-gidl.c \ dbus-gidl.h \ - dbus-glib-tool.c \ dbus-gloader-expat.c \ dbus-gparser.c \ dbus-gparser.h \ - dbus-gtool-test.h + dbus-gutils.c \ + dbus-gutils.h +libdbus_gtool_la_LIBADD = libdbus-glib-1.la -dbus_glib_tool_LDADD= $(DBUS_GLIB_TOOL_LIBS) libdbus-glib-1.la $(top_builddir)/dbus/libdbus-1.la +bin_PROGRAMS=dbus-glib-tool + +dbus_glib_tool_SOURCES = \ + dbus-glib-tool.c \ + dbus-gtool-test.h + +dbus_glib_tool_LDADD= $(DBUS_GLIB_TOOL_LIBS) libdbus-gtool.la if DBUS_BUILD_TESTS @@ -54,3 +66,4 @@ else TESTS= endif + diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c index b867d178..596b43ca 100644 --- a/glib/dbus-gidl.c +++ b/glib/dbus-gidl.c @@ -26,43 +26,131 @@ #ifndef DOXYGEN_SHOULD_SKIP_THIS -struct NodeInfo +struct BaseInfo { - int refcount; + unsigned int refcount : 28; + unsigned int type : 4; char *name; +}; + +struct NodeInfo +{ + BaseInfo base; GSList *interfaces; + GSList *nodes; }; struct InterfaceInfo { - int refcount; - char *name; + BaseInfo base; + /* Since we have BaseInfo now these could be one list */ GSList *methods; GSList *signals; }; struct MethodInfo { - int refcount; + BaseInfo base; GSList *args; - char *name; }; struct SignalInfo { - int refcount; + BaseInfo base; GSList *args; - char *name; }; struct ArgInfo { - int refcount; - char *name; + BaseInfo base; int type; ArgDirection direction; }; +void +base_info_ref (BaseInfo *info) +{ + g_return_if_fail (info != NULL); + g_return_if_fail (info->refcount > 0); + + info->refcount += 1; +} + +static void +base_info_free (void *ptr) +{ + BaseInfo *info; + + info = ptr; + + g_free (info->name); + g_free (info); +} + +void +base_info_unref (BaseInfo *info) +{ + g_return_if_fail (info != NULL); + g_return_if_fail (info->refcount > 0); + + /* This is sort of bizarre, BaseInfo was tacked on later */ + + switch (info->type) + { + case INFO_TYPE_NODE: + node_info_unref ((NodeInfo*) info); + break; + case INFO_TYPE_INTERFACE: + interface_info_unref ((InterfaceInfo*) info); + break; + case INFO_TYPE_SIGNAL: + signal_info_unref ((SignalInfo*) info); + break; + case INFO_TYPE_METHOD: + method_info_unref ((MethodInfo*) info); + break; + case INFO_TYPE_ARG: + arg_info_unref ((ArgInfo*) info); + break; + } +} + +InfoType +base_info_get_type (BaseInfo *info) +{ + return info->type; +} + +const char* +base_info_get_name (BaseInfo *info) +{ + return info->name; +} + +void +base_info_set_name (BaseInfo *info, + const char *name) +{ + char *old; + + old = info->name; + info->name = g_strdup (name); + g_free (old); +} + +GType +base_info_get_gtype (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("BaseInfo", + (GBoxedCopyFunc) base_info_ref, + (GBoxedFreeFunc) base_info_unref); + + return our_type; +} + static void free_interface_list (GSList **interfaces_p) { @@ -77,6 +165,20 @@ free_interface_list (GSList **interfaces_p) *interfaces_p = NULL; } +static void +free_node_list (GSList **nodes_p) +{ + GSList *tmp; + tmp = *nodes_p; + while (tmp != NULL) + { + node_info_unref (tmp->data); + tmp = tmp->next; + } + g_slist_free (*nodes_p); + *nodes_p = NULL; +} + static void free_method_list (GSList **methods_p) { @@ -113,34 +215,35 @@ node_info_new (const char *name) /* name can be NULL */ info = g_new0 (NodeInfo, 1); - info->refcount = 1; - info->name = g_strdup (name); - + info->base.refcount = 1; + info->base.name = g_strdup (name); + info->base.type = INFO_TYPE_NODE; + return info; } void node_info_ref (NodeInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void node_info_unref (NodeInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { free_interface_list (&info->interfaces); - g_free (info->name); - g_free (info); + free_node_list (&info->nodes); + base_info_free (info); } } const char* node_info_get_name (NodeInfo *info) { - return info->name; + return info->base.name; } GSList* @@ -157,6 +260,19 @@ node_info_add_interface (NodeInfo *info, info->interfaces = g_slist_append (info->interfaces, interface); } +GSList* +node_info_get_nodes (NodeInfo *info) +{ + return info->nodes; +} + +void +node_info_add_node (NodeInfo *info, + NodeInfo *node) +{ + node_info_ref (node); + info->nodes = g_slist_append (info->nodes, node); +} InterfaceInfo* interface_info_new (const char *name) @@ -164,35 +280,35 @@ interface_info_new (const char *name) InterfaceInfo *info; info = g_new0 (InterfaceInfo, 1); - info->refcount = 1; - info->name = g_strdup (name); - + info->base.refcount = 1; + info->base.name = g_strdup (name); + info->base.type = INFO_TYPE_INTERFACE; + return info; } void interface_info_ref (InterfaceInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void interface_info_unref (InterfaceInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { free_method_list (&info->methods); free_signal_list (&info->signals); - g_free (info->name); - g_free (info); + base_info_free (info); } } const char* interface_info_get_name (InterfaceInfo *info) { - return info->name; + return info->base.name; } GSList* @@ -243,34 +359,34 @@ method_info_new (const char *name) MethodInfo *info; info = g_new0 (MethodInfo, 1); - info->refcount = 1; - info->name = g_strdup (name); - + info->base.refcount = 1; + info->base.name = g_strdup (name); + info->base.type = INFO_TYPE_METHOD; + return info; } void method_info_ref (MethodInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void method_info_unref (MethodInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { free_arg_list (&info->args); - g_free (info->name); - g_free (info); + base_info_free (info); } } const char* method_info_get_name (MethodInfo *info) { - return info->name; + return info->base.name; } GSList* @@ -293,34 +409,34 @@ signal_info_new (const char *name) SignalInfo *info; info = g_new0 (SignalInfo, 1); - info->refcount = 1; - info->name = g_strdup (name); - + info->base.refcount = 1; + info->base.name = g_strdup (name); + info->base.type = INFO_TYPE_SIGNAL; + return info; } void signal_info_ref (SignalInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void signal_info_unref (SignalInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { free_arg_list (&info->args); - g_free (info->name); - g_free (info); + base_info_free (info); } } const char* signal_info_get_name (SignalInfo *info) { - return info->name; + return info->base.name; } GSList* @@ -345,10 +461,11 @@ arg_info_new (const char *name, ArgInfo *info; info = g_new0 (ArgInfo, 1); - info->refcount = 1; - + info->base.refcount = 1; + info->base.type = INFO_TYPE_ARG; + /* name can be NULL */ - info->name = g_strdup (name); + info->base.name = g_strdup (name); info->direction = direction; info->type = type; @@ -358,23 +475,22 @@ arg_info_new (const char *name, void arg_info_ref (ArgInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void arg_info_unref (ArgInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { - g_free (info->name); - g_free (info); + base_info_free (info); } } const char* arg_info_get_name (ArgInfo *info) { - return info->name; + return info->base.name; } int diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index 7a667240..f95abfbd 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -27,10 +27,11 @@ #ifndef DOXYGEN_SHOULD_SKIP_THIS #include -#include +#include G_BEGIN_DECLS +typedef struct BaseInfo BaseInfo; typedef struct NodeInfo NodeInfo; typedef struct InterfaceInfo InterfaceInfo; typedef struct MethodInfo MethodInfo; @@ -43,13 +44,36 @@ typedef enum ARG_OUT } ArgDirection; +typedef enum +{ + INFO_TYPE_NODE, + INFO_TYPE_INTERFACE, + INFO_TYPE_METHOD, + INFO_TYPE_SIGNAL, + INFO_TYPE_ARG + +} InfoType; + +void base_info_ref (BaseInfo *info); +void base_info_unref (BaseInfo *info); +InfoType base_info_get_type (BaseInfo *info); +const char* base_info_get_name (BaseInfo *info); +void base_info_set_name (BaseInfo *info, + const char *name); +GType base_info_get_gtype (void); +#define BASE_INFO_TYPE (base_info_get_gtype ()) + + NodeInfo* node_info_new (const char *name); void node_info_ref (NodeInfo *info); void node_info_unref (NodeInfo *info); const char* node_info_get_name (NodeInfo *info); GSList* node_info_get_interfaces (NodeInfo *info); +GSList* node_info_get_nodes (NodeInfo *info); void node_info_add_interface (NodeInfo *info, InterfaceInfo *interface); +void node_info_add_node (NodeInfo *info, + NodeInfo *child); InterfaceInfo* interface_info_new (const char *name); void interface_info_ref (InterfaceInfo *info); diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 4015dd99..63d34485 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -2,6 +2,7 @@ /* dbus-glib.h GLib integration * * Copyright (C) 2002, 2003 CodeFactory AB + * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 1.2 * @@ -30,7 +31,22 @@ G_BEGIN_DECLS #define DBUS_INSIDE_DBUS_GLIB_H 1 -void dbus_gthread_init (void); +GQuark dbus_g_error_quark (void); +#define DBUS_GERROR dbus_g_error_quark () + +typedef enum +{ + /* FIXME map all the DBUS_ERROR to DBUS_GERROR, should + * probably be automated in some way, perhaps + * via lame perl script + */ + DBUS_GERROR_FAILED +} DBusGError; + +void dbus_set_g_error (GError **gerror, + DBusError *derror); + +void dbus_g_thread_init (void); void dbus_connection_setup_with_g_main (DBusConnection *connection, GMainContext *context); void dbus_server_setup_with_g_main (DBusServer *server, @@ -63,14 +79,57 @@ struct DBusGObjectInfo void *dbus_internal_padding2; /**< Reserved for expansion */ }; -void dbus_gobject_class_install_info (GObjectClass *object_class, - const DBusGObjectInfo *info); -void dbus_connection_register_gobject (DBusConnection *connection, - const char *at_path, - GObject *object); +void dbus_g_object_class_install_info (GObjectClass *object_class, + const DBusGObjectInfo *info); +void dbus_connection_register_g_object (DBusConnection *connection, + const char *at_path, + GObject *object); + + +typedef struct DBusGProxy DBusGProxy; + +DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, + const char *service_name, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, + const char *service_name, + const char *interface_name, + GError **error); +DBusGProxy* dbus_gproxy_new_for_object_path (DBusConnection *connection, + const char *path, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection, + const char *interface_name); +void dbus_gproxy_ref (DBusGProxy *proxy); +void dbus_gproxy_unref (DBusGProxy *proxy); +gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy, + const char *signal_name, + GCallback callback, + void *data, + GFreeFunc free_data_func, + GError **error); +DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...); +gboolean dbus_gproxy_end_call (DBusGProxy *proxy, + DBusPendingCall *pending, + GError **error, + int first_arg_type, + ...); +void dbus_gproxy_oneway_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...); +void dbus_gproxy_send (DBusGProxy *proxy, + DBusMessage *message, + dbus_uint32_t *client_serial); #undef DBUS_INSIDE_DBUS_GLIB_H G_END_DECLS #endif /* DBUS_GLIB_H */ + + + diff --git a/glib/dbus-gloader-expat.c b/glib/dbus-gloader-expat.c index 149e7117..01587d21 100644 --- a/glib/dbus-gloader-expat.c +++ b/glib/dbus-gloader-expat.c @@ -163,31 +163,32 @@ expat_CharacterDataHandler (void *userData, s, len); } -Parser* +NodeInfo* description_load_from_file (const char *filename, GError **error) { char *contents; gsize len; - Parser *parser; + NodeInfo *nodes; contents = NULL; if (!g_file_get_contents (filename, &contents, &len, error)) return NULL; - parser = description_load_from_string (contents, len, error); + nodes = description_load_from_string (contents, len, error); g_free (contents); - return parser; + return nodes; } -Parser* +NodeInfo* description_load_from_string (const char *str, int len, GError **error) { XML_Parser expat; ExpatParseContext context; + NodeInfo *nodes; g_return_val_if_fail (error == NULL || *error == NULL, NULL); @@ -242,8 +243,11 @@ description_load_from_string (const char *str, XML_ParserFree (expat); g_string_free (context.content, TRUE); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - return context.parser; + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + nodes = parser_get_nodes (context.parser); + node_info_ref (nodes); + parser_unref (context.parser); + return nodes; failed: g_return_val_if_fail (error == NULL || *error != NULL, NULL); @@ -255,3 +259,4 @@ description_load_from_string (const char *str, parser_unref (context.parser); return NULL; } + diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c index c33f47e8..2e5604dc 100644 --- a/glib/dbus-gmain.c +++ b/glib/dbus-gmain.c @@ -25,6 +25,10 @@ #include "dbus-glib.h" #include "dbus-gtest.h" +#include +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x + /** * @defgroup DBusGLib GLib bindings * @ingroup DBus @@ -494,6 +498,43 @@ dbus_server_setup_with_g_main (DBusServer *server, g_error ("Not enough memory to set up DBusServer for use with GLib"); } +/** + * The implementation of DBUS_GERROR error domain. See documentation + * for GError in GLib reference manual. + * + * @returns the error domain quark for use with GError + */ +GQuark +dbus_g_error_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("g-exec-error-quark"); + return quark; +} + + +/** + * Set a GError return location from a DBusError. + * + * @todo expand the DBUS_GERROR enum and take advantage of it here + * + * @param gerror location to store a GError, or #NULL + * @param derror the DBusError + */ +void +dbus_set_g_error (GError **gerror, + DBusError *derror) +{ + g_return_if_fail (derror != NULL); + g_return_if_fail (dbus_error_is_set (derror)); + + g_set_error (gerror, DBUS_GERROR, + DBUS_GERROR_FAILED, + _("D-BUS error %s: %s"), + derror->name, derror->message); +} + /** @} */ /* end of public API */ #ifdef DBUS_BUILD_TESTS 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, diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c index f7264b5e..16d17f3d 100644 --- a/glib/dbus-gparser.c +++ b/glib/dbus-gparser.c @@ -262,7 +262,15 @@ parse_node (Parser *parser, return FALSE; } + node = node_info_new (name); + + if (parser->node_stack != NULL) + { + node_info_add_node (parser->node_stack->data, + node); + } + parser->node_stack = g_slist_prepend (parser->node_stack, node); diff --git a/glib/dbus-gparser.h b/glib/dbus-gparser.h index 3e87165b..cc58e5e0 100644 --- a/glib/dbus-gparser.h +++ b/glib/dbus-gparser.h @@ -52,11 +52,11 @@ gboolean parser_content (Parser *parser, gboolean parser_finished (Parser *parser, GError **error); -Parser* description_load_from_file (const char *filename, - GError **error); -Parser* description_load_from_string (const char *str, - int len, - GError **error); +NodeInfo* description_load_from_file (const char *filename, + GError **error); +NodeInfo* description_load_from_string (const char *str, + int len, + GError **error); NodeInfo* parser_get_nodes (Parser *parser); diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 8951707b..59d86a31 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -20,7 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#include "dbus-gproxy.h" +#include "dbus-glib.h" /** * @addtogroup DBusGLibInternals @@ -165,23 +165,59 @@ dbus_gproxy_unref (DBusGProxy *proxy) * To collect the results of the call (which may be an error, * or a reply), use dbus_gproxy_end_call(). * + * @todo this particular function shouldn't die on out of memory, + * since you should be able to do a call with large arguments. + * * @param proxy a proxy for a remote interface * @param method the name of the method to invoke * @param first_arg_type type of the first argument * * @returns opaque pending call object - * - */ + * */ DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, const char *method, int first_arg_type, ...) { + DBusPendingCall *pending; + DBusMessage *message; + va_list args; + g_return_val_if_fail (proxy != NULL, NULL); LOCK_PROXY (proxy); + message = dbus_message_new_method_call (proxy->service, + proxy->interface, + proxy->path, + method); + if (message == NULL) + goto oom; + + va_start (args, first_arg_type); + if (!dbus_message_append_args_valist (message, first_arg_type, + args)) + goto oom; + va_end (args); + + if (!dbus_connection_send_with_reply (proxy->connection, + message, + &pending, + -1)) + goto oom; + UNLOCK_PROXY (proxy); + + return pending; + + oom: + /* FIXME we should create a pending call that's + * immediately completed with an error status without + * ever going on the wire. + */ + + g_error ("Out of memory"); + return NULL; } /** @@ -189,7 +225,9 @@ dbus_gproxy_begin_call (DBusGProxy *proxy, * initiated with dbus_gproxy_end_call(). This function will block if * the results haven't yet been received; use * dbus_pending_call_set_notify() to be notified asynchronously that a - * pending call has been completed. + * pending call has been completed. Use + * dbus_pending_call_get_completed() to check whether a call has been + * completed. If it's completed, it will not block. * * If the call results in an error, the error is set as normal for * GError and the function returns #FALSE. @@ -198,12 +236,15 @@ dbus_gproxy_begin_call (DBusGProxy *proxy, * method are stored in the provided varargs list. * The list should be terminated with DBUS_TYPE_INVALID. * + * This function doesn't affect the reference count of the + * #DBusPendingCall, the caller of dbus_gproxy_begin_call() still owns + * a reference. + * * @param proxy a proxy for a remote interface * @param pending the pending call from dbus_gproxy_begin_call() * @param error return location for an error * @param first_arg_type type of first "out" argument - * @returns #FALSE if an error is set - */ + * @returns #FALSE if an error is set */ gboolean dbus_gproxy_end_call (DBusGProxy *proxy, DBusPendingCall *pending, @@ -211,10 +252,37 @@ dbus_gproxy_end_call (DBusGProxy *proxy, int first_arg_type, ...) { + DBusMessage *message; + va_list args; + DBusError derror; + g_return_val_if_fail (proxy != NULL, FALSE); + g_return_val_if_fail (pending != NULL, FALSE); + LOCK_PROXY (proxy); + dbus_pending_call_block (pending); + message = dbus_pending_call_get_reply (pending); + + g_assert (message != NULL); + + dbus_error_init (&derror); + va_start (args, first_arg_type); + if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args)) + { + va_end (args); + goto error; + } + va_end (args); + UNLOCK_PROXY (proxy); + + return TRUE; + + error: + dbus_set_g_error (error, &derror); + dbus_error_free (&derror); + return FALSE; } /** @@ -224,18 +292,17 @@ dbus_gproxy_end_call (DBusGProxy *proxy, * dbus_connection_flush(). * * The message is modified to be addressed to the target interface. - * That is, a destination service field or whatever is needed - * will be added to the message. + * That is, a destination service field or whatever is needed will be + * added to the message. The basic point of this function is to add + * the necessary header fields, otherwise it's equivalent to + * dbus_connection_send(). * * This function adds a reference to the message, so the caller * still owns its original reference. - * - * @todo fix for sending to interfaces and object IDs * * @param proxy a proxy for a remote interface * @param message the message to address and send - * @param client_serial return location for message's serial, or #NULL - */ + * @param client_serial return location for message's serial, or #NULL */ void dbus_gproxy_send (DBusGProxy *proxy, DBusMessage *message, @@ -247,17 +314,19 @@ dbus_gproxy_send (DBusGProxy *proxy, if (proxy->service) { if (!dbus_message_set_destination (message, proxy->service)) - g_error ("Out of memory\n"); + g_error ("Out of memory"); } if (proxy->interface) { - /* FIXME */ + if (!dbus_message_set_interface (message, proxy->interface)) + g_error ("Out of memory"); } if (proxy->path) { - /* FIXME */ + if (!dbus_message_set_path (message, proxy->path)) + g_error ("Out of memory"); } - + if (!dbus_connection_send (proxy->connection, message, client_serial)) g_error ("Out of memory\n"); diff --git a/glib/dbus-gtest.c b/glib/dbus-gtest.c index b853d3ed..48cd13f0 100644 --- a/glib/dbus-gtest.c +++ b/glib/dbus-gtest.c @@ -56,6 +56,10 @@ dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir) else printf ("No test data!\n"); + printf ("%s: running utils tests\n", "dbus-glib-test"); + if (!_dbus_gutils_test (test_data_dir)) + die ("gutils"); + printf ("%s: running mainloop integration tests\n", "dbus-glib-test"); if (!_dbus_gmain_test (test_data_dir)) die ("gmain"); diff --git a/glib/dbus-gtest.h b/glib/dbus-gtest.h index 6a33bdae..1174eb0a 100644 --- a/glib/dbus-gtest.h +++ b/glib/dbus-gtest.h @@ -28,6 +28,7 @@ dbus_bool_t _dbus_gmain_test (const char *test_data_dir); dbus_bool_t _dbus_gobject_test (const char *test_data_dir); +dbus_bool_t _dbus_gutils_test (const char *test_data_dir); void dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir); diff --git a/glib/dbus-gthread.c b/glib/dbus-gthread.c index 71a3c1f5..eb3e5572 100644 --- a/glib/dbus-gthread.c +++ b/glib/dbus-gthread.c @@ -165,7 +165,7 @@ dbus_gcondvar_wake_all (DBusCondVar *cond) * other function in the D-BUS API. */ void -dbus_gthread_init (void) +dbus_g_thread_init (void) { if (!g_thread_supported ()) g_error ("g_thread_init() must be called before dbus_threads_init()"); diff --git a/test/Makefile.am b/test/Makefile.am index ab04496e..84089517 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -89,7 +89,7 @@ all-local: for D in $(TESTDIRS); do \ test -d $(top_builddir)/test/$$D || mkdir $(top_builddir)/test/$$D || exit 1 ; \ done ; \ - if test $(srcdir) != . ; then \ + if ! (test $(srcdir) = . || test $(srcdir) -ef .) ; then \ FILES=`(cd $(srcdir) && $(FIND_TESTS))` ; \ for F in $$FILES; do \ SRC=$(srcdir)/$$F ; \ diff --git a/test/glib/test-profile.c b/test/glib/test-profile.c index 6d9d8e7f..23547a1f 100644 --- a/test/glib/test-profile.c +++ b/test/glib/test-profile.c @@ -185,7 +185,7 @@ main (int argc, char *argv[]) int i; g_thread_init (NULL); - dbus_gthread_init (); + dbus_g_thread_init (); dbus_error_init (&error); server = dbus_server_listen ("unix:tmpdir="DBUS_TEST_SOCKET_DIR, diff --git a/test/glib/test-thread-client.c b/test/glib/test-thread-client.c index d51d4e6a..122c839a 100644 --- a/test/glib/test-thread-client.c +++ b/test/glib/test-thread-client.c @@ -66,7 +66,7 @@ main (int argc, char *argv[]) int i; g_thread_init (NULL); - dbus_gthread_init (); + dbus_g_thread_init (); if(argc < 2) { diff --git a/test/glib/test-thread-server.c b/test/glib/test-thread-server.c index 8898ca7f..dd560328 100644 --- a/test/glib/test-thread-server.c +++ b/test/glib/test-thread-server.c @@ -178,7 +178,7 @@ main (int argc, char *argv[]) DBusError error; g_thread_init (NULL); - dbus_gthread_init (); + dbus_g_thread_init (); if (argc < 2) { diff --git a/tools/Makefile.am b/tools/Makefile.am index 80957854..a6a38a97 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS) +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS) $(DBUS_GTK_CFLAGS) -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" if HAVE_GLIB GLIB_TOOLS=dbus-monitor @@ -6,7 +6,13 @@ else GLIB_TOOLS= endif -bin_PROGRAMS=dbus-send $(GLIB_TOOLS) dbus-launch dbus-cleanup-sockets +if HAVE_GTK +GTK_TOOLS=dbus-viewer +else +GTK_TOOLS= +endif + +bin_PROGRAMS=dbus-send $(GLIB_TOOLS) dbus-launch dbus-cleanup-sockets $(GTK_TOOLS) dbus_send_SOURCES= \ dbus-print-message.c \ @@ -24,9 +30,17 @@ dbus_launch_SOURCES= \ dbus_cleanup_sockets_SOURCES= \ dbus-cleanup-sockets.c +dbus_viewer_SOURCES= \ + dbus-tree-view.c \ + dbus-tree-view.h \ + dbus-viewer.c + dbus_send_LDADD= $(top_builddir)/dbus/libdbus-1.la dbus_monitor_LDADD= $(top_builddir)/glib/libdbus-glib-1.la dbus_launch_LDADD= $(DBUS_X_LIBS) +dbus_viewer_LDADD= $(top_builddir)/glib/libdbus-gtool.la $(DBUS_GTK_LIBS) man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1 EXTRA_DIST = $(man_MANS) + + -- cgit v1.2.1