aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2012-06-11 18:22:43 +0800
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2012-06-14 15:21:50 +0800
commitf56ae9de2c19ee8d739b07909834816aa14ac6a1 (patch)
treeaaae2dbe13599bb7d53d22db41a31ecb043bc7f8
parent4726282c4b6985a0b34e77b7b7955bcad233cf50 (diff)
downloadgsoc2013-empathy-f56ae9de2c19ee8d739b07909834816aa14ac6a1.tar
gsoc2013-empathy-f56ae9de2c19ee8d739b07909834816aa14ac6a1.tar.gz
gsoc2013-empathy-f56ae9de2c19ee8d739b07909834816aa14ac6a1.tar.bz2
gsoc2013-empathy-f56ae9de2c19ee8d739b07909834816aa14ac6a1.tar.lz
gsoc2013-empathy-f56ae9de2c19ee8d739b07909834816aa14ac6a1.tar.xz
gsoc2013-empathy-f56ae9de2c19ee8d739b07909834816aa14ac6a1.tar.zst
gsoc2013-empathy-f56ae9de2c19ee8d739b07909834816aa14ac6a1.zip
roster-view: add API to display events
-rw-r--r--libempathy-gtk/empathy-roster-view.c226
-rw-r--r--libempathy-gtk/empathy-roster-view.h8
-rw-r--r--src/empathy-event-manager.h1
3 files changed, 235 insertions, 0 deletions
diff --git a/libempathy-gtk/empathy-roster-view.c b/libempathy-gtk/empathy-roster-view.c
index ce8f19f64..e68315cd1 100644
--- a/libempathy-gtk/empathy-roster-view.c
+++ b/libempathy-gtk/empathy-roster-view.c
@@ -10,6 +10,9 @@
G_DEFINE_TYPE (EmpathyRosterView, empathy_roster_view, EGG_TYPE_LIST_BOX)
+/* Flashing delay for icons (milliseconds). */
+#define FLASH_TIMEOUT 500
+
enum
{
PROP_MANAGER = 1,
@@ -23,6 +26,7 @@ enum
{
SIG_INDIVIDUAL_ACTIVATED,
SIG_POPUP_INDIVIDUAL_MENU,
+ SIG_EVENT_ACTIVATED,
LAST_SIGNAL
};
@@ -49,6 +53,13 @@ struct _EmpathyRosterViewPriv
/* Hash of the EmpathyRosterContact currently displayed */
GHashTable *displayed_contacts;
+ guint last_event_id;
+ /* queue of (Event *). The most recent events are in the head of the queue
+ * so we always display the icon of the oldest one. */
+ GQueue *events;
+ guint flash_id;
+ gboolean display_flash_event;
+
gboolean show_offline;
gboolean show_groups;
gboolean empty;
@@ -59,6 +70,39 @@ struct _EmpathyRosterViewPriv
gpointer individual_tooltip_data;
};
+typedef struct
+{
+ guint id;
+ FolksIndividual *individual;
+ gchar *icon;
+ gpointer user_data;
+} Event;
+
+static Event *
+event_new (guint id,
+ FolksIndividual *individual,
+ const gchar *icon,
+ gpointer user_data)
+{
+ Event *event = g_slice_new (Event);
+
+ event->id = id;
+ event->individual = g_object_ref (individual);
+ event->icon = g_strdup (icon);
+ event->user_data = user_data;
+ return event;
+}
+
+static void
+event_free (gpointer data)
+{
+ Event *event = data;
+ g_object_unref (event->individual);
+ g_free (event->icon);
+
+ g_slice_free (Event, event);
+}
+
static void
empathy_roster_view_get_property (GObject *object,
guint property_id,
@@ -281,6 +325,115 @@ update_group_widgets_count (EmpathyRosterView *self,
}
static void
+set_event_icon_on_individual (EmpathyRosterView *self,
+ FolksIndividual *individual,
+ const gchar *icon)
+{
+ GHashTable *contacts;
+ GHashTableIter iter;
+ gpointer v;
+
+ contacts = g_hash_table_lookup (self->priv->roster_contacts, individual);
+ if (contacts == NULL)
+ return;
+
+ g_hash_table_iter_init (&iter, contacts);
+ while (g_hash_table_iter_next (&iter, NULL, &v))
+ {
+ EmpathyRosterContact *contact =v;
+
+ empathy_roster_contact_set_event_icon (contact, icon);
+ }
+}
+
+static void
+flash_event (Event *event,
+ EmpathyRosterView *self)
+{
+ set_event_icon_on_individual (self, event->individual, event->icon);
+}
+
+static void
+unflash_event (Event *event,
+ EmpathyRosterView *self)
+{
+ set_event_icon_on_individual (self, event->individual, NULL);
+}
+
+static gboolean
+flash_cb (gpointer data)
+{
+ EmpathyRosterView *self = data;
+
+ if (self->priv->display_flash_event)
+ {
+ g_queue_foreach (self->priv->events, (GFunc) flash_event, self);
+ self->priv->display_flash_event = FALSE;
+ }
+ else
+ {
+ g_queue_foreach (self->priv->events, (GFunc) unflash_event, self);
+ self->priv->display_flash_event = TRUE;
+ }
+
+ return TRUE;
+}
+
+static void
+start_flashing (EmpathyRosterView *self)
+{
+ if (self->priv->flash_id != 0)
+ return;
+
+ self->priv->display_flash_event = TRUE;
+
+ self->priv->flash_id = g_timeout_add (FLASH_TIMEOUT,
+ flash_cb, self);
+}
+
+static void
+stop_flashing (EmpathyRosterView *self)
+{
+ if (self->priv->flash_id == 0)
+ return;
+
+ g_source_remove (self->priv->flash_id);
+ self->priv->flash_id = 0;
+}
+
+static void
+remove_event (EmpathyRosterView *self,
+ Event *event)
+{
+ unflash_event (event, self);
+ g_queue_remove (self->priv->events, event);
+
+ if (g_queue_get_length (self->priv->events) == 0)
+ {
+ stop_flashing (self);
+ }
+}
+
+static void
+remove_all_individual_event (EmpathyRosterView *self,
+ FolksIndividual *individual)
+{
+ GList *l;
+
+ for (l = g_queue_peek_head_link (self->priv->events); l != NULL;
+ l = g_list_next (l))
+ {
+ Event *event = l->data;
+
+ if (event->individual == individual)
+ {
+ remove_event (self, event);
+ return;
+ }
+ }
+}
+
+static void
individual_removed (EmpathyRosterView *self,
FolksIndividual *individual)
{
@@ -292,6 +445,8 @@ individual_removed (EmpathyRosterView *self,
if (contacts == NULL)
return;
+ remove_all_individual_event (self, individual);
+
g_hash_table_iter_init (&iter, contacts);
while (g_hash_table_iter_next (&iter, &key, &value))
{
@@ -826,6 +981,8 @@ empathy_roster_view_dispose (GObject *object)
void (*chain_up) (GObject *) =
((GObjectClass *) empathy_roster_view_parent_class)->dispose;
+ stop_flashing (self);
+
empathy_roster_view_set_live_search (self, NULL);
g_clear_object (&self->priv->manager);
@@ -843,6 +1000,7 @@ empathy_roster_view_finalize (GObject *object)
g_hash_table_unref (self->priv->roster_contacts);
g_hash_table_unref (self->priv->roster_groups);
g_hash_table_unref (self->priv->displayed_contacts);
+ g_queue_free_full (self->priv->events, event_free);
if (chain_up != NULL)
chain_up (object);
@@ -852,8 +1010,10 @@ static void
empathy_roster_view_child_activated (EggListBox *box,
GtkWidget *child)
{
+ EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (box);
EmpathyRosterContact *contact;
FolksIndividual *individual;
+ GList *l;
if (!EMPATHY_IS_ROSTER_CONTACT (child))
return;
@@ -861,6 +1021,20 @@ empathy_roster_view_child_activated (EggListBox *box,
contact = EMPATHY_ROSTER_CONTACT (child);
individual = empathy_roster_contact_get_individual (contact);
+ /* Activate the oldest event associated with this contact, if any */
+ for (l = g_queue_peek_tail_link (self->priv->events); l != NULL;
+ l = g_list_previous (l))
+ {
+ Event *event = l->data;
+
+ if (event->individual == individual)
+ {
+ g_signal_emit (box, signals[SIG_EVENT_ACTIVATED], 0, individual,
+ event->user_data);
+ return;
+ }
+ }
+
g_signal_emit (box, signals[SIG_INDIVIDUAL_ACTIVATED], 0, individual);
}
@@ -1038,6 +1212,13 @@ empathy_roster_view_class_init (
G_TYPE_NONE,
3, FOLKS_TYPE_INDIVIDUAL, G_TYPE_UINT, G_TYPE_UINT);
+ signals[SIG_EVENT_ACTIVATED] = g_signal_new ("event-activated",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 2, FOLKS_TYPE_INDIVIDUAL, G_TYPE_POINTER);
+
g_type_class_add_private (klass, sizeof (EmpathyRosterViewPriv));
}
@@ -1053,6 +1234,8 @@ empathy_roster_view_init (EmpathyRosterView *self)
g_free, NULL);
self->priv->displayed_contacts = g_hash_table_new (NULL, NULL);
+ self->priv->events = g_queue_new ();
+
self->priv->empty = TRUE;
}
@@ -1194,3 +1377,46 @@ empathy_roster_view_is_searching (EmpathyRosterView *self)
return (self->priv->search != NULL &&
gtk_widget_get_visible (GTK_WIDGET (self->priv->search)));
}
+
+/* Don't use EmpathyEvent as I prefer to keep this object not too specific to
+ * Empathy's internals. */
+guint
+empathy_roster_view_add_event (EmpathyRosterView *self,
+ FolksIndividual *individual,
+ const gchar *icon,
+ gpointer user_data)
+{
+ GHashTable *contacts;
+
+ contacts = g_hash_table_lookup (self->priv->roster_contacts, individual);
+ if (contacts == NULL)
+ return 0;
+
+ self->priv->last_event_id++;
+
+ g_queue_push_head (self->priv->events,
+ event_new (self->priv->last_event_id, individual, icon, user_data));
+
+ start_flashing (self);
+
+ return self->priv->last_event_id;
+}
+
+void
+empathy_roster_view_remove_event (EmpathyRosterView *self,
+ guint event_id)
+{
+ GList *l;
+
+ for (l = g_queue_peek_head_link (self->priv->events); l != NULL;
+ l = g_list_next (l))
+ {
+ Event *event = l->data;
+
+ if (event->id == event_id)
+ {
+ remove_event (self, event);
+ return;
+ }
+ }
+}
diff --git a/libempathy-gtk/empathy-roster-view.h b/libempathy-gtk/empathy-roster-view.h
index 7a87bea7a..c3d475b0b 100644
--- a/libempathy-gtk/empathy-roster-view.h
+++ b/libempathy-gtk/empathy-roster-view.h
@@ -79,6 +79,14 @@ gboolean empathy_roster_view_is_empty (EmpathyRosterView *self);
gboolean empathy_roster_view_is_searching (EmpathyRosterView *self);
+guint empathy_roster_view_add_event (EmpathyRosterView *self,
+ FolksIndividual *individual,
+ const gchar *icon,
+ gpointer user_data);
+
+void empathy_roster_view_remove_event (EmpathyRosterView *self,
+ guint event_id);
+
G_END_DECLS
#endif /* #ifndef __EMPATHY_ROSTER_VIEW_H__*/
diff --git a/src/empathy-event-manager.h b/src/empathy-event-manager.h
index 394db8d9c..70af9a1c2 100644
--- a/src/empathy-event-manager.h
+++ b/src/empathy-event-manager.h
@@ -69,6 +69,7 @@ typedef struct {
gchar *message;
gboolean must_ack;
GObject *handler_instance;
+ guint roster_view_id;
} EmpathyEvent;
GType empathy_event_manager_get_type (void) G_GNUC_CONST;