local-export-daemon r7238 - trunk/src
- From: otaylor svn gnome org
- To: svn-commits-list gnome org
- Subject: local-export-daemon r7238 - trunk/src
- Date: Mon, 17 Mar 2008 19:18:56 +0000 (GMT)
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]