summaryrefslogtreecommitdiffstats
path: root/glib/dbus-gproxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'glib/dbus-gproxy.c')
-rw-r--r--glib/dbus-gproxy.c258
1 files changed, 241 insertions, 17 deletions
diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c
index ebcbb5d4..99900e4c 100644
--- a/glib/dbus-gproxy.c
+++ b/glib/dbus-gproxy.c
@@ -44,6 +44,9 @@ struct DBusGProxy
char *interface; /**< Interface messages go to or NULL */
};
+/**
+ * Class struct for DBusGProxy
+ */
struct DBusGProxyClass
{
GObjectClass parent_class;
@@ -52,6 +55,8 @@ struct DBusGProxyClass
static void dbus_gproxy_init (DBusGProxy *proxy);
static void dbus_gproxy_class_init (DBusGProxyClass *klass);
static void dbus_gproxy_finalize (GObject *object);
+static void dbus_gproxy_dispose (GObject *object);
+static void dbus_gproxy_destroy (DBusGProxy *proxy);
static void dbus_gproxy_emit_received (DBusGProxy *proxy,
DBusMessage *message);
@@ -174,6 +179,11 @@ dbus_gproxy_manager_unref (DBusGProxyManager *manager)
if (manager->proxy_lists)
{
+ /* can't have any proxies left since they hold
+ * a reference to the proxy manager.
+ */
+ g_assert (g_hash_table_size (manager->proxy_lists) == 0);
+
g_hash_table_destroy (manager->proxy_lists);
manager->proxy_lists = NULL;
}
@@ -447,11 +457,13 @@ dbus_gproxy_manager_unregister (DBusGProxyManager *manager,
LOCK_MANAGER (manager);
+#ifndef G_DISABLE_CHECKS
if (manager->proxy_lists == NULL)
{
g_warning ("Trying to disconnect a signal on a proxy but none are connected\n");
return;
}
+#endif
tri = tristring_from_proxy (proxy);
@@ -459,21 +471,70 @@ dbus_gproxy_manager_unregister (DBusGProxyManager *manager,
g_free (tri);
+#ifndef G_DISABLE_CHECKS
if (list == NULL)
{
g_warning ("Trying to disconnect a signal on a proxy but none are connected\n");
return;
}
+#endif
g_assert (g_slist_find (list->proxies, proxy) != NULL);
list->proxies = g_slist_remove (list->proxies, proxy);
g_assert (g_slist_find (list->proxies, proxy) == NULL);
+
+ if (g_hash_table_size (manager->proxy_lists) == 0)
+ {
+ g_hash_table_destroy (manager->proxy_lists);
+ manager->proxy_lists = NULL;
+ }
UNLOCK_MANAGER (manager);
}
+static void
+list_proxies_foreach (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ DBusGProxyList *list;
+ GSList **ret;
+ GSList *tmp;
+
+ list = value;
+ ret = user_data;
+
+ tmp = list->proxies;
+ while (tmp != NULL)
+ {
+ DBusGProxy *proxy = DBUS_GPROXY (tmp->data);
+
+ g_object_ref (proxy);
+ *ret = g_slist_prepend (*ret, proxy);
+
+ tmp = tmp->next;
+ }
+}
+
+static GSList*
+dbus_gproxy_manager_list_all (DBusGProxyManager *manager)
+{
+ GSList *ret;
+
+ ret = NULL;
+
+ if (manager->proxy_lists)
+ {
+ g_hash_table_foreach (manager->proxy_lists,
+ list_proxies_foreach,
+ &ret);
+ }
+
+ return ret;
+}
+
static DBusHandlerResult
dbus_gproxy_manager_filter (DBusConnection *connection,
DBusMessage *message,
@@ -481,18 +542,48 @@ dbus_gproxy_manager_filter (DBusConnection *connection,
{
DBusGProxyManager *manager;
- manager = user_data;
-
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ manager = user_data;
+
+ dbus_gproxy_manager_ref (manager);
+
+ LOCK_MANAGER (manager);
+
if (dbus_message_is_signal (message,
DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
"Disconnected"))
{
- /* FIXME g_object_run_dispose() all the proxies; should proxies have
- * a "destroy" signal?
+ /* Destroy all the proxies, quite possibly resulting in unreferencing
+ * the proxy manager and the connection as well.
*/
+ GSList *all;
+ GSList *tmp;
+
+ all = dbus_gproxy_manager_list_all (manager);
+
+ tmp = all;
+ while (tmp != NULL)
+ {
+ DBusGProxy *proxy;
+
+ proxy = DBUS_GPROXY (tmp->data);
+
+ UNLOCK_MANAGER (manager);
+ dbus_gproxy_destroy (proxy);
+ g_object_unref (G_OBJECT (proxy));
+ LOCK_MANAGER (manager);
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (all);
+
+#ifndef G_DISABLE_CHECKS
+ if (manager->proxy_lists != NULL)
+ g_warning ("Disconnection emitted \"destroy\" on all DBusGProxy, but somehow new proxies were created in response to one of those destroy signals. This will cause a memory leak.");
+#endif
}
else
{
@@ -507,14 +598,38 @@ dbus_gproxy_manager_filter (DBusConnection *connection,
list = NULL;
g_free (tri);
+
+ /* Emit the signal */
if (list != NULL)
{
- /* FIXME Emit the signal on each proxy in the list */
-
+ GSList *tmp;
+ GSList *copy;
+ copy = g_slist_copy (list->proxies);
+ g_slist_foreach (copy, (GFunc) g_object_ref, NULL);
+
+ tmp = copy;
+ while (tmp != NULL)
+ {
+ DBusGProxy *proxy;
+
+ proxy = DBUS_GPROXY (tmp->data);
+
+ UNLOCK_MANAGER (manager);
+ dbus_gproxy_emit_received (proxy, message);
+ g_object_unref (G_OBJECT (proxy));
+ LOCK_MANAGER (manager);
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (copy);
}
}
+
+ UNLOCK_MANAGER (manager);
+ dbus_gproxy_manager_unref (manager);
/* "Handling" signals doesn't make sense, they are for everyone
* who cares
@@ -530,6 +645,7 @@ dbus_gproxy_manager_filter (DBusConnection *connection,
enum
{
+ DESTROY,
RECEIVED,
LAST_SIGNAL
};
@@ -551,7 +667,17 @@ dbus_gproxy_class_init (DBusGProxyClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = dbus_gproxy_finalize;
-
+ object_class->dispose = dbus_gproxy_dispose;
+
+ signals[DESTROY] =
+ g_signal_new ("destroy",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
signals[RECEIVED] =
g_signal_new ("received",
G_OBJECT_CLASS_TYPE (object_class),
@@ -563,6 +689,19 @@ dbus_gproxy_class_init (DBusGProxyClass *klass)
DBUS_TYPE_MESSAGE);
}
+
+static void
+dbus_gproxy_dispose (GObject *object)
+{
+ DBusGProxy *proxy;
+
+ proxy = DBUS_GPROXY (object);
+
+ g_signal_emit (object, signals[DESTROY], 0);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
static void
dbus_gproxy_finalize (GObject *object)
{
@@ -583,6 +722,15 @@ dbus_gproxy_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
+static void
+dbus_gproxy_destroy (DBusGProxy *proxy)
+{
+ /* FIXME do we need the GTK_IN_DESTRUCTION style flag
+ * from GtkObject?
+ */
+ g_object_run_dispose (G_OBJECT (proxy));
+}
+
static char*
create_signal_detail (const char *interface,
const char *signal)
@@ -697,18 +845,22 @@ dbus_gproxy_new (DBusConnection *connection,
}
/**
- * Creates a new proxy for a remote interface. Method calls and signal
- * connections over this proxy will go to the service owner; the
- * service owner is expected to support the given interface name. THE
- * SERVICE OWNER MAY CHANGE OVER TIME, for example between two
- * different method calls. If you need a fixed owner, you need to
- * request the current owner and bind a proxy to that rather than to
- * the generic service name; see dbus_gproxy_new_for_service_owner().
+ * Creates a new proxy for a remote interface exported by a service on
+ * a message bus. Method calls and signal connections over this proxy
+ * will go to the service owner; the service owner is expected to
+ * support the given interface name. THE SERVICE OWNER MAY CHANGE OVER
+ * TIME, for example between two different method calls. If you need a
+ * fixed owner, you need to request the current owner and bind a proxy
+ * to that rather than to the generic service name; see
+ * dbus_gproxy_new_for_service_owner().
*
* A service-associated proxy only makes sense with a message bus,
* not for app-to-app direct dbus connections.
*
- * @param connection the connection to the remote bus or app
+ * This proxy will only emit the "destroy" signal if the #DBusConnection
+ * is disconnected or the proxy is has no remaining references.
+ *
+ * @param connection the connection to the remote bus
* @param service_name name of the service on the message bus
* @param path_name name of the object inside the service to call methods on
* @param interface_name name of the interface to call methods on
@@ -734,6 +886,75 @@ dbus_gproxy_new_for_service (DBusConnection *connection,
}
/**
+ * Similar to dbus_gproxy_new_for_service(), but makes a round-trip
+ * request to the message bus to get the current service owner, then
+ * binds the proxy specifically to the current owner. As a result, the
+ * service owner will not change over time, and the proxy will emit
+ * the "destroy" signal when the owner disappears from the message
+ * bus.
+ *
+ * An example of the difference between dbus_gproxy_new_for_service()
+ * and dbus_gproxy_new_for_service_owner(): if you pass the service name
+ * "org.freedesktop.Database" dbus_gproxy_new_for_service() remains bound
+ * to that name as it changes owner. dbus_gproxy_new_for_service_owner()
+ * will fail if the service has no owner. If the service has an owner,
+ * dbus_gproxy_new_for_service_owner() will bind to the unique name
+ * of that owner rather than the generic service name.
+ *
+ * @param connection the connection to the remote bus
+ * @param service_name name of the service on the message bus
+ * @param path_name name of the object inside the service to call methods on
+ * @param interface_name name of the interface to call methods on
+ * @param error return location for an error
+ * @returns new proxy object, or #NULL on error
+ */
+DBusGProxy*
+dbus_gproxy_new_for_service_owner (DBusConnection *connection,
+ const char *service_name,
+ const char *path_name,
+ const char *interface_name,
+ GError **error)
+{
+ g_return_val_if_fail (connection != NULL, NULL);
+ g_return_val_if_fail (service_name != NULL, NULL);
+ g_return_val_if_fail (path_name != NULL, NULL);
+ g_return_val_if_fail (interface_name != NULL, NULL);
+
+
+}
+
+/**
+ * Creates a proxy for an object in peer application (one
+ * we're directly connected to). That is, this function is
+ * intended for use when there's no message bus involved,
+ * we're doing a simple 1-to-1 communication between two
+ * applications.
+ *
+ *
+ * @param connection the connection to the peer
+ * @param path_name name of the object inside the peer to call methods on
+ * @param interface_name name of the interface to call methods on
+ * @returns new proxy object
+ *
+ */
+DBusGProxy*
+dbus_gproxy_new_for_peer (DBusConnection *connection,
+ const char *path_name,
+ const char *interface_name)
+{
+ DBusGProxy *proxy;
+
+ g_return_val_if_fail (connection != NULL, NULL);
+ g_return_val_if_fail (path_name != NULL, NULL);
+ g_return_val_if_fail (interface_name != NULL, NULL);
+
+ proxy = dbus_gproxy_new (connection, NULL,
+ path_name, interface_name);
+
+ return proxy;
+}
+
+/**
* Invokes a method on a remote interface. This function does not
* block; instead it returns an opaque #DBusPendingCall object that
* tracks the pending call. The method call will not be sent over the
@@ -952,7 +1173,7 @@ dbus_gproxy_connect_signal (DBusGProxy *proxy,
const char *signal_name,
DBusGProxySignalHandler handler,
void *data,
- GFreeFunc free_data_func)
+ GClosureNotify free_data_func)
{
GClosure *closure;
char *detail;
@@ -989,12 +1210,14 @@ dbus_gproxy_disconnect_signal (DBusGProxy *proxy,
q = g_quark_try_string (detail);
g_free (detail);
+#ifndef G_DISABLE_CHECKS
if (q == 0)
{
g_warning ("%s: No signal handlers for %s found on this DBusGProxy",
G_GNUC_FUNCTION, signal_name);
return;
}
+#endif
g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
G_SIGNAL_MATCH_DETAIL |
@@ -1018,7 +1241,8 @@ dbus_gproxy_disconnect_signal (DBusGProxy *proxy,
dbus_bool_t
_dbus_gproxy_test (void)
{
-
+
+
return TRUE;
}