local-export-daemon r7238 - trunk/src



Author: otaylor
Date: Mon Mar 17 19:18:56 2008
New Revision: 7238
URL: http://svn.gnome.org/viewvc/local-export-daemon?rev=7238&view=rev

Log:
Update to latest version of hippo-dbus-helper from libddm

Modified:
   trunk/src/hippo-dbus-helper.c
   trunk/src/hippo-dbus-helper.h

Modified: trunk/src/hippo-dbus-helper.c
==============================================================================
--- trunk/src/hippo-dbus-helper.c	(original)
+++ trunk/src/hippo-dbus-helper.c	Mon Mar 17 19:18:56 2008
@@ -4,6 +4,7 @@
 #include <glib.h>
 #include <string.h>
 #include "hippo-dbus-helper.h"
+#include <dbus/dbus-glib-lowlevel.h>
 
 typedef struct {
     char *name;
@@ -18,19 +19,48 @@
 } HippoDBusObject;
 
 typedef struct {
+    guint refcount;
+    DBusConnection *connection;
     char *well_known_name;
     char *owner;
     void *data;
     const HippoDBusServiceTracker *tracker;
     const HippoDBusSignalTracker  *signal_handlers;
+    guint removed : 1;
 } HippoDBusService;
 
 typedef struct {
     GHashTable *interfaces;
     GHashTable *services_by_well_known;
     GHashTable *services_by_owner;
+    GHashTable *name_owners;
+    GSList *connection_trackers;
 } HippoDBusHelper;
 
+typedef struct {
+    const HippoDBusConnectionTracker *tracker;
+    void *data;
+    DBusConnection *connection;
+} HippoDBusConnection;
+
+typedef enum {
+    NAME_OWNERSHIP_UNKNOWN,
+    NAME_OWNERSHIP_OWNED,
+    NAME_OWNERSHIP_NOT_OWNED
+} NameOwnerState;
+
+typedef struct {
+    NameOwnerState state;
+    HippoDBusNameOwnershipStyle style;
+    char *well_known_name;
+    const HippoDBusNameOwner *owner;
+    void *data;
+} NameOwner;
+
+static guint try_session_connect_timeout = 0;
+static GSList *session_connection_trackers = NULL;
+static gboolean session_ever_attempted = FALSE;
+
 static DBusHandlerResult hippo_dbus_helper_handle_object_message(DBusConnection  *connection,
                                                                  DBusMessage     *message,
                                                                  HippoDBusObject *object);
@@ -182,10 +212,21 @@
 {
     HippoDBusHelper *helper = data;
 
+    /* we should be disconnected, so these should have been notified...
+     * unless we managed to unref the connection without ever
+     * completing dispatch. This warning probably isn't hard to
+     * fix but since it's probably an app bug if it happens,
+     * let's leave it for now.
+     */
+    if (helper->connection_trackers != NULL) {
+        g_warning("DBusConnection finalized without dispatching the incoming queue, which is not supported by hippo-dbus-helper.c right now (are you sure you meant to finalize it?)");
+    }
+    
     /* FIXME free the hash contents */
 
     g_hash_table_destroy(helper->services_by_well_known);
     g_hash_table_destroy(helper->services_by_owner);
+    g_hash_table_destroy(helper->name_owners);
     g_hash_table_destroy(helper->interfaces);
     g_free(helper);
 }
@@ -208,6 +249,10 @@
 
         helper->services_by_well_known = g_hash_table_new(g_str_hash, g_str_equal);
         helper->services_by_owner = g_hash_table_new(g_str_hash, g_str_equal);
+
+        /* string name to GSList of NameOwner */
+        helper->name_owners = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                    g_free, NULL);
         
         dbus_connection_set_data(connection, slot, helper, helper_free);
 
@@ -230,13 +275,23 @@
     HippoDBusInterface *iface;
     HippoDBusHelper *helper;
 
-    iface = iface_new(name, members, properties);
-
     helper = get_helper(connection);
-
-    g_return_if_fail(g_hash_table_lookup(helper->interfaces, iface->name) == NULL);
-
-    g_hash_table_replace(helper->interfaces, iface->name, iface);
+    
+    iface = g_hash_table_lookup(helper->interfaces, name);
+    if (iface == NULL) {    
+        iface = iface_new(name, members, properties);
+        g_hash_table_replace(helper->interfaces, iface->name, iface);
+    } else {
+        /* If we ever add unregister_interface() then we'll have to refcount
+         * the interface object and increment the count here.
+         * But since you can't unregister right now, we just do nothing
+         * on a second registration.
+         */
+        if (iface->members != members ||
+            iface->properties != properties) {
+            g_warning("registered an interface twice, differently each time");
+        }
+    }
 }
 
 static void
@@ -995,7 +1050,8 @@
 }
 
 static HippoDBusService*
-service_new(const char                    *well_known_name,
+service_new(DBusConnection                *connection,
+            const char                    *well_known_name,
             const HippoDBusServiceTracker *tracker,
             const HippoDBusSignalTracker  *signal_handlers,
             void                          *data)
@@ -1003,6 +1059,8 @@
     HippoDBusService *service;
 
     service = g_new0(HippoDBusService, 1);
+    service->refcount = 1;
+    service->connection = connection;
     service->well_known_name = g_strdup(well_known_name);
     service->tracker = tracker;
     service->signal_handlers = signal_handlers;
@@ -1011,12 +1069,23 @@
     return service;
 }
 
+static HippoDBusService *
+service_ref(HippoDBusService *service)
+{
+    service->refcount++;
+
+    return service;
+}
+
 static void
-service_free(HippoDBusService *service)
+service_unref(HippoDBusService *service)
 {
-    g_free(service->well_known_name);
-    g_free(service->owner);
-    g_free(service);
+    service->refcount--;
+    if (service->refcount == 0) {
+        g_free(service->well_known_name);
+        g_free(service->owner);
+        g_free(service);
+    }
 }
 
 static void
@@ -1078,9 +1147,18 @@
 }
 
 static void
+on_startup_nonexistence(HippoDBusService *service)
+{
+    if (!service->removed)
+        (* service->tracker->unavailable_handler) (service->connection,
+                                                   service->well_known_name,
+                                                   NULL,
+                                                   service->data);
+}
+
+static void
 handle_name_owner_changed(DBusConnection *connection,
                           const char     *well_known_name,
-                          /* old and new may be NULL */
                           const char     *old_owner,
                           const char     *new_owner)
 {
@@ -1093,20 +1171,21 @@
     if (service == NULL)
         return; /* we don't care about this */
 
-    if (service->owner &&
-        (new_owner == NULL ||
-         strcmp(service->owner, new_owner) != 0)) {
-        /* Our previously-believed owner is going away */
+    if ((new_owner == NULL ||
+         (service->owner != NULL && strcmp(service->owner, new_owner) != 0))) {
+        /* Our previously-believed owner is going away, or we didn't find
+         * the service on startup. */
         char *owner;
-        
+
         g_hash_table_remove(helper->services_by_owner,
                             service->owner);
         owner = service->owner;
         service->owner = NULL;
-
+        
         g_debug("Service '%s' is now unavailable, old owner was '%s'",
                 service->well_known_name,
-                owner);
+                owner ? owner : "");
+
         (* service->tracker->unavailable_handler) (connection,
                                                    service->well_known_name,
                                                    owner,
@@ -1132,30 +1211,30 @@
     }
 }
 
-typedef struct {
-    DBusConnection *connection;
-    char *well_known_name;
-} GetOwnerData;
-
-static GetOwnerData*
-get_owner_data_new(DBusConnection *connection,
-                   const char     *well_known_name)
-{
-    GetOwnerData *god;
-    god = g_new0(GetOwnerData, 1);
-    god->connection = connection;
-    god->well_known_name = g_strdup(well_known_name);
-    dbus_connection_ref(connection);
-
-    return god;
-}
-
 static void
-get_owner_data_free(GetOwnerData *god)
+on_start_service_by_name_reply(DBusPendingCall *pending,
+                               void            *user_data)
 {
-    dbus_connection_unref(god->connection);
-    g_free(god->well_known_name);
-    g_free(god);
+    DBusMessage *reply;
+    HippoDBusService *service;
+
+    service = user_data;
+    
+    reply = dbus_pending_call_steal_reply(pending);
+    if (reply == NULL) {
+        g_warning("NULL reply in on_start_service_by_name_reply?");
+        return;
+    }
+    
+    if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
+        /* Just ignore, we'll get a NameOwnerChanged */
+    } else {
+        const char *message = "Unknown error";
+        dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &message, DBUS_TYPE_INVALID);
+        
+        g_warning("Initial activation of service '%s' failed: %s", service->well_known_name, message);
+        on_startup_nonexistence(service);        
+    }
 }
 
 static void
@@ -1163,9 +1242,9 @@
                    void            *user_data)
 {
     DBusMessage *reply;
-    GetOwnerData *god;
+    HippoDBusService *service;
 
-    god = user_data;
+    service = user_data;
     
     reply = dbus_pending_call_steal_reply(pending);
     if (reply == NULL) {
@@ -1178,19 +1257,68 @@
         if (!dbus_message_get_args(reply, NULL,
                                    DBUS_TYPE_STRING, &v_STRING,
                                    DBUS_TYPE_INVALID)) {
-            g_debug("GetNameOwner has wrong args '%s'",
-                    dbus_message_get_signature(reply));
+            g_warning("GetNameOwner has wrong args '%s'",
+                      dbus_message_get_signature(reply));
+            on_startup_nonexistence(service);
         } else {
-            g_debug("Got name owner '%s' for '%s'",
-                    v_STRING, god->well_known_name);
-            if (*v_STRING == '\0')
-                v_STRING = NULL;
-
-            handle_name_owner_changed(god->connection,
-                                      god->well_known_name,
+            handle_name_owner_changed(service->connection,
+                                      service->well_known_name,
                                       NULL,
                                       v_STRING);
         }
+    } else  {
+        if (strcmp(dbus_message_get_error_name(reply),
+                   "org.freedesktop.DBus.Error.NameHasNoOwner") == 0) {
+
+            /* One time on startup, we will start the service if
+             * it's not running, which should lead to a notification.
+             * We don't check the error though and just give up
+             * if it fails.
+             */
+            if ((service->tracker->flags & HIPPO_DBUS_SERVICE_START_IF_NOT_RUNNING) != 0) {
+                DBusMessage *msg;
+                dbus_uint32_t flags;
+                DBusPendingCall *call;
+
+                msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+                                                    DBUS_PATH_DBUS,
+                                                    DBUS_INTERFACE_DBUS,
+                                                    "StartServiceByName");
+                
+                flags = 0;
+                if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &service->well_known_name,
+                                               DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID))
+                    g_error("out of memory");
+
+                call = NULL;
+                if (!dbus_connection_send_with_reply(service->connection, msg, &call, -1))
+                    g_error("out of memory");
+
+                /* Call == NULL means that we're already disconnected; in that case, we'll
+                 * omit any notification and assume that we're in some sort of
+                 * start-and-immediately-exit race.
+                 */
+                if (call != NULL) {
+                    if (!dbus_pending_call_set_notify(call, on_start_service_by_name_reply,
+                                                      service_ref(service),
+                                                      (DBusFreeFunction) service_unref))
+                        g_error("out of memory");
+
+                    /* rely on connection to hold a reference to it */
+                    dbus_pending_call_unref(call);
+                }
+                dbus_message_unref(msg);
+            } else {
+                on_startup_nonexistence(service);
+            }
+            
+        } else {
+            const char *message = "Unknown error";
+        
+            dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &message, DBUS_TYPE_INVALID);
+            g_warning("GetNameOwner failed: %s", message);
+            on_startup_nonexistence(service);
+        }
     }
     
     dbus_message_unref(reply);
@@ -1213,7 +1341,7 @@
     /* multiple registrations for the same name isn't allowed for now */
     g_return_if_fail(g_hash_table_lookup(helper->services_by_well_known, well_known_name) == NULL);
     
-    service = service_new(well_known_name, tracker, signal_handlers, data);
+    service = service_new(connection, well_known_name, tracker, signal_handlers, data);
 
     g_hash_table_replace(helper->services_by_well_known, service->well_known_name, service);
 
@@ -1233,18 +1361,24 @@
         g_error("out of memory");
     
     call = NULL;               
-    dbus_connection_send_with_reply(connection, get_owner, &call, -1);
+    if (!dbus_connection_send_with_reply(connection, get_owner, &call, -1))
+        g_error("out of memory");
+
+    /* Call == NULL means that we're already disconnected; in that case, we'll
+     * omit any notification and assume that we're in some sort of
+     * start-and-immediately-exit race.
+     */
     if (call != NULL) {
         if (!dbus_pending_call_set_notify(call, on_get_owner_reply,
-                                          get_owner_data_new(connection, well_known_name),
-                                          (DBusFreeFunction) get_owner_data_free))
+                                          service_ref(service),
+                                          (DBusFreeFunction) service_unref))
             g_error("out of memory");
         
         /* rely on connection to hold a reference to it, if finalized
-         * I think on_get_song_props_reply won't get called though, 
-         * which is fine currently
+         * I think on_get_owner_reply won't get called. Again we just omit
+         * notification.
          */
-        dbus_pending_call_unref(call);        
+        dbus_pending_call_unref(call);
     }
 }
 
@@ -1265,6 +1399,8 @@
         g_warning("Multiple registered trackers for same service doesn't work yet");
         return;
     }
+
+    service->removed = TRUE;
     
     set_signal_handlers_matched(connection, well_known_name, service->signal_handlers, FALSE);
     set_owner_matched(connection, well_known_name, FALSE);
@@ -1280,7 +1416,349 @@
                                                    service->data);
     }
 
-    service_free(service);
+    service_unref(service);
+}
+
+static gboolean attempt_session_connect_timeout(void *data);
+
+static void
+ensure_session_connect_attempt(void)
+{
+    if (try_session_connect_timeout == 0 &&
+        session_connection_trackers != NULL) {
+        int interval_secs;
+        if (session_ever_attempted) {
+            interval_secs = 15; /* retry periodically */
+        } else {
+            interval_secs = 0;  /* on startup, try immediately */
+        }
+        /* FIXME use g_timeout_add_seconds() once it's been available longer */
+        try_session_connect_timeout =            
+            g_timeout_add(interval_secs * 1000, attempt_session_connect_timeout, NULL);
+    }
+}
+
+static gboolean
+attempt_session_connect_timeout(void *data)
+{
+    DBusConnection *connection;
+    GSList *tmp;
+    GSList *copy;
+    HippoDBusHelper *helper;
+
+    /* we always return FALSE to remove ourselves */
+    try_session_connect_timeout = 0;
+    
+    session_ever_attempted = TRUE;
+    
+    connection = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+    if (connection == NULL) {
+        /* try again (since we set session_ever_attempted = TRUE, this
+         * will be after a timeout; also we may exit if that's what the
+         * app normally does on session bus disconnect)
+         */
+        ensure_session_connect_attempt();
+        return FALSE; /* remove ourselves */
+    }
+
+    dbus_connection_setup_with_g_main(connection, NULL);
+
+    helper = get_helper(connection);
+    
+    /* this is broken of course, since it means
+     * we can invoke a handler after it's removed.
+     */
+    copy = g_slist_copy(session_connection_trackers);
+
+    for (tmp = copy; tmp != NULL; tmp = tmp->next) {
+        HippoDBusConnection *closure = tmp->data;
+
+        closure->connection = connection;
+        dbus_connection_ref(closure->connection);
+        
+        (* closure->tracker->connected_handler) (closure->connection, closure->data);
+
+        helper->connection_trackers = g_slist_prepend(helper->connection_trackers,
+                                                      closure);
+    }
+
+    g_slist_free(copy);
+
+    dbus_connection_unref(connection);
+
+    return FALSE;
+}
+
+void
+hippo_dbus_helper_register_connection_tracker (DBusBusType                       bus_type,
+                                               const HippoDBusConnectionTracker *tracker,
+                                               void                             *data)
+{
+    HippoDBusConnection *closure;
+    
+    if (bus_type != DBUS_BUS_SESSION) {
+        g_warning ("Only the session bus is supported in %s for now", __FUNCTION__);
+        return;
+    }
+
+    closure = g_new0(HippoDBusConnection, 1);
+    closure->tracker = tracker;
+    closure->data = data;
+    
+    session_connection_trackers = g_slist_append(session_connection_trackers, closure);
+
+    ensure_session_connect_attempt();
+}
+
+void
+hippo_dbus_helper_unregister_connection_tracker (DBusBusType                       bus_type,
+                                                 const HippoDBusConnectionTracker *tracker,
+                                                 void                             *data)
+{
+    GSList *tmp;
+    HippoDBusConnection *closure;
+
+    closure = NULL;
+    for (tmp = session_connection_trackers; tmp != NULL; tmp = tmp->next) {
+        closure = tmp->data;
+        if (closure->tracker == tracker && closure->data == data)
+            break;
+    }
+
+    if (closure == NULL) {
+        g_warning("attempted to unregister not-registered connection tracker");
+        return;
+    }
+
+    session_connection_trackers = g_slist_remove(session_connection_trackers, closure);
+
+    if (closure->connection) {
+        HippoDBusHelper *helper;
+        
+        helper = get_helper(closure->connection);
+
+        helper->connection_trackers = g_slist_remove(helper->connection_trackers, closure);
+        
+        (* closure->tracker->disconnected_handler) (closure->connection, closure->data);
+        dbus_connection_unref(closure->connection);
+        closure->connection = NULL;
+    }
+    
+    g_free(closure);
+}
+
+static NameOwner*
+name_owner_new(const char                   *well_known_name,
+               HippoDBusNameOwnershipStyle   ownership_style,
+               const HippoDBusNameOwner     *owner,
+               void                         *data)
+{
+    NameOwner *no;
+
+    no = g_new0(NameOwner, 1);
+    no->state = NAME_OWNERSHIP_UNKNOWN;
+    no->well_known_name = g_strdup(well_known_name);
+    no->style = ownership_style;
+    no->owner = owner;
+    no->data = data;
+
+    return no;
+}
+
+static void
+name_owner_free(NameOwner *no)
+{
+    g_free(no->well_known_name);
+    g_free(no);
+}
+
+/* FIXME I think this isn't really needed since the bus always sends us
+ * this signal even if we don't match it
+ */
+static void
+set_name_acquired_matched(DBusConnection *connection,
+                          const char     *bus_name,
+                          gboolean        matched)
+{
+    char *s;
+    
+    s = g_strdup_printf("type='signal',sender='"
+                        DBUS_SERVICE_DBUS
+                        "',interface='"
+                        DBUS_INTERFACE_DBUS
+                        "',member='"
+                        "NameAcquired"
+                        "',arg0='%s'",
+                        bus_name);
+    
+    /* this is nonblocking since we don't ask for errors */
+    if (matched)
+        dbus_bus_add_match(connection,
+                           s, NULL);
+    else
+        dbus_bus_remove_match(connection, s, NULL);
+    
+    g_free(s);
+}
+
+/* FIXME I think this isn't really needed since the bus always sends us
+ * this signal even if we don't match it
+ */
+static void
+set_name_lost_matched(DBusConnection *connection,
+                      const char     *bus_name,
+                      gboolean        matched)
+{
+    char *s;
+    
+    s = g_strdup_printf("type='signal',sender='"
+                        DBUS_SERVICE_DBUS
+                        "',interface='"
+                        DBUS_INTERFACE_DBUS
+                        "',member='"
+                        "NameLost"
+                        "',arg0='%s'",
+                        bus_name);
+    
+    /* this is nonblocking since we don't ask for errors */
+    if (matched)
+        dbus_bus_add_match(connection,
+                           s, NULL);
+    else
+        dbus_bus_remove_match(connection, s, NULL);
+    
+    g_free(s);
+}
+
+static gboolean
+request_name(DBusConnection             *connection,
+             const char                 *bus_name,
+             HippoDBusNameOwnershipStyle ownership_style)
+{
+    unsigned int flags;
+    int result;
+
+    flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
+    if (ownership_style != HIPPO_DBUS_NAME_OWNED_OPTIONALLY)        
+        flags |= DBUS_NAME_FLAG_DO_NOT_QUEUE;
+    if (ownership_style == HIPPO_DBUS_NAME_SINGLE_INSTANCE_REPLACING_CURRENT_OWNER)
+        flags |= DBUS_NAME_FLAG_REPLACE_EXISTING;
+
+    /* FIXME this should really be async */
+
+    /* on error, result is -1 */
+    result = dbus_bus_request_name(connection, bus_name,
+                                   flags,
+                                   NULL);
+    
+    if (result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ||
+        result == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) {
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+static void
+handle_name_ownership_maybe_changed(DBusConnection *connection,
+                                    const char     *name,
+                                    gboolean        owned)
+{
+    GSList *list;
+    GSList *l;
+    HippoDBusHelper *helper;
+
+    helper = get_helper(connection);
+
+    list = g_hash_table_lookup(helper->name_owners, name);
+    if (list == NULL)
+        return;
+
+    /* FIXME not safe against registration/unregistration during callbacks */
+    
+    for (l = list; l != NULL; l = l->next) {
+        NameOwner *no = l->data;
+
+        if (owned && no->state != NAME_OWNERSHIP_OWNED) {
+            no->state = NAME_OWNERSHIP_OWNED;
+            (* no->owner->owned_handler) (connection, no->data);            
+        } else if (!owned && no->state != NAME_OWNERSHIP_NOT_OWNED) {
+            no->state = NAME_OWNERSHIP_NOT_OWNED;
+            (* no->owner->not_owned_handler) (connection, no->data);
+        }
+    }
+}
+
+void
+hippo_dbus_helper_register_name_owner(DBusConnection                   *connection,
+                                      const char                       *well_known_name,
+                                      HippoDBusNameOwnershipStyle       ownership_style,
+                                      const HippoDBusNameOwner         *owner,
+                                      void                             *data)
+{
+    NameOwner *no;
+    GSList *list;
+    HippoDBusHelper *helper;
+    gboolean owned;
+
+    helper = get_helper(connection);
+
+    no = name_owner_new(well_known_name, ownership_style, owner, data);
+
+    list = g_hash_table_lookup(helper->name_owners, well_known_name);
+    list = g_slist_prepend(list, no);
+    g_hash_table_replace(helper->name_owners, g_strdup(well_known_name), list);
+
+    set_name_acquired_matched(connection, well_known_name, TRUE);
+    set_name_lost_matched(connection, well_known_name, TRUE);
+
+    owned = request_name(connection, well_known_name, ownership_style);
+    
+    handle_name_ownership_maybe_changed(connection, well_known_name,
+                                        owned);
+}
+
+void
+hippo_dbus_helper_unregister_name_owner(DBusConnection                   *connection,
+                                        const char                       *well_known_name,
+                                        const HippoDBusNameOwner         *owner,
+                                        void                             *data)
+{    
+    NameOwner *no;
+    GSList *list;
+    GSList *l;
+    HippoDBusHelper *helper;
+
+    helper = get_helper(connection);
+
+    list = g_hash_table_lookup(helper->name_owners, well_known_name);
+
+    no = NULL;
+    for (l = list; l != NULL; l = l->next) {
+        NameOwner *existing = l->data;
+        if (existing->owner == owner &&
+            existing->data == data &&
+            strcmp(existing->well_known_name, well_known_name) == 0) {
+            no = existing;
+            break;
+        }
+    }
+    if (no == NULL) {
+        g_warning("Attempt to unregister name owner for %s, but none found", well_known_name);
+        return;
+    }
+
+    list = g_slist_remove(list, no);
+    g_hash_table_replace(helper->name_owners, g_strdup(well_known_name), list);    
+
+    set_name_acquired_matched(connection, well_known_name, FALSE);
+    set_name_lost_matched(connection, well_known_name, FALSE);
+
+    if (no->state != NAME_OWNERSHIP_NOT_OWNED) {
+        (* no->owner->not_owned_handler) (connection, no->data);
+    }
+    
+    name_owner_free(no);
 }
 
 static DBusHandlerResult
@@ -1308,6 +1786,68 @@
         } else {
             g_warning("NameOwnerChanged had wrong args???");
         }
+    } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameLost") &&
+               dbus_message_has_sender(message, DBUS_SERVICE_DBUS)) {
+        const char *name = NULL;
+        if (dbus_message_get_args(message, NULL,
+                                  DBUS_TYPE_STRING, &name,
+                                  DBUS_TYPE_INVALID)) {
+            g_debug("helper.c NameLost %s", name);
+            
+            handle_name_ownership_maybe_changed(connection, name, FALSE);
+        } else {
+            g_warning("NameLost had wrong args???");
+        }
+    } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameAcquired") &&
+               dbus_message_has_sender(message, DBUS_SERVICE_DBUS)) {
+        const char *name = NULL;
+        if (dbus_message_get_args(message, NULL,
+                                  DBUS_TYPE_STRING, &name,
+                                  DBUS_TYPE_INVALID)) {
+            g_debug("helper.c NameAcquired %s", name);
+            
+            handle_name_ownership_maybe_changed(connection, name, TRUE);
+        } else {
+            g_warning("NameAcquired had wrong args???");
+        }
+    }
+
+    if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) {
+        HippoDBusHelper *helper = get_helper(connection); 
+        const char *sender = dbus_message_get_sender(message);
+        HippoDBusService *service = g_hash_table_lookup(helper->services_by_owner, sender);
+
+        if (service != NULL) {
+            int i;
+
+            for (i = 0; service->signal_handlers[i].interface != NULL; i++) {
+                const HippoDBusSignalTracker *tracker = &service->signal_handlers[i];
+                if (dbus_message_is_signal(message, tracker->interface, tracker->signal)) {
+                    tracker->handler(connection, message, service->data);
+                }
+            }
+        }
+
+        if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
+
+            /* FIXME we need to pretend we got NameLost on all owned bus names */
+            
+            while (helper->connection_trackers != NULL) {
+                HippoDBusConnection *closure;
+
+                closure = helper->connection_trackers->data;
+                helper->connection_trackers = g_slist_remove(helper->connection_trackers, closure);
+                
+                (* closure->tracker->disconnected_handler) (closure->connection, closure->data);
+                dbus_connection_unref(closure->connection);
+                closure->connection = NULL;
+            }
+
+            /* If we don't exit (since someone told libdbus not to), then we'll try connecting
+             * again in a while
+             */
+            ensure_session_connect_attempt();
+        }
     }
     
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -1320,6 +1860,7 @@
     char              *path;
     char              *interface;
     char              *method_prefix;
+    int                timeout;
 };
 
 HippoDBusProxy*
@@ -1338,13 +1879,21 @@
     proxy->bus_name = g_strdup(bus_name);
     proxy->path = g_strdup(path);
     proxy->interface = g_strdup(interface);
+    proxy->timeout = -1; /* Use default D-BUS value */
 
     return proxy;
 }
 
 void
+hippo_dbus_proxy_set_timeout(HippoDBusProxy *proxy,
+                             int             timeout_milliseconds)
+{
+    proxy->timeout = timeout_milliseconds;
+}
+
+void
 hippo_dbus_proxy_set_method_prefix(HippoDBusProxy *proxy,
-                                   char           *method_prefix)
+                                   const char     *method_prefix)
 {
     if (proxy->method_prefix == method_prefix)
         return;
@@ -1410,7 +1959,7 @@
         }
     }
     
-    reply = dbus_connection_send_with_reply_and_block(proxy->connection, call, -1, error);
+    reply = dbus_connection_send_with_reply_and_block(proxy->connection, call, proxy->timeout, error);
     
     dbus_message_unref(call);
     
@@ -1593,7 +2142,7 @@
         DBusPendingCall *pending;
         
         pending = NULL;
-        dbus_connection_send_with_reply(proxy->connection, call, &pending, -1);
+        dbus_connection_send_with_reply(proxy->connection, call, &pending, proxy->timeout);
 
         if (pending == NULL) {
             g_warning("Failed to send method call %s (probably connection is disconnected)", method);
@@ -1734,6 +2283,20 @@
     }
 }
 
+dbus_bool_t
+hippo_dbus_proxy_VOID__VOID(HippoDBusProxy *proxy,
+                            const char     *method)
+{
+    DBusMessage *reply;
+    DBusError derror;
+    
+    dbus_error_init(&derror);    
+    reply = hippo_dbus_proxy_call_method_sync(proxy, method, &derror,
+                                              DBUS_TYPE_INVALID);
+    
+    return hippo_dbus_proxy_finish_method_call_freeing_reply(reply, method, &derror,
+                                                             DBUS_TYPE_INVALID);
+}
 
 dbus_bool_t
 hippo_dbus_proxy_INT32__VOID(HippoDBusProxy *proxy,

Modified: trunk/src/hippo-dbus-helper.h
==============================================================================
--- trunk/src/hippo-dbus-helper.h	(original)
+++ trunk/src/hippo-dbus-helper.h	Mon Mar 17 19:18:56 2008
@@ -15,12 +15,24 @@
     HIPPO_DBUS_MEMBER_SIGNAL
 } HippoDBusMemberType;
 
+typedef enum {
+    HIPPO_DBUS_SERVICE_START_IF_NOT_RUNNING = 1 << 0
+} HippoDBusServiceTrackerFlags;
+
+typedef enum {
+    HIPPO_DBUS_NAME_SINGLE_INSTANCE_REPLACING_CURRENT_OWNER,
+    HIPPO_DBUS_NAME_SINGLE_INSTANCE,
+    HIPPO_DBUS_NAME_OWNED_OPTIONALLY
+} HippoDBusNameOwnershipStyle;
+
 
 typedef struct HippoDBusProxy HippoDBusProxy;
 typedef struct HippoDBusMember HippoDBusMember;
 typedef struct HippoDBusProperty HippoDBusProperty;
 typedef struct HippoDBusServiceTracker HippoDBusServiceTracker;
 typedef struct HippoDBusSignalTracker HippoDBusSignalTracker;
+typedef struct HippoDBusConnectionTracker HippoDBusConnectionTracker;
+typedef struct HippoDBusNameOwner HippoDBusNameOwner;
 
 
 typedef void        (* HippoDBusReplyHandler) (DBusMessage *reply,
@@ -56,6 +68,16 @@
                                                      DBusMessage    *message,
                                                      void           *data);
 
+typedef void (* HippoDBusConnectedHandler)          (DBusConnection *connection,
+                                                     void           *data);
+typedef void (* HippoDBusDisconnectedHandler)       (DBusConnection *connection,
+                                                     void           *data);
+
+typedef void (* HippoDBusNameOwnedHandler)          (DBusConnection *connection,
+                                                     void           *data);
+typedef void (* HippoDBusNameNotOwnedHandler)       (DBusConnection *connection,
+                                                     void           *data);
+
 struct HippoDBusMember
 {
     HippoDBusMemberType member_type;
@@ -78,6 +100,7 @@
 
 struct HippoDBusServiceTracker
 {
+    HippoDBusServiceTrackerFlags flags;
     HippoDBusServiceAvailableHandler available_handler;
     HippoDBusServiceUnavailableHandler unavailable_handler;
 };
@@ -89,6 +112,18 @@
     HippoDBusSignalHandler handler;
 };
 
+struct HippoDBusConnectionTracker
+{
+    HippoDBusConnectedHandler connected_handler;
+    HippoDBusDisconnectedHandler disconnected_handler;
+};
+
+struct HippoDBusNameOwner
+{
+    HippoDBusNameOwnedHandler owned_handler;
+    HippoDBusNameNotOwnedHandler  not_owned_handler;
+};
+
 void              hippo_dbus_helper_register_interface   (DBusConnection          *connection,
                                                           const char              *name,
                                                           const HippoDBusMember   *members,
@@ -126,16 +161,42 @@
                                                           HippoDBusArgAppender     appender,
                                                           void                    *appender_data);
                                                           
+void hippo_dbus_helper_register_service_tracker      (DBusConnection                   *connection,
+                                                      const char                       *well_known_name,
+                                                      const HippoDBusServiceTracker    *tracker,
+                                                      const HippoDBusSignalTracker     *signal_handlers,
+                                                      void                             *data);
+void hippo_dbus_helper_unregister_service_tracker    (DBusConnection                   *connection,
+                                                      const char                       *well_known_name,
+                                                      const HippoDBusServiceTracker    *tracker,
+                                                      void                             *data);
+void hippo_dbus_helper_register_connection_tracker   (DBusBusType                       bus_type,
+                                                      const HippoDBusConnectionTracker *tracker,
+                                                      void                             *data);
+void hippo_dbus_helper_unregister_connection_tracker (DBusBusType                       bus_type,
+                                                      const HippoDBusConnectionTracker *tracker,
+                                                      void                             *data);
+void hippo_dbus_helper_register_name_owner           (DBusConnection                   *connection,
+                                                      const char                       *well_known_name,
+                                                      HippoDBusNameOwnershipStyle       ownership_style,
+                                                      const HippoDBusNameOwner         *owner,
+                                                      void                             *data);
+void hippo_dbus_helper_unregister_name_owner         (DBusConnection                   *connection,
+                                                      const char                       *well_known_name,
+                                                      const HippoDBusNameOwner         *owner,
+                                                      void                             *data);
+/* these two aren't implemented yet */
+void hippo_dbus_helper_register_name_owner_on_bus    (DBusBusType                       bus_type,
+                                                      const char                       *well_known_name,
+                                                      HippoDBusNameOwnershipStyle       ownership_style,
+                                                      const HippoDBusNameOwner         *owner,
+                                                      void                             *data);
+void hippo_dbus_helper_unregister_name_owner_on_bus  (DBusBusType                       bus_type,
+                                                      const char                       *well_known_name,
+                                                      const HippoDBusNameOwner         *owner,
+                                                      void                             *data);
+
 
-void hippo_dbus_helper_register_service_tracker   (DBusConnection                *connection,
-                                                   const char                    *well_known_name,
-                                                   const HippoDBusServiceTracker *tracker,
-                                                   const HippoDBusSignalTracker  *signal_handlers,
-                                                   void                          *data);
-void hippo_dbus_helper_unregister_service_tracker (DBusConnection                *connection,
-                                                   const char                    *well_known_name,
-                                                   const HippoDBusServiceTracker *tracker,
-                                                   void                          *data);
 
 HippoDBusProxy*   hippo_dbus_proxy_new                     (DBusConnection          *connection,
                                                             const char              *bus_name,
@@ -146,7 +207,11 @@
  * Gaim* and now are Purple*
  */
 void              hippo_dbus_proxy_set_method_prefix       (HippoDBusProxy          *proxy,
-                                                            char                    *method_prefix);
+                                                            const char              *method_prefix);
+/* Change the timeout from the default D-BUS value (25 seconds, as of D-BUS 1.3)
+ * -1 means use that default value */
+void              hippo_dbus_proxy_set_timeout             (HippoDBusProxy          *proxy,
+                                                            int                      timeout_milliseconds);
 void              hippo_dbus_proxy_unref                   (HippoDBusProxy          *proxy);
 
 DBusMessage* hippo_dbus_proxy_call_method_sync           (HippoDBusProxy        *proxy,
@@ -203,6 +268,8 @@
                                                                      int          first_arg_type,
                                                                      ...);
 
+dbus_bool_t hippo_dbus_proxy_VOID__VOID               (HippoDBusProxy  *proxy,
+                                                       const char      *method);
 dbus_bool_t hippo_dbus_proxy_INT32__VOID              (HippoDBusProxy  *proxy,
                                                        const char      *method,
                                                        dbus_int32_t    *out1_p);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]