diff options
author | Sjoerd Simons <sjoerd.simons@collabora.co.uk> | 2009-01-10 00:12:07 +0800 |
---|---|---|
committer | Xavier Claessens <xclaesse@src.gnome.org> | 2009-01-10 00:12:07 +0800 |
commit | 9940bfed4c589710add05be776b7b1817bf9d48d (patch) | |
tree | a60db33d3e746612c1c502006d151fd40407dc33 /libempathy/empathy-dispatch-operation.c | |
parent | 9d4e38bf73836e75dd4a86b3929317b612236f1f (diff) | |
download | gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.gz gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.bz2 gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.lz gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.xz gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.tar.zst gsoc2013-empathy-9940bfed4c589710add05be776b7b1817bf9d48d.zip |
Start reworking the dispatcher
Rework the channel dispatche so it's model is somewhat similar to the
ChannelDispatcher in the telepathy-spec. Which allows for a much cleaner and
extensible implementation containg no ugly hacks. Currently it's only able to
do Text Channels and a lot of the other functionality is temporary disabled
Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
svn path=/trunk/; revision=2130
Diffstat (limited to 'libempathy/empathy-dispatch-operation.c')
-rw-r--r-- | libempathy/empathy-dispatch-operation.c | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/libempathy/empathy-dispatch-operation.c b/libempathy/empathy-dispatch-operation.c new file mode 100644 index 000000000..7f3357b8f --- /dev/null +++ b/libempathy/empathy-dispatch-operation.c @@ -0,0 +1,519 @@ +/* + * empathy-dispatch-operation.c - Source for EmpathyDispatchOperation + * Copyright (C) 2008 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include "empathy-dispatch-operation.h" +#include <libempathy/empathy-enum-types.h> +#include <libempathy/empathy-tp-chat.h> +#include <libempathy/empathy-tp-call.h> + +#include "empathy-marshal.h" + +#define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER +#include <libempathy/empathy-debug.h> + +G_DEFINE_TYPE(EmpathyDispatchOperation, empathy_dispatch_operation, + G_TYPE_OBJECT) + +static void empathy_dispatch_operation_set_status ( + EmpathyDispatchOperation *self, EmpathyDispatchOperationState status); +static void empathy_dispatch_operation_channel_ready_cb (TpChannel *channel, + const GError *error, gpointer user_data); + +/* signal enum */ +enum +{ + /* Ready for dispatching */ + READY, + /* Approved by an approver, can only happens on incoming operations */ + APPROVED, + /* Claimed by a handler */ + CLAIMED, + /* Error, channel went away, inspecting it failed etc */ + INVALIDATED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +/* properties */ +enum { + PROP_CONNECTION = 1, + PROP_CHANNEL, + PROP_CHANNEL_WRAPPER, + PROP_CONTACT, + PROP_INCOMING, + PROP_STATUS, +}; + +/* private structure */ +typedef struct _EmpathyDispatchOperationPriv \ + EmpathyDispatchOperationPriv; + +struct _EmpathyDispatchOperationPriv +{ + gboolean dispose_has_run; + TpConnection *connection; + TpChannel *channel; + GObject *channel_wrapper; + EmpathyContact *contact; + EmpathyDispatchOperationState status; + gboolean incoming; + gboolean approved; + gulong invalidated_handler; +}; + +#define GET_PRIV(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_DISPATCH_OPERATION, \ + EmpathyDispatchOperationPriv)) + +static void +empathy_dispatch_operation_init (EmpathyDispatchOperation *obj) +{ + //EmpathyDispatchOperationPriv *priv = + // GET_PRIV (obj); + + /* allocate any data required by the object here */ +} + +static void empathy_dispatch_operation_dispose (GObject *object); +static void empathy_dispatch_operation_finalize (GObject *object); + +static void +empathy_dispatch_operation_set_property (GObject *object, + guint property_id, const GValue *value, GParamSpec *pspec) +{ + EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object); + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + switch (property_id) + { + case PROP_CONNECTION: + priv->connection = g_value_dup_object (value); + break; + case PROP_CHANNEL: + priv->channel = g_value_dup_object (value); + break; + case PROP_CHANNEL_WRAPPER: + priv->channel_wrapper = g_value_dup_object (value); + break; + case PROP_CONTACT: + if (priv->contact != NULL) + g_object_unref (priv->contact); + priv->contact = g_value_dup_object (value); + break; + case PROP_INCOMING: + priv->incoming = g_value_get_boolean (value); + break; + } +} + +static void +empathy_dispatch_operation_get_property (GObject *object, + guint property_id, GValue *value, GParamSpec *pspec) +{ + EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object); + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + switch (property_id) + { + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); + break; + case PROP_CHANNEL: + g_value_set_object (value, priv->channel); + break; + case PROP_CHANNEL_WRAPPER: + g_value_set_object (value, priv->channel_wrapper); + break; + case PROP_CONTACT: + g_value_set_object (value, priv->contact); + break; + case PROP_INCOMING: + g_value_set_boolean (value, priv->incoming); + break; + case PROP_STATUS: + g_value_set_enum (value, priv->status); + break; + } +} + +static void +empathy_dispatch_operation_invalidated (TpProxy *proxy, guint domain, + gint code, char *message, EmpathyDispatchOperation *self) +{ + empathy_dispatch_operation_set_status (self, + EMPATHY_DISPATCHER_OPERATION_STATE_INVALIDATED); + + g_signal_emit (self, signals[INVALIDATED], 0, domain, code, message); +} + +static void +empathy_dispatch_operation_constructed (GObject *object) +{ + EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object); + EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + + empathy_dispatch_operation_set_status (self, + EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING); + + priv->invalidated_handler = + g_signal_connect (priv->channel, "invalidated", + G_CALLBACK (empathy_dispatch_operation_invalidated), self); + + tp_channel_call_when_ready (priv->channel, + empathy_dispatch_operation_channel_ready_cb, self); +} + +static void +empathy_dispatch_operation_class_init ( + EmpathyDispatchOperationClass *empathy_dispatch_operation_class) +{ + GObjectClass *object_class = + G_OBJECT_CLASS (empathy_dispatch_operation_class); + GParamSpec *param_spec; + + g_type_class_add_private (empathy_dispatch_operation_class, + sizeof (EmpathyDispatchOperationPriv)); + + object_class->set_property = empathy_dispatch_operation_set_property; + object_class->get_property = empathy_dispatch_operation_get_property; + + object_class->dispose = empathy_dispatch_operation_dispose; + object_class->finalize = empathy_dispatch_operation_finalize; + object_class->constructed = empathy_dispatch_operation_constructed; + + signals[READY] = g_signal_new ("ready", + G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[APPROVED] = g_signal_new ("approved", + G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[CLAIMED] = g_signal_new ("claimed", + G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[INVALIDATED] = g_signal_new ("invalidated", + G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + _empathy_marshal_VOID__UINT_INT_STRING, + G_TYPE_NONE, 0); + + param_spec = g_param_spec_object ("connection", + "connection", "The telepathy connection", + TP_TYPE_CONNECTION, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CONNECTION, + param_spec); + + param_spec = g_param_spec_object ("channel", + "channel", "The telepathy channel", + TP_TYPE_CHANNEL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CHANNEL, + param_spec); + + param_spec = g_param_spec_object ("channel-wrapper", + "channel wrapper", "The empathy specific channel wrapper", + G_TYPE_OBJECT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CHANNEL_WRAPPER, + param_spec); + + param_spec = g_param_spec_object ("contact", + "contact", "The empathy contact", + EMPATHY_TYPE_CONTACT, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CONTACT, + param_spec); + + param_spec = g_param_spec_boolean ("incoming", + "incoming", "Whether or not the channel is incoming", + FALSE, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_INCOMING, + param_spec); + + param_spec = g_param_spec_enum ("status", + "status", "Status of the dispatch operation", + EMPATHY_TYPE_DISPATCH_OPERATION_STATE, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_STATUS, param_spec); +} + +void +empathy_dispatch_operation_dispose (GObject *object) +{ + EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object); + EmpathyDispatchOperationPriv *priv = + GET_PRIV (self); + + if (priv->dispose_has_run) + return; + + priv->dispose_has_run = TRUE; + + g_object_unref (priv->connection); + + g_signal_handler_disconnect (priv->channel, priv->invalidated_handler); + g_object_unref (priv->channel); + + if (priv->contact != NULL) + g_object_unref (priv->contact); + + if (G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose) + G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose (object); +} + +void +empathy_dispatch_operation_finalize (GObject *object) +{ + /* free any data held directly by the object here */ + G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->finalize (object); +} + +static void +empathy_dispatch_operation_set_status (EmpathyDispatchOperation *self, + EmpathyDispatchOperationState status) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + + g_assert (status >= priv->status); + + + if (priv->status != status) + { + DEBUG ("Dispatch operation %s status: %d -> %d", + empathy_dispatch_operation_get_object_path (self), + priv->status, status); + + priv->status = status; + g_object_notify (G_OBJECT (self), "status"); + + if (status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING) + g_signal_emit (self, signals[READY], 0); + } +} + +static void +empathy_dispatch_operation_channel_ready_cb (TpChannel *channel, + const GError *error, gpointer user_data) +{ + EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data); + EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + GQuark channel_type; + + g_assert (channel == priv->channel); + + if (priv->channel_wrapper != NULL) + goto out; + + channel_type = tp_channel_get_channel_type_id (channel); + + if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT) + { + EmpathyTpChat *chat= empathy_tp_chat_new (channel); + priv->channel_wrapper = G_OBJECT (chat); + } + else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA) + { + EmpathyTpCall *call = empathy_tp_call_new (channel); + priv->channel_wrapper = G_OBJECT (call); + } + +out: + empathy_dispatch_operation_set_status (self, + EMPATHY_DISPATCHER_OPERATION_STATE_PENDING); +} + +EmpathyDispatchOperation * +empathy_dispatch_operation_new (TpConnection *connection, TpChannel *channel, + EmpathyContact *contact, gboolean incoming) +{ + return empathy_dispatch_operation_new_with_wrapper (connection, channel, + contact, incoming, NULL); +} + +EmpathyDispatchOperation * +empathy_dispatch_operation_new_with_wrapper (TpConnection *connection, + TpChannel *channel, EmpathyContact *contact, gboolean incoming, + GObject *wrapper) +{ + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (channel != NULL, NULL); + + return EMPATHY_DISPATCH_OPERATION ( + g_object_new (EMPATHY_TYPE_DISPATCH_OPERATION, + "connection", connection, + "channel", channel, + "channel-wrapper", wrapper, + "contact", contact, + "incoming", incoming, + NULL)); +} + +void +empathy_dispatch_operation_start (EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + g_return_if_fail ( + priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING); + + if (priv->incoming && !priv->approved) + empathy_dispatch_operation_set_status (operation, + EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING); + else + empathy_dispatch_operation_set_status (operation, + EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING); +} + +void +empathy_dispatch_operation_approve (EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING) + { + DEBUG ("Approving operation %s", + empathy_dispatch_operation_get_object_path (operation)); + + empathy_dispatch_operation_set_status (operation, + EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING); + + g_signal_emit (operation, signals[APPROVED], 0); + } + else + { + DEBUG ("Pre-approving operation %s", + empathy_dispatch_operation_get_object_path (operation)); + priv->approved = TRUE; + } +} + +/* Returns whether or not the operation was successfully claimed */ +gboolean +empathy_dispatch_operation_claim (EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED) + return FALSE; + + empathy_dispatch_operation_set_status (operation, + EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED); + + g_signal_emit (operation, signals[CLAIMED], 0); + + return TRUE; +} + +TpConnection * +empathy_dispatch_operation_get_tp_connection ( + EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + return g_object_ref (priv->connection); +} + +TpChannel * +empathy_dispatch_operation_get_channel (EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + return TP_CHANNEL (g_object_ref (priv->channel)); +} + +GObject * +empathy_dispatch_operation_get_channel_wrapper ( + EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + if (priv->channel_wrapper != NULL) + g_object_ref (priv->channel_wrapper); + + return priv->channel_wrapper; +} + +const gchar * +empathy_dispatch_operation_get_channel_type ( + EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + return tp_channel_get_channel_type (priv->channel); +} + +GQuark +empathy_dispatch_operation_get_channel_type_id ( + EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + return tp_channel_get_channel_type_id (priv->channel); +} + +const gchar * +empathy_dispatch_operation_get_object_path ( + EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + return tp_proxy_get_object_path (TP_PROXY (priv->channel)); +} + +EmpathyDispatchOperationState +empathy_dispatch_operation_get_status (EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + return priv->status; +} + +gboolean +empathy_dispatch_operation_is_incoming (EmpathyDispatchOperation *operation) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (operation); + + return priv->incoming; +} |