From 391bad3cd5545b504fd69563b3bb598320c4957d Mon Sep 17 00:00:00 2001 From: Emilio Pozuelo Monfort Date: Mon, 18 Jul 2011 16:28:36 +0100 Subject: CallFactory: make it a TpBaseClient subclass So that we can make it both a handler and an observer at the same time. https://bugzilla.gnome.org/show_bug.cgi?id=580794 --- src/empathy-call-factory.c | 106 +++++++++++++++------------------------------ src/empathy-call-factory.h | 5 +-- 2 files changed, 38 insertions(+), 73 deletions(-) diff --git a/src/empathy-call-factory.c b/src/empathy-call-factory.c index 9f3fe16ec..a2b4dc0fa 100644 --- a/src/empathy-call-factory.c +++ b/src/empathy-call-factory.c @@ -29,6 +29,7 @@ #include +#include #include #include #include @@ -40,16 +41,15 @@ #define DEBUG_FLAG EMPATHY_DEBUG_VOIP #include -G_DEFINE_TYPE(EmpathyCallFactory, empathy_call_factory, G_TYPE_OBJECT) +G_DEFINE_TYPE(EmpathyCallFactory, empathy_call_factory, TP_TYPE_BASE_CLIENT) -static void handle_channels_cb (TpSimpleHandler *handler, +static void handle_channels (TpBaseClient *client, TpAccount *account, TpConnection *connection, GList *channels, GList *requests_satisfied, gint64 user_action_time, - TpHandleChannelsContext *context, - gpointer user_data); + TpHandleChannelsContext *context); /* signal enum */ enum @@ -60,38 +60,21 @@ enum static guint signals[LAST_SIGNAL] = {0}; -/* private structure */ -typedef struct { - TpBaseClient *handler; - gboolean dispose_has_run; -} EmpathyCallFactoryPriv; - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyCallFactory) - static GObject *call_factory = NULL; static void empathy_call_factory_init (EmpathyCallFactory *obj) { - EmpathyCallFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (obj, - EMPATHY_TYPE_CALL_FACTORY, EmpathyCallFactoryPriv); - TpAccountManager *am; + TpBaseClient *client = (TpBaseClient *) obj; - obj->priv = priv; - - am = tp_account_manager_dup (); - - priv->handler = tp_simple_handler_new_with_am (am, FALSE, FALSE, - EMPATHY_CALL_BUS_NAME_SUFFIX, FALSE, handle_channels_cb, obj, NULL); - - tp_base_client_take_handler_filter (priv->handler, tp_asv_new ( + tp_base_client_take_handler_filter (client, tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TPY_IFACE_CHANNEL_TYPE_CALL, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, NULL)); - tp_base_client_take_handler_filter (priv->handler, tp_asv_new ( + tp_base_client_take_handler_filter (client, tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TPY_IFACE_CHANNEL_TYPE_CALL, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, @@ -99,7 +82,7 @@ empathy_call_factory_init (EmpathyCallFactory *obj) TPY_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, G_TYPE_BOOLEAN, TRUE, NULL)); - tp_base_client_take_handler_filter (priv->handler, tp_asv_new ( + tp_base_client_take_handler_filter (client, tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TPY_IFACE_CHANNEL_TYPE_CALL, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, @@ -107,13 +90,11 @@ empathy_call_factory_init (EmpathyCallFactory *obj) TPY_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, G_TYPE_BOOLEAN, TRUE, NULL)); - tp_base_client_add_handler_capabilities_varargs (priv->handler, + tp_base_client_add_handler_capabilities_varargs (client, "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/ice-udp", "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/gtalk-p2p", "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/video/h264", NULL); - - g_object_unref (am); } static GObject * @@ -130,46 +111,18 @@ empathy_call_factory_constructor (GType type, guint n_construct_params, } static void -empathy_call_factory_finalize (GObject *object) +empathy_call_factory_class_init (EmpathyCallFactoryClass *klass) { - /* free any data held directly by the object here */ - - if (G_OBJECT_CLASS (empathy_call_factory_parent_class)->finalize) - G_OBJECT_CLASS (empathy_call_factory_parent_class)->finalize (object); -} - -static void -empathy_call_factory_dispose (GObject *object) -{ - EmpathyCallFactoryPriv *priv = GET_PRIV (object); - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - tp_clear_object (&priv->handler); - - if (G_OBJECT_CLASS (empathy_call_factory_parent_class)->dispose) - G_OBJECT_CLASS (empathy_call_factory_parent_class)->dispose (object); -} - -static void -empathy_call_factory_class_init ( - EmpathyCallFactoryClass *empathy_call_factory_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (empathy_call_factory_class); - - g_type_class_add_private (empathy_call_factory_class, - sizeof (EmpathyCallFactoryPriv)); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + TpBaseClientClass *base_clt_cls = TP_BASE_CLIENT_CLASS (klass); object_class->constructor = empathy_call_factory_constructor; - object_class->dispose = empathy_call_factory_dispose; - object_class->finalize = empathy_call_factory_finalize; + + base_clt_cls->handle_channels = handle_channels; signals[NEW_CALL_HANDLER] = g_signal_new ("new-call-handler", - G_TYPE_FROM_CLASS (empathy_call_factory_class), + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _src_marshal_VOID__OBJECT_BOOLEAN, @@ -180,9 +133,25 @@ empathy_call_factory_class_init ( EmpathyCallFactory * empathy_call_factory_initialise (void) { + EmpathyCallFactory *self; + EmpathyClientFactory *factory; + TpAccountManager *am; + g_return_val_if_fail (call_factory == NULL, NULL); - return EMPATHY_CALL_FACTORY (g_object_new (EMPATHY_TYPE_CALL_FACTORY, NULL)); + am = tp_account_manager_dup (); + factory = empathy_client_factory_dup (); + + self = EMPATHY_CALL_FACTORY (g_object_new (EMPATHY_TYPE_CALL_FACTORY, + "account-manager", am, + "factory", factory, + "name", EMPATHY_CALL_BUS_NAME_SUFFIX, + NULL)); + + g_object_unref (am); + g_object_unref (factory); + + return self; } EmpathyCallFactory * @@ -254,16 +223,15 @@ call_channel_ready_cb (TpyCallChannel *call, static void -handle_channels_cb (TpSimpleHandler *handler, +handle_channels (TpBaseClient *client, TpAccount *account, TpConnection *connection, GList *channels, GList *requests_satisfied, gint64 user_action_time, - TpHandleChannelsContext *context, - gpointer user_data) + TpHandleChannelsContext *context) { - EmpathyCallFactory *self = user_data; + EmpathyCallFactory *self = EMPATHY_CALL_FACTORY (client); GList *l; for (l = channels; l != NULL; l = g_list_next (l)) @@ -302,7 +270,5 @@ gboolean empathy_call_factory_register (EmpathyCallFactory *self, GError **error) { - EmpathyCallFactoryPriv *priv = GET_PRIV (self); - - return tp_base_client_register (priv->handler, error); + return tp_base_client_register (TP_BASE_CLIENT (self), error); } diff --git a/src/empathy-call-factory.h b/src/empathy-call-factory.h index 0e5276278..174fbf4bd 100644 --- a/src/empathy-call-factory.h +++ b/src/empathy-call-factory.h @@ -29,12 +29,11 @@ typedef struct _EmpathyCallFactory EmpathyCallFactory; typedef struct _EmpathyCallFactoryClass EmpathyCallFactoryClass; struct _EmpathyCallFactoryClass { - GObjectClass parent_class; + TpBaseClientClass parent_class; }; struct _EmpathyCallFactory { - GObject parent; - gpointer priv; + TpBaseClient parent; }; GType empathy_call_factory_get_type (void); -- cgit v1.2.3 From 44731ebba06458462f5c26fed8fd0abab30e7450 Mon Sep 17 00:00:00 2001 From: Emilio Pozuelo Monfort Date: Mon, 18 Jul 2011 17:07:45 +0100 Subject: Make EmpathyCallFactory an approver https://bugzilla.gnome.org/show_bug.cgi?id=580794 --- src/empathy-call-factory.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/empathy-call-factory.c b/src/empathy-call-factory.c index a2b4dc0fa..ba17270c7 100644 --- a/src/empathy-call-factory.c +++ b/src/empathy-call-factory.c @@ -51,10 +51,18 @@ static void handle_channels (TpBaseClient *client, gint64 user_action_time, TpHandleChannelsContext *context); +static void approve_channels (TpBaseClient *client, + TpAccount *account, + TpConnection *connection, + GList *channels, + TpChannelDispatchOperation *dispatch_operation, + TpAddDispatchOperationContext *context); + /* signal enum */ enum { NEW_CALL_HANDLER, + INCOMING_CALL, LAST_SIGNAL }; @@ -67,6 +75,13 @@ empathy_call_factory_init (EmpathyCallFactory *obj) { TpBaseClient *client = (TpBaseClient *) obj; + tp_base_client_take_approver_filter (client, tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, + TPY_IFACE_CHANNEL_TYPE_CALL, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, + G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, + NULL)); + tp_base_client_take_handler_filter (client, tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TPY_IFACE_CHANNEL_TYPE_CALL, @@ -119,6 +134,7 @@ empathy_call_factory_class_init (EmpathyCallFactoryClass *klass) object_class->constructor = empathy_call_factory_constructor; base_clt_cls->handle_channels = handle_channels; + base_clt_cls->add_dispatch_operation = approve_channels; signals[NEW_CALL_HANDLER] = g_signal_new ("new-call-handler", @@ -128,6 +144,17 @@ empathy_call_factory_class_init (EmpathyCallFactoryClass *klass) _src_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, EMPATHY_TYPE_CALL_HANDLER, G_TYPE_BOOLEAN); + + signals[INCOMING_CALL] = + g_signal_new ("incoming-call", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, + NULL, NULL, + _src_marshal_BOOLEAN__UINT_OBJECT_OBJECT_OBJECT, + G_TYPE_BOOLEAN, + 4, G_TYPE_UINT, TPY_TYPE_CALL_CHANNEL, + TP_TYPE_CHANNEL_DISPATCH_OPERATION, + TP_TYPE_ADD_DISPATCH_OPERATION_CONTEXT); } EmpathyCallFactory * @@ -266,6 +293,77 @@ handle_channels (TpBaseClient *client, tp_handle_channels_context_accept (context); } +static TpyCallChannel * +find_call_channel (GList *channels) +{ + GList *l; + + for (l = channels; l != NULL; l = g_list_next (l)) + { + TpChannel *channel = l->data; + GQuark channel_type; + + if (tp_proxy_get_invalidated (channel) != NULL) + continue; + + channel_type = tp_channel_get_channel_type_id (channel); + + if (channel_type == TPY_IFACE_QUARK_CHANNEL_TYPE_CALL) + return TPY_CALL_CHANNEL (channel); + } + + return NULL; +} + +static void +approve_channels (TpBaseClient *client, + TpAccount *account, + TpConnection *connection, + GList *channels, + TpChannelDispatchOperation *dispatch_operation, + TpAddDispatchOperationContext *context) +{ + EmpathyCallFactory *self = EMPATHY_CALL_FACTORY (client); + TpyCallChannel *channel; + guint handle; + GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "" }; + gboolean handled = FALSE; + + channel = find_call_channel (channels); + + if (channel == NULL) + { + DEBUG ("Failed to find the main channel; ignoring"); + error.message = "Unknown channel"; + goto out; + } + + handle = tp_channel_get_handle (TP_CHANNEL (channel), NULL); + + if (handle == 0) + { + DEBUG ("Unknown handle, ignoring"); + error.code = TP_ERROR_INVALID_HANDLE; + error.message = "Unknown handle"; + goto out; + } + + g_signal_emit (self, signals[INCOMING_CALL], 0, + handle, channel, dispatch_operation, context, + &handled); + + if (handled) + return; + + /* There was no call window so the context wasn't handled. */ + DEBUG ("Call with a contact for which there's no existing " + "call window, ignoring"); + error.message = "No call window with this contact"; + + out: + tp_add_dispatch_operation_context_fail (context, &error); +} + gboolean empathy_call_factory_register (EmpathyCallFactory *self, GError **error) -- cgit v1.2.3 From d5136f90339362d53d780700808dc055fc0a7121 Mon Sep 17 00:00:00 2001 From: Emilio Pozuelo Monfort Date: Fri, 8 Jul 2011 12:46:33 +0100 Subject: Reuse Call windows when possible If we have a call window opened for a contact and we get an incoming call from the same person, use the existing window instead of creating another one. Based on a patch from Jonathan Tellier. https://bugzilla.gnome.org/show_bug.cgi?id=580794 --- src/empathy-call-window.c | 47 +++++++++++++++++++++++++++++++++++------------ src/empathy-call-window.h | 6 ++++++ src/empathy-call.c | 43 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index ccec9f628..af06b6251 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -293,6 +293,8 @@ static gboolean empathy_call_window_video_output_motion_notify ( static void empathy_call_window_video_menu_popup (EmpathyCallWindow *window, guint button); +static void empathy_call_window_connect_handler (EmpathyCallWindow *self); + static void empathy_call_window_dialpad_cb (GtkToggleToolButton *button, EmpathyCallWindow *window); @@ -2199,6 +2201,20 @@ empathy_call_window_new (EmpathyCallHandler *handler) g_object_new (EMPATHY_TYPE_CALL_WINDOW, "handler", handler, NULL)); } +void +empathy_call_window_present (EmpathyCallWindow *self, + EmpathyCallHandler *handler) +{ + g_return_if_fail (EMPATHY_IS_CALL_HANDLER (handler)); + + tp_clear_object (&self->priv->handler); + self->priv->handler = g_object_ref (handler); + empathy_call_window_connect_handler (self); + + empathy_window_present (GTK_WINDOW (self)); + empathy_call_window_restart_call (self); +} + static void empathy_call_window_conference_added_cb (EmpathyCallHandler *handler, GstElement *conference, gpointer user_data) @@ -3272,9 +3288,9 @@ call_handler_notify_call_cb (EmpathyCallHandler *handler, } static void -empathy_call_window_realized_cb (GtkWidget *widget, EmpathyCallWindow *window) +empathy_call_window_connect_handler (EmpathyCallWindow *self) { - EmpathyCallWindowPriv *priv = GET_PRIV (window); + EmpathyCallWindowPriv *priv = GET_PRIV (self); TpyCallChannel *call; gint width; @@ -3283,24 +3299,24 @@ empathy_call_window_realized_cb (GtkWidget *widget, EmpathyCallWindow *window) gtk_widget_set_size_request (priv->hangup_button, width * 2, -1); g_signal_connect (priv->handler, "state-changed", - G_CALLBACK (empathy_call_window_state_changed_cb), window); + G_CALLBACK (empathy_call_window_state_changed_cb), self); g_signal_connect (priv->handler, "conference-added", - G_CALLBACK (empathy_call_window_conference_added_cb), window); + G_CALLBACK (empathy_call_window_conference_added_cb), self); g_signal_connect (priv->handler, "conference-removed", - G_CALLBACK (empathy_call_window_conference_removed_cb), window); + G_CALLBACK (empathy_call_window_conference_removed_cb), self); g_signal_connect (priv->handler, "closed", - G_CALLBACK (empathy_call_window_channel_closed_cb), window); + G_CALLBACK (empathy_call_window_channel_closed_cb), self); g_signal_connect (priv->handler, "src-pad-added", - G_CALLBACK (empathy_call_window_src_added_cb), window); + G_CALLBACK (empathy_call_window_src_added_cb), self); g_signal_connect (priv->handler, "sink-pad-added", - G_CALLBACK (empathy_call_window_sink_added_cb), window); + G_CALLBACK (empathy_call_window_sink_added_cb), self); g_signal_connect (priv->handler, "sink-pad-removed", - G_CALLBACK (empathy_call_window_sink_removed_cb), window); + G_CALLBACK (empathy_call_window_sink_removed_cb), self); g_object_get (priv->handler, "call-channel", &call, NULL); if (call != NULL) { - call_handler_notify_call_cb (priv->handler, NULL, window); + call_handler_notify_call_cb (priv->handler, NULL, self); g_object_unref (call); } else @@ -3308,10 +3324,17 @@ empathy_call_window_realized_cb (GtkWidget *widget, EmpathyCallWindow *window) /* call-channel doesn't exist yet, we'll connect signals once it has been * set */ g_signal_connect (priv->handler, "notify::call-channel", - G_CALLBACK (call_handler_notify_call_cb), window); + G_CALLBACK (call_handler_notify_call_cb), self); } +} + +static void +empathy_call_window_realized_cb (GtkWidget *widget, + EmpathyCallWindow *self) +{ + empathy_call_window_connect_handler (self); - gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + gst_element_set_state (self->priv->pipeline, GST_STATE_PAUSED); } static gboolean diff --git a/src/empathy-call-window.h b/src/empathy-call-window.h index eebb55f69..81cf170ae 100644 --- a/src/empathy-call-window.h +++ b/src/empathy-call-window.h @@ -63,6 +63,12 @@ GType empathy_call_window_get_type (void); EmpathyCallWindowClass)) EmpathyCallWindow *empathy_call_window_new (EmpathyCallHandler *handler); +void empathy_call_window_present (EmpathyCallWindow *window, + EmpathyCallHandler *handler); +void empathy_call_window_start_ringing (EmpathyCallWindow *self, + TpyCallChannel *channel, + TpChannelDispatchOperation *dispatch_operation, + TpAddDispatchOperationContext *context); GtkUIManager *empathy_call_window_get_ui_manager (EmpathyCallWindow *window); diff --git a/src/empathy-call.c b/src/empathy-call.c index 1f60217db..a5e463ba3 100644 --- a/src/empathy-call.c +++ b/src/empathy-call.c @@ -34,6 +34,8 @@ #include +#include + #include #include "empathy-call-window.h" @@ -55,6 +57,19 @@ static gboolean use_timer = TRUE; static EmpathyCallFactory *call_factory = NULL; +/* An EmpathyContact -> EmpathyCallWindow hash table for all existing + * Call windows. We own a ref on the EmpathyContacts. */ +static GHashTable *call_windows; + +static void +call_window_destroyed_cb (GtkWidget *window, + EmpathyContact *contact) +{ + g_hash_table_remove (call_windows, contact); + + g_application_release (G_APPLICATION (app)); +} + static void new_call_handler_cb (EmpathyCallFactory *factory, EmpathyCallHandler *handler, @@ -62,17 +77,29 @@ new_call_handler_cb (EmpathyCallFactory *factory, gpointer user_data) { EmpathyCallWindow *window; + EmpathyContact *contact; - DEBUG ("Create a new call window"); + DEBUG ("Show the call window"); - window = empathy_call_window_new (handler); + g_object_get (handler, "target-contact", &contact, NULL); - g_application_hold (G_APPLICATION (app)); + window = g_hash_table_lookup (call_windows, contact); + + if (window != NULL) + { + empathy_call_window_present (window, handler); + } + else + { + window = empathy_call_window_new (handler); - g_signal_connect_swapped (window, "destroy", - G_CALLBACK (g_application_release), app); + g_hash_table_insert (call_windows, g_object_ref (contact), window); + g_application_hold (G_APPLICATION (app)); + g_signal_connect (window, "destroy", + G_CALLBACK (call_window_destroyed_cb), contact); - gtk_widget_show (GTK_WIDGET (window)); + gtk_widget_show (GTK_WIDGET (window)); + } } static void @@ -172,6 +199,9 @@ main (int argc, use_timer = FALSE; } + call_windows = g_hash_table_new_full (g_direct_hash, g_direct_equal, + g_object_unref, NULL); + /* the inactivity timeout can only be set while the application is held */ g_application_hold (G_APPLICATION (app)); g_application_set_inactivity_timeout (G_APPLICATION (app), TIMEOUT * 1000); @@ -179,6 +209,7 @@ main (int argc, retval = g_application_run (G_APPLICATION (app), argc, argv); + g_hash_table_unref (call_windows); g_object_unref (app); tp_clear_object (&call_factory); -- cgit v1.2.3 From ee02c5c89132db72e5cd987cd443cd09202b6f5b Mon Sep 17 00:00:00 2001 From: Emilio Pozuelo Monfort Date: Wed, 7 Sep 2011 15:54:29 +0100 Subject: Let the existing call window know about new incoming calls https://bugzilla.gnome.org/show_bug.cgi?id=580794 --- src/empathy-call-window.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++ src/empathy-call.c | 38 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index af06b6251..81bee0596 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -103,6 +104,7 @@ enum { }; typedef enum { + RINGING, CONNECTING, CONNECTED, HELD, @@ -184,6 +186,12 @@ struct _EmpathyCallWindowPriv easilly repack everything when toggling fullscreen */ GtkWidget *content_hbox; + /* These are used to accept or reject an incoming call when the status + is RINGING. */ + TpyCallChannel *pending_channel; + TpChannelDispatchOperation *pending_cdo; + TpAddDispatchOperationContext *pending_context; + gulong video_output_motion_handler_id; guint bus_message_source_id; @@ -1359,6 +1367,60 @@ empathy_call_window_stage_allocation_changed_cb (ClutterActor *stage, FLOATING_TOOLBAR_SPACING - FLOATING_TOOLBAR_HEIGHT); } +static void +empathy_call_window_set_state_ringing (EmpathyCallWindow *self) +{ + g_assert (self->priv->call_state != CONNECTED); + + empathy_call_window_status_message (self, _("Incoming call")); + self->priv->call_state = RINGING; +} + +static void +empathy_call_window_stop_ringing (EmpathyCallWindow *self) +{ + empathy_call_window_status_message (self, _("Disconnected")); + self->priv->call_state = DISCONNECTED; +} + +static void +empathy_call_window_incoming_channel_invalidated_cb (TpProxy *channel, + guint domain, + gint code, + gchar *message, + EmpathyCallWindow *self) +{ + tp_channel_dispatch_operation_destroy_channels_async ( + self->priv->pending_cdo, NULL, NULL); + empathy_call_window_stop_ringing (self); + + tp_clear_object (&self->priv->pending_cdo); + tp_clear_object (&self->priv->pending_channel); + tp_clear_object (&self->priv->pending_context); +} + +void +empathy_call_window_start_ringing (EmpathyCallWindow *self, + TpyCallChannel *channel, + TpChannelDispatchOperation *dispatch_operation, + TpAddDispatchOperationContext *context) +{ + g_assert (self->priv->pending_channel == NULL); + g_assert (self->priv->pending_context == NULL); + g_assert (self->priv->pending_cdo == NULL); + + /* Start ringing and delay until the user answers or hangs. */ + self->priv->pending_channel = g_object_ref (channel); + self->priv->pending_context = g_object_ref (context); + self->priv->pending_cdo = g_object_ref (dispatch_operation); + + g_signal_connect (self->priv->pending_channel, "invalidated", + G_CALLBACK (empathy_call_window_incoming_channel_invalidated_cb), self); + + empathy_call_window_set_state_ringing (self); + tp_add_dispatch_operation_context_accept (context); +} + static void empathy_call_window_init (EmpathyCallWindow *self) { diff --git a/src/empathy-call.c b/src/empathy-call.c index a5e463ba3..1b643dec1 100644 --- a/src/empathy-call.c +++ b/src/empathy-call.c @@ -70,6 +70,42 @@ call_window_destroyed_cb (GtkWidget *window, g_application_release (G_APPLICATION (app)); } +static gboolean +find_window_for_handle (gpointer key, + gpointer value, + gpointer user_data) +{ + EmpathyContact *contact = key; + guint handle = GPOINTER_TO_UINT (user_data); + + if (handle == empathy_contact_get_handle (contact)) + return TRUE; + + return FALSE; +} + +static gboolean +incoming_call_cb (EmpathyCallFactory *factory, + guint handle, + TpyCallChannel *channel, + TpChannelDispatchOperation *dispatch_operation, + TpAddDispatchOperationContext *context, + gpointer user_data) +{ + EmpathyCallWindow *window = g_hash_table_find (call_windows, + find_window_for_handle, GUINT_TO_POINTER (handle)); + + if (window != NULL) + { + /* The window takes care of accepting or rejecting the context. */ + empathy_call_window_start_ringing (window, + channel, dispatch_operation, context); + return TRUE; + } + + return FALSE; +} + static void new_call_handler_cb (EmpathyCallFactory *factory, EmpathyCallHandler *handler, @@ -123,6 +159,8 @@ activate_cb (GApplication *application) g_signal_connect (G_OBJECT (call_factory), "new-call-handler", G_CALLBACK (new_call_handler_cb), NULL); + g_signal_connect (G_OBJECT (call_factory), "incoming-call", + G_CALLBACK (incoming_call_cb), NULL); if (!empathy_call_factory_register (call_factory, &error)) { -- cgit v1.2.3 From 3f30f0aac8ec4f21acb84e4b5b9afa6acd131b99 Mon Sep 17 00:00:00 2001 From: Emilio Pozuelo Monfort Date: Wed, 7 Sep 2011 13:19:24 +0100 Subject: CallWindow: display a dialog to accept or reject incoming calls https://bugzilla.gnome.org/show_bug.cgi?id=580794 --- src/empathy-call-window.c | 72 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index 81bee0596..c8d17c00e 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -188,6 +188,7 @@ struct _EmpathyCallWindowPriv /* These are used to accept or reject an incoming call when the status is RINGING. */ + GtkWidget *incoming_call_dialog; TpyCallChannel *pending_channel; TpChannelDispatchOperation *pending_cdo; TpAddDispatchOperationContext *pending_context; @@ -1367,36 +1368,81 @@ empathy_call_window_stage_allocation_changed_cb (ClutterActor *stage, FLOATING_TOOLBAR_SPACING - FLOATING_TOOLBAR_HEIGHT); } +static void +empathy_call_window_incoming_call_response_cb (GtkDialog *dialog, + gint response_id, + EmpathyCallWindow *self) +{ + switch (response_id) + { + case GTK_RESPONSE_ACCEPT: + tp_channel_dispatch_operation_handle_with_async ( + self->priv->pending_cdo, EMPATHY_CALL_BUS_NAME, NULL, NULL); + + tp_clear_object (&self->priv->pending_cdo); + tp_clear_object (&self->priv->pending_channel); + tp_clear_object (&self->priv->pending_context); + + break; + case GTK_RESPONSE_CANCEL: + tp_channel_dispatch_operation_close_channels_async ( + self->priv->pending_cdo, NULL, NULL); + + empathy_call_window_status_message (self, _("Disconnected")); + self->priv->call_state = DISCONNECTED; + break; + default: + g_warn_if_reached (); + } +} + static void empathy_call_window_set_state_ringing (EmpathyCallWindow *self) { + gboolean video; + g_assert (self->priv->call_state != CONNECTED); + video = tpy_call_channel_has_initial_video (self->priv->pending_channel); + empathy_call_window_status_message (self, _("Incoming call")); self->priv->call_state = RINGING; -} -static void -empathy_call_window_stop_ringing (EmpathyCallWindow *self) -{ - empathy_call_window_status_message (self, _("Disconnected")); - self->priv->call_state = DISCONNECTED; + self->priv->incoming_call_dialog = gtk_message_dialog_new ( + GTK_WINDOW (self), GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, + video ? _("Incoming video call from %s") : _("Incoming call from %s"), + empathy_contact_get_alias (self->priv->contact)); + + gtk_dialog_add_buttons (GTK_DIALOG (self->priv->incoming_call_dialog), + _("Reject"), GTK_RESPONSE_CANCEL, + _("Answer"), GTK_RESPONSE_ACCEPT, + NULL); + + g_signal_connect (self->priv->incoming_call_dialog, "response", + G_CALLBACK (empathy_call_window_incoming_call_response_cb), self); + gtk_widget_show (self->priv->incoming_call_dialog); } static void -empathy_call_window_incoming_channel_invalidated_cb (TpProxy *channel, +empathy_call_window_cdo_invalidated_cb (TpProxy *channel, guint domain, gint code, gchar *message, EmpathyCallWindow *self) { - tp_channel_dispatch_operation_destroy_channels_async ( - self->priv->pending_cdo, NULL, NULL); - empathy_call_window_stop_ringing (self); - tp_clear_object (&self->priv->pending_cdo); tp_clear_object (&self->priv->pending_channel); tp_clear_object (&self->priv->pending_context); + + /* We don't know if the incoming call has been accepted or not, so we + * assume it hasn't and if it has, we'll set the proper status when + * we get the new handler. */ + empathy_call_window_status_message (self, _("Disconnected")); + self->priv->call_state = DISCONNECTED; + + gtk_widget_destroy (self->priv->incoming_call_dialog); + self->priv->incoming_call_dialog = NULL; } void @@ -1414,8 +1460,8 @@ empathy_call_window_start_ringing (EmpathyCallWindow *self, self->priv->pending_context = g_object_ref (context); self->priv->pending_cdo = g_object_ref (dispatch_operation); - g_signal_connect (self->priv->pending_channel, "invalidated", - G_CALLBACK (empathy_call_window_incoming_channel_invalidated_cb), self); + g_signal_connect (self->priv->pending_cdo, "invalidated", + G_CALLBACK (empathy_call_window_cdo_invalidated_cb), self); empathy_call_window_set_state_ringing (self); tp_add_dispatch_operation_context_accept (context); -- cgit v1.2.3 From 309ca0453965d145bfeec6d9a497330833c76b7b Mon Sep 17 00:00:00 2001 From: Emilio Pozuelo Monfort Date: Tue, 6 Sep 2011 12:00:31 +0100 Subject: Resize the hangup button in ::realize So that it's not resized many times. https://bugzilla.gnome.org/show_bug.cgi?id=580794 --- src/empathy-call-window.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index c8d17c00e..e53521dcb 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -3400,11 +3400,6 @@ empathy_call_window_connect_handler (EmpathyCallWindow *self) { EmpathyCallWindowPriv *priv = GET_PRIV (self); TpyCallChannel *call; - gint width; - - /* Make the hangup button twice as wide */ - width = gtk_widget_get_allocated_width (priv->hangup_button); - gtk_widget_set_size_request (priv->hangup_button, width * 2, -1); g_signal_connect (priv->handler, "state-changed", G_CALLBACK (empathy_call_window_state_changed_cb), self); @@ -3440,6 +3435,12 @@ static void empathy_call_window_realized_cb (GtkWidget *widget, EmpathyCallWindow *self) { + gint width; + + /* Make the hangup button twice as wide */ + width = gtk_widget_get_allocated_width (self->priv->hangup_button); + gtk_widget_set_size_request (self->priv->hangup_button, width * 2, -1); + empathy_call_window_connect_handler (self); gst_element_set_state (self->priv->pipeline, GST_STATE_PAUSED); -- cgit v1.2.3 From 42ea425116ef9c079fa199039e3ac5ed0bb8e150 Mon Sep 17 00:00:00 2001 From: Emilio Pozuelo Monfort Date: Mon, 11 Jul 2011 12:45:25 +0100 Subject: CallWindow: explain call states https://bugzilla.gnome.org/show_bug.cgi?id=580794 --- src/empathy-call-window.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index e53521dcb..33d4a085c 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -104,12 +104,12 @@ enum { }; typedef enum { - RINGING, - CONNECTING, - CONNECTED, - HELD, - DISCONNECTED, - REDIALING + RINGING, /* Incoming call */ + CONNECTING, /* Outgoing call */ + CONNECTED, /* Connected */ + HELD, /* Connected, but on hold */ + DISCONNECTED, /* Disconnected */ + REDIALING /* Redialing (special case of CONNECTING) */ } CallState; typedef enum { -- cgit v1.2.3