From 976d656a08ded1864324b6060ef035ffcb0b833b Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 6 Jun 2007 09:10:23 +0000 Subject: Add support for blinking when there is an event. Make use of EmpathyIdle 2007-06-06 Xavier Claessens * libempathy-gtk/empathy-status-icon.c: Add support for blinking when there is an event. Make use of EmpathyIdle for presence handling. Add an event when a contact requets subscription. * libempathy-gtk/gossip-contact-list-store.c: * libempathy-gtk/gossip-contact-list-view.c: * libempathy/empathy-contact-manager.c: * libempathy/empathy-tp-contact-list.c: * libempathy/empathy-tp-chatroom.c: * libempathy/empathy-contact-list.c: * libempathy/empathy-contact-list.h: get_contacts() is renamed to get_members(). Adding a signal and a method for local-pending with contacts with the message. Rework completely the contact-list handling in EmpathyTpContactList to follow tp spec. * libempathy/empathy-idle.c: * libempathy/empathy-idle.h: Add properties for the state and the status message. EmpathyIdle is now a singleton to manager self presence. * TODO: Updated. svn path=/trunk/; revision=123 --- libempathy-gtk/empathy-status-icon.c | 333 +++++++++++++++++++++++------ libempathy-gtk/gossip-contact-list-store.c | 6 +- libempathy-gtk/gossip-contact-list-view.c | 2 +- 3 files changed, 274 insertions(+), 67 deletions(-) (limited to 'libempathy-gtk') diff --git a/libempathy-gtk/empathy-status-icon.c b/libempathy-gtk/empathy-status-icon.c index 01a542493..5c364083b 100644 --- a/libempathy-gtk/empathy-status-icon.c +++ b/libempathy-gtk/empathy-status-icon.c @@ -26,9 +26,13 @@ #include #include +#include #include +#include +#include +#include #include #include #include @@ -46,42 +50,74 @@ #define DEBUG_DOMAIN "StatusIcon" +/* Number of ms to wait when blinking */ +#define BLINK_TIMEOUT 500 + struct _EmpathyStatusIconPriv { - MissionControl *mc; - GtkStatusIcon *icon; - EmpathyIdle *idle; + GtkStatusIcon *icon; + EmpathyContactManager *manager; + EmpathyIdle *idle; + GList *events; + guint blink_timeout; + gboolean showing_state_icon; + + GtkWindow *window; + + GtkWidget *popup_menu; + GtkWidget *show_window_item; + GtkWidget *message_item; + GtkWidget *status_item; +}; - GtkWindow *window; +typedef struct _StatusIconEvent StatusIconEvent; - GtkWidget *popup_menu; - GtkWidget *show_window_item; - GtkWidget *message_item; - GtkWidget *status_item; +typedef void (*EventActivatedFunc) (StatusIconEvent *event); + +struct _StatusIconEvent { + gchar *icon_name; + gchar *message; + EventActivatedFunc func; + gpointer user_data; }; -static void empathy_status_icon_class_init (EmpathyStatusIconClass *klass); -static void empathy_status_icon_init (EmpathyStatusIcon *icon); -static void status_icon_finalize (GObject *object); -static void status_icon_presence_changed_cb (MissionControl *mc, - McPresence state, - EmpathyStatusIcon *icon); -static void status_icon_toggle_visibility (EmpathyStatusIcon *icon); -static void status_icon_activate_cb (GtkStatusIcon *status_icon, - EmpathyStatusIcon *icon); -static gboolean status_icon_delete_event_cb (GtkWidget *widget, - GdkEvent *event, - EmpathyStatusIcon *icon); -static void status_icon_popup_menu_cb (GtkStatusIcon *status_icon, - guint button, - guint activate_time, - EmpathyStatusIcon *icon); -static void status_icon_create_menu (EmpathyStatusIcon *icon); -static void status_icon_new_message_cb (GtkWidget *widget, - EmpathyStatusIcon *icon); -static void status_icon_quit_cb (GtkWidget *window, - EmpathyStatusIcon *icon); -static void status_icon_show_hide_window_cb (GtkWidget *widget, - EmpathyStatusIcon *icon); + +static void empathy_status_icon_class_init (EmpathyStatusIconClass *klass); +static void empathy_status_icon_init (EmpathyStatusIcon *icon); +static void status_icon_finalize (GObject *object); +static void status_icon_idle_notify_cb (EmpathyIdle *idle, + GParamSpec *param, + EmpathyStatusIcon *icon); +static void status_icon_update_tooltip (EmpathyStatusIcon *icon); +static void status_icon_set_from_state (EmpathyStatusIcon *icon); +static void status_icon_toggle_visibility (EmpathyStatusIcon *icon); +static void status_icon_activate_cb (GtkStatusIcon *status_icon, + EmpathyStatusIcon *icon); +static gboolean status_icon_delete_event_cb (GtkWidget *widget, + GdkEvent *event, + EmpathyStatusIcon *icon); +static void status_icon_popup_menu_cb (GtkStatusIcon *status_icon, + guint button, + guint activate_time, + EmpathyStatusIcon *icon); +static void status_icon_create_menu (EmpathyStatusIcon *icon); +static void status_icon_new_message_cb (GtkWidget *widget, + EmpathyStatusIcon *icon); +static void status_icon_quit_cb (GtkWidget *window, + EmpathyStatusIcon *icon); +static void status_icon_show_hide_window_cb (GtkWidget *widget, + EmpathyStatusIcon *icon); +static void status_icon_local_pending_cb (EmpathyContactManager *manager, + GossipContact *contact, + gchar *message, + EmpathyStatusIcon *icon); +static void status_icon_event_subscribe_cb (StatusIconEvent *event); +static StatusIconEvent * status_icon_event_new (EmpathyStatusIcon *icon, + const gchar *icon_name, + const gchar *message); +static void status_icon_event_remove (EmpathyStatusIcon *icon, + StatusIconEvent *event); +static gboolean status_icon_event_timeout_cb (EmpathyStatusIcon *icon); +static void status_icon_event_free (StatusIconEvent *event); G_DEFINE_TYPE (EmpathyStatusIcon, empathy_status_icon, G_TYPE_OBJECT); @@ -99,29 +135,43 @@ static void empathy_status_icon_init (EmpathyStatusIcon *icon) { EmpathyStatusIconPriv *priv; - McPresence state; + GList *pending, *l; priv = GET_PRIV (icon); priv->icon = gtk_status_icon_new (); - priv->mc = gossip_mission_control_new (); priv->idle = empathy_idle_new (); + priv->manager = empathy_contact_manager_new (); + priv->showing_state_icon = TRUE; status_icon_create_menu (icon); + status_icon_set_from_state (icon); + status_icon_update_tooltip (icon); - state = mission_control_get_presence_actual (priv->mc, NULL); - status_icon_presence_changed_cb (priv->mc, state, icon); - - dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), - "PresenceStatusActual", - G_CALLBACK (status_icon_presence_changed_cb), - icon, NULL); + g_signal_connect (priv->idle, "notify", + G_CALLBACK (status_icon_idle_notify_cb), + icon); g_signal_connect (priv->icon, "activate", G_CALLBACK (status_icon_activate_cb), icon); g_signal_connect (priv->icon, "popup-menu", G_CALLBACK (status_icon_popup_menu_cb), icon); + g_signal_connect (priv->manager, "local-pending", + G_CALLBACK (status_icon_local_pending_cb), + icon); + + pending = empathy_contact_list_get_local_pending (EMPATHY_CONTACT_LIST (priv->manager)); + for (l = pending; l; l = l->next) { + EmpathyContactListInfo *info; + + info = l->data; + status_icon_local_pending_cb (priv->manager, + info->contact, + info->message, + icon); + } + g_list_free (pending); } static void @@ -131,15 +181,17 @@ status_icon_finalize (GObject *object) priv = GET_PRIV (object); - dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), - "PresenceStatusActual", - G_CALLBACK (status_icon_presence_changed_cb), - object); + g_list_foreach (priv->events, (GFunc) status_icon_event_free, NULL); + g_list_free (priv->events); + + if (priv->blink_timeout) { + g_source_remove (priv->blink_timeout); + } - g_object_unref (priv->mc); g_object_unref (priv->icon); g_object_unref (priv->window); g_object_unref (priv->idle); + g_object_unref (priv->manager); } EmpathyStatusIcon * @@ -174,33 +226,55 @@ empathy_status_icon_new (GtkWindow *window) } static void -status_icon_presence_changed_cb (MissionControl *mc, - McPresence state, - EmpathyStatusIcon *icon) +status_icon_idle_notify_cb (EmpathyIdle *idle, + GParamSpec *param, + EmpathyStatusIcon *icon) { EmpathyStatusIconPriv *priv; - const gchar *icon_name; - gchar *status; priv = GET_PRIV (icon); - icon_name = gossip_icon_name_for_presence_state (state); - status = mission_control_get_presence_message_actual (priv->mc, NULL); - if (G_STR_EMPTY (status)) { - g_free (status); - status = g_strdup (gossip_presence_state_get_default_status (state)); + if (priv->showing_state_icon) { + status_icon_set_from_state (icon); } - gtk_status_icon_set_from_icon_name (priv->icon, icon_name); - gtk_status_icon_set_tooltip (priv->icon, status); + status_icon_update_tooltip (icon); +} + +static void +status_icon_update_tooltip (EmpathyStatusIcon *icon) +{ + EmpathyStatusIconPriv *priv; + const gchar *tooltip = NULL; - g_free (status); + priv = GET_PRIV (icon); - if (state < MC_PRESENCE_AVAILABLE) { - gtk_widget_set_sensitive (priv->message_item, FALSE); - } else { - gtk_widget_set_sensitive (priv->message_item, TRUE); + if (priv->events) { + StatusIconEvent *event; + + event = priv->events->data; + tooltip = event->message; + } + + if (!tooltip) { + tooltip = empathy_idle_get_status (priv->idle); } + + gtk_status_icon_set_tooltip (priv->icon, tooltip); +} + +static void +status_icon_set_from_state (EmpathyStatusIcon *icon) +{ + EmpathyStatusIconPriv *priv; + McPresence state; + const gchar *icon_name; + + priv = GET_PRIV (icon); + + state = empathy_idle_get_state (priv->idle); + icon_name = gossip_icon_name_for_presence_state (state); + gtk_status_icon_set_from_icon_name (priv->icon, icon_name); } static void @@ -240,7 +314,15 @@ static void status_icon_activate_cb (GtkStatusIcon *status_icon, EmpathyStatusIcon *icon) { - status_icon_toggle_visibility (icon); + EmpathyStatusIconPriv *priv; + + priv = GET_PRIV (icon); + + if (priv->events) { + status_icon_event_remove (icon, priv->events->data); + } else { + status_icon_toggle_visibility (icon); + } } static gboolean @@ -343,3 +425,128 @@ status_icon_show_hide_window_cb (GtkWidget *widget, status_icon_toggle_visibility (icon); } +static void +status_icon_local_pending_cb (EmpathyContactManager *manager, + GossipContact *contact, + gchar *message, + EmpathyStatusIcon *icon) +{ + EmpathyStatusIconPriv *priv; + StatusIconEvent *event; + gchar *str; + GList *l; + + priv = GET_PRIV (icon); + + for (l = priv->events; l; l = l->next) { + if (gossip_contact_equal (contact, ((StatusIconEvent*)l->data)->user_data)) { + return; + } + } + + str = g_strdup_printf (_("Subscription requested for %s\n" + "Message: %s"), + gossip_contact_get_name (contact), + message); + + event = status_icon_event_new (icon, GTK_STOCK_DIALOG_QUESTION, str); + event->user_data = g_object_ref (contact); + event->func = status_icon_event_subscribe_cb; + + g_free (str); +} + +static void +status_icon_event_subscribe_cb (StatusIconEvent *event) +{ + GossipContact *contact; + + contact = GOSSIP_CONTACT (event->user_data); + + g_object_unref (contact); +} + +static StatusIconEvent * +status_icon_event_new (EmpathyStatusIcon *icon, + const gchar *icon_name, + const gchar *message) +{ + EmpathyStatusIconPriv *priv; + StatusIconEvent *event; + + priv = GET_PRIV (icon); + + event = g_slice_new0 (StatusIconEvent); + event->icon_name = g_strdup (icon_name); + event->message = g_strdup (message); + + priv->events = g_list_append (priv->events, event); + if (!priv->blink_timeout) { + priv->blink_timeout = g_timeout_add (BLINK_TIMEOUT, + (GSourceFunc) status_icon_event_timeout_cb, + icon); + status_icon_event_timeout_cb (icon); + } + + return event; +} + +static void +status_icon_event_remove (EmpathyStatusIcon *icon, + StatusIconEvent *event) +{ + EmpathyStatusIconPriv *priv; + + priv = GET_PRIV (icon); + + if (event->func) { + event->func (event); + } + priv->events = g_list_remove (priv->events, event); + status_icon_event_free (event); + status_icon_update_tooltip (icon); + + if (priv->events) { + return; + } + + status_icon_set_from_state (icon); + priv->showing_state_icon = TRUE; + + if (priv->blink_timeout) { + g_source_remove (priv->blink_timeout); + priv->blink_timeout = 0; + + } +} + +static gboolean +status_icon_event_timeout_cb (EmpathyStatusIcon *icon) +{ + EmpathyStatusIconPriv *priv; + + priv = GET_PRIV (icon); + + priv->showing_state_icon = !priv->showing_state_icon; + + if (priv->showing_state_icon) { + status_icon_set_from_state (icon); + } else { + StatusIconEvent *event; + + event = priv->events->data; + gtk_status_icon_set_from_icon_name (priv->icon, event->icon_name); + } + status_icon_update_tooltip (icon); + + return TRUE; +} + +static void +status_icon_event_free (StatusIconEvent *event) +{ + g_free (event->icon_name); + g_free (event->message); + g_slice_free (StatusIconEvent, event); +} + diff --git a/libempathy-gtk/gossip-contact-list-store.c b/libempathy-gtk/gossip-contact-list-store.c index f0ff476dd..4a5b5506e 100644 --- a/libempathy-gtk/gossip-contact-list-store.c +++ b/libempathy-gtk/gossip-contact-list-store.c @@ -343,7 +343,7 @@ gossip_contact_list_store_new (EmpathyContactList *list_iface) /* Add contacts already created. Do not highlight them. */ show_active = priv->show_active; priv->show_active = FALSE; - contacts = empathy_contact_list_get_contacts (priv->list); + contacts = empathy_contact_list_get_members (priv->list); for (l = contacts; l; l = l->next) { GossipContact *contact; @@ -401,7 +401,7 @@ gossip_contact_list_store_set_show_offline (GossipContactListStore *store, /* Disable temporarily. */ priv->show_active = FALSE; - contacts = empathy_contact_list_get_contacts (priv->list); + contacts = empathy_contact_list_get_members (priv->list); for (l = contacts; l; l = l->next) { GossipContact *contact; @@ -654,7 +654,7 @@ gossip_contact_list_store_set_contact_groups_func (GossipContactListStore *stor * to call himself gossip_contact_list_store_update_contact_groups () * when needed. If func is NULL we come back to default. */ - contacts = empathy_contact_list_get_contacts (priv->list); + contacts = empathy_contact_list_get_members (priv->list); for (l = contacts; l; l = l->next) { GossipContact *contact; diff --git a/libempathy-gtk/gossip-contact-list-view.c b/libempathy-gtk/gossip-contact-list-view.c index 3cad7821d..368ba8be4 100644 --- a/libempathy-gtk/gossip-contact-list-view.c +++ b/libempathy-gtk/gossip-contact-list-view.c @@ -1383,7 +1383,7 @@ contact_list_view_filter_show_group (GossipContactListView *view, * show exists in it. */ list = gossip_contact_list_store_get_list_iface (priv->store); - contacts = empathy_contact_list_get_contacts (list); + contacts = empathy_contact_list_get_members (list); for (l = contacts; l && !show_group; l = l->next) { if (!gossip_contact_is_in_group (l->data, group)) { continue; -- cgit v1.2.3