Commit 31881de7 authored by Havoc Pennington's avatar Havoc Pennington

2003-09-23 Havoc Pennington <hp@pobox.com>

	* glib/dbus-gproxy.c (dbus_gproxy_manager_filter): implement
parent 52f275a7
2003-09-23 Havoc Pennington <hp@pobox.com>
* glib/dbus-gproxy.c (dbus_gproxy_manager_filter): implement
2003-09-23 Havoc Pennington <hp@redhat.com>
* glib/dbus-gproxy.c (dbus_gproxy_connect_signal): implement
......
......@@ -123,7 +123,7 @@ void dbus_gproxy_connect_signal (DBusGProxy *pr
const char *signal_name,
DBusGProxySignalHandler handler,
void *data,
GFreeFunc free_data_func);
GClosureNotify free_data_func);
void dbus_gproxy_disconnect_signal (DBusGProxy *proxy,
const char *signal_name,
DBusGProxySignalHandler handler,
......
......@@ -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
......@@ -733,6 +885,75 @@ dbus_gproxy_new_for_service (DBusConnection *connection,
return proxy;
}
/**
* 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
......@@ -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;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment