]> git.0d.be Git - empathy.git/blobdiff - src/empathy-main-window.c
Add Marco Barisione to CONTRIBUTORS
[empathy.git] / src / empathy-main-window.c
index 79fb1d39222b2c6171afd977dc2d9af81506fc3a..e41b3f11ea8d5a6a92539cafc6c51680776cd5fb 100644 (file)
@@ -29,7 +29,6 @@
 #include <glib/gi18n.h>
 
 #include <libempathy/empathy-contact.h>
-#include <libempathy/empathy-debug.h>
 #include <libempathy/empathy-utils.h>
 #include <libempathy/empathy-chatroom-manager.h>
 #include <libempathy/empathy-chatroom.h>
 #include <libempathy-gtk/empathy-ui-utils.h>
 #include <libempathy-gtk/empathy-geometry.h>
 #include <libempathy-gtk/empathy-conf.h>
-#include <libempathy-gtk/empathy-accounts-dialog.h>
 #include <libempathy-gtk/empathy-log-window.h>
 #include <libempathy-gtk/empathy-new-message-dialog.h>
 #include <libempathy-gtk/empathy-gtk-enum-types.h>
 
+#include "empathy-accounts-dialog.h"
 #include "empathy-main-window.h"
 #include "ephy-spinner.h"
 #include "empathy-preferences.h"
 #include "empathy-about-dialog.h"
 #include "empathy-new-chatroom-dialog.h"
 #include "empathy-chatrooms-window.h"
+#include "empathy-event-manager.h"
+
+#define DEBUG_FLAG EMPATHY_DEBUG_OTHER
+#include <libempathy/empathy-debug.h>
 
-#define DEBUG_DOMAIN "MainWindow"
+/* Flashing delay for icons (milliseconds). */
+#define FLASH_TIMEOUT 500
 
 /* Minimum width of roster window if something goes wrong. */
 #define MIN_WIDTH 50
@@ -73,6 +77,10 @@ typedef struct {
        EmpathyContactListStore *list_store;
        MissionControl          *mc;
        EmpathyChatroomManager  *chatroom_manager;
+       EmpathyEventManager     *event_manager;
+       guint                    flash_timeout_id;
+       gboolean                 flash_on;
+       gpointer                 token;
 
        GtkWidget              *window;
        GtkWidget              *main_vbox;
@@ -171,6 +179,193 @@ static void     main_window_notify_sort_criterium_cb           (EmpathyConf
                                                                const gchar              *key,
                                                                EmpathyMainWindow        *window);
 
+static void
+main_window_flash_stop (EmpathyMainWindow *window)
+{
+       if (window->flash_timeout_id == 0) {
+               return;
+       }
+
+       DEBUG ("Stop flashing");
+       g_source_remove (window->flash_timeout_id);
+       window->flash_timeout_id = 0;
+       window->flash_on = FALSE;
+}
+
+typedef struct {
+       EmpathyEvent *event;
+       gboolean      on;
+} FlashForeachData;
+
+static gboolean
+main_window_flash_foreach (GtkTreeModel *model,
+                          GtkTreePath  *path,
+                          GtkTreeIter  *iter,
+                          gpointer      user_data)
+{
+       FlashForeachData *data = (FlashForeachData*) user_data;
+       EmpathyContact   *contact;
+       const gchar      *icon_name;
+       GtkTreePath      *parent_path = NULL;
+       GtkTreeIter       parent_iter;
+
+       /* To be used with gtk_tree_model_foreach, update the status icon
+        * of the contact to show the event icon (on=TRUE) or the presence
+        * (on=FALSE) */
+       gtk_tree_model_get (model, iter,
+                           EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact,
+                           -1);
+
+       if (contact != data->event->contact) {
+               if (contact) {
+                       g_object_unref (contact);
+               }
+               return FALSE;
+       }
+
+       if (data->on) {
+               icon_name = data->event->icon_name;
+       } else {
+               icon_name = empathy_icon_name_for_contact (contact);
+       }
+
+       gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+                           EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS, icon_name,
+                           -1);
+
+       /* To make sure the parent is shown correctly, we emit
+        * the row-changed signal on the parent so it prompts
+        * it to be refreshed by the filter func. 
+        */
+       if (gtk_tree_model_iter_parent (model, &parent_iter, iter)) {
+               parent_path = gtk_tree_model_get_path (model, &parent_iter);
+       }
+       if (parent_path) {
+               gtk_tree_model_row_changed (model, parent_path, &parent_iter);
+               gtk_tree_path_free (parent_path);
+       }
+
+       g_object_unref (contact);
+
+       return FALSE;
+}
+
+static gboolean
+main_window_flash_cb (EmpathyMainWindow *window)
+{
+       GtkTreeModel     *model;
+       GSList           *events, *l;
+       gboolean          found_event = FALSE;
+       FlashForeachData  data;
+
+       window->flash_on = !window->flash_on;
+       data.on = window->flash_on;
+       model = GTK_TREE_MODEL (window->list_store);
+
+       events = empathy_event_manager_get_events (window->event_manager);
+       for (l = events; l; l = l->next) {
+               data.event = l->data;
+               if (!data.event->contact) {
+                       continue;
+               }
+
+               found_event = TRUE;
+               gtk_tree_model_foreach (model,
+                                       main_window_flash_foreach,
+                                       &data);
+       }
+
+       if (!found_event) {
+               main_window_flash_stop (window);
+       }
+
+       return TRUE;
+}
+
+static void
+main_window_flash_start (EmpathyMainWindow *window)
+{
+
+       if (window->flash_timeout_id != 0) {
+               return;
+       }
+
+       DEBUG ("Start flashing");
+       window->flash_timeout_id = g_timeout_add (FLASH_TIMEOUT,
+                                                 (GSourceFunc) main_window_flash_cb,
+                                                 window);
+       main_window_flash_cb (window);
+}
+
+static void
+main_window_event_added_cb (EmpathyEventManager *manager,
+                           EmpathyEvent        *event,
+                           EmpathyMainWindow   *window)
+{
+       if (event->contact) {
+               main_window_flash_start (window);
+       }
+}
+
+static void
+main_window_event_removed_cb (EmpathyEventManager *manager,
+                             EmpathyEvent        *event,
+                             EmpathyMainWindow   *window)
+{
+       FlashForeachData data;
+
+       if (!event->contact) {
+               return;
+       }
+
+       data.on = FALSE;
+       data.event = event;
+       gtk_tree_model_foreach (GTK_TREE_MODEL (window->list_store),
+                               main_window_flash_foreach,
+                               &data);
+}
+
+static void
+main_window_row_activated_cb (EmpathyContactListView *view,
+                             GtkTreePath            *path,
+                             GtkTreeViewColumn      *col,
+                             EmpathyMainWindow      *window)
+{
+       EmpathyContact *contact;
+       GtkTreeModel   *model;
+       GtkTreeIter     iter;
+       GSList         *events, *l;
+
+       model = GTK_TREE_MODEL (window->list_store);
+       gtk_tree_model_get_iter (model, &iter, path);
+       gtk_tree_model_get (model, &iter,
+                           EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact,
+                           -1);
+
+       if (!contact) {
+               return;
+       }
+
+       /* If the contact has an event activate it, otherwise the
+        * default handler of row-activated will be called. */
+       events = empathy_event_manager_get_events (window->event_manager);
+       for (l = events; l; l = l->next) {
+               EmpathyEvent *event = l->data;
+
+               if (event->contact == contact) {
+                       DEBUG ("Activate event");
+                       empathy_event_activate (event);
+
+                       /* We don't want the default handler of this signal
+                        * (e.g. open a chat) */
+                       g_signal_stop_emission_by_name (view, "row-activated");
+                       break;
+               }
+       }
+
+       g_object_unref (contact);
+}
+
 GtkWidget *
 empathy_main_window_show (void)
 {
@@ -187,6 +382,7 @@ empathy_main_window_show (void)
        gboolean                  compact_contact_list;
        gint                      x, y, w, h;
        gchar                    *filename;
+       GSList                   *l;
 
        if (window) {
                empathy_window_present (GTK_WINDOW (window->window), TRUE);
@@ -239,9 +435,9 @@ empathy_main_window_show (void)
        g_object_unref (glade);
 
        window->mc = empathy_mission_control_new ();
-       dbus_g_proxy_connect_signal (DBUS_G_PROXY (window->mc), "AccountStatusChanged",
-                                    G_CALLBACK (main_window_status_changed_cb),
-                                    window, NULL);
+       window->token = empathy_connect_to_account_status_changed (window->mc,
+                                                  G_CALLBACK (main_window_status_changed_cb),
+                                                  window, NULL);
 
        window->errors = g_hash_table_new_full (empathy_account_hash,
                                                empathy_account_equal,
@@ -290,12 +486,16 @@ empathy_main_window_show (void)
        list_iface = EMPATHY_CONTACT_LIST (empathy_contact_manager_new ());
        window->list_store = empathy_contact_list_store_new (list_iface);
        window->list_view = empathy_contact_list_view_new (window->list_store,
-                                                          EMPATHY_CONTACT_LIST_FEATURE_ALL);
+                                                          EMPATHY_CONTACT_LIST_FEATURE_ALL,
+                                                          EMPATHY_CONTACT_FEATURE_ALL);
        g_object_unref (list_iface);
 
        gtk_widget_show (GTK_WIDGET (window->list_view));
        gtk_container_add (GTK_CONTAINER (sw),
                           GTK_WIDGET (window->list_view));
+       g_signal_connect (window->list_view, "row-activated",
+                         G_CALLBACK (main_window_row_activated_cb),
+                         window);
 
        /* Load user-defined accelerators. */
        main_window_accels_load ();
@@ -307,7 +507,7 @@ empathy_main_window_show (void)
                /* Use the defaults from the glade file if we
                 * don't have good w, h geometry.
                 */
-               empathy_debug (DEBUG_DOMAIN, "Configuring window default size w:%d, h:%d", w, h);
+               DEBUG ("Configuring window default size w:%d, h:%d", w, h);
                gtk_window_set_default_size (GTK_WINDOW (window->window), w, h);
        }
 
@@ -315,12 +515,28 @@ empathy_main_window_show (void)
                /* Let the window manager position it if we
                 * don't have good x, y coordinates.
                 */
-               empathy_debug (DEBUG_DOMAIN, "Configuring window default position x:%d, y:%d", x, y);
+               DEBUG ("Configuring window default position x:%d, y:%d", x, y);
                gtk_window_move (GTK_WINDOW (window->window), x, y);
        }
 
+       /* Enable event handling */
+       window->event_manager = empathy_event_manager_new ();
+       g_signal_connect (window->event_manager, "event-added",
+                         G_CALLBACK (main_window_event_added_cb),
+                         window);
+       g_signal_connect (window->event_manager, "event-removed",
+                         G_CALLBACK (main_window_event_removed_cb),
+                         window);
+
+       l = empathy_event_manager_get_events (window->event_manager);
+       while (l) {
+               main_window_event_added_cb (window->event_manager,
+                                           l->data, window);
+               l = l->next;
+       }
+
        conf = empathy_conf_get ();
-       
+
        /* Show offline ? */
        empathy_conf_get_bool (conf,
                              EMPATHY_PREFS_CONTACTS_SHOW_OFFLINE,
@@ -374,9 +590,7 @@ main_window_destroy_cb (GtkWidget         *widget,
        /* Save user-defined accelerators. */
        main_window_accels_save ();
 
-       dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (window->mc), "AccountStatusChanged",
-                                       G_CALLBACK (main_window_status_changed_cb),
-                                       window);
+       empathy_disconnect_account_status_changed (window->token);
 
        if (window->size_timeout_id) {
                g_source_remove (window->size_timeout_id);
@@ -389,6 +603,14 @@ main_window_destroy_cb (GtkWidget         *widget,
        g_object_unref (window->list_store);
        g_hash_table_destroy (window->errors);
 
+       g_signal_handlers_disconnect_by_func (window->event_manager,
+                                             main_window_event_added_cb,
+                                             window);
+       g_signal_handlers_disconnect_by_func (window->event_manager,
+                                             main_window_event_removed_cb,
+                                             window);
+       g_object_unref (window->event_manager);
+
        g_free (window);
 }
 
@@ -500,20 +722,23 @@ main_window_favorite_chatroom_join (EmpathyChatroom *chatroom)
 {
        MissionControl *mc;
        McAccount      *account;
+       TpConnection   *connection;
        const gchar    *room;
 
        mc = empathy_mission_control_new ();
        account = empathy_chatroom_get_account (chatroom);
        room = empathy_chatroom_get_room (chatroom);
 
-       empathy_debug (DEBUG_DOMAIN, "Requesting channel for '%s'", room);
+       DEBUG ("Requesting channel for '%s'", room);
 
-       mission_control_request_channel_with_string_handle (mc,
-                                                           account,
-                                                           TP_IFACE_CHANNEL_TYPE_TEXT,
-                                                           room,
-                                                           TP_HANDLE_TYPE_ROOM,
-                                                           NULL, NULL);        
+       connection = mission_control_get_tpconnection (mc, account, NULL);
+       tp_connection_run_until_ready (connection, TRUE, NULL, NULL);   
+       empathy_connection_request_channel (connection, -1,
+                                           TP_IFACE_CHANNEL_TYPE_TEXT,
+                                           TP_HANDLE_TYPE_ROOM,
+                                           room, TRUE,
+                                           NULL, NULL, NULL, NULL);
+       g_object_unref (connection);
        g_object_unref (mc);
 }
 
@@ -595,53 +820,43 @@ main_window_edit_button_press_event_cb (GtkWidget         *widget,
                                        GdkEventButton    *event,
                                        EmpathyMainWindow *window)
 {
-       EmpathyContact *contact;
-       gchar         *group;
+       GtkWidget *submenu;
 
        if (!event->button == 1) {
                return FALSE;
        }
 
-       group = empathy_contact_list_view_get_selected_group (window->list_view);
-       if (group) {
+       submenu = empathy_contact_list_view_get_contact_menu (window->list_view);
+       if (submenu) {
                GtkMenuItem *item;
                GtkWidget   *label;
-               GtkWidget   *submenu;
 
                item = GTK_MENU_ITEM (window->edit_context);
                label = gtk_bin_get_child (GTK_BIN (item));
-               gtk_label_set_text (GTK_LABEL (label), _("Group"));
+               gtk_label_set_text (GTK_LABEL (label), _("Contact"));
 
                gtk_widget_show (window->edit_context);
                gtk_widget_show (window->edit_context_separator);
 
-               submenu = empathy_contact_list_view_get_group_menu (window->list_view);
                gtk_menu_item_set_submenu (item, submenu);
 
-               g_free (group);
-
                return FALSE;
        }
 
-       contact = empathy_contact_list_view_get_selected (window->list_view);
-       if (contact) {
+       submenu = empathy_contact_list_view_get_group_menu (window->list_view);
+       if (submenu) {
                GtkMenuItem *item;
                GtkWidget   *label;
-               GtkWidget   *submenu;
 
                item = GTK_MENU_ITEM (window->edit_context);
                label = gtk_bin_get_child (GTK_BIN (item));
-               gtk_label_set_text (GTK_LABEL (label), _("Contact"));
+               gtk_label_set_text (GTK_LABEL (label), _("Group"));
 
                gtk_widget_show (window->edit_context);
                gtk_widget_show (window->edit_context_separator);
 
-               submenu = empathy_contact_list_view_get_contact_menu (window->list_view,
-                                                                    contact);
                gtk_menu_item_set_submenu (item, submenu);
 
-               g_object_unref (contact);
-
                return FALSE;
        }
 
@@ -655,7 +870,7 @@ static void
 main_window_edit_accounts_cb (GtkWidget         *widget,
                              EmpathyMainWindow *window)
 {
-       empathy_accounts_dialog_show (GTK_WINDOW (window->window));
+       empathy_accounts_dialog_show (GTK_WINDOW (window->window), NULL);
 }
 
 static void
@@ -707,7 +922,7 @@ static void
 main_window_help_contents_cb (GtkWidget         *widget,
                              EmpathyMainWindow *window)
 {
-       //empathy_help_show ();
+       empathy_url_show ("ghelp:empathy");
 }
 
 static gboolean
@@ -720,7 +935,7 @@ main_window_throbber_button_press_event_cb (GtkWidget         *throbber_ebox,
                return FALSE;
        }
 
-       empathy_accounts_dialog_show (GTK_WINDOW (window->window));
+       empathy_accounts_dialog_show (GTK_WINDOW (window->window), NULL);
 
        return FALSE;
 }
@@ -732,9 +947,9 @@ main_window_error_edit_clicked_cb (GtkButton         *button,
        McAccount *account;
        GtkWidget *error_widget;
 
-       empathy_accounts_dialog_show (GTK_WINDOW (window->window));
-
        account = g_object_get_data (G_OBJECT (button), "account");
+       empathy_accounts_dialog_show (GTK_WINDOW (window->window), account);
+
        error_widget = g_hash_table_lookup (window->errors, account);
        gtk_widget_destroy (error_widget);
        g_hash_table_remove (window->errors, account);
@@ -898,10 +1113,13 @@ main_window_status_changed_cb (MissionControl           *mc,
        account = mc_account_lookup (unique_name);
 
        if (status == TP_CONNECTION_STATUS_DISCONNECTED &&
-           reason > TP_CONNECTION_STATUS_REASON_REQUESTED) {
+           reason != TP_CONNECTION_STATUS_REASON_REQUESTED) {
                const gchar *message;
 
                switch (reason) {
+               case TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED:
+                       message = _("No error specified");
+                       break;
                case TP_CONNECTION_STATUS_REASON_NETWORK_ERROR:
                        message = _("Network error");
                        break;
@@ -933,7 +1151,7 @@ main_window_status_changed_cb (MissionControl           *mc,
                        message = _("Certificate fingerprint mismatch");
                        break;
                case TP_CONNECTION_STATUS_REASON_CERT_SELF_SIGNED:
-                       message = _("Certificate self signed");
+                       message = _("Certificate self-signed");
                        break;
                case TP_CONNECTION_STATUS_REASON_CERT_OTHER_ERROR:
                        message = _("Certificate error");
@@ -1019,7 +1237,7 @@ main_window_accels_load (void)
 
        filename = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, ACCELS_FILENAME, NULL);
        if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
-               empathy_debug (DEBUG_DOMAIN, "Loading from:'%s'", filename);
+               DEBUG ("Loading from:'%s'", filename);
                gtk_accel_map_load (filename);
        }
 
@@ -1037,7 +1255,7 @@ main_window_accels_save (void)
        file_with_path = g_build_filename (dir, ACCELS_FILENAME, NULL);
        g_free (dir);
 
-       empathy_debug (DEBUG_DOMAIN, "Saving to:'%s'", file_with_path);
+       DEBUG ("Saving to:'%s'", file_with_path);
        gtk_accel_map_save (file_with_path);
 
        g_free (file_with_path);