diff options
author | Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk> | 2011-04-29 23:25:35 +0800 |
---|---|---|
committer | Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk> | 2011-04-29 23:25:35 +0800 |
commit | b028f1e3930ab201994eccd4ff7d1bc18c50e6f3 (patch) | |
tree | 4b83e90fe17af81dd8edffaf8084688a9d022bc7 | |
parent | cf401b3897d7d4eba4e8dbe5fec9e85079e17446 (diff) | |
parent | 1c68eae8b655e8904bbb0a90001f01eb6d3b342a (diff) | |
download | gsoc2013-empathy-b028f1e3930ab201994eccd4ff7d1bc18c50e6f3.tar gsoc2013-empathy-b028f1e3930ab201994eccd4ff7d1bc18c50e6f3.tar.gz gsoc2013-empathy-b028f1e3930ab201994eccd4ff7d1bc18c50e6f3.tar.bz2 gsoc2013-empathy-b028f1e3930ab201994eccd4ff7d1bc18c50e6f3.tar.lz gsoc2013-empathy-b028f1e3930ab201994eccd4ff7d1bc18c50e6f3.tar.xz gsoc2013-empathy-b028f1e3930ab201994eccd4ff7d1bc18c50e6f3.tar.zst gsoc2013-empathy-b028f1e3930ab201994eccd4ff7d1bc18c50e6f3.zip |
Merge branch 'empathy-skype' into debian
-rw-r--r-- | configure.ac | 17 | ||||
-rw-r--r-- | data/.gitignore | 1 | ||||
-rw-r--r-- | libempathy-gtk/empathy-account-widget-skype.c | 86 | ||||
-rw-r--r-- | libempathy-gtk/empathy-account-widget.c | 15 | ||||
-rw-r--r-- | libempathy-gtk/empathy-chat.c | 96 | ||||
-rw-r--r-- | libempathy-gtk/empathy-chat.h | 2 | ||||
-rw-r--r-- | libempathy/empathy-tp-chat.c | 94 | ||||
-rw-r--r-- | libempathy/empathy-tp-chat.h | 6 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/empathy-account-assistant.c | 5 | ||||
-rw-r--r-- | src/empathy-call-handler.c | 13 | ||||
-rw-r--r-- | src/empathy-call-window.c | 113 | ||||
-rw-r--r-- | src/empathy-chat-window.c | 34 |
13 files changed, 413 insertions, 71 deletions
diff --git a/configure.ac b/configure.ac index 86d6b805f..c151b3a3f 100644 --- a/configure.ac +++ b/configure.ac @@ -42,7 +42,7 @@ LIBCANBERRA_GTK_REQUIRED=0.4 LIBNOTIFY_REQUIRED=0.7.0 TELEPATHY_FARSIGHT_REQUIRED=0.0.14 TELEPATHY_GLIB_REQUIRED=0.14.1 -TELEPATHY_LOGGER=0.2.0 +TELEPATHY_LOGGER=0.2.8 UNIQUE_REQUIRED=1.1.2 # Optionnal deps @@ -200,6 +200,21 @@ if test "x$with_call" = "xyes" -a "x$have_farstream" != "xyes"; then fi AM_CONDITIONAL(HAVE_CALL, test "x$have_farstream" = "xyes") + +# ----------------------------------------------------------- +# Call support in tp-logger +# ----------------------------------------------------------- +SAVE_CFLAGS=$CFLAGS +SAVE_CPPFLAGS=$CPPFLAGS +CFLAGS="$CFLAGS $EMPATHY_CFLAGS" +CPPFLAGS="$CPPFLAGS $EMPATHY_CFLAGS" + +AC_CHECK_HEADER(telepathy-logger/call-event.h,, + AC_MSG_ERROR([tp-logger must be compiled with --enable-call])) + +CFLAGS=$SAVE_CFLAGS +CPPFLAGS=$SAVE_CPPFLAGS + # ----------------------------------------------------------- # evolution-data-server (about-me) # ----------------------------------------------------------- diff --git a/data/.gitignore b/data/.gitignore index 7ec3d4d81..902e80747 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -7,3 +7,4 @@ org.freedesktop.Telepathy.Client.Empathy.AudioVideo.service empathy-accounts.desktop empathy-accounts.desktop.in org.freedesktop.Telepathy.Client.Empathy.Auth.service +org.freedesktop.Telepathy.Client.Empathy.Call.service diff --git a/libempathy-gtk/empathy-account-widget-skype.c b/libempathy-gtk/empathy-account-widget-skype.c index 9b8e6270f..288fc039a 100644 --- a/libempathy-gtk/empathy-account-widget-skype.c +++ b/libempathy-gtk/empathy-account-widget-skype.c @@ -149,7 +149,6 @@ auth_observer_observe_channels (TpSimpleObserver *auth_observer, TpChannel *channel; GHashTable *props; GStrv available_mechanisms; - GtkWidget *password_entry = user_data; const char *password = NULL; gboolean remember; @@ -157,11 +156,11 @@ auth_observer_observe_channels (TpSimpleObserver *auth_observer, if (tp_strdiff ( tp_connection_get_connection_manager_name (connection), "psyke")) - goto except; + goto finally; /* can only deal with one channel */ if (g_list_length (channels) != 1) - goto except; + goto finally; channel = channels->data; props = tp_channel_borrow_immutable_properties (channel); @@ -172,18 +171,14 @@ auth_observer_observe_channels (TpSimpleObserver *auth_observer, /* must support X-TELEPATHY-PASSWORD */ if (!tp_strv_contains ((const char * const *) available_mechanisms, "X-TELEPATHY-PASSWORD")) - goto except; + goto finally; - /* do we have a password */ - if (g_object_get_data (G_OBJECT (password_entry), "fake-password") == NULL) - password = gtk_entry_get_text (GTK_ENTRY (password_entry)); + password = g_object_get_data (G_OBJECT (auth_observer), "password"); + remember = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (auth_observer), + "remember-password")); if (tp_str_empty (password)) - goto except; - - /* do we want to remember it */ - remember = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON ( - g_object_get_data (G_OBJECT (password_entry), "remember-password"))); + goto finally; DEBUG ("claiming auth channel"); @@ -191,12 +186,12 @@ auth_observer_observe_channels (TpSimpleObserver *auth_observer, auth_observer_claim_cb, observe_channels_data_new (account, channel, password, remember)); -except: +finally: tp_observe_channels_context_accept (context); } static TpBaseClient * -auth_observer_new (GtkWidget *password_entry) +auth_observer_new (void) { TpDBusDaemon *dbus; TpBaseClient *auth_observer; @@ -212,7 +207,7 @@ auth_observer_new (GtkWidget *password_entry) } auth_observer = tp_simple_observer_new (dbus, FALSE, "Empathy.PsykePreAuth", - FALSE, auth_observer_observe_channels, password_entry, NULL); + FALSE, auth_observer_observe_channels, NULL, NULL); tp_base_client_set_observer_delay_approvers (auth_observer, TRUE); tp_base_client_take_observer_filter (auth_observer, tp_asv_new ( @@ -365,7 +360,7 @@ account_widget_build_skype_get_password_saved_cb (TpProxy *account, gpointer user_data, GObject *password_entry) { - GtkWidget *remember_password; + GtkWidget *remember_password = user_data; gboolean password_saved; if (in_error != NULL) @@ -385,9 +380,6 @@ account_widget_build_skype_get_password_saved_cb (TpProxy *account, !tp_str_empty (gtk_entry_get_text (GTK_ENTRY (password_entry)))) return; - remember_password = - GTK_WIDGET (g_object_get_data (password_entry, "remember-password")); - gtk_entry_set_text (GTK_ENTRY (password_entry), password_saved ? "xxxxxxxxxxxx": ""); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (remember_password), @@ -417,7 +409,7 @@ account_widget_build_skype_account_properties_changed_cb (TpProxy *account, return; account_widget_build_skype_get_password_saved_cb (account, value, NULL, - NULL, password_entry); + user_data, password_entry); } static void @@ -453,6 +445,26 @@ account_widget_skype_additional_apply_async (EmpathyAccountWidget *self, TpAccount *account = empathy_account_settings_get_account (priv->settings); GSimpleAsyncResult *simple = g_simple_async_result_new (G_OBJECT (self), callback, user_data, NULL); + GtkWidget *password_entry, *remember_password; + GObject *auth_observer; + const char *password = NULL; + gboolean remember; + + /* sync the password with the observer */ + auth_observer = g_object_get_data (G_OBJECT (self), "auth-observer"); + password_entry = g_object_get_data (G_OBJECT (self), "password-entry"); + remember_password = g_object_get_data (G_OBJECT (self), "remember-password"); + + if (g_object_get_data (G_OBJECT (password_entry), "fake-password") == NULL) + password = gtk_entry_get_text (GTK_ENTRY (password_entry)); + + remember = gtk_toggle_button_get_active ( + GTK_TOGGLE_BUTTON (remember_password)); + + g_object_set_data_full (auth_observer, "password", + g_strdup (password), g_free); + g_object_set_data (auth_observer, "remember-password", + GUINT_TO_POINTER (remember)); /* we have to forget the password, else psyke won't query for the new one */ emp_cli_account_interface_external_password_storage_call_forget_password ( @@ -782,6 +794,7 @@ void empathy_account_widget_build_skype (EmpathyAccountWidget *self, const char *filename) { + static TpBaseClient *auth_observer = NULL; EmpathyAccountWidgetPriv *priv = GET_PRIV (self); TpAccount *account = empathy_account_settings_get_account (priv->settings); GtkWidget *password_entry, *remember_password; @@ -854,12 +867,17 @@ empathy_account_widget_build_skype (EmpathyAccountWidget *self, self->ui_details->default_focus = g_strdup ("entry_id"); } - /* create the Psyke pre-authentication observer -- - * tie the lifetime of the observer to the lifetime of the widget */ - g_object_set_data_full (G_OBJECT (self->ui_details->widget), "auth-observer", - auth_observer_new (password_entry), g_object_unref); - g_object_set_data (G_OBJECT (password_entry), "remember-password", - remember_password); + /* create the Psyke pre-authentication observer */ + if (auth_observer == NULL) + { + /* the auth observer lives for the lifetime of the process */ + DEBUG ("Creating Psyke authentication observer"); + auth_observer = auth_observer_new (); + } + + g_object_set_data (G_OBJECT (self), "auth-observer", auth_observer); + g_object_set_data (G_OBJECT (self), "password-entry", password_entry); + g_object_set_data (G_OBJECT (self), "remember-password", remember_password); g_object_bind_property (remember_password, "active", password_entry, "sensitive", G_BINDING_SYNC_CREATE); @@ -872,10 +890,10 @@ empathy_account_widget_build_skype (EmpathyAccountWidget *self, EMP_IFACE_ACCOUNT_INTERFACE_EXTERNAL_PASSWORD_STORAGE, "PasswordSaved", account_widget_build_skype_get_password_saved_cb, - NULL, NULL, G_OBJECT (password_entry)); + remember_password, NULL, G_OBJECT (password_entry)); tp_cli_dbus_properties_connect_to_properties_changed (account, account_widget_build_skype_account_properties_changed_cb, - NULL, NULL, G_OBJECT (password_entry), NULL); + remember_password, NULL, G_OBJECT (password_entry), NULL); } /* if the user changes the password, it's probably no longer a fake @@ -962,12 +980,16 @@ static gboolean is_other_psyke_account (TpAccount *ours, TpAccount *other) { - if (ours == NULL) - return TRUE; + gboolean paths_diff; - return (tp_strdiff ( + if (ours == NULL) + paths_diff = TRUE; + else + paths_diff = tp_strdiff ( tp_proxy_get_object_path (ours), - tp_proxy_get_object_path (other)) && + tp_proxy_get_object_path (other)); + + return (paths_diff && tp_account_is_enabled (other) && !tp_strdiff (tp_account_get_connection_manager (other), "psyke")); } diff --git a/libempathy-gtk/empathy-account-widget.c b/libempathy-gtk/empathy-account-widget.c index c78bcb7b8..edc2f98eb 100644 --- a/libempathy-gtk/empathy-account-widget.c +++ b/libempathy-gtk/empathy-account-widget.c @@ -866,7 +866,20 @@ static void account_widget_apply_clicked_cb (GtkWidget *button, EmpathyAccountWidget *self) { - empathy_accounts_dialog_skype_disable_other_accounts (NULL, NULL); + EmpathyAccountWidgetPriv *priv = GET_PRIV (self); + GtkWidget *parent; + + parent = gtk_widget_get_toplevel (button); + if (!GTK_IS_WINDOW (parent) || !gtk_widget_is_toplevel (parent)) + parent = NULL; + + if (priv->creating_account) + { + if (!empathy_accounts_dialog_skype_disable_other_accounts (NULL, + GTK_WINDOW (parent))) + /* the user chose not to proceed */ + return; + } account_widget_apply_and_log_in (self); } diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c index ee18be657..fd43473dd 100644 --- a/libempathy-gtk/empathy-chat.c +++ b/libempathy-gtk/empathy-chat.c @@ -170,6 +170,7 @@ enum { PROP_REMOTE_CONTACT, PROP_SHOW_CONTACTS, PROP_SMS_CHANNEL, + PROP_N_MESSAGES_SENDING, }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -210,6 +211,10 @@ chat_get_property (GObject *object, case PROP_SMS_CHANNEL: g_value_set_boolean (value, priv->sms_channel); break; + case PROP_N_MESSAGES_SENDING: + g_value_set_uint (value, + empathy_chat_get_n_messages_sending (chat)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -1198,31 +1203,41 @@ static void chat_send_error_cb (EmpathyTpChat *tp_chat, const gchar *message_body, TpChannelTextSendError error_code, + const gchar *dbus_error, EmpathyChat *chat) { - const gchar *error; + const gchar *error = NULL; gchar *str; - switch (error_code) { - case TP_CHANNEL_TEXT_SEND_ERROR_OFFLINE: - error = _("offline"); - break; - case TP_CHANNEL_TEXT_SEND_ERROR_INVALID_CONTACT: - error = _("invalid contact"); - break; - case TP_CHANNEL_TEXT_SEND_ERROR_PERMISSION_DENIED: - error = _("permission denied"); - break; - case TP_CHANNEL_TEXT_SEND_ERROR_TOO_LONG: - error = _("too long message"); - break; - case TP_CHANNEL_TEXT_SEND_ERROR_NOT_IMPLEMENTED: - error = _("not implemented"); - break; - case TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN: - default: - error = _("unknown"); - break; + if (!tp_strdiff (dbus_error, TP_ERROR_STR_INSUFFICIENT_BALANCE)) { + error = _("insufficient balance to send message"); + } else if (!tp_strdiff (dbus_error, TP_ERROR_STR_NOT_CAPABLE)) { + error = _("not capable"); + } + + if (error == NULL) { + /* if we didn't find a dbus-error, try the old error */ + switch (error_code) { + case TP_CHANNEL_TEXT_SEND_ERROR_OFFLINE: + error = _("offline"); + break; + case TP_CHANNEL_TEXT_SEND_ERROR_INVALID_CONTACT: + error = _("invalid contact"); + break; + case TP_CHANNEL_TEXT_SEND_ERROR_PERMISSION_DENIED: + error = _("permission denied"); + break; + case TP_CHANNEL_TEXT_SEND_ERROR_TOO_LONG: + error = _("too long message"); + break; + case TP_CHANNEL_TEXT_SEND_ERROR_NOT_IMPLEMENTED: + error = _("not implemented"); + break; + case TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN: + default: + error = _("unknown"); + break; + } } if (message_body != NULL) { @@ -2813,6 +2828,14 @@ empathy_chat_class_init (EmpathyChatClass *klass) FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, + PROP_N_MESSAGES_SENDING, + g_param_spec_uint ("n-messages-sending", + "Num Messages Sending", + "The number of messages being sent", + 0, G_MAXUINT, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + signals[COMPOSING] = g_signal_new ("composing", G_OBJECT_CLASS_TYPE (object_class), @@ -3089,6 +3112,12 @@ chat_sms_channel_changed_cb (EmpathyChat *self) g_object_notify (G_OBJECT (self), "sms-channel"); } +static void +chat_n_messages_sending_changed_cb (EmpathyChat *self) +{ + g_object_notify (G_OBJECT (self), "n-messages-sending"); +} + void empathy_chat_set_tp_chat (EmpathyChat *chat, EmpathyTpChat *tp_chat) @@ -3143,6 +3172,9 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, g_signal_connect_swapped (tp_chat, "notify::sms-channel", G_CALLBACK (chat_sms_channel_changed_cb), chat); + g_signal_connect_swapped (tp_chat, "notify::n-messages-sending", + G_CALLBACK (chat_n_messages_sending_changed_cb), + chat); /* Get initial value of properties */ properties = empathy_tp_chat_get_properties (priv->tp_chat); @@ -3439,3 +3471,25 @@ empathy_chat_is_sms_channel (EmpathyChat *self) return priv->sms_channel; } + +guint +empathy_chat_get_n_messages_sending (EmpathyChat *self) +{ + EmpathyChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHAT (self), 0); + + priv = GET_PRIV (self); + + if (priv->tp_chat == NULL) { + return 0; + } else { + guint n_messages; + + g_object_get (priv->tp_chat, + "n-messages-sending", &n_messages, + NULL); + + return n_messages; + } +} diff --git a/libempathy-gtk/empathy-chat.h b/libempathy-gtk/empathy-chat.h index 08472400e..0fd779cc6 100644 --- a/libempathy-gtk/empathy-chat.h +++ b/libempathy-gtk/empathy-chat.h @@ -90,6 +90,8 @@ guint empathy_chat_get_nb_unread_messages (EmpathyChat *chat); void empathy_chat_messages_read (EmpathyChat *self); gboolean empathy_chat_is_sms_channel (EmpathyChat *self); +guint empathy_chat_get_n_messages_sending (EmpathyChat *self); + G_END_DECLS #endif /* __EMPATHY_CHAT_H__ */ diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c index e829d6e6b..29f886416 100644 --- a/libempathy/empathy-tp-chat.c +++ b/libempathy/empathy-tp-chat.c @@ -31,6 +31,7 @@ #include "empathy-tp-contact-factory.h" #include "empathy-contact-list.h" #include "empathy-dispatcher.h" +#include "empathy-enum-types.h" #include "empathy-marshal.h" #include "empathy-time.h" #include "empathy-utils.h" @@ -61,6 +62,8 @@ typedef struct { gboolean can_upgrade_to_muc; gboolean got_sms_channel; gboolean sms_channel; + + GHashTable *messages_being_sent; } EmpathyTpChatPriv; static void tp_chat_iface_init (EmpathyContactListIface *iface); @@ -73,6 +76,7 @@ enum { PROP_PASSWORD_NEEDED, PROP_READY, PROP_SMS_CHANNEL, + PROP_N_MESSAGES_SENDING, }; enum { @@ -93,6 +97,39 @@ G_DEFINE_TYPE_WITH_CODE (EmpathyTpChat, empathy_tp_chat, G_TYPE_OBJECT, static void acknowledge_messages (EmpathyTpChat *chat, GArray *ids); static void +tp_chat_set_delivery_status (EmpathyTpChat *self, + const gchar *token, + EmpathyDeliveryStatus delivery_status) +{ + EmpathyTpChatPriv *priv = GET_PRIV (self); + + /* channel must support receiving failures and successes */ + if (!tp_str_empty (token) && + tp_text_channel_get_delivery_reporting_support ( + TP_TEXT_CHANNEL (priv->channel)) & + (TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_FAILURES | + TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_SUCCESSES)) { + + DEBUG ("Delivery status (%s) = %u", token, delivery_status); + + switch (delivery_status) { + case EMPATHY_DELIVERY_STATUS_NONE: + g_hash_table_remove (priv->messages_being_sent, + token); + break; + + default: + g_hash_table_insert (priv->messages_being_sent, + g_strdup (token), + GUINT_TO_POINTER (delivery_status)); + break; + } + + g_object_notify (G_OBJECT (self), "n-messages-sending"); + } +} + +static void tp_chat_invalidated_cb (TpProxy *proxy, guint domain, gint code, @@ -322,19 +359,38 @@ handle_delivery_report (EmpathyTpChat *self, gboolean valid; GPtrArray *echo; const gchar *message_body = NULL; + const gchar *delivery_dbus_error; + const gchar *delivery_token = NULL; header = tp_message_peek (message, 0); if (header == NULL) goto out; + delivery_token = tp_asv_get_string (header, "delivery-token"); delivery_status = tp_asv_get_uint32 (header, "delivery-status", &valid); - if (!valid || delivery_status != TP_DELIVERY_STATUS_PERMANENTLY_FAILED) + + if (!valid) { + goto out; + } else if (delivery_status == TP_DELIVERY_STATUS_ACCEPTED) { + DEBUG ("Accepted %s", delivery_token); + tp_chat_set_delivery_status (self, delivery_token, + EMPATHY_DELIVERY_STATUS_ACCEPTED); + goto out; + } else if (delivery_status == TP_DELIVERY_STATUS_DELIVERED) { + DEBUG ("Delivered %s", delivery_token); + tp_chat_set_delivery_status (self, delivery_token, + EMPATHY_DELIVERY_STATUS_NONE); + goto out; + } else if (delivery_status != TP_DELIVERY_STATUS_PERMANENTLY_FAILED) { goto out; + } delivery_error = tp_asv_get_uint32 (header, "delivery-error", &valid); if (!valid) delivery_error = TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN; + delivery_dbus_error = tp_asv_get_string (header, "delivery-dbus-error"); + /* TODO: ideally we should use tp-glib API giving us the echoed message as a * TpMessage. (fdo #35884) */ echo = tp_asv_get_boxed (header, "delivery-echo", @@ -347,7 +403,10 @@ handle_delivery_report (EmpathyTpChat *self, message_body = tp_asv_get_string (echo_body, "content"); } - g_signal_emit (self, signals[SEND_ERROR], 0, message_body, delivery_error); + tp_chat_set_delivery_status (self, delivery_token, + EMPATHY_DELIVERY_STATUS_NONE); + g_signal_emit (self, signals[SEND_ERROR], 0, message_body, + delivery_error, delivery_dbus_error); out: tp_text_channel_ack_message_async (TP_TEXT_CHANNEL (priv->channel), @@ -439,9 +498,10 @@ message_send_cb (GObject *source, { EmpathyTpChat *chat = user_data; TpTextChannel *channel = (TpTextChannel *) source; + gchar *token = NULL; GError *error = NULL; - if (!tp_text_channel_send_message_finish (channel, result, NULL, &error)) { + if (!tp_text_channel_send_message_finish (channel, result, &token, &error)) { DEBUG ("Error: %s", error->message); /* FIXME: we should use the body of the message as first argument of the @@ -449,10 +509,14 @@ message_send_cb (GObject *source, * we'll have rebased EmpathyTpChat on top of TpTextChannel we'll be able * to use the user_data pointer to pass the message and fix this. */ g_signal_emit (chat, signals[SEND_ERROR], 0, - NULL, error_to_text_send_error (error)); + NULL, error_to_text_send_error (error), NULL); g_error_free (error); } + + tp_chat_set_delivery_status (chat, token, + EMPATHY_DELIVERY_STATUS_SENDING); + g_free (token); } typedef struct { @@ -812,6 +876,7 @@ tp_chat_finalize (GObject *object) g_queue_free (priv->messages_queue); g_queue_free (priv->pending_messages_queue); + g_hash_table_destroy (priv->messages_being_sent); G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object); } @@ -1414,6 +1479,10 @@ tp_chat_get_property (GObject *object, case PROP_SMS_CHANNEL: g_value_set_boolean (value, priv->sms_channel); break; + case PROP_N_MESSAGES_SENDING: + g_value_set_uint (value, + g_hash_table_size (priv->messages_being_sent)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -1503,6 +1572,14 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass) FALSE, G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_N_MESSAGES_SENDING, + g_param_spec_uint ("n-messages-sending", + "Num Messages Sending", + "The number of messages being sent", + 0, G_MAXUINT, 0, + G_PARAM_READABLE)); + /* Signals */ signals[MESSAGE_RECEIVED] = g_signal_new ("message-received", @@ -1520,9 +1597,9 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, - _empathy_marshal_VOID__STRING_UINT, + _empathy_marshal_VOID__STRING_UINT_STRING, G_TYPE_NONE, - 2, G_TYPE_STRING, G_TYPE_UINT); + 3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING); signals[CHAT_STATE_CHANGED] = g_signal_new ("chat-state-changed", @@ -1566,6 +1643,8 @@ empathy_tp_chat_init (EmpathyTpChat *chat) chat->priv = priv; priv->messages_queue = g_queue_new (); priv->pending_messages_queue = g_queue_new (); + priv->messages_being_sent = g_hash_table_new_full ( + g_str_hash, g_str_equal, g_free, NULL); } static void @@ -1684,7 +1763,8 @@ empathy_tp_chat_send (EmpathyTpChat *chat, DEBUG ("Sending message: %s", message_body); tp_text_channel_send_message_async (TP_TEXT_CHANNEL (priv->channel), - message, 0, message_send_cb, chat); + message, TP_MESSAGE_SENDING_FLAG_REPORT_DELIVERY, + message_send_cb, chat); g_free (message_body); } diff --git a/libempathy/empathy-tp-chat.h b/libempathy/empathy-tp-chat.h index d72c30e06..34651d13c 100644 --- a/libempathy/empathy-tp-chat.h +++ b/libempathy/empathy-tp-chat.h @@ -59,6 +59,12 @@ typedef struct { GValue *value; } EmpathyTpChatProperty; +typedef enum { + EMPATHY_DELIVERY_STATUS_NONE, + EMPATHY_DELIVERY_STATUS_SENDING, + EMPATHY_DELIVERY_STATUS_ACCEPTED +} EmpathyDeliveryStatus; + GType empathy_tp_chat_get_type (void) G_GNUC_CONST; EmpathyTpChat *empathy_tp_chat_new (TpAccount *account, TpChannel *channel); diff --git a/src/Makefile.am b/src/Makefile.am index 246296172..3915f0404 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -259,7 +259,7 @@ dist_man_MANS = \ src-marshal.list: $(empathy_SOURCES) Makefile.am $(AM_V_GEN)( cd $(srcdir) && \ sed -n -e 's/.*src_marshal_\([[:upper:][:digit:]]*__[[:upper:][:digit:]_]*\).*/\1/p' \ - $(empathy_SOURCES) $(empathy_av_SOURCES) ) \ + $(empathy_SOURCES) $(empathy_av_SOURCES) $(empathy_call_SOURCES) ) \ | sed -e 's/__/:/' -e 'y/_/,/' | sort -u > $@.tmp @if cmp -s $@.tmp $@; then \ rm $@.tmp; \ diff --git a/src/empathy-account-assistant.c b/src/empathy-account-assistant.c index f7753bdb3..e3fffc2ed 100644 --- a/src/empathy-account-assistant.c +++ b/src/empathy-account-assistant.c @@ -565,6 +565,11 @@ account_assistant_finish_enter_or_create_page (EmpathyAccountAssistant *self, _("Enter the details for the new account")); } + /* if someone clicked 'Back' this signal handler can be connected twice: + * disconnect any existing handlers */ + g_signal_handlers_disconnect_by_func (priv->chooser, + account_assistant_protocol_changed_cb, self); + g_signal_connect (priv->chooser, "changed", G_CALLBACK (account_assistant_protocol_changed_cb), self); diff --git a/src/empathy-call-handler.c b/src/empathy-call-handler.c index aff96bd6e..56d109838 100644 --- a/src/empathy-call-handler.c +++ b/src/empathy-call-handler.c @@ -189,13 +189,18 @@ static void on_call_state_changed_cb (TpyCallChannel *call, TpyCallState state, TpyCallFlags flags, - const GValueArray *call_state_reason, + const GValueArray *call_state_reason, GHashTable *call_state_details, EmpathyCallHandler *handler) { EmpathyCallHandlerPriv *priv = handler->priv; + gchar *dbus_reason; + guint actor, reason; - g_signal_emit (handler, signals[STATE_CHANGED], 0, state); + tp_value_array_unpack ((GValueArray *) call_state_reason, 3, + &actor, &reason, &dbus_reason); + + g_signal_emit (handler, signals[STATE_CHANGED], 0, state, dbus_reason); if (state == TPY_CALL_STATE_ENDED) { @@ -503,8 +508,8 @@ empathy_call_handler_class_init (EmpathyCallHandlerClass *klass) signals[STATE_CHANGED] = g_signal_new ("state-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); + _src_marshal_VOID__UINT_STRING, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); } EmpathyCallHandler * diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index fdb753245..3f260327a 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -2110,14 +2110,37 @@ empathy_call_window_update_timer (gpointer user_data) return TRUE; } -#if 0 +enum +{ + EMP_RESPONSE_BALANCE +}; + +static void +on_error_infobar_response_cb (GtkInfoBar *info_bar, + gint response_id, + gpointer user_data) +{ + switch (response_id) + { + case GTK_RESPONSE_CLOSE: + gtk_widget_destroy (GTK_WIDGET (info_bar)); + break; + case EMP_RESPONSE_BALANCE: + empathy_url_show (GTK_WIDGET (info_bar), + g_object_get_data (G_OBJECT (info_bar), "uri")); + break; + } +} + static void display_error (EmpathyCallWindow *self, - TpyCallChannel *call, const gchar *img, const gchar *title, const gchar *desc, - const gchar *details) + const gchar *details, + const gchar *button_text, + const gchar *uri, + gint button_response) { EmpathyCallWindowPriv *priv = GET_PRIV (self); GtkWidget *info_bar; @@ -2132,6 +2155,14 @@ display_error (EmpathyCallWindow *self, info_bar = gtk_info_bar_new_with_buttons (GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); + if (button_text != NULL) + { + gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), + button_text, button_response); + g_object_set_data_full (G_OBJECT (info_bar), + "uri", g_strdup (uri), g_free); + } + gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING); content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar)); @@ -2179,13 +2210,14 @@ display_error (EmpathyCallWindow *self, } g_signal_connect (info_bar, "response", - G_CALLBACK (gtk_widget_destroy), NULL); + G_CALLBACK (on_error_infobar_response_cb), NULL); gtk_box_pack_start (GTK_BOX (priv->errors_vbox), info_bar, FALSE, FALSE, CONTENT_HBOX_CHILDREN_PACKING_PADDING); gtk_widget_show_all (info_bar); } +#if 0 static gchar * media_stream_error_to_txt (EmpathyCallWindow *self, TpyCallChannel *call, @@ -2305,14 +2337,87 @@ empathy_call_window_video_stream_error (TpyCallChannel *call, #endif static void +got_balance_props (TpProxy *proxy, + GHashTable *props, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (weak_object); + GValueArray *balance; + gchar *balance_str, *currency, *tmp; + const gchar *uri; + gint amount, scale; + + if (error != NULL) + { + DEBUG ("Failed to get Balance: %s", error->message); + return; + } + + balance = tp_asv_get_boxed (props, "AccountBalance", + TP_STRUCT_TYPE_CURRENCY_AMOUNT); + uri = tp_asv_get_string (props, "ManageCreditURI"); + tp_value_array_unpack (balance, 3, + &amount, + &scale, + ¤cy); + + if (amount == 0 && + scale == G_MAXINT32 && + tp_str_empty (currency)) + { + /* unknown balance */ + balance_str = g_strdup ("(--)"); + } + else + { + char *money = empathy_format_currency (amount, scale, currency); + + balance_str = g_strdup_printf ("%s %s", + currency, money); + g_free (money); + } + + /* FIXME: don't hardcode Skype here */ + display_error (self, + NULL, + _("Sorry, you don’t have enough Skype Credit for that call."), + tmp = g_strdup_printf (_("Your current balance is %s."), + balance_str), + NULL, + _("Buy Skype credit..."), + uri, + EMP_RESPONSE_BALANCE); + g_free (tmp); +} + +static void empathy_call_window_state_changed_cb (EmpathyCallHandler *handler, TpyCallState state, + gchar *reason, EmpathyCallWindow *self) { EmpathyCallWindowPriv *priv = GET_PRIV (self); TpyCallChannel *call; gboolean can_send_video; + if (state == TPY_CALL_STATE_ENDED && + !tp_strdiff (reason, TP_ERROR_STR_INSUFFICIENT_BALANCE)) + { + g_object_get (handler, "call-channel", &call, NULL); + + tp_cli_dbus_properties_call_get_all ( + tp_channel_borrow_connection (TP_CHANNEL (call)), + -1, + TP_IFACE_CONNECTION_INTERFACE_BALANCE, + got_balance_props, + NULL, NULL, G_OBJECT (self)); + + g_object_unref (call); + return; + } + if (state != TPY_CALL_STATE_ACCEPTED) return; diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index aa7a1a152..4bbf1a789 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -294,6 +294,16 @@ chat_window_create_label (EmpathyChatWindow *window, gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0); if (is_tab_label) { + GtkWidget *sending_spinner; + + sending_spinner = gtk_spinner_new (); + + gtk_box_pack_start (GTK_BOX (hbox), sending_spinner, + FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (chat), + "chat-window-tab-sending-spinner", + sending_spinner); + close_button = gtk_button_new (); gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE); g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button); @@ -647,6 +657,8 @@ chat_window_update_chat_tab_full (EmpathyChat *chat, const gchar *icon_name; GtkWidget *tab_image; GtkWidget *menu_image; + GtkWidget *sending_spinner; + guint nb_sending; window = chat_window_find_chat (chat); if (!window) { @@ -695,6 +707,16 @@ chat_window_update_chat_tab_full (EmpathyChat *chat, gtk_widget_hide (menu_image); } + /* Update the sending spinner */ + nb_sending = empathy_chat_get_n_messages_sending (chat); + sending_spinner = g_object_get_data (G_OBJECT (chat), + "chat-window-tab-sending-spinner"); + + g_object_set (sending_spinner, + "active", nb_sending > 0, + "visible", nb_sending > 0, + NULL); + /* Update tab tooltip */ tooltip = g_string_new (NULL); @@ -714,6 +736,15 @@ chat_window_update_chat_tab_full (EmpathyChat *chat, id, tp_account_get_display_name (account)); + if (nb_sending > 0) { + append_markup_printf (tooltip, "\n"); + append_markup_printf (tooltip, + ngettext ("Sending %d message", + "Sending %d messages", + nb_sending), + nb_sending); + } + if (!EMP_STR_EMPTY (status)) { append_markup_printf (tooltip, "\n<i>%s</i>", status); } @@ -2239,6 +2270,9 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window, g_signal_connect (chat, "notify::sms-channel", G_CALLBACK (chat_window_chat_notify_cb), NULL); + g_signal_connect (chat, "notify::n-messages-sending", + G_CALLBACK (chat_window_chat_notify_cb), + NULL); chat_window_chat_notify_cb (chat); gtk_notebook_append_page_menu (GTK_NOTEBOOK (priv->notebook), child, label, popup_label); |