[vinagre] Import TpHandler to Vinagre source tree



commit 2fc7557d426e035610af180b8ace394105c9e669
Author: Guillaume Desmottes <guillaume desmottes collabora co uk>
Date:   Wed Jan 13 16:36:17 2010 +0000

    Import TpHandler to Vinagre source tree
    
    Branch has not been merged in tp-glib yet.

 vinagre/Makefile.am             |    1 +
 vinagre/handler.c               |  773 +++++++++++++++++++++++++++++++++++++++
 vinagre/handler.h               |  128 +++++++
 vinagre/vinagre-tubes-manager.h |    2 +-
 4 files changed, 903 insertions(+), 1 deletions(-)
---
diff --git a/vinagre/Makefile.am b/vinagre/Makefile.am
index c57792c..3e178ad 100644
--- a/vinagre/Makefile.am
+++ b/vinagre/Makefile.am
@@ -275,6 +275,7 @@ vinagre_LDADD += $(TELEPATHY_LIBS)
 handwritten_sources += \
 	vinagre-tubes-manager.c vinagre-tubes-manager.h		\
 	vinagre-tube-handler.c vinagre-tube-handler.h		\
+	handler.c handler.h \
 	$(NULL)
 
 endif
diff --git a/vinagre/handler.c b/vinagre/handler.c
new file mode 100644
index 0000000..18419c5
--- /dev/null
+++ b/vinagre/handler.c
@@ -0,0 +1,773 @@
+/*
+ * handler.c - convenience class to implement a Telepathy Handler
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.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 <telepathy-glib/dbus.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/enums.h>
+#include <telepathy-glib/svc-generic.h>
+#include <telepathy-glib/svc-client.h>
+#include <telepathy-glib/util.h>
+
+#include "handler.h"
+#include "vinagre-marshal.h"
+
+#define DEBUG
+
+static void handler_iface_init (gpointer, gpointer);
+static void requests_iface_init (gpointer, gpointer);
+
+#define GET_PRIVATE(obj)	(G_TYPE_INSTANCE_GET_PRIVATE ((obj), TP_TYPE_HANDLER, TpHandlerPrivate))
+
+/**
+ * SECTION:handler
+ * @title: TpHandler
+ * @short_description: convenience class to implement a Telepathy Handler
+ *
+ * Provides a #GObject implementing the Client.Handler interface that can be
+ * published using dbus-glib.
+ *
+ * <example><programlisting>
+ * tpdbus = tp_dbus_daemon_dup (NULL);
+ * dbus = tp_get_bus ();
+ *
+ * filter = g_ptr_array_new ();
+ * map = tp_asv_new (
+ *       TP_IFACE_CHANNEL ".ChannelType", G_TYPE_STRING,
+ *           TP_IFACE_CHANNEL_TYPE_DBUS_TUBE,
+ *       TP_IFACE_CHANNEL ".TargetHandleType", G_TYPE_UINT,
+ *           TP_HANDLE_TYPE_ROOM,
+ *       TP_IFACE_CHANNEL ".Requested", G_TYPE_BOOLEAN,
+ *           FALSE,
+ *       TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName", G_TYPE_STRING,
+ *           SERVICE_NAME,
+ *       NULL
+ *     );
+ *  g_ptr_array_add (filter, map);
+ *
+ * handler = tp_handler_new (filter, FALSE, handle_channels);
+ *
+ * g_assert (tp_dbus_daemon_request_name (tpdbus,
+ *     TP_CLIENT_BUS_NAME_BASE CLIENT_NAME,
+ *     TRUE, NULL));
+ * dbus_g_connection_register_g_object (dbus,
+ *     TP_CLIENT_OBJECT_PATH_BASE CLIENT_NAME,
+ *     G_OBJECT (handler));
+ * </programlisting></example>
+ */
+
+G_DEFINE_TYPE_WITH_CODE (TpHandler, tp_handler, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+      tp_dbus_properties_mixin_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT, NULL);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT_HANDLER, handler_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT_INTERFACE_REQUESTS, requests_iface_init);
+    );
+
+static const char *client_interfaces[] = {
+    TP_IFACE_CLIENT_HANDLER,
+    TP_IFACE_CLIENT_INTERFACE_REQUESTS,
+    NULL
+};
+
+enum /* properties */
+{
+  PROP_0,
+  PROP_INTERFACES,
+  PROP_CHANNEL_FILTER,
+  PROP_BYPASS_APPROVAL,
+  PROP_HANDLED_CHANNELS,
+  PROP_HANDLE_CHANNELS_CB
+};
+
+enum /* signals */
+{
+  ADD_REQUEST,
+  REMOVE_REQUEST,
+  LAST_SIGNAL
+};
+
+static guint tp_handler_signals[LAST_SIGNAL] = { 0, };
+
+typedef struct _TpHandlerPrivate TpHandlerPrivate;
+struct _TpHandlerPrivate
+{
+  GList                     *channels;
+  GHashTable                *requests;
+  GPtrArray                 *channel_filter;
+  gboolean                   bypass_approval;
+  TpHandlerHandleChannelsCb  callback;
+};
+
+typedef struct
+{
+  TpHandler              *self;
+  TpAccount              *account;
+  TpConnection           *connection;
+  TpChannel             **channels;
+  TpChannelRequest      **requests_satisfied;
+  guint64                 user_action_time;
+  GHashTable             *handler_info;
+  DBusGMethodInvocation  *context;
+} HandleChannelsCall;
+
+static TpChannelRequest *
+lookup_channel_request (TpHandler  *self,
+                        const char *request_path,
+                        GHashTable *properties)
+{
+  TpHandlerPrivate *priv = GET_PRIVATE (self);
+  TpChannelRequest *request;
+
+  request = g_hash_table_lookup (priv->requests, request_path);
+
+  if (request == NULL)
+    {
+      TpDBusDaemon *bus;
+      GError *error = NULL;
+
+      /* we need to create the request */
+      DEBUG ("Creating Channel Request\n");
+
+      bus = tp_dbus_daemon_dup (NULL);
+      request = tp_channel_request_new (bus, request_path, properties, &error);
+      if (error != NULL)
+        {
+          g_error ("%s", error->message);
+        }
+
+      g_hash_table_insert (priv->requests, g_strdup (request_path), request);
+      g_object_unref (bus);
+    }
+
+  return g_object_ref (request);
+}
+
+static void
+handle_channels_call_maybe (HandleChannelsCall *call)
+{
+  TpHandlerPrivate *priv = GET_PRIVATE (call->self);
+
+  /* if all of our D-Bus objects are ready, call the callback */
+  if (!tp_account_is_prepared (call->account, TP_ACCOUNT_FEATURE_CORE) ||
+      !tp_connection_is_ready (call->connection))
+    {
+      return;
+    }
+
+    {
+      TpChannel **ptr;
+
+      for (ptr = call->channels; *ptr; ptr++)
+        {
+          if (!tp_channel_is_ready (*ptr))
+            {
+              return;
+            }
+        }
+    }
+
+  DEBUG ("Ready to make callback");
+
+  if ((* priv->callback) (call->self, call->account, call->connection,
+                          call->channels, call->requests_satisfied,
+                          call->user_action_time, call->handler_info))
+    {
+      tp_svc_client_handler_return_from_handle_channels (call->context);
+    }
+  else
+    {
+      GError error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+                       "Handler failed to accept channels" };
+
+      DEBUG ("Callback failed, returning NotAvailable");
+
+      dbus_g_method_return_error (call->context, &error);
+    }
+
+  /* release refs/free mem */
+  g_object_unref (call->account);
+  g_object_unref (call->connection);
+  /* we don't need to unref each channel, because it's still referenced by
+   * priv->channels */
+  g_free (call->channels);
+
+    {
+      TpChannelRequest **ptr;
+
+      for (ptr = call->requests_satisfied; *ptr; ptr++)
+        {
+          /* the request is no longer pending, drop it from the map */
+          g_hash_table_remove (priv->requests, tp_proxy_get_object_path (
+                TP_PROXY (*ptr)));
+
+          g_object_unref (*ptr);
+        }
+    }
+  g_free (call->requests_satisfied);
+
+  g_hash_table_unref (call->handler_info);
+
+  g_slice_free (HandleChannelsCall, call);
+}
+
+static void
+account_ready_cb (GObject      *account,
+                  GAsyncResult *res,
+                  gpointer      user_data)
+{
+  GError *error = NULL;
+
+  tp_account_prepare_finish (TP_ACCOUNT (account), res, &error);
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+
+  DEBUG ("Account ready");
+
+  handle_channels_call_maybe (user_data);
+}
+
+static void
+connection_ready_cb (TpConnection *connection,
+                     const GError *error,
+                     gpointer      user_data)
+{
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+
+  DEBUG ("Connection Ready");
+
+  handle_channels_call_maybe (user_data);
+}
+
+static void
+channel_closed_cb (TpChannel *channel,
+                   gpointer   user_data,
+                   GObject   *self)
+{
+  TpHandlerPrivate *priv = GET_PRIVATE (self);
+
+  DEBUG ("Channel Closed: %s", tp_proxy_get_object_path (channel));
+
+  /* remove this channel from the list of channels we're handling */
+  priv->channels = g_list_remove (priv->channels, channel);
+  g_object_unref (channel);
+}
+
+static void
+channel_ready_cb (TpChannel    *channel,
+                  const GError *error,
+                  gpointer      user_data)
+{
+  HandleChannelsCall *call = user_data;
+  TpHandler *self = TP_HANDLER (call->self);
+  TpHandlerPrivate *priv = GET_PRIVATE (self);
+  GError *error2 = NULL;
+
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+
+  DEBUG ("Channel Ready: %s", tp_proxy_get_object_path (channel));
+
+  /* put this channel into the list of channels we're handling */
+  priv->channels = g_list_prepend (priv->channels, channel);
+  tp_cli_channel_connect_to_closed (channel, channel_closed_cb,
+      NULL, NULL, G_OBJECT (self), &error2);
+  if (error2 != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+
+  handle_channels_call_maybe (call);
+}
+
+static void
+tp_handler_handle_channels (TpSvcClientHandler   *self,
+                            const char            *account_path,
+                            const char            *connection_path,
+                            const GPtrArray       *channels,
+                            const GPtrArray       *requests_satisfied,
+                            guint64                user_action_time,
+                            GHashTable            *handler_info,
+                            DBusGMethodInvocation *context)
+{
+  TpDBusDaemon *bus;
+  HandleChannelsCall *call;
+  GError *error = NULL;
+  guint i;
+
+  DEBUG ("HandleChannels called");
+
+  call = g_slice_new0 (HandleChannelsCall);
+  call->self = TP_HANDLER (self);
+
+  bus = tp_dbus_daemon_dup (&error);
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+
+  call->account = tp_account_new (bus, account_path, &error);
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+  tp_account_prepare_async (call->account, NULL, account_ready_cb, call);
+
+  call->connection = tp_connection_new (bus, NULL, connection_path, &error);
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+  tp_connection_call_when_ready (call->connection, connection_ready_cb, call);
+
+  call->channels = g_new0 (TpChannel *, channels->len + 1);
+  for (i = 0; i < channels->len; i++)
+    {
+      GValueArray *array = g_ptr_array_index (channels, i);
+      const char *channel_path = g_value_get_boxed (
+          g_value_array_get_nth (array, 0));
+      GHashTable *map = g_value_get_boxed (
+          g_value_array_get_nth (array, 1));
+
+      call->channels[i] = tp_channel_new_from_properties (call->connection,
+          channel_path, map, &error);
+      if (error != NULL)
+        {
+          g_error ("%s", error->message);
+        }
+      tp_channel_call_when_ready (call->channels[i], channel_ready_cb, call);
+    }
+
+  call->requests_satisfied = g_new0 (TpChannelRequest *,
+      requests_satisfied->len + 1);
+  for (i = 0; i < requests_satisfied->len; i++)
+    {
+      const char *request_path = g_ptr_array_index (requests_satisfied, i);
+
+      call->requests_satisfied[i] = lookup_channel_request (TP_HANDLER (self),
+          request_path, NULL);
+    }
+
+  call->user_action_time = user_action_time;
+  call->handler_info = g_hash_table_ref (handler_info);
+  call->context = context;
+
+  g_object_unref (bus);
+}
+
+static void
+tp_handler_add_request (TpSvcClientInterfaceRequests *self,
+                        const char                   *request_path,
+                        GHashTable                   *properties,
+                        DBusGMethodInvocation        *context)
+{
+  TpChannelRequest *request;
+
+  DEBUG ("AddRequest called: %s", request_path);
+
+  request = lookup_channel_request (TP_HANDLER (self),
+      request_path, properties);
+
+  g_signal_emit (self, tp_handler_signals[ADD_REQUEST], 0, request, properties);
+  tp_svc_client_interface_requests_return_from_add_request (context);
+
+  g_object_unref (request);
+}
+
+static void
+tp_handler_remove_request (TpSvcClientInterfaceRequests *self,
+                           const char                   *request_path,
+                           const char                   *error_name,
+                           const char                   *message,
+                           DBusGMethodInvocation        *context)
+{
+  TpHandlerPrivate *priv = GET_PRIVATE (self);
+  TpChannelRequest *request;
+
+  DEBUG ("RemoveRequest called: %s", request_path);
+
+  request = lookup_channel_request (TP_HANDLER (self), request_path, NULL);
+  /* the request is no longer pending, drop it from the map */
+  g_hash_table_remove (priv->requests, request_path);
+
+  g_signal_emit (self, tp_handler_signals[REMOVE_REQUEST], 0, request,
+      error_name, message);
+  tp_svc_client_interface_requests_return_from_remove_request (context);
+
+  g_object_unref (request);
+}
+
+static void
+tp_handler_get_property (GObject    *self,
+                         guint       property_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+  TpHandlerPrivate *priv = GET_PRIVATE (self);
+
+  switch (property_id)
+    {
+      case PROP_INTERFACES:
+        g_value_set_boxed (value, client_interfaces);
+        break;
+
+      case PROP_CHANNEL_FILTER:
+        g_value_set_boxed (value, priv->channel_filter);
+        break;
+
+      case PROP_BYPASS_APPROVAL:
+        g_value_set_boolean (value, priv->bypass_approval);
+        break;
+
+      case PROP_HANDLED_CHANNELS:
+        /* the Telepathy spec says that HandledChannels should report the
+         * union of all Handlers sharing a unique name, but we are deciding to
+         * ignore this, because it's a pain in the neck to implement correctly
+         * (how do you deal with people not using TpHandler, or how do you
+         * deal with people not even using tp-glib).
+         *
+         * This is filed as bug
+         * https://bugs.freedesktop.org/show_bug.cgi?id=25286 */
+          {
+            GPtrArray *array = g_ptr_array_new ();
+            GList *ptr;
+
+            for (ptr = priv->channels; ptr; ptr = ptr->next)
+              {
+                g_ptr_array_add (array,
+                    g_strdup (tp_proxy_get_object_path (TP_PROXY (ptr->data))));
+              }
+
+            g_value_take_boxed (value, array);
+          }
+
+        break;
+
+      case PROP_HANDLE_CHANNELS_CB:
+        g_value_set_pointer (value, priv->callback);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
+        break;
+    }
+}
+
+static void
+tp_handler_set_property (GObject      *self,
+                         guint         property_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  TpHandlerPrivate *priv = GET_PRIVATE (self);
+
+  switch (property_id)
+    {
+      case PROP_CHANNEL_FILTER:
+        priv->channel_filter = g_value_dup_boxed (value);
+        break;
+
+      case PROP_BYPASS_APPROVAL:
+        priv->bypass_approval = g_value_get_boolean (value);
+        break;
+
+      case PROP_HANDLE_CHANNELS_CB:
+        priv->callback = g_value_get_pointer (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
+        break;
+    }
+}
+
+static void
+tp_handler_dispose (GObject *self)
+{
+  TpHandlerPrivate *priv = GET_PRIVATE (self);
+  GList *ptr;
+  guint i;
+
+  for (ptr = priv->channels; ptr; ptr = ptr->next)
+    {
+      g_object_unref (ptr->data);
+    }
+  g_list_free (priv->channels);
+  priv->channels = NULL;
+
+  if (priv->requests)
+    {
+      g_hash_table_destroy (priv->requests);
+      priv->requests = NULL;
+    }
+
+  /* free the filter we dupped */
+  for (i = 0; i < priv->channel_filter->len; i++)
+    {
+      g_hash_table_destroy (g_ptr_array_index (priv->channel_filter, i));
+    }
+  g_ptr_array_free (priv->channel_filter, TRUE);
+  priv->channel_filter = NULL;
+
+  G_OBJECT_CLASS (tp_handler_parent_class)->dispose (self);
+}
+
+static void
+tp_handler_class_init (TpHandlerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  static TpDBusPropertiesMixinPropImpl client_props[] = {
+        { "Interfaces", "interfaces", NULL },
+        { NULL }
+  };
+
+  static TpDBusPropertiesMixinPropImpl client_handler_props[] = {
+        { "HandlerChannelFilter", "channel-filter", NULL },
+        { "BypassApproval", "bypass-approval", NULL },
+        { "HandledChannels", "handled-channels", NULL },
+        { NULL }
+  };
+
+  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+        { TP_IFACE_CLIENT,
+          tp_dbus_properties_mixin_getter_gobject_properties,
+          NULL,
+          client_props
+        },
+        { TP_IFACE_CLIENT_HANDLER,
+          tp_dbus_properties_mixin_getter_gobject_properties,
+          NULL,
+          client_handler_props
+        },
+        { NULL }
+  };
+
+  object_class->get_property = tp_handler_get_property;
+  object_class->set_property = tp_handler_set_property;
+  object_class->dispose      = tp_handler_dispose;
+
+  g_object_class_install_property (object_class, PROP_INTERFACES,
+      g_param_spec_boxed ("interfaces",
+                          "Interfaces",
+                          "Available D-Bus Interfaces",
+                          G_TYPE_STRV,
+                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * TpHandler:channel-filter
+   *
+   * Filter for channels we handle, matches the HandlerChannelFilter property.
+   * A #GPtrArray of a{sv} #GHashTable maps for the types of channels that
+   * can be dispatched to this client.
+   *
+   * <example><programlisting>
+   * GPtrArray *filter;
+   * GHashTable *map;
+   *
+   * filter = g_ptr_array_new ();
+   * map = tp_asv_new (
+   *       TP_IFACE_CHANNEL ".ChannelType", G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE,
+   *       TP_IFACE_CHANNEL ".TargetHandleType", G_TYPE_UINT, TP_HANDLE_TYPE_ROOM,
+   *       TP_IFACE_CHANNEL ".Requested", G_TYPE_BOOLEAN, FALSE,
+   *       TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName", G_TYPE_STRING, SERVICE_NAME,
+   *       NULL
+   *     );
+   *  g_ptr_array_add (filter, map);
+   * </programlisting></example>
+   */
+  g_object_class_install_property (object_class, PROP_CHANNEL_FILTER,
+      g_param_spec_boxed ("channel-filter",
+                          "Channel Filter",
+                          "Filter for channels we handle",
+                          TP_ARRAY_TYPE_CHANNEL_CLASS_LIST,
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class, PROP_BYPASS_APPROVAL,
+      g_param_spec_boolean ("bypass-approval",
+                            "Bypass Approval",
+                            "Whether or not this Client should bypass approval",
+                            FALSE,
+                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class, PROP_HANDLED_CHANNELS,
+      g_param_spec_boxed ("handled-channels",
+                          "Handled Channels",
+                          "List of channels we're handling",
+                          TP_ARRAY_TYPE_OBJECT_PATH_LIST,
+                          G_PARAM_READABLE));
+
+  g_object_class_install_property (object_class, PROP_HANDLE_CHANNELS_CB,
+      g_param_spec_pointer ("handle-channels-cb",
+                            "Handle Channels Callback",
+                            "Callback to pass HandleChannels to",
+                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  /**
+   * TpHandler::add-request:
+   * @self: the handler
+   * @request: the incoming request
+   * @properties: immutable properties for the request (an a{sv} map)
+   *
+   * Emitted in response to the AddRequest call being made on this Handler
+   * by the Channel Dispatcher. The AddRequest method is used by the Channel
+   * Dispatcher to indicate a request that you <emphasis>may</emphasis> be
+   * asked to handle, but this isn't guaranteed. This signal is provided so
+   * that your user interface can provide some pending notification, etc.
+   *
+   * If you are asked to handle the channels, @request will be passed to your
+   * callback as a satisfied request. If another Handler ends up handling the
+   * channels, or the request dies for some reason, @request will be passed in
+   * TpHandler::remove-request.
+   */
+  tp_handler_signals[ADD_REQUEST] = g_signal_new ("add-request",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (TpHandlerClass, add_request),
+      NULL, NULL,
+      _vinagre_marshal_VOID__OBJECT_BOXED,
+      G_TYPE_NONE, 2,
+      TP_TYPE_CHANNEL_REQUEST, TP_HASH_TYPE_QUALIFIED_PROPERTY_VALUE_MAP);
+
+  /**
+   * TpHandler::remove-request:
+   * @self: the handler
+   * @request: the removed request
+   * @error: the D-Bus name of an error, why this request was lost
+   * @message: a more informative message
+   *
+   * Emitted in response to the RemoveRequest call being made on this Handler
+   * by the Channel Dispatcher. The RemoveRequest method is used by the
+   * Channel Dispatcher to indicate a request that you were previously
+   * notified about through TpHandler::add-request.
+   *
+   * @error gives the name of a D-Bus error for why the request was lost. The
+   * error <literal>org.freedesktop.Telepathy.Error.NotYours</literal> means
+   * that the channels were given to another handler.
+   */
+  tp_handler_signals[REMOVE_REQUEST] = g_signal_new ("remove-request",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (TpHandlerClass, remove_request),
+      NULL, NULL,
+      _vinagre_marshal_VOID__OBJECT_BOXED,
+      G_TYPE_NONE, 3,
+      TP_TYPE_CHANNEL_REQUEST, G_TYPE_STRING, G_TYPE_STRING);
+
+  /* call our mixin class init */
+  klass->dbus_props_class.interfaces = prop_interfaces;
+  tp_dbus_properties_mixin_class_init (object_class,
+      G_STRUCT_OFFSET (TpHandlerClass, dbus_props_class));
+
+  g_type_class_add_private (klass, sizeof (TpHandlerPrivate));
+}
+
+static void
+tp_handler_init (TpHandler *self)
+{
+  TpHandlerPrivate *priv = GET_PRIVATE (self);
+
+  priv->requests = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                          g_free, g_object_unref);
+}
+
+static void
+handler_iface_init (gpointer g_iface, gpointer iface_data)
+{
+  TpSvcClientHandlerClass *klass = (TpSvcClientHandlerClass *) g_iface;
+
+#define IMPLEMENT(x) tp_svc_client_handler_implement_##x (klass, \
+    tp_handler_##x)
+  IMPLEMENT (handle_channels);
+#undef IMPLEMENT
+}
+
+static void
+requests_iface_init (gpointer g_iface, gpointer iface_data)
+{
+  TpSvcClientInterfaceRequestsClass *klass = g_iface;
+
+#define IMPLEMENT(x) tp_svc_client_interface_requests_implement_##x (klass, \
+    tp_handler_##x)
+  IMPLEMENT (add_request);
+  IMPLEMENT (remove_request);
+#undef IMPLEMENT
+}
+
+/**
+ * tp_handler_new:
+ * @channel_filter: a #GPtrArray of #GHashTable a{sv} maps defining
+ * HandleChannelFilter
+ * @bypass_approval: whether or not this Handler bypasses any Approvers
+ * @handle_channels_cb: the function to call to handle dispatched channels
+ *
+ * Creates a new Client.Handler object that can be published on the session bus
+ * with dbus-glib. The parameters @channel_filter and @bypass_approval are set
+ * when the object is published and cannot be changed afterwards.
+ *
+ * For further information consult the <link url="http://telepathy.freedesktop.org/spec/org.freedesktop.Telepathy.Client.Handler.html";>Telepathy spec</link>.
+ *
+ * Returns: a #TpHandler ready to be published on the session bus.
+ */
+TpHandler *
+tp_handler_new (GPtrArray                 *channel_filter,
+                gboolean                   bypass_approval,
+                TpHandlerHandleChannelsCb  handle_channels_cb)
+{
+  g_return_val_if_fail (channel_filter != NULL, NULL);
+  g_return_val_if_fail (handle_channels_cb != NULL, NULL);
+
+  return g_object_new (TP_TYPE_HANDLER,
+      "channel-filter", channel_filter,
+      "bypass-approval", bypass_approval,
+      "handle-channels-cb", handle_channels_cb,
+      NULL);
+}
+
+/**
+ * tp_handler_get_pending_requests:
+ * @self: the handler
+ *
+ * Retrieves a list of all pending #TpChannelRequest objects for this handler.
+ * The addition of channel requests is notified via TpHandler::add-request and
+ * resolved by TpHandler::remove-request and the TpHandler:handle-channels-cb
+ * callback.
+ *
+ * Returns: a #GList of #TpChannelRequest objects, owned by the Handler, do
+ * not unreference. Free list with g_list_free() when done.
+ */
+GList *
+tp_handler_get_pending_requests (TpHandler *self)
+{
+  TpHandlerPrivate *priv;
+
+  g_return_val_if_fail (TP_IS_HANDLER (self), NULL);
+
+  priv = GET_PRIVATE (self);
+
+  return g_hash_table_get_values (priv->requests);
+}
diff --git a/vinagre/handler.h b/vinagre/handler.h
new file mode 100644
index 0000000..65f121b
--- /dev/null
+++ b/vinagre/handler.h
@@ -0,0 +1,128 @@
+/*
+ * handler.h - convenience class to implement a Telepathy Handler
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.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
+ */
+
+#ifndef __TP_HANDLER_H__
+#define __TP_HANDLER_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/account.h>
+#include <telepathy-glib/connection.h>
+#include <telepathy-glib/channel.h>
+#include <telepathy-glib/channel-request.h>
+#include <telepathy-glib/dbus-properties-mixin.h>
+
+G_BEGIN_DECLS
+
+#define TP_TYPE_HANDLER	(tp_handler_get_type ())
+#define TP_HANDLER(obj)	(G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TYPE_HANDLER, TpHandler))
+#define TP_HANDLER_CLASS(obj)	(G_TYPE_CHECK_CLASS_CAST ((obj), TP_TYPE_HANDLER, TpHandlerClass))
+#define TP_IS_HANDLER(obj)	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TYPE_HANDLER))
+#define TP_IS_HANDLER_CLASS(obj)	(G_TYPE_CHECK_CLASS_TYPE ((obj), TP_TYPE_HANDLER))
+#define TP_HANDLER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TYPE_HANDLER, TpHandlerClass))
+
+typedef struct _TpHandler TpHandler;
+struct _TpHandler
+{
+  GObject parent;
+};
+
+typedef struct _TpHandlerClass TpHandlerClass;
+struct _TpHandlerClass
+{
+  GObjectClass parent_class;
+  TpDBusPropertiesMixinClass dbus_props_class;
+
+  void (* add_request) (TpHandler        *self,
+                        TpChannelRequest *request,
+                        GHashTable       *properties);
+  void (* remove_request) (TpHandler        *self,
+                           TpChannelRequest *request,
+                           const char       *error,
+                           const char       *message);
+
+  gpointer _padding[8];
+};
+
+/**
+ * TpHandlerHandleChannelsCb:
+ * @self: the handler
+ * @account: the Account with which the channels are associated
+ * @connection: the Connection with which the channels are associated
+ * @channels: a NULL-terminated list of channels to handle
+ * @requests_satisfied: the ChannelRequests that handling this request satisfies
+ * @user_action_time: the time at which user action occurred, used for
+ * focus-stealing prevention
+ * @handler_info: an a{sv} map of additional handler information
+ *
+ * This callback will be called whenever channels are dispatched to your
+ * Handler for handling.
+ *
+ * <example><programlisting>
+ * static void
+ * handle_channels (TpHandler         *self,
+ *                  TpAccount         *account,
+ *                  TpConnection      *connection,
+ *                  TpChannel        **channels,
+ *                  TpChannelRequest **requests,
+ *                  guint64            user_action_time,
+ *                  GHashTable        *handler_info)
+ * {
+ *   g_print ("handle channels\n");
+ *   g_print ("  account = %p: %s\n", account,
+ *       tp_proxy_get_object_path (TP_PROXY (account)));
+ *   g_print ("  connection = %p: %s\n", connection,
+ *       tp_proxy_get_object_path (TP_PROXY (connection)));
+ *
+ *     {
+ *       TpChannel **ptr;
+ *
+ *       for (ptr = channels; *ptr; ptr++)
+ *         {
+ *           TpChannel *channel = *ptr;
+ *
+ *           g_print ("  channel = %p: %s\n", channel,
+ *               tp_proxy_get_object_path (TP_PROXY (channel)));
+ *
+ *         }
+ *     }
+ * }
+ * </programlisting></example>
+ *
+ * Returns: TRUE if the Handler success, FALSE to return a NotAvailable to the
+ * Channel Dispatcher
+ */
+typedef gboolean (* TpHandlerHandleChannelsCb) (TpHandler         *self,
+                                                TpAccount         *account,
+                                                TpConnection      *connection,
+                                                TpChannel        **channels,
+                                                TpChannelRequest **request_satisfied,
+                                                guint64            user_action_time,
+                                                GHashTable        *handler_info);
+
+GType tp_handler_get_type (void);
+TpHandler *tp_handler_new (GPtrArray                 *channel_filter,
+                           gboolean                   bypass_approval,
+                           TpHandlerHandleChannelsCb  handle_channels_cb);
+GList *tp_handler_get_pending_requests (TpHandler *self);
+
+G_END_DECLS
+
+#endif
diff --git a/vinagre/vinagre-tubes-manager.h b/vinagre/vinagre-tubes-manager.h
index bb231a2..dc52658 100644
--- a/vinagre/vinagre-tubes-manager.h
+++ b/vinagre/vinagre-tubes-manager.h
@@ -27,7 +27,7 @@
 
 #include <glib-object.h>
 
-#include <telepathy-glib/handler.h>
+#include "handler.h"
 
 #include "vinagre-window.h"
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]