X-Git-Url: https://git.0d.be/?p=empathy.git;a=blobdiff_plain;f=src%2Fempathy-main-window.c;h=f3722524bb83abbe2f2994f5f8e0ce41c6c7f9ff;hp=851a424ead67f26ab15bab099b6b8d901b64b84f;hb=e3598826ad6ede2f72fbee91c528e621f6dce926;hpb=c698741b1825e306de447fa09624f4a93f067374 diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c index 851a424e..f3722524 100644 --- a/src/empathy-main-window.c +++ b/src/empathy-main-window.c @@ -145,6 +145,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* */ @@ -200,18 +204,15 @@ main_window_flash_foreach (GtkTreeModel *model, GdkPixbuf *pixbuf = NULL; gtk_tree_model_get (model, iter, - EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, - &individual, + EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, -1); if (individual == NULL) return FALSE; contact = empathy_contact_dup_from_folks_individual (individual); - if (contact != data->event->contact) { - tp_clear_object (&contact); - return FALSE; - } + if (contact != data->event->contact) + goto out; if (data->on) { icon_name = data->event->icon_name; @@ -240,6 +241,7 @@ main_window_flash_foreach (GtkTreeModel *model, gtk_tree_path_free (parent_path); } +out: g_object_unref (individual); tp_clear_object (&contact); tp_clear_object (&pixbuf); @@ -429,12 +431,94 @@ main_window_auth_display (EmpathyMainWindow *window, g_hash_table_insert (priv->auths, event, info_bar); } +static void +modify_event_count (GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyEvent *event, + gboolean increase) +{ + FolksIndividual *individual; + EmpathyContact *contact; + guint count; + + gtk_tree_model_get (model, iter, + EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, + EMPATHY_INDIVIDUAL_STORE_COL_EVENT_COUNT, &count, + -1); + + if (individual == NULL) + return; + + increase ? count++ : count--; + + contact = empathy_contact_dup_from_folks_individual (individual); + if (contact == event->contact) { + gtk_tree_store_set (GTK_TREE_STORE (model), iter, + EMPATHY_INDIVIDUAL_STORE_COL_EVENT_COUNT, count, -1); + } + + tp_clear_object (&contact); + g_object_unref (individual); +} + +static gboolean +increase_event_count_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + EmpathyEvent *event = user_data; + + modify_event_count (model, iter, event, TRUE); + + return FALSE; +} + +static void +increase_event_count (EmpathyMainWindow *self, + EmpathyEvent *event) +{ + EmpathyMainWindowPriv *priv = GET_PRIV (self); + GtkTreeModel *model; + + model = GTK_TREE_MODEL (priv->individual_store); + + gtk_tree_model_foreach (model, increase_event_count_foreach, event); +} + +static gboolean +decrease_event_count_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + EmpathyEvent *event = user_data; + + modify_event_count (model, iter, event, FALSE); + + return FALSE; +} + +static void +decrease_event_count (EmpathyMainWindow *self, + EmpathyEvent *event) +{ + EmpathyMainWindowPriv *priv = GET_PRIV (self); + GtkTreeModel *model; + + model = GTK_TREE_MODEL (priv->individual_store); + + gtk_tree_model_foreach (model, decrease_event_count_foreach, event); +} + static void main_window_event_added_cb (EmpathyEventManager *manager, EmpathyEvent *event, EmpathyMainWindow *window) { if (event->contact) { + increase_event_count (window, event); + main_window_flash_start (window); } else if (event->type == EMPATHY_EVENT_TYPE_AUTH) { main_window_auth_display (window, event); @@ -458,6 +542,8 @@ main_window_event_removed_cb (EmpathyEventManager *manager, return; } + decrease_event_count (window, event); + data.on = FALSE; data.event = event; data.window = window; @@ -783,6 +869,282 @@ main_window_update_status (EmpathyMainWindow *window) g_list_free (children); } +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, + TpConnection *conn) +{ + TpAccount *account = tp_connection_get_account (conn); + GtkWidget *label; + int amount = 0; + guint scale = G_MAXINT32; + const gchar *currency = ""; + char *money, *str; + + if (!tp_connection_get_balance (conn, &amount, &scale, ¤cy)) + return; + + if (amount == 0 && + scale == G_MAXINT32 && + tp_str_empty (currency)) { + /* unknown balance */ + money = g_strdup ("--"); + } else { + char *tmp = empathy_format_currency (amount, scale, currency); + + money = g_strdup_printf ("%s %s", currency, tmp); + g_free (tmp); + } + + /* Translators: this string will be something like: + * Top up My Account ($1.23)..." */ + str = g_strdup_printf (_("Top up %s (%s)..."), + tp_account_get_display_name (account), + money); + + gtk_action_set_label (action, str); + g_free (str); + + /* update the money label in the roster */ + label = g_object_get_data (G_OBJECT (action), "money-label"); + + gtk_label_set_text (GTK_LABEL (label), money); + g_free (money); +} + +static void +main_window_balance_changed_cb (TpConnection *conn, + guint balance, + guint scale, + const gchar *currency, + GtkAction *action) +{ + main_window_balance_update_balance (action, conn); +} + +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_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 ( + "" + " " + " " + " " + " " + " " + " " + " " + "", + 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, + TpAccount *account) +{ + EmpathyMainWindowPriv *priv = GET_PRIV (window); + GtkWidget *hbox, *image, *label, *button; + + hbox = gtk_hbox_new (FALSE, 6); + + /* protocol icon */ + image = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); + g_object_bind_property (action, "icon-name", image, "icon-name", + G_BINDING_SYNC_CREATE); + + /* account name label */ + 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); + g_object_bind_property (account, "display-name", label, "label", + G_BINDING_SYNC_CREATE); + + /* balance label */ + label = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (action), "money-label", label); + + /* top up button */ + button = gtk_button_new_with_label (_("Top Up...")); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0); + g_signal_connect_swapped (button, "clicked", + G_CALLBACK (gtk_action_activate), action); + + gtk_box_pack_start (GTK_BOX (priv->balance_vbox), hbox, FALSE, TRUE, 0); + gtk_widget_show_all (hbox); + + /* 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 (EmpathyMainWindow *window, + TpAccount *account) +{ + EmpathyMainWindowPriv *priv = GET_PRIV (window); + TpConnection *conn = tp_account_get_connection (account); + GtkAction *action; + const gchar *uri; + + if (conn == NULL) + return; + + if (!tp_proxy_is_prepared (conn, TP_CONNECTION_FEATURE_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 */ + main_window_setup_balance_create_widget (window, action, account); + + /* check the current balance and monitor for any changes */ + uri = tp_connection_get_balance_uri (conn); + + g_object_set_data_full (G_OBJECT (action), "manage-credit-uri", + g_strdup (uri), g_free); + gtk_action_set_sensitive (GTK_ACTION (action), !tp_str_empty (uri)); + + main_window_balance_update_balance (GTK_ACTION (action), conn); + + g_signal_connect (conn, "balance-changed", + G_CALLBACK (main_window_balance_changed_cb), action); + +} + +static void +main_window_remove_balance_action (EmpathyMainWindow *window, + TpAccount *account) +{ + EmpathyMainWindowPriv *priv = GET_PRIV (window); + GtkAction *action; + char *name; + GList *a; + + if (priv->balance_action_group == NULL) + return; + + 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); +} + static void main_window_connection_changed_cb (TpAccount *account, guint old_status, @@ -804,6 +1166,9 @@ main_window_connection_changed_cb (TpAccount *account, if (current == TP_CONNECTION_STATUS_DISCONNECTED) { empathy_sound_manager_play (priv->sound_mgr, GTK_WIDGET (window), EMPATHY_SOUND_ACCOUNT_DISCONNECTED); + + /* remove balance action if required */ + main_window_remove_balance_action (window, account); } if (current == TP_CONNECTION_STATUS_CONNECTED) { @@ -812,6 +1177,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); } } @@ -895,14 +1261,10 @@ main_window_key_press_event_cb (GtkWidget *window, GdkEventKey *event, gpointer user_data) { - EmpathyChatManager *chat_manager; - if (event->keyval == GDK_KEY_T && event->state & GDK_SHIFT_MASK && event->state & GDK_CONTROL_MASK) { - chat_manager = empathy_chat_manager_dup_singleton (); - empathy_chat_manager_undo_closed_chat (chat_manager); - g_object_unref (chat_manager); + empathy_chat_manager_call_undo_closed_chat (); } return FALSE; } @@ -1253,7 +1615,7 @@ main_window_favorite_chatroom_join (EmpathyChatroom *chatroom) join_fav_account_sig_ctx *ctx; ctx = join_fav_account_sig_ctx_new (account, chatroom, - gtk_get_current_event_time ()); + empathy_get_current_action_time ()); ctx->sig_id = g_signal_connect_data (account, "status-changed", G_CALLBACK (account_status_changed_cb), ctx, @@ -1264,7 +1626,7 @@ main_window_favorite_chatroom_join (EmpathyChatroom *chatroom) return; } - join_chatroom (chatroom, gtk_get_current_event_time ()); + join_chatroom (chatroom, empathy_get_current_action_time ()); } static void @@ -1280,14 +1642,20 @@ main_window_favorite_chatroom_menu_add (EmpathyMainWindow *window, { EmpathyMainWindowPriv *priv = GET_PRIV (window); GtkWidget *menu_item; - const gchar *name; + const gchar *name, *account_name; + gchar *label; + if (g_object_get_data (G_OBJECT (chatroom), "menu_item")) { return; } name = empathy_chatroom_get_name (chatroom); - menu_item = gtk_menu_item_new_with_label (name); + account_name = tp_account_get_display_name ( + empathy_chatroom_get_account (chatroom)); + label = g_strdup_printf ("%s (%s)", name, account_name); + menu_item = gtk_menu_item_new_with_label (label); + g_free (label); g_object_set_data (G_OBJECT (menu_item), "is_favorite", GUINT_TO_POINTER (TRUE)); @@ -1479,9 +1847,9 @@ main_window_edit_blocked_contacts_cb (GtkAction *action, G_CALLBACK (gtk_widget_destroy), NULL); } -static void -main_window_edit_preferences_cb (GtkAction *action, - EmpathyMainWindow *window) +void +empathy_main_window_show_preferences (EmpathyMainWindow *window, + const gchar *tab) { EmpathyMainWindowPriv *priv = GET_PRIV (window); @@ -1494,6 +1862,17 @@ main_window_edit_preferences_cb (GtkAction *action, } else { gtk_window_present (GTK_WINDOW (priv->preferences)); } + + if (tab != NULL) + empathy_preferences_show_tab ( + EMPATHY_PREFERENCES (priv->preferences), tab); +} + +static void +main_window_edit_preferences_cb (GtkAction *action, + EmpathyMainWindow *window) +{ + empathy_main_window_show_preferences (window, NULL); } static void @@ -1507,42 +1886,7 @@ static void main_window_help_debug_cb (GtkAction *action, EmpathyMainWindow *window) { - GdkDisplay *display; - GError *error = NULL; - gchar *path; - GAppInfo *app_info; - GdkAppLaunchContext *context = NULL; - - /* Try to run from source directory if possible */ - path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"), "src", - "empathy-debugger", NULL); - - if (!g_file_test (path, G_FILE_TEST_EXISTS)) { - g_free (path); - path = g_build_filename (BIN_DIR, "empathy-debugger", NULL); - } - - app_info = g_app_info_create_from_commandline (path, NULL, 0, &error); - if (app_info == NULL) { - DEBUG ("Failed to create app info: %s", error->message); - g_error_free (error); - goto out; - } - - display = gdk_display_get_default (); - context = gdk_display_get_app_launch_context (display); - - if (!g_app_info_launch (app_info, NULL, (GAppLaunchContext *) context, - &error)) { - g_warning ("Failed to open debug window: %s", error->message); - g_error_free (error); - goto out; - } - -out: - tp_clear_object (&app_info); - tp_clear_object (&context); - g_free (path); + empathy_launch_program (BIN_DIR, "empathy-debugger", NULL); } static void @@ -1586,6 +1930,9 @@ main_window_account_removed_cb (TpAccountManager *manager, /* remove errors if any */ main_window_remove_error (window, account); + + /* remove the balance action if required */ + main_window_remove_balance_action (window, account); } static void @@ -1637,9 +1984,11 @@ main_window_connection_items_setup (EmpathyMainWindow *window, "room_join_favorites", "chat_new_message", "chat_new_call", + "chat_search_contacts", "chat_add_contact", "edit_personal_information", - "edit_blocked_contacts" + "edit_blocked_contacts", + "edit_search_contacts" }; for (i = 0, list = NULL; i < G_N_ELEMENTS (actions_connected); i++) { @@ -1661,7 +2010,7 @@ account_manager_prepared_cb (GObject *source_object, EmpathyMainWindowPriv *priv = GET_PRIV (window); GError *error = NULL; - if (!tp_account_manager_prepare_finish (manager, result, &error)) { + if (!tp_proxy_prepare_finish (manager, result, &error)) { DEBUG ("Failed to prepare account manager: %s", error->message); g_error_free (error); return; @@ -1677,6 +2026,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", @@ -1747,7 +2098,7 @@ empathy_main_window_init (EmpathyMainWindow *window) { EmpathyMainWindowPriv *priv; EmpathyIndividualManager *individual_manager; - GtkBuilder *gui; + GtkBuilder *gui, *gui_mgr; GtkWidget *sw; GtkToggleAction *show_offline_widget; GtkAction *show_map_widget; @@ -1756,6 +2107,8 @@ empathy_main_window_init (EmpathyMainWindow *window) gchar *filename; GSList *l; GtkTreeModel *model; + GtkWidget *search_vbox; + GtkWidget *menubar; priv = window->priv = G_TYPE_INSTANCE_GET_PRIVATE (window, EMPATHY_TYPE_MAIN_WINDOW, EmpathyMainWindowPriv); @@ -1769,12 +2122,28 @@ empathy_main_window_init (EmpathyMainWindow *window) gtk_window_set_role (GTK_WINDOW (window), "contact_list"); gtk_window_set_default_size (GTK_WINDOW (window), 225, 325); + /* don't finalize the widget on delete-event, just hide it */ + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), NULL); + /* Set up interface */ 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, + "search_vbox", &search_vbox, + "presence_toolbar", &priv->presence_toolbar, + "notebook", &priv->notebook, + "no_entry_label", &priv->no_entry_label, + "roster_scrolledwindow", &sw, + NULL); + g_free (filename); + + /* Set UI manager */ + filename = empathy_file_lookup ("empathy-main-window-menubar.ui", "src"); + gui_mgr = empathy_builder_get_file (filename, "ui_manager", &priv->ui_manager, "view_show_offline", &show_offline_widget, "view_show_protocols", &priv->show_protocols, @@ -1786,20 +2155,24 @@ empathy_main_window_init (EmpathyMainWindow *window) "view_history", &priv->view_history, "view_show_map", &show_map_widget, "room_join_favorites", &priv->room_join_favorites, - "presence_toolbar", &priv->presence_toolbar, - "notebook", &priv->notebook, - "no_entry_label", &priv->no_entry_label, - "roster_scrolledwindow", &sw, + "view_balance_show_in_roster", &priv->view_balance_show_in_roster, + "menubar", &menubar, NULL); g_free (filename); + /* The UI manager is living in its own .ui file as Glade doesn't support + * those. The GtkMenubar has to be in this file as well to we manually add + * it to the first position of the vbox. */ + gtk_box_pack_start (GTK_BOX (priv->main_vbox), menubar, FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (priv->main_vbox), menubar, 0); + gtk_container_add (GTK_CONTAINER (window), priv->main_vbox); gtk_widget_show (priv->main_vbox); g_signal_connect (window, "key-press-event", G_CALLBACK (main_window_key_press_event_cb), NULL); - empathy_builder_connect (gui, window, + empathy_builder_connect (gui_mgr, window, "chat_quit", "activate", main_window_chat_quit_cb, "chat_new_message", "activate", main_window_chat_new_message_cb, "chat_new_call", "activate", main_window_chat_new_call_cb, @@ -1827,10 +2200,11 @@ empathy_main_window_init (EmpathyMainWindow *window) NULL); /* Set up connection related widgets. */ - main_window_connection_items_setup (window, gui); + main_window_connection_items_setup (window, gui_mgr); g_object_ref (priv->ui_manager); g_object_unref (gui); + g_object_unref (gui_mgr); #ifndef HAVE_LIBCHAMPLAIN gtk_action_set_visible (show_map_widget, FALSE); @@ -1838,7 +2212,7 @@ empathy_main_window_init (EmpathyMainWindow *window) priv->account_manager = tp_account_manager_dup (); - tp_account_manager_prepare_async (priv->account_manager, NULL, + tp_proxy_prepare_async (priv->account_manager, NULL, account_manager_prepared_cb, window); priv->errors = g_hash_table_new_full (g_direct_hash, @@ -1881,7 +2255,6 @@ empathy_main_window_init (EmpathyMainWindow *window) /* Set up the throbber */ priv->throbber = gtk_spinner_new (); gtk_widget_set_size_request (priv->throbber, 16, -1); - gtk_widget_set_tooltip_text (priv->throbber, _("Show and edit accounts")); gtk_widget_set_events (priv->throbber, GDK_BUTTON_PRESS_MASK); g_signal_connect (priv->throbber, "button-press-event", G_CALLBACK (main_window_throbber_button_press_event_cb), @@ -1929,8 +2302,9 @@ empathy_main_window_init (EmpathyMainWindow *window) GTK_WIDGET (priv->individual_view)); empathy_individual_view_set_live_search (priv->individual_view, EMPATHY_LIVE_SEARCH (priv->search_bar)); - gtk_box_pack_start (GTK_BOX (priv->main_vbox), priv->search_bar, + gtk_box_pack_start (GTK_BOX (search_vbox), priv->search_bar, FALSE, TRUE, 0); + g_signal_connect_swapped (window, "map", G_CALLBACK (gtk_widget_grab_focus), priv->individual_view); @@ -1950,6 +2324,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 ();