2005-01-30 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Sun, 30 Jan 2005 07:44:08 +0000 (07:44 +0000)
committerHavoc Pennington <hp@redhat.com>
Sun, 30 Jan 2005 07:44:08 +0000 (07:44 +0000)
* glib/dbus-gobject.c (introspect_properties): fix the XML
generated

* dbus/dbus-message.c (dbus_message_unref): add an in_cache flag
which effectively detects the use of freed messages

* glib/dbus-gobject.c (handle_introspect): modify and return the
reply message instead of the incoming message

* dbus/dbus-object-tree.c (handle_default_introspect_unlocked):
gee, maybe it should SEND THE XML instead of just making a string
and freeing it again ;-)

* tools/dbus-print-message.c (print_message): improve printing of
messages

* configure.in: add debug-glib.service to the output

15 files changed:
ChangeLog
bus/driver.c
configure.in
dbus/dbus-connection-internal.h
dbus/dbus-connection.c
dbus/dbus-marshal-validate.c
dbus/dbus-message-private.h
dbus/dbus-message.c
dbus/dbus-object-tree.c
glib/dbus-gobject.c
glib/dbus-gparser.c
test/glib/run-test.sh
test/glib/test-service-glib.c
tools/dbus-print-message.c
tools/dbus-viewer.c

index dcb3a6d..029dafe 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
 2005-01-30  Havoc Pennington  <hp@redhat.com>
 
+       * glib/dbus-gobject.c (introspect_properties): fix the XML
+       generated
+
+       * dbus/dbus-message.c (dbus_message_unref): add an in_cache flag
+       which effectively detects the use of freed messages
+
+       * glib/dbus-gobject.c (handle_introspect): modify and return the
+       reply message instead of the incoming message
+
+       * dbus/dbus-object-tree.c (handle_default_introspect_unlocked):
+       gee, maybe it should SEND THE XML instead of just making a string
+       and freeing it again ;-)
+
+       * tools/dbus-print-message.c (print_message): improve printing of
+       messages
+
+       * configure.in: add debug-glib.service to the output
+
+2005-01-30  Havoc Pennington  <hp@redhat.com>
+
         dbus-viewer introspected and displayed the bus driver
        
        * dbus/dbus-object-tree.c 
index 58b8fcb..580301a 100644 (file)
@@ -470,7 +470,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
                               DBUS_TYPE_INVALID))
     return FALSE;
   
-  _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags);
+  _dbus_verbose ("Trying to own name %s with flags 0x%x\n", name, flags);
   
   retval = FALSE;
   reply = NULL;
index b09430d..1df7699 100644 (file)
@@ -1111,7 +1111,7 @@ AC_SUBST(TEST_$1)
 
 TEST_PATH(SERVICE_DIR, data/valid-service-files)
 TEST_PATH(SERVICE_BINARY, test-service)
-TEST_PATH(GLIB_SERVICE_BINARY, test-service-glib)
+TEST_PATH(GLIB_SERVICE_BINARY, glib/test-service-glib)
 TEST_PATH(EXIT_BINARY, test-exit)
 TEST_PATH(SEGFAULT_BINARY, test-segfault)
 TEST_PATH(SLEEP_FOREVER_BINARY, test-sleep-forever)
@@ -1216,6 +1216,7 @@ test/data/valid-config-files/debug-allow-all.conf
 test/data/valid-config-files/debug-allow-all-sha1.conf
 test/data/valid-service-files/debug-echo.service
 test/data/valid-service-files/debug-segfault.service
+test/data/valid-service-files/debug-glib.service
 ])
 
 ### FIXME it's bizarre that have_qt and have_glib are used
index b5781d9..14184ad 100644 (file)
@@ -89,7 +89,9 @@ DBusMessage*      _dbus_connection_block_for_reply             (DBusConnection
                                                                 int                 timeout_milliseconds);
 void              _dbus_pending_call_complete_and_unlock       (DBusPendingCall    *pending,
                                                                 DBusMessage        *message);
-
+dbus_bool_t       _dbus_connection_send_unlocked               (DBusConnection     *connection,
+                                                                DBusMessage        *message,
+                                                                dbus_uint32_t      *client_serial);
 
 /**
  * @addtogroup DBusPendingCallInternals DBusPendingCall implementation details
index 90d7c38..f01133c 100644 (file)
@@ -357,7 +357,7 @@ _dbus_connection_queue_received_message_link (DBusConnection  *connection,
 
   _dbus_connection_wakeup_mainloop (connection);
   
-  _dbus_verbose ("Message %p (%d %s %s '%s') added to incoming queue %p, %d incoming\n",
+  _dbus_verbose ("Message %p (%d %s %s '%s' reply to %u) added to incoming queue %p, %d incoming\n",
                  message,
                  dbus_message_get_type (message),
                  dbus_message_get_interface (message) ?
@@ -367,6 +367,7 @@ _dbus_connection_queue_received_message_link (DBusConnection  *connection,
                  dbus_message_get_member (message) :
                  "no member",
                  dbus_message_get_signature (message),
+                 dbus_message_get_reply_serial (message),
                  connection,
                  connection->n_incoming);
 }
@@ -1562,7 +1563,7 @@ _dbus_connection_send_preallocated_unlocked (DBusConnection       *connection,
 
   sig = dbus_message_get_signature (message);
   
-  _dbus_verbose ("Message %p (%d %s %s '%s') added to outgoing queue %p, %d pending to send\n",
+  _dbus_verbose ("Message %p (%d %s %s '%s') for %s added to outgoing queue %p, %d pending to send\n",
                  message,
                  dbus_message_get_type (message),
                  dbus_message_get_interface (message) ?
@@ -1572,6 +1573,9 @@ _dbus_connection_send_preallocated_unlocked (DBusConnection       *connection,
                  dbus_message_get_member (message) :
                  "no member",
                  sig,
+                 dbus_message_get_destination (message) ?
+                 dbus_message_get_destination (message) :
+                 "null",
                  connection,
                  connection->n_outgoing);
 
@@ -1587,6 +1591,9 @@ _dbus_connection_send_preallocated_unlocked (DBusConnection       *connection,
       if (client_serial)
         *client_serial = dbus_message_get_serial (message);
     }
+
+  _dbus_verbose ("Message %p serial is %u\n",
+                 message, dbus_message_get_serial (message));
   
   _dbus_message_lock (message);
 
@@ -1638,7 +1645,7 @@ dbus_connection_send_preallocated (DBusConnection       *connection,
   CONNECTION_UNLOCK (connection);  
 }
 
-static dbus_bool_t
+dbus_bool_t
 _dbus_connection_send_unlocked (DBusConnection *connection,
                                 DBusMessage    *message,
                                 dbus_uint32_t  *client_serial)
index d9b85cb..b144b62 100644 (file)
@@ -178,9 +178,11 @@ validate_body_helper (DBusTypeReader       *reader,
       const unsigned char *a;
       int alignment;
 
+#if 0
       _dbus_verbose ("   validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
                      _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
                      (int) (end - p));
+#endif
 
       /* Guarantee that p has one byte to look at */
       if (p == end)
@@ -436,9 +438,11 @@ validate_body_helper (DBusTypeReader       *reader,
           break;
         }
 
+#if 0
       _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
                      _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
                      (int) (end - p));
+#endif
 
       if (p > end)
         {
index 5f727ae..9ba5c2f 100644 (file)
@@ -97,6 +97,10 @@ struct DBusMessage
 
   unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
 
+#ifndef DBUS_DISABLE_CHECKS
+  unsigned int in_cache : 1; /**< Has been "freed" since it's in the cache (this is a debug feature) */
+#endif
+  
   DBusList *size_counters;   /**< 0-N DBusCounter used to track message size. */
   long size_counter_delta;   /**< Size we incremented the size counters by.   */
 
index 8525200..0d81659 100644 (file)
@@ -456,6 +456,8 @@ dbus_message_finalize (DBusMessage *message)
   _dbus_header_free (&message->header);
   _dbus_string_free (&message->body);
 
+  _dbus_assert (message->refcount.value == 0);
+  
   dbus_free (message);
 }
 
@@ -657,10 +659,15 @@ dbus_message_cache_or_finalize (DBusMessage *message)
   message_cache[i] = message;
   message_cache_count += 1;
   was_cached = TRUE;
+#ifndef DBUS_DISABLE_CHECKS
+  message->in_cache = TRUE;
+#endif
 
  out:
   _DBUS_UNLOCK (message_cache);
 
+  _dbus_assert (message->refcount.value == 0);
+  
   if (!was_cached)
     dbus_message_finalize (message);
 }
@@ -691,6 +698,9 @@ dbus_message_new_empty_header (void)
   message->refcount.value = 1;
   message->byte_order = DBUS_COMPILER_BYTE_ORDER;
   message->locked = FALSE;
+#ifndef DBUS_DISABLE_CHECKS
+  message->in_cache = FALSE;
+#endif
   message->size_counters = NULL;
   message->size_counter_delta = 0;
   message->changed_stamp = 0;
@@ -1067,7 +1077,8 @@ dbus_message_ref (DBusMessage *message)
 
   _dbus_return_val_if_fail (message != NULL, NULL);
   _dbus_return_val_if_fail (message->generation == _dbus_current_generation, NULL);
-
+  _dbus_return_val_if_fail (!message->in_cache, NULL);
+  
   old_refcount = _dbus_atomic_inc (&message->refcount);
   _dbus_assert (old_refcount >= 1);
 
@@ -1087,6 +1098,7 @@ dbus_message_unref (DBusMessage *message)
 
   _dbus_return_if_fail (message != NULL);
   _dbus_return_if_fail (message->generation == _dbus_current_generation);
+  _dbus_return_if_fail (!message->in_cache);
 
   old_refcount = _dbus_atomic_dec (&message->refcount);
 
index f879759..da8d8c2 100644 (file)
@@ -615,11 +615,22 @@ handle_default_introspect_unlocked (DBusObjectTree          *tree,
   DBusHandlerResult result;
   char **children;
   int i;
+  DBusMessage *reply;
+  DBusMessageIter iter;
+  const char *v_STRING;
 
+  /* We have the connection lock here */
+  
+  _dbus_verbose (" considering default Introspect() handler...\n");
+
+  reply = NULL;
+  
   if (!dbus_message_is_method_call (message,
                                     DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
                                     "Introspect"))
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  _dbus_verbose (" using default Introspect() handler!\n");
   
   if (!_dbus_string_init (&xml))
     return DBUS_HANDLER_RESULT_NEED_MEMORY;
@@ -648,12 +659,31 @@ handle_default_introspect_unlocked (DBusObjectTree          *tree,
 
   if (!_dbus_string_append (&xml, "</node>\n"))
     goto out;
+
+  reply = dbus_message_new_method_return (message);
+  if (reply == NULL)
+    goto out;
+
+  dbus_message_iter_init_append (reply, &iter);
+  v_STRING = _dbus_string_get_const_data (&xml);
+  if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
+    goto out;
+  
+#ifdef DBUS_BUILD_TESTS
+  if (tree->connection)
+#endif
+    {
+      if (!_dbus_connection_send_unlocked (tree->connection, reply, NULL))
+        goto out;
+    }
   
   result = DBUS_HANDLER_RESULT_HANDLED;
   
  out:
   _dbus_string_free (&xml);
   dbus_free_string_array (children);
+  if (reply)
+    dbus_message_unref (reply);
   
   return result;
 }
index 245ebf1..abaf2e0 100644 (file)
@@ -204,7 +204,7 @@ introspect_properties (GObject *object, GString *xml)
           g_string_append (xml, s);
           g_string_append (xml, "\" type=\"");
           g_string_append (xml, _dbus_gutils_type_to_string (dbus_type));
-          g_string_append (xml, "\" access=\"\n");
+          g_string_append (xml, "\" access=\"");
 
           if (can_set && can_get)
             g_string_append (xml, "readwrite");
@@ -216,7 +216,7 @@ introspect_properties (GObject *object, GString *xml)
               g_string_append (xml, "write");
             }
           
-          g_string_append (xml, "\">\n");
+          g_string_append (xml, "\"/>\n");
         }
       
       g_free (s);
@@ -329,12 +329,12 @@ handle_introspect (DBusConnection *connection,
   if (ret == NULL)
     g_error ("Out of memory");
 
-  dbus_message_append_args (message,
+  dbus_message_append_args (ret,
                             DBUS_TYPE_STRING, &xml->str,
                             DBUS_TYPE_INVALID);
 
-  dbus_connection_send (connection, message, NULL);
-  dbus_message_unref (message);
+  dbus_connection_send (connection, ret, NULL);
+  dbus_message_unref (ret);
 
   g_string_free (xml, TRUE);
 
index 83922af..963a573 100644 (file)
@@ -483,6 +483,8 @@ basic_type_from_string (const char *str)
     return DBUS_TYPE_BYTE;
   else if (strcmp (str, "object") == 0)
     return DBUS_TYPE_OBJECT_PATH;
+  else if (strcmp (str, "variant") == 0)
+    return DBUS_TYPE_VARIANT;
   else
     return DBUS_TYPE_INVALID;
 }
index 0a5e3f6..cf0a85f 100755 (executable)
@@ -67,9 +67,12 @@ elif test x$MODE = xviewer ; then
   echo "Launching dbus-viewer"
   ARGS=
   if test x$DEBUG = x ; then
-      ARGS="--services org.freedesktop.DBus"
+      ARGS="--services org.freedesktop.DBus org.freedesktop.DBus.TestSuiteGLibService"
   fi
   libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/tools/dbus-viewer $ARGS || die "could not run dbus-viewer"
+elif test x$MODE = xwait ; then
+  echo "Waiting DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS"
+  sleep 86400
 else
   echo "running test-dbus-glib"
   libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/glib/test-dbus-glib || die "test-dbus-glib failed"
index 9b1be0a..413bcc2 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <glib/gi18n.h>
 
 typedef struct MyObject MyObject;
 typedef struct MyObjectClass MyObjectClass;
@@ -12,6 +13,7 @@ GType my_object_get_type (void);
 struct MyObject
 {
   GObject parent;
+  char *this_is_a_string;
 };
 
 struct MyObjectClass
@@ -20,7 +22,7 @@ struct MyObjectClass
 };
 
 #define MY_TYPE_OBJECT              (my_object_get_type ())
-#define MY_OBJECT_OBJECT(object)    (G_TYPE_CHECK_INSTANCE_CAST ((object), MY_TYPE_OBJECT, MyObject))
+#define MY_OBJECT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MY_TYPE_OBJECT, MyObject))
 #define MY_OBJECT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MY_TYPE_OBJECT, MyObjectClass))
 #define MY_IS_OBJECT(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MY_TYPE_OBJECT))
 #define MY_IS_OBJECT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_TYPE_OBJECT))
@@ -28,6 +30,67 @@ struct MyObjectClass
 
 G_DEFINE_TYPE(MyObject, my_object, G_TYPE_OBJECT)
 
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_THIS_IS_A_STRING
+};
+
+static void
+my_object_finalize (GObject *object)
+{
+  MyObject *mobject = MY_OBJECT (object);
+
+  g_free (mobject->this_is_a_string);
+
+  (G_OBJECT_CLASS (my_object_parent_class)->finalize) (object);
+}
+
+static void
+my_object_set_property (GObject      *object,
+                        guint         prop_id,
+                        const GValue *value,
+                        GParamSpec   *pspec)
+{
+  MyObject *mobject;
+
+  mobject = MY_OBJECT (object);
+  
+  switch (prop_id)
+    {
+    case PROP_THIS_IS_A_STRING:
+      g_free (mobject->this_is_a_string);
+      mobject->this_is_a_string = g_value_dup_string (value);
+      break;
+      
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+my_object_get_property (GObject      *object,
+                        guint         prop_id,
+                        GValue       *value,
+                        GParamSpec   *pspec)
+{
+  MyObject *mobject;
+
+  mobject = MY_OBJECT (object);
+  
+  switch (prop_id)
+    {
+    case PROP_THIS_IS_A_STRING:
+      g_value_set_string (value, mobject->this_is_a_string);
+      break;
+      
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
 
 static void
 my_object_init (MyObject *obj)
@@ -36,9 +99,21 @@ my_object_init (MyObject *obj)
 }
 
 static void
-my_object_class_init (MyObjectClass *obj_class)
+my_object_class_init (MyObjectClass *mobject_class)
 {
+  GObjectClass *gobject_class = G_OBJECT_CLASS (mobject_class);
+
+  gobject_class->finalize = my_object_finalize;
+  gobject_class->set_property = my_object_set_property;
+  gobject_class->get_property = my_object_get_property;
   
+  g_object_class_install_property (gobject_class,
+                                  PROP_THIS_IS_A_STRING,
+                                  g_param_spec_string ("this_is_a_string",
+                                                        _("Sample string"),
+                                                        _("Example of a string property"),
+                                                        "default value",
+                                                        G_PARAM_READWRITE));
 }
      
 static GMainLoop *loop;
@@ -49,6 +124,10 @@ main (int argc, char **argv)
   DBusGConnection *connection;
   GError *error;
   GObject *obj;
+  DBusGProxy *driver_proxy;
+  DBusGPendingCall *call;
+  const char *v_STRING;
+  guint32 v_UINT32;
   
   g_type_init ();
   
@@ -70,7 +149,40 @@ main (int argc, char **argv)
   dbus_g_connection_register_g_object (connection,
                                        "/org/freedesktop/my_test_object",
                                        obj);
-  
+
+  driver_proxy = dbus_g_proxy_new_for_name (connection,
+                                            DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+                                            DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+                                            DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS);
+
+  v_STRING = "org.freedesktop.DBus.TestSuiteGLibService";
+  v_UINT32 = 0;
+  call = dbus_g_proxy_begin_call (driver_proxy, "RequestName",
+                                  DBUS_TYPE_STRING,
+                                  &v_STRING,
+                                  DBUS_TYPE_UINT32,
+                                  &v_UINT32,
+                                  DBUS_TYPE_INVALID);
+  if (!dbus_g_proxy_end_call (driver_proxy, call,
+                              &error, DBUS_TYPE_UINT32, &v_UINT32,
+                              DBUS_TYPE_INVALID))
+    {
+      g_assert (error != NULL);
+      g_printerr ("Failed to get name: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+  g_assert (error == NULL);
+  dbus_g_pending_call_unref (call);
+
+  if (!(v_UINT32 == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER))
+    {
+      g_printerr ("Got result code %u from requesting name\n", v_UINT32);
+      exit (1);
+    }
+
+  g_print ("GLib test service has name '%s'\n", v_STRING);
   g_print ("GLib test service entering main loop\n");
 
   g_main_loop_run (loop);
index 572a1d1..b355925 100644 (file)
@@ -44,43 +44,45 @@ print_message (DBusMessage *message)
 {
   DBusMessageIter iter;
   const char *sender;
+  const char *destination;
   int message_type;
+  int count;
 
   message_type = dbus_message_get_type (message);
-  sender = dbus_message_get_sender (message); 
-
+  sender = dbus_message_get_sender (message);
+  destination = dbus_message_get_destination (message);
+
+  printf ("%s sender=%s -> dest=%s",
+          type_to_name (message_type),
+          sender ? sender : "(null sender)",
+          destination ? destination : "(null destination)");
+         
   switch (message_type)
     {
     case DBUS_MESSAGE_TYPE_METHOD_CALL:
     case DBUS_MESSAGE_TYPE_SIGNAL:
-      printf ("%s interface=%s; member=%s; sender=%s\n",
-              type_to_name (message_type),
+      printf (" interface=%s; member=%s\n",
               dbus_message_get_interface (message),
-              dbus_message_get_member (message),
-              sender ? sender : "(no sender)");
+              dbus_message_get_member (message));
       break;
       
     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
-      printf ("%s; sender=%s\n",
-              type_to_name (message_type),
-              sender ? sender : "(no sender)");
+      printf ("\n");
       break;
 
     case DBUS_MESSAGE_TYPE_ERROR:
-      printf ("%s name=%s; sender=%s\n",
-              type_to_name (message_type),
-              dbus_message_get_error_name (message),
-              sender ? sender : "(no sender)");
+      printf (" error_name=%s\n",
+              dbus_message_get_error_name (message));
       break;
 
     default:
-      printf ("Message of unknown type %d received\n",
-              message_type);
+      printf ("\n");
       break;
     }
-      
-  dbus_message_iter_init (message, &iter);
 
+  dbus_message_iter_init (message, &iter);
+  count = 0;
+  
   do
     {
       int type = dbus_message_iter_get_arg_type (&iter);
@@ -98,38 +100,40 @@ print_message (DBusMessage *message)
        {
        case DBUS_TYPE_STRING:
           dbus_message_iter_get_basic (&iter, &str);
-         printf ("string:%s\n", str);
+         printf (" %d string \"%s\"\n", count, str);
          break;
 
        case DBUS_TYPE_INT32:
           dbus_message_iter_get_basic (&iter, &int32);
-         printf ("int32:%d\n", int32);
+         printf (" %d int32 %d\n", count, int32);
          break;
 
        case DBUS_TYPE_UINT32:
           dbus_message_iter_get_basic (&iter, &uint32);
-         printf ("int32:%u\n", uint32);
+         printf (" %d uint32 %u\n", count, uint32);
          break;
 
        case DBUS_TYPE_DOUBLE:
          dbus_message_iter_get_basic (&iter, &d);
-         printf ("double:%f\n", d);
+         printf (" %d double %g\n", count, d);
          break;
 
        case DBUS_TYPE_BYTE:
          dbus_message_iter_get_basic (&iter, &byte);
-         printf ("byte:%d\n", byte);
+         printf (" %d byte %d\n", count, byte);
          break;
 
        case DBUS_TYPE_BOOLEAN:
           dbus_message_iter_get_basic (&iter, &boolean);
-         printf ("boolean:%s\n", boolean ? "true" : "false");
+         printf (" %d boolean %s\n", count, boolean ? "true" : "false");
          break;
 
        default:
-         printf ("(unknown arg type %d)\n", type);
+         printf (" (dbus-monitor too dumb to decipher arg type '%c')\n", type);
          break;
        }
+      
+      count += 1;
     } while (dbus_message_iter_next (&iter));
 }
 
index c32e6fd..abd299f 100644 (file)
@@ -192,6 +192,7 @@ show_error_dialog (GtkWindow *transient_parent,
 static gboolean
 load_child_nodes (const char *service_name,
                   NodeInfo   *parent,
+                  GString    *path,
                   GError    **error)
 {
   DBusGConnection *connection;
@@ -200,7 +201,7 @@ load_child_nodes (const char *service_name,
   connection = dbus_g_bus_get (DBUS_BUS_SESSION, error);
   if (connection == NULL)
     return FALSE;
-
+  
   tmp = node_info_get_nodes (parent);
   while (tmp != NULL)
     {
@@ -209,17 +210,37 @@ load_child_nodes (const char *service_name,
       const char *data;
       NodeInfo *child;
       NodeInfo *complete_child;
+      int save_len;
 
       complete_child = NULL;
+      call = NULL;
       
       child = tmp->data;
 
-      g_assert (*service_name == ':'); /* so we don't need new_for_name_owner */
-      proxy = dbus_g_proxy_new_for_name (connection,
-                                         service_name,
-                                         "/",
-                                         DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE);
-      g_assert (proxy != NULL);
+      save_len = path->len;
+
+      if (save_len > 1)
+        g_string_append (path, "/");
+      g_string_append (path, base_info_get_name ((BaseInfo*)child));
+
+      if (*service_name == ':')
+        {
+          proxy = dbus_g_proxy_new_for_name (connection,
+                                             service_name,
+                                             path->str,
+                                             DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE);
+          g_assert (proxy != NULL);
+        }
+      else
+        {
+          proxy = dbus_g_proxy_new_for_name_owner (connection,
+                                                   service_name,
+                                                   path->str,
+                                                   DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
+                                                   error);
+          if (proxy == NULL)
+            goto done;
+        }
   
       call = dbus_g_proxy_begin_call (proxy, "Introspect",
                                       DBUS_TYPE_INVALID);
@@ -231,10 +252,14 @@ load_child_nodes (const char *service_name,
       
       complete_child = description_load_from_string (data, -1, error);
       if (complete_child == NULL)
-        goto done;
+        {
+          g_printerr ("%s\n", data);
+          goto done;
+        }
       
     done:
-      dbus_g_pending_call_unref (call);
+      if (call)
+        dbus_g_pending_call_unref (call);
       g_object_unref (proxy);
 
       if (complete_child == NULL)
@@ -249,8 +274,11 @@ load_child_nodes (const char *service_name,
       node_info_unref (complete_child); /* ref still held by parent */
       
       /* Now recurse */
-      if (!load_child_nodes (service_name, complete_child, error))
+      if (!load_child_nodes (service_name, complete_child, path, error))
         return FALSE;
+
+      /* restore path */
+      g_string_set_size (path, save_len);
       
       tmp = tmp->next;
     }
@@ -267,21 +295,36 @@ load_from_service (const char *service_name,
   DBusGPendingCall *call;
   const char *data;
   NodeInfo *node;
+  GString *path;
 
   node = NULL;
   call = NULL;
+  path = NULL;
   
   connection = dbus_g_bus_get (DBUS_BUS_SESSION, error);
   if (connection == NULL)
     return NULL;
 
+#if 1
+  /* this will end up autolaunching the service when we introspect it */
+  root_proxy = dbus_g_proxy_new_for_name (connection,
+                                          service_name,
+                                          "/",
+                                          DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE);
+  g_assert (root_proxy != NULL);
+#else
+  /* this will be an error if the service doesn't exist */
   root_proxy = dbus_g_proxy_new_for_name_owner (connection,
                                                 service_name,
                                                 "/",
                                                 DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
                                                 error);
   if (root_proxy == NULL)
-    return NULL;
+    {
+      g_printerr ("Failed to get owner of '%s'\n", service_name);
+      return NULL;
+    }
+#endif
   
   call = dbus_g_proxy_begin_call (root_proxy, "Introspect",
                                   DBUS_TYPE_INVALID);
@@ -289,7 +332,11 @@ load_from_service (const char *service_name,
   data = NULL;
   if (!dbus_g_proxy_end_call (root_proxy, call, error, DBUS_TYPE_STRING, &data,
                               DBUS_TYPE_INVALID))
-    goto out;
+    {
+      g_printerr ("Failed to Introspect() %s\n",
+                  dbus_g_proxy_get_bus_name (root_proxy));
+      goto out;
+    }
 
   node = description_load_from_string (data, -1, error);
 
@@ -299,9 +346,11 @@ load_from_service (const char *service_name,
     goto out;
 
   base_info_set_name ((BaseInfo*)node, "/");
+
+  path = g_string_new ("/");
   
   if (!load_child_nodes (dbus_g_proxy_get_bus_name (root_proxy),
-                         node, error))
+                         node, path, error))
     {
       node_info_unref (node);
       node = NULL;
@@ -313,6 +362,10 @@ load_from_service (const char *service_name,
     dbus_g_pending_call_unref (call);
     
   g_object_unref (root_proxy);
+
+  if (path)
+    g_string_free (path, TRUE);
+  
   return node;
 }