diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/empathy-account-assistant.c | 15 | ||||
-rw-r--r-- | src/empathy-accounts-dialog.c | 36 | ||||
-rw-r--r-- | src/empathy-call-handler.c | 13 | ||||
-rw-r--r-- | src/empathy-call-window.c | 113 | ||||
-rw-r--r-- | src/empathy-chat-manager.c | 20 | ||||
-rw-r--r-- | src/empathy-chat-window.c | 123 | ||||
-rw-r--r-- | src/empathy-chat-window.h | 3 | ||||
-rw-r--r-- | src/empathy-event-manager.c | 2 | ||||
-rw-r--r-- | src/empathy-main-window.c | 329 | ||||
-rw-r--r-- | src/empathy-main-window.ui | 29 | ||||
-rw-r--r-- | src/empathy-map-view.c | 16 |
12 files changed, 660 insertions, 41 deletions
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 e84fa650c..e3fffc2ed 100644 --- a/src/empathy-account-assistant.c +++ b/src/empathy-account-assistant.c @@ -34,6 +34,7 @@ #include <libempathy/empathy-utils.h> #include <libempathy-gtk/empathy-account-widget.h> +#include <libempathy-gtk/empathy-account-widget-skype.h> #include <libempathy-gtk/empathy-protocol-chooser.h> #include <libempathy-gtk/empathy-ui-utils.h> @@ -400,6 +401,15 @@ account_assistant_protocol_changed_cb (GtkComboBox *chooser, /* we are not ready yet */ return; + if (!tp_strdiff (proto->name, "skype")) + { + if (!empathy_account_widget_skype_show_eula (GTK_WINDOW (self))) + { + gtk_combo_box_set_active (chooser, 0); + return; + } + } + /* Create account */ if (is_gtalk) name = "gtalk"; @@ -555,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-accounts-dialog.c b/src/empathy-accounts-dialog.c index 3c690c071..6619442a8 100644 --- a/src/empathy-accounts-dialog.c +++ b/src/empathy-accounts-dialog.c @@ -46,6 +46,7 @@ #include <libempathy-gtk/empathy-account-widget.h> #include <libempathy-gtk/empathy-account-widget-irc.h> #include <libempathy-gtk/empathy-account-widget-sip.h> +#include <libempathy-gtk/empathy-account-widget-skype.h> #include <libempathy-gtk/empathy-cell-renderer-activatable.h> #include <libempathy-gtk/empathy-images.h> #include <libempathy-gtk/mx-gtk-light-switch.h> @@ -257,6 +258,20 @@ accounts_dialog_enable_switch_flipped (MxGtkLightSwitch *sw, if (account == NULL) return; + if (state == TRUE && + !tp_strdiff (tp_account_get_connection_manager (account), "psyke")) + { + /* psyke typically doesn't support more than one simultaneous connection + * unless you've compiled it to do so */ + if (!empathy_accounts_dialog_skype_disable_other_accounts (account, + GTK_WINDOW (dialog))) + { + /* user chose not to proceed */ + mx_gtk_light_switch_set_active (sw, FALSE); + return; + } + } + tp_account_set_enabled_async (account, state, accounts_dialog_enable_account_cb, NULL); } @@ -740,6 +755,8 @@ accounts_dialog_protocol_changed_cb (GtkWidget *widget, GtkTreeIter iter; gboolean creating; EmpathyAccountSettings *settings; + TpConnectionManager *cm; + TpConnectionManagerProtocol *proto; gchar *account = NULL, *password = NULL; /* The "changed" signal is fired during the initiation of the @@ -758,6 +775,25 @@ accounts_dialog_protocol_changed_cb (GtkWidget *widget, if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; + cm = empathy_protocol_chooser_dup_selected ( + EMPATHY_PROTOCOL_CHOOSER (priv->combobox_protocol), &proto, NULL, NULL); + + if (cm == NULL) + return; + + g_object_unref (cm); + + if (!tp_strdiff (proto->name, "skype")) + { + if (!empathy_account_widget_skype_show_eula (GTK_WINDOW (dialog))) + { + gtk_combo_box_set_active ( + GTK_COMBO_BOX (priv->combobox_protocol), 0); + empathy_account_dialog_cancel (dialog); + return; + } + } + /* Save "account" and "password" parameters */ g_object_get (priv->setting_widget_object, "settings", &settings, NULL); 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-manager.c b/src/empathy-chat-manager.c index cfa38ec84..8455001f5 100644 --- a/src/empathy-chat-manager.c +++ b/src/empathy-chat-manager.c @@ -119,18 +119,16 @@ process_tp_chat (EmpathyTpChat *tp_chat, gint64 user_action_time) { EmpathyChat *chat = NULL; - const gchar *id; + const char *channel_path; tell_chatroom_manager_if_needed (account, tp_chat); - id = empathy_tp_chat_get_id (tp_chat); - if (!tp_str_empty (id)) - { - chat = empathy_chat_window_find_chat (account, id); - } + channel_path = empathy_tp_chat_get_channel_path (tp_chat); + chat = empathy_chat_window_find_chat_by_channel (channel_path); if (chat != NULL) { + DEBUG ("found chat %p for path %s", chat, channel_path); empathy_chat_set_tp_chat (chat, tp_chat); } else @@ -218,6 +216,16 @@ handle_channels (TpSimpleHandler *handler, TpChannel *channel = l->data; EmpathyTpChat *tp_chat; + if (tp_proxy_get_invalidated (channel) != NULL) + continue; + + if (!TP_IS_TEXT_CHANNEL (channel)) + { + DEBUG ("Channel %s doesn't implement Messages; can't handle it", + tp_proxy_get_object_path (channel)); + continue; + } + tp_chat = empathy_tp_chat_new (account, channel); if (empathy_tp_chat_is_ready (tp_chat)) diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index 4995dcdc6..d498d8fec 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -146,6 +146,8 @@ static const GtkTargetEntry drag_types_dest_file[] = { static void chat_window_update (EmpathyChatWindow *window, gboolean update_contact_menu); +static EmpathyChat *empathy_chat_window_find_chat (TpAccount *account, + const gchar *id); G_DEFINE_TYPE (EmpathyChatWindow, empathy_chat_window, G_TYPE_OBJECT); @@ -292,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); @@ -442,14 +454,14 @@ get_all_unread_messages (EmpathyChatWindowPriv *priv) static gchar * get_window_title_name (EmpathyChatWindowPriv *priv) { - const gchar *active_name; + gchar *active_name, *ret; guint nb_chats; guint current_unread_msgs; nb_chats = g_list_length (priv->chats); g_assert (nb_chats > 0); - active_name = empathy_chat_get_name (priv->current_chat); + active_name = empathy_chat_dup_name (priv->current_chat); current_unread_msgs = empathy_chat_get_nb_unread_messages ( priv->current_chat); @@ -457,9 +469,9 @@ get_window_title_name (EmpathyChatWindowPriv *priv) if (nb_chats == 1) { /* only one tab */ if (current_unread_msgs == 0) - return g_strdup (active_name); + ret = g_strdup (active_name); else - return g_strdup_printf (ngettext ( + ret = g_strdup_printf (ngettext ( "%s (%d unread)", "%s (%d unread)", current_unread_msgs), active_name, current_unread_msgs); @@ -471,7 +483,7 @@ get_window_title_name (EmpathyChatWindowPriv *priv) if (all_unread_msgs == 0) { /* no unread message */ - return g_strdup_printf (ngettext ( + ret = g_strdup_printf (ngettext ( "%s (and %u other)", "%s (and %u others)", nb_others), active_name, nb_others); @@ -479,7 +491,7 @@ get_window_title_name (EmpathyChatWindowPriv *priv) else if (all_unread_msgs == current_unread_msgs) { /* unread messages are in the current tab */ - return g_strdup_printf (ngettext ( + ret = g_strdup_printf (ngettext ( "%s (%d unread)", "%s (%d unread)", current_unread_msgs), active_name, current_unread_msgs); @@ -487,7 +499,7 @@ get_window_title_name (EmpathyChatWindowPriv *priv) else if (current_unread_msgs == 0) { /* unread messages are in other tabs */ - return g_strdup_printf (ngettext ( + ret = g_strdup_printf (ngettext ( "%s (%d unread from others)", "%s (%d unread from others)", all_unread_msgs), @@ -496,13 +508,17 @@ get_window_title_name (EmpathyChatWindowPriv *priv) else { /* unread messages are in all the tabs */ - return g_strdup_printf (ngettext ( + ret = g_strdup_printf (ngettext ( "%s (%d unread from all)", "%s (%d unread from all)", all_unread_msgs), active_name, all_unread_msgs); } } + + g_free (active_name); + + return ret; } static void @@ -630,7 +646,7 @@ chat_window_update_chat_tab_full (EmpathyChat *chat, EmpathyChatWindow *window; EmpathyChatWindowPriv *priv; EmpathyContact *remote_contact; - const gchar *name; + gchar *name; const gchar *id; TpAccount *account; const gchar *subject; @@ -641,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) { @@ -649,7 +667,7 @@ chat_window_update_chat_tab_full (EmpathyChat *chat, priv = GET_PRIV (window); /* Get information */ - name = empathy_chat_get_name (chat); + name = empathy_chat_dup_name (chat); account = empathy_chat_get_account (chat); subject = empathy_chat_get_subject (chat); remote_contact = empathy_chat_get_remote_contact (chat); @@ -668,6 +686,9 @@ chat_window_update_chat_tab_full (EmpathyChat *chat, else if (g_list_find (priv->chats_composing, chat)) { icon_name = EMPATHY_IMAGE_TYPING; } + else if (empathy_chat_is_sms_channel (chat)) { + icon_name = EMPATHY_IMAGE_SMS; + } else if (remote_contact) { icon_name = empathy_icon_name_for_contact (remote_contact); } else { @@ -686,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); @@ -696,11 +727,24 @@ chat_window_update_chat_tab_full (EmpathyChat *chat, id = name; } + if (empathy_chat_is_sms_channel (chat)) { + append_markup_printf (tooltip, "%s ", _("SMS:")); + } + append_markup_printf (tooltip, "<b>%s</b><small> (%s)</small>", 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); } @@ -731,6 +775,8 @@ chat_window_update_chat_tab_full (EmpathyChat *chat, if (priv->current_chat == chat) { chat_window_update (window, update_contact_menu); } + + g_free (name); } static void @@ -858,21 +904,24 @@ chat_window_favorite_toggled_cb (GtkToggleAction *toggle_action, EmpathyChatWindowPriv *priv = GET_PRIV (window); gboolean active; TpAccount *account; + gchar *name; const gchar *room; EmpathyChatroom *chatroom; active = gtk_toggle_action_get_active (toggle_action); account = empathy_chat_get_account (priv->current_chat); room = empathy_chat_get_id (priv->current_chat); + name = empathy_chat_dup_name (priv->current_chat); chatroom = empathy_chatroom_manager_ensure_chatroom ( priv->chatroom_manager, account, room, - empathy_chat_get_name (priv->current_chat)); + name); empathy_chatroom_set_favorite (chatroom, active); g_object_unref (chatroom); + g_free (name); } static void @@ -882,21 +931,24 @@ chat_window_always_urgent_toggled_cb (GtkToggleAction *toggle_action, EmpathyChatWindowPriv *priv = GET_PRIV (window); gboolean active; TpAccount *account; + gchar *name; const gchar *room; EmpathyChatroom *chatroom; active = gtk_toggle_action_get_active (toggle_action); account = empathy_chat_get_account (priv->current_chat); room = empathy_chat_get_id (priv->current_chat); + name = empathy_chat_dup_name (priv->current_chat); chatroom = empathy_chatroom_manager_ensure_chatroom ( priv->chatroom_manager, account, room, - empathy_chat_get_name (priv->current_chat)); + name); empathy_chatroom_set_always_urgent (chatroom, active); g_object_unref (chatroom); + g_free (name); } static void @@ -1359,18 +1411,20 @@ chat_window_show_or_update_notification (EmpathyChatWindow *window, static void chat_window_set_highlight_room_tab_label (EmpathyChat *chat) { - gchar *markup; + gchar *markup, *name; GtkWidget *widget; if (!empathy_chat_is_room (chat)) return; + name = empathy_chat_dup_name (chat); markup = g_markup_printf_escaped ( "<span color=\"red\" weight=\"bold\">%s</span>", - empathy_chat_get_name (chat)); + name); widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label"); gtk_label_set_markup (GTK_LABEL (widget), markup); + g_free (name); g_free (markup); } @@ -2214,6 +2268,12 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window, g_signal_connect (chat, "notify::remote-contact", G_CALLBACK (chat_window_chat_notify_cb), NULL); + 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); @@ -2330,7 +2390,7 @@ empathy_chat_window_has_focus (EmpathyChatWindow *window) return has_focus; } -EmpathyChat * +static EmpathyChat * empathy_chat_window_find_chat (TpAccount *account, const gchar *id) { @@ -2361,6 +2421,39 @@ empathy_chat_window_find_chat (TpAccount *account, return NULL; } +EmpathyChat * +empathy_chat_window_find_chat_by_channel (const char *channel_path) +{ + GList *l; + + g_return_val_if_fail (!EMP_STR_EMPTY (channel_path), NULL); + + for (l = chat_windows; l; l = l->next) { + EmpathyChatWindowPriv *priv; + EmpathyChatWindow *window; + GList *ll; + + window = l->data; + priv = GET_PRIV (window); + + for (ll = priv->chats; ll; ll = ll->next) { + EmpathyChat *chat; + EmpathyTpChat *tp_chat; + const char *path; + + chat = ll->data; + tp_chat = empathy_chat_get_tp_chat (chat); + path = empathy_tp_chat_get_channel_path (tp_chat); + + if (!tp_strdiff (channel_path, path)) { + return chat; + } + } + } + + return NULL; +} + void empathy_chat_window_present_chat (EmpathyChat *chat, gint64 timestamp) diff --git a/src/empathy-chat-window.h b/src/empathy-chat-window.h index 4cbd2094a..33caec70c 100644 --- a/src/empathy-chat-window.h +++ b/src/empathy-chat-window.h @@ -70,8 +70,7 @@ void empathy_chat_window_move_chat (EmpathyChatWindow *old_wi void empathy_chat_window_switch_to_chat (EmpathyChatWindow *window, EmpathyChat *chat); gboolean empathy_chat_window_has_focus (EmpathyChatWindow *window); -EmpathyChat * empathy_chat_window_find_chat (TpAccount *account, - const gchar *id); +EmpathyChat * empathy_chat_window_find_chat_by_channel (const char *path); void empathy_chat_window_present_chat (EmpathyChat *chat, gint64 timestamp); diff --git a/src/empathy-event-manager.c b/src/empathy-event-manager.c index 041d22a18..e2ce0725f 100644 --- a/src/empathy-event-manager.c +++ b/src/empathy-event-manager.c @@ -1037,7 +1037,7 @@ approve_channels (TpSimpleApprover *approver, channel_type = tp_channel_get_channel_type_id (channel); - if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT) + if (TP_IS_TEXT_CHANNEL (channel)) { EmpathyTpChat *tp_chat; diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c index c93b25b9d..73ae51bd6 100644 --- a/src/empathy-main-window.c +++ b/src/empathy-main-window.c @@ -144,6 +144,10 @@ struct _EmpathyMainWindowPriv { GtkWidget *edit_context; GtkWidget *edit_context_separator; + GtkActionGroup *balance_action_group; + GtkAction *view_balance_show_in_roster; + GtkWidget *balance_vbox; + guint size_timeout_id; /* reffed TpAccount* => visible GtkInfoBar* */ @@ -907,6 +911,278 @@ main_window_update_status (EmpathyMainWindow *window) } } +static char * +main_window_account_to_action_name (TpAccount *account) +{ + char *r; + + /* action names can't have '/' in them, replace it with '.' */ + r = g_strdup (tp_account_get_path_suffix (account)); + r = g_strdelimit (r, "/", '.'); + + return r; +} + +static void +main_window_balance_activate_cb (GtkAction *action, + EmpathyMainWindow *window) +{ + const char *uri; + + uri = g_object_get_data (G_OBJECT (action), "manage-credit-uri"); + + if (!tp_str_empty (uri)) { + DEBUG ("Top-up credit URI: %s", uri); + empathy_url_show (GTK_WIDGET (window), uri); + } else { + DEBUG ("unknown protocol for top-up"); + } +} + +static void +main_window_balance_update_balance (GtkAction *action, + GValueArray *balance) +{ + TpAccount *account = g_object_get_data (G_OBJECT (action), "account"); + int amount = 0; + guint scale = G_MAXINT32; + const char *currency = ""; + char *str; + + if (balance != NULL) + tp_value_array_unpack (balance, 3, + &amount, + &scale, + ¤cy); + + if (amount == 0 && + scale == G_MAXINT32 && + tp_str_empty (currency)) { + /* unknown balance */ + str = g_strdup_printf ("%s (--)", + tp_account_get_display_name (account)); + } else { + char *money = empathy_format_currency (amount, scale, currency); + + str = g_strdup_printf ("%s (%s %s)", + tp_account_get_display_name (account), + currency, money); + g_free (money); + } + + gtk_action_set_label (action, str); + g_free (str); +} + +static void +main_window_setup_balance_got_balance_props (TpProxy *conn, + GHashTable *props, + const GError *in_error, + gpointer user_data, + GObject *action) +{ + GValueArray *balance = NULL; + const char *uri; + + if (in_error != NULL) { + DEBUG ("Failed to get account balance properties: %s", + in_error->message); + goto finally; + } + + balance = tp_asv_get_boxed (props, "AccountBalance", + TP_STRUCT_TYPE_CURRENCY_AMOUNT); + uri = tp_asv_get_string (props, "ManageCreditURI"); + + g_object_set_data_full (action, "manage-credit-uri", + g_strdup (uri), g_free); + gtk_action_set_sensitive (GTK_ACTION (action), !tp_str_empty (uri)); + +finally: + main_window_balance_update_balance (GTK_ACTION (action), balance); +} + +static void +main_window_balance_changed_cb (TpConnection *conn, + const GValueArray *balance, + gpointer user_data, + GObject *action) +{ + main_window_balance_update_balance (GTK_ACTION (action), + (GValueArray *) balance); +} + +static GtkAction * +main_window_setup_balance_create_action (EmpathyMainWindow *window, + TpAccount *account) +{ + EmpathyMainWindowPriv *priv = GET_PRIV (window); + GtkAction *action; + char *name, *ui; + guint merge_id; + GError *error = NULL; + + /* create the action group if required */ + if (priv->balance_action_group == NULL) { + priv->balance_action_group = + gtk_action_group_new ("balance-action-group"); + + gtk_ui_manager_insert_action_group (priv->ui_manager, + priv->balance_action_group, -1); + } + + /* create the action */ + name = main_window_account_to_action_name (account); + action = gtk_action_new (name, + tp_account_get_display_name (account), + _("Top up account credit"), + NULL); + g_object_bind_property (account, "icon-name", action, "icon-name", + G_BINDING_SYNC_CREATE); + + g_object_set_data (G_OBJECT (action), "account", account); + g_signal_connect (action, "activate", + G_CALLBACK (main_window_balance_activate_cb), window); + + gtk_action_group_add_action (priv->balance_action_group, action); + g_object_unref (action); + + ui = g_strdup_printf ( + "<ui>" + " <menubar name='menubar'>" + " <menu action='view'>" + " <placeholder name='view_balance_placeholder'>" + " <menuitem action='%s'/>" + " </placeholder>" + " </menu>" + " </menubar>" + "</ui>", + name); + + merge_id = gtk_ui_manager_add_ui_from_string (priv->ui_manager, + ui, -1, &error); + if (error != NULL) { + DEBUG ("Failed to add balance UI for %s: %s", + tp_account_get_display_name (account), + error->message); + g_error_free (error); + } + + g_object_set_data (G_OBJECT (action), + "merge-id", GUINT_TO_POINTER (merge_id)); + + g_free (name); + g_free (ui); + + return action; +} + +static GtkWidget * +main_window_setup_balance_create_widget (EmpathyMainWindow *window, + GtkAction *action) +{ + EmpathyMainWindowPriv *priv = GET_PRIV (window); + GtkWidget *hbox, *image, *label, *button; + + hbox = gtk_hbox_new (FALSE, 6); + + image = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); + gtk_widget_show (image); + + label = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + gtk_widget_show (label); + + button = gtk_button_new_with_label (_("Top Up...")); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + gtk_box_pack_start (GTK_BOX (priv->balance_vbox), hbox, FALSE, TRUE, 0); + gtk_widget_show_all (hbox); + + /* bind the properties from the action to the widgets -- I could have + * written a widget that implemented GtkActivatable, but effort */ + g_object_bind_property (action, "label", label, "label", + G_BINDING_SYNC_CREATE); + g_object_bind_property (action, "icon-name", image, "icon-name", + G_BINDING_SYNC_CREATE); + g_signal_connect_swapped (button, "clicked", + G_CALLBACK (gtk_action_activate), action); + + /* tie the lifetime of the widget to the lifetime of the action */ + g_object_weak_ref (G_OBJECT (action), + (GWeakNotify) gtk_widget_destroy, hbox); + + return hbox; +} + +static void +main_window_setup_balance_conn_ready (GObject *conn, + GAsyncResult *result, + gpointer user_data) +{ + EmpathyMainWindow *window = user_data; + EmpathyMainWindowPriv *priv = GET_PRIV (window); + TpAccount *account = g_object_get_data (conn, "account"); + GtkAction *action; + GtkWidget *widget; + GError *error = NULL; + + if (!tp_proxy_prepare_finish (conn, result, &error)) { + DEBUG ("Failed to prepare connection: %s", error->message); + + g_error_free (error); + return; + } + + if (!tp_proxy_has_interface_by_id (conn, + TP_IFACE_QUARK_CONNECTION_INTERFACE_BALANCE)) { + return; + } + + DEBUG ("Setting up balance for acct: %s", + tp_account_get_display_name (account)); + + /* create the action */ + action = main_window_setup_balance_create_action (window, account); + + if (action == NULL) + return; + + gtk_action_set_visible (priv->view_balance_show_in_roster, TRUE); + + /* create the display widget */ + widget = main_window_setup_balance_create_widget (window, action); + + /* request the current balance and monitor for any changes */ + tp_cli_dbus_properties_call_get_all (conn, -1, + TP_IFACE_CONNECTION_INTERFACE_BALANCE, + main_window_setup_balance_got_balance_props, + window, NULL, G_OBJECT (action)); + + tp_cli_connection_interface_balance_connect_to_balance_changed ( + TP_CONNECTION (conn), main_window_balance_changed_cb, + window, NULL, G_OBJECT (action), NULL); +} + +static void +main_window_setup_balance (EmpathyMainWindow *window, + TpAccount *account) +{ + TpConnection *conn = tp_account_get_connection (account); + + if (conn == NULL) + return; + + /* need to prepare the connection: + * store the account on the connection */ + g_object_set_data (G_OBJECT (conn), "account", account); + tp_proxy_prepare_async (conn, NULL, + main_window_setup_balance_conn_ready, window); +} + static void main_window_connection_changed_cb (TpAccount *account, guint old_status, @@ -916,6 +1192,8 @@ main_window_connection_changed_cb (TpAccount *account, GHashTable *details, EmpathyMainWindow *window) { + EmpathyMainWindowPriv *priv = GET_PRIV (window); + main_window_update_status (window); if (current == TP_CONNECTION_STATUS_DISCONNECTED && @@ -926,6 +1204,44 @@ main_window_connection_changed_cb (TpAccount *account, if (current == TP_CONNECTION_STATUS_DISCONNECTED) { empathy_sound_play (GTK_WIDGET (window), EMPATHY_SOUND_ACCOUNT_DISCONNECTED); + + /* remove balance action if required */ + if (priv->balance_action_group != NULL) { + GtkAction *action; + char *name; + GList *a; + + name = main_window_account_to_action_name (account); + + action = gtk_action_group_get_action ( + priv->balance_action_group, name); + + if (action != NULL) { + guint merge_id; + + DEBUG ("Removing action"); + + merge_id = GPOINTER_TO_UINT (g_object_get_data ( + G_OBJECT (action), + "merge-id")); + + gtk_ui_manager_remove_ui (priv->ui_manager, + merge_id); + gtk_action_group_remove_action ( + priv->balance_action_group, action); + } + + g_free (name); + + a = gtk_action_group_list_actions ( + priv->balance_action_group); + + gtk_action_set_visible ( + priv->view_balance_show_in_roster, + g_list_length (a) > 0); + + g_list_free (a); + } } if (current == TP_CONNECTION_STATUS_CONNECTED) { @@ -934,6 +1250,7 @@ main_window_connection_changed_cb (TpAccount *account, /* Account connected without error, remove error message if any */ main_window_remove_error (window, account); + main_window_setup_balance (window, account); } } @@ -1778,6 +2095,8 @@ account_manager_prepared_cb (GObject *source_object, window); g_hash_table_insert (priv->status_changed_handlers, account, GUINT_TO_POINTER (handler_id)); + + main_window_setup_balance (window, account); } g_signal_connect (manager, "account-validity-changed", @@ -1873,6 +2192,7 @@ empathy_main_window_init (EmpathyMainWindow *window) filename = empathy_file_lookup ("empathy-main-window.ui", "src"); gui = empathy_builder_get_file (filename, "main_vbox", &priv->main_vbox, + "balance_vbox", &priv->balance_vbox, "errors_vbox", &priv->errors_vbox, "auth_vbox", &priv->auth_vbox, "ui_manager", &priv->ui_manager, @@ -1890,6 +2210,7 @@ empathy_main_window_init (EmpathyMainWindow *window) "notebook", &priv->notebook, "no_entry_label", &priv->no_entry_label, "roster_scrolledwindow", &sw, + "view_balance_show_in_roster", &priv->view_balance_show_in_roster, NULL); g_free (filename); @@ -2047,6 +2368,14 @@ empathy_main_window_init (EmpathyMainWindow *window) /* Set window size. */ empathy_geometry_bind (GTK_WINDOW (window), GEOMETRY_NAME); + /* bind view_balance_show_in_roster */ + g_settings_bind (priv->gsettings_ui, "show-balance-in-roster", + priv->view_balance_show_in_roster, "active", + G_SETTINGS_BIND_DEFAULT); + g_object_bind_property (priv->view_balance_show_in_roster, "active", + priv->balance_vbox, "visible", + G_BINDING_SYNC_CREATE); + /* Enable event handling */ priv->call_observer = empathy_call_observer_dup_singleton (); priv->event_manager = empathy_event_manager_dup_singleton (); diff --git a/src/empathy-main-window.ui b/src/empathy-main-window.ui index a538e0120..95a6ec8dd 100644 --- a/src/empathy-main-window.ui +++ b/src/empathy-main-window.ui @@ -69,6 +69,13 @@ </object> </child> <child> + <object class="GtkToggleAction" id="view_balance_show_in_roster"> + <property name="name">view_balance_show_in_roster</property> + <property name="label" translatable="yes">Show Account _Balances in Roster</property> + <property name="visible">False</property> + </object> + </child> + <child> <object class="GtkAction" id="view_show_map"> <property name="name">view_show_map</property> <property name="label" translatable="yes">Contacts on a _Map</property> @@ -256,6 +263,9 @@ <menuitem action="view_show_offline"/> <menuitem action="view_show_protocols"/> <separator/> + <menuitem action="view_balance_show_in_roster"/> + <placeholder name="view_balance_placeholder"/> + <separator/> <menuitem action="view_sort_by_name"/> <menuitem action="view_sort_by_status"/> <separator/> @@ -305,7 +315,8 @@ </packing> </child> <child> - <object class="GtkVBox" id="errors_vbox"> + <object class="GtkVBox" id="balance_vbox"> + <property name="spacing">3</property> <child> <placeholder/> </child> @@ -317,7 +328,7 @@ </packing> </child> <child> - <object class="GtkVBox" id="auth_vbox"> + <object class="GtkVBox" id="errors_vbox"> <child> <placeholder/> </child> @@ -329,6 +340,18 @@ </packing> </child> <child> + <object class="GtkVBox" id="auth_vbox"> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">4</property> + </packing> + </child> + <child> <object class="GtkNotebook" id="notebook"> <property name="visible">True</property> <property name="can_focus">True</property> @@ -360,7 +383,7 @@ </child> </object> <packing> - <property name="position">4</property> + <property name="position">5</property> </packing> </child> </object> diff --git a/src/empathy-map-view.c b/src/empathy-map-view.c index 31fa997c2..321fbce53 100644 --- a/src/empathy-map-view.c +++ b/src/empathy-map-view.c @@ -231,7 +231,7 @@ map_view_contacts_update_label (ChamplainMarker *marker) gchar *date; gchar *label; GValue *gtime; - time_t loctime; + gint64 loctime; GHashTable *location; EmpathyContact *contact; @@ -242,18 +242,24 @@ map_view_contacts_update_label (ChamplainMarker *marker) if (gtime != NULL) { - time_t now; + GDateTime *now, *d; + GTimeSpan delta; loctime = g_value_get_int64 (gtime); date = empathy_time_to_string_relative (loctime); label = g_strconcat ("<b>", name, "</b>\n<small>", date, "</small>", NULL); g_free (date); - now = time (NULL); + now = g_date_time_new_now_utc (); + d = g_date_time_new_from_unix_utc (loctime); + delta = g_date_time_difference (now, d); /* if location is older than a week */ - if (now - loctime > (60 * 60 * 24 * 7)) - clutter_actor_set_opacity (CLUTTER_ACTOR (marker), 0.75 * 255); + if (delta > G_TIME_SPAN_DAY * 7) + clutter_actor_set_opacity (marker, 0.75 * 255); + + g_date_time_unref (now); + g_date_time_unref (d); } else { |