summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2012-07-30 15:41:00 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2012-07-30 15:41:00 +0100
commitddd21ba082fd5a90e93052463d00927853a8ecea (patch)
treeff8a133eefd41fc1ed5792029091c6c0e294701d
parentee34e40100294702f9bcde300056f659de4e3ed8 (diff)
parent694be3e53cb8523f86afb73f3ecc0f089610375a (diff)
downloadtelepathy-mission-control-ddd21ba082fd5a90e93052463d00927853a8ecea.tar.gz
Merge branch 'one-channel-should-be-enough-for-anyone'
Reviewed-by: Jonny Lamb <jonny.lamb@collabora.co.uk> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=52305
-rw-r--r--src/client-registry.c33
-rw-r--r--src/client-registry.h2
-rw-r--r--src/mcd-connection.c87
-rw-r--r--src/mcd-connection.h9
-rw-r--r--src/mcd-dispatch-operation-priv.h11
-rw-r--r--src/mcd-dispatch-operation.c401
-rw-r--r--src/mcd-dispatcher-priv.h6
-rw-r--r--src/mcd-dispatcher.c167
-rw-r--r--src/plugin-dispatch-operation.c22
-rw-r--r--tests/twisted/dispatcher/exploding-bundles.py156
10 files changed, 418 insertions, 476 deletions
diff --git a/src/client-registry.c b/src/client-registry.c
index 3e01a66d..acc65e78 100644
--- a/src/client-registry.c
+++ b/src/client-registry.c
@@ -604,11 +604,10 @@ GList *
_mcd_client_registry_list_possible_handlers (McdClientRegistry *self,
const gchar *preferred_handler,
GHashTable *request_props,
- const GList *channels,
+ TpChannel *channel,
const gchar *must_have_unique_name)
{
GList *handlers = NULL;
- const GList *iter;
GList *handlers_iter;
GHashTableIter client_iter;
gpointer client_p;
@@ -618,7 +617,8 @@ _mcd_client_registry_list_possible_handlers (McdClientRegistry *self,
while (g_hash_table_iter_next (&client_iter, NULL, &client_p))
{
McdClientProxy *client = MCD_CLIENT_PROXY (client_p);
- gsize total_quality = 0;
+ GHashTable *properties;
+ gsize quality;
if (must_have_unique_name != NULL &&
tp_strdiff (must_have_unique_name,
@@ -636,48 +636,33 @@ _mcd_client_registry_list_possible_handlers (McdClientRegistry *self,
continue;
}
- if (channels == NULL)
+ if (channel == NULL)
{
- /* We don't know any channels' properties (the next loop will not
+ /* We don't know the channel's properties (the next part will not
* execute), so we must work out the quality of match from the
* channel request. We can assume that the request will return one
* channel, with the requested properties, plus Requested == TRUE.
*/
g_assert (request_props != NULL);
- total_quality = _mcd_client_match_filters (request_props,
+ quality = _mcd_client_match_filters (request_props,
_mcd_client_proxy_get_handler_filters (client), TRUE);
}
-
- for (iter = channels; iter != NULL; iter = iter->next)
+ else
{
- TpChannel *channel = iter->data;
- GHashTable *properties;
- guint quality;
-
g_assert (TP_IS_CHANNEL (channel));
properties = tp_channel_borrow_immutable_properties (channel);
quality = _mcd_client_match_filters (properties,
_mcd_client_proxy_get_handler_filters (client), FALSE);
-
- if (quality == 0)
- {
- total_quality = 0;
- break;
- }
- else
- {
- total_quality += quality;
- }
}
- if (total_quality > 0)
+ if (quality > 0)
{
PossibleHandler *ph = g_slice_new0 (PossibleHandler);
ph->client = client;
ph->bypass = _mcd_client_proxy_get_bypass_approval (client);
- ph->quality = total_quality;
+ ph->quality = quality;
handlers = g_list_prepend (handlers, ph);
}
diff --git a/src/client-registry.h b/src/client-registry.h
index 88f19569..ec2e167c 100644
--- a/src/client-registry.h
+++ b/src/client-registry.h
@@ -82,7 +82,7 @@ G_GNUC_INTERNAL void _mcd_client_registry_init_hash_iter (
G_GNUC_INTERNAL GList *_mcd_client_registry_list_possible_handlers (
McdClientRegistry *self, const gchar *preferred_handler,
- GHashTable *request_props, const GList *channels,
+ GHashTable *request_props, TpChannel *channel,
const gchar *must_have_unique_name);
G_END_DECLS
diff --git a/src/mcd-connection.c b/src/mcd-connection.c
index 166f9de4..f2518491 100644
--- a/src/mcd-connection.c
+++ b/src/mcd-connection.c
@@ -573,9 +573,8 @@ on_new_channel (TpConnection *proxy, const gchar *chan_obj_path,
* AddDispatchOperation or HandleChannels.
*
* We assume that channels without suppress_handler are incoming. */
- _mcd_dispatcher_take_channels (priv->dispatcher,
- g_list_prepend (NULL, channel),
- suppress_handler, suppress_handler);
+ _mcd_dispatcher_add_channel (priv->dispatcher, channel,
+ suppress_handler, suppress_handler);
}
}
@@ -1171,6 +1170,10 @@ connect_cb (TpConnection *tp_conn, const GError *error,
}
}
+static gboolean
+_mcd_connection_request_channel (McdConnection *connection,
+ McdChannel *channel);
+
static void
request_unrequested_channels (McdConnection *connection)
{
@@ -1216,16 +1219,16 @@ mcd_connection_find_channel_by_path (McdConnection *connection,
return NULL;
}
+static gboolean mcd_connection_need_dispatch (McdConnection *connection,
+ const gchar *object_path,
+ GHashTable *props);
+
static void
on_new_channels (TpConnection *proxy, const GPtrArray *channels,
gpointer user_data, GObject *weak_object)
{
McdConnection *connection = MCD_CONNECTION (weak_object);
McdConnectionPrivate *priv = user_data;
- McdChannel *channel;
- GList *channel_list = NULL;
- gboolean requested = FALSE;
- gboolean only_observe = FALSE;
guint i;
if (DEBUGGING)
@@ -1256,9 +1259,6 @@ on_new_channels (TpConnection *proxy, const GPtrArray *channels,
* FALSE: they'll also be in Channels in the GetAll(Requests) result */
if (!priv->dispatched_initial_channels) return;
- only_observe = ! MCD_CONNECTION_GET_CLASS (connection)->need_dispatch (
- connection, channels);
-
sp_timestamp ("NewChannels received");
for (i = 0; i < channels->len; i++)
{
@@ -1266,11 +1266,17 @@ on_new_channels (TpConnection *proxy, const GPtrArray *channels,
const gchar *object_path;
GHashTable *props;
GValue *value;
+ gboolean requested = FALSE;
+ gboolean only_observe = FALSE;
+ McdChannel *channel;
va = g_ptr_array_index (channels, i);
object_path = g_value_get_boxed (va->values);
props = g_value_get_boxed (va->values + 1);
+ only_observe = !mcd_connection_need_dispatch (connection, object_path,
+ props);
+
/* Don't do anything for requested channels */
value = g_hash_table_lookup (props, TP_IFACE_CHANNEL ".Requested");
if (value && g_value_get_boolean (value))
@@ -1289,17 +1295,15 @@ on_new_channels (TpConnection *proxy, const GPtrArray *channels,
MCD_MISSION (channel));
}
- channel_list = g_list_prepend (channel_list, channel);
- }
+ if (!requested)
+ {
+ /* we always dispatch unrequested (incoming) channels */
+ only_observe = FALSE;
+ }
- if (!requested)
- {
- /* we always dispatch unrequested (incoming) channels */
- only_observe = FALSE;
+ _mcd_dispatcher_add_channel (priv->dispatcher, channel, requested,
+ only_observe);
}
-
- _mcd_dispatcher_take_channels (priv->dispatcher, channel_list, requested,
- only_observe);
}
static void
@@ -2125,18 +2129,19 @@ _mcd_connection_get_property (GObject * obj, guint prop_id,
/*
* mcd_connection_need_dispatch:
* @connection: the #McdConnection.
- * @channels: array of #McdChannel elements.
+ * @object_path: the object path of the new channel (only for debugging)
+ * @props: the properties of the new channel
*
* This functions must be called in response to a NewChannels signals, and is
* responsible for deciding whether MC must handle the channels or not.
*/
static gboolean
mcd_connection_need_dispatch (McdConnection *connection,
- const GPtrArray *channels)
+ const gchar *object_path,
+ GHashTable *props)
{
McdAccount *account = mcd_connection_get_account (connection);
- gboolean any_requested = FALSE, requested_by_us = FALSE;
- guint i;
+ gboolean requested = FALSE, requested_by_us = FALSE;
if (_mcd_account_needs_dispatch (account))
{
@@ -2149,31 +2154,18 @@ mcd_connection_need_dispatch (McdConnection *connection,
* have no McdChannel object associated: these are the channels directly
* requested to the CM by some other application, and we must ignore them
*/
- for (i = 0; i < channels->len; i++)
- {
- GValueArray *va;
- const gchar *object_path;
- GHashTable *props;
- gboolean requested;
- va = g_ptr_array_index (channels, i);
- object_path = g_value_get_boxed (va->values);
- props = g_value_get_boxed (va->values + 1);
-
- requested = tp_asv_get_boolean (props, TP_IFACE_CHANNEL ".Requested",
- NULL);
- if (requested)
- {
- any_requested = TRUE;
-
- if (mcd_connection_find_channel_by_path (connection, object_path))
- requested_by_us = TRUE;
- }
+ requested = tp_asv_get_boolean (props, TP_IFACE_CHANNEL ".Requested",
+ NULL);
+ if (requested)
+ {
+ if (mcd_connection_find_channel_by_path (connection, object_path))
+ requested_by_us = TRUE;
}
/* handle only bundles which were not requested or that were requested
* through MC */
- return !any_requested || requested_by_us;
+ return !requested || requested_by_us;
}
gboolean
@@ -2205,7 +2197,8 @@ _mcd_connection_target_handle_is_urgent (McdConnection *self, guint handle)
}
static gboolean
-_mcd_connection_request_channel (McdConnection *connection, McdChannel *channel)
+_mcd_connection_request_channel (McdConnection *connection,
+ McdChannel *channel)
{
McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
gboolean ret;
@@ -2253,9 +2246,6 @@ mcd_connection_class_init (McdConnectionClass * klass)
object_class->set_property = _mcd_connection_set_property;
object_class->get_property = _mcd_connection_get_property;
- klass->need_dispatch = mcd_connection_need_dispatch;
- klass->request_channel = _mcd_connection_request_channel;
-
_mcd_ext_register_dbus_glib_marshallers ();
tp_connection_init_known_interfaces ();
@@ -2479,8 +2469,7 @@ mcd_connection_request_channel (McdConnection *connection,
mcd_operation_take_mission (MCD_OPERATION (connection),
MCD_MISSION (channel));
- return MCD_CONNECTION_GET_CLASS (connection)->request_channel (connection,
- channel);
+ return _mcd_connection_request_channel (connection, channel);
}
void
diff --git a/src/mcd-connection.h b/src/mcd-connection.h
index 6ea414bc..8f450b92 100644
--- a/src/mcd-connection.h
+++ b/src/mcd-connection.h
@@ -55,15 +55,6 @@ struct _McdConnection
struct _McdConnectionClass
{
McdOperationClass parent_class;
- gboolean (*need_dispatch) (McdConnection *connection,
- const GPtrArray *channels);
- void (*_mc_reserved2) (void);
- gboolean (*request_channel) (McdConnection *connection,
- McdChannel *channel);
- void (*_mc_reserved3) (void);
- void (*_mc_reserved4) (void);
- void (*_mc_reserved5) (void);
- void (*_mc_reserved6) (void);
};
#include "mcd-dispatcher.h"
diff --git a/src/mcd-dispatch-operation-priv.h b/src/mcd-dispatch-operation-priv.h
index 933c12a4..ce168fc3 100644
--- a/src/mcd-dispatch-operation-priv.h
+++ b/src/mcd-dispatch-operation-priv.h
@@ -69,15 +69,18 @@ G_GNUC_INTERNAL void _mcd_dispatch_operation_approve
#define MCD_DISPATCH_OPERATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MCD_TYPE_DISPATCH_OPERATION, McdDispatchOperationClass))
G_GNUC_INTERNAL McdDispatchOperation *_mcd_dispatch_operation_new (
- McdClientRegistry *client_registry, McdHandlerMap *handler_map,
- gboolean needs_approval, gboolean observe_only, GList *channels,
+ McdClientRegistry *client_registry,
+ McdHandlerMap *handler_map,
+ gboolean needs_approval,
+ gboolean observe_only,
+ McdChannel *channel,
const gchar * const *possible_handlers);
G_GNUC_INTERNAL gboolean _mcd_dispatch_operation_has_channel (
McdDispatchOperation *self, McdChannel *channel);
-G_GNUC_INTERNAL const GList *_mcd_dispatch_operation_peek_channels (
+G_GNUC_INTERNAL McdChannel *_mcd_dispatch_operation_peek_channel (
McdDispatchOperation *self);
-G_GNUC_INTERNAL GList *_mcd_dispatch_operation_dup_channels (
+G_GNUC_INTERNAL McdChannel *_mcd_dispatch_operation_dup_channel (
McdDispatchOperation *self);
G_GNUC_INTERNAL gboolean _mcd_dispatch_operation_is_finished (
diff --git a/src/mcd-dispatch-operation.c b/src/mcd-dispatch-operation.c
index 6a4a2877..ac036f0c 100644
--- a/src/mcd-dispatch-operation.c
+++ b/src/mcd-dispatch-operation.c
@@ -196,14 +196,14 @@ struct _McdDispatchOperationPrivate
McdAccount *account;
McdConnection *connection;
- /* Owned McdChannels we're dispatching */
- GList *channels;
- /* Owned McdChannels for which we can't emit ChannelLost yet, in
- * reverse chronological order */
- GList *lost_channels;
-
- /* If TRUE, either the channels being dispatched were requested, or they
- * were pre-approved by being returned as a response to another request,
+ /* Owned McdChannel we're dispatching */
+ McdChannel *channel;
+ /* If non-NULL, we have lost the McdChannel but can't emit
+ * ChannelLost yet */
+ McdChannel *lost_channel;
+
+ /* If TRUE, either the channel being dispatched was requested, or it
+ * was pre-approved by being returned as a response to another request,
* or a client approved processing with arbitrary handlers */
gboolean approved;
@@ -246,7 +246,7 @@ struct _McdDispatchOperationPrivate
/* If TRUE, we're dispatching a channel request and it was cancelled */
gboolean cancelled;
- /* if TRUE, these channels were requested "behind our back", so stop
+ /* if TRUE, this channel was requested "behind our back", so stop
* after observers */
gboolean observe_only;
@@ -345,7 +345,7 @@ _mcd_dispatch_operation_dec_ado_pending (McdDispatchOperation *self)
if (self->priv->ado_pending == 0 && !self->priv->accepted_by_an_approver)
{
- DEBUG ("No approver accepted the channels; considering them to be "
+ DEBUG ("No approver accepted the channel; considering it to be "
"approved");
g_queue_push_tail (self->priv->approvals,
approval_new (APPROVAL_TYPE_NO_APPROVERS));
@@ -429,7 +429,7 @@ _mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
if (!self->priv->tried_handlers_before_approval &&
!_mcd_dispatch_operation_handlers_can_bypass_approval (self)
&& self->priv->delay_approver_observers_pending == 0
- && self->priv->channels != NULL &&
+ && self->priv->channel != NULL &&
! _mcd_plugin_dispatch_operation_will_terminate (
self->priv->plugin_api))
{
@@ -463,7 +463,7 @@ _mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
return;
}
- /* if a handler has claimed or accepted the channels, we have nothing to
+ /* if a handler has claimed or accepted the channel, we have nothing to
* do */
if (self->priv->result != NULL)
{
@@ -481,24 +481,21 @@ _mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
if (_mcd_dispatch_operation_is_internal (self))
{
- guint i = 0;
- GList *list = self->priv->channels;
-
DEBUG ("Invoking internal handlers for requests");
- for (; list != NULL; list = g_list_next (list), i++)
+ if (self->priv->channel != NULL)
{
- McdChannel *channel = list->data;
+ McdChannel *channel = self->priv->channel;
McdRequest *request = _mcd_channel_get_request (channel);
- if (request == NULL)
- continue;
-
- DEBUG ("Internal handler for request channel #%u", i);
- _mcd_handler_map_set_channel_handled_internally (
- self->priv->handler_map,
- mcd_channel_get_tp_channel (channel),
- _mcd_dispatch_operation_get_account_path (self));
- _mcd_request_handle_internally (request, channel, TRUE);
+ if (request != NULL)
+ {
+ DEBUG ("Internal handler for request channel");
+ _mcd_handler_map_set_channel_handled_internally (
+ self->priv->handler_map,
+ mcd_channel_get_tp_channel (channel),
+ _mcd_dispatch_operation_get_account_path (self));
+ _mcd_request_handle_internally (request, channel, TRUE);
+ }
}
/* The rest of this function deals with externally handled requests: *
@@ -524,7 +521,6 @@ _mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
/* if we've been claimed, respond, then do not call HandleChannels */
if (approval != NULL && approval->type == APPROVAL_TYPE_CLAIM)
{
- const GList *list;
/* this needs to be copied because we don't use it til after we've
* freed approval->context */
gchar *caller = g_strdup (dbus_g_method_get_sender (
@@ -534,9 +530,9 @@ _mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
* failure */
g_queue_pop_head (self->priv->approvals);
- for (list = self->priv->channels; list != NULL; list = list->next)
+ if (self->priv->channel != NULL)
{
- McdChannel *channel = MCD_CHANNEL (list->data);
+ McdChannel *channel = self->priv->channel;
mcd_dispatch_operation_set_channel_handled_by (self, channel,
caller, NULL);
@@ -615,7 +611,7 @@ _mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
enum
{
PROP_0,
- PROP_CHANNELS,
+ PROP_CHANNEL,
PROP_CLIENT_REGISTRY,
PROP_HANDLER_MAP,
PROP_POSSIBLE_HANDLERS,
@@ -724,8 +720,16 @@ get_channels (TpSvcDBusProperties *iface, const gchar *name, GValue *value)
DEBUG ("called for %s", self->priv->unique_name);
g_value_init (value, TP_ARRAY_TYPE_CHANNEL_DETAILS_LIST);
+
+ if (self->priv->channel == NULL)
+ {
+ g_value_take_boxed (value, g_ptr_array_sized_new (0));
+ return;
+ }
+
g_value_take_boxed (value,
- _mcd_tp_channel_details_build_from_list (self->priv->channels));
+ _mcd_tp_channel_details_build_from_tp_chan (
+ mcd_channel_get_tp_channel (self->priv->channel)));
}
static void
@@ -868,7 +872,8 @@ _mcd_dispatch_operation_finish (McdDispatchOperation *operation,
else
{
/* Handling finished for some other reason: perhaps the
- * channel was claimed, or perhaps we ran out of channels.
+ * channel was claimed, or perhaps it closed or we were
+ * told to forget about it.
*/
DEBUG ("HandleWith -> error: %s %d: %s",
g_quark_to_string (priv->result->domain),
@@ -1073,7 +1078,7 @@ mcd_dispatch_operation_constructor (GType type, guint n_params,
g_return_val_if_fail (operation != NULL, NULL);
priv = operation->priv;
- if (!priv->client_registry || !priv->handler_map)
+ if (!priv->client_registry || !priv->handler_map || !priv->channel)
goto error;
if (priv->needs_approval && priv->observe_only)
@@ -1087,14 +1092,12 @@ mcd_dispatch_operation_constructor (GType type, guint n_params,
DEBUG ("%s/%p: needs_approval=%c", priv->unique_name, object,
priv->needs_approval ? 'T' : 'F');
- if (DEBUGGING)
+ if (priv->channel != NULL)
{
- GList *list;
-
- for (list = priv->channels; list != NULL; list = list->next)
- {
- DEBUG ("Channel: %s", mcd_channel_get_object_path (list->data));
- }
+ DEBUG ("Channel: %s",
+ mcd_channel_get_object_path (priv->channel));
+ g_assert (mcd_channel_get_account (priv->channel) ==
+ priv->account);
}
/* If approval is not needed, we don't appear on D-Bus (and approvers
@@ -1149,7 +1152,7 @@ mcd_dispatch_operation_channel_aborted_cb (McdChannel *channel,
_mcd_dispatch_operation_lose_channel (self, channel);
- if (_mcd_dispatch_operation_peek_channels (self) == NULL)
+ if (self->priv->channel == NULL)
{
DEBUG ("Nothing left in this context");
}
@@ -1163,7 +1166,6 @@ mcd_dispatch_operation_set_property (GObject *obj, guint prop_id,
{
McdDispatchOperation *operation = MCD_DISPATCH_OPERATION (obj);
McdDispatchOperationPrivate *priv = operation->priv;
- GList *list;
switch (prop_id)
{
@@ -1177,21 +1179,19 @@ mcd_dispatch_operation_set_property (GObject *obj, guint prop_id,
priv->handler_map = MCD_HANDLER_MAP (g_value_dup_object (val));
break;
- case PROP_CHANNELS:
+ case PROP_CHANNEL:
/* because this is construct-only, we can assert that: */
- g_assert (priv->channels == NULL);
+ g_assert (priv->channel == NULL);
g_assert (g_queue_is_empty (priv->approvals));
- priv->channels = g_list_copy (g_value_get_pointer (val));
+ priv->channel = g_value_dup_object (val);
- if (G_LIKELY (priv->channels))
+ if (G_LIKELY (priv->channel))
{
- /* get the connection and account from the first channel */
- McdChannel *channel = MCD_CHANNEL (priv->channels->data);
const gchar *preferred_handler;
priv->connection = (McdConnection *)
- mcd_mission_get_parent (MCD_MISSION (channel));
+ mcd_mission_get_parent (MCD_MISSION (priv->channel));
if (G_LIKELY (priv->connection))
{
@@ -1203,10 +1203,10 @@ mcd_dispatch_operation_set_property (GObject *obj, guint prop_id,
g_warning ("Channel has no Connection?!");
}
- /* if the first channel is actually a channel request, get the
+ /* if the channel is actually a channel request, get the
* preferred handler from it */
preferred_handler =
- _mcd_channel_get_request_preferred_handler (channel);
+ _mcd_channel_get_request_preferred_handler (priv->channel);
if (preferred_handler != NULL &&
g_str_has_prefix (preferred_handler, TP_CLIENT_BUS_NAME_BASE) &&
@@ -1220,7 +1220,7 @@ mcd_dispatch_operation_set_property (GObject *obj, guint prop_id,
approval_new_requested (preferred_handler));
}
- priv->account = mcd_channel_get_account (channel);
+ priv->account = mcd_channel_get_account (priv->channel);
if (G_LIKELY (priv->account != NULL))
{
@@ -1233,16 +1233,10 @@ mcd_dispatch_operation_set_property (GObject *obj, guint prop_id,
"Account?!");
}
- /* reference the channels and connect to their signals */
- for (list = priv->channels; list != NULL; list = list->next)
- {
- g_object_ref (list->data);
-
- g_signal_connect_after (list->data, "abort",
- G_CALLBACK (mcd_dispatch_operation_channel_aborted_cb),
- operation);
-
- }
+ /* connect to its signals */
+ g_signal_connect_after (priv->channel, "abort",
+ G_CALLBACK (mcd_dispatch_operation_channel_aborted_cb),
+ operation);
}
break;
@@ -1317,32 +1311,18 @@ static void
mcd_dispatch_operation_dispose (GObject *object)
{
McdDispatchOperationPrivate *priv = MCD_DISPATCH_OPERATION_PRIV (object);
- GList *list;
tp_clear_object (&priv->plugin_api);
tp_clear_object (&priv->successful_handler);
- if (priv->channels != NULL)
- {
- for (list = priv->channels; list != NULL; list = list->next)
- {
- g_signal_handlers_disconnect_by_func (list->data,
- mcd_dispatch_operation_channel_aborted_cb, object);
- g_object_unref (list->data);
- }
-
- tp_clear_pointer (&priv->channels, g_list_free);
- }
-
- if (priv->lost_channels != NULL)
+ if (priv->channel != NULL)
{
- for (list = priv->lost_channels; list != NULL; list = list->next)
- g_object_unref (list->data);
-
- tp_clear_pointer (&priv->lost_channels, g_list_free);
+ g_signal_handlers_disconnect_by_func (priv->channel,
+ mcd_dispatch_operation_channel_aborted_cb, object);
}
- tp_clear_object (&priv->connection);
+ tp_clear_object (&priv->channel);
+ tp_clear_object (&priv->lost_channel);
tp_clear_object (&priv->account);
tp_clear_object (&priv->handler_map);
tp_clear_object (&priv->client_registry);
@@ -1383,9 +1363,11 @@ _mcd_dispatch_operation_class_init (McdDispatchOperationClass * klass)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (object_class, PROP_CHANNELS,
- g_param_spec_pointer ("channels", "channels", "channels",
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_CHANNEL,
+ g_param_spec_object ("channel", "Channel", "the channel to dispatch",
+ MCD_TYPE_CHANNEL,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_POSSIBLE_HANDLERS,
g_param_spec_boxed ("possible-handlers", "Possible handlers",
@@ -1429,31 +1411,31 @@ _mcd_dispatch_operation_init (McdDispatchOperation *operation)
* _mcd_dispatch_operation_new:
* @client_registry: the client registry.
* @handler_map: the handler map
- * @channels: a #GList of #McdChannel elements to dispatch.
- * @possible_handlers: the bus names of possible handlers for these channels.
+ * @channel: the channel to dispatch
+ * @possible_handlers: the bus names of possible handlers for this channel
*
- * Creates a #McdDispatchOperation. The #GList @channels will be no longer
- * valid after this function has been called.
+ * Creates a #McdDispatchOperation.
*/
McdDispatchOperation *
_mcd_dispatch_operation_new (McdClientRegistry *client_registry,
McdHandlerMap *handler_map,
gboolean needs_approval,
gboolean observe_only,
- GList *channels,
+ McdChannel *channel,
const gchar * const *possible_handlers)
{
gpointer *obj;
- /* If we're only observing, then the channels were requested "behind MC's
+ /* If we're only observing, then the channel was requested "behind MC's
* back", so they can't need approval (i.e. observe_only implies
* !needs_approval) */
g_return_val_if_fail (!observe_only || !needs_approval, NULL);
+ g_return_val_if_fail (MCD_IS_CHANNEL (channel), NULL);
obj = g_object_new (MCD_TYPE_DISPATCH_OPERATION,
"client-registry", client_registry,
"handler-map", handler_map,
- "channels", channels,
+ "channel", channel,
"possible-handlers", possible_handlers,
"needs-approval", needs_approval,
"observe-only", observe_only,
@@ -1620,16 +1602,18 @@ static void
_mcd_dispatch_operation_lose_channel (McdDispatchOperation *self,
McdChannel *channel)
{
- GList *li = g_list_find (self->priv->channels, channel);
const gchar *object_path;
const GError *error = NULL;
- if (li == NULL)
+ if (G_UNLIKELY (channel != self->priv->channel))
{
+ g_warning ("%s: apparently lost %p but my channel is %p",
+ G_STRFUNC, channel, self->priv->channel);
return;
}
- self->priv->channels = g_list_delete_link (self->priv->channels, li);
+ /* steal the reference */
+ self->priv->channel = NULL;
object_path = mcd_channel_get_object_path (channel);
error = mcd_channel_get_error (channel);
@@ -1650,9 +1634,8 @@ _mcd_dispatch_operation_lose_channel (McdDispatchOperation *self,
"%" G_GSIZE_FORMAT " approvers",
self->priv->unique_name, self, object_path,
self->priv->observers_pending, self->priv->ado_pending);
- self->priv->lost_channels =
- g_list_prepend (self->priv->lost_channels,
- g_object_ref (channel));
+ g_assert (self->priv->lost_channel == NULL);
+ self->priv->lost_channel = g_object_ref (channel);
}
else
{
@@ -1667,15 +1650,12 @@ _mcd_dispatch_operation_lose_channel (McdDispatchOperation *self,
g_free (error_name);
}
- /* We previously had a ref in the linked list - drop it */
+ /* We previously stole this ref from self->priv->channel - drop it */
g_object_unref (channel);
- if (self->priv->channels == NULL)
- {
- /* no channels left, so the CDO finishes (if it hasn't already) */
- _mcd_dispatch_operation_finish (self, error->domain, error->code,
- "%s", error->message);
- }
+ /* no channels left, so the CDO finishes (if it hasn't already) */
+ _mcd_dispatch_operation_finish (self, error->domain, error->code,
+ "%s", error->message);
}
static void
@@ -1683,28 +1663,26 @@ _mcd_dispatch_operation_check_finished (McdDispatchOperation *self)
{
if (mcd_dispatch_operation_may_signal_finished (self))
{
- GList *lost_channels;
+ McdChannel *lost_channel = self->priv->lost_channel;
- /* get the lost channels into chronological order, and steal them from
- * the object*/
- lost_channels = g_list_reverse (self->priv->lost_channels);
- self->priv->lost_channels = NULL;
+ /* steal it */
+ self->priv->lost_channel = NULL;
- while (lost_channels != NULL)
+ if (lost_channel != NULL)
{
- McdChannel *channel = lost_channels->data;
- const gchar *object_path = mcd_channel_get_object_path (channel);
+ const gchar *object_path = mcd_channel_get_object_path (
+ lost_channel);
if (object_path == NULL)
{
/* This shouldn't happen, but McdChannel is twisty enough
* that I can't be sure */
g_critical ("McdChannel has already lost its TpChannel: %p",
- channel);
+ lost_channel);
}
else
{
- const GError *error = mcd_channel_get_error (channel);
+ const GError *error = mcd_channel_get_error (lost_channel);
gchar *error_name = _mcd_build_error_string (error);
DEBUG ("%s/%p losing channel %s: %s: %s",
@@ -1715,8 +1693,7 @@ _mcd_dispatch_operation_check_finished (McdDispatchOperation *self)
g_free (error_name);
}
- g_object_unref (channel);
- lost_channels = g_list_delete_link (lost_channels, lost_channels);
+ g_object_unref (lost_channel);
}
if (self->priv->result != NULL)
@@ -1884,25 +1861,28 @@ _mcd_dispatch_operation_has_channel (McdDispatchOperation *self,
McdChannel *channel)
{
g_return_val_if_fail (MCD_IS_DISPATCH_OPERATION (self), FALSE);
- return (g_list_find (self->priv->channels, channel) != NULL);
+
+ return (self->priv->channel != NULL &&
+ self->priv->channel == channel);
}
-const GList *
-_mcd_dispatch_operation_peek_channels (McdDispatchOperation *self)
+McdChannel *
+_mcd_dispatch_operation_peek_channel (McdDispatchOperation *self)
{
g_return_val_if_fail (MCD_IS_DISPATCH_OPERATION (self), NULL);
- return self->priv->channels;
+
+ return self->priv->channel;
}
-GList *
-_mcd_dispatch_operation_dup_channels (McdDispatchOperation *self)
+McdChannel *
+_mcd_dispatch_operation_dup_channel (McdDispatchOperation *self)
{
- GList *copy;
-
g_return_val_if_fail (MCD_IS_DISPATCH_OPERATION (self), NULL);
- copy = g_list_copy (self->priv->channels);
- g_list_foreach (copy, (GFunc) g_object_ref, NULL);
- return copy;
+
+ if (self->priv->channel != NULL)
+ return g_object_ref (self->priv->channel);
+
+ return NULL;
}
static void
@@ -1922,11 +1902,10 @@ _mcd_dispatch_operation_handle_channels_cb (TpClient *client,
}
else
{
- const GList *list;
-
- for (list = self->priv->channels; list != NULL; list = list->next)
+ /* FIXME: can channel ever be NULL here? */
+ if (self->priv->channel != NULL)
{
- McdChannel *channel = list->data;
+ McdChannel *channel = MCD_CHANNEL (self->priv->channel);
const gchar *unique_name;
unique_name = _mcd_client_proxy_get_unique_name (MCD_CLIENT_PROXY (client));
@@ -1955,11 +1934,12 @@ _mcd_dispatch_operation_handle_channels_cb (TpClient *client,
g_warning ("Closing channel %s as a result",
mcd_channel_get_object_path (channel));
_mcd_channel_undispatchable (channel);
- continue;
}
-
- mcd_dispatch_operation_set_channel_handled_by (self, channel,
- unique_name, tp_proxy_get_bus_name (client));
+ else
+ {
+ mcd_dispatch_operation_set_channel_handled_by (self, channel,
+ unique_name, tp_proxy_get_bus_name (client));
+ }
}
/* emit Finished, if we haven't already; but first make a note of the
@@ -1998,36 +1978,25 @@ observe_channels_cb (TpClient *proxy, const GError *error,
* request-properties for Observer_Info or Handler_Info
*/
static void
-collect_satisfied_requests (const GList *channels,
+collect_satisfied_requests (McdChannel *channel,
GPtrArray **paths_out,
GHashTable **props_out)
{
- const GList *c;
- GHashTable *set;
GHashTableIter it;
gpointer path, value;
GPtrArray *satisfied_requests;
GHashTable *request_properties;
+ GHashTable *reqs;
- set = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_object_unref);
-
- for (c = channels; c != NULL; c = c->next)
- {
- GHashTable *reqs = _mcd_channel_get_satisfied_requests (c->data,
- NULL);
- tp_g_hash_table_update (set, reqs,
- (GBoxedCopyFunc) g_strdup, (GBoxedCopyFunc) g_object_ref);
- g_hash_table_unref (reqs);
- }
+ reqs = _mcd_channel_get_satisfied_requests (channel, NULL);
- satisfied_requests = g_ptr_array_sized_new (g_hash_table_size (set));
+ satisfied_requests = g_ptr_array_sized_new (g_hash_table_size (reqs));
g_ptr_array_set_free_func (satisfied_requests, g_free);
request_properties = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) g_hash_table_unref);
- g_hash_table_iter_init (&it, set);
+ g_hash_table_iter_init (&it, reqs);
while (g_hash_table_iter_next (&it, &path, &value))
{
@@ -2039,7 +2008,7 @@ collect_satisfied_requests (const GList *channels,
g_hash_table_insert (request_properties, g_strdup (path), props);
}
- g_hash_table_unref (set);
+ g_hash_table_unref (reqs);
if (paths_out != NULL)
*paths_out = satisfied_requests;
@@ -2055,7 +2024,6 @@ collect_satisfied_requests (const GList *channels,
static void
_mcd_dispatch_operation_run_observers (McdDispatchOperation *self)
{
- const GList *cl;
const gchar *dispatch_operation_path = "/";
GHashTable *observer_info;
GHashTableIter iter;
@@ -2068,7 +2036,7 @@ _mcd_dispatch_operation_run_observers (McdDispatchOperation *self)
while (g_hash_table_iter_next (&iter, NULL, &client_p))
{
McdClientProxy *client = MCD_CLIENT_PROXY (client_p);
- GList *observed = NULL;
+ gboolean observed = FALSE;
const gchar *account_path, *connection_path;
GPtrArray *channels_array, *satisfied_requests;
GHashTable *request_properties;
@@ -2077,9 +2045,9 @@ _mcd_dispatch_operation_run_observers (McdDispatchOperation *self)
TP_IFACE_QUARK_CLIENT_OBSERVER))
continue;
- for (cl = self->priv->channels; cl != NULL; cl = cl->next)
+ if (self->priv->channel != NULL)
{
- McdChannel *channel = MCD_CHANNEL (cl->data);
+ McdChannel *channel = MCD_CHANNEL (self->priv->channel);
GHashTable *properties;
properties = _mcd_channel_get_immutable_properties (channel);
@@ -2088,8 +2056,10 @@ _mcd_dispatch_operation_run_observers (McdDispatchOperation *self)
if (_mcd_client_match_filters (properties,
_mcd_client_proxy_get_observer_filters (client),
FALSE))
- observed = g_list_prepend (observed, channel);
+ observed = TRUE;
}
+
+ /* in particular this happens if there is no channel at all */
if (!observed) continue;
/* build up the parameters and invoke the observer */
@@ -2099,9 +2069,10 @@ _mcd_dispatch_operation_run_observers (McdDispatchOperation *self)
/* TODO: there's room for optimization here: reuse the channels_array,
* if the observed list is the same */
- channels_array = _mcd_tp_channel_details_build_from_list (observed);
+ channels_array = _mcd_tp_channel_details_build_from_tp_chan (
+ mcd_channel_get_tp_channel (self->priv->channel));
- collect_satisfied_requests (observed, &satisfied_requests,
+ collect_satisfied_requests (self->priv->channel, &satisfied_requests,
&request_properties);
/* transfer ownership into observer_info */
@@ -2129,8 +2100,6 @@ _mcd_dispatch_operation_run_observers (McdDispatchOperation *self)
g_ptr_array_unref (satisfied_requests);
_mcd_tp_channel_details_free (channels_array);
-
- g_list_free (observed);
}
g_hash_table_unref (observer_info);
@@ -2173,7 +2142,6 @@ add_dispatch_operation_cb (TpClient *proxy,
static void
_mcd_dispatch_operation_run_approvers (McdDispatchOperation *self)
{
- const GList *cl;
GHashTableIter iter;
gpointer client_p;
@@ -2195,9 +2163,9 @@ _mcd_dispatch_operation_run_approvers (McdDispatchOperation *self)
TP_IFACE_QUARK_CLIENT_APPROVER))
continue;
- for (cl = self->priv->channels; cl != NULL; cl = cl->next)
+ if (self->priv->channel != NULL)
{
- McdChannel *channel = MCD_CHANNEL (cl->data);
+ McdChannel *channel = MCD_CHANNEL (self->priv->channel);
GHashTable *channel_properties;
channel_properties = _mcd_channel_get_immutable_properties (channel);
@@ -2208,15 +2176,17 @@ _mcd_dispatch_operation_run_approvers (McdDispatchOperation *self)
FALSE))
{
matched = TRUE;
- break;
}
}
+
+ /* in particular, after this point, self->priv->channel can't
+ * be NULL */
if (!matched) continue;
dispatch_operation = _mcd_dispatch_operation_get_path (self);
properties = _mcd_dispatch_operation_get_properties (self);
- channel_details =
- _mcd_tp_channel_details_build_from_list (self->priv->channels);
+ channel_details = _mcd_tp_channel_details_build_from_tp_chan (
+ mcd_channel_get_tp_channel (self->priv->channel));
DEBUG ("Calling AddDispatchOperation on approver %s for CDO %s @ %p",
tp_proxy_get_bus_name (client), dispatch_operation, self);
@@ -2262,7 +2232,7 @@ _mcd_dispatch_operation_run_clients (McdDispatchOperation *self)
g_object_ref (self);
DEBUG ("%s %p", self->priv->unique_name, self);
- if (self->priv->channels != NULL)
+ if (self->priv->channel != NULL)
{
const GList *mini_plugins;
@@ -2308,6 +2278,7 @@ _mcd_dispatch_operation_run_clients (McdDispatchOperation *self)
static void
mcd_dispatch_operation_handle_channels (McdDispatchOperation *self)
{
+ GList *channels = NULL;
GHashTable *handler_info;
GHashTable *request_properties;
@@ -2330,19 +2301,31 @@ mcd_dispatch_operation_handle_channels (McdDispatchOperation *self)
return;
}
+ /* FIXME: it shouldn't be possible to get here without a channel */
+ if (self->priv->channel != NULL)
+ {
+ collect_satisfied_requests (self->priv->channel, NULL,
+ &request_properties);
+ channels = g_list_prepend (NULL, self->priv->channel);
+ }
+ else
+ {
+ request_properties = g_hash_table_new_full (g_str_hash,
+ g_str_equal, g_free, (GDestroyNotify) g_hash_table_unref);
+ }
+
handler_info = tp_asv_new (NULL, NULL);
- collect_satisfied_requests (self->priv->channels, NULL,
- &request_properties);
tp_asv_take_boxed (handler_info, "request-properties",
TP_HASH_TYPE_OBJECT_IMMUTABLE_PROPERTIES_MAP, request_properties);
request_properties = NULL;
_mcd_client_proxy_handle_channels (self->priv->trying_handler,
- -1, self->priv->channels, self->priv->handle_with_time,
+ -1, channels, self->priv->handle_with_time,
handler_info, _mcd_dispatch_operation_handle_channels_cb,
g_object_ref (self), g_object_unref, NULL);
g_hash_table_unref (handler_info);
+ g_list_free (channels);
}
static void
@@ -2385,9 +2368,7 @@ mcd_dispatch_operation_try_handler (McdDispatchOperation *self,
self->priv->handler_suitable_pending = 0;
- DEBUG ("%s: channel ACL verification [%u channels]",
- self->priv->unique_name,
- g_list_length (self->priv->channels));
+ DEBUG ("%s: channel ACL verification", self->priv->unique_name);
for (p = mcp_list_objects (); p != NULL; p = g_list_next (p))
{
@@ -2495,8 +2476,6 @@ static void
_mcd_dispatch_operation_close_as_undispatchable (McdDispatchOperation *self,
const GError *error)
{
- GList *channels, *list;
-
/* All of the usable handlers vanished while we were thinking about it
* (this can only happen if non-activatable handlers exit after we
* include them in the list of possible handlers, but before we .
@@ -2507,20 +2486,17 @@ _mcd_dispatch_operation_close_as_undispatchable (McdDispatchOperation *self,
_mcd_dispatch_operation_finish (self, error->domain, error->code,
"%s", error->message);
- channels = _mcd_dispatch_operation_dup_channels (self);
-
- for (list = channels; list != NULL; list = list->next)
+ if (self->priv->channel != NULL)
{
- McdChannel *channel = MCD_CHANNEL (list->data);
+ McdChannel *channel = MCD_CHANNEL (self->priv->channel);
GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE,
"Handler no longer available" };
+ g_object_ref (channel);
mcd_channel_take_error (channel, g_error_copy (&e));
_mcd_channel_undispatchable (channel);
g_object_unref (channel);
}
-
- g_list_free (channels);
}
void
@@ -2549,20 +2525,18 @@ _mcd_dispatch_operation_end_plugin_delay (McdDispatchOperation *self)
void
_mcd_dispatch_operation_forget_channels (McdDispatchOperation *self)
{
- /* make a temporary copy, which is destroyed during the loop - otherwise
- * we'll be trying to iterate over the list at the same time
- * that mcd_mission_abort results in modifying it, which would be bad */
- GList *list = _mcd_dispatch_operation_dup_channels (self);
-
- while (list != NULL)
+ if (self->priv->channel != NULL)
{
- mcd_mission_abort (list->data);
- g_object_unref (list->data);
- list = g_list_delete_link (list, list);
+ /* Take a temporary copy, because self->priv->channels is going
+ * to be modified as a result of mcd_mission_abort() */
+ McdChannel *channel = g_object_ref (self->priv->channel);
+
+ mcd_mission_abort (MCD_MISSION (channel));
+ g_object_unref (channel);
}
- /* There should now be none left (they all aborted) */
- g_return_if_fail (self->priv->channels == NULL);
+ /* There should now be no channel left (it was aborted) */
+ g_return_if_fail (self->priv->channel == NULL);
}
void
@@ -2570,20 +2544,19 @@ _mcd_dispatch_operation_leave_channels (McdDispatchOperation *self,
TpChannelGroupChangeReason reason,
const gchar *message)
{
- GList *list;
-
if (message == NULL)
{
message = "";
}
- list = _mcd_dispatch_operation_dup_channels (self);
-
- while (list != NULL)
+ if (self->priv->channel != NULL)
{
- _mcd_channel_depart (list->data, reason, message);
- g_object_unref (list->data);
- list = g_list_delete_link (list, list);
+ /* Take a temporary copy, because self->priv->channels could
+ * be modified as a result */
+ McdChannel *channel = g_object_ref (self->priv->channel);
+
+ _mcd_channel_depart (channel, reason, message);
+ g_object_unref (channel);
}
_mcd_dispatch_operation_forget_channels (self);
@@ -2592,13 +2565,14 @@ _mcd_dispatch_operation_leave_channels (McdDispatchOperation *self,
void
_mcd_dispatch_operation_close_channels (McdDispatchOperation *self)
{
- GList *list = _mcd_dispatch_operation_dup_channels (self);
-
- while (list != NULL)
+ if (self->priv->channel != NULL)
{
- _mcd_channel_close (list->data);
- g_object_unref (list->data);
- list = g_list_delete_link (list, list);
+ /* Take a temporary copy, because self->priv->channels could
+ * be modified as a result */
+ McdChannel *channel = g_object_ref (self->priv->channel);
+
+ _mcd_channel_close (channel);
+ g_object_unref (channel);
}
_mcd_dispatch_operation_forget_channels (self);
@@ -2607,13 +2581,14 @@ _mcd_dispatch_operation_close_channels (McdDispatchOperation *self)
void
_mcd_dispatch_operation_destroy_channels (McdDispatchOperation *self)
{
- GList *list = _mcd_dispatch_operation_dup_channels (self);
-
- while (list != NULL)
+ if (self->priv->channel != NULL)
{
- _mcd_channel_undispatchable (list->data);
- g_object_unref (list->data);
- list = g_list_delete_link (list, list);
+ /* Take a temporary copy, because self->priv->channels could
+ * be modified as a result */
+ McdChannel *channel = g_object_ref (self->priv->channel);
+
+ _mcd_channel_undispatchable (channel);
+ g_object_unref (channel);
}
_mcd_dispatch_operation_forget_channels (self);
diff --git a/src/mcd-dispatcher-priv.h b/src/mcd-dispatcher-priv.h
index 82c7ad42..639d751a 100644
--- a/src/mcd-dispatcher-priv.h
+++ b/src/mcd-dispatcher-priv.h
@@ -34,8 +34,10 @@
G_BEGIN_DECLS
/* not exported */
-G_GNUC_INTERNAL void _mcd_dispatcher_take_channels (
- McdDispatcher *dispatcher, GList *channels, gboolean requested,
+G_GNUC_INTERNAL void _mcd_dispatcher_add_channel (
+ McdDispatcher *dispatcher,
+ McdChannel *channel,
+ gboolean requested,
gboolean only_observe);
G_GNUC_INTERNAL
void _mcd_dispatcher_add_channel_request (McdDispatcher *dispatcher,
diff --git a/src/mcd-dispatcher.c b/src/mcd-dispatcher.c
index 19d11d6b..c7f3c7a3 100644
--- a/src/mcd-dispatcher.c
+++ b/src/mcd-dispatcher.c
@@ -178,14 +178,14 @@ mcd_dispatcher_dup_internal_handlers (void)
static GStrv
mcd_dispatcher_dup_possible_handlers (McdDispatcher *self,
McdRequest *request,
- const GList *channels,
+ TpChannel *channel,
const gchar *must_have_unique_name)
{
GList *handlers = _mcd_client_registry_list_possible_handlers (
self->priv->clients,
request != NULL ? _mcd_request_get_preferred_handler (request) : NULL,
request != NULL ? _mcd_request_get_properties (request) : NULL,
- channels, must_have_unique_name);
+ channel, must_have_unique_name);
guint n_handlers = g_list_length (handlers);
guint i;
GStrv ret;
@@ -238,7 +238,7 @@ on_operation_finished (McdDispatchOperation *operation,
static void
_mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
- GList *channels,
+ McdChannel *channel,
const gchar * const *possible_handlers,
gboolean requested,
gboolean only_observe)
@@ -248,11 +248,10 @@ _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
McdAccount *account;
g_return_if_fail (MCD_IS_DISPATCHER (dispatcher));
- g_return_if_fail (channels != NULL);
- g_return_if_fail (MCD_IS_CHANNEL (channels->data));
+ g_return_if_fail (MCD_IS_CHANNEL (channel));
g_return_if_fail (requested || !only_observe);
- account = mcd_channel_get_account (channels->data);
+ account = mcd_channel_get_account (channel);
if (G_UNLIKELY (!account))
{
g_warning ("%s called with no account", G_STRFUNC);
@@ -261,19 +260,13 @@ _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
priv = dispatcher->priv;
- DEBUG ("new dispatch operation for %s channel %p (%s): %s",
+ DEBUG ("new dispatch operation for %s channel %p: %s",
requested ? "requested" : "unrequested",
- channels->data,
- channels->next == NULL ? "only" : "and more",
- mcd_channel_get_object_path (channels->data));
-
- /* FIXME: what should we do when the channels are a mixture of Requested
- * and unRequested? At the moment we act as though they're all Requested;
- * perhaps we should act as though they're all unRequested, or split up the
- * bundle? */
+ channel,
+ mcd_channel_get_object_path (channel));
operation = _mcd_dispatch_operation_new (priv->clients,
- priv->handler_map, !requested, only_observe, channels,
+ priv->handler_map, !requested, only_observe, channel,
(const gchar * const *) possible_handlers);
if (!requested)
@@ -297,28 +290,21 @@ _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
{
GError error = { TP_ERROR, TP_ERROR_CANCELLED,
"Channel request cancelled" };
- GList *list;
+ McdChannel *cancelled;
- /* make a temporary copy, which is destroyed during the loop -
- * otherwise we'll be trying to iterate over the list at the same time
- * that mcd_mission_abort results in modifying it, which would be
- * bad */
- list = _mcd_dispatch_operation_dup_channels (operation);
+ cancelled = _mcd_dispatch_operation_dup_channel (operation);
- while (list != NULL)
+ if (cancelled != NULL)
{
- McdChannel *channel = MCD_CHANNEL (list->data);
-
- if (mcd_channel_get_error (channel) == NULL)
- mcd_channel_take_error (channel, g_error_copy (&error));
+ if (mcd_channel_get_error (cancelled) == NULL)
+ mcd_channel_take_error (cancelled, g_error_copy (&error));
- _mcd_channel_undispatchable (channel);
+ _mcd_channel_undispatchable (cancelled);
- g_object_unref (channel);
- list = g_list_delete_link (list, list);
+ g_object_unref (cancelled);
}
}
- else if (_mcd_dispatch_operation_peek_channels (operation) == NULL)
+ else if (_mcd_dispatch_operation_peek_channel (operation) == NULL)
{
DEBUG ("No channels left");
}
@@ -546,7 +532,6 @@ _mcd_dispatcher_lookup_handler (McdDispatcher *self,
if (handler == NULL)
{
GList *possible_handlers;
- GList *channels;
/* Failing that, maybe the Handler it was dispatched to was temporary;
* try to pick another Handler that can deal with it, on the same
@@ -554,12 +539,11 @@ _mcd_dispatcher_lookup_handler (McdDispatcher *self,
* It can also happen in the case an Observer/Approver Claimed the
* channel; in that case we did not get its handler well known name.
*/
- channels = g_list_prepend (NULL, channel);
possible_handlers = _mcd_client_registry_list_possible_handlers (
self->priv->clients,
request != NULL ? _mcd_request_get_preferred_handler (request) : NULL,
request != NULL ? _mcd_request_get_properties (request) : NULL,
- channels, unique_name);
+ channel, unique_name);
if (possible_handlers != NULL)
{
@@ -576,7 +560,6 @@ _mcd_dispatcher_lookup_handler (McdDispatcher *self,
unique_name, object_path);
}
- g_list_free (channels);
g_list_free (possible_handlers);
}
@@ -632,11 +615,11 @@ mcd_dispatcher_client_needs_recovery_cb (McdClientProxy *client,
if (_mcd_dispatch_operation_has_invoked_observers (op))
{
- for (channels = _mcd_dispatch_operation_peek_channels (op);
- channels != NULL;
- channels = channels->next)
+ McdChannel *mcd_channel =
+ _mcd_dispatch_operation_peek_channel (op);
+
+ if (mcd_channel != NULL)
{
- McdChannel *mcd_channel = channels->data;
GHashTable *properties =
_mcd_channel_get_immutable_properties (mcd_channel);
@@ -924,36 +907,31 @@ mcd_dispatcher_new (TpDBusDaemon *dbus_daemon, McdMaster *master)
}
/*
- * _mcd_dispatcher_take_channels:
+ * _mcd_dispatcher_add_channel:
* @dispatcher: the #McdDispatcher.
- * @channels: a #GList of #McdChannel elements, each of which must own a
- * #TpChannel
+ * @channel: (transfer none): a #McdChannel which must own a #TpChannel
* @requested: whether the channels were requested by MC.
*
- * Dispatch @channels. The #GList @channels will be no longer valid after this
- * function has been called.
+ * Add @channel to the dispatching state machine.
*/
void
-_mcd_dispatcher_take_channels (McdDispatcher *dispatcher, GList *channels,
- gboolean requested, gboolean only_observe)
+_mcd_dispatcher_add_channel (McdDispatcher *dispatcher,
+ McdChannel *channel,
+ gboolean requested,
+ gboolean only_observe)
{
- GList *list;
- GList *tp_channels = NULL;
+ TpChannel *tp_channel = NULL;
GStrv possible_handlers;
McdRequest *request = NULL;
gboolean internal_request = FALSE;
- if (channels == NULL)
- {
- DEBUG ("trivial case - no channels");
- return;
- }
+ g_return_if_fail (MCD_IS_DISPATCHER (dispatcher));
+ g_return_if_fail (MCD_IS_CHANNEL (channel));
- DEBUG ("%s channel %p (%s): %s",
+ DEBUG ("%s channel %p: %s",
requested ? "requested" : "unrequested",
- channels->data,
- channels->next == NULL ? "only" : "and more",
- mcd_channel_get_object_path (channels->data));
+ channel,
+ mcd_channel_get_object_path (channel));
if (only_observe)
{
@@ -961,29 +939,17 @@ _mcd_dispatcher_take_channels (McdDispatcher *dispatcher, GList *channels,
/* these channels were requested "behind our back", so only call
* ObserveChannels on them */
- _mcd_dispatcher_enter_state_machine (dispatcher, channels, NULL,
+ _mcd_dispatcher_enter_state_machine (dispatcher, channel, NULL,
TRUE, TRUE);
- g_list_free (channels);
return;
}
- /* These channels must have the TpChannel part of McdChannel's double life.
- * They might also have the McdRequest part. */
- for (list = channels; list != NULL; list = list->next)
- {
- TpChannel *tp_channel = mcd_channel_get_tp_channel (list->data);
-
- g_assert (tp_channel != NULL);
- tp_channels = g_list_prepend (tp_channels, g_object_ref (tp_channel));
-
- /* We take the channel request from the first McdChannel that (has|is)
- * one.*/
- if (request == NULL)
- {
- request = _mcd_channel_get_request (list->data);
- }
- }
+ /* The channel must have the TpChannel part of McdChannel's double life.
+ * It might also have the McdRequest part. */
+ tp_channel = mcd_channel_get_tp_channel (channel);
+ g_assert (tp_channel != NULL);
+ request = _mcd_channel_get_request (channel);
internal_request = _mcd_request_is_internal (request);
/* See if there are any handlers that can take all these channels */
@@ -992,49 +958,24 @@ _mcd_dispatcher_take_channels (McdDispatcher *dispatcher, GList *channels,
else
possible_handlers = mcd_dispatcher_dup_possible_handlers (dispatcher,
request,
- tp_channels,
+ tp_channel,
NULL);
- g_list_foreach (tp_channels, (GFunc) g_object_unref, NULL);
- g_list_free (tp_channels);
-
if (possible_handlers == NULL)
{
- if (channels->next == NULL)
- {
- DEBUG ("One channel, which cannot be handled - making a CDO "
- "anyway, to get Observers run");
- }
- else
- {
- DEBUG ("Two or more channels, which cannot all be handled - "
- "will split up the batch and try again");
-
- while (channels != NULL)
- {
- list = channels;
- channels = g_list_remove_link (channels, list);
- _mcd_dispatcher_take_channels (dispatcher, list, requested,
- FALSE);
- }
-
- return;
- }
+ DEBUG ("Channel cannot be handled - making a CDO "
+ "anyway, to get Observers run");
}
else
{
- DEBUG ("%s handler(s) found, dispatching %u channels",
- internal_request ? "internal" : "possible",
- g_list_length (channels));
+ DEBUG ("%s handler(s) found, dispatching channel",
+ internal_request ? "internal" : "possible");
}
- for (list = channels; list != NULL; list = list->next)
- _mcd_channel_set_status (MCD_CHANNEL (list->data),
- MCD_CHANNEL_STATUS_DISPATCHING);
+ _mcd_channel_set_status (channel, MCD_CHANNEL_STATUS_DISPATCHING);
- _mcd_dispatcher_enter_state_machine (dispatcher, channels,
+ _mcd_dispatcher_enter_state_machine (dispatcher, channel,
(const gchar * const *) possible_handlers, requested, FALSE);
- g_list_free (channels);
g_strfreev (possible_handlers);
}
@@ -1245,10 +1186,7 @@ _mcd_dispatcher_recover_channel (McdDispatcher *dispatcher,
DEBUG ("%s is unhandled, redispatching", path);
requested = mcd_channel_is_requested (channel);
- _mcd_dispatcher_take_channels (dispatcher,
- g_list_prepend (NULL, channel),
- requested,
- FALSE);
+ _mcd_dispatcher_add_channel (dispatcher, channel, requested, FALSE);
}
}
@@ -2126,16 +2064,11 @@ add_possible_handlers (McdDispatcher *self,
const gchar *sender,
const gchar *preferred_handler)
{
- GList *channels = NULL;
GStrv possible_handlers;
guint i;
- channels = g_list_prepend (channels, tp_channel);
-
possible_handlers = mcd_dispatcher_dup_possible_handlers (self,
- NULL, channels, NULL);
-
- g_list_free (channels);
+ NULL, tp_channel, NULL);
for (i = 0; possible_handlers[i] != NULL; i++)
{
diff --git a/src/plugin-dispatch-operation.c b/src/plugin-dispatch-operation.c
index 934e6dde..0281dbfc 100644
--- a/src/plugin-dispatch-operation.c
+++ b/src/plugin-dispatch-operation.c
@@ -178,9 +178,11 @@ plugin_do_get_n_channels (McpDispatchOperation *obj)
McdPluginDispatchOperation *self = MCD_PLUGIN_DISPATCH_OPERATION (obj);
g_return_val_if_fail (self != NULL, 0);
- /* FIXME: O(n) */
- return g_list_length ((GList *) _mcd_dispatch_operation_peek_channels (
- self->real_cdo));
+
+ if (_mcd_dispatch_operation_peek_channel (self->real_cdo) != NULL)
+ return 1;
+
+ return 0;
}
static const gchar *
@@ -191,11 +193,10 @@ plugin_do_get_nth_channel_path (McpDispatchOperation *obj,
McdChannel *channel;
g_return_val_if_fail (self != NULL, NULL);
- /* FIXME: O(n) */
- channel = g_list_nth_data ((GList *) _mcd_dispatch_operation_peek_channels (
- self->real_cdo), n);
- if (channel == NULL)
+ channel = _mcd_dispatch_operation_peek_channel (self->real_cdo);
+
+ if (channel == NULL || n != 0)
return NULL;
return mcd_channel_get_object_path (channel);
@@ -210,11 +211,10 @@ plugin_do_ref_nth_channel_properties (McpDispatchOperation *obj,
GHashTable *ret;
g_return_val_if_fail (self != NULL, NULL);
- /* FIXME: O(n) */
- channel = g_list_nth_data ((GList *) _mcd_dispatch_operation_peek_channels (
- self->real_cdo), n);
- if (channel == NULL)
+ channel = _mcd_dispatch_operation_peek_channel (self->real_cdo);
+
+ if (channel == NULL || n != 0)
return NULL;
ret = _mcd_channel_get_immutable_properties (channel);
diff --git a/tests/twisted/dispatcher/exploding-bundles.py b/tests/twisted/dispatcher/exploding-bundles.py
index a62a7009..27d3be3a 100644
--- a/tests/twisted/dispatcher/exploding-bundles.py
+++ b/tests/twisted/dispatcher/exploding-bundles.py
@@ -107,34 +107,30 @@ def test(q, bus, mc):
conn.NewChannels([text_chan, media_chan])
- # A channel dispatch operation is created
+ # A channel dispatch operation is created for the Text channel first.
e = q.expect('dbus-signal',
path=cs.CD_PATH,
interface=cs.CD_IFACE_OP_LIST,
signal='NewDispatchOperation')
- cdo_path = e.args[0]
- cdo_properties = e.args[1]
+ text_cdo_path = e.args[0]
+ text_cdo_properties = e.args[1]
- assert cdo_properties[cs.CDO + '.Account'] == account.object_path
- assert cdo_properties[cs.CDO + '.Connection'] == conn.object_path
+ assert text_cdo_properties[cs.CDO + '.Account'] == account.object_path
+ assert text_cdo_properties[cs.CDO + '.Connection'] == conn.object_path
- handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
- # only Empathy can handle the whole batch
- assert handlers == [cs.tp_name_prefix + '.Client.org.gnome.Empathy'], \
- handlers
+ handlers = text_cdo_properties[cs.CDO + '.PossibleHandlers'][:]
+ assert (sorted(handlers) ==
+ [cs.tp_name_prefix + '.Client.org.gnome.Empathy',
+ cs.tp_name_prefix + '.Client.org.kde.Kopete']), handlers
- assert cs.CD_IFACE_OP_LIST in cd_props.Get(cs.CD, 'Interfaces')
- assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') ==\
- [(cdo_path, cdo_properties)]
-
- cdo = bus.get_object(cs.CD, cdo_path)
- cdo_iface = dbus.Interface(cdo, cs.CDO)
+ text_cdo = bus.get_object(cs.CD, text_cdo_path)
+ text_cdo_iface = dbus.Interface(text_cdo, cs.CDO)
- # Both Observers are told about the new channels
+ # Both Observers are told about the new Text channel
- e, k = q.expect_many(
+ e_observe_text, k_observe_text = q.expect_many(
EventPattern('dbus-method-call',
path=empathy.object_path,
interface=cs.OBSERVER, method='ObserveChannels',
@@ -144,62 +140,130 @@ def test(q, bus, mc):
interface=cs.OBSERVER, method='ObserveChannels',
handled=False),
)
- assert e.args[0] == account.object_path, e.args
- assert e.args[1] == conn.object_path, e.args
- assert e.args[3] == cdo_path, e.args
- assert e.args[4] == [], e.args # no requests satisfied
- channels = e.args[2]
- assert len(channels) == 2, channels
+ assert e_observe_text.args[0] == account.object_path, e_observe_text.args
+ assert e_observe_text.args[1] == conn.object_path, e_observe_text.args
+ assert e_observe_text.args[3] == text_cdo_path, e_observe_text.args
+ assert e_observe_text.args[4] == [], e_observe_text.args
+ channels = e_observe_text.args[2]
+ assert len(channels) == 1, channels
assert (text_chan.object_path, text_channel_properties) in channels
+
+ assert k_observe_text.args[0] == e_observe_text.args[0], k_observe_text.args
+ assert k_observe_text.args[1] == e_observe_text.args[1], k_observe_text.args
+ assert (k_observe_text.args[2] ==
+ [(text_chan.object_path, text_channel_properties)])
+
+ # Now a separate CDO is created for the media channel.
+
+ e = q.expect('dbus-signal',
+ path=cs.CD_PATH,
+ interface=cs.CD_IFACE_OP_LIST,
+ signal='NewDispatchOperation')
+
+ media_cdo_path = e.args[0]
+ media_cdo_properties = e.args[1]
+
+ assert media_cdo_properties[cs.CDO + '.Account'] == account.object_path
+ assert media_cdo_properties[cs.CDO + '.Connection'] == conn.object_path
+
+ handlers = media_cdo_properties[cs.CDO + '.PossibleHandlers'][:]
+ # only Empathy can handle it
+ assert (sorted(handlers) ==
+ [cs.tp_name_prefix + '.Client.org.gnome.Empathy']), handlers
+
+ assert cs.CD_IFACE_OP_LIST in cd_props.Get(cs.CD, 'Interfaces')
+ assert (sorted(cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations')) ==
+ [(text_cdo_path, text_cdo_properties),
+ (media_cdo_path, media_cdo_properties)])
+
+ media_cdo = bus.get_object(cs.CD, media_cdo_path)
+ media_cdo_iface = dbus.Interface(media_cdo, cs.CDO)
+
+ # Only Empathy is told about the new media channel
+
+ e_observe_media = q.expect('dbus-method-call',
+ path=empathy.object_path,
+ interface=cs.OBSERVER, method='ObserveChannels',
+ handled=False)
+ assert e_observe_media.args[0] == account.object_path, e_observe_media.args
+ assert e_observe_media.args[1] == conn.object_path, e_observe_media.args
+ assert e_observe_media.args[3] == media_cdo_path, e_observe_media.args
+ assert e_observe_media.args[4] == [], e_observe_media.args
+ channels = e_observe_media.args[2]
+ assert len(channels) == 1, channels
assert (media_chan.object_path, media_channel_properties) in channels
- # fd.o #21089: telepathy-spec doesn't say whether Kopete observes the whole
- # batch or just the text channel. In current MC, it only observes the text.
- assert k.args[0] == e.args[0], k.args
- assert k.args[1] == e.args[1], e.args
- assert k.args[2] == [(text_chan.object_path, text_channel_properties)]
+ # All Observers reply.
- # Both Observers indicate that they are ready to proceed
- q.dbus_return(k.message, signature='')
- q.dbus_return(e.message, signature='')
+ q.dbus_return(e_observe_text.message, signature='')
+ q.dbus_return(k_observe_text.message, signature='')
+ q.dbus_return(e_observe_media.message, signature='')
# The Approvers are next
- # fd.o #21090: telepathy-spec doesn't say whether Kopete is asked to
- # approve this CDO. In current MC, it is.
- e, k = q.expect_many(
+ e_approve_text, k_approve_text, e_approve_media = q.expect_many(
EventPattern('dbus-method-call',
path=empathy.object_path,
interface=cs.APPROVER, method='AddDispatchOperation',
+ predicate=lambda e: e.args[1] == text_cdo_path,
handled=False),
EventPattern('dbus-method-call',
path=kopete.object_path,
interface=cs.APPROVER, method='AddDispatchOperation',
handled=False),
+ EventPattern('dbus-method-call',
+ path=empathy.object_path,
+ interface=cs.APPROVER, method='AddDispatchOperation',
+ predicate=lambda e: e.args[1] == media_cdo_path,
+ handled=False)
)
- assert len(e.args[0]) == 2
- assert (text_chan.object_path, text_channel_properties) in e.args[0]
- assert (media_chan.object_path, media_channel_properties) in e.args[0]
- assert e.args[1:] == [cdo_path, cdo_properties]
- assert k.args == e.args
+ assert len(e_approve_text.args[0]) == 1
+ assert ((text_chan.object_path, text_channel_properties) in
+ e_approve_text.args[0])
+ assert e_approve_text.args[1:] == [text_cdo_path, text_cdo_properties]
+ assert k_approve_text.args == e_approve_text.args
- q.dbus_return(e.message, signature='')
- q.dbus_return(k.message, signature='')
+ assert len(e_approve_media.args[0]) == 1
+ assert ((media_chan.object_path, media_channel_properties) in
+ e_approve_media.args[0])
+ assert e_approve_media.args[1:] == [media_cdo_path, media_cdo_properties]
+
+ q.dbus_return(e_approve_text.message, signature='')
+ q.dbus_return(k_approve_text.message, signature='')
+ q.dbus_return(e_approve_media.message, signature='')
# Both Approvers now have a flashing icon or something, trying to get the
- # user's attention
+ # user's attention. The user clicks on Empathy
+ call_async(q, text_cdo_iface, 'HandleWith',
+ cs.tp_name_prefix + '.Client.org.gnome.Empathy')
+
+ # Empathy is asked to handle the channel
+ e = q.expect('dbus-method-call',
+ path=empathy.object_path,
+ interface=cs.HANDLER, method='HandleChannels',
+ handled=False)
+
+ # Empathy accepts the channel
+ q.dbus_return(e.message, signature='')
+
+ q.expect_many(
+ EventPattern('dbus-return', method='HandleWith'),
+ EventPattern('dbus-signal', interface=cs.CDO, signal='Finished'),
+ EventPattern('dbus-signal', interface=cs.CD_IFACE_OP_LIST,
+ signal='DispatchOperationFinished'),
+ )
- # The user doesn't care which one will handle the channels - because
+ # The user doesn't care which client will handle the channel - because
# Empathy is the only possibility, it will be chosen (this is also a
# regression test for the ability to leave the handler unspecified).
- call_async(q, cdo_iface, 'HandleWith', '')
+ call_async(q, media_cdo_iface, 'HandleWith', '')
- # Empathy is asked to handle the channels
+ # Empathy is asked to handle the channel
e = q.expect('dbus-method-call',
path=empathy.object_path,
interface=cs.HANDLER, method='HandleChannels',
handled=False)
- # Empathy accepts the channels
+ # Empathy accepts the channel
q.dbus_return(e.message, signature='')
q.expect_many(