From: Xavier Claessens Date: Tue, 15 Jul 2008 14:00:42 +0000 (+0000) Subject: Blink the status icon when a contact has an event. X-Git-Url: https://git.0d.be/?p=empathy.git;a=commitdiff_plain;h=284af952a6644b052dad4aa131175c14658312f7 Blink the status icon when a contact has an event. svn path=/trunk/; revision=1247 --- diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c index 760ad6d5..f8942cbb 100644 --- a/libempathy-gtk/empathy-contact-list-view.c +++ b/libempathy-gtk/empathy-contact-list-view.c @@ -46,6 +46,7 @@ #include "empathy-cell-renderer-expander.h" #include "empathy-cell-renderer-text.h" #include "empathy-cell-renderer-activatable.h" +#include "empathy-event-manager.h" #include "empathy-ui-utils.h" #include "empathy-gtk-enum-types.h" #include "empathy-gtk-marshal.h" @@ -67,6 +68,9 @@ typedef struct { EmpathyContactListFeatureFlags list_features; EmpathyContactFeatureFlags contact_features; GtkWidget *tooltip_widget; + EmpathyEventManager *event_manager; + guint flash_timeout_id; + gboolean flash_on; } EmpathyContactListViewPriv; typedef struct { @@ -117,6 +121,154 @@ static guint signals[LAST_SIGNAL]; G_DEFINE_TYPE (EmpathyContactListView, empathy_contact_list_view, GTK_TYPE_TREE_VIEW); +static void +contact_list_view_flash_stop (EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv = GET_PRIV (view); + + if (priv->flash_timeout_id == 0) { + return; + } + + DEBUG ("Stop flashing"); + g_source_remove (priv->flash_timeout_id); + priv->flash_timeout_id = 0; + priv->flash_on = FALSE; +} + +typedef struct { + EmpathyEvent *event; + gboolean on; +} FlashForeachData; + +static gboolean +contact_list_view_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; + + + 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 +contact_list_view_flash_cb (EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv = GET_PRIV (view); + GtkTreeModel *model; + GSList *events, *l; + gboolean found_event = FALSE; + FlashForeachData data; + + priv->flash_on = !priv->flash_on; + data.on = priv->flash_on; + model = GTK_TREE_MODEL (priv->store); + + events = empathy_event_manager_get_events (priv->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, + contact_list_view_flash_foreach, + &data); + } + + if (!found_event) { + contact_list_view_flash_stop (view); + } + + return TRUE; +} + +static void +contact_list_view_flash_start (EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv = GET_PRIV (view); + + if (priv->flash_timeout_id != 0) { + return; + } + + DEBUG ("Start flashing"); + priv->flash_timeout_id = g_timeout_add (FLASH_TIMEOUT, + (GSourceFunc) contact_list_view_flash_cb, + view); +} + +static void +contact_list_view_event_added_cb (EmpathyEventManager *manager, + EmpathyEvent *event, + EmpathyContactListView *view) +{ + if (event->contact) { + contact_list_view_flash_start (view); + } +} + +static void +contact_list_view_event_removed_cb (EmpathyEventManager *manager, + EmpathyEvent *event, + EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv = GET_PRIV (view); + FlashForeachData data; + + if (!event->contact) { + return; + } + + data.on = FALSE; + data.event = event; + gtk_tree_model_foreach (GTK_TREE_MODEL (priv->store), + contact_list_view_flash_foreach, + &data); +} + static gboolean contact_list_view_query_tooltip_cb (EmpathyContactListView *view, gint x, @@ -951,13 +1103,47 @@ contact_list_view_set_list_features (EmpathyContactListView *view, G_N_ELEMENTS (drag_types_dest), GDK_ACTION_MOVE | GDK_ACTION_COPY); } else { - /* FIXME: URI could still be droped depending on FT feature */ + /* FIXME: URI could still be droped depending on FT feature */ gtk_drag_dest_unset (GTK_WIDGET (view)); } /* Update has-tooltip */ has_tooltip = (features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_TOOLTIP) != 0; gtk_widget_set_has_tooltip (GTK_WIDGET (view), has_tooltip); + + /* Enable event handling if needed */ + if (features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_EVENTS && + !priv->event_manager) { + GSList *l; + + priv->event_manager = empathy_event_manager_new (); + g_signal_connect (priv->event_manager, "event-added", + G_CALLBACK (contact_list_view_event_added_cb), + view); + g_signal_connect (priv->event_manager, "event-removed", + G_CALLBACK (contact_list_view_event_removed_cb), + view); + + l = empathy_event_manager_get_events (priv->event_manager); + while (l) { + contact_list_view_event_added_cb (priv->event_manager, + l->data, view); + l = l->next; + } + } + + /* Disable event handling if needed */ + if (!(features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_EVENTS) && + priv->event_manager) { + g_signal_handlers_disconnect_by_func (priv->event_manager, + contact_list_view_event_added_cb, + view); + g_signal_handlers_disconnect_by_func (priv->event_manager, + contact_list_view_event_removed_cb, + view); + g_object_unref (priv->event_manager); + priv->event_manager = NULL; + } } static void @@ -971,6 +1157,16 @@ contact_list_view_finalize (GObject *object) g_object_unref (priv->store); } + if (priv->event_manager) { + g_signal_handlers_disconnect_by_func (priv->event_manager, + contact_list_view_event_added_cb, + object); + g_signal_handlers_disconnect_by_func (priv->event_manager, + contact_list_view_event_removed_cb, + object); + g_object_unref (priv->event_manager); + } + G_OBJECT_CLASS (empathy_contact_list_view_parent_class)->finalize (object); } diff --git a/libempathy-gtk/empathy-contact-list-view.h b/libempathy-gtk/empathy-contact-list-view.h index 82990d64..e7d7769b 100644 --- a/libempathy-gtk/empathy-contact-list-view.h +++ b/libempathy-gtk/empathy-contact-list-view.h @@ -54,7 +54,8 @@ typedef enum { EMPATHY_CONTACT_LIST_FEATURE_CONTACT_DROP = 1 << 4, EMPATHY_CONTACT_LIST_FEATURE_CONTACT_DRAG = 1 << 5, EMPATHY_CONTACT_LIST_FEATURE_CONTACT_TOOLTIP = 1 << 6, - EMPATHY_CONTACT_LIST_FEATURE_ALL = (1 << 7) - 1, + EMPATHY_CONTACT_LIST_FEATURE_CONTACT_EVENTS = 1 << 7, + EMPATHY_CONTACT_LIST_FEATURE_ALL = (1 << 8) - 1, } EmpathyContactListFeatureFlags; struct _EmpathyContactListView {