From 976d656a08ded1864324b6060ef035ffcb0b833b Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 6 Jun 2007 09:10:23 +0000 Subject: [PATCH] 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 --- ChangeLog | 23 ++ TODO | 8 +- libempathy-gtk/empathy-status-icon.c | 333 +++++++++++++++---- libempathy-gtk/gossip-contact-list-store.c | 6 +- libempathy-gtk/gossip-contact-list-view.c | 2 +- libempathy/empathy-contact-list.c | 58 +++- libempathy/empathy-contact-list.h | 52 +-- libempathy/empathy-contact-manager.c | 78 ++++- libempathy/empathy-idle.c | 233 +++++++++++++- libempathy/empathy-idle.h | 15 +- libempathy/empathy-marshal.list | 8 +- libempathy/empathy-tp-chatroom.c | 14 +- libempathy/empathy-tp-contact-list.c | 355 ++++++++++++--------- 13 files changed, 898 insertions(+), 287 deletions(-) diff --git a/ChangeLog b/ChangeLog index c54d06c6..c7b9ecb8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +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. + 2007-06-03 Xavier Claessens * libempathy-gtk/gossip-accounts-dialog.glade: Set use_stock for diff --git a/TODO b/TODO index f6d5d9cd..5be759c2 100644 --- a/TODO +++ b/TODO @@ -1,15 +1,13 @@ Things you can do if you want to help: - - Rename all files and functions name to use the empathy namespace. + - Rename all files and functions name to use the empathy namespace. Bug #444490. - Porting gossip-account-widget-*.{c,h} from gossip project (Guillaume is already working on IRC widget). - Porting various UI widgets from gossip to libempathy-gtk for contact info, adding contact, personal info, etc. - GtkWidget-ify gossip widgets imported in libempathy-gtk. Actually most window/dialog do not inherit from GtkWindow/GtkDialog. Need to create a glade catalog. - - Fix setting subscription for contacts in EmpathyTpContactList. - - Filter channels before dispatching them. For example we need a GtkStatusIcon that blink when an event arrives (text/voip/ft channel) and tells the MC to dispatch the channel only when the user clicked the icon. Like in gossip. For that we need a filter DBus API in MC, not yet written. + - Filter channels before dispatching them. For example we need a GtkStatusIcon that blink when an event arrives (text/voip/ft channel) and tells the MC to dispatch the channel only when the user clicked the icon. Like in gossip. For that we need a filter DBus API in MC, not yet written, a draft spec is proposed on the telepathy ML. - Make use of NetworkManager to set the presence - Remove Quit option everywhere, empathy is a session service and shouldn't be leaved. - Add sound events - - Import loggin system from gossip - Add register capability in GossipAccountsDialog if the profile says it's supported. - Testing and Bugfixing. @@ -19,4 +17,4 @@ SoC projects: If you want to contribute you can ask for information at - #telepathy on freenode - - Telepathy's mailing list. + - Telepathy's mailing list: telepathy@lists.freedesktop.org diff --git a/libempathy-gtk/empathy-status-icon.c b/libempathy-gtk/empathy-status-icon.c index 01a54249..5c364083 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 f0ff476d..4a5b5506 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 3cad7821..368ba8be 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; diff --git a/libempathy/empathy-contact-list.c b/libempathy/empathy-contact-list.c index b7d02010..c55d0abf 100644 --- a/libempathy/empathy-contact-list.c +++ b/libempathy/empathy-contact-list.c @@ -23,6 +23,7 @@ #include "config.h" #include "empathy-contact-list.h" +#include "empathy-marshal.h" static void contact_list_base_init (gpointer klass); @@ -70,10 +71,49 @@ contact_list_base_init (gpointer klass) G_TYPE_NONE, 1, GOSSIP_TYPE_CONTACT); + g_signal_new ("local-pending", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + empathy_marshal_VOID__OBJECT_STRING, + G_TYPE_NONE, + 2, GOSSIP_TYPE_CONTACT, G_TYPE_STRING); + initialized = TRUE; } } +EmpathyContactListInfo * +empathy_contact_list_info_new (GossipContact *contact, + const gchar *message) +{ + EmpathyContactListInfo *info; + + g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); + + info = g_slice_new0 (EmpathyContactListInfo); + info->contact = g_object_ref (contact); + info->message = g_strdup (message); + + return info; +} + +void +empathy_contact_list_info_free (EmpathyContactListInfo *info) +{ + if (!info) { + return; + } + + if (info->contact) { + g_object_unref (info->contact); + } + g_free (info->message); + + g_slice_free (EmpathyContactListInfo, info); +} + void empathy_contact_list_setup (EmpathyContactList *list) { @@ -122,12 +162,24 @@ empathy_contact_list_remove (EmpathyContactList *list, } GList * -empathy_contact_list_get_contacts (EmpathyContactList *list) +empathy_contact_list_get_members (EmpathyContactList *list) +{ + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list), NULL); + + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_members) { + return EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_members (list); + } + + return NULL; +} + +GList * +empathy_contact_list_get_local_pending (EmpathyContactList *list) { g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list), NULL); - if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_contacts) { - return EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_contacts (list); + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_local_pending) { + return EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_local_pending (list); } return NULL; diff --git a/libempathy/empathy-contact-list.h b/libempathy/empathy-contact-list.h index 02ec3186..09f54621 100644 --- a/libempathy/empathy-contact-list.h +++ b/libempathy/empathy-contact-list.h @@ -37,33 +37,43 @@ G_BEGIN_DECLS typedef struct _EmpathyContactList EmpathyContactList; typedef struct _EmpathyContactListIface EmpathyContactListIface; +typedef struct { + GossipContact *contact; + gchar *message; +} EmpathyContactListInfo; + struct _EmpathyContactListIface { GTypeInterface base_iface; /* VTabled */ - void (*setup) (EmpathyContactList *list); - GossipContact * (*find) (EmpathyContactList *list, - const gchar *id); - void (*add) (EmpathyContactList *list, - GossipContact *contact, - const gchar *message); - void (*remove) (EmpathyContactList *list, - GossipContact *contact, - const gchar *message); - GList * (*get_contacts) (EmpathyContactList *list); + void (*setup) (EmpathyContactList *list); + GossipContact * (*find) (EmpathyContactList *list, + const gchar *id); + void (*add) (EmpathyContactList *list, + GossipContact *contact, + const gchar *message); + void (*remove) (EmpathyContactList *list, + GossipContact *contact, + const gchar *message); + GList * (*get_members) (EmpathyContactList *list); + GList * (*get_local_pending) (EmpathyContactList *list); }; -GType empathy_contact_list_get_type (void) G_GNUC_CONST; -void empathy_contact_list_setup (EmpathyContactList *list); -GossipContact * empathy_contact_list_find (EmpathyContactList *list, - const gchar *id); -void empathy_contact_list_add (EmpathyContactList *list, - GossipContact *contact, - const gchar *message); -void empathy_contact_list_remove (EmpathyContactList *list, - GossipContact *contact, - const gchar *message); -GList * empathy_contact_list_get_contacts (EmpathyContactList *list); +GType empathy_contact_list_get_type (void) G_GNUC_CONST; +EmpathyContactListInfo *empathy_contact_list_info_new (GossipContact *contact, + const gchar *message); +void empathy_contact_list_info_free (EmpathyContactListInfo *info); +void empathy_contact_list_setup (EmpathyContactList *list); +GossipContact * empathy_contact_list_find (EmpathyContactList *list, + const gchar *id); +void empathy_contact_list_add (EmpathyContactList *list, + GossipContact *contact, + const gchar *message); +void empathy_contact_list_remove (EmpathyContactList *list, + GossipContact *contact, + const gchar *message); +GList * empathy_contact_list_get_members (EmpathyContactList *list); +GList * empathy_contact_list_get_local_pending (EmpathyContactList *list); G_END_DECLS diff --git a/libempathy/empathy-contact-manager.c b/libempathy/empathy-contact-manager.c index fa62da98..5e5f09a4 100644 --- a/libempathy/empathy-contact-manager.c +++ b/libempathy/empathy-contact-manager.c @@ -65,7 +65,8 @@ static void contact_manager_add (EmpathyContactList static void contact_manager_remove (EmpathyContactList *manager, GossipContact *contact, const gchar *message); -static GList * contact_manager_get_contacts (EmpathyContactList *manager); +static GList * contact_manager_get_members (EmpathyContactList *manager); +static GList * contact_manager_get_local_pending (EmpathyContactList *manager); static void contact_manager_setup_foreach (McAccount *account, EmpathyTpContactList *list, EmpathyContactManager *manager); @@ -80,6 +81,10 @@ static void contact_manager_added_cb (EmpathyTpContactList static void contact_manager_removed_cb (EmpathyTpContactList *list, GossipContact *contact, EmpathyContactManager *manager); +static void contact_manager_local_pending_cb (EmpathyTpContactList *list, + GossipContact *contact, + const gchar *message, + EmpathyContactManager *manager); static void contact_manager_destroy_cb (EmpathyTpContactList *list, EmpathyContactManager *manager); static void contact_manager_rename_group_foreach (McAccount *account, @@ -88,7 +93,10 @@ static void contact_manager_rename_group_foreach (McAccount static void contact_manager_get_groups_foreach (McAccount *account, EmpathyTpContactList *list, GList **all_groups); -static void contact_manager_get_contacts_foreach (McAccount *account, +static void contact_manager_get_members_foreach (McAccount *account, + EmpathyTpContactList *list, + GList **contacts); +static void contact_manager_get_local_pending_foreach (McAccount *account, EmpathyTpContactList *list, GList **contacts); static void contact_manager_status_changed_cb (MissionControl *mc, @@ -115,11 +123,12 @@ empathy_contact_manager_class_init (EmpathyContactManagerClass *klass) static void contact_manager_iface_init (EmpathyContactListIface *iface) { - iface->setup = contact_manager_setup; - iface->find = contact_manager_find; - iface->add = contact_manager_add; - iface->remove = contact_manager_remove; - iface->get_contacts = contact_manager_get_contacts; + iface->setup = contact_manager_setup; + iface->find = contact_manager_find; + iface->add = contact_manager_add; + iface->remove = contact_manager_remove; + iface->get_members = contact_manager_get_members; + iface->get_local_pending = contact_manager_get_local_pending; } static void @@ -269,7 +278,7 @@ contact_manager_remove (EmpathyContactList *manager, } static GList * -contact_manager_get_contacts (EmpathyContactList *manager) +contact_manager_get_members (EmpathyContactList *manager) { EmpathyContactManagerPriv *priv; GList *contacts = NULL; @@ -279,12 +288,29 @@ contact_manager_get_contacts (EmpathyContactList *manager) priv = GET_PRIV (manager); g_hash_table_foreach (priv->lists, - (GHFunc) contact_manager_get_contacts_foreach, + (GHFunc) contact_manager_get_members_foreach, &contacts); return contacts; } +static GList * +contact_manager_get_local_pending (EmpathyContactList *manager) +{ + EmpathyContactManagerPriv *priv; + GList *pending = NULL; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); + + priv = GET_PRIV (manager); + + g_hash_table_foreach (priv->lists, + (GHFunc) contact_manager_get_local_pending_foreach, + &pending); + + return pending; +} + EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, McAccount *account) @@ -435,6 +461,9 @@ contact_manager_add_account (EmpathyContactManager *manager, g_signal_connect (list, "contact-removed", G_CALLBACK (contact_manager_removed_cb), manager); + g_signal_connect (list, "local-pending", + G_CALLBACK (contact_manager_local_pending_cb), + manager); g_signal_connect (list, "destroy", G_CALLBACK (contact_manager_destroy_cb), manager); @@ -460,6 +489,15 @@ contact_manager_removed_cb (EmpathyTpContactList *list, g_signal_emit_by_name (manager, "contact-removed", contact); } +static void +contact_manager_local_pending_cb (EmpathyTpContactList *list, + GossipContact *contact, + const gchar *message, + EmpathyContactManager *manager) +{ + g_signal_emit_by_name (manager, "local-pending", contact, message); +} + static void contact_manager_destroy_cb (EmpathyTpContactList *list, EmpathyContactManager *manager) @@ -481,6 +519,9 @@ contact_manager_destroy_cb (EmpathyTpContactList *list, g_signal_handlers_disconnect_by_func (list, contact_manager_removed_cb, manager); + g_signal_handlers_disconnect_by_func (list, + contact_manager_local_pending_cb, + manager); g_signal_handlers_disconnect_by_func (list, contact_manager_destroy_cb, manager); @@ -520,13 +561,24 @@ contact_manager_get_groups_foreach (McAccount *account, } static void -contact_manager_get_contacts_foreach (McAccount *account, - EmpathyTpContactList *list, - GList **contacts) +contact_manager_get_members_foreach (McAccount *account, + EmpathyTpContactList *list, + GList **contacts) +{ + GList *l; + + l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list)); + *contacts = g_list_concat (*contacts, l); +} + +static void +contact_manager_get_local_pending_foreach (McAccount *account, + EmpathyTpContactList *list, + GList **contacts) { GList *l; - l = empathy_contact_list_get_contacts (EMPATHY_CONTACT_LIST (list)); + l = empathy_contact_list_get_local_pending (EMPATHY_CONTACT_LIST (list)); *contacts = g_list_concat (*contacts, l); } diff --git a/libempathy/empathy-idle.c b/libempathy/empathy-idle.c index 6b9cfb3b..f9b50bd4 100644 --- a/libempathy/empathy-idle.c +++ b/libempathy/empathy-idle.c @@ -27,8 +27,6 @@ #include -#include - #include "empathy-idle.h" #include "gossip-utils.h" #include "gossip-debug.h" @@ -49,6 +47,9 @@ struct _EmpathyIdlePriv { MissionControl *mc; DBusGProxy *gs_proxy; gboolean is_idle; + McPresence state; + McPresence slack_state; + gchar *status; McPresence saved_state; gchar *saved_status; guint ext_away_timeout; @@ -57,6 +58,17 @@ struct _EmpathyIdlePriv { static void empathy_idle_class_init (EmpathyIdleClass *klass); static void empathy_idle_init (EmpathyIdle *idle); static void idle_finalize (GObject *object); +static void idle_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void idle_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void idle_presence_changed_cb (MissionControl *mc, + McPresence state, + EmpathyIdle *idle); static void idle_session_idle_changed_cb (DBusGProxy *gs_proxy, gboolean is_idle, EmpathyIdle *idle); @@ -64,7 +76,12 @@ static void idle_ext_away_start (EmpathyIdle *idle); static void idle_ext_away_stop (EmpathyIdle *idle); static gboolean idle_ext_away_cb (EmpathyIdle *idle); -//static guint signals[LAST_SIGNAL]; +enum { + PROP_0, + PROP_STATE, + PROP_STATUS, + PROP_SLACK_STATE +}; G_DEFINE_TYPE (EmpathyIdle, empathy_idle, G_TYPE_OBJECT) @@ -74,6 +91,34 @@ empathy_idle_class_init (EmpathyIdleClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = idle_finalize; + object_class->get_property = idle_get_property; + object_class->set_property = idle_set_property; + + g_object_class_install_property (object_class, + PROP_STATE, + g_param_spec_uint ("state", + "state", + "state", + MC_PRESENCE_UNSET, + LAST_MC_PRESENCE, + MC_PRESENCE_AVAILABLE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_STATUS, + g_param_spec_string ("status", + "status", + "status", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SLACK_STATE, + g_param_spec_uint ("slack-state", + "slack-state", + "slack-state", + MC_PRESENCE_UNSET, + LAST_MC_PRESENCE, + MC_PRESENCE_UNSET, + G_PARAM_READWRITE)); g_type_class_add_private (object_class, sizeof (EmpathyIdlePriv)); } @@ -87,6 +132,8 @@ empathy_idle_init (EmpathyIdle *idle) priv->is_idle = FALSE; priv->mc = gossip_mission_control_new (); + priv->state = mission_control_get_presence_actual (priv->mc, NULL); + priv->status = mission_control_get_presence_message_actual (priv->mc, NULL); priv->gs_proxy = dbus_g_proxy_new_for_name (tp_get_bus (), "org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", @@ -102,6 +149,10 @@ empathy_idle_init (EmpathyIdle *idle) dbus_g_proxy_connect_signal (priv->gs_proxy, "SessionIdleChanged", G_CALLBACK (idle_session_idle_changed_cb), idle, NULL); + dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), + "PresenceStatusActual", + G_CALLBACK (idle_presence_changed_cb), + idle, NULL); } static void @@ -111,6 +162,7 @@ idle_finalize (GObject *object) priv = GET_PRIV (object); + g_free (priv->status); g_free (priv->saved_status); g_object_unref (priv->mc); @@ -121,6 +173,62 @@ idle_finalize (GObject *object) idle_ext_away_stop (EMPATHY_IDLE (object)); } +static void +idle_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyIdlePriv *priv; + EmpathyIdle *idle; + + priv = GET_PRIV (object); + idle = EMPATHY_IDLE (object); + + switch (param_id) { + case PROP_STATE: + g_value_set_uint (value, empathy_idle_get_state (idle)); + break; + case PROP_STATUS: + g_value_set_string (value, empathy_idle_get_status (idle)); + break; + case PROP_SLACK_STATE: + g_value_set_uint (value, empathy_idle_get_slack_state (idle)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +idle_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyIdlePriv *priv; + EmpathyIdle *idle; + + priv = GET_PRIV (object); + idle = EMPATHY_IDLE (object); + + switch (param_id) { + case PROP_STATE: + empathy_idle_set_state (idle, g_value_get_uint (value)); + break; + case PROP_STATUS: + empathy_idle_set_status (idle, g_value_get_string (value)); + break; + case PROP_SLACK_STATE: + empathy_idle_set_slack_state (idle, g_value_get_uint (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + EmpathyIdle * empathy_idle_new (void) { @@ -136,6 +244,99 @@ empathy_idle_new (void) return idle; } +McPresence +empathy_idle_get_state (EmpathyIdle *idle) +{ + EmpathyIdlePriv *priv; + + priv = GET_PRIV (idle); + + return priv->state; +} + +void +empathy_idle_set_state (EmpathyIdle *idle, + McPresence state) +{ + EmpathyIdlePriv *priv; + + priv = GET_PRIV (idle); + + mission_control_set_presence (priv->mc, + state, + priv->status, + NULL, NULL); +} + +const gchar * +empathy_idle_get_status (EmpathyIdle *idle) +{ + EmpathyIdlePriv *priv; + + priv = GET_PRIV (idle); + + return priv->status; +} + +void +empathy_idle_set_status (EmpathyIdle *idle, + const gchar *status) +{ + EmpathyIdlePriv *priv; + + priv = GET_PRIV (idle); + + mission_control_set_presence (priv->mc, + priv->state, + status, + NULL, NULL); +} + +McPresence +empathy_idle_get_slack_state (EmpathyIdle *idle) +{ + EmpathyIdlePriv *priv; + + priv = GET_PRIV (idle); + + return priv->slack_state; +} + +void +empathy_idle_set_slack_state (EmpathyIdle *idle, + McPresence state) +{ + EmpathyIdlePriv *priv; + + priv = GET_PRIV (idle); + + priv->slack_state = state; + + g_object_notify (G_OBJECT (idle), "slack-state"); +} + +static void +idle_presence_changed_cb (MissionControl *mc, + McPresence state, + EmpathyIdle *idle) +{ + EmpathyIdlePriv *priv; + + priv = GET_PRIV (idle); + + g_free (priv->status); + priv->state = state; + priv->status = mission_control_get_presence_message_actual (priv->mc, NULL); + + if (G_STR_EMPTY (priv->status)) { + g_free (priv->status); + priv->status = g_strdup (gossip_presence_state_get_default_status (state)); + } + + g_object_notify (G_OBJECT (idle), "state"); + g_object_notify (G_OBJECT (idle), "status"); +} + static void idle_session_idle_changed_cb (DBusGProxy *gs_proxy, gboolean is_idle, @@ -150,30 +351,29 @@ idle_session_idle_changed_cb (DBusGProxy *gs_proxy, is_idle ? "yes" : "no"); if (is_idle && !priv->is_idle) { - McPresence new_state = MC_PRESENCE_AWAY; + McPresence new_state; /* We are now idle, set state to away */ - priv->saved_state = mission_control_get_presence_actual (priv->mc, NULL); - priv->saved_status = mission_control_get_presence_message_actual (priv->mc, NULL); - - if (priv->saved_state <= MC_PRESENCE_OFFLINE || - priv->saved_state == MC_PRESENCE_HIDDEN) { + if (priv->state <= MC_PRESENCE_OFFLINE || + priv->state == MC_PRESENCE_HIDDEN) { /* We are not online so nothing to do here */ return; - } else if (priv->saved_state == MC_PRESENCE_AWAY || - priv->saved_state == MC_PRESENCE_EXTENDED_AWAY) { + } else if (priv->state == MC_PRESENCE_AWAY || + priv->state == MC_PRESENCE_EXTENDED_AWAY) { /* User set away manually, when coming back we restore * default presence. */ - new_state = priv->saved_state; + new_state = priv->state; priv->saved_state = MC_PRESENCE_AVAILABLE; priv->saved_status = NULL; + } else { + new_state = MC_PRESENCE_AWAY; + priv->saved_state = priv->state; + priv->saved_status = g_strdup (priv->status); } gossip_debug (DEBUG_DOMAIN, "Going to autoaway"); - mission_control_set_presence (priv->mc, - new_state, - priv->saved_status, - NULL, NULL); + empathy_idle_set_state (idle, new_state); + idle_ext_away_start (idle); } else if (!is_idle && priv->is_idle) { /* We are no more idle, restore state */ @@ -187,6 +387,7 @@ idle_session_idle_changed_cb (DBusGProxy *gs_proxy, priv->saved_state, priv->saved_status, NULL, NULL); + g_free (priv->saved_status); priv->saved_status = NULL; } diff --git a/libempathy/empathy-idle.h b/libempathy/empathy-idle.h index df8846b9..13c5dd29 100644 --- a/libempathy/empathy-idle.h +++ b/libempathy/empathy-idle.h @@ -25,6 +25,8 @@ #include +#include + G_BEGIN_DECLS #define EMPATHY_TYPE_IDLE (empathy_idle_get_type ()) @@ -46,8 +48,17 @@ struct _EmpathyIdleClass { GObjectClass parent_class; }; -GType empathy_idle_get_type (void) G_GNUC_CONST; -EmpathyIdle *empathy_idle_new (void); +GType empathy_idle_get_type (void) G_GNUC_CONST; +EmpathyIdle *empathy_idle_new (void); +McPresence empathy_idle_get_state (EmpathyIdle *idle); +void empathy_idle_set_state (EmpathyIdle *idle, + McPresence state); +const gchar *empathy_idle_get_status (EmpathyIdle *idle); +void empathy_idle_set_status (EmpathyIdle *idle, + const gchar *message); +McPresence empathy_idle_get_slack_state (EmpathyIdle *idle); +void empathy_idle_set_slack_state (EmpathyIdle *idle, + McPresence state); G_END_DECLS diff --git a/libempathy/empathy-marshal.list b/libempathy/empathy-marshal.list index f13e9f08..3b36b7be 100644 --- a/libempathy/empathy-marshal.list +++ b/libempathy/empathy-marshal.list @@ -1,8 +1,10 @@ -VOID:POINTER,UINT,UINT,STRING VOID:OBJECT,UINT VOID:OBJECT,OBJECT -VOID:INT,STRING VOID:OBJECT,OBJECT,UINT -VOID:UINT,BOOLEAN VOID:OBJECT,BOOLEAN VOID:OBJECT,STRING,STRING +VOID:OBJECT,STRING +VOID:POINTER,UINT,UINT,STRING +VOID:INT,STRING +VOID:UINT,BOOLEAN + diff --git a/libempathy/empathy-tp-chatroom.c b/libempathy/empathy-tp-chatroom.c index eb47c9bb..232db30f 100644 --- a/libempathy/empathy-tp-chatroom.c +++ b/libempathy/empathy-tp-chatroom.c @@ -72,7 +72,7 @@ static void tp_chatroom_add (EmpathyContactList * static void tp_chatroom_remove (EmpathyContactList *list, GossipContact *contact, const gchar *message); -static GList * tp_chatroom_get_contacts (EmpathyContactList *list); +static GList * tp_chatroom_get_members (EmpathyContactList *list); G_DEFINE_TYPE_WITH_CODE (EmpathyTpChatroom, empathy_tp_chatroom, EMPATHY_TYPE_TP_CHAT, G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST, @@ -91,11 +91,11 @@ empathy_tp_chatroom_class_init (EmpathyTpChatroomClass *klass) static void tp_chatroom_iface_init (EmpathyContactListIface *iface) { - iface->setup = tp_chatroom_setup; - iface->find = tp_chatroom_find; - iface->add = tp_chatroom_add; - iface->remove = tp_chatroom_remove; - iface->get_contacts = tp_chatroom_get_contacts; + iface->setup = tp_chatroom_setup; + iface->find = tp_chatroom_find; + iface->add = tp_chatroom_add; + iface->remove = tp_chatroom_remove; + iface->get_members = tp_chatroom_get_members; } static void @@ -339,7 +339,7 @@ tp_chatroom_remove (EmpathyContactList *list, } static GList * -tp_chatroom_get_contacts (EmpathyContactList *list) +tp_chatroom_get_members (EmpathyContactList *list) { EmpathyTpChatroomPriv *priv; GArray *members; diff --git a/libempathy/empathy-tp-contact-list.c b/libempathy/empathy-tp-contact-list.c index 7668057e..284f5113 100644 --- a/libempathy/empathy-tp-contact-list.c +++ b/libempathy/empathy-tp-contact-list.c @@ -52,12 +52,12 @@ struct _EmpathyTpContactListPriv { GossipContact *user_contact; gboolean setup; - GossipTelepathyGroup *known; GossipTelepathyGroup *publish; GossipTelepathyGroup *subscribe; GHashTable *groups; GHashTable *contacts; + GList *local_pending; DBusGProxy *aliasing_iface; DBusGProxy *avatars_iface; @@ -67,7 +67,6 @@ struct _EmpathyTpContactListPriv { }; typedef enum { - TP_CONTACT_LIST_TYPE_KNOWN, TP_CONTACT_LIST_TYPE_PUBLISH, TP_CONTACT_LIST_TYPE_SUBSCRIBE, TP_CONTACT_LIST_TYPE_UNKNOWN, @@ -103,7 +102,10 @@ static void tp_contact_list_add (EmpathyC static void tp_contact_list_remove (EmpathyContactList *list, GossipContact *contact, const gchar *message); -static GList * tp_contact_list_get_contacts (EmpathyContactList *list); +static GList * tp_contact_list_get_members (EmpathyContactList *list); +static GList * tp_contact_list_get_local_pending (EmpathyContactList *list); +static void tp_contact_list_remove_local_pending (EmpathyTpContactList *list, + GossipContact *contact); static void tp_contact_list_contact_removed_foreach (guint handle, GossipContact *contact, EmpathyTpContactList *list); @@ -120,20 +122,20 @@ static void tp_contact_list_newchannel_cb (DBusGPro gboolean suppress_handle, EmpathyTpContactList *list); static TpContactListType tp_contact_list_get_type (EmpathyTpContactList *list, - TpChan *list_chan); -static void tp_contact_list_contact_added_cb (GossipTelepathyGroup *group, + GossipTelepathyGroup *group); +static void tp_contact_list_added_cb (GossipTelepathyGroup *group, GArray *handles, guint actor_handle, guint reason, const gchar *message, EmpathyTpContactList *list); -static void tp_contact_list_contact_removed_cb (GossipTelepathyGroup *group, +static void tp_contact_list_removed_cb (GossipTelepathyGroup *group, GArray *handles, guint actor_handle, guint reason, const gchar *message, EmpathyTpContactList *list); -static void tp_contact_list_local_pending_cb (GossipTelepathyGroup *group, +static void tp_contact_list_pending_cb (GossipTelepathyGroup *group, GArray *handles, guint actor_handle, guint reason, @@ -173,7 +175,7 @@ static void tp_contact_list_group_members_removed_cb (GossipTe guint reason, const gchar *message, EmpathyTpContactList *list); -static void tp_contact_list_get_contacts_foreach (guint handle, +static void tp_contact_list_get_members_foreach (guint handle, GossipContact *contact, GList **contacts); static void tp_contact_list_get_info (EmpathyTpContactList *list, @@ -248,11 +250,12 @@ empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass) static void tp_contact_list_iface_init (EmpathyContactListIface *iface) { - iface->setup = tp_contact_list_setup; - iface->find = tp_contact_list_find; - iface->add = tp_contact_list_add; - iface->remove = tp_contact_list_remove; - iface->get_contacts = tp_contact_list_get_contacts; + iface->setup = tp_contact_list_setup; + iface->find = tp_contact_list_find; + iface->add = tp_contact_list_add; + iface->remove = tp_contact_list_remove; + iface->get_members = tp_contact_list_get_members; + iface->get_local_pending = tp_contact_list_get_local_pending; } static void @@ -293,15 +296,9 @@ tp_contact_list_finalize (GObject *object) if (priv->tp_conn) { g_object_unref (priv->tp_conn); } - - if (priv->known) { - g_object_unref (priv->known); - } - if (priv->subscribe) { g_object_unref (priv->subscribe); } - if (priv->publish) { g_object_unref (priv->publish); } @@ -312,6 +309,9 @@ tp_contact_list_finalize (GObject *object) g_hash_table_destroy (priv->groups); g_hash_table_destroy (priv->contacts); + g_list_foreach (priv->local_pending, (GFunc) empathy_contact_list_info_free, NULL); + g_list_free (priv->local_pending); + G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object); } @@ -383,6 +383,7 @@ empathy_tp_contact_list_new (McAccount *account) error ? error->message : "No error given"); g_clear_error (&error); } else { + /* FIXME: this adds the handle to the roster */ priv->user_contact = empathy_tp_contact_list_get_from_handle (list, handle); } @@ -490,11 +491,10 @@ tp_contact_list_remove (EmpathyContactList *list, handle = gossip_contact_get_handle (contact); gossip_telepathy_group_remove_member (priv->subscribe, handle, message); gossip_telepathy_group_remove_member (priv->publish, handle, message); - gossip_telepathy_group_remove_member (priv->known, handle, message); } static GList * -tp_contact_list_get_contacts (EmpathyContactList *list) +tp_contact_list_get_members (EmpathyContactList *list) { EmpathyTpContactListPriv *priv; GList *contacts = NULL; @@ -503,14 +503,25 @@ tp_contact_list_get_contacts (EmpathyContactList *list) priv = GET_PRIV (list); - /* FIXME: we should only return contacts that are in the contact list */ g_hash_table_foreach (priv->contacts, - (GHFunc) tp_contact_list_get_contacts_foreach, + (GHFunc) tp_contact_list_get_members_foreach, &contacts); return contacts; } +static GList * +tp_contact_list_get_local_pending (EmpathyContactList *list) +{ + EmpathyTpContactListPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); + + priv = GET_PRIV (list); + + return g_list_copy (priv->local_pending); +} + McAccount * empathy_tp_contact_list_get_account (EmpathyTpContactList *list) { @@ -943,87 +954,77 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, if (handle_type == TP_HANDLE_TYPE_LIST) { TpContactListType list_type; - list_type = tp_contact_list_get_type (list, new_chan); + group = gossip_telepathy_group_new (new_chan, priv->tp_conn); + + list_type = tp_contact_list_get_type (list, group); if (list_type == TP_CONTACT_LIST_TYPE_UNKNOWN) { - gossip_debug (DEBUG_DOMAIN, "Unknown contact list channel"); + gossip_debug (DEBUG_DOMAIN, + "Type of contact list channel unknown: %s", + gossip_telepathy_group_get_name (group)); + g_object_unref (new_chan); + g_object_unref (group); return; + } else { + gossip_debug (DEBUG_DOMAIN, + "New contact list channel of type: %d", + list_type); } - gossip_debug (DEBUG_DOMAIN, "New contact list channel of type: %d", - list_type); + g_signal_connect (group, "members-added", + G_CALLBACK (tp_contact_list_added_cb), + list); + g_signal_connect (group, "members-removed", + G_CALLBACK (tp_contact_list_removed_cb), + list); - group = gossip_telepathy_group_new (new_chan, priv->tp_conn); + members = gossip_telepathy_group_get_members (group); + tp_contact_list_added_cb (group, members, 0, + TP_CHANNEL_GROUP_CHANGE_REASON_NONE, + NULL, list); + g_array_free (members, TRUE); + + if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { + GList *pendings, *l; - switch (list_type) { - case TP_CONTACT_LIST_TYPE_KNOWN: - if (priv->known) { - g_object_unref (priv->known); - } - priv->known = group; - break; - case TP_CONTACT_LIST_TYPE_PUBLISH: if (priv->publish) { g_object_unref (priv->publish); } priv->publish = group; - break; - case TP_CONTACT_LIST_TYPE_SUBSCRIBE: - if (priv->subscribe) { - g_object_unref (priv->subscribe); - } - priv->subscribe = group; - break; - default: - g_assert_not_reached (); - } - - /* Connect and setup the new contact-list group */ - if (list_type == TP_CONTACT_LIST_TYPE_KNOWN || - list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { - g_signal_connect (group, "members-added", - G_CALLBACK (tp_contact_list_contact_added_cb), - list); - g_signal_connect (group, "members-removed", - G_CALLBACK (tp_contact_list_contact_removed_cb), - list); - - members = gossip_telepathy_group_get_members (group); - tp_contact_list_contact_added_cb (group, members, 0, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE, - NULL, list); - g_array_free (members, TRUE); - } - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { - GList *members, *l; - GArray *pending; + /* Makes no sense to be in remote-pending */ g_signal_connect (group, "local-pending", - G_CALLBACK (tp_contact_list_local_pending_cb), + G_CALLBACK (tp_contact_list_pending_cb), list); - members = gossip_telepathy_group_get_local_pending_members_with_info (group); - if (!members) { - g_object_unref (new_chan); - return; + pendings = gossip_telepathy_group_get_local_pending_members_with_info (group); + if (pendings) { + GArray *pending; + + pending = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); + for (l = pendings; l; l = l->next) { + GossipTpGroupInfo *info; + + info = l->data; + + g_array_insert_val (pending, 0, info->member); + tp_contact_list_pending_cb (group, pending, + info->actor, + info->reason, + info->message, + list); + } + g_array_free (pending, TRUE); + gossip_telepathy_group_info_list_free (pendings); } - - pending = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - for (l = members; l; l = l->next) { - GossipTpGroupInfo *info; - - info = l->data; - - g_array_insert_val (pending, 0, info->member); - tp_contact_list_local_pending_cb (group, pending, - info->actor, - info->reason, - info->message, - list); + } + else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { + if (priv->subscribe) { + g_object_unref (priv->subscribe); } - - gossip_telepathy_group_info_list_free (members); - g_array_free (pending, TRUE); + priv->subscribe = group; + } else { + g_assert_not_reached (); } } else if (handle_type == TP_HANDLE_TYPE_GROUP) { @@ -1065,72 +1066,69 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, static TpContactListType tp_contact_list_get_type (EmpathyTpContactList *list, - TpChan *list_chan) + GossipTelepathyGroup *group) { EmpathyTpContactListPriv *priv; - GArray *handles; - gchar **handle_name; TpContactListType list_type; - GError *error = NULL; + const gchar *name; priv = GET_PRIV (list); - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, list_chan->handle); - - if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn), - TP_HANDLE_TYPE_LIST, - handles, - &handle_name, - &error)) { - gossip_debug (DEBUG_DOMAIN, - "InspectHandle Error: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - g_array_free (handles, TRUE); - return TP_CONTACT_LIST_TYPE_UNKNOWN; - } - - if (strcmp (*handle_name, "subscribe") == 0) { + name = gossip_telepathy_group_get_name (group); + if (strcmp (name, "subscribe") == 0) { list_type = TP_CONTACT_LIST_TYPE_SUBSCRIBE; - } else if (strcmp (*handle_name, "publish") == 0) { + } else if (strcmp (name, "publish") == 0) { list_type = TP_CONTACT_LIST_TYPE_PUBLISH; - } else if (strcmp (*handle_name, "known") == 0) { - list_type = TP_CONTACT_LIST_TYPE_KNOWN; } else { list_type = TP_CONTACT_LIST_TYPE_UNKNOWN; } - g_strfreev (handle_name); - g_array_free (handles, TRUE); - return list_type; } static void -tp_contact_list_contact_added_cb (GossipTelepathyGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_added_cb (GossipTelepathyGroup *group, + GArray *handles, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv; GList *added_list, *l; + TpContactListType list_type; priv = GET_PRIV (list); - added_list = empathy_tp_contact_list_get_from_handles (list, handles); + list_type = tp_contact_list_get_type (list, group); + added_list = empathy_tp_contact_list_get_from_handles (list, handles); for (l = added_list; l; l = l->next) { - GossipContact *contact; + GossipContact *contact; + GossipSubscription subscription; contact = GOSSIP_CONTACT (l->data); + + gossip_debug (DEBUG_DOMAIN, "Contact '%s' added to list type %d", + gossip_contact_get_name (contact), + list_type); + + subscription = gossip_contact_get_subscription (contact); + if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { + subscription |= GOSSIP_SUBSCRIPTION_FROM; + } + else if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { + subscription |= GOSSIP_SUBSCRIPTION_TO; + } + tp_contact_list_block_contact (list, contact); - gossip_contact_set_subscription (contact, GOSSIP_SUBSCRIPTION_BOTH); + gossip_contact_set_subscription (contact, subscription); tp_contact_list_unblock_contact (list, contact); - g_signal_emit_by_name (list, "contact-added", contact); + if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { + tp_contact_list_remove_local_pending (list, contact); + g_signal_emit_by_name (list, "contact-added", contact); + } g_object_unref (contact); } @@ -1139,31 +1137,48 @@ tp_contact_list_contact_added_cb (GossipTelepathyGroup *group, } static void -tp_contact_list_contact_removed_cb (GossipTelepathyGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_removed_cb (GossipTelepathyGroup *group, + GArray *handles, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv; GList *removed_list, *l; + TpContactListType list_type; priv = GET_PRIV (list); - removed_list = empathy_tp_contact_list_get_from_handles (list, handles); + list_type = tp_contact_list_get_type (list, group); + removed_list = empathy_tp_contact_list_get_from_handles (list, handles); for (l = removed_list; l; l = l->next) { - GossipContact *contact; - guint handle; + GossipContact *contact; + GossipSubscription subscription; contact = GOSSIP_CONTACT (l->data); - handle = gossip_contact_get_handle (contact); - g_hash_table_remove (priv->contacts, GUINT_TO_POINTER (handle)); + gossip_debug (DEBUG_DOMAIN, "Contact '%s' removed from list type %d", + gossip_contact_get_name (contact), + list_type); + + subscription = gossip_contact_get_subscription (contact); + if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { + subscription &= !GOSSIP_SUBSCRIPTION_FROM; + } + else if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { + subscription &= !GOSSIP_SUBSCRIPTION_TO; + } - g_signal_emit_by_name (list, "contact-removed", contact); + tp_contact_list_block_contact (list, contact); + gossip_contact_set_subscription (contact, subscription); + tp_contact_list_unblock_contact (list, contact); + if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { + tp_contact_list_remove_local_pending (list, contact); + g_signal_emit_by_name (list, "contact-removed", contact); + } g_object_unref (contact); } @@ -1171,30 +1186,41 @@ tp_contact_list_contact_removed_cb (GossipTelepathyGroup *group, } static void -tp_contact_list_local_pending_cb (GossipTelepathyGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_pending_cb (GossipTelepathyGroup *group, + GArray *handles, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv; GList *pending_list, *l; + TpContactListType list_type; priv = GET_PRIV (list); - pending_list = empathy_tp_contact_list_get_from_handles (list, handles); + list_type = tp_contact_list_get_type (list, group); + pending_list = empathy_tp_contact_list_get_from_handles (list, handles); for (l = pending_list; l; l = l->next) { GossipContact *contact; contact = GOSSIP_CONTACT (l->data); - /* FIXME: Is that the correct way ? */ - tp_contact_list_block_contact (list, contact); - gossip_contact_set_subscription (contact, GOSSIP_SUBSCRIPTION_FROM); - tp_contact_list_unblock_contact (list, contact); - g_signal_emit_by_name (list, "contact-added", contact); + gossip_debug (DEBUG_DOMAIN, "Contact '%s' pending in list type %d", + gossip_contact_get_name (contact), + list_type); + + if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { + EmpathyContactListInfo *info; + + info = empathy_contact_list_info_new (contact, message); + priv->local_pending = g_list_prepend (priv->local_pending, + info); + + g_signal_emit_by_name (list, "local-pending", + contact, message); + } g_object_unref (contact); } @@ -1202,6 +1228,30 @@ tp_contact_list_local_pending_cb (GossipTelepathyGroup *group, g_list_free (pending_list); } +static void +tp_contact_list_remove_local_pending (EmpathyTpContactList *list, + GossipContact *contact) +{ + EmpathyTpContactListPriv *priv; + GList *l; + + priv = GET_PRIV (list); + + for (l = priv->local_pending; l; l = l->next) { + EmpathyContactListInfo *info; + + info = l->data; + if (gossip_contact_equal (contact, info->contact)) { + gossip_debug (DEBUG_DOMAIN, "Contact no more local-pending: %s", + gossip_contact_get_name (contact)); + + priv->local_pending = g_list_delete_link (priv->local_pending, l); + empathy_contact_list_info_free (info); + break; + } + } +} + static void tp_contact_list_groups_updated_cb (GossipContact *contact, GParamSpec *param, @@ -1531,11 +1581,16 @@ tp_contact_list_group_members_removed_cb (GossipTelepathyGroup *group, } static void -tp_contact_list_get_contacts_foreach (guint handle, +tp_contact_list_get_members_foreach (guint handle, GossipContact *contact, GList **contacts) { - *contacts = g_list_append (*contacts, g_object_ref (contact)); + GossipSubscription subscription; + + subscription = gossip_contact_get_subscription (contact); + if (subscription & GOSSIP_SUBSCRIPTION_TO) { + *contacts = g_list_append (*contacts, g_object_ref (contact)); + } } static void -- 2.39.2