2005-01-30 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Sun, 30 Jan 2005 23:06:32 +0000 (23:06 +0000)
committerHavoc Pennington <hp@redhat.com>
Sun, 30 Jan 2005 23:06:32 +0000 (23:06 +0000)
* glib/dbus-glib.c (dbus_g_pending_call_set_notify): new function
(dbus_g_pending_call_cancel): new function

* dbus/dbus-glib.h: move GType decls for connection/message here;
* dbus/dbus-glib.c: move all the g_type and ref/unref stuff in
here, just kind of rationalizing how we handle all that

* tools/dbus-names-model.c: new file for a tree model listing the
services on a bus

* tools/dbus-tree-view.c (model_new): use proper typing on the
model rows

14 files changed:
ChangeLog
dbus/dbus-glib-lowlevel.h
dbus/dbus-glib.h
dbus/dbus-pending-call.c
doc/TODO
glib/dbus-glib.c
glib/dbus-gmain.c
glib/dbus-gproxy.c
test/glib/test-dbus-glib.c
tools/Makefile.am
tools/dbus-names-model.c [new file with mode: 0644]
tools/dbus-names-model.h [new file with mode: 0644]
tools/dbus-tree-view.c
tools/dbus-viewer.c

index db61a28..dd4d175 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
 2005-01-30  Havoc Pennington  <hp@redhat.com>
 
+       * glib/dbus-glib.c (dbus_g_pending_call_set_notify): new function
+       (dbus_g_pending_call_cancel): new function
+
+       * dbus/dbus-glib.h: move GType decls for connection/message here;
+       * dbus/dbus-glib.c: move all the g_type and ref/unref stuff in
+       here, just kind of rationalizing how we handle all that
+
+       * tools/dbus-names-model.c: new file for a tree model listing the
+       services on a bus
+
+       * tools/dbus-tree-view.c (model_new): use proper typing on the
+       model rows
+
+2005-01-30  Havoc Pennington  <hp@redhat.com>
+
        * glib/dbus-gmain.c: add a custom GSource back that just checks
        whether the message queue has anything in it; otherwise, there are 
        cases where we won't see messages in the queue since there was no 
index a689a92..9413215 100644 (file)
@@ -32,15 +32,12 @@ G_BEGIN_DECLS
 void dbus_set_g_error (GError   **gerror,
                        DBusError *derror);
 
-#define DBUS_TYPE_CONNECTION (dbus_connection_get_g_type ())
-#define DBUS_TYPE_MESSAGE    (dbus_message_get_g_type ())
-GType dbus_connection_get_g_type (void) G_GNUC_CONST;
-GType dbus_message_get_g_type    (void) G_GNUC_CONST;
-
-#define DBUS_TYPE_G_CONNECTION (dbus_g_connection_get_g_type ())
-#define DBUS_TYPE_G_MESSAGE    (dbus_g_message_get_g_type ())
-GType dbus_g_connection_get_g_type (void) G_GNUC_CONST;
-GType dbus_g_message_get_g_type    (void) G_GNUC_CONST;
+#define DBUS_TYPE_CONNECTION      (dbus_connection_get_g_type ())
+#define DBUS_TYPE_MESSAGE         (dbus_message_get_g_type ())
+#define DBUS_TYPE_PENDING_CALL    (dbus_pending_call_get_g_type ())
+GType dbus_connection_get_g_type   (void) G_GNUC_CONST;
+GType dbus_message_get_g_type      (void) G_GNUC_CONST;
+GType dbus_pending_call_get_g_type (void) G_GNUC_CONST;
 
 void            dbus_connection_setup_with_g_main (DBusConnection  *connection,
                                                    GMainContext    *context);
index 3e73b98..6c3c3c5 100644 (file)
@@ -34,11 +34,11 @@ G_BEGIN_DECLS
 
 
 /**
- * Convert to DBusConnection with dbus_g_connection_get_connection()
+ * Convert to DBusConnection with dbus_g_connection_get_connection() in dbus-glib-lowlevel.h
  */
 typedef struct DBusGConnection DBusGConnection;
 /**
- * Convert to DBusMessage with dbus_g_message_get_message()
+ * Convert to DBusMessage with dbus_g_message_get_message() in dbus-glib-lowlevel.h
  */
 typedef struct DBusGMessage DBusGMessage;
 /**
@@ -46,7 +46,33 @@ typedef struct DBusGMessage DBusGMessage;
  */
 typedef struct DBusGPendingCall DBusGPendingCall;
 
-void dbus_g_connection_flush (DBusGConnection *connection);
+typedef void (* DBusGPendingCallNotify) (DBusGPendingCall *pending,
+                                         void             *user_data);
+
+
+#define DBUS_TYPE_G_CONNECTION   (dbus_g_connection_get_g_type ())
+#define DBUS_TYPE_G_MESSAGE      (dbus_g_message_get_g_type ())
+#define DBUS_TYPE_G_PENDING_CALL (dbus_g_message_get_g_type ())
+GType dbus_g_connection_get_g_type   (void) G_GNUC_CONST;
+GType dbus_g_message_get_g_type      (void) G_GNUC_CONST;
+GType dbus_g_pending_call_get_g_type (void) G_GNUC_CONST;
+
+
+DBusGConnection*  dbus_g_connection_ref          (DBusGConnection        *connection);
+void              dbus_g_connection_unref        (DBusGConnection        *connection);
+DBusGPendingCall* dbus_g_pending_call_ref        (DBusGPendingCall       *call);
+void              dbus_g_pending_call_unref      (DBusGPendingCall       *call);
+DBusGMessage*     dbus_g_message_ref             (DBusGMessage           *message);
+void              dbus_g_message_unref           (DBusGMessage           *message);
+
+void              dbus_g_connection_flush        (DBusGConnection        *connection);
+
+void              dbus_g_pending_call_set_notify (DBusGPendingCall       *call,
+                                                  DBusGPendingCallNotify  callback,
+                                                  void                   *callback_data,
+                                                  GDestroyNotify          free_data_func);
+void              dbus_g_pending_call_cancel     (DBusGPendingCall       *call);
+
 
 GQuark dbus_g_error_quark (void);
 #define DBUS_GERROR dbus_g_error_quark ()
@@ -147,9 +173,6 @@ void              dbus_g_proxy_call_no_reply         (DBusGProxy        *proxy,
                                                       ...);
 const char*       dbus_g_proxy_get_bus_name          (DBusGProxy        *proxy);
 
-DBusGPendingCall* dbus_g_pending_call_ref            (DBusGPendingCall  *call);
-void              dbus_g_pending_call_unref          (DBusGPendingCall  *call);
-
 #undef DBUS_INSIDE_DBUS_GLIB_H
 
 G_END_DECLS
index d0403b0..b69f7c3 100644 (file)
@@ -227,11 +227,11 @@ dbus_pending_call_set_notify (DBusPendingCall              *pending,
 }
 
 /**
- * Cancels the pending call, such that any reply
- * or error received will just be ignored.
- * Drops at least one reference to the #DBusPendingCall
- * so will free the call if nobody else is holding
- * a reference.
+ * Cancels the pending call, such that any reply or error received
+ * will just be ignored.  Drops the dbus library's internal reference
+ * to the #DBusPendingCall so will free the call if nobody else is
+ * holding a reference. However you usually get a reference
+ * from dbus_connection_send() so probably your app owns a ref also.
  * 
  * @param pending the pending call
  */
index 49b0077..0590bb4 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -51,16 +51,9 @@ Important for 1.0 GLib Bindings
  - finish dbus-glib-tool support for adding introspection 
    data to GObject and autoexporting GObject using same
 
- - the GLib bindings varargs take DBUS_TYPE_WHATEVER and 
-   return stuff allocated with dbus_malloc(); should this 
-   be made more "G" at some expense in code duplication?
-   You also still have to use some D-BUS functions such as 
-   dbus_message_get_args() which takes a DBusError. 
-   Probably we need to either fully encapsulate and hide 
-   dbus/dbus.h, or encapsulate it slightly less e.g. no 
-   GError. Or maybe it's as simple as "never return dbus_malloc() 
-   memory" and just fully encapsulate the get_args() type of 
-   stuff.
+ - Need to make sure that dbus-glib.h never returns any 
+   dbus_malloc() memory, only g_malloc(). 
+   dbus_g_proxy_end_call() is the major offender. 
 
  - dbus_gproxy_connect_signal() has to take a signature for the signal 
    so it can figure out how to invoke the callback, or we have to rely
index 4250a65..a870873 100644 (file)
@@ -47,6 +47,341 @@ dbus_g_connection_flush (DBusGConnection *connection)
   dbus_connection_flush (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
 }
 
+/**
+ * Increment refcount on a #DBusGConnection
+ * 
+ * @param connection the connection to ref
+ * @returns the connection that was ref'd
+ */
+DBusGConnection*
+dbus_g_connection_ref (DBusGConnection *gconnection)
+{
+  DBusConnection *c;
+
+  c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
+  dbus_connection_ref (c);
+  return gconnection;
+}
+
+
+/**
+ * Decrement refcount on a #DBusGConnection
+ * 
+ * @param connection the connection to unref
+ */
+void
+dbus_g_connection_unref (DBusGConnection *gconnection)
+{
+  DBusConnection *c;
+
+  c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
+  dbus_connection_unref (c);
+}
+
+
+/**
+ * Increment refcount on a #DBusGMessage
+ * 
+ * @param message the message to ref
+ * @returns the message that was ref'd
+ */
+DBusGMessage*
+dbus_g_message_ref (DBusGMessage *gmessage)
+{
+  DBusMessage *c;
+
+  c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
+  dbus_message_ref (c);
+  return gmessage;
+}
+
+/**
+ * Decrement refcount on a #DBusGMessage
+ * 
+ * @param message the message to unref
+ */
+void
+dbus_g_message_unref (DBusGMessage *gmessage)
+{
+  DBusMessage *c;
+
+  c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
+  dbus_message_unref (c);
+}
+
+/**
+ * Increments refcount on a pending call.
+ *
+ * @param call the call
+ * @returns the same call
+ */
+DBusGPendingCall*
+dbus_g_pending_call_ref (DBusGPendingCall  *call)
+{
+  dbus_pending_call_ref (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (call));
+  return call;
+}
+
+/**
+ * Decrements refcount on a pending call.
+ *
+ * @param call the call
+ */
+void
+dbus_g_pending_call_unref (DBusGPendingCall  *call)
+{
+  dbus_pending_call_unref (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (call));
+}
+
+/**
+ * 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);  
+}
+
+/**
+ * Get the GLib type ID for a DBusConnection boxed type.
+ *
+ * @returns GLib type
+ */
+GType
+dbus_connection_get_g_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("DBusConnection",
+                                             (GBoxedCopyFunc) dbus_connection_ref,
+                                             (GBoxedFreeFunc) dbus_connection_unref);
+
+  return our_type;
+}
+
+/**
+ * Get the GLib type ID for a DBusMessage boxed type.
+ *
+ * @returns GLib type
+ */
+GType
+dbus_message_get_g_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("DBusMessage",
+                                             (GBoxedCopyFunc) dbus_message_ref,
+                                             (GBoxedFreeFunc) dbus_message_unref);
+
+  return our_type;
+}
+
+/**
+ * Get the GLib type ID for a DBusPendingCall boxed type.
+ *
+ * @returns GLib type
+ */
+GType
+dbus_pending_call_get_g_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("DBusPendingCall",
+                                             (GBoxedCopyFunc) dbus_pending_call_ref,
+                                             (GBoxedFreeFunc) dbus_pending_call_unref);
+
+  return our_type;
+}
+
+/**
+ * Get the GLib type ID for a DBusGConnection boxed type.
+ *
+ * @returns GLib type
+ */
+GType
+dbus_g_connection_get_g_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("DBusGConnection",
+                                             (GBoxedCopyFunc) dbus_g_connection_ref,
+                                             (GBoxedFreeFunc) dbus_g_connection_unref);
+
+  return our_type;
+}
+
+/**
+ * Get the GLib type ID for a DBusGMessage boxed type.
+ *
+ * @returns GLib type
+ */
+GType
+dbus_g_message_get_g_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("DBusGMessage",
+                                             (GBoxedCopyFunc) dbus_g_message_ref,
+                                             (GBoxedFreeFunc) dbus_g_message_unref);
+
+  return our_type;
+}
+
+/**
+ * Get the GLib type ID for a DBusGPendingCall boxed type.
+ *
+ * @returns GLib type
+ */
+GType
+dbus_g_pending_call_get_g_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("DBusGPendingCall",
+                                             (GBoxedCopyFunc) dbus_g_pending_call_ref,
+                                             (GBoxedFreeFunc) dbus_g_pending_call_unref);
+
+  return our_type;
+}
+
+/**
+ * Get the DBusConnection corresponding to this DBusGConnection.
+ * The return value does not have its refcount incremented.
+ *
+ * @returns DBusConnection 
+ */
+DBusConnection*
+dbus_g_connection_get_connection (DBusGConnection *gconnection)
+{
+  return DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
+}
+
+/**
+ * Get the DBusMessage corresponding to this DBusGMessage.
+ * The return value does not have its refcount incremented.
+ *
+ * @returns DBusMessage 
+ */
+DBusMessage*
+dbus_g_message_get_message (DBusGMessage *gmessage)
+{
+  return DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
+}
+
+typedef struct
+{
+  DBusGPendingCallNotify func;
+  void *data;
+  GDestroyNotify free_data_func;
+} GPendingNotifyClosure;
+
+static void
+d_pending_call_notify (DBusPendingCall *dcall,
+                       void            *data)
+{
+  GPendingNotifyClosure *closure = data;
+  DBusGPendingCall *gcall = DBUS_G_PENDING_CALL_FROM_PENDING_CALL (dcall);
+
+  (* closure->func) (gcall, closure->data);
+}
+
+static void
+d_pending_call_free (void *data)
+{
+  GPendingNotifyClosure *closure = data;
+  
+  if (closure->free_data_func)
+    (* closure->free_data_func) (closure->data);
+
+  g_free (closure);
+}
+  
+/**
+ * Sets up a notification to be invoked when the pending call
+ * is ready to be ended without blocking.
+ * You can call dbus_g_proxy_end_call() at any time,
+ * but it will block if no reply or error has been received yet.
+ * This function lets you handle the reply asynchronously.
+ *
+ * @param call the pending call
+ * @param callback the callback
+ * @param callback_data data for the callback
+ * @param free_data_func free the callback data with this
+ */
+void
+dbus_g_pending_call_set_notify (DBusGPendingCall      *call,
+                                DBusGPendingCallNotify callback,
+                                void                  *callback_data,
+                                GDestroyNotify         free_data_func)
+{
+  GPendingNotifyClosure *closure;
+  DBusPendingCall *dcall;
+
+  g_return_if_fail (callback != NULL);
+  
+  closure = g_new (GPendingNotifyClosure, 1);
+
+  closure->func = callback;
+  closure->data = callback_data;
+  closure->free_data_func = free_data_func;
+
+  dcall = DBUS_PENDING_CALL_FROM_G_PENDING_CALL (call);
+  dbus_pending_call_set_notify (dcall, d_pending_call_notify,
+                                closure,
+                                d_pending_call_free);
+}
+
+/**
+ * Cancels a pending call. Does not affect the reference count
+ * of the call, but it means you will never be notified of call
+ * completion, and can't call dbus_g_proxy_end_call().
+ *
+ * @param call the call
+ */
+void
+dbus_g_pending_call_cancel (DBusGPendingCall *call)
+{
+  DBusPendingCall *dcall;
+  
+  dcall = DBUS_PENDING_CALL_FROM_G_PENDING_CALL (call);
+
+  dbus_pending_call_cancel (dcall);
+}
+
 /** @} */ /* end of public API */
 
 
index 63e1d79..4057482 100644 (file)
@@ -731,178 +731,6 @@ dbus_g_bus_get (DBusBusType     type,
   return DBUS_G_CONNECTION_FROM_CONNECTION (connection);
 }
 
-/**
- * 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);  
-}
-
-/**
- * Get the GLib type ID for a DBusConnection boxed type.
- *
- * @returns GLib type
- */
-GType
-dbus_connection_get_g_type (void)
-{
-  static GType our_type = 0;
-  
-  if (our_type == 0)
-    our_type = g_boxed_type_register_static ("DBusConnection",
-                                             (GBoxedCopyFunc) dbus_connection_ref,
-                                             (GBoxedFreeFunc) dbus_connection_unref);
-
-  return our_type;
-}
-
-/**
- * Get the GLib type ID for a DBusMessage boxed type.
- *
- * @returns GLib type
- */
-GType
-dbus_message_get_g_type (void)
-{
-  static GType our_type = 0;
-  
-  if (our_type == 0)
-    our_type = g_boxed_type_register_static ("DBusMessage",
-                                             (GBoxedCopyFunc) dbus_message_ref,
-                                             (GBoxedFreeFunc) dbus_message_unref);
-
-  return our_type;
-}
-
-static DBusGConnection*
-dbus_g_connection_ref (DBusGConnection *gconnection)
-{
-  DBusConnection *c;
-
-  c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
-  dbus_connection_ref (c);
-  return gconnection;
-}
-
-static void
-dbus_g_connection_unref (DBusGConnection *gconnection)
-{
-  DBusConnection *c;
-
-  c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
-  dbus_connection_unref (c);
-}
-
-
-static DBusGMessage*
-dbus_g_message_ref (DBusGMessage *gmessage)
-{
-  DBusMessage *c;
-
-  c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
-  dbus_message_ref (c);
-  return gmessage;
-}
-
-static void
-dbus_g_message_unref (DBusGMessage *gmessage)
-{
-  DBusMessage *c;
-
-  c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
-  dbus_message_unref (c);
-}
-
-/**
- * Get the GLib type ID for a DBusGConnection boxed type.
- *
- * @returns GLib type
- */
-GType
-dbus_g_connection_get_g_type (void)
-{
-  static GType our_type = 0;
-  
-  if (our_type == 0)
-    our_type = g_boxed_type_register_static ("DBusGConnection",
-                                             (GBoxedCopyFunc) dbus_g_connection_ref,
-                                             (GBoxedFreeFunc) dbus_g_connection_unref);
-
-  return our_type;
-}
-
-/**
- * Get the GLib type ID for a DBusGMessage boxed type.
- *
- * @returns GLib type
- */
-GType
-dbus_g_message_get_g_type (void)
-{
-  static GType our_type = 0;
-  
-  if (our_type == 0)
-    our_type = g_boxed_type_register_static ("DBusGMessage",
-                                             (GBoxedCopyFunc) dbus_g_message_ref,
-                                             (GBoxedFreeFunc) dbus_g_message_unref);
-
-  return our_type;
-}
-
-/**
- * Get the DBusConnection corresponding to this DBusGConnection.
- * The return value does not have its refcount incremented.
- *
- * @returns DBusConnection 
- */
-DBusConnection*
-dbus_g_connection_get_connection (DBusGConnection *gconnection)
-{
-  return DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
-}
-
-/**
- * Get the DBusMessage corresponding to this DBusGMessage.
- * The return value does not have its refcount incremented.
- *
- * @returns DBusMessage 
- */
-DBusMessage*
-dbus_g_message_get_message (DBusGMessage *gmessage)
-{
-  return DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
-}
-
 /** @} */ /* end of public API */
 
 #ifdef DBUS_BUILD_TESTS
index 39f8ba8..c38c702 100644 (file)
@@ -1122,10 +1122,8 @@ dbus_g_proxy_begin_call (DBusGProxy *proxy,
  * Collects the results of a method call. The method call was normally
  * initiated with dbus_g_proxy_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. Use
- * dbus_pending_call_get_completed() to check whether a call has been
- * completed. If it's completed, it will not block.
+ * dbus_g_pending_call_set_notify() to be notified asynchronously that a
+ * pending 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.
@@ -1135,7 +1133,7 @@ dbus_g_proxy_begin_call (DBusGProxy *proxy,
  * The list should be terminated with #DBUS_TYPE_INVALID.
  *
  * This function doesn't affect the reference count of the
- * #DBusPendingCall, the caller of dbus_g_proxy_begin_call() still owns
+ * #DBusGPendingCall, the caller of dbus_g_proxy_begin_call() still owns
  * a reference.
  *
  * @todo this should be changed to make a g_malloc() copy of the
@@ -1247,30 +1245,6 @@ dbus_g_proxy_call_no_reply (DBusGProxy               *proxy,
 }
 
 /**
- * Increments refcount on a pending call.
- *
- * @param call the call
- * @returns the same call
- */
-DBusGPendingCall*
-dbus_g_pending_call_ref (DBusGPendingCall  *call)
-{
-  dbus_pending_call_ref (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (call));
-  return call;
-}
-
-/**
- * Decrements refcount on a pending call.
- *
- * @param call the call
- */
-void
-dbus_g_pending_call_unref (DBusGPendingCall  *call)
-{
-  dbus_pending_call_unref (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (call));
-}
-
-/**
  * Sends a message to the interface we're proxying for.  Does not
  * block or wait for a reply. The message is only actually written out
  * when you return to the main loop or block in
index f217cf5..5f565a0 100644 (file)
@@ -80,6 +80,11 @@ main (int argc, char **argv)
       exit (1);
     }
 
+  /* should always get the same one */
+  g_assert (connection == dbus_g_bus_get (DBUS_BUS_SESSION, NULL));
+  g_assert (connection == dbus_g_bus_get (DBUS_BUS_SESSION, NULL));
+  g_assert (connection == dbus_g_bus_get (DBUS_BUS_SESSION, NULL));
+  
   /* Create a proxy object for the "bus driver" */
   
   driver = dbus_g_proxy_new_for_name (connection,
index d3accc8..b6747b0 100644 (file)
@@ -31,6 +31,8 @@ dbus_cleanup_sockets_SOURCES=                 \
        dbus-cleanup-sockets.c
 
 dbus_viewer_SOURCES=                           \
+       dbus-names-model.c                      \
+       dbus-names-model.h                      \
        dbus-tree-view.c                        \
        dbus-tree-view.h                        \
        dbus-viewer.c
diff --git a/tools/dbus-names-model.c b/tools/dbus-names-model.c
new file mode 100644 (file)
index 0000000..09f1236
--- /dev/null
@@ -0,0 +1,352 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-names-model.c GtkTreeModel for names on the bus
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "dbus-names-model.h"
+#include <glib/gi18n.h>
+
+enum
+{
+  MODEL_COLUMN_NAME_DATA,
+  
+  MODEL_COLUMN_LAST
+};
+
+typedef struct
+{
+  int   refcount;
+  char *name;
+} NameData;
+
+static NameData*
+name_data_new (const char *name)
+{
+  NameData *nd;
+
+  nd = g_new0 (NameData, 1);
+
+  nd->refcount = 1;
+  nd->name = g_strdup (name);
+
+  return nd;
+}
+
+static NameData*
+name_data_ref (NameData *nd)
+{
+  nd->refcount += 1;
+  return nd;
+}
+
+static void
+name_data_unref (NameData *nd)
+{
+  nd->refcount -= 1;
+  if (nd->refcount == 0)
+    {
+      g_free (nd->name);
+      g_free (nd);
+    }
+}
+
+static GType
+name_data_get_gtype (void)
+{
+  static GType our_type = 0;
+
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("NameData",
+                                             (GBoxedCopyFunc) name_data_ref,
+                                             (GBoxedFreeFunc) name_data_unref);
+
+  return our_type;
+}
+
+#define NAME_DATA_TYPE (name_data_get_gtype())
+
+
+typedef struct NamesModel NamesModel;
+typedef struct NamesModelClass NamesModelClass;
+
+GType names_model_get_type (void);
+
+struct NamesModel
+{
+  GtkTreeStore parent;
+  DBusGConnection *connection;
+  DBusGProxy *driver_proxy;
+  DBusGPendingCall *pending_list_names;
+};
+
+struct NamesModelClass
+{
+  GtkTreeStoreClass parent;
+};
+
+#define TYPE_NAMES_MODEL              (names_model_get_type ())
+#define NAMES_MODEL(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), TYPE_NAMES_MODEL, NamesModel))
+#define NAMES_MODEL_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NAMES_MODEL, NamesModelClass))
+#define IS_NAMES_MODEL(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), TYPE_NAMES_MODEL))
+#define IS_NAMES_MODEL_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NAMES_MODEL))
+#define NAMES_MODEL_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NAMES_MODEL, NamesModelClass))
+
+static void
+have_names_notify (DBusGPendingCall *call,
+                   void             *data)
+{
+  NamesModel *names_model;
+  GError *error;
+  char **names;
+  int n_elements;
+  int i;
+
+  names_model = NAMES_MODEL (data);
+
+  g_assert (names_model->pending_list_names);
+  g_assert (names_model->driver_proxy);
+
+  names = NULL;
+  error = NULL;
+  if (!dbus_g_proxy_end_call (names_model->driver_proxy,
+                              names_model->pending_list_names,
+                              &error, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+                              &names, &n_elements, DBUS_TYPE_INVALID))
+    {
+      g_assert (names == NULL);
+      g_assert (error != NULL);
+      
+      g_printerr (_("Failed to load names on the bus: %s\n"), error->message);
+      return;
+    }
+
+  i = 0;
+  while (names[i])
+    {
+      NameData *nd;
+      GtkTreeIter iter;
+      
+      nd = name_data_new (names[i]);
+
+      gtk_tree_store_append (GTK_TREE_STORE (names_model),
+                             &iter, NULL);
+
+      gtk_tree_store_set (GTK_TREE_STORE (names_model),
+                          &iter,
+                          MODEL_COLUMN_NAME_DATA, nd,
+                          -1);
+
+      name_data_unref (nd);
+      
+      ++i;
+    }
+  
+  g_strfreev (names);
+}
+
+static void
+names_model_reload (NamesModel *names_model)
+{
+  GtkTreeStore *tree_store;
+
+  tree_store = GTK_TREE_STORE (names_model);
+
+  if (names_model->pending_list_names)
+    {
+      dbus_g_pending_call_cancel (names_model->pending_list_names);
+      dbus_g_pending_call_unref (names_model->pending_list_names);
+      names_model->pending_list_names = NULL;
+    }
+  
+  gtk_tree_store_clear (tree_store);
+  
+  if (names_model->connection == NULL)
+    return;
+  
+  names_model->pending_list_names =
+    dbus_g_proxy_begin_call (names_model->driver_proxy,
+                             "ListNames",
+                             DBUS_TYPE_INVALID);
+
+  dbus_g_pending_call_set_notify (names_model->pending_list_names,
+                                  have_names_notify, names_model, NULL);
+}
+
+static void
+names_model_set_connection (NamesModel      *names_model,
+                            DBusGConnection *connection)
+{
+  const char *match_rule = "type='signal',member='NameOwnerChanged'";
+
+  g_return_if_fail (IS_NAMES_MODEL (names_model));
+  
+  if (connection == names_model->connection)
+    return;
+
+  if (names_model->connection)
+    {
+      dbus_g_proxy_call_no_reply (names_model->driver_proxy,
+                                  "RemoveMatch", 
+                                  DBUS_TYPE_STRING, &match_rule,
+                                  DBUS_TYPE_INVALID);
+      g_object_unref (names_model->driver_proxy);
+      names_model->driver_proxy = NULL;
+      dbus_g_connection_unref (names_model->connection);
+      names_model->connection = NULL;
+    }
+  
+  if (connection)
+    {
+      names_model->connection = connection;
+      dbus_g_connection_ref (names_model->connection);
+      
+      names_model->driver_proxy =
+        dbus_g_proxy_new_for_name (names_model->connection,
+                                   DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+                                   DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+                                   DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS);
+      g_assert (names_model->driver_proxy);
+    }
+
+  names_model_reload (names_model);
+}
+
+G_DEFINE_TYPE(NamesModel, names_model, GTK_TYPE_TREE_STORE)
+
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_CONNECTION
+};
+
+static void
+names_model_dispose (GObject *object)
+{
+  NamesModel *names_model = NAMES_MODEL (object);
+
+  names_model_set_connection (names_model, NULL);
+
+  g_assert (names_model->connection == NULL);
+  g_assert (names_model->driver_proxy == NULL);
+  g_assert (names_model->pending_list_names == NULL);
+
+  (G_OBJECT_CLASS (names_model_parent_class)->dispose) (object);
+}
+
+static void
+names_model_finalize (GObject *object)
+{
+  NamesModel *names_model = NAMES_MODEL (object);
+
+  g_assert (names_model->connection == NULL);
+  g_assert (names_model->driver_proxy == NULL);
+  g_assert (names_model->pending_list_names == NULL);
+
+  (G_OBJECT_CLASS (names_model_parent_class)->finalize) (object);
+}
+
+static void
+names_model_set_property (GObject      *object,
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  NamesModel *names_model;
+
+  names_model = NAMES_MODEL (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONNECTION:
+      names_model_set_connection (names_model, g_value_get_boxed (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+names_model_get_property (GObject      *object,
+                          guint         prop_id,
+                          GValue       *value,
+                          GParamSpec   *pspec)
+{
+  NamesModel *names_model;
+
+  names_model = NAMES_MODEL (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONNECTION:
+      g_value_set_boxed (value, names_model->connection);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+names_model_init (NamesModel *names_model)
+{
+  GtkTreeStore *tree_store;
+  GType types[MODEL_COLUMN_LAST];
+
+  tree_store = GTK_TREE_STORE (names_model);
+
+  types[0] = NAME_DATA_TYPE;
+  gtk_tree_store_set_column_types (tree_store, MODEL_COLUMN_LAST, types);
+}
+
+static void
+names_model_class_init (NamesModelClass *names_model_class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (names_model_class);
+
+  gobject_class->finalize = names_model_finalize;
+  gobject_class->dispose = names_model_dispose;
+  gobject_class->set_property = names_model_set_property;
+  gobject_class->get_property = names_model_get_property;
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_CONNECTION,
+                                  g_param_spec_boxed ("connection",
+                                                       _("Bus connection"),
+                                                       _("Connection to the message bus"),
+                                                       DBUS_TYPE_G_CONNECTION,
+                                                       G_PARAM_READWRITE));
+}
+
+GtkTreeModel*
+names_model_new (DBusGConnection *connection)
+{
+  NamesModel *names_model;
+
+  names_model = g_object_new (TYPE_NAMES_MODEL,
+                              "connection", connection,
+                              NULL);
+
+  return GTK_TREE_MODEL (names_model);
+}
+
diff --git a/tools/dbus-names-model.h b/tools/dbus-names-model.h
new file mode 100644 (file)
index 0000000..c2b54fc
--- /dev/null
@@ -0,0 +1,31 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-names-model.h GtkTreeModel for names on the bus
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef DBUS_NAMES_MODEL_H
+#define DBUS_NAMES_MODEL_H
+
+#include <gtk/gtk.h>
+#include <dbus/dbus-glib.h>
+
+GtkTreeModel* names_model_new (DBusGConnection *connection);
+
+#endif /* DBUS_NAMES_MODEL_H */
index 7c52935..d2898fb 100644 (file)
 #include <string.h>
 #include <config.h>
 #include "dbus-tree-view.h"
-
-#include <libintl.h>
-#define _(x) dgettext (GETTEXT_PACKAGE, x)
-#define N_(x) x
+#include <glib/gi18n.h>
 
 enum
 {
@@ -52,12 +49,7 @@ model_new (void)
   GtkTreeStore *store;
 
   store = gtk_tree_store_new (MODEL_COLUMN_LAST,
-                              G_TYPE_POINTER);
-  /* FIXME, BASE_INFO_TYPE doesn't work right (crashes),
-   * G_TYPE_POINTER has a memleak. BASE_INFO_TYPE problem maybe just a
-   * bad GTK build on my laptop.
-   */
-  /* BASE_INFO_TYPE); */
+                              BASE_INFO_TYPE);
 
   model = GTK_TREE_MODEL (store);
 
@@ -114,7 +106,6 @@ set_info (GtkTreeModel *model,
    */
   if (root != NULL)
     {
-      base_info_ref (info); /* FIXME once boxed types are working */
       gtk_tree_store_set (store, root,
                           MODEL_COLUMN_INFO, info,
                           -1);
index abd299f..524030c 100644 (file)
 #include <string.h>
 #include <gtk/gtk.h>
 #include "dbus-tree-view.h"
+#include "dbus-names-model.h"
 #include <glib/dbus-gparser.h>
 #include <glib/dbus-gutils.h>
 #include <dbus/dbus-glib.h>
-
-#include <libintl.h>
-#define _(x) dgettext (GETTEXT_PACKAGE, x)
-#define N_(x) x
-
-typedef struct
-{
-  int refcount;
-  char *name;
-
-} ServiceData;
-
-static ServiceData*
-service_data_new (const char *name)
-{
-  ServiceData *sd;
-
-  sd = g_new0 (ServiceData, 1);
-
-  sd->refcount = 1;
-  sd->name = g_strdup (name);
-
-  return sd;
-}
-
-static void
-service_data_ref (ServiceData *sd)
-{
-  sd->refcount += 1;
-}
-
-static void
-service_data_unref (ServiceData *sd)
-{
-  sd->refcount -= 1;
-  if (sd->refcount == 0)
-    {
-      g_free (sd->name);
-      g_free (sd);
-    }
-}
+#include <glib/gi18n.h>
 
 typedef struct
 {
   GtkWidget *window;
   GtkWidget *treeview;
-  GtkWidget *service_menu;
+  GtkWidget *name_menu;
 
-  GSList *services;
+  GtkTreeModel *names_model;
   
 } TreeWindow;
 
@@ -92,12 +53,14 @@ window_closed_callback (GtkWidget  *window,
 }
 
 static TreeWindow*
-tree_window_new (void)
+tree_window_new (DBusGConnection *connection,
+                 GtkTreeModel    *names_model)
 {
   TreeWindow *w;
   GtkWidget *sw;
   GtkWidget *vbox;
   GtkWidget *hbox;
+  GtkWidget *combo;
 
   /* Should use glade, blah */
   
@@ -117,6 +80,17 @@ tree_window_new (void)
   hbox = gtk_hbox_new (FALSE, 6);
   gtk_container_add (GTK_CONTAINER (vbox), hbox);
 
+
+  /* Create names option menu */
+  if (connection)
+    {
+      w->names_model = names_model;
+
+      combo = gtk_combo_box_new_with_model (w->names_model);
+
+      gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
+    }
+  
   /* Create tree view */
   
   sw = gtk_scrolled_window_new (NULL, NULL);
@@ -130,10 +104,6 @@ tree_window_new (void)
 
   gtk_container_add (GTK_CONTAINER (sw), w->treeview);
 
-  /* Create services option menu */
-
-  
-
   /* Show everything */
   gtk_widget_show_all (w->window);
 
@@ -287,11 +257,11 @@ load_child_nodes (const char *service_name,
 }
 
 static NodeInfo*
-load_from_service (const char *service_name,
-                   GError    **error)
+load_from_service (DBusGConnection *connection,
+                   const char      *service_name,
+                   GError         **error)
 {
-  DBusGConnection *connection;
-  DBusGProxy *root_proxy;
+   DBusGProxy *root_proxy;
   DBusGPendingCall *call;
   const char *data;
   NodeInfo *node;
@@ -300,11 +270,7 @@ load_from_service (const char *service_name,
   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,
@@ -396,6 +362,9 @@ main (int argc, char **argv)
   gboolean end_of_args;
   GSList *tmp;
   gboolean services;
+  DBusGConnection *connection;
+  GError *error;
+  GtkTreeModel *names_model;
   
   bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR);
   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
@@ -443,20 +412,41 @@ main (int argc, char **argv)
       ++i;
     }
 
+  if (services)
+    {
+      error = NULL;
+      connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+      if (connection == NULL)
+        {
+          g_printerr ("Could not open bus connection: %s\n",
+                      error->message);
+          g_error_free (error);
+          exit (1);
+        }
+
+      g_assert (connection == dbus_g_bus_get (DBUS_BUS_SESSION, NULL));
+
+      names_model = names_model_new (connection);
+    }
+  else
+    {
+      connection = NULL;
+      names_model = NULL;
+    }
+  
   files = g_slist_reverse (files);
 
   tmp = files;
   while (tmp != NULL)
     {
       NodeInfo *node;
-      GError *error;
       const char *filename;
 
       filename = tmp->data;
 
       error = NULL;
       if (services)
-        node = load_from_service (filename, &error);
+        node = load_from_service (connection, filename, &error);
       else
         node = description_load_from_file (filename,
                                            &error);
@@ -485,7 +475,7 @@ main (int argc, char **argv)
 
           path = _dbus_gutils_split_path (name);
           
-          w = tree_window_new ();          
+          w = tree_window_new (connection, names_model); 
           dbus_tree_view_update (GTK_TREE_VIEW (w->treeview),
                                  (const char**) path,
                                  node);