2003-09-15 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Wed, 17 Sep 2003 03:52:07 +0000 (03:52 +0000)
committerHavoc Pennington <hp@redhat.com>
Wed, 17 Sep 2003 03:52:07 +0000 (03:52 +0000)
* 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

31 files changed:
ChangeLog
Makefile.am
configure.in
dbus/dbus-connection-internal.h
dbus/dbus-connection.c
dbus/dbus-connection.h
dbus/dbus-internals.h
dbus/dbus-object-tree.c
dbus/dbus-object-tree.h
dbus/dbus-pending-call.c
dbus/dbus-pending-call.h
dbus/dbus-threads.c
doc/TODO
glib/Makefile.am
glib/dbus-gidl.c
glib/dbus-gidl.h
glib/dbus-glib.h
glib/dbus-gloader-expat.c
glib/dbus-gmain.c
glib/dbus-gobject.c
glib/dbus-gparser.c
glib/dbus-gparser.h
glib/dbus-gproxy.c
glib/dbus-gtest.c
glib/dbus-gtest.h
glib/dbus-gthread.c
test/Makefile.am
test/glib/test-profile.c
test/glib/test-thread-client.c
test/glib/test-thread-server.c
tools/Makefile.am

index a4dba23..caa4a75 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
index 7384af0..5bb5ae6 100644 (file)
@@ -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)
index c403fd8..e81a8d6 100644 (file)
@@ -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}
index 5a04dec..b19ab63 100644 (file)
@@ -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) */
index bab6ffd..b55f270 100644 (file)
@@ -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);
 
index abc8805..a4212c7 100644 (file)
@@ -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;
 
index 06a011e..b301035 100644 (file)
@@ -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);
 
index 9922dec..07d3ae5 100644 (file)
@@ -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>
 
  * @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
index 21d8b5f..bf34d97 100644 (file)
@@ -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 */
index 2b6021e..dad444e 100644 (file)
@@ -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 (&notify_user_data_slot))
+    return NULL;
   
   pending = dbus_new (DBusPendingCall, 1);
   
   if (pending == NULL)
-    return NULL;
+    {
+      dbus_pending_call_free_data_slot (&notify_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 (&notify_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 (&notify_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
index 81af872..4f1e92c 100644 (file)
@@ -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 */
index c5ce638..2170c46 100644 (file)
@@ -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),
index 6b308d3..5c2b149 100644 (file)
--- 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.
index 65d71cf..a45aa59 100644 (file)
@@ -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
+
index b867d17..596b43c 100644 (file)
 
 #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
index 7a66724..f95abfb 100644 (file)
 #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);
index 4015dd9..63d3448 100644 (file)
@@ -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 */
+
+
+
index 149e711..01587d2 100644 (file)
@@ -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;
 }
+
index c33f47e..2e5604d 100644 (file)
 #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
index b0f6c13..6e65770 100644 (file)
@@ -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,
index f7264b5..16d17f3 100644 (file)
@@ -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);
   
index 3e87165..cc58e5e 100644 (file)
@@ -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);
 
index 8951707..59d86a3 100644 (file)
@@ -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");
 
index b853d3e..48cd13f 100644 (file)
@@ -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");
index 6a33bda..1174eb0 100644 (file)
@@ -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);
 
index 71a3c1f..eb3e557 100644 (file)
@@ -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()");
index ab04496..8408951 100644 (file)
@@ -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 ;                                                     \
index 6d9d8e7..23547a1 100644 (file)
@@ -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,
index d51d4e6..122c839 100644 (file)
@@ -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)
     {
index 8898ca7..dd56032 100644 (file)
@@ -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)
     {
index 8095785..a6a38a9 100644 (file)
@@ -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)
+
+