diff options
| author | Havoc Pennington <hp@redhat.com> | 2003-09-17 03:52:07 +0000 | 
|---|---|---|
| committer | Havoc Pennington <hp@redhat.com> | 2003-09-17 03:52:07 +0000 | 
| commit | 583994cb3b7f5562fb7b8c37b4cb0d5af78e4ce2 (patch) | |
| tree | d61f39d2ccb581f3a46d03f58bca93c2ac229afd | |
| parent | 85ab0327d82e4945ad16630e583d8cc68df25a90 (diff) | |
2003-09-15  Havoc Pennington  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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
| -rw-r--r-- | ChangeLog | 66 | ||||
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | configure.in | 30 | ||||
| -rw-r--r-- | dbus/dbus-connection-internal.h | 5 | ||||
| -rw-r--r-- | dbus/dbus-connection.c | 28 | ||||
| -rw-r--r-- | dbus/dbus-connection.h | 3 | ||||
| -rw-r--r-- | dbus/dbus-internals.h | 3 | ||||
| -rw-r--r-- | dbus/dbus-object-tree.c | 164 | ||||
| -rw-r--r-- | dbus/dbus-object-tree.h | 4 | ||||
| -rw-r--r-- | dbus/dbus-pending-call.c | 171 | ||||
| -rw-r--r-- | dbus/dbus-pending-call.h | 11 | ||||
| -rw-r--r-- | dbus/dbus-threads.c | 1 | ||||
| -rw-r--r-- | doc/TODO | 4 | ||||
| -rw-r--r-- | glib/Makefile.am | 29 | ||||
| -rw-r--r-- | glib/dbus-gidl.c | 226 | ||||
| -rw-r--r-- | glib/dbus-gidl.h | 26 | ||||
| -rw-r--r-- | glib/dbus-glib.h | 71 | ||||
| -rw-r--r-- | glib/dbus-gloader-expat.c | 19 | ||||
| -rw-r--r-- | glib/dbus-gmain.c | 41 | ||||
| -rw-r--r-- | glib/dbus-gobject.c | 89 | ||||
| -rw-r--r-- | glib/dbus-gparser.c | 8 | ||||
| -rw-r--r-- | glib/dbus-gparser.h | 10 | ||||
| -rw-r--r-- | glib/dbus-gproxy.c | 101 | ||||
| -rw-r--r-- | glib/dbus-gtest.c | 4 | ||||
| -rw-r--r-- | glib/dbus-gtest.h | 1 | ||||
| -rw-r--r-- | glib/dbus-gthread.c | 2 | ||||
| -rw-r--r-- | test/Makefile.am | 2 | ||||
| -rw-r--r-- | test/glib/test-profile.c | 2 | ||||
| -rw-r--r-- | test/glib/test-thread-client.c | 2 | ||||
| -rw-r--r-- | test/glib/test-thread-server.c | 2 | ||||
| -rw-r--r-- | tools/Makefile.am | 18 | 
31 files changed, 944 insertions, 201 deletions
| @@ -1,3 +1,69 @@ +2003-09-15  Havoc Pennington  <hp@pobox.com> + +	* 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  <hp@pobox.com> + +	* 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  <hp@pobox.com> + +	* 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  <hp@pobox.com>  	* 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 <dbus/dbus-resources.h>  #include <dbus/dbus-list.h>  #include <dbus/dbus-timeout.h> +#include <dbus/dbus-dataslot.h>  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 <string.h>  #include <stdlib.h> @@ -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, "<node>\n")) +    goto out; + +  i = 0; +  while (children[i] != NULL) +    { +      if (!_dbus_string_append_printf (&xml, "  <node name=\"%s\"/>\n", +                                       children[i])) +        goto out; + +      ++i; +    } + +  if (!_dbus_string_append (&xml, "</node>\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), @@ -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)  { @@ -78,6 +166,20 @@ free_interface_list (GSList **interfaces_p)  }  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)  {    GSList *tmp; @@ -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 <dbus/dbus.h> -#include <glib.h> +#include <glib-object.h>  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 <libintl.h> +#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 <config.h>  #include "dbus-glib.h"  #include "dbus-gtest.h" +#include "dbus-gutils.h"  #include <string.h>  /** @@ -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, "  <node name=\"%s\"/>\n", +                              children[i]); +      ++i; +    } +      /* Close the XML, and send it to the requesting app */    g_string_append (xml, "</node>\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) + + | 
