aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/empathy-account-assistant.c15
-rw-r--r--src/empathy-accounts-dialog.c36
-rw-r--r--src/empathy-call-handler.c13
-rw-r--r--src/empathy-call-window.c113
-rw-r--r--src/empathy-chat-manager.c20
-rw-r--r--src/empathy-chat-window.c123
-rw-r--r--src/empathy-chat-window.h3
-rw-r--r--src/empathy-event-manager.c2
-rw-r--r--src/empathy-main-window.c329
-rw-r--r--src/empathy-main-window.ui29
-rw-r--r--src/empathy-map-view.c16
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,
+ &currency);
+
+ 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,
+ &currency);
+
+ 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
{