diff options
89 files changed, 4998 insertions, 6189 deletions
diff --git a/configure.ac b/configure.ac index c3926fdb2..0ff17396d 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ GLIB_REQUIRED=2.16.0 GTK_REQUIRED=2.16.0 GCONF_REQUIRED=1.2.0 LIBPANELAPPLET_REQUIRED=2.10.0 -TELEPATHY_GLIB_REQUIRED=0.7.23 +TELEPATHY_GLIB_REQUIRED=0.7.27 MISSION_CONTROL_REQUIRED=4.61 ENCHANT_REQUIRED=1.2.0 ISO_CODES_REQUIRED=0.35 diff --git a/docs/libempathy/libempathy-docs.sgml b/docs/libempathy/libempathy-docs.sgml index a7e3df9b8..f3291f772 100644 --- a/docs/libempathy/libempathy-docs.sgml +++ b/docs/libempathy/libempathy-docs.sgml @@ -21,7 +21,6 @@ <xi:include href="xml/empathy-call-handler.xml"/> <xi:include href="xml/empathy-chatroom-manager.xml"/> <xi:include href="xml/empathy-chatroom.xml"/> - <xi:include href="xml/empathy-contact-factory.xml"/> <xi:include href="xml/empathy-contact-groups.xml"/> <xi:include href="xml/empathy-contact-list.xml"/> <xi:include href="xml/empathy-contact-manager.xml"/> @@ -45,7 +44,6 @@ <xi:include href="xml/empathy-tp-contact-factory.xml"/> <xi:include href="xml/empathy-tp-contact-list.xml"/> <xi:include href="xml/empathy-tp-file.xml"/> - <xi:include href="xml/empathy-tp-group.xml"/> <xi:include href="xml/empathy-tp-roomlist.xml"/> <xi:include href="xml/empathy-tp-tube.xml"/> <xi:include href="xml/empathy-tube-handler.xml"/> diff --git a/docs/libempathy/libempathy.types b/docs/libempathy/libempathy.types index 1a81ac671..26040474e 100644 --- a/docs/libempathy/libempathy.types +++ b/docs/libempathy/libempathy.types @@ -3,7 +3,6 @@ empathy_call_factory_get_type empathy_call_handler_get_type empathy_chatroom_get_type empathy_chatroom_manager_get_type -empathy_contact_factory_get_type empathy_contact_get_type empathy_avatar_get_type empathy_contact_list_get_type @@ -12,7 +11,6 @@ empathy_contact_monitor_get_type empathy_dispatcher_get_type empathy_dispatch_operation_get_type empathy_capabilities_get_type -empathy_contact_ready_get_type empathy_debug_flags_get_type empathy_dispatch_operation_state_get_type empathy_tp_call_status_get_type @@ -29,7 +27,6 @@ empathy_tp_chat_get_type empathy_tp_contact_factory_get_type empathy_tp_contact_list_get_type empathy_tp_file_get_type -empathy_tp_group_get_type empathy_tp_roomlist_get_type empathy_tp_tube_get_type empathy_tube_handler_get_type diff --git a/empathy.doap b/empathy.doap index 7b5e75642..acd6494bc 100644 --- a/empathy.doap +++ b/empathy.doap @@ -6,6 +6,7 @@ xmlns="http://usefulinc.com/ns/doap#"> <name xml:lang="en">Empathy Instant Messenger</name> <shortdesc xml:lang="en">Send and receive instant messages</shortdesc> + <category rdf:resource="http://api.gnome.org/doap-extensions#desktop" /> <homepage rdf:resource="http://live.gnome.org/Empathy" /> <mailing-list rdf:resource="http://lists.freedesktop.org/mailman/listinfo/telepathy" /> diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am index 470d44ea5..2065589e3 100644 --- a/libempathy-gtk/Makefile.am +++ b/libempathy-gtk/Makefile.am @@ -49,6 +49,7 @@ libempathy_gtk_la_SOURCES = \ empathy-profile-chooser.c \ empathy-smiley-manager.c \ empathy-spell.c \ + empathy-status-preset-dialog.c \ empathy-theme-boxes.c \ empathy-theme-irc.c \ empathy-theme-manager.c \ @@ -101,6 +102,7 @@ libempathy_gtk_headers = \ empathy-profile-chooser.h \ empathy-smiley-manager.h \ empathy-spell.h \ + empathy-status-preset-dialog.h \ empathy-theme-boxes.h \ empathy-theme-irc.h \ empathy-theme-manager.h \ @@ -115,7 +117,6 @@ uidir = $(datadir)/empathy ui_DATA = \ empathy-contact-widget.ui \ empathy-contact-dialogs.ui \ - empathy-presence-chooser.ui \ empathy-account-widget-generic.ui \ empathy-account-widget-jabber.ui \ empathy-account-widget-msn.ui \ @@ -126,6 +127,7 @@ ui_DATA = \ empathy-account-widget-yahoo.ui \ empathy-account-widget-groupwise.ui \ empathy-account-widget-aim.ui \ + empathy-status-preset-dialog.ui \ empathy-log-window.ui \ empathy-chat.ui \ empathy-new-message-dialog.ui diff --git a/libempathy-gtk/empathy-account-chooser.c b/libempathy-gtk/empathy-account-chooser.c index 8c402c07a..5d11e8e1e 100644 --- a/libempathy-gtk/empathy-account-chooser.c +++ b/libempathy-gtk/empathy-account-chooser.c @@ -37,6 +37,23 @@ #include "empathy-ui-utils.h" #include "empathy-account-chooser.h" +/** + * SECTION:empathy-account-chooser + * @title:EmpathyAccountChooser + * @short_description: A widget used to choose from a list of accounts + * @include: libempathy-gtk/empathy-account-chooser.h + * + * #EmpathyAccountChooser is a widget which extends #GtkComboBox to provide + * a chooser of available accounts. + */ + +/** + * EmpathyAccountChooser: + * @parent: parent object + * + * Widget which extends #GtkComboBox to provide a chooser of available accounts. + */ + #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountChooser) typedef struct { EmpathyAccountManager *manager; @@ -112,6 +129,11 @@ empathy_account_chooser_class_init (EmpathyAccountChooserClass *klass) object_class->get_property = account_chooser_get_property; object_class->set_property = account_chooser_set_property; + /** + * EmpathyAccountChooser:has-all-option: + * + * Have an additional option in the list to mean all accounts. + */ g_object_class_install_property (object_class, PROP_HAS_ALL_OPTION, g_param_spec_boolean ("has-all-option", @@ -209,6 +231,13 @@ account_chooser_set_property (GObject *object, }; } +/** + * empathy_account_chooser_new: + * + * Creates a new #EmpathyAccountChooser. + * + * Return value: A new #EmpathyAccountChooser + */ GtkWidget * empathy_account_chooser_new (void) { @@ -219,8 +248,18 @@ empathy_account_chooser_new (void) return chooser; } +/** + * empathy_account_chooser_dup_account: + * @chooser: an #EmpathyAccountChooser + * + * Returns the account which is currently selected in the chooser or %NULL + * if there is no account selected. The #McAccount returned should be + * unrefed with g_object_unref() when finished with. + * + * Return value: a new ref to the #McAccount currently selected, or %NULL. + */ McAccount * -empathy_account_chooser_get_account (EmpathyAccountChooser *chooser) +empathy_account_chooser_dup_account (EmpathyAccountChooser *chooser) { EmpathyAccountChooserPriv *priv; McAccount *account; @@ -241,6 +280,44 @@ empathy_account_chooser_get_account (EmpathyAccountChooser *chooser) return account; } +/** + * empathy_account_chooser_get_connection: + * @chooser: an #EmpathyAccountChooser + * + * Returns a borrowed reference to the #TpConnection associated with the + * account currently selected. The caller must reference the returned object with + * g_object_ref() if it will be kept + * + * Return value: a borrowed reference to the #TpConnection associated with the + * account curently selected. + */ +TpConnection * +empathy_account_chooser_get_connection (EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + McAccount *account; + TpConnection *connection; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), NULL); + + priv = GET_PRIV (chooser); + + account = empathy_account_chooser_dup_account (chooser); + connection = empathy_account_manager_get_connection (priv->manager, account); + g_object_unref (account); + + return connection; +} + +/** + * empathy_account_chooser_set_account: + * @chooser: an #EmpathyAccountChooser + * @account: an #McAccount + * + * Sets the currently selected account to @account, if it exists in the list. + * + * Return value: whether the chooser was set to @account. + */ gboolean empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, McAccount *account) @@ -266,6 +343,16 @@ empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, return data.set; } +/** + * empathy_account_chooser_get_has_all_option: + * @chooser: an #EmpathyAccountChooser + * + * Returns whether @chooser has the #EmpathyAccountChooser:has-all-option property + * set to true. + * + * Return value: whether @chooser has the #EmpathyAccountChooser:has-all-option property + * enabled. + */ gboolean empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser) { @@ -278,6 +365,13 @@ empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser) return priv->has_all_option; } +/** + * empathy_account_chooser_set_has_all_option: + * @chooser: an #EmpathyAccountChooser + * @has_all_option: a new value for the #EmpathyAccountChooser:has-all-option property + * + * Sets the #EmpathyAccountChooser:has-all-option property. + */ void empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser, gboolean has_all_option) @@ -618,6 +712,15 @@ account_chooser_filter_foreach (GtkTreeModel *model, return FALSE; } +/** + * empathy_account_chooser_set_filter: + * @chooser: an #EmpathyAccountChooser + * @filter: a filter + * @user_data: data to pass to @filter, or %NULL + * + * Sets a filter on the @chooser so only accounts that are %TRUE in the eyes + * of the filter are visible in the @chooser. + */ void empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser, EmpathyAccountChooserFilterFunc filter, @@ -639,6 +742,27 @@ empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser, gtk_tree_model_foreach (model, account_chooser_filter_foreach, chooser); } +/** + * EmpathyAccountChooserFilterFunc: + * @account: an #McAccount + * @user_data: user data, or %NULL + * + * A function which decides whether the account indicated by @account + * is visible. + * + * Return value: whether the account indicated by @account is visible. + */ + +/** + * empathy_account_chooser_filter_is_connected: + * @account: an #McAccount + * @user_data: user data or %NULL + * + * A useful #EmpathyAccountChooserFilterFunc that one could pass into + * empathy_account_chooser_set_filter() and only show connected accounts. + * + * Return value: Whether @account is connected + */ gboolean empathy_account_chooser_filter_is_connected (McAccount *account, gpointer user_data) diff --git a/libempathy-gtk/empathy-account-chooser.h b/libempathy-gtk/empathy-account-chooser.h index c15923bc3..98d568bcc 100644 --- a/libempathy-gtk/empathy-account-chooser.h +++ b/libempathy-gtk/empathy-account-chooser.h @@ -47,6 +47,8 @@ typedef struct _EmpathyAccountChooserClass EmpathyAccountChooserClass; struct _EmpathyAccountChooser { GtkComboBox parent; + + /*<private>*/ gpointer priv; }; @@ -56,7 +58,8 @@ struct _EmpathyAccountChooserClass { GType empathy_account_chooser_get_type (void) G_GNUC_CONST; GtkWidget * empathy_account_chooser_new (void); -McAccount * empathy_account_chooser_get_account (EmpathyAccountChooser *chooser); +McAccount * empathy_account_chooser_dup_account (EmpathyAccountChooser *chooser); +TpConnection * empathy_account_chooser_get_connection (EmpathyAccountChooser *chooser); gboolean empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, McAccount *account); gboolean empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser); diff --git a/libempathy-gtk/empathy-account-widget-irc.c b/libempathy-gtk/empathy-account-widget-irc.c index 3af842415..cc86a5aaa 100644 --- a/libempathy-gtk/empathy-account-widget-irc.c +++ b/libempathy-gtk/empathy-account-widget-irc.c @@ -50,9 +50,6 @@ typedef struct { GtkWidget *vbox_settings; GtkWidget *combobox_network; - GtkWidget *button_add_network; - GtkWidget *button_network; - GtkWidget *button_remove; } EmpathyAccountWidgetIrc; enum { @@ -462,9 +459,6 @@ empathy_account_widget_irc_new (McAccount *account) gui = empathy_builder_get_file (filename, "vbox_irc_settings", &settings->vbox_settings, "combobox_network", &settings->combobox_network, - "button_network", &settings->button_network, - "button_add_network", &settings->button_add_network, - "button_remove", &settings->button_remove, NULL); g_free (filename); @@ -501,7 +495,7 @@ empathy_account_widget_irc_new (McAccount *account) "vbox_irc_settings", "destroy", account_widget_irc_destroy_cb, "button_network", "clicked", account_widget_irc_button_edit_network_clicked_cb, "button_add_network", "clicked", account_widget_irc_button_add_network_clicked_cb, - "button_remove", "clicked", account_widget_irc_button_remove_clicked_cb, + "button_remove_network", "clicked", account_widget_irc_button_remove_clicked_cb, "combobox_network", "changed", account_widget_irc_combobox_network_changed_cb, NULL); diff --git a/libempathy-gtk/empathy-account-widget-irc.ui b/libempathy-gtk/empathy-account-widget-irc.ui index f499866eb..76c67f711 100644 --- a/libempathy-gtk/empathy-account-widget-irc.ui +++ b/libempathy-gtk/empathy-account-widget-irc.ui @@ -3,7 +3,6 @@ <requires lib="gtk+" version="2.16"/> <!-- interface-naming-policy toplevel-contextual --> <object class="GtkDialog" id="irc_network_dialog"> - <property name="visible">True</property> <property name="border_width">5</property> <property name="title" translatable="yes">Network</property> <property name="window_position">center-on-parent</property> @@ -418,7 +417,7 @@ </packing> </child> <child> - <object class="GtkButton" id="button_remove"> + <object class="GtkButton" id="button_remove_network"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> @@ -444,7 +443,7 @@ </packing> </child> <child> - <object class="GtkLabel" id="label_network"> + <object class="GtkLabel" id="label_network2"> <property name="visible">True</property> <property name="xalign">0</property> <property name="label" translatable="yes">Network:</property> diff --git a/libempathy-gtk/empathy-avatar-chooser.c b/libempathy-gtk/empathy-avatar-chooser.c index 02aa689eb..c86b85d25 100644 --- a/libempathy-gtk/empathy-avatar-chooser.c +++ b/libempathy-gtk/empathy-avatar-chooser.c @@ -30,7 +30,7 @@ #include <gio/gio.h> #include <libempathy/empathy-utils.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> #include "empathy-avatar-chooser.h" #include "empathy-conf.h" @@ -39,15 +39,31 @@ #define DEBUG_FLAG EMPATHY_DEBUG_OTHER #include <libempathy/empathy-debug.h> +/** + * SECTION:empathy-avatar-chooser + * @title: EmpathyAvatarChooser + * @short_description: A widget used to change avatar + * @include: libempathy-gtk/empathy-avatar-chooser.h + * + * #EmpathyAvatarChooser is a widget which extends #GtkButton to + * provide a way of changing avatar. + */ + +/** + * EmpathyAvatarChooser: + * @parent: parent object + * + * Widget which extends #GtkButton to provide a way of changing avatar. + */ + #define AVATAR_SIZE_SAVE 96 #define AVATAR_SIZE_VIEW 64 #define DEFAULT_DIR DATADIR"/pixmaps/faces" #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAvatarChooser) typedef struct { - EmpathyContactFactory *contact_factory; - McAccount *account; - EmpathyTpContactFactory *tp_contact_factory; + EmpathyTpContactFactory *factory; + TpConnection *connection; GtkFileChooser *chooser_dialog; gulong ready_handler_id; @@ -56,8 +72,8 @@ typedef struct { } EmpathyAvatarChooserPriv; static void avatar_chooser_finalize (GObject *object); -static void avatar_chooser_set_account (EmpathyAvatarChooser *self, - McAccount *account); +static void avatar_chooser_set_connection (EmpathyAvatarChooser *self, + TpConnection *connection); static void avatar_chooser_set_image (EmpathyAvatarChooser *chooser, EmpathyAvatar *avatar, GdkPixbuf *pixbuf, @@ -96,7 +112,7 @@ enum { enum { PROP_0, - PROP_ACCOUNT + PROP_CONNECTION }; static guint signals [LAST_SIGNAL]; @@ -125,8 +141,8 @@ avatar_chooser_get_property (GObject *object, EmpathyAvatarChooserPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -143,8 +159,8 @@ avatar_chooser_set_property (GObject *object, EmpathyAvatarChooser *self = EMPATHY_AVATAR_CHOOSER (object); switch (param_id) { - case PROP_ACCOUNT: - avatar_chooser_set_account (self, g_value_get_object (value)); + case PROP_CONNECTION: + avatar_chooser_set_connection (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -162,6 +178,13 @@ empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass) object_class->get_property = avatar_chooser_get_property; object_class->set_property = avatar_chooser_set_property; + /** + * EmpathyAvatarChooser::changed: + * @chooser: an #EmpathyAvatarChooser + * + * Emitted when the chosen avatar has changed. + * + */ signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (klass), @@ -171,15 +194,21 @@ empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - param_spec = g_param_spec_object ("account", - "McAccount", - "McAccount whose avatar should be " + /** + * EmpathyAvatarChooser:connection: + * + * The #TpConnection whose avatar should be shown and modified by + * the #EmpathyAvatarChooser instance. + */ + param_spec = g_param_spec_object ("connection", + "TpConnection", + "TpConnection whose avatar should be " "shown and modified by this widget", - MC_TYPE_ACCOUNT, + TP_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, - PROP_ACCOUNT, + PROP_CONNECTION, param_spec); g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv)); @@ -214,8 +243,6 @@ empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser) G_CALLBACK (avatar_chooser_clicked_cb), chooser); - priv->contact_factory = empathy_contact_factory_dup_singleton (); - empathy_avatar_chooser_set (chooser, NULL); } @@ -226,11 +253,9 @@ avatar_chooser_finalize (GObject *object) priv = GET_PRIV (object); - avatar_chooser_set_account (EMPATHY_AVATAR_CHOOSER (object), NULL); - g_assert (priv->account == NULL); - g_assert (priv->tp_contact_factory == NULL); - - g_object_unref (priv->contact_factory); + avatar_chooser_set_connection (EMPATHY_AVATAR_CHOOSER (object), NULL); + g_assert (priv->connection == NULL); + g_assert (priv->factory == NULL); if (priv->avatar != NULL) { empathy_avatar_unref (priv->avatar); @@ -240,51 +265,22 @@ avatar_chooser_finalize (GObject *object) } static void -avatar_chooser_tp_cf_ready_cb (EmpathyTpContactFactory *tp_cf, - GParamSpec *unused, - EmpathyAvatarChooser *self) -{ - EmpathyAvatarChooserPriv *priv = GET_PRIV (self); - gboolean ready; - - /* sanity check that we're listening on the right ETpCF */ - g_assert (priv->tp_contact_factory == tp_cf); - - ready = empathy_tp_contact_factory_is_ready (tp_cf); - gtk_widget_set_sensitive (GTK_WIDGET (self), ready); -} - -static void -avatar_chooser_set_account (EmpathyAvatarChooser *self, - McAccount *account) +avatar_chooser_set_connection (EmpathyAvatarChooser *self, + TpConnection *connection) { EmpathyAvatarChooserPriv *priv = GET_PRIV (self); - if (priv->account != NULL) { - g_object_unref (priv->account); - priv->account = NULL; + if (priv->connection != NULL) { + g_object_unref (priv->connection); + priv->connection = NULL; - g_assert (priv->tp_contact_factory != NULL); - - g_signal_handler_disconnect (priv->tp_contact_factory, - priv->ready_handler_id); - priv->ready_handler_id = 0; - - g_object_unref (priv->tp_contact_factory); - priv->tp_contact_factory = NULL; + g_object_unref (priv->factory); + priv->factory = NULL; } - if (account != NULL) { - priv->account = g_object_ref (account); - priv->tp_contact_factory = g_object_ref ( - empathy_contact_factory_get_tp_factory ( - priv->contact_factory, priv->account)); - - priv->ready_handler_id = g_signal_connect ( - priv->tp_contact_factory, "notify::ready", - G_CALLBACK (avatar_chooser_tp_cf_ready_cb), self); - avatar_chooser_tp_cf_ready_cb (priv->tp_contact_factory, NULL, - self); + if (connection != NULL) { + priv->connection = g_object_ref (connection); + priv->factory = empathy_tp_contact_factory_dup_singleton (connection); } } @@ -412,7 +408,6 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser, EmpathyAvatar *avatar) { EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser); - EmpathyTpContactFactory *tp_cf = priv->tp_contact_factory; guint max_width = 0, max_height = 0, max_size = 0; gchar **mime_types = NULL; gboolean needs_conversion = FALSE; @@ -424,15 +419,7 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser, gchar *converted_image_data = NULL; gsize converted_image_size = 0; - /* This should only be called if the user is setting a new avatar, - * which should only be allowed once the avatar requirements have been - * discovered. - */ - g_return_val_if_fail (tp_cf != NULL, NULL); - g_return_val_if_fail (empathy_tp_contact_factory_is_ready (tp_cf), - NULL); - - g_object_get (tp_cf, + g_object_get (priv->factory, "avatar-mime-types", &mime_types, /* Needs g_strfreev-ing */ "avatar-max-width", &max_width, "avatar-max-height", &max_height, @@ -901,16 +888,6 @@ avatar_chooser_response_cb (GtkWidget *widget, priv->chooser_dialog = NULL; - if (response == GTK_RESPONSE_CANCEL) { - goto out; - } - - /* Check if we went non-ready since displaying the dialog. */ - if (!empathy_tp_contact_factory_is_ready (priv->tp_contact_factory)) { - DEBUG ("Can't set avatar when contact factory isn't ready."); - goto out; - } - if (response == GTK_RESPONSE_OK) { gchar *filename; gchar *path; @@ -932,7 +909,6 @@ avatar_chooser_response_cb (GtkWidget *widget, avatar_chooser_clear_image (chooser); } -out: gtk_widget_destroy (widget); } @@ -1037,12 +1013,26 @@ avatar_chooser_clicked_cb (GtkWidget *button, g_free (saved_dir); } +/** + * empathy_avatar_chooser_new: + * + * Creates a new #EmpathyAvatarChooser. + * + * Return value: a new #EmpathyAvatarChooser + */ GtkWidget * empathy_avatar_chooser_new () { return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL); } +/** + * empathy_avatar_chooser_set: + * @chooser: an #EmpathyAvatarChooser + * @avatar: a new #EmpathyAvatar + * + * Sets the @chooser to display the avatar indicated by @avatar. + */ void empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser, EmpathyAvatar *avatar) @@ -1056,6 +1046,15 @@ empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser, } } +/** + * empathy_avatar_chooser_get_image_data: + * @chooser: an #EmpathyAvatarChooser + * @data: avatar bytes + * @data_size: size of @data + * @mime_type: avatar mime-type + * + * Gets image data about the currently selected avatar. + */ void empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser, const gchar **data, diff --git a/libempathy-gtk/empathy-avatar-chooser.h b/libempathy-gtk/empathy-avatar-chooser.h index bdc5b40ae..564c1f37d 100644 --- a/libempathy-gtk/empathy-avatar-chooser.h +++ b/libempathy-gtk/empathy-avatar-chooser.h @@ -41,6 +41,8 @@ typedef struct _EmpathyAvatarChooserClass EmpathyAvatarChooserClass; struct _EmpathyAvatarChooser { GtkButton parent; + + /*<private>*/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-avatar-image.c b/libempathy-gtk/empathy-avatar-image.c index 51f30bdd5..e5513231b 100644 --- a/libempathy-gtk/empathy-avatar-image.c +++ b/libempathy-gtk/empathy-avatar-image.c @@ -33,6 +33,22 @@ #include "empathy-avatar-image.h" #include "empathy-ui-utils.h" +/** + * SECTION:empathy-avatar-image + * @title: EmpathyAvatarImage + * @short_description: A widget to display an avatar + * @include: libempathy-gtk/empathy-avatar-image.h + * + * #EmpathyAvatarImage is a widget which displays an avatar. + */ + +/** + * EmpathyAvatarImage: + * @parent: parent object + * + * Widget which displays an avatar. + */ + #define MAX_SMALL 64 #define MAX_LARGE 400 @@ -251,6 +267,13 @@ avatar_image_button_release_event (GtkWidget *widget, GdkEventButton *event) return TRUE; } +/** + * empathy_avatar_image_new: + * + * Creates a new #EmpathyAvatarImage. + * + * Return value: a new #EmpathyAvatarImage + */ GtkWidget * empathy_avatar_image_new (void) { @@ -261,6 +284,13 @@ empathy_avatar_image_new (void) return GTK_WIDGET (avatar_image); } +/** + * empathy_avatar_image_set: + * @avatar_image: an #EmpathyAvatarImage + * @avatar: the #EmpathyAvatar to set @avatar_image to + * + * Sets @avatar_image to display the avatar indicated by @avatar. + */ void empathy_avatar_image_set (EmpathyAvatarImage *avatar_image, EmpathyAvatar *avatar) diff --git a/libempathy-gtk/empathy-avatar-image.h b/libempathy-gtk/empathy-avatar-image.h index d6a6cd0b0..8969c1227 100644 --- a/libempathy-gtk/empathy-avatar-image.h +++ b/libempathy-gtk/empathy-avatar-image.h @@ -42,6 +42,8 @@ typedef struct _EmpathyAvatarImageClass EmpathyAvatarImageClass; struct _EmpathyAvatarImage { GtkEventBox parent; + + /*<private>*/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c index c8ec59f1b..425a1c555 100644 --- a/libempathy-gtk/empathy-chat.c +++ b/libempathy-gtk/empathy-chat.c @@ -64,7 +64,6 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChat) typedef struct { EmpathyTpChat *tp_chat; - gulong tp_chat_destroy_handler; McAccount *account; gchar *id; gchar *name; @@ -189,17 +188,15 @@ chat_connect_channel_reconnected (EmpathyDispatchOperation *dispatch, } static void -chat_connection_changed_cb (EmpathyAccountManager *manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus current, - TpConnectionStatus previous, - EmpathyChat *chat) +chat_new_connection_cb (EmpathyAccountManager *manager, + TpConnection *connection, + EmpathyChat *chat) { EmpathyChatPriv *priv = GET_PRIV (chat); + McAccount *account; - if (current == TP_CONNECTION_STATUS_CONNECTED && !priv->tp_chat && - empathy_account_equal (account, priv->account) && + account = empathy_account_manager_get_account (manager, connection); + if (!priv->tp_chat && empathy_account_equal (account, priv->account) && priv->handle_type != TP_HANDLE_TYPE_NONE && !EMP_STR_EMPTY (priv->id)) { @@ -207,12 +204,14 @@ chat_connection_changed_cb (EmpathyAccountManager *manager, switch (priv->handle_type) { case TP_HANDLE_TYPE_CONTACT: - empathy_dispatcher_chat_with_contact_id (account, priv->id, + empathy_dispatcher_chat_with_contact_id ( + connection, priv->id, chat_connect_channel_reconnected, chat); break; case TP_HANDLE_TYPE_ROOM: - empathy_dispatcher_join_muc (account, priv->id, + empathy_dispatcher_join_muc (connection, + priv->id, chat_connect_channel_reconnected, chat); break; @@ -1168,10 +1167,6 @@ chat_members_changed_cb (EmpathyTpChat *tp_chat, if (priv->block_events_timeout_id == 0) { gchar *str; - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_NAME, - NULL); - if (is_member) { str = g_strdup_printf (_("%s has joined the room"), empathy_contact_get_name (contact)); @@ -1463,13 +1458,26 @@ chat_finalize (GObject *object) chat_composing_remove_timeout (chat); g_signal_handlers_disconnect_by_func (priv->account_manager, - chat_connection_changed_cb, object); + chat_new_connection_cb, object); g_object_unref (priv->account_manager); g_object_unref (priv->log_manager); if (priv->tp_chat) { - g_signal_handler_disconnect (priv->tp_chat, priv->tp_chat_destroy_handler); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_destroy_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_message_received_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_send_error_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_state_changed_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_property_changed_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_members_changed_cb, chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_remote_contact_changed_cb, chat); empathy_tp_chat_close (priv->tp_chat); g_object_unref (priv->tp_chat); } @@ -1607,8 +1615,8 @@ empathy_chat_init (EmpathyChat *chat) priv->account_manager = empathy_account_manager_dup_singleton (); g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (chat_connection_changed_cb), + "new-connection", + G_CALLBACK (chat_new_connection_cb), chat); /* Block events for some time to avoid having "has come online" or @@ -1642,6 +1650,7 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, EmpathyTpChat *tp_chat) { EmpathyChatPriv *priv = GET_PRIV (chat); + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CHAT (chat)); g_return_if_fail (EMPATHY_IS_TP_CHAT (tp_chat)); @@ -1656,8 +1665,14 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, } priv->tp_chat = g_object_ref (tp_chat); - priv->account = g_object_ref (empathy_tp_chat_get_account (tp_chat)); + connection = empathy_tp_chat_get_connection (priv->tp_chat); + priv->account = empathy_account_manager_get_account (priv->account_manager, + connection); + g_object_ref (priv->account); + g_signal_connect (tp_chat, "destroy", + G_CALLBACK (chat_destroy_cb), + chat); g_signal_connect (tp_chat, "message-received", G_CALLBACK (chat_message_received_cb), chat); @@ -1676,10 +1691,6 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, g_signal_connect_swapped (tp_chat, "notify::remote-contact", G_CALLBACK (chat_remote_contact_changed_cb), chat); - priv->tp_chat_destroy_handler = - g_signal_connect (tp_chat, "destroy", - G_CALLBACK (chat_destroy_cb), - chat); chat_remote_contact_changed_cb (chat); @@ -1759,20 +1770,6 @@ empathy_chat_get_remote_contact (EmpathyChat *chat) return priv->remote_contact; } -guint -empathy_chat_get_members_count (EmpathyChat *chat) -{ - EmpathyChatPriv *priv = GET_PRIV (chat); - - g_return_val_if_fail (EMPATHY_IS_CHAT (chat), 0); - - if (priv->tp_chat) { - return empathy_tp_chat_get_members_count (priv->tp_chat); - } - - return 0; -} - GtkWidget * empathy_chat_get_contact_menu (EmpathyChat *chat) { diff --git a/libempathy-gtk/empathy-chat.h b/libempathy-gtk/empathy-chat.h index 6b7fcf26e..f61ce4154 100644 --- a/libempathy-gtk/empathy-chat.h +++ b/libempathy-gtk/empathy-chat.h @@ -71,7 +71,6 @@ const gchar * empathy_chat_get_id (EmpathyChat *chat); const gchar * empathy_chat_get_name (EmpathyChat *chat); const gchar * empathy_chat_get_subject (EmpathyChat *chat); EmpathyContact * empathy_chat_get_remote_contact (EmpathyChat *chat); -guint empathy_chat_get_members_count (EmpathyChat *chat); GtkWidget * empathy_chat_get_contact_menu (EmpathyChat *chat); void empathy_chat_clear (EmpathyChat *chat); void empathy_chat_scroll_down (EmpathyChat *chat); diff --git a/libempathy-gtk/empathy-contact-dialogs.c b/libempathy-gtk/empathy-contact-dialogs.c index 72b5b28b3..056ec2d85 100644 --- a/libempathy-gtk/empathy-contact-dialogs.c +++ b/libempathy-gtk/empathy-contact-dialogs.c @@ -30,6 +30,7 @@ #include <libmissioncontrol/mission-control.h> #include <libempathy/empathy-contact-manager.h> +#include <libempathy/empathy-account-manager.h> #include <libempathy/empathy-contact-list.h> #include <libempathy/empathy-utils.h> @@ -39,9 +40,10 @@ static GList *subscription_dialogs = NULL; static GList *information_dialogs = NULL; +static GList *edit_dialogs = NULL; +static GtkWidget *personal_dialog = NULL; static GtkWidget *new_contact_dialog = NULL; - static gint contact_dialogs_find (GtkDialog *dialog, EmpathyContact *contact) @@ -114,6 +116,7 @@ empathy_subscription_dialog_show (EmpathyContact *contact, g_free (filename); g_object_unref (gui); + /* Contact info widget */ contact_widget = empathy_contact_widget_new (contact, EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | EMPATHY_CONTACT_WIDGET_EDIT_GROUPS); @@ -123,7 +126,6 @@ empathy_subscription_dialog_show (EmpathyContact *contact, 0); gtk_widget_show (contact_widget); - g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget); subscription_dialogs = g_list_prepend (subscription_dialogs, dialog); @@ -143,25 +145,22 @@ empathy_subscription_dialog_show (EmpathyContact *contact, */ static void -contact_information_response_cb (GtkDialog *dialog, - gint response, - GtkWidget *contact_widget) +contact_dialogs_response_cb (GtkDialog *dialog, + gint response, + GList **dialogs) { - information_dialogs = g_list_remove (information_dialogs, dialog); + *dialogs = g_list_remove (*dialogs, dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); } void empathy_contact_information_dialog_show (EmpathyContact *contact, - GtkWindow *parent, - gboolean edit, - gboolean is_user) + GtkWindow *parent) { - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *contact_widget; - GList *l; - EmpathyContactWidgetFlags flags = 0; + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *contact_widget; + GList *l; g_return_if_fail (EMPATHY_IS_CONTACT (contact)); @@ -177,15 +176,7 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, dialog = gtk_dialog_new (); gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); - if (is_user) { - gtk_window_set_title (GTK_WINDOW (dialog), _("Personal Information")); - } - else if (edit) { - gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information")); - } - else { - gtk_window_set_title (GTK_WINDOW (dialog), _("Contact Information")); - } + gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information")); /* Close button */ button = gtk_button_new_with_label (GTK_STOCK_CLOSE); @@ -198,34 +189,79 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, gtk_widget_show (button); /* Contact info widget */ - if (edit) { - flags |= EMPATHY_CONTACT_WIDGET_EDIT_ALIAS; - } - if (is_user) { - flags |= EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT; - flags |= EMPATHY_CONTACT_WIDGET_EDIT_AVATAR; + contact_widget = empathy_contact_widget_new (contact, + EMPATHY_CONTACT_WIDGET_EDIT_NONE); + gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + contact_widget, + TRUE, TRUE, 0); + gtk_widget_show (contact_widget); + + g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget); + information_dialogs = g_list_prepend (information_dialogs, dialog); + + g_signal_connect (dialog, "response", + G_CALLBACK (contact_dialogs_response_cb), + &information_dialogs); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); } - if (!is_user && edit) { - flags |= EMPATHY_CONTACT_WIDGET_EDIT_GROUPS; + + gtk_widget_show (dialog); +} + +void +empathy_contact_edit_dialog_show (EmpathyContact *contact, + GtkWindow *parent) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *contact_widget; + GList *l; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + l = g_list_find_custom (edit_dialogs, + contact, + (GCompareFunc) contact_dialogs_find); + if (l) { + gtk_window_present (GTK_WINDOW (l->data)); + return; } - contact_widget = empathy_contact_widget_new (contact, flags); + + /* Create dialog */ + dialog = gtk_dialog_new (); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information")); + + /* Close button */ + button = gtk_button_new_with_label (GTK_STOCK_CLOSE); + gtk_button_set_use_stock (GTK_BUTTON (button), TRUE); + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), + button, + GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_window_set_default (GTK_WINDOW (dialog), button); + gtk_widget_show (button); + + /* Contact info widget */ + contact_widget = empathy_contact_widget_new (contact, + EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | + EMPATHY_CONTACT_WIDGET_EDIT_GROUPS); gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), contact_widget, TRUE, TRUE, 0); - if (flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT) { - empathy_contact_widget_set_account_filter (contact_widget, - empathy_account_chooser_filter_is_connected, - NULL); - } gtk_widget_show (contact_widget); g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget); - information_dialogs = g_list_prepend (information_dialogs, dialog); + edit_dialogs = g_list_prepend (edit_dialogs, dialog); g_signal_connect (dialog, "response", - G_CALLBACK (contact_information_response_cb), - contact_widget); + G_CALLBACK (contact_dialogs_response_cb), + &edit_dialogs); if (parent) { gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); @@ -234,6 +270,58 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, gtk_widget_show (dialog); } +void +empathy_contact_personal_dialog_show (GtkWindow *parent) +{ + GtkWidget *button; + GtkWidget *contact_widget; + + if (personal_dialog) { + gtk_window_present (GTK_WINDOW (personal_dialog)); + return; + } + + /* Create dialog */ + personal_dialog = gtk_dialog_new (); + gtk_dialog_set_has_separator (GTK_DIALOG (personal_dialog), FALSE); + gtk_window_set_resizable (GTK_WINDOW (personal_dialog), FALSE); + gtk_window_set_title (GTK_WINDOW (personal_dialog), _("Personal Information")); + + /* Close button */ + button = gtk_button_new_with_label (GTK_STOCK_CLOSE); + gtk_button_set_use_stock (GTK_BUTTON (button), TRUE); + gtk_dialog_add_action_widget (GTK_DIALOG (personal_dialog), + button, + GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_window_set_default (GTK_WINDOW (personal_dialog), button); + gtk_widget_show (button); + + /* Contact info widget */ + contact_widget = empathy_contact_widget_new (NULL, + EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT | + EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | + EMPATHY_CONTACT_WIDGET_EDIT_AVATAR); + gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (personal_dialog)->vbox), + contact_widget, + TRUE, TRUE, 0); + empathy_contact_widget_set_account_filter (contact_widget, + empathy_account_chooser_filter_is_connected, NULL); + gtk_widget_show (contact_widget); + + g_signal_connect (personal_dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + g_object_add_weak_pointer (G_OBJECT (personal_dialog), + (gpointer) &personal_dialog); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (personal_dialog), parent); + } + + gtk_widget_show (personal_dialog); +} + /* * New contact dialog */ @@ -242,12 +330,23 @@ static gboolean can_add_contact_to_account (McAccount *account, gpointer user_data) { - EmpathyContactManager *mgr; + EmpathyAccountManager *account_manager; + EmpathyContactManager *contact_manager; + TpConnection *connection; gboolean result; - mgr = empathy_contact_manager_dup_singleton (); - result = empathy_contact_manager_can_add (mgr, account); - g_object_unref (mgr); + account_manager = empathy_account_manager_dup_singleton (); + connection = empathy_account_manager_get_connection (account_manager, + account); + if (!connection) { + g_object_unref (account_manager); + return FALSE; + } + + contact_manager = empathy_contact_manager_dup_singleton (); + result = empathy_contact_manager_can_add (contact_manager, connection); + g_object_unref (contact_manager); + g_object_unref (account_manager); return result; } diff --git a/libempathy-gtk/empathy-contact-dialogs.h b/libempathy-gtk/empathy-contact-dialogs.h index e375f959c..c714c6b96 100644 --- a/libempathy-gtk/empathy-contact-dialogs.h +++ b/libempathy-gtk/empathy-contact-dialogs.h @@ -29,12 +29,13 @@ G_BEGIN_DECLS void empathy_subscription_dialog_show (EmpathyContact *contact, - GtkWindow *parent); + GtkWindow *parent); void empathy_contact_information_dialog_show (EmpathyContact *contact, - GtkWindow *parent, - gboolean edit, - gboolean is_user); -void empathy_new_contact_dialog_show (GtkWindow *parent); + GtkWindow *parent); +void empathy_contact_edit_dialog_show (EmpathyContact *contact, + GtkWindow *parent); +void empathy_contact_personal_dialog_show (GtkWindow *parent); +void empathy_new_contact_dialog_show (GtkWindow *parent); G_END_DECLS diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c index 3fdc7b327..ca224f526 100644 --- a/libempathy-gtk/empathy-contact-list-view.c +++ b/libempathy-gtk/empathy-contact-list-view.c @@ -31,10 +31,12 @@ #include <gdk/gdkkeysyms.h> #include <gtk/gtk.h> +#include <telepathy-glib/util.h> #include <libmissioncontrol/mc-account.h> +#include <libempathy/empathy-account-manager.h> #include <libempathy/empathy-call-factory.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-contact-list.h> #include <libempathy/empathy-contact-groups.h> #include <libempathy/empathy-dispatcher.h> @@ -122,8 +124,8 @@ contact_list_view_tooltip_destroy_cb (GtkWidget *widget, if (priv->tooltip_widget) { DEBUG ("Tooltip destroyed"); + g_object_unref (priv->tooltip_widget); priv->tooltip_widget = NULL; - g_object_unref (widget); } } @@ -188,8 +190,52 @@ OUT: return ret; } +typedef struct { + gchar *new_group; + gchar *old_group; + GdkDragAction action; +} DndGetContactData; + +static void +contact_list_view_dnd_get_contact_free (DndGetContactData *data) +{ + g_free (data->new_group); + g_free (data->old_group); + g_slice_free (DndGetContactData, data); +} + static void -contact_list_view_drag_data_received (GtkWidget *widget, +contact_list_view_drag_got_contact (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *view) +{ + EmpathyContactListViewPriv *priv = GET_PRIV (view); + DndGetContactData *data = user_data; + EmpathyContactList *list; + + if (error != NULL) { + DEBUG ("Error: %s", error->message); + return; + } + + DEBUG ("contact %s (%d) dragged from '%s' to '%s'", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + data->old_group, data->new_group); + + list = empathy_contact_list_store_get_list_iface (priv->store); + if (data->new_group) { + empathy_contact_list_add_to_group (list, contact, data->new_group); + } + if (data->old_group && data->action == GDK_ACTION_MOVE) { + empathy_contact_list_remove_from_group (list, contact, data->old_group); + } +} + +static void +contact_list_view_drag_data_received (GtkWidget *view, GdkDragContext *context, gint x, gint y, @@ -198,88 +244,102 @@ contact_list_view_drag_data_received (GtkWidget *widget, guint time) { EmpathyContactListViewPriv *priv; - EmpathyContactList *list; - EmpathyContactFactory *factory; + EmpathyAccountManager *account_manager; + EmpathyTpContactFactory *factory = NULL; McAccount *account; GtkTreeModel *model; - GtkTreePath *path; GtkTreeViewDropPosition position; - EmpathyContact *contact = NULL; + GtkTreePath *path; const gchar *id; - gchar **strv; + gchar **strv = NULL; + const gchar *account_id; + const gchar *contact_id; gchar *new_group = NULL; gchar *old_group = NULL; + DndGetContactData *data; gboolean is_row; + gboolean success = TRUE; - priv = GET_PRIV (widget); - - id = (const gchar*) selection->data; - DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'", - context->action == GDK_ACTION_MOVE ? "move" : "", - context->action == GDK_ACTION_COPY ? "copy" : "", - id); + priv = GET_PRIV (view); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - strv = g_strsplit (id, "/", 2); - factory = empathy_contact_factory_dup_singleton (); - account = mc_account_lookup (strv[0]); - if (account) { - contact = empathy_contact_factory_get_from_id (factory, - account, - strv[1]); - g_object_unref (account); - } - g_object_unref (factory); - g_strfreev (strv); + /* Get destination group information. */ + is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view), + x, + y, + &path, + &position); - if (!contact) { - DEBUG ("No contact found associated with drag & drop"); - return; + if (is_row) { + new_group = empathy_contact_list_store_get_parent_group (model, + path, NULL); + gtk_tree_path_free (path); } - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_HANDLE, - NULL); - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); - /* Get source group information. */ if (priv->drag_row) { path = gtk_tree_row_reference_get_path (priv->drag_row); if (path) { - old_group = empathy_contact_list_store_get_parent_group (model, path, NULL); + old_group = empathy_contact_list_store_get_parent_group ( + model, path, NULL); gtk_tree_path_free (path); } } - /* Get destination group information. */ - is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), - x, - y, - &path, - &position); - - if (is_row) { - new_group = empathy_contact_list_store_get_parent_group (model, path, NULL); - gtk_tree_path_free (path); + if (!tp_strdiff (old_group, new_group)) { + g_free (new_group); + g_free (old_group); + goto OUT; } - DEBUG ("contact %s (%d) dragged from '%s' to '%s'", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - old_group, new_group); + id = (const gchar*) selection->data; + DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'", + context->action == GDK_ACTION_MOVE ? "move" : "", + context->action == GDK_ACTION_COPY ? "copy" : "", + id); - list = empathy_contact_list_store_get_list_iface (priv->store); - if (new_group) { - empathy_contact_list_add_to_group (list, contact, new_group); + strv = g_strsplit (id, "/", 2); + account_id = strv[0]; + contact_id = strv[1]; + account = mc_account_lookup (account_id); + if (account) { + TpConnection *connection; + + /* FIXME: We assume we have already an account manager */ + account_manager = empathy_account_manager_dup_singleton (); + connection = empathy_account_manager_get_connection (account_manager, + account); + if (connection) { + factory = empathy_tp_contact_factory_dup_singleton (connection); + } + g_object_unref (account_manager); } - if (old_group && context->action == GDK_ACTION_MOVE) { - empathy_contact_list_remove_from_group (list, contact, old_group); + + if (!factory) { + DEBUG ("Failed to get factory for account '%s'", account_id); + success = FALSE; + g_free (new_group); + g_free (old_group); + goto OUT; } - g_free (old_group); - g_free (new_group); + data = g_slice_new0 (DndGetContactData); + data->new_group = new_group; + data->old_group = old_group; + data->action = context->action; - gtk_drag_finish (context, TRUE, FALSE, GDK_CURRENT_TIME); + /* FIXME: We should probably wait for the cb before calling + * gtk_drag_finish */ + empathy_tp_contact_factory_get_from_id (factory, contact_id, + contact_list_view_drag_got_contact, + data, (GDestroyNotify) contact_list_view_dnd_get_contact_free, + G_OBJECT (view)); + + g_object_unref (factory); + +OUT: + g_strfreev (strv); + gtk_drag_finish (context, success, FALSE, GDK_CURRENT_TIME); } static gboolean @@ -414,7 +474,7 @@ contact_list_view_drag_data_get (GtkWidget *widget, gtk_tree_path_free (src_path); - contact = empathy_contact_list_view_get_selected (EMPATHY_CONTACT_LIST_VIEW (widget)); + contact = empathy_contact_list_view_dup_selected (EMPATHY_CONTACT_LIST_VIEW (widget)); if (!contact) { return; } @@ -1158,7 +1218,7 @@ empathy_contact_list_view_new (EmpathyContactListStore *store, } EmpathyContact * -empathy_contact_list_view_get_selected (EmpathyContactListView *view) +empathy_contact_list_view_dup_selected (EmpathyContactListView *view) { EmpathyContactListViewPriv *priv; GtkTreeSelection *selection; @@ -1324,7 +1384,7 @@ contact_list_view_remove_activate_cb (GtkMenuItem *menuitem, EmpathyContactListViewPriv *priv = GET_PRIV (view); EmpathyContact *contact; - contact = empathy_contact_list_view_get_selected (view); + contact = empathy_contact_list_view_dup_selected (view); if (contact) { gchar *text; @@ -1357,7 +1417,7 @@ empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view) g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); - contact = empathy_contact_list_view_get_selected (view); + contact = empathy_contact_list_view_dup_selected (view); if (!contact) { return NULL; } diff --git a/libempathy-gtk/empathy-contact-list-view.h b/libempathy-gtk/empathy-contact-list-view.h index 82990d64f..bb6766c4a 100644 --- a/libempathy-gtk/empathy-contact-list-view.h +++ b/libempathy-gtk/empathy-contact-list-view.h @@ -70,7 +70,7 @@ GType empathy_contact_list_view_get_type (void) G EmpathyContactListView * empathy_contact_list_view_new (EmpathyContactListStore *store, EmpathyContactListFeatureFlags list_features, EmpathyContactFeatureFlags contact_features); -EmpathyContact * empathy_contact_list_view_get_selected (EmpathyContactListView *view); +EmpathyContact * empathy_contact_list_view_dup_selected (EmpathyContactListView *view); gchar * empathy_contact_list_view_get_selected_group (EmpathyContactListView *view); GtkWidget * empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view); GtkWidget * empathy_contact_list_view_get_group_menu (EmpathyContactListView *view); diff --git a/libempathy-gtk/empathy-contact-menu.c b/libempathy-gtk/empathy-contact-menu.c index 9cd9a0b9f..a3cf1da26 100644 --- a/libempathy-gtk/empathy-contact-menu.c +++ b/libempathy-gtk/empathy-contact-menu.c @@ -236,7 +236,7 @@ empathy_contact_file_transfer_menu_item_new (EmpathyContact *contact) static void contact_info_menu_item_activate_cb (EmpathyContact *contact) { - empathy_contact_information_dialog_show (contact, NULL, FALSE, FALSE); + empathy_contact_information_dialog_show (contact, NULL); } GtkWidget * @@ -263,7 +263,7 @@ empathy_contact_info_menu_item_new (EmpathyContact *contact) static void contact_edit_menu_item_activate_cb (EmpathyContact *contact) { - empathy_contact_information_dialog_show (contact, NULL, TRUE, FALSE); + empathy_contact_edit_dialog_show (contact, NULL); } GtkWidget * diff --git a/libempathy-gtk/empathy-contact-selector.c b/libempathy-gtk/empathy-contact-selector.c index 539629a23..f4a302c5b 100644 --- a/libempathy-gtk/empathy-contact-selector.c +++ b/libempathy-gtk/empathy-contact-selector.c @@ -31,6 +31,23 @@ #include "empathy-contact-selector.h" +/** + * SECTION:empathy-contact-selector + * @title:EmpathyContactSelector + * @short_description: A widget used to choose from a list of contacts. + * @include: libempathy-gtk/empathy-contact-selector.h + * + * #EmpathyContactSelector is a widget which extends #GtkComboBox to provide + * a chooser of available contacts. + */ + +/** + * EmpathyContactSelector: + * @parent: parent object + * + * Widget which extends #GtkComboBox to provide a chooser of available contacts. + */ + G_DEFINE_TYPE (EmpathyContactSelector, empathy_contact_selector, GTK_TYPE_COMBO_BOX) @@ -320,14 +337,27 @@ empathy_contact_selector_class_init (EmpathyContactSelectorClass *klass) object_class->get_property = contact_selector_get_property; g_type_class_add_private (klass, sizeof (EmpathyContactSelectorPriv)); + /** + * EmpathyContactSelector:contact-list: + * + * An #EmpathyContactList containing the contacts for the + * #EmpathyContactSelector. + */ g_object_class_install_property (object_class, PROP_CONTACT_LIST, g_param_spec_object ("contact-list", "contact list", "contact list", EMPATHY_TYPE_CONTACT_LIST, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); } -/* public methods */ - +/** + * empathy_contact_selector_new: + * @contact_list: an #EmpathyContactList containing the contacts to list in + * the contact selector + * + * Creates a new #EmpathyContactSelector. + * + * Return value: A new #EmpathyContactSelector + */ GtkWidget * empathy_contact_selector_new (EmpathyContactList *contact_list) { @@ -337,6 +367,16 @@ empathy_contact_selector_new (EmpathyContactList *contact_list) "contact-list", contact_list, NULL)); } +/** + * empathy_contact_selector_dup_selected: + * @selector: An #EmpathyContactSelector + * + * Returns a new reference to the contact which is currently selected in + * @selector, or %NULL if there is no contact selected. The returned contact + * should be unrefed with g_object_unref() when finished with. + * + * Return value: A new reference to the contact currently selected, or %NULL + */ EmpathyContact * empathy_contact_selector_dup_selected (EmpathyContactSelector *selector) { @@ -390,6 +430,19 @@ contact_selector_filter_visible_func (GtkTreeModel *model, return visible; } +/** + * empathy_contact_selector_set_visible: + * @selector: an #EmpathyContactSelector + * @func: an #EmpathyContactSelectorFilterFunc to filter the contacts + * @user_data: data to pass to @func or %NULL + * + * Sets a filter on the @selector so only contacts that return %TRUE + * when passed into @func are visible. + * + * A typical usage for this function would be to only show contacts that + * can send or receive files. In this case, one could use the + * empathy_contact_can_send_files() function + */ void empathy_contact_selector_set_visible (EmpathyContactSelector *selector, EmpathyContactSelectorFilterFunc func, @@ -407,3 +460,14 @@ empathy_contact_selector_set_visible (EmpathyContactSelector *selector, gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->model)); } + +/** + * EmpathyContactSelectorFilterFunc: + * @contact: an #EmpathyContact + * @user_data: user data or %NULL + * + * A function which decides whether the contact indicated by @contact + * is visible. + * + * Return value: whether @contact is visible + */ diff --git a/libempathy-gtk/empathy-contact-selector.h b/libempathy-gtk/empathy-contact-selector.h index f7af92f2c..205b9e411 100644 --- a/libempathy-gtk/empathy-contact-selector.h +++ b/libempathy-gtk/empathy-contact-selector.h @@ -49,6 +49,8 @@ typedef struct _EmpathyContactSelectorClass EmpathyContactSelectorClass; struct _EmpathyContactSelector { GtkComboBox parent; + + /*<private>*/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index ef259b0a4..0821066fa 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -30,7 +30,7 @@ #include <libmissioncontrol/mc-account.h> #include <telepathy-glib/util.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-contact-manager.h> #include <libempathy/empathy-contact-list.h> #include <libempathy/empathy-utils.h> @@ -44,12 +44,31 @@ #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT #include <libempathy/empathy-debug.h> +/** + * SECTION:empathy-contact-widget + * @title:EmpathyContactWidget + * @short_description: A widget used to display and edit details about a contact + * @include: libempathy-empathy-contact-widget.h + * + * #EmpathyContactWidget is a widget which displays appropriate widgets + * with details about a contact, also allowing changing these details, + * if desired. + */ + +/** + * EmpathyContactWidget: + * @parent: parent object + * + * Widget which displays appropriate widgets with details about a contact, + * also allowing changing these details, if desired. + */ + /* Delay before updating the widget when the id entry changed (seconds) */ #define ID_CHANGED_TIMEOUT 1 typedef struct { - EmpathyContactFactory *factory; + EmpathyTpContactFactory *factory; EmpathyContactManager *manager; EmpathyContact *contact; EmpathyContactWidgetFlags flags; @@ -106,8 +125,6 @@ static void contact_widget_contact_update (EmpathyContactWidget *information); static void contact_widget_change_contact (EmpathyContactWidget *information); static void contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser, EmpathyContactWidget *information); -static void contact_widget_account_changed_cb (GtkComboBox *widget, - EmpathyContactWidget *information); static gboolean contact_widget_id_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EmpathyContactWidget *information); static gboolean contact_widget_entry_alias_focus_event_cb ( @@ -153,6 +170,15 @@ enum COL_COUNT }; +/** + * empathy_contact_widget_new: + * @contact: an #EmpathyContact + * @flags: #EmpathyContactWidgetFlags for the new contact widget + * + * Creates a new #EmpathyContactWidget. + * + * Return value: a new #EmpathyContactWidget + */ GtkWidget * empathy_contact_widget_new (EmpathyContact *contact, EmpathyContactWidgetFlags flags) @@ -161,9 +187,10 @@ empathy_contact_widget_new (EmpathyContact *contact, GtkBuilder *gui; gchar *filename; + g_return_val_if_fail (contact == NULL || EMPATHY_IS_CONTACT (contact), NULL); + information = g_slice_new0 (EmpathyContactWidget); information->flags = flags; - information->factory = empathy_contact_factory_dup_singleton (); filename = empathy_file_lookup ("empathy-contact-widget.ui", "libempathy-gtk"); @@ -206,12 +233,25 @@ empathy_contact_widget_new (EmpathyContact *contact, contact_widget_details_setup (information); contact_widget_client_setup (information); - contact_widget_set_contact (information, contact); + if (contact != NULL) + contact_widget_set_contact (information, contact); + + else if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT || + information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) + contact_widget_change_contact (information); return empathy_builder_unref_and_keep_widget (gui, information->vbox_contact_widget); } +/** + * empathy_contact_widget_get_contact: + * @widget: an #EmpathyContactWidget + * + * Get the #EmpathyContact related with the #EmpathyContactWidget @widget. + * + * Returns: the #EmpathyContact associated with @widget + */ EmpathyContact * empathy_contact_widget_get_contact (GtkWidget *widget) { @@ -226,6 +266,13 @@ empathy_contact_widget_get_contact (GtkWidget *widget) return information->contact; } +/** + * empathy_contact_widget_set_contact: + * @widget: an #EmpathyContactWidget + * @contact: a different #EmpathyContact + * + * Change the #EmpathyContact related with the #EmpathyContactWidget @widget. + */ void empathy_contact_widget_set_contact (GtkWidget *widget, EmpathyContact *contact) @@ -242,6 +289,15 @@ empathy_contact_widget_set_contact (GtkWidget *widget, contact_widget_set_contact (information, contact); } +/** + * empathy_contact_widget_set_account_filter: + * @widget: an #EmpathyContactWidget + * @filter: a #EmpathyAccountChooserFilterFunc + * @user_data: user data to pass to @filter, or %NULL + * + * Set a filter on the #EmpathyAccountChooser included in the + * #EmpathyContactWidget. + */ void empathy_contact_widget_set_account_filter ( GtkWidget *widget, @@ -272,10 +328,6 @@ contact_widget_destroy_cb (GtkWidget *widget, { g_source_remove (information->widget_id_timeout); } - if (information->factory) - { - g_object_unref (information->factory); - } if (information->manager) { g_object_unref (information->manager); @@ -299,7 +351,9 @@ contact_widget_remove_contact (EmpathyContactWidget *information) contact_widget_groups_notify_cb, information); g_object_unref (information->contact); + g_object_unref (information->factory); information->contact = NULL; + information->factory = NULL; } } @@ -312,7 +366,13 @@ contact_widget_set_contact (EmpathyContactWidget *information, contact_widget_remove_contact (information); if (contact) + { + TpConnection *connection; + + connection = empathy_contact_get_connection (contact); information->contact = g_object_ref (contact); + information->factory = empathy_tp_contact_factory_dup_singleton (connection); + } /* Update information for widgets */ contact_widget_contact_update (information); @@ -491,10 +551,10 @@ static void update_avatar_chooser_account_cb (EmpathyAccountChooser *account_chooser, EmpathyAvatarChooser *avatar_chooser) { - McAccount *account; + TpConnection *connection; - account = empathy_account_chooser_get_account (account_chooser); - g_object_set (avatar_chooser, "account", account, NULL); + connection = empathy_account_chooser_get_connection (account_chooser); + g_object_set (avatar_chooser, "connection", connection, NULL); } static void @@ -505,8 +565,8 @@ contact_widget_contact_setup (EmpathyContactWidget *information) { information->widget_account = empathy_account_chooser_new (); - g_signal_connect (information->widget_account, "changed", - G_CALLBACK (contact_widget_account_changed_cb), + g_signal_connect_swapped (information->widget_account, "changed", + G_CALLBACK (contact_widget_change_contact), information); } else @@ -636,12 +696,12 @@ contact_widget_contact_update (EmpathyContactWidget *information) if (account) { g_signal_handlers_block_by_func (information->widget_account, - contact_widget_account_changed_cb, + contact_widget_change_contact, information); empathy_account_chooser_set_account ( EMPATHY_ACCOUNT_CHOOSER (information->widget_account), account); g_signal_handlers_unblock_by_func (information->widget_account, - contact_widget_account_changed_cb, information); + contact_widget_change_contact, information); } } else @@ -683,83 +743,71 @@ contact_widget_contact_update (EmpathyContactWidget *information) } static void -contact_widget_change_contact_cb (EmpathyContact *contact, - const GError *error, - gpointer information, - GObject *weak_object) +contact_widget_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) { - if (error) - DEBUG ("Error: %s", error->message); - else - contact_widget_set_contact (information, contact); - g_object_unref (contact); + EmpathyContactWidget *information = user_data; + + if (error != NULL) + { + DEBUG ("Error: %s", error->message); + return; + } + + contact_widget_set_contact (information, contact); } static void contact_widget_change_contact (EmpathyContactWidget *information) { - EmpathyContact *contact; - McAccount *account; + EmpathyTpContactFactory *factory; + TpConnection *connection; - account = empathy_account_chooser_get_account ( + connection = empathy_account_chooser_get_connection ( EMPATHY_ACCOUNT_CHOOSER (information->widget_account)); - if (!account) + if (!connection) return; + factory = empathy_tp_contact_factory_dup_singleton (connection); if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) { const gchar *id; id = gtk_entry_get_text (GTK_ENTRY (information->widget_id)); - if (EMP_STR_EMPTY (id)) - return; - - contact = empathy_contact_factory_get_from_id (information->factory, - account, id); + if (!EMP_STR_EMPTY (id)) + { + empathy_tp_contact_factory_get_from_id (factory, id, + contact_widget_got_contact_cb, information, NULL, + G_OBJECT (information->vbox_contact_widget)); + } } else { - contact = empathy_contact_factory_get_user (information->factory, - account); - } - - if (contact) - { - /* Give the contact ref to the callback */ - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_HANDLE | - EMPATHY_CONTACT_READY_ID, - contact_widget_change_contact_cb, - information, NULL, + empathy_tp_contact_factory_get_from_handle (factory, + tp_connection_get_self_handle (connection), + contact_widget_got_contact_cb, information, NULL, G_OBJECT (information->vbox_contact_widget)); } + + g_object_unref (factory); } static void contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser, EmpathyContactWidget *information) { - if (information->contact && empathy_contact_is_user (information->contact)) - { - McAccount *account; - const gchar *data; - gsize size; - const gchar *mime_type; - - account = empathy_contact_get_account (information->contact); - empathy_avatar_chooser_get_image_data ( - EMPATHY_AVATAR_CHOOSER (information->widget_avatar), - &data, &size, &mime_type); - empathy_contact_factory_set_avatar (information->factory, account, - data, size, mime_type); - } -} - -static void -contact_widget_account_changed_cb (GtkComboBox *widget, - EmpathyContactWidget *information) -{ - contact_widget_change_contact (information); + const gchar *data; + gsize size; + const gchar *mime_type; + + empathy_avatar_chooser_get_image_data ( + EMPATHY_AVATAR_CHOOSER (information->widget_avatar), + &data, &size, &mime_type); + empathy_tp_contact_factory_set_avatar (information->factory, + data, size, mime_type); } static gboolean @@ -781,7 +829,7 @@ contact_widget_entry_alias_focus_event_cb (GtkEditable *editable, const gchar *alias; alias = gtk_entry_get_text (GTK_ENTRY (editable)); - empathy_contact_factory_set_alias (information->factory, + empathy_tp_contact_factory_set_alias (information->factory, information->contact, alias); } diff --git a/libempathy-gtk/empathy-contact-widget.h b/libempathy-gtk/empathy-contact-widget.h index 4ba75e17f..0da5580a3 100644 --- a/libempathy-gtk/empathy-contact-widget.h +++ b/libempathy-gtk/empathy-contact-widget.h @@ -29,6 +29,27 @@ G_BEGIN_DECLS +/** + * EmpathyContactWidgetFlags: + * @EMPATHY_CONTACT_WIDGET_EDIT_NONE: Don't show any widgets to edit any details + * of the contact. This should be the option for widgets that merely display + * information about a contact. + * @EMPATHY_CONTACT_WIDGET_EDIT_ALIAS: Show a #GtkEntry allowing changes to the + * contact's alias. + * @EMPATHY_CONTACT_WIDGET_EDIT_AVATAR: Show an #EmpathyAvatarChooser allowing + * changes to the contact's avatar. + * @EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT: Show an #EmpathyAccountChooser allowing + * changes to the contact's account. + * @EMPATHY_CONTACT_WIDGET_EDIT_ID: Show a #GtkEntry allowing changes to the + * contact's identifier. + * @EMPATHY_CONTACT_WIDGET_EDIT_GROUPS: Show a widget to change the groups the + * contact is in. + * @EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP: Make widgets more designed for a tooltip. + * For example, make widgets not selectable. + * + * Flags used when creating an #EmpathyContactWidget to specify which features + * should be available. + */ typedef enum { EMPATHY_CONTACT_WIDGET_EDIT_NONE = 0, diff --git a/libempathy-gtk/empathy-irc-network-dialog.c b/libempathy-gtk/empathy-irc-network-dialog.c index 89ee5b284..8f7f47bda 100644 --- a/libempathy-gtk/empathy-irc-network-dialog.c +++ b/libempathy-gtk/empathy-irc-network-dialog.c @@ -572,6 +572,7 @@ empathy_irc_network_dialog_show (EmpathyIrcNetwork *network, gtk_window_set_modal (GTK_WINDOW (dialog->dialog), TRUE); irc_network_dialog_network_update_buttons (dialog); + gtk_widget_show_all (dialog->dialog); return dialog->dialog; } diff --git a/libempathy-gtk/empathy-log-window.c b/libempathy-gtk/empathy-log-window.c index 2cec17783..13d9bcbd3 100644 --- a/libempathy-gtk/empathy-log-window.c +++ b/libempathy-gtk/empathy-log-window.c @@ -618,7 +618,7 @@ log_window_chats_populate (EmpathyLogWindow *window) GtkTreeIter iter; account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); view = GTK_TREE_VIEW (window->treeview_chats); model = gtk_tree_view_get_model (view); diff --git a/libempathy-gtk/empathy-new-message-dialog.c b/libempathy-gtk/empathy-new-message-dialog.c index f6eb46a5f..3e6e3f11d 100644 --- a/libempathy-gtk/empathy-new-message-dialog.c +++ b/libempathy-gtk/empathy-new-message-dialog.c @@ -31,7 +31,7 @@ #include <libmissioncontrol/mission-control.h> #include <libempathy/empathy-call-factory.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-contact-manager.h> #include <libempathy/empathy-dispatcher.h> #include <libempathy/empathy-utils.h> @@ -44,6 +44,16 @@ #include "empathy-new-message-dialog.h" #include "empathy-account-chooser.h" +/** + * SECTION:empathy-new-message-dialog + * @title: EmpathyNewMessageDialog + * @short_description: A dialog to show a new message + * @include: libempathy-gtk/empathy-new-message-dialog.h + * + * #EmpathyNewMessageDialog is a dialog which allows a text chat or + * call to be started with any contact on any enabled account. + */ + typedef struct { GtkWidget *dialog; GtkWidget *table_contact; @@ -65,48 +75,54 @@ new_message_dialog_account_changed_cb (GtkWidget *widget, EmpathyNewMessageDialog *dialog) { EmpathyAccountChooser *chooser; - McAccount *account; + TpConnection *connection; EmpathyTpContactList *contact_list; - GList *members, *l; + GList *members; GtkListStore *store; GtkEntryCompletion *completion; GtkTreeIter iter; gchar *tmpstr; - chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); - account = empathy_account_chooser_get_account (chooser); - contact_list = empathy_contact_manager_get_list (dialog->contact_manager, - account); - members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (contact_list)); + /* Remove completions */ completion = gtk_entry_get_completion (GTK_ENTRY (dialog->entry_id)); store = GTK_LIST_STORE (gtk_entry_completion_get_model (completion)); gtk_list_store_clear (store); - for (l = members; l; l = l->next) { - EmpathyContact *contact = l->data; + /* Get members of the new account */ + chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); + connection = empathy_account_chooser_get_connection (chooser); + if (!connection) { + return; + } + contact_list = empathy_contact_manager_get_list (dialog->contact_manager, + connection); + members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (contact_list)); + + /* Add members to the completion */ + while (members) { + EmpathyContact *contact = members->data; - if (!empathy_contact_is_online (contact)) { - continue; - } + if (empathy_contact_is_online (contact)) { + DEBUG ("Adding contact ID %s, Name %s", + empathy_contact_get_id (contact), + empathy_contact_get_name (contact)); - DEBUG ("Adding contact ID %s, Name %s", - empathy_contact_get_id (contact), - empathy_contact_get_name (contact)); + tmpstr = g_strdup_printf ("%s (%s)", + empathy_contact_get_name (contact), + empathy_contact_get_id (contact)); - tmpstr = g_strdup_printf ("%s (%s)", - empathy_contact_get_name (contact), - empathy_contact_get_id (contact)); + gtk_list_store_insert_with_values (store, &iter, -1, + COMPLETION_COL_TEXT, tmpstr, + COMPLETION_COL_ID, empathy_contact_get_id (contact), + COMPLETION_COL_NAME, empathy_contact_get_name (contact), + -1); - gtk_list_store_insert_with_values (store, &iter, -1, - COMPLETION_COL_TEXT, tmpstr, - COMPLETION_COL_ID, empathy_contact_get_id (contact), - COMPLETION_COL_NAME, empathy_contact_get_name (contact), - -1); + g_free (tmpstr); + } - g_free (tmpstr); + g_object_unref (contact); + members = g_list_delete_link (members, members); } - - g_object_unref (account); } static gboolean @@ -166,41 +182,51 @@ new_message_dialog_match_func (GtkEntryCompletion *completion, } static void +new_message_dialog_call_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyCallFactory *call_factory; + + if (error != NULL) { + DEBUG ("Error: %s", error->message); + return; + } + + call_factory = empathy_call_factory_get(); + empathy_call_factory_new_call (call_factory, contact); +} + +static void new_message_dialog_response_cb (GtkWidget *widget, gint response, EmpathyNewMessageDialog *dialog) { - McAccount *account; + TpConnection *connection; const gchar *id; - account = empathy_account_chooser_get_account (EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser)); + connection = empathy_account_chooser_get_connection ( + EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser)); id = gtk_entry_get_text (GTK_ENTRY (dialog->entry_id)); - if (!account || EMP_STR_EMPTY (id)) { - if (account) { - g_object_unref (account); - } + if (!connection || EMP_STR_EMPTY (id)) { gtk_widget_destroy (widget); return; } if (response == 1) { - EmpathyContactFactory *factory; - EmpathyContact *contact; - EmpathyCallFactory *call_factory; - - factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_id (factory, account, id); + EmpathyTpContactFactory *factory; - call_factory = empathy_call_factory_get(); - empathy_call_factory_new_call (call_factory, contact); - - g_object_unref (contact); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_id (factory, id, + new_message_dialog_call_got_contact_cb, + NULL, NULL, NULL); g_object_unref (factory); } else if (response == 2) { - empathy_dispatcher_chat_with_contact_id (account, id, NULL, NULL); + empathy_dispatcher_chat_with_contact_id (connection, id, NULL, NULL); } - g_object_unref (account); gtk_widget_destroy (widget); } @@ -226,6 +252,14 @@ new_message_dialog_destroy_cb (GtkWidget *widget, g_free (dialog); } +/** + * empathy_new_message_dialog_show: + * @parent: parent #GtkWindow of the dialog + * + * Create a new #EmpathyNewMessageDialog and show it. + * + * Return value: the new #EmpathyNewMessageDialog + */ GtkWidget * empathy_new_message_dialog_show (GtkWindow *parent) { diff --git a/libempathy-gtk/empathy-presence-chooser.c b/libempathy-gtk/empathy-presence-chooser.c index 8e9574bc5..f4a325b51 100644 --- a/libempathy-gtk/empathy-presence-chooser.c +++ b/libempathy-gtk/empathy-presence-chooser.c @@ -46,6 +46,24 @@ #include "empathy-ui-utils.h" #include "empathy-images.h" #include "empathy-presence-chooser.h" +#include "empathy-status-preset-dialog.h" + +/** + * SECTION:empathy-presence-chooser + * @title:EmpathyPresenceChooser + * @short_description: A widget used to change presence + * @include: libempathy-gtk/empathy-presence-chooser.h + * + * #EmpathyPresenceChooser is a widget which extends #GtkComboBoxEntry + * to change presence. + */ + +/** + * EmpathyAccountChooser: + * @parent: parent object + * + * Widget which extends #GtkComboBoxEntry to change presence. + */ /* Flashing delay for icons (milliseconds). */ #define FLASH_TIMEOUT 500 @@ -95,16 +113,6 @@ typedef struct { guint flash_timeout_id; } EmpathyPresenceChooserPriv; -typedef struct { - GtkWidget *dialog; - GtkWidget *checkbutton_save; - GtkWidget *comboboxentry_message; - GtkWidget *entry_message; - GtkWidget *combobox_status; - GtkTreeModel *model_status; -} CustomMessageDialog; - -static CustomMessageDialog *message_dialog = NULL; /* States to be listed in the menu. * Each state has a boolean telling if it can have custom message */ static guint states[] = {MC_PRESENCE_AVAILABLE, TRUE, @@ -130,7 +138,6 @@ static void presence_chooser_set_state (McPresence const gchar *status); static void presence_chooser_custom_activate_cb (GtkWidget *item, gpointer user_data); -static void presence_chooser_dialog_show (GtkWindow *parent); G_DEFINE_TYPE (EmpathyPresenceChooser, empathy_presence_chooser, GTK_TYPE_COMBO_BOX_ENTRY); @@ -180,7 +187,8 @@ presence_chooser_create_model (EmpathyPresenceChooser *self) if (states[i+1]) { /* Set custom messages if wanted */ - list = empathy_status_presets_get (states[i], 5); + list = empathy_status_presets_get (states[i], -1); + list = g_list_sort (list, (GCompareFunc) g_utf8_collate); for (l = list; l; l = l->next) { gtk_list_store_insert_with_values (store, NULL, -1, @@ -576,7 +584,7 @@ presence_chooser_changed_cb (GtkComboBox *self, gpointer user_data) } if (type == ENTRY_TYPE_EDIT_CUSTOM) { - GtkWidget *window; + GtkWidget *window, *dialog; presence_chooser_reset_status (EMPATHY_PRESENCE_CHOOSER (self)); @@ -586,7 +594,9 @@ presence_chooser_changed_cb (GtkComboBox *self, gpointer user_data) window = NULL; } - presence_chooser_dialog_show (GTK_WINDOW (window)); + dialog = empathy_status_preset_dialog_new (GTK_WINDOW (window)); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); } else if (type == ENTRY_TYPE_CUSTOM) { gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), @@ -789,6 +799,13 @@ presence_chooser_finalize (GObject *object) G_OBJECT_CLASS (empathy_presence_chooser_parent_class)->finalize (object); } +/** + * empathy_presence_chooser_new: + * + * Creates a new #EmpathyPresenceChooser widget. + * + * Return value: A new #EmpathyPresenceChooser widget + */ GtkWidget * empathy_presence_chooser_new (void) { @@ -946,6 +963,13 @@ presence_chooser_flash_stop (EmpathyPresenceChooser *chooser, empathy_icon_name_for_presence (state)); } +/** + * empathy_presence_chooser_create_menu: + * + * Creates a new #GtkMenu allowing users to change their presence from a menu. + * + * Return value: a new #GtkMenu for changing presence in a menu. + */ GtkWidget * empathy_presence_chooser_create_menu (void) { @@ -1058,220 +1082,9 @@ static void presence_chooser_custom_activate_cb (GtkWidget *item, gpointer user_data) { - presence_chooser_dialog_show (NULL); -} - -static McPresence -presence_chooser_dialog_get_selected (CustomMessageDialog *dialog) -{ - GtkTreeModel *model; - GtkTreeIter iter; - McPresence presence = LAST_MC_PRESENCE; + GtkWidget *dialog; - model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->combobox_status)); - if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->combobox_status), &iter)) { - gtk_tree_model_get (model, &iter, - COL_PRESENCE, &presence, - -1); - } - - return presence; + dialog = empathy_status_preset_dialog_new (NULL); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); } - -static void -presence_chooser_dialog_status_changed_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - GtkListStore *store; - GtkTreeIter iter; - McPresence presence = LAST_MC_PRESENCE; - GList *messages, *l; - - presence = presence_chooser_dialog_get_selected (dialog); - - store = gtk_list_store_new (1, G_TYPE_STRING); - messages = empathy_status_presets_get (presence, -1); - for (l = messages; l; l = l->next) { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, l->data, -1); - } - - gtk_entry_set_text (GTK_ENTRY (dialog->entry_message), - messages ? messages->data : ""); - - g_list_free (messages); - - gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->comboboxentry_message), - GTK_TREE_MODEL (store)); - - g_object_unref (store); -} - -static void -presence_chooser_dialog_message_changed_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - McPresence presence; - GList *messages, *l; - const gchar *text; - gboolean found = FALSE; - - presence = presence_chooser_dialog_get_selected (dialog); - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message)); - - messages = empathy_status_presets_get (presence, -1); - for (l = messages; l; l = l->next) { - if (!tp_strdiff (text, l->data)) { - found = TRUE; - break; - } - } - g_list_free (messages); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save), - found); -} - -static void -presence_chooser_dialog_save_toggled_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - gboolean active; - McPresence state; - const gchar *text; - - active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save)); - state = presence_chooser_dialog_get_selected (dialog); - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message)); - - if (active) { - empathy_status_presets_set_last (state, text); - } else { - empathy_status_presets_remove (state, text); - } -} - -static void -presence_chooser_dialog_setup (CustomMessageDialog *dialog) -{ - GtkListStore *store; - GtkCellRenderer *renderer; - GtkTreeIter iter; - guint i; - - store = gtk_list_store_new (COL_COUNT, - G_TYPE_STRING, /* Icon name */ - G_TYPE_STRING, /* Label */ - MC_TYPE_PRESENCE); /* Presence */ - gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->combobox_status), - GTK_TREE_MODEL (store)); - - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, FALSE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, - "icon-name", COL_ICON, - NULL); - g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, TRUE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, - "text", COL_LABEL, - NULL); - - for (i = 0; i < G_N_ELEMENTS (states); i += 2) { - if (!states[i+1]) { - continue; - } - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_ICON, empathy_icon_name_for_presence (states[i]), - COL_LABEL, empathy_presence_get_default_message (states[i]), - COL_PRESENCE, states[i], - -1); - } - - gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_status), 0); -} - -static void -presence_chooser_dialog_response_cb (GtkWidget *widget, - gint response, - CustomMessageDialog *dialog) -{ - if (response == GTK_RESPONSE_APPLY) { - McPresence state; - const gchar *text; - - state = presence_chooser_dialog_get_selected (dialog); - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message)); - - presence_chooser_set_state (state, text); - } - - gtk_widget_destroy (widget); -} - -static void -presence_chooser_dialog_destroy_cb (GtkWidget *widget, - CustomMessageDialog *dialog) -{ - - g_free (dialog); - message_dialog = NULL; -} - -static void -presence_chooser_dialog_show (GtkWindow *parent) -{ - GtkBuilder *gui; - gchar *filename; - - if (message_dialog) { - gtk_window_present (GTK_WINDOW (message_dialog->dialog)); - return; - } - - message_dialog = g_new0 (CustomMessageDialog, 1); - - filename = empathy_file_lookup ("empathy-presence-chooser.ui", - "libempathy-gtk"); - gui = empathy_builder_get_file (filename, - "custom_message_dialog", &message_dialog->dialog, - "checkbutton_save", &message_dialog->checkbutton_save, - "comboboxentry_message", &message_dialog->comboboxentry_message, - "combobox_status", &message_dialog->combobox_status, - NULL); - g_free (filename); - - empathy_builder_connect (gui, message_dialog, - "custom_message_dialog", "destroy", presence_chooser_dialog_destroy_cb, - "custom_message_dialog", "response", presence_chooser_dialog_response_cb, - "combobox_status", "changed", presence_chooser_dialog_status_changed_cb, - "checkbutton_save", "toggled", presence_chooser_dialog_save_toggled_cb, - NULL); - - g_object_unref (gui); - - /* Setup the message combobox */ - message_dialog->entry_message = GTK_BIN (message_dialog->comboboxentry_message)->child; - gtk_entry_set_activates_default (GTK_ENTRY (message_dialog->entry_message), TRUE); - gtk_entry_set_width_chars (GTK_ENTRY (message_dialog->entry_message), 25); - g_signal_connect (message_dialog->entry_message, "changed", - G_CALLBACK (presence_chooser_dialog_message_changed_cb), - message_dialog); - - presence_chooser_dialog_setup (message_dialog); - - gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (message_dialog->comboboxentry_message), 0); - - if (parent) { - gtk_window_set_transient_for ( - GTK_WINDOW (message_dialog->dialog), - parent); - } - - gtk_widget_show_all (message_dialog->dialog); -} - diff --git a/libempathy-gtk/empathy-presence-chooser.h b/libempathy-gtk/empathy-presence-chooser.h index 138e1dc7f..dab95f553 100644 --- a/libempathy-gtk/empathy-presence-chooser.h +++ b/libempathy-gtk/empathy-presence-chooser.h @@ -43,6 +43,8 @@ typedef struct _EmpathyPresenceChooserClass EmpathyPresenceChooserClass; struct _EmpathyPresenceChooser { GtkComboBoxEntry parent; + + /*<private>*/ gpointer priv; }; diff --git a/libempathy-gtk/empathy-presence-chooser.ui b/libempathy-gtk/empathy-presence-chooser.ui deleted file mode 100644 index 6e0a155d0..000000000 --- a/libempathy-gtk/empathy-presence-chooser.ui +++ /dev/null @@ -1,140 +0,0 @@ -<?xml version="1.0"?> -<interface> - <requires lib="gtk+" version="2.16"/> - <!-- interface-naming-policy toplevel-contextual --> - <object class="GtkDialog" id="custom_message_dialog"> - <property name="visible">True</property> - <property name="border_width">5</property> - <property name="title" translatable="yes">Custom message</property> - <property name="resizable">False</property> - <property name="type_hint">dialog</property> - <property name="has_separator">False</property> - <child internal-child="vbox"> - <object class="GtkVBox" id="dialog-vbox6"> - <property name="visible">True</property> - <child> - <object class="GtkTable" id="table1"> - <property name="visible">True</property> - <property name="border_width">5</property> - <property name="n_rows">3</property> - <property name="n_columns">2</property> - <property name="column_spacing">6</property> - <property name="row_spacing">6</property> - <child> - <object class="GtkComboBox" id="combobox_status"> - <property name="visible">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <object class="GtkComboBoxEntry" id="comboboxentry_message"> - <property name="visible">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <object class="GtkCheckButton" id="checkbutton_save"> - <property name="label" translatable="yes">Save message</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> - </object> - <packing> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label472"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Message:</property> - </object> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label471"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Status:</property> - </object> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child internal-child="action_area"> - <object class="GtkHButtonBox" id="dialog-action_area6"> - <property name="visible">True</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="closebutton1"> - <property name="label">gtk-cancel</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="receives_default">False</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="button1"> - <property name="label">gtk-apply</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="receives_default">False</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-6">closebutton1</action-widget> - <action-widget response="-10">button1</action-widget> - </action-widgets> - </object> -</interface> diff --git a/libempathy-gtk/empathy-profile-chooser.c b/libempathy-gtk/empathy-profile-chooser.c index fd68dd8b0..10eb3791a 100644 --- a/libempathy-gtk/empathy-profile-chooser.c +++ b/libempathy-gtk/empathy-profile-chooser.c @@ -30,6 +30,16 @@ #include "empathy-profile-chooser.h" #include "empathy-ui-utils.h" +/** + * SECTION:empathy-profile-chooser + * @title: EmpathyProfileChooser + * @short_description: A widget used to choose from a list of profiles + * @include: libempathy-gtk/empathy-account-chooser.h + * + * #EmpathyProfileChooser is a widget which provides a chooser of available + * profiles. + */ + enum { COL_ICON, COL_LABEL, @@ -37,8 +47,17 @@ enum { COL_COUNT }; +/** + * empathy_profile_chooser_dup_selected: + * @widget: an #EmpathyProfileChooser + * + * Returns a new reference to the selected #McProfile in @widget. The returned + * #McProfile should be unrefed with g_object_unref() when finished with. + * + * Return value: a new reference to the selected #McProfile + */ McProfile* -empathy_profile_chooser_get_selected (GtkWidget *widget) +empathy_profile_chooser_dup_selected (GtkWidget *widget) { GtkTreeModel *model; GtkTreeIter iter; @@ -54,6 +73,14 @@ empathy_profile_chooser_get_selected (GtkWidget *widget) return profile; } +/** + * empathy_profile_chooser_n_profiles: + * @widget: an #EmpathyProfileChooser + * + * Returns the number of profiles in @widget. + * + * Return value: the number of profiles in @widget + */ gint empathy_profile_chooser_n_profiles (GtkWidget *widget) { @@ -115,6 +142,13 @@ profile_chooser_sort_func (GtkTreeModel *model, return cmp; } +/** + * empathy_profile_chooser_new: + * + * Creates a new #EmpathyProfileChooser widget. + * + * Return value: a new #EmpathyProfileChooser widget + */ GtkWidget * empathy_profile_chooser_new (void) { diff --git a/libempathy-gtk/empathy-profile-chooser.h b/libempathy-gtk/empathy-profile-chooser.h index 8cdc33d67..74c761cc4 100644 --- a/libempathy-gtk/empathy-profile-chooser.h +++ b/libempathy-gtk/empathy-profile-chooser.h @@ -27,7 +27,7 @@ G_BEGIN_DECLS GtkWidget * empathy_profile_chooser_new (void); -McProfile * empathy_profile_chooser_get_selected (GtkWidget *widget); +McProfile * empathy_profile_chooser_dup_selected (GtkWidget *widget); gint empathy_profile_chooser_n_profiles (GtkWidget *widget); G_END_DECLS diff --git a/libempathy-gtk/empathy-status-preset-dialog.c b/libempathy-gtk/empathy-status-preset-dialog.c new file mode 100644 index 000000000..734ac356a --- /dev/null +++ b/libempathy-gtk/empathy-status-preset-dialog.c @@ -0,0 +1,549 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * empathy-status-preset-dialog.c + * + * EmpathyStatusPresetDialog - a dialog for adding and removing preset status + * messages. + * + * Copyright (C) 2009 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Davyd Madeley <davyd.madeley@collabora.co.uk> + */ +/** + * SECTION:empathy-status-preset-dialog + * @title: EmpathyStatusPresetDialog + * @short_description: a dialog for editing the saved status messages + * @include: libempathy-gtk/empathy-status-preset-dialog.h + * + * #EmpathyStatusPresetDialog is a dialog allowing the user to add/remove/edit + * their saved status messages. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> +#include <gtk/gtk.h> + +#include <libmissioncontrol/mc-enum-types.h> + +#include <libempathy/empathy-utils.h> +#include <libempathy/empathy-status-presets.h> + +#define DEBUG_FLAG EMPATHY_DEBUG_OTHER +#include <libempathy/empathy-debug.h> + +#include "empathy-ui-utils.h" +#include "empathy-status-preset-dialog.h" + +#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyStatusPresetDialog) + +G_DEFINE_TYPE (EmpathyStatusPresetDialog, empathy_status_preset_dialog, GTK_TYPE_DIALOG); + +static McPresence states[] = { + MC_PRESENCE_AVAILABLE, + MC_PRESENCE_DO_NOT_DISTURB, + MC_PRESENCE_AWAY +}; + +typedef struct _EmpathyStatusPresetDialogPriv EmpathyStatusPresetDialogPriv; +struct _EmpathyStatusPresetDialogPriv +{ + /* block status_preset_dialog_add_combo_changed() when > 0 */ + int block_add_combo_changed; + + GtkWidget *presets_treeview; + GtkWidget *add_combobox; + GtkWidget *add_button; + + GtkTreeIter selected_iter; + gboolean add_combo_changed; + char *saved_status; +}; + +enum +{ + PRESETS_STORE_STATE, + PRESETS_STORE_ICON_NAME, + PRESETS_STORE_STATUS, + PRESETS_STORE_N_COLS +}; + +enum +{ + ADD_COMBO_STATE, + ADD_COMBO_ICON_NAME, + ADD_COMBO_STATUS, + ADD_COMBO_DEFAULT_TEXT, + ADD_COMBO_N_COLS +}; + +static void +empathy_status_preset_dialog_finalize (GObject *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + + g_free (priv->saved_status); + + G_OBJECT_CLASS (empathy_status_preset_dialog_parent_class)->finalize (self); +} + +static void +empathy_status_preset_dialog_class_init (EmpathyStatusPresetDialogClass *class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = empathy_status_preset_dialog_finalize; + + g_type_class_add_private (gobject_class, + sizeof (EmpathyStatusPresetDialogPriv)); +} + +static void +status_preset_dialog_presets_update (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkListStore *store; + int i; + + store = GTK_LIST_STORE (gtk_tree_view_get_model ( + GTK_TREE_VIEW (priv->presets_treeview))); + + gtk_list_store_clear (store); + + for (i = 0; i < G_N_ELEMENTS (states); i++) { + GList *presets, *l; + const char *icon_name; + + icon_name = empathy_icon_name_for_presence (states[i]); + presets = empathy_status_presets_get (states[i], -1); + presets = g_list_sort (presets, (GCompareFunc) g_utf8_collate); + + for (l = presets; l; l = l->next) { + char *preset = (char *) l->data; + + gtk_list_store_insert_with_values (store, + NULL, -1, + PRESETS_STORE_STATE, states[i], + PRESETS_STORE_ICON_NAME, icon_name, + PRESETS_STORE_STATUS, preset, + -1); + } + + g_list_free (presets); + } +} + +static void +status_preset_add_combo_reset (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->add_combobox), + &priv->selected_iter); +} + +static void +status_preset_dialog_setup_add_combobox (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *combobox = priv->add_combobox; + GtkListStore *store; + GtkCellRenderer *renderer; + int i; + + store = gtk_list_store_new (ADD_COMBO_N_COLS, + MC_TYPE_PRESENCE, /* ADD_COMBO_STATE */ + G_TYPE_STRING, /* ADD_COMBO_ICON_NAME */ + G_TYPE_STRING, /* ADD_COMBO_STATUS */ + G_TYPE_STRING); /* ADD_COMBO_DEFAULT_TEXT */ + + gtk_combo_box_set_model (GTK_COMBO_BOX (combobox), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (combobox), + ADD_COMBO_DEFAULT_TEXT); + + for (i = 0; i < G_N_ELEMENTS (states); i++) { + gtk_list_store_insert_with_values (store, NULL, -1, + ADD_COMBO_STATE, states[i], + ADD_COMBO_ICON_NAME, empathy_icon_name_for_presence (states[i]), + ADD_COMBO_STATUS, empathy_presence_get_default_message (states[i]), + ADD_COMBO_DEFAULT_TEXT, "", + -1); + } + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox)); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox), renderer, + "icon-name", ADD_COMBO_ICON_NAME); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox), renderer, + "text", ADD_COMBO_STATUS); + g_object_set (renderer, + "style", PANGO_STYLE_ITALIC, + "foreground", "Gray", /* FIXME - theme */ + NULL); + + gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0); +} + +static void +status_preset_dialog_status_edited (GtkCellRendererText *renderer, + char *path_str, + char *new_status, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + McPresence state; + char *old_status; + gboolean valid; + + if (strlen (new_status) == 0) { + /* status is empty, ignore */ + return; + } + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->presets_treeview)); + path = gtk_tree_path_new_from_string (path_str); + valid = gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + + if (!valid) return; + + gtk_tree_model_get (model, &iter, + PRESETS_STORE_STATE, &state, + PRESETS_STORE_STATUS, &old_status, + -1); + + if (!strcmp (old_status, new_status)) { + /* statuses are the same */ + g_free (old_status); + return; + } + + DEBUG ("EDITED STATUS (%s) -> (%s)\n", old_status, new_status); + + empathy_status_presets_remove (state, old_status); + empathy_status_presets_set_last (state, new_status); + + g_free (old_status); + + status_preset_dialog_presets_update (self); +} + +static void +status_preset_dialog_setup_presets_treeview (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *treeview = priv->presets_treeview; + GtkListStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + + store = gtk_list_store_new (PRESETS_STORE_N_COLS, + MC_TYPE_PRESENCE, /* PRESETS_STORE_STATE */ + G_TYPE_STRING, /* PRESETS_STORE_ICON_NAME */ + G_TYPE_STRING); /* PRESETS_STORE_STATUS */ + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + status_preset_dialog_presets_update (self); + + column = gtk_tree_view_column_new (); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "icon-name", PRESETS_STORE_ICON_NAME); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "text", PRESETS_STORE_STATUS); + g_object_set (renderer, + "editable", TRUE, + NULL); + g_signal_connect (renderer, "edited", + G_CALLBACK (status_preset_dialog_status_edited), self); +} + +static void +status_preset_dialog_preset_selection_changed (GtkTreeSelection *selection, + GtkWidget *remove_button) +{ + /* update the sensitivity of the Remove button */ + gtk_widget_set_sensitive (remove_button, + gtk_tree_selection_get_selected (selection, NULL, NULL)); +} + +static void +status_preset_dialog_preset_remove (GtkButton *button, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + McPresence state; + char *status; + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (priv->presets_treeview)); + + g_return_if_fail (gtk_tree_selection_get_selected (selection, + &model, &iter)); + + gtk_tree_model_get (model, &iter, + PRESETS_STORE_STATE, &state, + PRESETS_STORE_STATUS, &status, + -1); + + DEBUG ("REMOVE PRESET (%i, %s)\n", state, status); + empathy_status_presets_remove (state, status); + + g_free (status); + + status_preset_dialog_presets_update (self); +} + +static void +status_preset_dialog_set_add_combo_changed (EmpathyStatusPresetDialog *self, + gboolean state, + gboolean reset_text) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *entry; + + entry = gtk_bin_get_child (GTK_BIN (priv->add_combobox)); + + priv->add_combo_changed = state; + gtk_widget_set_sensitive (priv->add_button, state); + + if (state) { + gtk_widget_modify_text (entry, GTK_STATE_NORMAL, NULL); + } else { + GdkColor colour; + + gdk_color_parse ("Gray", &colour); /* FIXME - theme */ + gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &colour); + + if (reset_text) { + priv->block_add_combo_changed++; + gtk_entry_set_text (GTK_ENTRY (entry), + _("Enter Custom Message")); + priv->block_add_combo_changed--; + } + } +} + +static void +status_preset_dialog_add_combo_changed (GtkComboBox *combo, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkWidget *entry; + GtkTreeModel *model; + GtkTreeIter iter; + + if (priv->block_add_combo_changed) return; + + model = gtk_combo_box_get_model (combo); + entry = gtk_bin_get_child (GTK_BIN (combo)); + + if (gtk_combo_box_get_active_iter (combo, &iter)) { + char *icon_name; + + priv->selected_iter = iter; + gtk_tree_model_get (model, &iter, + PRESETS_STORE_ICON_NAME, &icon_name, + -1); + + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), + GTK_ENTRY_ICON_PRIMARY, + icon_name); + + g_free (icon_name); + + status_preset_dialog_set_add_combo_changed (self, FALSE, TRUE); + if (priv->saved_status && strlen (priv->saved_status) > 0) { + gtk_entry_set_text (GTK_ENTRY (entry), + priv->saved_status); + } + } else { + g_free (priv->saved_status); + priv->saved_status = g_strdup ( + gtk_entry_get_text (GTK_ENTRY (entry))); + + status_preset_dialog_set_add_combo_changed (self, + strlen (priv->saved_status) > 0, FALSE); + } +} + +static void +status_preset_dialog_add_preset (GtkWidget *widget, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + GtkTreeModel *model; + GtkWidget *entry; + McPresence state; + const char *status; + + g_return_if_fail (priv->add_combo_changed); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->add_combobox)); + entry = gtk_bin_get_child (GTK_BIN (priv->add_combobox)); + + status = gtk_entry_get_text (GTK_ENTRY (entry)); + gtk_tree_model_get (model, &priv->selected_iter, + PRESETS_STORE_STATE, &state, + -1); + + DEBUG ("ADD PRESET (%i, %s)\n", state, status); + empathy_status_presets_set_last (state, status); + + status_preset_dialog_presets_update (self); + status_preset_add_combo_reset (self); +} + +static gboolean +status_preset_dialog_add_combo_press_event (GtkWidget *widget, + GdkEventButton *event, + EmpathyStatusPresetDialog *self) +{ + if (!GTK_WIDGET_HAS_FOCUS (widget)) { + /* if the widget isn't focused, focus it and select the text */ + gtk_widget_grab_focus (widget); + gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1); + + return TRUE; + } + + return FALSE; +} + +static gboolean +status_preset_dialog_add_combo_focus_out (GtkWidget *widget, + GdkEventFocus *event, + EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = GET_PRIV (self); + const char *status; + + gtk_editable_set_position (GTK_EDITABLE (widget), 0); + + status = gtk_entry_get_text (GTK_ENTRY (widget)); + status_preset_dialog_set_add_combo_changed (self, + priv->add_combo_changed && strlen (status) > 0, + TRUE); + + return FALSE; +} + +static void +empathy_status_preset_dialog_init (EmpathyStatusPresetDialog *self) +{ + EmpathyStatusPresetDialogPriv *priv = self->priv = + G_TYPE_INSTANCE_GET_PRIVATE (self, + EMPATHY_TYPE_STATUS_PRESET_DIALOG, + EmpathyStatusPresetDialogPriv); + GtkBuilder *gui; + GtkWidget *toplevel_vbox, *remove_button, *entry; + char *filename; + + gtk_window_set_title (GTK_WINDOW (self), + _("Edit Custom Messages")); + gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE); + gtk_dialog_add_button (GTK_DIALOG (self), + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); + + filename = empathy_file_lookup ("empathy-status-preset-dialog.ui", + "libempathy-gtk"); + gui = empathy_builder_get_file (filename, + "toplevel-vbox", &toplevel_vbox, + "presets-treeview", &priv->presets_treeview, + "remove-button", &remove_button, + "add-combobox", &priv->add_combobox, + "add-button", &priv->add_button, + NULL); + g_free (filename); + + g_signal_connect (gtk_tree_view_get_selection ( + GTK_TREE_VIEW (priv->presets_treeview)), + "changed", + G_CALLBACK (status_preset_dialog_preset_selection_changed), + remove_button); + + entry = gtk_bin_get_child (GTK_BIN (priv->add_combobox)); + g_signal_connect (entry, "activate", + G_CALLBACK (status_preset_dialog_add_preset), self); + g_signal_connect (entry, "button-press-event", + G_CALLBACK (status_preset_dialog_add_combo_press_event), + self); + g_signal_connect (entry, "focus-out-event", + G_CALLBACK (status_preset_dialog_add_combo_focus_out), + self); + + empathy_builder_connect (gui, self, + "remove-button", "clicked", status_preset_dialog_preset_remove, + "add-combobox", "changed", status_preset_dialog_add_combo_changed, + "add-button", "clicked", status_preset_dialog_add_preset, + NULL); + + status_preset_dialog_setup_presets_treeview (self); + status_preset_dialog_setup_add_combobox (self); + + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (self)->vbox), toplevel_vbox, + TRUE, TRUE, 0); + + g_object_unref (gui); +} + +/** + * empathy_status_preset_dialog_new: + * @parent: the parent window of this dialog (or NULL) + * + * Creates a new #EmpathyStatusPresetDialog that allows the user to + * add/remove/edit their saved status messages. + * + * Returns: the newly constructed dialog. + */ +GtkWidget * +empathy_status_preset_dialog_new (GtkWindow *parent) +{ + GtkWidget *self = g_object_new (EMPATHY_TYPE_STATUS_PRESET_DIALOG, + NULL); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (self), parent); + } + + return self; +} diff --git a/libempathy-gtk/empathy-status-preset-dialog.h b/libempathy-gtk/empathy-status-preset-dialog.h new file mode 100644 index 000000000..e53c3d8ad --- /dev/null +++ b/libempathy-gtk/empathy-status-preset-dialog.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * empathy-status-preset-dialog.c + * + * EmpathyStatusPresetDialog - a dialog for adding and removing preset status + * messages. + * + * Copyright (C) 2009 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Davyd Madeley <davyd.madeley@collabora.co.uk> + */ + +#ifndef __EMPATHY_STATUS_PRESET_DIALOG_H__ +#define __EMPATHY_STATUS_PRESET_DIALOG_H__ + +#include <glib.h> + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_STATUS_PRESET_DIALOG (empathy_status_preset_dialog_get_type ()) +#define EMPATHY_STATUS_PRESET_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG, EmpathyStatusPresetDialog)) +#define EMPATHY_STATUS_PRESET_DIALOG_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG, EmpathyStatusPresetDialogClass)) +#define EMPATHY_IS_STATUS_PRESET_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG)) +#define EMPATHY_IS_STATUS_PRESET_DIALOG_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG)) +#define EMPATHY_STATUS_PRESET_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_STATUS_PRESET_DIALOG, EmpathyStatusPresetDialogClass)) + +typedef struct _EmpathyStatusPresetDialog EmpathyStatusPresetDialog; +typedef struct _EmpathyStatusPresetDialogClass EmpathyStatusPresetDialogClass; + +struct _EmpathyStatusPresetDialog +{ + GtkDialog parent; + + /*< private >*/ + gpointer priv; +}; + +struct _EmpathyStatusPresetDialogClass +{ + GtkDialogClass parent_class; +}; + +GType empathy_status_preset_dialog_get_type (void); +GtkWidget *empathy_status_preset_dialog_new (GtkWindow *parent); + +G_END_DECLS + +#endif diff --git a/libempathy-gtk/empathy-status-preset-dialog.ui b/libempathy-gtk/empathy-status-preset-dialog.ui new file mode 100644 index 000000000..ead8ab85d --- /dev/null +++ b/libempathy-gtk/empathy-status-preset-dialog.ui @@ -0,0 +1,116 @@ +<?xml version="1.0"?> +<interface> + <requires lib="gtk+" version="2.16"/> + <!-- interface-naming-policy project-wide --> + <object class="GtkVBox" id="toplevel-vbox"> + <property name="visible">True</property> + <property name="border_width">6</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Saved Presets</property> + <property name="mnemonic_widget">add-combobox</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">never</property> + <property name="shadow_type">etched-in</property> + <child> + <object class="GtkTreeView" id="presets-treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="remove-button"> + <property name="label" translatable="yes">gtk-remove</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Add _New Preset</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">add-combobox</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="spacing">3</property> + <child> + <object class="GtkComboBoxEntry" id="add-combobox"> + <property name="visible">True</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="add-button"> + <property name="label" translatable="yes">gtk-add</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">4</property> + </packing> + </child> + </object> +</interface> diff --git a/libempathy-gtk/empathy-theme-boxes.c b/libempathy-gtk/empathy-theme-boxes.c index 0561ecac0..5b435f1d5 100644 --- a/libempathy-gtk/empathy-theme-boxes.c +++ b/libempathy-gtk/empathy-theme-boxes.c @@ -208,9 +208,9 @@ theme_boxes_maybe_append_header (EmpathyThemeBoxes *theme, DEBUG ("Maybe add fancy header"); /* Only insert a header if the previously inserted block is not the same - * as this one. This catches all the different cases: + * as this one. */ - if (last_contact && empathy_contact_equal (last_contact, contact)) { + if (last_contact == contact) { return; } diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am index f82f4cc0f..ba1f6f8c7 100644 --- a/libempathy/Makefile.am +++ b/libempathy/Makefile.am @@ -21,10 +21,9 @@ libempathy_la_SOURCES = \ empathy-account-manager.c \ empathy-chatroom.c \ empathy-chatroom-manager.c \ - empathy-call-factory.c \ - empathy-call-handler.c \ + empathy-call-factory.c \ + empathy-call-handler.c \ empathy-contact.c \ - empathy-contact-factory.c \ empathy-contact-groups.c \ empathy-contact-list.c \ empathy-contact-manager.c \ @@ -47,7 +46,6 @@ libempathy_la_SOURCES = \ empathy-tp-contact-factory.c \ empathy-tp-contact-list.c \ empathy-tp-file.c \ - empathy-tp-group.c \ empathy-tp-roomlist.c \ empathy-tp-tube.c \ empathy-tube-handler.c \ @@ -72,7 +70,6 @@ libempathy_headers = \ empathy-call-factory.h \ empathy-call-handler.h \ empathy-contact.h \ - empathy-contact-factory.h \ empathy-contact-groups.h \ empathy-contact-list.h \ empathy-contact-manager.h \ @@ -95,7 +92,6 @@ libempathy_headers = \ empathy-tp-contact-factory.h \ empathy-tp-contact-list.h \ empathy-tp-file.h \ - empathy-tp-group.h \ empathy-tp-roomlist.h \ empathy-tp-tube.h \ empathy-tube-handler.h \ diff --git a/libempathy/empathy-account-manager.c b/libempathy/empathy-account-manager.c index 5962a8676..b84543176 100644 --- a/libempathy/empathy-account-manager.c +++ b/libempathy/empathy-account-manager.c @@ -26,19 +26,24 @@ #include "empathy-marshal.h" #include "empathy-utils.h" +#define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT +#include <libempathy/empathy-debug.h> + #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountManager) typedef struct { McAccountMonitor *monitor; MissionControl *mc; - GHashTable *accounts; + GHashTable *accounts; /* McAccount -> AccountData */ + GHashTable *connections; /* TpConnection -> McAccount */ int connected; int connecting; gboolean dispose_run; } EmpathyAccountManagerPriv; typedef struct { + TpConnection *connection; McPresence presence; TpConnectionStatus status; gboolean is_enabled; @@ -54,6 +59,7 @@ enum { ACCOUNT_CHANGED, ACCOUNT_CONNECTION_CHANGED, ACCOUNT_PRESENCE_CHANGED, + NEW_CONNECTION, LAST_SIGNAL }; @@ -112,11 +118,75 @@ account_data_free (AccountData *data) g_source_remove (data->source_id); data->source_id = 0; } + if (data->connection != NULL) + { + g_object_unref (data->connection); + data->connection = NULL; + } g_slice_free (AccountData, data); } static void +connection_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + EmpathyAccountManager *manager) +{ + EmpathyAccountManagerPriv *priv = GET_PRIV (manager); + McAccount *account; + AccountData *data; + + DEBUG ("Message: %s", message); + + account = g_hash_table_lookup (priv->connections, connection); + g_assert (account != NULL); + + data = g_hash_table_lookup (priv->accounts, account); + g_assert (data != NULL); + + g_object_unref (data->connection); + data->connection = NULL; + + g_hash_table_remove (priv->connections, connection); +} + +static void +connection_ready_cb (TpConnection *connection, + const GError *error, + gpointer manager) +{ + /* Errors will be handled in invalidated callback */ + if (error != NULL) + return; + + g_signal_emit (manager, signals[NEW_CONNECTION], 0, connection); +} + +static void +account_manager_update_connection (EmpathyAccountManager *manager, + AccountData *data, + McAccount *account) +{ + EmpathyAccountManagerPriv *priv = GET_PRIV (manager); + + if (data->connection) + return; + + data->connection = mission_control_get_tpconnection (priv->mc, account, NULL); + if (data->connection != NULL) + { + g_signal_connect (data->connection, "invalidated", + G_CALLBACK (connection_invalidated_cb), manager); + g_hash_table_insert (priv->connections, g_object_ref (data->connection), + g_object_ref (account)); + tp_connection_call_when_ready (data->connection, connection_ready_cb, + manager); + } +} + +static void account_created_cb (McAccountMonitor *mon, gchar *account_name, EmpathyAccountManager *manager) @@ -132,6 +202,7 @@ account_created_cb (McAccountMonitor *mon, AccountData *data; data = account_data_new_default (priv->mc, account); + g_hash_table_insert (priv->accounts, g_object_ref (account), data); initial_status = mission_control_get_connection_status (priv->mc, account, NULL); @@ -141,12 +212,10 @@ account_created_cb (McAccountMonitor *mon, else if (initial_status == TP_CONNECTION_STATUS_CONNECTING) priv->connecting++; - /* the reference returned by mc_account_lookup is owned by the - * hash table. - */ - g_hash_table_insert (priv->accounts, account, data); + account_manager_update_connection (manager, data, account); g_signal_emit (manager, signals[ACCOUNT_CREATED], 0, account); + g_object_unref (account); } } @@ -313,10 +382,11 @@ account_status_changed_idle_cb (ChangedSignalData *signal_data) if (status == TP_CONNECTION_STATUS_CONNECTED) { - if (data->source_id > 0) { - g_source_remove (data->source_id); - data->source_id = 0; - } + if (data->source_id > 0) + { + g_source_remove (data->source_id); + data->source_id = 0; + } data->source_id = g_timeout_add_seconds (10, remove_data_timeout, @@ -325,6 +395,8 @@ account_status_changed_idle_cb (ChangedSignalData *signal_data) emit_connection = TRUE; } + account_manager_update_connection (manager, data, account); + if (emit_presence) g_signal_emit (manager, signals[ACCOUNT_PRESENCE_CHANGED], 0, account, presence, old_p); @@ -381,6 +453,8 @@ empathy_account_manager_init (EmpathyAccountManager *manager) empathy_account_equal, g_object_unref, (GDestroyNotify) account_data_free); + priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, + g_object_unref, g_object_unref); mc_accounts = mc_accounts_list (); @@ -412,6 +486,7 @@ do_finalize (GObject *obj) EmpathyAccountManagerPriv *priv = GET_PRIV (manager); g_hash_table_unref (priv->accounts); + g_hash_table_unref (priv->connections); G_OBJECT_CLASS (empathy_account_manager_parent_class)->finalize (obj); } @@ -562,6 +637,16 @@ empathy_account_manager_class_init (EmpathyAccountManagerClass *klass) 3, MC_TYPE_ACCOUNT, G_TYPE_INT, /* actual presence */ G_TYPE_INT); /* previous presence */ + + signals[NEW_CONNECTION] = + g_signal_new ("new-connection", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, TP_TYPE_CONNECTION); g_type_class_add_private (oclass, sizeof (EmpathyAccountManagerPriv)); } @@ -634,3 +719,91 @@ empathy_account_manager_get_count (EmpathyAccountManager *manager) return g_hash_table_size (priv->accounts); } + +McAccount * +empathy_account_manager_get_account (EmpathyAccountManager *manager, + TpConnection *connection) +{ + EmpathyAccountManagerPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0); + + priv = GET_PRIV (manager); + + return g_hash_table_lookup (priv->connections, connection); +} + +GList * +empathy_account_manager_dup_accounts (EmpathyAccountManager *manager) +{ + EmpathyAccountManagerPriv *priv; + GList *ret; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL); + + priv = GET_PRIV (manager); + + ret = g_hash_table_get_keys (priv->accounts); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + + return ret; +} + +/** + * empathy_account_manager_get_connection: + * @manager: a #EmpathyAccountManager + * @account: a #McAccount + * + * Get the connection of the accounts, or NULL if account is offline or the + * connection is not yet ready. This function does not return a new ref. + * + * Returns: the connection of the accounts. + **/ +TpConnection * +empathy_account_manager_get_connection (EmpathyAccountManager *manager, + McAccount *account) +{ + EmpathyAccountManagerPriv *priv; + AccountData *data; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + + priv = GET_PRIV (manager); + + data = g_hash_table_lookup (priv->accounts, account); + if (data && data->connection && tp_connection_is_ready (data->connection)) + return data->connection; + + return NULL; +} + +/** + * empathy_account_manager_dup_connections: + * @manager: a #EmpathyAccountManager + * + * Get a #GList of all ready #TpConnection. The list must be freed with + * g_list_free, and its elements must be unreffed. + * + * Returns: the list of connections + **/ +GList * +empathy_account_manager_dup_connections (EmpathyAccountManager *manager) +{ + EmpathyAccountManagerPriv *priv; + GHashTableIter iter; + gpointer connection; + GList *ret = NULL; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL); + + priv = GET_PRIV (manager); + + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, &connection, NULL)) + if (connection != NULL && tp_connection_is_ready (connection)) + ret = g_list_prepend (ret, g_object_ref (connection)); + + return ret; +} + diff --git a/libempathy/empathy-account-manager.h b/libempathy/empathy-account-manager.h index b9aecb09f..ac90a34f7 100644 --- a/libempathy/empathy-account-manager.h +++ b/libempathy/empathy-account-manager.h @@ -61,6 +61,16 @@ gboolean empathy_account_manager_is_account_just_connected McAccount *account); int empathy_account_manager_get_count (EmpathyAccountManager *manager); +McAccount * empathy_account_manager_get_account + (EmpathyAccountManager *manager, + TpConnection *connection); +GList * empathy_account_manager_dup_accounts + (EmpathyAccountManager *manager); +TpConnection * empathy_account_manager_get_connection + (EmpathyAccountManager *manager, + McAccount *account); +GList * empathy_account_manager_dup_connections + (EmpathyAccountManager *manager); G_END_DECLS diff --git a/libempathy/empathy-call-handler.c b/libempathy/empathy-call-handler.c index 39d5899bd..820de6de5 100644 --- a/libempathy/empathy-call-handler.c +++ b/libempathy/empathy-call-handler.c @@ -402,30 +402,38 @@ empathy_call_handler_request_cb (EmpathyDispatchOperation *operation, empathy_dispatch_operation_claim (operation); } -static void -empathy_call_handler_contact_ready_cb (EmpathyContact *contact, - const GError *error, gpointer user_data, GObject *object) +void +empathy_call_handler_start_call (EmpathyCallHandler *handler) { - EmpathyCallHandler *self = EMPATHY_CALL_HANDLER (object); - EmpathyCallHandlerPriv *priv = GET_PRIV (self); + + EmpathyCallHandlerPriv *priv = GET_PRIV (handler); EmpathyDispatcher *dispatcher; - McAccount *account; + TpConnection *connection; GStrv allowed; GValue *value; - GHashTable *request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify) tp_g_value_slice_free); + GHashTable *request; + + if (priv->call != NULL) + { + empathy_call_handler_start_tpfs (handler); + empathy_tp_call_accept_incoming_call (priv->call); + return; + } g_assert (priv->contact != NULL); dispatcher = empathy_dispatcher_dup_singleton (); - account = empathy_contact_get_account (priv->contact); - allowed = empathy_dispatcher_find_channel_class (dispatcher, account, + connection = empathy_contact_get_connection (priv->contact); + allowed = empathy_dispatcher_find_channel_class (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_HANDLE_TYPE_CONTACT); if (!tp_strv_contains ((const gchar * const *) allowed, TP_IFACE_CHANNEL ".TargetHandle")) return; + request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify) tp_g_value_slice_free); + /* org.freedesktop.Telepathy.Channel.ChannelType */ value = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); @@ -441,27 +449,9 @@ empathy_call_handler_contact_ready_cb (EmpathyContact *contact, g_value_set_uint (value, empathy_contact_get_handle (priv->contact)); g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value); - empathy_dispatcher_create_channel (dispatcher, account, - request, empathy_call_handler_request_cb, self); + empathy_dispatcher_create_channel (dispatcher, connection, + request, empathy_call_handler_request_cb, handler); g_object_unref (dispatcher); } -void -empathy_call_handler_start_call (EmpathyCallHandler *handler) -{ - - EmpathyCallHandlerPriv *priv = GET_PRIV (handler); - - if (priv->call == NULL) - { - empathy_contact_call_when_ready (priv->contact, - EMPATHY_CONTACT_READY_HANDLE, - empathy_call_handler_contact_ready_cb, NULL, NULL, G_OBJECT (handler)); - } - else - { - empathy_call_handler_start_tpfs (handler); - empathy_tp_call_accept_incoming_call (priv->call); - } -} diff --git a/libempathy/empathy-chatroom-manager.c b/libempathy/empathy-chatroom-manager.c index 6765d9e48..e57dae7d3 100644 --- a/libempathy/empathy-chatroom-manager.c +++ b/libempathy/empathy-chatroom-manager.c @@ -1,7 +1,6 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2004-2007 Imendio AB - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +32,7 @@ #include "empathy-tp-chat.h" #include "empathy-chatroom-manager.h" +#include "empathy-account-manager.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_OTHER @@ -45,26 +45,19 @@ static EmpathyChatroomManager *chatroom_manager_singleton = NULL; #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChatroomManager) -typedef struct { - GList *chatrooms; +typedef struct +{ + GList *chatrooms; gchar *file; + EmpathyAccountManager *account_manager; /* source id of the autosave timer */ gint save_timer_id; } EmpathyChatroomManagerPriv; -static void chatroom_manager_finalize (GObject *object); -static gboolean chatroom_manager_get_all (EmpathyChatroomManager *manager); -static gboolean chatroom_manager_file_parse (EmpathyChatroomManager *manager, - const gchar *filename); -static void chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, - xmlNodePtr node); -static gboolean chatroom_manager_file_save (EmpathyChatroomManager *manager); -static void reset_save_timeout (EmpathyChatroomManager *self); - enum { - CHATROOM_ADDED, - CHATROOM_REMOVED, - LAST_SIGNAL + CHATROOM_ADDED, + CHATROOM_REMOVED, + LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; @@ -78,6 +71,238 @@ enum G_DEFINE_TYPE (EmpathyChatroomManager, empathy_chatroom_manager, G_TYPE_OBJECT); +/* + * API to save/load and parse the chatrooms file. + */ + +static gboolean +chatroom_manager_file_save (EmpathyChatroomManager *manager) +{ + EmpathyChatroomManagerPriv *priv; + xmlDocPtr doc; + xmlNodePtr root; + GList *l; + + priv = GET_PRIV (manager); + + doc = xmlNewDoc ("1.0"); + root = xmlNewNode (NULL, "chatrooms"); + xmlDocSetRootElement (doc, root); + + for (l = priv->chatrooms; l; l = l->next) { + EmpathyChatroom *chatroom; + xmlNodePtr node; + const gchar *account_id; + + chatroom = l->data; + + if (!empathy_chatroom_is_favorite (chatroom)) { + continue; + } + + account_id = mc_account_get_unique_name (empathy_chatroom_get_account (chatroom)); + + node = xmlNewChild (root, NULL, "chatroom", NULL); + xmlNewTextChild (node, NULL, "name", empathy_chatroom_get_name (chatroom)); + xmlNewTextChild (node, NULL, "room", empathy_chatroom_get_room (chatroom)); + xmlNewTextChild (node, NULL, "account", account_id); + xmlNewTextChild (node, NULL, "auto_connect", + empathy_chatroom_get_auto_connect (chatroom) ? "yes" : "no"); + } + + /* Make sure the XML is indented properly */ + xmlIndentTreeOutput = 1; + + DEBUG ("Saving file:'%s'", priv->file); + xmlSaveFormatFileEnc (priv->file, doc, "utf-8", 1); + xmlFreeDoc (doc); + + xmlCleanupParser (); + xmlMemoryDump (); + + return TRUE; +} + +static gboolean +save_timeout (EmpathyChatroomManager *self) +{ + EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + + priv->save_timer_id = 0; + chatroom_manager_file_save (self); + + return FALSE; +} + +static void +reset_save_timeout (EmpathyChatroomManager *self) +{ + EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + + if (priv->save_timer_id > 0) + { + g_source_remove (priv->save_timer_id); + } + + priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER, + (GSourceFunc) save_timeout, self); +} + +static void +chatroom_changed_cb (EmpathyChatroom *chatroom, + GParamSpec *spec, + EmpathyChatroomManager *self) +{ + reset_save_timeout (self); +} + +static void +add_chatroom (EmpathyChatroomManager *self, + EmpathyChatroom *chatroom) +{ + EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + + priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom)); + + g_signal_connect (chatroom, "notify", + G_CALLBACK (chatroom_changed_cb), self); +} + +static void +chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, + xmlNodePtr node) +{ + EmpathyChatroomManagerPriv *priv; + EmpathyChatroom *chatroom; + McAccount *account; + xmlNodePtr child; + gchar *str; + gchar *name; + gchar *room; + gchar *account_id; + gboolean auto_connect; + + priv = GET_PRIV (manager); + + /* default values. */ + name = NULL; + room = NULL; + auto_connect = TRUE; + account_id = NULL; + + for (child = node->children; child; child = child->next) { + gchar *tag; + + if (xmlNodeIsText (child)) { + continue; + } + + tag = (gchar *) child->name; + str = (gchar *) xmlNodeGetContent (child); + + if (strcmp (tag, "name") == 0) { + name = g_strdup (str); + } + else if (strcmp (tag, "room") == 0) { + room = g_strdup (str); + } + else if (strcmp (tag, "auto_connect") == 0) { + if (strcmp (str, "yes") == 0) { + auto_connect = TRUE; + } else { + auto_connect = FALSE; + } + } + else if (strcmp (tag, "account") == 0) { + account_id = g_strdup (str); + } + + xmlFree (str); + } + + account = mc_account_lookup (account_id); + if (!account) { + g_free (name); + g_free (room); + g_free (account_id); + return; + } + + chatroom = empathy_chatroom_new_full (account, room, name, auto_connect); + empathy_chatroom_set_favorite (chatroom, TRUE); + add_chatroom (manager, chatroom); + g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); + + g_object_unref (account); + g_free (name); + g_free (room); + g_free (account_id); +} + +static gboolean +chatroom_manager_file_parse (EmpathyChatroomManager *manager, + const gchar *filename) +{ + EmpathyChatroomManagerPriv *priv; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + xmlNodePtr chatrooms; + xmlNodePtr node; + + priv = GET_PRIV (manager); + + DEBUG ("Attempting to parse file:'%s'...", filename); + + ctxt = xmlNewParserCtxt (); + + /* Parse and validate the file. */ + doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); + if (!doc) { + g_warning ("Failed to parse file:'%s'", filename); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + if (!empathy_xml_validate (doc, CHATROOMS_DTD_FILENAME)) { + g_warning ("Failed to validate file:'%s'", filename); + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + /* The root node, chatrooms. */ + chatrooms = xmlDocGetRootElement (doc); + + for (node = chatrooms->children; node; node = node->next) { + if (strcmp ((gchar *) node->name, "chatroom") == 0) { + chatroom_manager_parse_chatroom (manager, node); + } + } + + DEBUG ("Parsed %d chatrooms", g_list_length (priv->chatrooms)); + + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + + return TRUE; +} + +static gboolean +chatroom_manager_get_all (EmpathyChatroomManager *manager) +{ + EmpathyChatroomManagerPriv *priv; + + priv = GET_PRIV (manager); + + /* read file in */ + if (g_file_test (priv->file, G_FILE_TEST_EXISTS) && + !chatroom_manager_file_parse (manager, priv->file)) { + return FALSE; + } + + return TRUE; +} + static void empathy_chatroom_manager_get_property (GObject *object, guint property_id, @@ -119,6 +344,41 @@ empathy_chatroom_manager_set_property (GObject *object, } } +static void +chatroom_manager_finalize (GObject *object) +{ + EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object); + EmpathyChatroomManagerPriv *priv; + GList *l; + + priv = GET_PRIV (object); + + g_object_unref (priv->account_manager); + + if (priv->save_timer_id > 0) + { + /* have to save before destroy the object */ + g_source_remove (priv->save_timer_id); + priv->save_timer_id = 0; + chatroom_manager_file_save (self); + } + + for (l = priv->chatrooms; l != NULL; l = g_list_next (l)) + { + EmpathyChatroom *chatroom = l->data; + + g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, + self); + + g_object_unref (chatroom); + } + + g_list_free (priv->chatrooms); + g_free (priv->file); + + (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->finalize) (object); +} + static GObject * empathy_chatroom_manager_constructor (GType type, guint n_props, @@ -141,6 +401,8 @@ empathy_chatroom_manager_constructor (GType type, chatroom_manager_singleton = self; g_object_add_weak_pointer (obj, (gpointer) &chatroom_manager_singleton); + priv->account_manager = empathy_account_manager_dup_singleton (); + if (priv->file == NULL) { /* Set the default file path */ @@ -161,7 +423,7 @@ empathy_chatroom_manager_constructor (GType type, static void empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *param_spec; object_class->constructor = empathy_chatroom_manager_constructor; @@ -181,201 +443,108 @@ empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass) G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_FILE, param_spec); - signals[CHATROOM_ADDED] = - g_signal_new ("chatroom-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, EMPATHY_TYPE_CHATROOM); - signals[CHATROOM_REMOVED] = - g_signal_new ("chatroom-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, EMPATHY_TYPE_CHATROOM); - - g_type_class_add_private (object_class, - sizeof (EmpathyChatroomManagerPriv)); + signals[CHATROOM_ADDED] = g_signal_new ("chatroom-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, EMPATHY_TYPE_CHATROOM); + + signals[CHATROOM_REMOVED] = g_signal_new ("chatroom-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, EMPATHY_TYPE_CHATROOM); + + g_type_class_add_private (object_class, sizeof (EmpathyChatroomManagerPriv)); } static void empathy_chatroom_manager_init (EmpathyChatroomManager *manager) { - EmpathyChatroomManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, - EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerPriv); - - manager->priv = priv; -} - -static void -chatroom_changed_cb (EmpathyChatroom *chatroom, - GParamSpec *spec, - EmpathyChatroomManager *self) -{ - reset_save_timeout (self); -} - -static void -chatroom_manager_finalize (GObject *object) -{ - EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object); - EmpathyChatroomManagerPriv *priv; - GList *l; - - priv = GET_PRIV (object); - - if (priv->save_timer_id > 0) - { - /* have to save before destroy the object */ - g_source_remove (priv->save_timer_id); - priv->save_timer_id = 0; - chatroom_manager_file_save (self); - } - - for (l = priv->chatrooms; l != NULL; l = g_list_next (l)) - { - EmpathyChatroom *chatroom = l->data; + EmpathyChatroomManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, + EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerPriv); - g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, - self); - - g_object_unref (chatroom); - } - - g_list_free (priv->chatrooms); - g_free (priv->file); - - (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->finalize) (object); + manager->priv = priv; } EmpathyChatroomManager * empathy_chatroom_manager_dup_singleton (const gchar *file) { - return EMPATHY_CHATROOM_MANAGER (g_object_new (EMPATHY_TYPE_CHATROOM_MANAGER, - "file", file, NULL)); -} - -static gboolean -save_timeout (EmpathyChatroomManager *self) -{ - EmpathyChatroomManagerPriv *priv = GET_PRIV (self); - - priv->save_timer_id = 0; - chatroom_manager_file_save (self); - - return FALSE; -} - -static void -reset_save_timeout (EmpathyChatroomManager *self) -{ - EmpathyChatroomManagerPriv *priv = GET_PRIV (self); - - if (priv->save_timer_id > 0) - { - g_source_remove (priv->save_timer_id); - } - - priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER, - (GSourceFunc) save_timeout, self); -} - -static void -add_chatroom (EmpathyChatroomManager *self, - EmpathyChatroom *chatroom) -{ - EmpathyChatroomManagerPriv *priv = GET_PRIV (self); - - priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom)); - - g_signal_connect (chatroom, "notify", - G_CALLBACK (chatroom_changed_cb), self); + return EMPATHY_CHATROOM_MANAGER (g_object_new (EMPATHY_TYPE_CHATROOM_MANAGER, + "file", file, NULL)); } gboolean empathy_chatroom_manager_add (EmpathyChatroomManager *manager, EmpathyChatroom *chatroom) { - EmpathyChatroomManagerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), FALSE); - g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); - - priv = GET_PRIV (manager); + EmpathyChatroomManagerPriv *priv; - /* don't add more than once */ - if (!empathy_chatroom_manager_find (manager, - empathy_chatroom_get_account (chatroom), - empathy_chatroom_get_room (chatroom))) { - gboolean favorite; + g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), FALSE); + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); - g_object_get (chatroom, "favorite", &favorite, NULL); + priv = GET_PRIV (manager); - add_chatroom (manager, chatroom); + /* don't add more than once */ + if (!empathy_chatroom_manager_find (manager, + empathy_chatroom_get_account (chatroom), + empathy_chatroom_get_room (chatroom))) + { + add_chatroom (manager, chatroom); - if (favorite) - { + if (empathy_chatroom_is_favorite (chatroom)) reset_save_timeout (manager); - } - g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); - - return TRUE; - } + g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); + return TRUE; + } - return FALSE; + return FALSE; } void empathy_chatroom_manager_remove (EmpathyChatroomManager *manager, - EmpathyChatroom *chatroom) + EmpathyChatroom *chatroom) { - EmpathyChatroomManagerPriv *priv; - GList *l; - - g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager)); - g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); - - priv = GET_PRIV (manager); + EmpathyChatroomManagerPriv *priv; + GList *l; - for (l = priv->chatrooms; l; l = l->next) { - EmpathyChatroom *this_chatroom; + g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager)); + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); - this_chatroom = l->data; + priv = GET_PRIV (manager); - if (this_chatroom == chatroom || - empathy_chatroom_equal (chatroom, this_chatroom)) { - gboolean favorite; - priv->chatrooms = g_list_delete_link (priv->chatrooms, l); + for (l = priv->chatrooms; l; l = l->next) + { + EmpathyChatroom *this_chatroom; - g_object_get (chatroom, "favorite", &favorite, NULL); + this_chatroom = l->data; - if (favorite) + if (this_chatroom == chatroom || + empathy_chatroom_equal (chatroom, this_chatroom)) { - reset_save_timeout (manager); - } - - g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, this_chatroom); + priv->chatrooms = g_list_delete_link (priv->chatrooms, l); + if (empathy_chatroom_is_favorite (chatroom)) + reset_save_timeout (manager); - g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, - manager); + g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, this_chatroom); + g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, + manager); - g_object_unref (this_chatroom); - break; - } - } + g_object_unref (this_chatroom); + break; + } + } } EmpathyChatroom * empathy_chatroom_manager_find (EmpathyChatroomManager *manager, - McAccount *account, - const gchar *room) + McAccount *account, + const gchar *room) { EmpathyChatroomManagerPriv *priv; GList *l; @@ -457,7 +626,7 @@ empathy_chatroom_manager_get_count (EmpathyChatroomManager *manager, chatroom = l->data; if (empathy_account_equal (account, - empathy_chatroom_get_account (chatroom))) { + empathy_chatroom_get_account (chatroom))) { count++; } } @@ -465,225 +634,36 @@ empathy_chatroom_manager_get_count (EmpathyChatroomManager *manager, return count; } -/* - * API to save/load and parse the chatrooms file. - */ - -static gboolean -chatroom_manager_get_all (EmpathyChatroomManager *manager) -{ - EmpathyChatroomManagerPriv *priv; - - priv = GET_PRIV (manager); - - /* read file in */ - if (g_file_test (priv->file, G_FILE_TEST_EXISTS) && - !chatroom_manager_file_parse (manager, priv->file)) - return FALSE; - - return TRUE; -} - -static gboolean -chatroom_manager_file_parse (EmpathyChatroomManager *manager, - const gchar *filename) -{ - EmpathyChatroomManagerPriv *priv; - xmlParserCtxtPtr ctxt; - xmlDocPtr doc; - xmlNodePtr chatrooms; - xmlNodePtr node; - - priv = GET_PRIV (manager); - - DEBUG ("Attempting to parse file:'%s'...", filename); - - ctxt = xmlNewParserCtxt (); - - /* Parse and validate the file. */ - doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); - if (!doc) { - g_warning ("Failed to parse file:'%s'", filename); - xmlFreeParserCtxt (ctxt); - return FALSE; - } - - if (!empathy_xml_validate (doc, CHATROOMS_DTD_FILENAME)) { - g_warning ("Failed to validate file:'%s'", filename); - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - return FALSE; - } - - /* The root node, chatrooms. */ - chatrooms = xmlDocGetRootElement (doc); - - for (node = chatrooms->children; node; node = node->next) { - if (strcmp ((gchar *) node->name, "chatroom") == 0) { - chatroom_manager_parse_chatroom (manager, node); - } - } - - DEBUG ("Parsed %d chatrooms", g_list_length (priv->chatrooms)); - - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - - return TRUE; -} - -static void -chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, - xmlNodePtr node) -{ - EmpathyChatroomManagerPriv *priv; - EmpathyChatroom *chatroom; - McAccount *account; - xmlNodePtr child; - gchar *str; - gchar *name; - gchar *room; - gchar *account_id; - gboolean auto_connect; - - priv = GET_PRIV (manager); - - /* default values. */ - name = NULL; - room = NULL; - auto_connect = TRUE; - account_id = NULL; - - for (child = node->children; child; child = child->next) { - gchar *tag; - - if (xmlNodeIsText (child)) { - continue; - } - - tag = (gchar *) child->name; - str = (gchar *) xmlNodeGetContent (child); - - if (strcmp (tag, "name") == 0) { - name = g_strdup (str); - } - else if (strcmp (tag, "room") == 0) { - room = g_strdup (str); - } - else if (strcmp (tag, "auto_connect") == 0) { - if (strcmp (str, "yes") == 0) { - auto_connect = TRUE; - } else { - auto_connect = FALSE; - } - } - else if (strcmp (tag, "account") == 0) { - account_id = g_strdup (str); - } - - xmlFree (str); - } - - account = mc_account_lookup (account_id); - if (!account) { - g_free (name); - g_free (room); - g_free (account_id); - return; - } - - chatroom = empathy_chatroom_new_full (account, room, name, auto_connect); - g_object_set (chatroom, "favorite", TRUE, NULL); - add_chatroom (manager, chatroom); - g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); - - g_object_unref (account); - g_free (name); - g_free (room); - g_free (account_id); -} - -static gboolean -chatroom_manager_file_save (EmpathyChatroomManager *manager) -{ - EmpathyChatroomManagerPriv *priv; - xmlDocPtr doc; - xmlNodePtr root; - GList *l; - - priv = GET_PRIV (manager); - - doc = xmlNewDoc ("1.0"); - root = xmlNewNode (NULL, "chatrooms"); - xmlDocSetRootElement (doc, root); - - for (l = priv->chatrooms; l; l = l->next) { - EmpathyChatroom *chatroom; - xmlNodePtr node; - const gchar *account_id; - gboolean favorite; - - chatroom = l->data; - - g_object_get (chatroom, "favorite", &favorite, NULL); - if (!favorite) - continue; - - account_id = mc_account_get_unique_name (empathy_chatroom_get_account (chatroom)); - - node = xmlNewChild (root, NULL, "chatroom", NULL); - xmlNewTextChild (node, NULL, "name", empathy_chatroom_get_name (chatroom)); - xmlNewTextChild (node, NULL, "room", empathy_chatroom_get_room (chatroom)); - xmlNewTextChild (node, NULL, "account", account_id); - xmlNewTextChild (node, NULL, "auto_connect", empathy_chatroom_get_auto_connect (chatroom) ? "yes" : "no"); - } - - /* Make sure the XML is indented properly */ - xmlIndentTreeOutput = 1; - - DEBUG ("Saving file:'%s'", priv->file); - xmlSaveFormatFileEnc (priv->file, doc, "utf-8", 1); - xmlFreeDoc (doc); - - xmlCleanupParser (); - xmlMemoryDump (); - - return TRUE; -} - static void chatroom_manager_chat_destroyed_cb (EmpathyTpChat *chat, - gpointer user_data) + gpointer manager) { - EmpathyChatroomManager *manager = EMPATHY_CHATROOM_MANAGER (user_data); - McAccount *account = empathy_tp_chat_get_account (chat); - EmpathyChatroom *chatroom; - const gchar *roomname; - gboolean favorite; - - roomname = empathy_tp_chat_get_id (chat); - chatroom = empathy_chatroom_manager_find (manager, account, roomname); + EmpathyChatroomManagerPriv *priv = GET_PRIV (manager); + GList *l; - if (chatroom == NULL) - return; + for (l = priv->chatrooms; l; l = l->next) + { + EmpathyChatroom *chatroom = l->data; - g_object_set (chatroom, "tp-chat", NULL, NULL); - g_object_get (chatroom, "favorite", &favorite, NULL); + if (empathy_chatroom_get_tp_chat (chatroom) != chat) + continue; - if (!favorite) - { - /* Remove the chatroom from the list, unless it's in the list of - * favourites.. - * FIXME this policy should probably not be in libempathy */ - empathy_chatroom_manager_remove (manager, chatroom); + empathy_chatroom_set_tp_chat (chatroom, NULL); + if (!empathy_chatroom_is_favorite (chatroom)) + { + /* Remove the chatroom from the list, unless it's in the list of + * favourites.. + * FIXME this policy should probably not be in libempathy */ + empathy_chatroom_manager_remove (manager, chatroom); + } } } static void chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, - EmpathyDispatchOperation *operation, gpointer user_data) + EmpathyDispatchOperation *operation, gpointer manager) { - EmpathyChatroomManager *manager = EMPATHY_CHATROOM_MANAGER (user_data); + EmpathyChatroomManagerPriv *priv = GET_PRIV (manager); EmpathyChatroom *chatroom; TpChannel *channel; EmpathyTpChat *chat; @@ -691,6 +671,7 @@ chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, GQuark channel_type; TpHandleType handle_type; McAccount *account; + TpConnection *connection; channel_type = empathy_dispatch_operation_get_channel_type_id (operation); @@ -706,7 +687,9 @@ chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, chat = EMPATHY_TP_CHAT ( empathy_dispatch_operation_get_channel_wrapper (operation)); - account = empathy_tp_chat_get_account (chat); + connection = empathy_tp_chat_get_connection (chat); + account = empathy_account_manager_get_account (priv->account_manager, + connection); roomname = empathy_tp_chat_get_id (chat); @@ -716,13 +699,13 @@ chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, { chatroom = empathy_chatroom_new_full (account, roomname, roomname, FALSE); - g_object_set (G_OBJECT (chatroom), "tp-chat", chat, NULL); + empathy_chatroom_set_tp_chat (chatroom, chat); empathy_chatroom_manager_add (manager, chatroom); g_object_unref (chatroom); } else { - g_object_set (G_OBJECT (chatroom), "tp-chat", chat, NULL); + empathy_chatroom_set_tp_chat (chatroom, chat); } /* A TpChat is always destroyed as it only gets unreffed after the channel diff --git a/libempathy/empathy-chatroom.c b/libempathy/empathy-chatroom.c index 8ffd8a51e..6575bb998 100644 --- a/libempathy/empathy-chatroom.c +++ b/libempathy/empathy-chatroom.c @@ -111,17 +111,14 @@ empathy_chatroom_class_init (EmpathyChatroomClass *klass) FALSE, G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_FAVORITE, - g_param_spec_boolean ("favorite", - "Favorite", - "TRUE if the chatroom is in user's favorite list", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + g_object_class_install_property (object_class, + PROP_FAVORITE, + g_param_spec_boolean ("favorite", + "Favorite", + "TRUE if the chatroom is in user's favorite list", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_TP_CHAT, @@ -284,30 +281,14 @@ chatroom_set_property (GObject *object, empathy_chatroom_set_auto_connect (EMPATHY_CHATROOM (object), g_value_get_boolean (value)); break; - case PROP_FAVORITE: - priv->favorite = g_value_get_boolean (value); - if (!priv->favorite) - { - empathy_chatroom_set_auto_connect (EMPATHY_CHATROOM (object), - FALSE); - } - break; - case PROP_TP_CHAT: { - GObject *chat = g_value_dup_object (value); - - if (chat == (GObject *) priv->tp_chat) - break; - - g_assert (chat == NULL || priv->tp_chat == NULL); - - if (priv->tp_chat != NULL) { - g_object_unref (priv->tp_chat); - priv->tp_chat = NULL; - } else { - priv->tp_chat = EMPATHY_TP_CHAT (chat); - } + case PROP_FAVORITE: + empathy_chatroom_set_favorite (EMPATHY_CHATROOM (object), + g_value_get_boolean (value)); + break; + case PROP_TP_CHAT: + empathy_chatroom_set_tp_chat (EMPATHY_CHATROOM (object), + g_value_get_object (value)); break; - } case PROP_SUBJECT: empathy_chatroom_set_subject (EMPATHY_CHATROOM (object), g_value_get_string (value)); @@ -476,12 +457,11 @@ empathy_chatroom_set_auto_connect (EmpathyChatroom *chatroom, priv->auto_connect = auto_connect; - if (priv->auto_connect) - { - /* auto_connect implies favorite */ - priv->favorite = TRUE; - g_object_notify (G_OBJECT (chatroom), "favorite"); - } + if (priv->auto_connect) { + /* auto_connect implies favorite */ + priv->favorite = TRUE; + g_object_notify (G_OBJECT (chatroom), "favorite"); + } g_object_notify (G_OBJECT (chatroom), "auto-connect"); } @@ -504,12 +484,13 @@ empathy_chatroom_equal (gconstpointer v1, room_a = empathy_chatroom_get_room (EMPATHY_CHATROOM (v1)); room_b = empathy_chatroom_get_room (EMPATHY_CHATROOM (v2)); - return empathy_account_equal (account_a, account_b) && !tp_strdiff (room_a, - room_b); + return empathy_account_equal (account_a, account_b) && + !tp_strdiff (room_a, room_b); } EmpathyTpChat * -empathy_chatroom_get_tp_chat (EmpathyChatroom *chatroom) { +empathy_chatroom_get_tp_chat (EmpathyChatroom *chatroom) +{ EmpathyChatroomPriv *priv; g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), NULL); @@ -631,3 +612,59 @@ empathy_chatroom_set_invite_only (EmpathyChatroom *chatroom, g_object_notify (G_OBJECT (chatroom), "invite-only"); } +void +empathy_chatroom_set_tp_chat (EmpathyChatroom *chatroom, + EmpathyTpChat *tp_chat) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + g_return_if_fail (tp_chat == NULL || EMPATHY_IS_TP_CHAT (tp_chat)); + + priv = GET_PRIV (chatroom); + + if (priv->tp_chat == tp_chat) { + return; + } + + if (priv->tp_chat != NULL) { + g_object_unref (priv->tp_chat); + } + + priv->tp_chat = tp_chat ? g_object_ref (tp_chat) : NULL; + g_object_notify (G_OBJECT (chatroom), "tp-chat"); +} + +gboolean +empathy_chatroom_is_favorite (EmpathyChatroom *chatroom) +{ + EmpathyChatroomPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); + + priv = GET_PRIV (chatroom); + + return priv->favorite; +} + +void +empathy_chatroom_set_favorite (EmpathyChatroom *chatroom, + gboolean favorite) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + + priv = GET_PRIV (chatroom); + + if (priv->favorite == favorite) { + return; + } + + priv->favorite = favorite; + if (!priv->favorite) { + empathy_chatroom_set_auto_connect (chatroom, FALSE); + } + g_object_notify (G_OBJECT (chatroom), "favorite"); +} + diff --git a/libempathy/empathy-chatroom.h b/libempathy/empathy-chatroom.h index 08e3bc1eb..560517d48 100644 --- a/libempathy/empathy-chatroom.h +++ b/libempathy/empathy-chatroom.h @@ -84,6 +84,11 @@ void empathy_chatroom_set_invite_only (EmpathyChatroom *chatroom, gboolean empathy_chatroom_equal (gconstpointer v1, gconstpointer v2); EmpathyTpChat * empathy_chatroom_get_tp_chat (EmpathyChatroom *chatroom); +void empathy_chatroom_set_tp_chat (EmpathyChatroom *chatroom, + EmpathyTpChat *tp_chat); +gboolean empathy_chatroom_is_favorite (EmpathyChatroom *chatroom); +void empathy_chatroom_set_favorite (EmpathyChatroom *chatroom, + gboolean favorite); G_END_DECLS diff --git a/libempathy/empathy-contact-factory.c b/libempathy/empathy-contact-factory.c deleted file mode 100644 index c35005774..000000000 --- a/libempathy/empathy-contact-factory.c +++ /dev/null @@ -1,187 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Xavier Claessens <xclaesse@gmail.com> - */ - -#include <config.h> - -#include "empathy-contact-factory.h" -#include "empathy-utils.h" - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactFactory) -typedef struct { - GHashTable *accounts; -} EmpathyContactFactoryPriv; - -G_DEFINE_TYPE (EmpathyContactFactory, empathy_contact_factory, G_TYPE_OBJECT); - -static EmpathyContactFactory * factory_singleton = NULL; - -EmpathyTpContactFactory * -empathy_contact_factory_get_tp_factory (EmpathyContactFactory *factory, - McAccount *account) -{ - EmpathyContactFactoryPriv *priv = GET_PRIV (factory); - EmpathyTpContactFactory *tp_factory; - - tp_factory = g_hash_table_lookup (priv->accounts, account); - if (!tp_factory) { - tp_factory = empathy_tp_contact_factory_new (account); - g_hash_table_insert (priv->accounts, account, tp_factory); - } - - return g_object_ref (tp_factory); -} - -EmpathyContact * -empathy_contact_factory_get_user (EmpathyContactFactory *factory, - McAccount *account) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_user (tp_factory); -} - -EmpathyContact * -empathy_contact_factory_get_from_id (EmpathyContactFactory *factory, - McAccount *account, - const gchar *id) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_from_id (tp_factory, id); -} - -EmpathyContact * -empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory, - McAccount *account, - guint handle) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_from_handle (tp_factory, handle); -} - -GList * -empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory, - McAccount *account, - const GArray *handles) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_from_handles (tp_factory, handles); -} - -void -empathy_contact_factory_set_alias (EmpathyContactFactory *factory, - EmpathyContact *contact, - const gchar *alias) -{ - EmpathyTpContactFactory *tp_factory; - McAccount *account; - - account = empathy_contact_get_account (contact); - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_set_alias (tp_factory, contact, alias); -} - -void -empathy_contact_factory_set_avatar (EmpathyContactFactory *factory, - McAccount *account, - const gchar *data, - gsize size, - const gchar *mime_type) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_set_avatar (tp_factory, - data, size, mime_type); -} - -static void -contact_factory_finalize (GObject *object) -{ - EmpathyContactFactoryPriv *priv = GET_PRIV (object); - - g_hash_table_destroy (priv->accounts); - - G_OBJECT_CLASS (empathy_contact_factory_parent_class)->finalize (object); -} - -static GObject * -contact_factory_constructor (GType type, - guint n_props, - GObjectConstructParam *props) -{ - GObject *retval; - - if (factory_singleton) { - retval = g_object_ref (factory_singleton); - } else { - retval = G_OBJECT_CLASS (empathy_contact_factory_parent_class)->constructor - (type, n_props, props); - - factory_singleton = EMPATHY_CONTACT_FACTORY (retval); - g_object_add_weak_pointer (retval, (gpointer) &factory_singleton); - } - - return retval; -} - -static void -empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = contact_factory_finalize; - object_class->constructor = contact_factory_constructor; - - g_type_class_add_private (object_class, sizeof (EmpathyContactFactoryPriv)); -} - -static void -empathy_contact_factory_init (EmpathyContactFactory *factory) -{ - EmpathyContactFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (factory, - EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryPriv); - - factory->priv = priv; - priv->accounts = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, - g_object_unref, - g_object_unref); -} - -EmpathyContactFactory * -empathy_contact_factory_dup_singleton (void) -{ - return g_object_new (EMPATHY_TYPE_CONTACT_FACTORY, NULL); -} - diff --git a/libempathy/empathy-contact-factory.h b/libempathy/empathy-contact-factory.h deleted file mode 100644 index 16df02bcd..000000000 --- a/libempathy/empathy-contact-factory.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Xavier Claessens <xclaesse@gmail.com> - */ - -#ifndef __EMPATHY_CONTACT_FACTORY_H__ -#define __EMPATHY_CONTACT_FACTORY_H__ - -#include <glib.h> - -#include <libmissioncontrol/mc-account.h> - -#include "empathy-contact.h" -#include "empathy-tp-contact-factory.h" - -G_BEGIN_DECLS - -#define EMPATHY_TYPE_CONTACT_FACTORY (empathy_contact_factory_get_type ()) -#define EMPATHY_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactory)) -#define EMPATHY_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryClass)) -#define EMPATHY_IS_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CONTACT_FACTORY)) -#define EMPATHY_IS_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CONTACT_FACTORY)) -#define EMPATHY_CONTACT_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryClass)) - -typedef struct _EmpathyContactFactory EmpathyContactFactory; -typedef struct _EmpathyContactFactoryClass EmpathyContactFactoryClass; - -struct _EmpathyContactFactory { - GObject parent; - gpointer priv; -}; - -struct _EmpathyContactFactoryClass { - GObjectClass parent_class; -}; - -GType empathy_contact_factory_get_type (void) G_GNUC_CONST; -EmpathyContactFactory *empathy_contact_factory_dup_singleton (void); -EmpathyTpContactFactory *empathy_contact_factory_get_tp_factory (EmpathyContactFactory *factory, - McAccount *account); -EmpathyContact * empathy_contact_factory_get_user (EmpathyContactFactory *factory, - McAccount *account); -EmpathyContact * empathy_contact_factory_get_from_id (EmpathyContactFactory *factory, - McAccount *account, - const gchar *id); -EmpathyContact * empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory, - McAccount *account, - guint handle); -GList * empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory, - McAccount *account, - const GArray *handles); -void empathy_contact_factory_set_alias (EmpathyContactFactory *factory, - EmpathyContact *contact, - const gchar *alias); -void empathy_contact_factory_set_avatar (EmpathyContactFactory *factory, - McAccount *account, - const gchar *data, - gsize size, - const gchar *mime_type); - -G_END_DECLS - -#endif /* __EMPATHY_CONTACT_FACTORY_H__ */ diff --git a/libempathy/empathy-contact-manager.c b/libempathy/empathy-contact-manager.c index 409f41c44..66c4514af 100644 --- a/libempathy/empathy-contact-manager.c +++ b/libempathy/empathy-contact-manager.c @@ -86,9 +86,6 @@ contact_manager_groups_changed_cb (EmpathyTpContactList *list, contact, group, is_member); } -static void contact_manager_destroy_cb (EmpathyTpContactList *list, - EmpathyContactManager *manager); - static void contact_manager_disconnect_foreach (gpointer key, gpointer value, @@ -107,75 +104,60 @@ contact_manager_disconnect_foreach (gpointer key, g_signal_handlers_disconnect_by_func (list, contact_manager_groups_changed_cb, manager); - g_signal_handlers_disconnect_by_func (list, - contact_manager_destroy_cb, - manager); } static void -contact_manager_destroy_cb (EmpathyTpContactList *list, - EmpathyContactManager *manager) +contact_manager_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + EmpathyContactManager *manager) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); - McAccount *account; + EmpathyTpContactList *list; - account = empathy_tp_contact_list_get_account (list); + DEBUG ("Removing connection: %s (%s)", + tp_proxy_get_object_path (TP_PROXY (connection)), + message); - DEBUG ("Removing account: %s", mc_account_get_display_name (account)); - - contact_manager_disconnect_foreach (account, list, manager); - g_hash_table_remove (priv->lists, account); + list = g_hash_table_lookup (priv->lists, connection); + if (list) { + empathy_tp_contact_list_remove_all (list); + g_hash_table_remove (priv->lists, connection); + } } static void -contact_manager_add_account (EmpathyContactManager *manager, - McAccount *account) +contact_manager_new_connection_cb (EmpathyAccountManager *account_manager, + TpConnection *connection, + EmpathyContactManager *self) { - EmpathyContactManagerPriv *priv = GET_PRIV (manager); + EmpathyContactManagerPriv *priv = GET_PRIV (self); EmpathyTpContactList *list; - if (g_hash_table_lookup (priv->lists, account)) { + if (g_hash_table_lookup (priv->lists, connection)) { return; } - DEBUG ("Adding new account: %s", mc_account_get_display_name (account)); - - list = empathy_tp_contact_list_new (account); - if (!list) { - return; - } + DEBUG ("Adding new connection: %s", + tp_proxy_get_object_path (TP_PROXY (connection))); - g_hash_table_insert (priv->lists, g_object_ref (account), list); + list = empathy_tp_contact_list_new (connection); + g_hash_table_insert (priv->lists, g_object_ref (connection), list); + g_signal_connect (connection, "invalidated", + G_CALLBACK (contact_manager_invalidated_cb), + self); /* Connect signals */ g_signal_connect (list, "members-changed", G_CALLBACK (contact_manager_members_changed_cb), - manager); + self); g_signal_connect (list, "pendings-changed", G_CALLBACK (contact_manager_pendings_changed_cb), - manager); + self); g_signal_connect (list, "groups-changed", G_CALLBACK (contact_manager_groups_changed_cb), - manager); - g_signal_connect (list, "destroy", - G_CALLBACK (contact_manager_destroy_cb), - manager); -} - -static void -contact_manager_connection_changed_cb (EmpathyAccountManager *account_manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus current, - TpConnectionStatus previous, - EmpathyContactManager *manager) -{ - if (current != TP_CONNECTION_STATUS_CONNECTED) { - /* We only care about newly connected accounts */ - return; - } - - contact_manager_add_account (manager, account); + self); } static void @@ -189,7 +171,7 @@ contact_manager_finalize (GObject *object) g_hash_table_destroy (priv->lists); g_signal_handlers_disconnect_by_func (priv->account_manager, - contact_manager_connection_changed_cb, + contact_manager_new_connection_cb, object); g_object_unref (priv->account_manager); @@ -232,34 +214,30 @@ empathy_contact_manager_class_init (EmpathyContactManagerClass *klass) static void empathy_contact_manager_init (EmpathyContactManager *manager) { - GSList *accounts, *l; - MissionControl *mc; + GList *connections, *l; EmpathyContactManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv); manager->priv = priv; - priv->lists = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, + priv->lists = g_hash_table_new_full (empathy_proxy_hash, + empathy_proxy_equal, (GDestroyNotify) g_object_unref, (GDestroyNotify) g_object_unref); priv->account_manager = empathy_account_manager_dup_singleton (); priv->contact_monitor = NULL; - g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (contact_manager_connection_changed_cb), manager); - - mc = empathy_mission_control_dup_singleton (); + g_signal_connect (priv->account_manager, "new-connection", + G_CALLBACK (contact_manager_new_connection_cb), + manager); /* Get ContactList for existing connections */ - accounts = mission_control_get_online_connections (mc, NULL); - for (l = accounts; l; l = l->next) { - contact_manager_add_account (manager, l->data); + connections = empathy_account_manager_dup_connections (priv->account_manager); + for (l = connections; l; l = l->next) { + contact_manager_new_connection_cb (priv->account_manager, + l->data, manager); g_object_unref (l->data); } - - g_slist_free (accounts); - g_object_unref (mc); + g_list_free (connections); } EmpathyContactManager * @@ -270,14 +248,14 @@ empathy_contact_manager_dup_singleton (void) EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, - McAccount *account) + TpConnection *connection) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL); - return g_hash_table_lookup (priv->lists, account); + return g_hash_table_lookup (priv->lists, connection); } static void @@ -287,12 +265,12 @@ contact_manager_add (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_add (list, contact, message); @@ -301,17 +279,17 @@ contact_manager_add (EmpathyContactList *manager, static void contact_manager_remove (EmpathyContactList *manager, - EmpathyContact *contact, + EmpathyContact *contact, const gchar *message) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_remove (list, contact, message); @@ -319,7 +297,7 @@ contact_manager_remove (EmpathyContactList *manager, } static void -contact_manager_get_members_foreach (McAccount *account, +contact_manager_get_members_foreach (TpConnection *connection, EmpathyTpContactList *list, GList **contacts) { @@ -357,7 +335,7 @@ contact_manager_get_monitor (EmpathyContactList *manager) } static void -contact_manager_get_pendings_foreach (McAccount *account, +contact_manager_get_pendings_foreach (TpConnection *connection, EmpathyTpContactList *list, GList **contacts) { @@ -383,7 +361,7 @@ contact_manager_get_pendings (EmpathyContactList *manager) } static void -contact_manager_get_all_groups_foreach (McAccount *account, +contact_manager_get_all_groups_foreach (TpConnection *connection, EmpathyTpContactList *list, GList **all_groups) { @@ -424,12 +402,12 @@ contact_manager_get_groups (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { return empathy_contact_list_get_groups (list, contact); @@ -445,12 +423,12 @@ contact_manager_add_to_group (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_add_to_group (list, contact, group); @@ -464,12 +442,12 @@ contact_manager_remove_from_group (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_remove_from_group (list, contact, group); @@ -482,7 +460,7 @@ typedef struct { } RenameGroupData; static void -contact_manager_rename_group_foreach (McAccount *account, +contact_manager_rename_group_foreach (TpConnection *connection, EmpathyTpContactList *list, RenameGroupData *data) { @@ -508,7 +486,7 @@ contact_manager_rename_group (EmpathyContactList *manager, &data); } -static void contact_manager_remove_group_foreach (McAccount *account, +static void contact_manager_remove_group_foreach (TpConnection *connection, EmpathyTpContactList *list, const gchar *group) { @@ -547,14 +525,14 @@ contact_manager_iface_init (EmpathyContactListIface *iface) gboolean empathy_contact_manager_can_add (EmpathyContactManager *manager, - McAccount *account) + TpConnection *connection) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyTpContactList *list; g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), FALSE); - list = g_hash_table_lookup (priv->lists, account); + list = g_hash_table_lookup (priv->lists, connection); if (list == NULL) return FALSE; diff --git a/libempathy/empathy-contact-manager.h b/libempathy/empathy-contact-manager.h index 57e8764e4..fbe9e2df0 100644 --- a/libempathy/empathy-contact-manager.h +++ b/libempathy/empathy-contact-manager.h @@ -24,8 +24,6 @@ #include <glib.h> -#include <libmissioncontrol/mc-account.h> - #include "empathy-contact.h" #include "empathy-tp-contact-list.h" #include "empathy-contact-list.h" @@ -54,9 +52,9 @@ struct _EmpathyContactManagerClass { GType empathy_contact_manager_get_type (void) G_GNUC_CONST; EmpathyContactManager *empathy_contact_manager_dup_singleton (void); EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, - McAccount *account); + TpConnection *connection); gboolean empathy_contact_manager_can_add (EmpathyContactManager *manager, - McAccount *account); + TpConnection *connection); G_END_DECLS diff --git a/libempathy/empathy-contact.c b/libempathy/empathy-contact.c index 1cac48513..fe8cf8234 100644 --- a/libempathy/empathy-contact.c +++ b/libempathy/empathy-contact.c @@ -1,27 +1,22 @@ /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ /* - * Copyright (C) 2004 Imendio AB - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * Authors: Mikael Hallendal <micke@imendio.com> - * Martyn Russell <martyn@imendio.com> - * Xavier Claessens <xclaesse@gmail.com> - * Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * Authors: Xavier Claessens <xclaesse@gmail.com> */ #include "config.h" @@ -34,7 +29,7 @@ #include <libmissioncontrol/mc-enum-types.h> #include "empathy-contact.h" -#include "empathy-contact-factory.h" +#include "empathy-account-manager.h" #include "empathy-utils.h" #include "empathy-enum-types.h" #include "empathy-marshal.h" @@ -44,29 +39,19 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContact) typedef struct { - EmpathyContactFactory *factory; + TpContact *tp_contact; + McAccount *account; gchar *id; gchar *name; EmpathyAvatar *avatar; - McAccount *account; McPresence presence; gchar *presence_message; guint handle; EmpathyCapabilities capabilities; gboolean is_user; guint hash; - EmpathyContactReady ready; - GList *ready_callbacks; } EmpathyContactPriv; -typedef struct { - EmpathyContactReady ready; - EmpathyContactReadyCb *callback; - gpointer user_data; - GDestroyNotify destroy; - GObject *weak_object; -} ReadyCbData; - static void contact_finalize (GObject *object); static void contact_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); @@ -78,16 +63,16 @@ G_DEFINE_TYPE (EmpathyContact, empathy_contact, G_TYPE_OBJECT); enum { PROP_0, + PROP_TP_CONTACT, + PROP_ACCOUNT, PROP_ID, PROP_NAME, PROP_AVATAR, - PROP_ACCOUNT, PROP_PRESENCE, PROP_PRESENCE_MESSAGE, PROP_HANDLE, PROP_CAPABILITIES, PROP_IS_USER, - PROP_READY }; enum { @@ -98,18 +83,48 @@ enum { static guint signals[LAST_SIGNAL]; static void +tp_contact_notify_cb (TpContact *tp_contact, + GParamSpec *param, + GObject *contact) +{ + EmpathyContactPriv *priv = GET_PRIV (contact); + + /* Forward property notifications */ + if (!tp_strdiff (param->name, "alias")) + g_object_notify (contact, "name"); + else if (!tp_strdiff (param->name, "presence-type")) { + McPresence presence; + + presence = empathy_contact_get_presence (EMPATHY_CONTACT (contact)); + g_signal_emit (contact, signals[PRESENCE_CHANGED], 0, presence, priv->presence); + priv->presence = presence; + g_object_notify (contact, "presence"); + } + else if (!tp_strdiff (param->name, "presence-message")) + g_object_notify (contact, "presence-message"); + else if (!tp_strdiff (param->name, "identifier")) + g_object_notify (contact, "id"); + else if (!tp_strdiff (param->name, "handle")) + g_object_notify (contact, "handle"); +} + +static void contact_dispose (GObject *object) { EmpathyContactPriv *priv = GET_PRIV (object); + if (priv->tp_contact) + { + g_signal_handlers_disconnect_by_func (priv->tp_contact, + tp_contact_notify_cb, object); + g_object_unref (priv->tp_contact); + } + priv->tp_contact = NULL; + if (priv->account) g_object_unref (priv->account); priv->account = NULL; - if (priv->factory) - g_object_unref (priv->factory); - priv->factory = NULL; - G_OBJECT_CLASS (empathy_contact_parent_class)->dispose (object); } @@ -126,12 +141,28 @@ empathy_contact_class_init (EmpathyContactClass *class) object_class->set_property = contact_set_property; g_object_class_install_property (object_class, + PROP_TP_CONTACT, + g_param_spec_object ("tp-contact", + "TpContact", + "The TpContact associated with the contact", + TP_TYPE_CONTACT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, + PROP_ACCOUNT, + g_param_spec_object ("account", + "The account", + "The account associated with the contact", + MC_TYPE_ACCOUNT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_ID, g_param_spec_string ("id", "Contact id", "String identifying contact", NULL, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_NAME, @@ -139,7 +170,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Contact Name", "The name of the contact", NULL, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_AVATAR, @@ -147,15 +178,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Avatar image", "The avatar image", EMPATHY_TYPE_AVATAR, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "Contact Account", - "The account associated with the contact", - MC_TYPE_ACCOUNT, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_PRESENCE, @@ -165,7 +188,7 @@ empathy_contact_class_init (EmpathyContactClass *class) MC_PRESENCE_UNSET, LAST_MC_PRESENCE, MC_PRESENCE_UNSET, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_PRESENCE_MESSAGE, @@ -173,7 +196,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Contact presence message", "Presence message of contact", NULL, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_HANDLE, @@ -183,7 +206,7 @@ empathy_contact_class_init (EmpathyContactClass *class) 0, G_MAXUINT, 0, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_CAPABILITIES, @@ -192,7 +215,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Capabilities of the contact", EMPATHY_TYPE_CAPABILITIES, EMPATHY_CAPABILITIES_UNKNOWN, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE)); + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_IS_USER, @@ -200,16 +223,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Contact is-user", "Is contact the user", FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_READY, - g_param_spec_flags ("ready", - "Contact ready flags", - "Flags for ready properties", - EMPATHY_TYPE_CONTACT_READY, - EMPATHY_CONTACT_READY_NONE, - G_PARAM_READABLE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); signals[PRESENCE_CHANGED] = g_signal_new ("presence-changed", @@ -232,17 +246,12 @@ empathy_contact_init (EmpathyContact *contact) EMPATHY_TYPE_CONTACT, EmpathyContactPriv); contact->priv = priv; - - /* Keep a ref to the factory to be sure it is not finalized while there is - * still contacts alive. */ - priv->factory = empathy_contact_factory_dup_singleton (); } static void contact_finalize (GObject *object) { EmpathyContactPriv *priv; - GList *l; priv = GET_PRIV (object); @@ -252,18 +261,6 @@ contact_finalize (GObject *object) g_free (priv->id); g_free (priv->presence_message); - for (l = priv->ready_callbacks; l != NULL; l = g_list_next (l)) - { - ReadyCbData *d = (ReadyCbData *)l->data; - - if (d->destroy != NULL) - d->destroy (d->user_data); - g_slice_free (ReadyCbData, d); - } - - g_list_free (priv->ready_callbacks); - priv->ready_callbacks = NULL; - if (priv->avatar) empathy_avatar_unref (priv->avatar); @@ -271,47 +268,61 @@ contact_finalize (GObject *object) } static void +set_tp_contact (EmpathyContact *contact, + TpContact *tp_contact) +{ + EmpathyContactPriv *priv = GET_PRIV (contact); + + if (tp_contact == NULL) + return; + + g_assert (priv->tp_contact == NULL); + priv->tp_contact = g_object_ref (tp_contact); + priv->presence = empathy_contact_get_presence (contact); + + g_signal_connect (priv->tp_contact, "notify", + G_CALLBACK (tp_contact_notify_cb), contact); +} + +static void contact_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { - EmpathyContactPriv *priv; - - priv = GET_PRIV (object); + EmpathyContact *contact = EMPATHY_CONTACT (object); switch (param_id) { + case PROP_TP_CONTACT: + g_value_set_object (value, empathy_contact_get_tp_contact (contact)); + break; + case PROP_ACCOUNT: + g_value_set_object (value, empathy_contact_get_account (contact)); + break; case PROP_ID: - g_value_set_string (value, priv->id); + g_value_set_string (value, empathy_contact_get_id (contact)); break; case PROP_NAME: - g_value_set_string (value, - empathy_contact_get_name (EMPATHY_CONTACT (object))); + g_value_set_string (value, empathy_contact_get_name (contact)); break; case PROP_AVATAR: - g_value_set_boxed (value, priv->avatar); - break; - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + g_value_set_boxed (value, empathy_contact_get_avatar (contact)); break; case PROP_PRESENCE: - g_value_set_uint (value, priv->presence); + g_value_set_uint (value, empathy_contact_get_presence (contact)); break; case PROP_PRESENCE_MESSAGE: - g_value_set_string (value, priv->presence_message); + g_value_set_string (value, empathy_contact_get_presence_message (contact)); break; case PROP_HANDLE: - g_value_set_uint (value, priv->handle); + g_value_set_uint (value, empathy_contact_get_handle (contact)); break; case PROP_CAPABILITIES: - g_value_set_flags (value, priv->capabilities); + g_value_set_flags (value, empathy_contact_get_capabilities (contact)); break; case PROP_IS_USER: - g_value_set_boolean (value, priv->is_user); - break; - case PROP_READY: - g_value_set_flags (value, priv->ready); + g_value_set_boolean (value, empathy_contact_is_user (contact)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -325,47 +336,41 @@ contact_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - EmpathyContactPriv *priv; - - priv = GET_PRIV (object); + EmpathyContact *contact = EMPATHY_CONTACT (object); + EmpathyContactPriv *priv = GET_PRIV (object); switch (param_id) { + case PROP_TP_CONTACT: + set_tp_contact (contact, g_value_get_object (value)); + break; + case PROP_ACCOUNT: + g_assert (priv->account == NULL); + priv->account = g_value_dup_object (value); + break; case PROP_ID: - empathy_contact_set_id (EMPATHY_CONTACT (object), - g_value_get_string (value)); + empathy_contact_set_id (contact, g_value_get_string (value)); break; case PROP_NAME: - empathy_contact_set_name (EMPATHY_CONTACT (object), - g_value_get_string (value)); + empathy_contact_set_name (contact, g_value_get_string (value)); break; case PROP_AVATAR: - empathy_contact_set_avatar (EMPATHY_CONTACT (object), - g_value_get_boxed (value)); - break; - case PROP_ACCOUNT: - empathy_contact_set_account (EMPATHY_CONTACT (object), - MC_ACCOUNT (g_value_get_object (value))); + empathy_contact_set_avatar (contact, g_value_get_boxed (value)); break; case PROP_PRESENCE: - empathy_contact_set_presence (EMPATHY_CONTACT (object), - g_value_get_uint (value)); + empathy_contact_set_presence (contact, g_value_get_uint (value)); break; case PROP_PRESENCE_MESSAGE: - empathy_contact_set_presence_message (EMPATHY_CONTACT (object), - g_value_get_string (value)); + empathy_contact_set_presence_message (contact, g_value_get_string (value)); break; case PROP_HANDLE: - empathy_contact_set_handle (EMPATHY_CONTACT (object), - g_value_get_uint (value)); + empathy_contact_set_handle (contact, g_value_get_uint (value)); break; case PROP_CAPABILITIES: - empathy_contact_set_capabilities (EMPATHY_CONTACT (object), - g_value_get_flags (value)); + empathy_contact_set_capabilities (contact, g_value_get_flags (value)); break; case PROP_IS_USER: - empathy_contact_set_is_user (EMPATHY_CONTACT (object), - g_value_get_boolean (value)); + empathy_contact_set_is_user (contact, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -373,120 +378,43 @@ contact_set_property (GObject *object, }; } -static gboolean -contact_is_ready (EmpathyContact *contact, EmpathyContactReady ready) -{ - EmpathyContactPriv *priv = GET_PRIV (contact); - - /* When the name is NULL, empathy_contact_get_name() fallback to the id. - * When the caller want to wait the name to be ready, it also want to wait - * the id to be ready in case of fallback. */ - if ((ready & EMPATHY_CONTACT_READY_NAME) && EMP_STR_EMPTY (priv->name)) - ready |= EMPATHY_CONTACT_READY_ID; - - return (priv->ready & ready) == ready; -} - -static void -contact_weak_object_notify (gpointer data, GObject *old_object) -{ - EmpathyContact *contact = EMPATHY_CONTACT (data); - EmpathyContactPriv *priv = GET_PRIV (contact); - - GList *l, *ln; - - for (l = priv->ready_callbacks ; l != NULL ; l = ln ) - { - ReadyCbData *d = (ReadyCbData *)l->data; - ln = g_list_next (l); - - if (d->weak_object == old_object) - { - if (d->destroy != NULL) - d->destroy (d->user_data); - - priv->ready_callbacks = g_list_delete_link (priv->ready_callbacks, - l); - - g_slice_free (ReadyCbData, d); - } - } -} - -static void -contact_call_ready_callback (EmpathyContact *contact, const GError *error, - ReadyCbData *data) -{ - data->callback (contact, error, data->user_data, data->weak_object); - if (data->destroy != NULL) - data->destroy (data->user_data); - - if (data->weak_object) - g_object_weak_unref (data->weak_object, - contact_weak_object_notify, contact); -} - - -static void -contact_set_ready_flag (EmpathyContact *contact, - EmpathyContactReady flag) -{ - EmpathyContactPriv *priv = GET_PRIV (contact); - - if (!(priv->ready & flag)) - { - GList *l, *ln; - - priv->ready |= flag; - g_object_notify (G_OBJECT (contact), "ready"); - - for (l = priv->ready_callbacks ; l != NULL ; l = ln ) - { - ReadyCbData *d = (ReadyCbData *)l->data; - ln = g_list_next (l); - - if (contact_is_ready (contact, d->ready)) - { - contact_call_ready_callback (contact, NULL, d); - priv->ready_callbacks = g_list_delete_link - (priv->ready_callbacks, l); - g_slice_free (ReadyCbData, d); - } - } - } -} - -static void -contact_remove_ready_flag (EmpathyContact *contact, - EmpathyContactReady flag) +EmpathyContact * +empathy_contact_new (TpContact *tp_contact) { - EmpathyContactPriv *priv = GET_PRIV (contact); + g_return_val_if_fail (TP_IS_CONTACT (tp_contact), NULL); - if (priv->ready & flag) - { - priv->ready ^= flag; - g_object_notify (G_OBJECT (contact), "ready"); - } + return g_object_new (EMPATHY_TYPE_CONTACT, + "tp-contact", tp_contact, + NULL); } EmpathyContact * -empathy_contact_new (McAccount *account) +empathy_contact_new_for_log (McAccount *account, + const gchar *id, + const gchar *name, + gboolean is_user) { + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (id != NULL, NULL); + return g_object_new (EMPATHY_TYPE_CONTACT, "account", account, + "id", id, + "name", name, + "is-user", is_user, NULL); } -EmpathyContact * -empathy_contact_new_full (McAccount *account, - const gchar *id, - const gchar *name) +TpContact * +empathy_contact_get_tp_contact (EmpathyContact *contact) { - return g_object_new (EMPATHY_TYPE_CONTACT, - "account", account, - "name", name, - "id", id, - NULL); + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->tp_contact; } const gchar * @@ -498,6 +426,9 @@ empathy_contact_get_id (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_identifier (priv->tp_contact); + return priv->id; } @@ -524,7 +455,6 @@ empathy_contact_set_id (EmpathyContact *contact, if (EMP_STR_EMPTY (priv->name)) g_object_notify (G_OBJECT (contact), "name"); } - contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_ID); g_object_unref (contact); } @@ -538,6 +468,9 @@ empathy_contact_get_name (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_alias (priv->tp_contact); + if (EMP_STR_EMPTY (priv->name)) return empathy_contact_get_id (contact); @@ -561,7 +494,6 @@ empathy_contact_set_name (EmpathyContact *contact, priv->name = g_strdup (name); g_object_notify (G_OBJECT (contact), "name"); } - contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_NAME); g_object_unref (contact); } @@ -611,28 +543,61 @@ empathy_contact_get_account (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->account == NULL && priv->tp_contact != NULL) + { + EmpathyAccountManager *manager; + TpConnection *connection; + + /* FIXME: This assume the account manager already exists */ + manager = empathy_account_manager_dup_singleton (); + connection = tp_contact_get_connection (priv->tp_contact); + priv->account = empathy_account_manager_get_account (manager, connection); + g_object_ref (priv->account); + g_object_unref (manager); + } + return priv->account; } -void -empathy_contact_set_account (EmpathyContact *contact, - McAccount *account) +TpConnection * +empathy_contact_get_connection (EmpathyContact *contact) { EmpathyContactPriv *priv; - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); priv = GET_PRIV (contact); - if (account == priv->account) - return; + if (priv->tp_contact != NULL) + return tp_contact_get_connection (priv->tp_contact); - if (priv->account) - g_object_unref (priv->account); - priv->account = g_object_ref (account); + return NULL; +} + +static McPresence +presence_type_to_mc_presence (TpConnectionPresenceType type) +{ + switch (type) + { + case TP_CONNECTION_PRESENCE_TYPE_UNSET: + case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN: + case TP_CONNECTION_PRESENCE_TYPE_ERROR: + return MC_PRESENCE_UNSET; + case TP_CONNECTION_PRESENCE_TYPE_OFFLINE: + return MC_PRESENCE_OFFLINE; + case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE: + return MC_PRESENCE_AVAILABLE; + case TP_CONNECTION_PRESENCE_TYPE_AWAY: + return MC_PRESENCE_AWAY; + case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY: + return MC_PRESENCE_EXTENDED_AWAY; + case TP_CONNECTION_PRESENCE_TYPE_HIDDEN: + return MC_PRESENCE_HIDDEN; + case TP_CONNECTION_PRESENCE_TYPE_BUSY: + return MC_PRESENCE_DO_NOT_DISTURB; + } - g_object_notify (G_OBJECT (contact), "account"); + return MC_PRESENCE_UNSET; } McPresence @@ -644,6 +609,10 @@ empathy_contact_get_presence (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return presence_type_to_mc_presence (tp_contact_get_presence_type ( + priv->tp_contact)); + return priv->presence; } @@ -678,6 +647,9 @@ empathy_contact_get_presence_message (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_presence_message (priv->tp_contact); + return priv->presence_message; } @@ -707,6 +679,9 @@ empathy_contact_get_handle (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_handle (priv->tp_contact); + return priv->handle; } @@ -726,12 +701,6 @@ empathy_contact_set_handle (EmpathyContact *contact, priv->handle = handle; g_object_notify (G_OBJECT (contact), "handle"); } - - if (handle != 0) - contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE); - else - contact_remove_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE); - g_object_unref (contact); } @@ -798,28 +767,24 @@ empathy_contact_set_is_user (EmpathyContact *contact, gboolean empathy_contact_is_online (EmpathyContact *contact) { - EmpathyContactPriv *priv; - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - priv = GET_PRIV (contact); - - return (priv->presence > MC_PRESENCE_OFFLINE); + return (empathy_contact_get_presence (contact) > MC_PRESENCE_OFFLINE); } const gchar * empathy_contact_get_status (EmpathyContact *contact) { - EmpathyContactPriv *priv; + const gchar *message; g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), ""); - priv = GET_PRIV (contact); - - if (priv->presence_message) - return priv->presence_message; + message = empathy_contact_get_presence_message (contact); + if (!EMP_STR_EMPTY (message)) + return message; - return empathy_presence_get_default_message (priv->presence); + return empathy_presence_get_default_message ( + empathy_contact_get_presence (contact)); } gboolean @@ -847,112 +812,12 @@ empathy_contact_can_send_files (EmpathyContact *contact) return priv->capabilities & EMPATHY_CAPABILITIES_FT; } -EmpathyContactReady -empathy_contact_get_ready (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - - priv = GET_PRIV (contact); - - return priv->ready; -} - -gboolean -empathy_contact_equal (gconstpointer v1, - gconstpointer v2) -{ - McAccount *account_a; - McAccount *account_b; - const gchar *id_a; - const gchar *id_b; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE); - g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE); - - account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1)); - account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2)); - - id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1)); - id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2)); - - return empathy_account_equal (account_a, account_b) && - !tp_strdiff (id_a, id_b); -} - -guint -empathy_contact_hash (gconstpointer key) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (key), +1); - - priv = GET_PRIV (EMPATHY_CONTACT (key)); - - if (priv->hash == 0) - { - priv->hash = empathy_account_hash (priv->account) ^ - g_str_hash (priv->id); - } - - return priv->hash; -} - -void empathy_contact_call_when_ready (EmpathyContact *contact, - EmpathyContactReady ready, EmpathyContactReadyCb *callback, - gpointer user_data, GDestroyNotify destroy, GObject *weak_object) -{ - EmpathyContactPriv *priv = GET_PRIV (contact); - - g_return_if_fail (contact != NULL); - g_return_if_fail (callback != NULL); - - if (contact_is_ready (contact, ready)) - { - callback (contact, NULL, user_data, weak_object); - if (destroy != NULL) - destroy (user_data); - } - else - { - ReadyCbData *d = g_slice_new0 (ReadyCbData); - d->ready = ready; - d->callback = callback; - d->user_data = user_data; - d->destroy = destroy; - d->weak_object = weak_object; - - if (weak_object != NULL) - g_object_weak_ref (weak_object, contact_weak_object_notify, contact); - - priv->ready_callbacks = g_list_prepend (priv->ready_callbacks, d); - } -} - -static gboolean -contact_is_ready_func (GObject *contact, - gpointer user_data) -{ - return contact_is_ready (EMPATHY_CONTACT (contact), - GPOINTER_TO_UINT (user_data)); -} - -void -empathy_contact_run_until_ready (EmpathyContact *contact, - EmpathyContactReady ready, - GMainLoop **loop) -{ - empathy_run_until_ready_full (contact, "notify::ready", - contact_is_ready_func, GUINT_TO_POINTER (ready), - loop); -} - static gchar * contact_get_avatar_filename (EmpathyContact *contact, const gchar *token) { EmpathyContactPriv *priv = GET_PRIV (contact); + McAccount *account; gchar *avatar_path; gchar *avatar_file; gchar *token_escaped; @@ -963,11 +828,13 @@ contact_get_avatar_filename (EmpathyContact *contact, contact_escaped = tp_escape_as_identifier (priv->id); token_escaped = tp_escape_as_identifier (token); + account = empathy_contact_get_account (contact); + /* FIXME: Do not use the account, but proto/cm instead */ avatar_path = g_build_filename (g_get_user_cache_dir (), PACKAGE_NAME, "avatars", - mc_account_get_unique_name (priv->account), + mc_account_get_unique_name (account), contact_escaped, NULL); g_mkdir_with_parents (avatar_path, 0700); diff --git a/libempathy/empathy-contact.h b/libempathy/empathy-contact.h index 52c969f61..c10561d0f 100644 --- a/libempathy/empathy-contact.h +++ b/libempathy/empathy-contact.h @@ -1,26 +1,22 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2004 Imendio AB - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * Authors: Mikael Hallendal <micke@imendio.com> - * Martyn Russell <martyn@imendio.com> - * Xavier Claessens <xclaesse@gmail.com> + * Authors: Xavier Claessens <xclaesse@gmail.com> */ #ifndef __EMPATHY_CONTACT_H__ @@ -28,8 +24,8 @@ #include <glib-object.h> +#include <telepathy-glib/contact.h> #include <libmissioncontrol/mc-account.h> -#include <libmissioncontrol/mission-control.h> G_BEGIN_DECLS @@ -70,18 +66,11 @@ typedef enum { EMPATHY_CAPABILITIES_UNKNOWN = 1 << 7 } EmpathyCapabilities; -typedef enum { - EMPATHY_CONTACT_READY_NONE = 0, - EMPATHY_CONTACT_READY_ID = 1 << 0, - EMPATHY_CONTACT_READY_HANDLE = 1 << 1, - EMPATHY_CONTACT_READY_NAME = 1 << 2, - EMPATHY_CONTACT_READY_ALL = (1 << 3) - 1, -} EmpathyContactReady; - GType empathy_contact_get_type (void) G_GNUC_CONST; -EmpathyContact * empathy_contact_new (McAccount *account); -EmpathyContact * empathy_contact_new_full (McAccount *account, const gchar *id, - const gchar *name); +EmpathyContact * empathy_contact_new (TpContact *tp_contact); +EmpathyContact * empathy_contact_new_for_log (McAccount *account, + const gchar *id, const gchar *name, gboolean is_user); +TpContact * empathy_contact_get_tp_contact (EmpathyContact *contact); const gchar * empathy_contact_get_id (EmpathyContact *contact); void empathy_contact_set_id (EmpathyContact *contact, const gchar *id); const gchar * empathy_contact_get_name (EmpathyContact *contact); @@ -90,7 +79,7 @@ EmpathyAvatar * empathy_contact_get_avatar (EmpathyContact *contact); void empathy_contact_set_avatar (EmpathyContact *contact, EmpathyAvatar *avatar); McAccount * empathy_contact_get_account (EmpathyContact *contact); -void empathy_contact_set_account (EmpathyContact *contact, McAccount *account); +TpConnection * empathy_contact_get_connection (EmpathyContact *contact); McPresence empathy_contact_get_presence (EmpathyContact *contact); void empathy_contact_set_presence (EmpathyContact *contact, McPresence presence); @@ -102,7 +91,6 @@ void empathy_contact_set_handle (EmpathyContact *contact, guint handle); EmpathyCapabilities empathy_contact_get_capabilities (EmpathyContact *contact); void empathy_contact_set_capabilities (EmpathyContact *contact, EmpathyCapabilities capabilities); -EmpathyContactReady empathy_contact_get_ready (EmpathyContact *contact); gboolean empathy_contact_is_user (EmpathyContact *contact); void empathy_contact_set_is_user (EmpathyContact *contact, gboolean is_user); @@ -110,19 +98,8 @@ gboolean empathy_contact_is_online (EmpathyContact *contact); const gchar * empathy_contact_get_status (EmpathyContact *contact); gboolean empathy_contact_can_voip (EmpathyContact *contact); gboolean empathy_contact_can_send_files (EmpathyContact *contact); -gboolean empathy_contact_equal (gconstpointer v1, gconstpointer v2); guint empathy_contact_hash (gconstpointer key); -typedef void (EmpathyContactReadyCb) - (EmpathyContact *contact, const GError *error, gpointer user_data, - GObject *weak_object); -void empathy_contact_call_when_ready (EmpathyContact *contact, - EmpathyContactReady ready, EmpathyContactReadyCb *callback, gpointer - user_data, GDestroyNotify destroy, GObject *weak_object); - -void empathy_contact_run_until_ready (EmpathyContact *contact, - EmpathyContactReady ready, GMainLoop **loop); - void empathy_contact_load_avatar_data (EmpathyContact *contact, const guchar *data, const gsize len, const gchar *format, const gchar *token); diff --git a/libempathy/empathy-dispatch-operation.c b/libempathy/empathy-dispatch-operation.c index 1786e4169..cfe111181 100644 --- a/libempathy/empathy-dispatch-operation.c +++ b/libempathy/empathy-dispatch-operation.c @@ -24,6 +24,7 @@ #include "empathy-dispatch-operation.h" #include <libempathy/empathy-enum-types.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-tp-chat.h> #include <libempathy/empathy-tp-call.h> #include <libempathy/empathy-tp-file.h> @@ -173,10 +174,37 @@ empathy_dispatch_operation_invalidated (TpProxy *proxy, guint domain, } static void +dispatcher_operation_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *self) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + + if (error) + { + /* FIXME: We should cancel the operation */ + DEBUG ("Error: %s", error->message); + return; + } + + if (priv->contact != NULL) + g_object_unref (priv->contact); + priv->contact = g_object_ref (contact); + g_object_notify (G_OBJECT (self), "contact"); + + tp_channel_call_when_ready (priv->channel, + empathy_dispatch_operation_channel_ready_cb, self); +} + +static void empathy_dispatch_operation_constructed (GObject *object) { EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object); EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + TpHandle handle; + TpHandleType handle_type; empathy_dispatch_operation_set_status (self, EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING); @@ -185,6 +213,19 @@ empathy_dispatch_operation_constructed (GObject *object) g_signal_connect (priv->channel, "invalidated", G_CALLBACK (empathy_dispatch_operation_invalidated), self); + handle = tp_channel_get_handle (priv->channel, &handle_type); + + if (handle_type == TP_CONN_HANDLE_TYPE_CONTACT && priv->contact == NULL) + { + EmpathyTpContactFactory *factory; + + factory = empathy_tp_contact_factory_dup_singleton (priv->connection); + empathy_tp_contact_factory_get_from_handle (factory, handle, + dispatcher_operation_got_contact_cb, NULL, NULL, object); + g_object_unref (factory); + return; + } + tp_channel_call_when_ready (priv->channel, empathy_dispatch_operation_channel_ready_cb, self); } @@ -365,6 +406,23 @@ empathy_dispatcher_operation_tp_chat_ready_cb (GObject *object, } static void +empathy_dispatcher_operation_tp_file_ready_cb (GObject *object, + GParamSpec *spec, gpointer user_data) +{ + EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data); + EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + + if (!empathy_tp_file_is_ready (EMPATHY_TP_FILE (priv->channel_wrapper))) + return; + + g_signal_handler_disconnect (priv->channel_wrapper, priv->ready_handler); + priv->ready_handler = 0; + + empathy_dispatch_operation_set_status (self, + EMPATHY_DISPATCHER_OPERATION_STATE_PENDING); +} + +static void empathy_dispatch_operation_channel_ready_cb (TpChannel *channel, const GError *error, gpointer user_data) { @@ -395,18 +453,23 @@ empathy_dispatch_operation_channel_ready_cb (TpChannel *channel, G_CALLBACK (empathy_dispatcher_operation_tp_chat_ready_cb), self); return; } - } else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA) { - EmpathyTpCall *call = empathy_tp_call_new (channel); - priv->channel_wrapper = G_OBJECT (call); - + EmpathyTpCall *call = empathy_tp_call_new (channel); + priv->channel_wrapper = G_OBJECT (call); } else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER) { - EmpathyTpFile *file = empathy_tp_file_new (channel); - priv->channel_wrapper = G_OBJECT (file); + EmpathyTpFile *file = empathy_tp_file_new (channel); + priv->channel_wrapper = G_OBJECT (file); + + if (!empathy_tp_file_is_ready (file)) + { + priv->ready_handler = g_signal_connect (file, "notify::ready", + G_CALLBACK (empathy_dispatcher_operation_tp_file_ready_cb), self); + return; + } } ready: @@ -524,7 +587,7 @@ empathy_dispatch_operation_get_tp_connection ( priv = GET_PRIV (operation); - return g_object_ref (priv->connection); + return priv->connection; } TpChannel * diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 12c7da967..c8a0f9e60 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -31,7 +31,6 @@ #include <telepathy-glib/gtypes.h> #include <libmissioncontrol/mission-control.h> -#include <libmissioncontrol/mc-account.h> #include <extensions/extensions.h> @@ -39,7 +38,7 @@ #include "empathy-utils.h" #include "empathy-tube-handler.h" #include "empathy-account-manager.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-tp-file.h" #include "empathy-chatroom-manager.h" #include "empathy-utils.h" @@ -54,8 +53,6 @@ typedef struct MissionControl *mc; /* connection to connection data mapping */ GHashTable *connections; - /* accounts to connection mapping */ - GHashTable *accounts; gpointer token; GSList *tubes; @@ -102,7 +99,6 @@ typedef struct typedef struct { - McAccount *account; /* ObjectPath => DispatchData.. */ GHashTable *dispatched_channels; /* ObjectPath -> EmpathyDispatchOperations */ @@ -185,10 +181,9 @@ free_dispatcher_request_data (DispatcherRequestData *r) } static ConnectionData * -new_connection_data (McAccount *account) +new_connection_data (void) { ConnectionData *cd = g_slice_new0 (ConnectionData); - cd->account = g_object_ref (account); cd->dispatched_channels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) free_dispatch_data); @@ -206,7 +201,7 @@ static void free_connection_data (ConnectionData *cd) { GList *l; - g_object_unref (cd->account); + g_hash_table_destroy (cd->dispatched_channels); g_hash_table_destroy (cd->dispatching_channels); int i; @@ -233,12 +228,8 @@ dispatcher_connection_invalidated_cb (TpConnection *connection, EmpathyDispatcher *dispatcher) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - ConnectionData *cd; DEBUG ("Error: %s", message); - cd = g_hash_table_lookup (priv->connections, connection); - - g_hash_table_remove (priv->accounts, cd->account); g_hash_table_remove (priv->connections, connection); } @@ -362,7 +353,6 @@ dispatch_operation_claimed_cb (EmpathyDispatchOperation *operation, connection = empathy_dispatch_operation_get_tp_connection (operation); cd = g_hash_table_lookup (priv->connections, connection); g_assert (cd != NULL); - g_object_unref (G_OBJECT (connection)); object_path = empathy_dispatch_operation_get_object_path (operation); @@ -406,7 +396,6 @@ dispatch_operation_ready_cb (EmpathyDispatchOperation *operation, connection = empathy_dispatch_operation_get_tp_connection (operation); cd = g_hash_table_lookup (priv->connections, connection); g_assert (cd != NULL); - g_object_unref (G_OBJECT (connection)); g_object_ref (operation); g_object_ref (dispatcher); @@ -511,7 +500,6 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, TpChannel *channel; ConnectionData *cd; EmpathyDispatchOperation *operation; - EmpathyContact *contact = NULL; int i; /* Channel types we never want to dispatch because they're either deprecated * or can't sensibly be dispatch (e.g. channels that should always be @@ -575,15 +563,7 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, priv->channels = g_list_prepend (priv->channels, channel); - if (handle_type == TP_CONN_HANDLE_TYPE_CONTACT) - { - EmpathyContactFactory *factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_handle (factory, - cd->account, handle); - g_object_unref (factory); - } - - operation = empathy_dispatch_operation_new (connection, channel, contact, + operation = empathy_dispatch_operation_new (connection, channel, NULL, incoming); g_object_unref (channel); @@ -786,21 +766,21 @@ dispatcher_connection_advertise_capabilities_cb (TpConnection *connection, } static void -dispatcher_connection_ready_cb (TpConnection *connection, - const GError *error, - gpointer dispatcher) +dispatcher_new_connection_cb (EmpathyAccountManager *manager, + TpConnection *connection, + EmpathyDispatcher *dispatcher) { + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); GPtrArray *capabilities; GType cap_type; GValue cap = {0, }; const gchar *remove = NULL; - if (error) - { - dispatcher_connection_invalidated_cb (connection, error->domain, - error->code, error->message, dispatcher); - return; - } + if (g_hash_table_lookup (priv->connections, connection) != NULL) + return; + + g_hash_table_insert (priv->connections, g_object_ref (connection), + new_connection_data ()); g_signal_connect (connection, "invalidated", G_CALLBACK (dispatcher_connection_invalidated_cb), dispatcher); @@ -815,7 +795,7 @@ dispatcher_connection_ready_cb (TpConnection *connection, tp_cli_dbus_properties_call_get_all (connection, -1, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, dispatcher_connection_got_all, - NULL, NULL, dispatcher); + NULL, NULL, G_OBJECT (dispatcher)); } else { @@ -852,44 +832,6 @@ dispatcher_connection_ready_cb (TpConnection *connection, g_ptr_array_free (capabilities, TRUE); } -static void -dispatcher_update_account (EmpathyDispatcher *dispatcher, - McAccount *account) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - TpConnection *connection; - - connection = g_hash_table_lookup (priv->accounts, account); - if (connection != NULL) - return; - - connection = mission_control_get_tpconnection (priv->mc, account, NULL); - if (connection == NULL) - return; - - g_hash_table_insert (priv->connections, g_object_ref (connection), - new_connection_data (account)); - - g_hash_table_insert (priv->accounts, g_object_ref (account), - g_object_ref (connection)); - - tp_connection_call_when_ready (connection, dispatcher_connection_ready_cb, - dispatcher); - - g_object_unref (connection); -} - -static void -dispatcher_account_connection_cb (EmpathyAccountManager *manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus status, - TpConnectionStatus previous, - EmpathyDispatcher *dispatcher) -{ - dispatcher_update_account (dispatcher, account); -} - static GObject* dispatcher_constructor (GType type, guint n_construct_params, @@ -922,7 +864,7 @@ dispatcher_finalize (GObject *object) gpointer connection; g_signal_handlers_disconnect_by_func (priv->account_manager, - dispatcher_account_connection_cb, object); + dispatcher_new_connection_cb, object); for (l = priv->channels; l; l = l->next) { @@ -942,7 +884,6 @@ dispatcher_finalize (GObject *object) g_object_unref (priv->account_manager); g_object_unref (priv->mc); - g_hash_table_destroy (priv->accounts); g_hash_table_destroy (priv->connections); } @@ -991,7 +932,7 @@ empathy_dispatcher_class_init (EmpathyDispatcherClass *klass) static void empathy_dispatcher_init (EmpathyDispatcher *dispatcher) { - GList *accounts, *l; + GList *connections, *l; EmpathyDispatcherPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (dispatcher, EMPATHY_TYPE_DISPATCHER, EmpathyDispatcherPriv); @@ -999,27 +940,22 @@ empathy_dispatcher_init (EmpathyDispatcher *dispatcher) priv->mc = empathy_mission_control_dup_singleton (); priv->account_manager = empathy_account_manager_dup_singleton (); - g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (dispatcher_account_connection_cb), + g_signal_connect (priv->account_manager, "new-connection", + G_CALLBACK (dispatcher_new_connection_cb), dispatcher); - priv->accounts = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, g_object_unref, g_object_unref); - priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) free_connection_data); priv->channels = NULL; - accounts = mc_accounts_list_by_enabled (TRUE); - - for (l = accounts; l; l = l->next) + connections = empathy_account_manager_dup_connections (priv->account_manager); + for (l = connections; l; l = l->next) { - dispatcher_update_account (dispatcher, l->data); + dispatcher_new_connection_cb (priv->account_manager, l->data, dispatcher); g_object_unref (l->data); } - g_list_free (accounts); + g_list_free (connections); } EmpathyDispatcher * @@ -1168,57 +1104,12 @@ dispatcher_request_channel (DispatcherRequestData *request_data) } void -empathy_dispatcher_call_with_contact (EmpathyContact *contact, - EmpathyDispatcherRequestCb *callback, - gpointer user_data) -{ - EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton(); - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - McAccount *account; - TpConnection *connection; - ConnectionData *cd; - DispatcherRequestData *request_data; - - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - account = empathy_contact_get_account (contact); - connection = g_hash_table_lookup (priv->accounts, account); - - g_assert (connection != NULL); - cd = g_hash_table_lookup (priv->connections, connection); - request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_HANDLE_TYPE_NONE, 0, NULL, - contact, callback, user_data); - - cd->outstanding_requests = g_list_prepend - (cd->outstanding_requests, request_data); - - dispatcher_request_channel (request_data); - - g_object_unref (dispatcher); -} - -static void -dispatcher_chat_with_contact_cb (EmpathyContact *contact, - const GError *error, - gpointer user_data, - GObject *object) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - - request_data->handle = empathy_contact_get_handle (contact); - - dispatcher_request_channel (request_data); -} - -void empathy_dispatcher_chat_with_contact (EmpathyContact *contact, EmpathyDispatcherRequestCb *callback, gpointer user_data) { EmpathyDispatcher *dispatcher; EmpathyDispatcherPriv *priv; - McAccount *account; TpConnection *connection; ConnectionData *connection_data; DispatcherRequestData *request_data; @@ -1228,46 +1119,75 @@ empathy_dispatcher_chat_with_contact (EmpathyContact *contact, dispatcher = empathy_dispatcher_dup_singleton(); priv = GET_PRIV (dispatcher); - account = empathy_contact_get_account (contact); - connection = g_hash_table_lookup (priv->accounts, account); + connection = empathy_contact_get_connection (contact); connection_data = g_hash_table_lookup (priv->connections, connection); /* The contact handle might not be known yet */ request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_CONTACT, 0, NULL, - contact, callback, user_data); + TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_CONTACT, + empathy_contact_get_handle (contact), NULL, contact, callback, user_data); connection_data->outstanding_requests = g_list_prepend (connection_data->outstanding_requests, request_data); - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_HANDLE, dispatcher_chat_with_contact_cb, - request_data, NULL, G_OBJECT (dispatcher)); + dispatcher_request_channel (request_data); g_object_unref (dispatcher); } +typedef struct +{ + EmpathyDispatcher *dispatcher; + EmpathyDispatcherRequestCb *callback; + gpointer user_data; +} ChatWithContactIdData; + +static void +dispatcher_chat_with_contact_id_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + ChatWithContactIdData *data = user_data; + + if (error) + { + /* FIXME: Should call data->callback with the error */ + DEBUG ("Error: %s", error->message); + } + else + { + empathy_dispatcher_chat_with_contact (contact, data->callback, data->user_data); + } + + g_object_unref (data->dispatcher); + g_slice_free (ChatWithContactIdData, data); +} + void -empathy_dispatcher_chat_with_contact_id (McAccount *account, +empathy_dispatcher_chat_with_contact_id (TpConnection *connection, const gchar *contact_id, EmpathyDispatcherRequestCb *callback, gpointer user_data) { - EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton (); - EmpathyContactFactory *factory; - EmpathyContact *contact; + EmpathyDispatcher *dispatcher; + EmpathyTpContactFactory *factory; + ChatWithContactIdData *data; - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (TP_IS_CONNECTION (connection)); g_return_if_fail (!EMP_STR_EMPTY (contact_id)); - factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_id (factory, account, contact_id); - - empathy_dispatcher_chat_with_contact (contact, callback, user_data); + dispatcher = empathy_dispatcher_dup_singleton (); + factory = empathy_tp_contact_factory_dup_singleton (connection); + data = g_slice_new0 (ChatWithContactIdData); + data->dispatcher = dispatcher; + data->callback = callback; + data->user_data = user_data; + empathy_tp_contact_factory_get_from_id (factory, contact_id, + dispatcher_chat_with_contact_id_cb, data, NULL, NULL); - g_object_unref (contact); g_object_unref (factory); - g_object_unref (dispatcher); } static void @@ -1304,7 +1224,7 @@ dispatcher_request_handles_cb (TpConnection *connection, } void -empathy_dispatcher_join_muc (McAccount *account, +empathy_dispatcher_join_muc (TpConnection *connection, const gchar *roomname, EmpathyDispatcherRequestCb *callback, gpointer user_data) @@ -1312,20 +1232,17 @@ empathy_dispatcher_join_muc (McAccount *account, EmpathyDispatcher *dispatcher; EmpathyDispatcherPriv *priv; DispatcherRequestData *request_data; - TpConnection *connection; ConnectionData *connection_data; const gchar *names[] = { roomname, NULL }; - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (TP_IS_CONNECTION (connection)); g_return_if_fail (!EMP_STR_EMPTY (roomname)); dispatcher = empathy_dispatcher_dup_singleton(); priv = GET_PRIV (dispatcher); - connection = g_hash_table_lookup (priv->accounts, account); connection_data = g_hash_table_lookup (priv->connections, connection); - /* Don't know the room handle yet */ request_data = new_dispatcher_request_data (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_ROOM, 0, NULL, @@ -1359,7 +1276,7 @@ dispatcher_create_channel_cb (TpConnection *connect, void empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, - McAccount *account, + TpConnection *connection, GHashTable *request, EmpathyDispatcherRequestCb *callback, gpointer user_data) @@ -1371,15 +1288,11 @@ empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, guint handle_type; guint handle; gboolean valid; - TpConnection *connection; g_return_if_fail (EMPATHY_IS_DISPATCHER (dispatcher)); - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (TP_IS_CONNECTION (connection)); g_return_if_fail (request != NULL); - connection = g_hash_table_lookup (priv->accounts, account); - g_assert (connection != NULL); - connection_data = g_hash_table_lookup (priv->connections, connection); g_assert (connection_data != NULL); @@ -1405,56 +1318,6 @@ empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, G_OBJECT (request_data->dispatcher)); } -static void -dispatcher_create_channel_with_contact_cb (EmpathyContact *contact, - const GError *error, - gpointer user_data, - GObject *object) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - GValue *target_handle; - - g_assert (request_data->request); - - if (error != NULL) - { - dispatcher_request_failed (request_data->dispatcher, - request_data, error); - return; - } - - request_data->handle = empathy_contact_get_handle (contact); - - target_handle = tp_g_value_slice_new (G_TYPE_UINT); - g_value_set_uint (target_handle, request_data->handle); - g_hash_table_insert (request_data->request, - TP_IFACE_CHANNEL ".TargetHandle", target_handle); - - tp_cli_connection_interface_requests_call_create_channel ( - request_data->connection, -1, - request_data->request, dispatcher_create_channel_cb, request_data, NULL, - G_OBJECT (request_data->dispatcher)); -} - -static void -dispatcher_send_file_connection_ready_cb (TpConnection *connection, - const GError *error, - gpointer user_data) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - - if (error != NULL) - { - dispatcher_request_failed (request_data->dispatcher, - request_data, error); - return; - } - - empathy_contact_call_when_ready (request_data->contact, - EMPATHY_CONTACT_READY_HANDLE, dispatcher_create_channel_with_contact_cb, - request_data, NULL, G_OBJECT (request_data->dispatcher)); -} - void empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, const gchar *filename, @@ -1466,8 +1329,7 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, { EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton(); EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - McAccount *account = empathy_contact_get_account (contact); - TpConnection *connection = g_hash_table_lookup (priv->accounts, account); + TpConnection *connection = empathy_contact_get_connection (contact); ConnectionData *connection_data = g_hash_table_lookup (priv->connections, connection); DispatcherRequestData *request_data; @@ -1489,6 +1351,11 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandleType", value); + /* org.freedesktop.Telepathy.Channel.TargetHandle */ + value = tp_g_value_slice_new (G_TYPE_UINT); + g_value_set_uint (value, empathy_contact_get_handle (contact)); + g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value); + /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentType */ value = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (value, content_type); @@ -1513,46 +1380,40 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, g_hash_table_insert (request, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Date", value); - - /* The contact handle might not be known yet */ - request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT, 0, request, - contact, callback, user_data); + request_data = new_dispatcher_request_data (dispatcher, connection, + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT, + empathy_contact_get_handle (contact), request, contact, callback, + user_data); connection_data->outstanding_requests = g_list_prepend (connection_data->outstanding_requests, request_data); - tp_connection_call_when_ready (connection, - dispatcher_send_file_connection_ready_cb, (gpointer) request_data); + tp_cli_connection_interface_requests_call_create_channel ( + request_data->connection, -1, + request_data->request, dispatcher_create_channel_cb, request_data, NULL, + G_OBJECT (request_data->dispatcher)); g_object_unref (dispatcher); } GStrv empathy_dispatcher_find_channel_class (EmpathyDispatcher *dispatcher, - McAccount *account, + TpConnection *connection, const gchar *channel_type, guint handle_type) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); ConnectionData *cd; - TpConnection *connection; int i; GPtrArray *classes; g_return_val_if_fail (channel_type != NULL, NULL); g_return_val_if_fail (handle_type != 0, NULL); - connection = g_hash_table_lookup (priv->accounts, account); - - if (connection == NULL) - return NULL; - cd = g_hash_table_lookup (priv->connections, connection); if (cd == NULL) return NULL; - classes = cd->requestable_channels; if (classes == NULL) return NULL; diff --git a/libempathy/empathy-dispatcher.h b/libempathy/empathy-dispatcher.h index 13ef06afd..fb7c6fe35 100644 --- a/libempathy/empathy-dispatcher.h +++ b/libempathy/empathy-dispatcher.h @@ -62,15 +62,11 @@ typedef void (EmpathyDispatcherRequestCb) ( GType empathy_dispatcher_get_type (void) G_GNUC_CONST; void empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, - McAccount *account, GHashTable *request, - EmpathyDispatcherRequestCb *callback, gpointer user_data); - -/* Requesting 1 to 1 stream media channels */ -void empathy_dispatcher_call_with_contact (EmpathyContact *contact, + TpConnection *connection, GHashTable *request, EmpathyDispatcherRequestCb *callback, gpointer user_data); /* Requesting 1 to 1 text channels */ -void empathy_dispatcher_chat_with_contact_id (McAccount *account, +void empathy_dispatcher_chat_with_contact_id (TpConnection *connection, const gchar *contact_id, EmpathyDispatcherRequestCb *callback, gpointer user_data); void empathy_dispatcher_chat_with_contact (EmpathyContact *contact, @@ -83,12 +79,12 @@ void empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, gpointer user_data); /* Request a muc channel */ -void empathy_dispatcher_join_muc (McAccount *account, +void empathy_dispatcher_join_muc (TpConnection *connection, const gchar *roomname, EmpathyDispatcherRequestCb *callback, gpointer user_data); GStrv empathy_dispatcher_find_channel_class (EmpathyDispatcher *dispatcher, - McAccount *account, const gchar *channel_type, guint handle_type); + TpConnection *connection, const gchar *channel_type, guint handle_type); /* Get the dispatcher singleton */ EmpathyDispatcher * empathy_dispatcher_dup_singleton (void); diff --git a/libempathy/empathy-log-store-empathy.c b/libempathy/empathy-log-store-empathy.c index 37a76676f..b74b5e177 100644 --- a/libempathy/empathy-log-store-empathy.c +++ b/libempathy/empathy-log-store-empathy.c @@ -481,8 +481,9 @@ log_store_empathy_get_messages_for_file (EmpathyLogStore *self, t = empathy_time_parse (time); - sender = empathy_contact_new_full (account, sender_id, sender_name); - empathy_contact_set_is_user (sender, is_user); + sender = empathy_contact_new_for_log (account, sender_id, sender_name, + is_user); + if (!EMP_STR_EMPTY (sender_avatar_token)) empathy_contact_load_avatar_cache (sender, sender_avatar_token); diff --git a/libempathy/empathy-tp-call.c b/libempathy/empathy-tp-call.c index 42bf7a063..a5c0003c5 100644 --- a/libempathy/empathy-tp-call.c +++ b/libempathy/empathy-tp-call.c @@ -27,7 +27,7 @@ #include <telepathy-glib/interfaces.h> #include "empathy-tp-call.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_TP @@ -253,22 +253,27 @@ tp_call_request_streams_for_capabilities (EmpathyTpCall *call, g_array_free (stream_types, TRUE); } -static EmpathyContact * -tp_call_dup_contact_from_handle (EmpathyTpCall *call, TpHandle handle) +static void +tp_call_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *call) { EmpathyTpCallPriv *priv = GET_PRIV (call); - EmpathyContactFactory *factory; - McAccount *account; - EmpathyContact *contact; - - factory = empathy_contact_factory_dup_singleton (); - account = empathy_channel_get_account (priv->channel); - contact = empathy_contact_factory_get_from_handle (factory, account, handle); - g_object_unref (factory); - g_object_unref (account); + if (error) + { + DEBUG ("Error: %s", error->message); + return; + } - return contact; + priv->contact = g_object_ref (contact); + priv->is_incoming = TRUE; + priv->status = EMPATHY_TP_CALL_STATUS_PENDING; + g_object_notify (G_OBJECT (call), "is-incoming"); + g_object_notify (G_OBJECT (call), "contact"); + g_object_notify (G_OBJECT (call), "status"); } static void @@ -288,13 +293,15 @@ tp_call_update_status (EmpathyTpCall *call) { if (priv->contact == NULL && iter.element != self_handle) { + EmpathyTpContactFactory *factory; + TpConnection *connection; + /* We found the remote contact */ - priv->contact = tp_call_dup_contact_from_handle (call, iter.element); - priv->is_incoming = TRUE; - priv->status = EMPATHY_TP_CALL_STATUS_PENDING; - g_object_notify (G_OBJECT (call), "is-incoming"); - g_object_notify (G_OBJECT (call), "contact"); - g_object_notify (G_OBJECT (call), "status"); + connection = tp_channel_borrow_connection (priv->channel); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_handle (factory, iter.element, + tp_call_got_contact_cb, NULL, NULL, G_OBJECT (call)); + g_object_unref (factory); } if (priv->status == EMPATHY_TP_CALL_STATUS_PENDING && @@ -309,20 +316,6 @@ tp_call_update_status (EmpathyTpCall *call) g_object_unref (call); } -static void -tp_call_members_changed_cb (TpChannel *channel, - gchar *message, - GArray *added, - GArray *removed, - GArray *local_pending, - GArray *remote_pending, - guint actor, - guint reason, - EmpathyTpCall *call) -{ - tp_call_update_status (call); -} - void empathy_tp_call_to (EmpathyTpCall *call, EmpathyContact *contact) { @@ -392,8 +385,8 @@ tp_call_constructor (GType type, /* Update status when members changes */ tp_call_update_status (call); - g_signal_connect (priv->channel, "group-members-changed", - G_CALLBACK (tp_call_members_changed_cb), call); + g_signal_connect_swapped (priv->channel, "group-members-changed", + G_CALLBACK (tp_call_update_status), call); return object; } diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c index 048f5b275..54e08d071 100644 --- a/libempathy/empathy-tp-chat.c +++ b/libempathy/empathy-tp-chat.c @@ -28,8 +28,7 @@ #include <telepathy-glib/util.h> #include "empathy-tp-chat.h" -#include "empathy-tp-group.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-contact-monitor.h" #include "empathy-contact-list.h" #include "empathy-marshal.h" @@ -42,12 +41,11 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpChat) typedef struct { gboolean dispose_has_run; - EmpathyContactFactory *factory; + EmpathyTpContactFactory *factory; EmpathyContactMonitor *contact_monitor; EmpathyContact *user; EmpathyContact *remote_contact; - EmpathyTpGroup *group; - McAccount *account; + GList *members; TpChannel *channel; gboolean listing_pending_messages; /* Queue of messages not signalled yet */ @@ -57,7 +55,6 @@ typedef struct { gboolean had_properties_list; GPtrArray *properties; gboolean ready; - guint members_count; } EmpathyTpChatPriv; typedef struct { @@ -100,13 +97,8 @@ tp_chat_invalidated_cb (TpProxy *proxy, gchar *message, EmpathyTpChat *chat) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - DEBUG ("Channel invalidated: %s", message); g_signal_emit (chat, signals[DESTROY], 0); - - g_object_unref (priv->channel); - priv->channel = NULL; } static void @@ -121,108 +113,6 @@ tp_chat_async_cb (TpChannel *proxy, } static void -tp_chat_member_added_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - guint handle_type = 0; - - if (priv->channel == NULL) - return; - - priv->members_count++; - g_signal_emit_by_name (chat, "members-changed", - contact, actor, reason, message, - TRUE); - - g_object_get (priv->channel, "handle-type", &handle_type, NULL); - if (handle_type == TP_HANDLE_TYPE_ROOM) { - return; - } - - if (priv->members_count > 2 && priv->remote_contact) { - /* We now have more than 2 members, this is not a p2p chat - * anymore. Remove the remote-contact as it makes no sense, the - * EmpathyContactList interface must be used now. */ - g_object_unref (priv->remote_contact); - priv->remote_contact = NULL; - g_object_notify (G_OBJECT (chat), "remote-contact"); - } - if (priv->members_count <= 2 && !priv->remote_contact && - !empathy_contact_is_user (contact)) { - /* This is a p2p chat, if it's not ourself that means this is - * the remote contact with who we are chatting. This is to - * avoid forcing the usage of the EmpathyContactList interface - * for p2p chats. */ - priv->remote_contact = g_object_ref (contact); - g_object_notify (G_OBJECT (chat), "remote-contact"); - } -} - -static void -tp_chat_member_removed_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - guint handle_type = 0; - - if (priv->channel == NULL) - return; - - priv->members_count--; - g_signal_emit_by_name (chat, "members-changed", - contact, actor, reason, message, - FALSE); - - g_object_get (priv->channel, "handle-type", &handle_type, NULL); - if (handle_type == TP_HANDLE_TYPE_ROOM) { - return; - } - - if (priv->members_count <= 2 && !priv->remote_contact) { - GList *members, *l; - - /* We are not a MUC anymore, get the remote contact back */ - members = empathy_tp_group_get_members (group); - for (l = members; l; l = l->next) { - if (!empathy_contact_is_user (l->data)) { - priv->remote_contact = g_object_ref (l->data); - g_object_notify (G_OBJECT (chat), "remote-contact"); - break; - } - } - g_list_foreach (members, (GFunc) g_object_unref, NULL); - g_list_free (members); - } -} - -static void -tp_chat_local_pending_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - - if (priv->channel == NULL) - return; - - g_signal_emit_by_name (chat, "pendings-changed", - contact, actor, reason, message, - TRUE); -} - -static void tp_chat_add (EmpathyContactList *list, EmpathyContact *contact, const gchar *message) @@ -268,8 +158,9 @@ tp_chat_get_members (EmpathyContactList *list) g_return_val_if_fail (EMPATHY_IS_TP_CHAT (list), NULL); - if (priv->group) { - members = empathy_tp_group_get_members (priv->group); + if (priv->members) { + members = g_list_copy (priv->members); + g_list_foreach (members, (GFunc) g_object_ref, NULL); } else { members = g_list_prepend (members, g_object_ref (priv->user)); members = g_list_prepend (members, g_object_ref (priv->remote_contact)); @@ -294,119 +185,74 @@ tp_chat_get_monitor (EmpathyContactList *list) return priv->contact_monitor; } -static EmpathyMessage * -tp_chat_build_message (EmpathyTpChat *chat, - guint id, - guint type, - guint timestamp, - guint from_handle, - const gchar *message_body) +static void +tp_chat_emit_queued_messages (EmpathyTpChat *chat) { - EmpathyTpChatPriv *priv; + EmpathyTpChatPriv *priv = GET_PRIV (chat); EmpathyMessage *message; - EmpathyContact *sender; - priv = GET_PRIV (chat); - - if (from_handle == 0) { - sender = g_object_ref (priv->user); - } else { - sender = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - from_handle); - } - - message = empathy_message_new (message_body); - empathy_message_set_tptype (message, type); - empathy_message_set_sender (message, sender); - empathy_message_set_receiver (message, priv->user); - empathy_message_set_timestamp (message, timestamp); - empathy_message_set_id (message, id); - - g_object_unref (sender); - - return message; -} - -static void -tp_chat_sender_ready_notify_cb (EmpathyContact *contact, - GParamSpec *param_spec, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyMessage *message; - EmpathyContactReady ready; - EmpathyContact *sender = NULL; - gboolean removed = FALSE; - - /* Emit all messages queued until we find a message with not - * ready sender (in case of a MUC we could have more than one sender). - * When leaving this loop, sender is the first not ready contact queued - * and removed tells if at least one message got removed - * from the queue. */ + /* Check if we can now emit some queued messages */ while ((message = g_queue_peek_head (priv->messages_queue)) != NULL) { - sender = empathy_message_get_sender (message); - ready = empathy_contact_get_ready (sender); - - if ((ready & EMPATHY_CONTACT_READY_NAME) == 0 || - (ready & EMPATHY_CONTACT_READY_ID) == 0) { + if (empathy_message_get_sender (message) == NULL) { break; } DEBUG ("Queued message ready"); - message = g_queue_pop_head (priv->messages_queue); + g_queue_pop_head (priv->messages_queue); g_queue_push_tail (priv->pending_messages_queue, message); g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message); - removed = TRUE; } +} - if (removed) { - /* We removed at least one message from the queue, disconnect - * the ready signal from the previous contact */ - g_signal_handlers_disconnect_by_func (contact, - tp_chat_sender_ready_notify_cb, - chat); - - if (g_queue_get_length (priv->messages_queue) > 0) { - /* We still have queued message, connect the ready - * signal on the new first message sender. */ - g_signal_connect (sender, "notify::ready", - G_CALLBACK (tp_chat_sender_ready_notify_cb), - chat); - } +static void +tp_chat_got_sender_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer message, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + if (error) { + DEBUG ("Error: %s", error->message); + /* Do not block the message queue, just drop this message */ + g_queue_remove (priv->messages_queue, message); + } else { + empathy_message_set_sender (message, contact); } + + tp_chat_emit_queued_messages (EMPATHY_TP_CHAT (chat)); } static void -tp_chat_emit_or_queue_message (EmpathyTpChat *chat, - EmpathyMessage *message) +tp_chat_build_message (EmpathyTpChat *chat, + guint id, + guint type, + guint timestamp, + guint from_handle, + const gchar *message_body) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyContact *sender; - EmpathyContactReady ready; + EmpathyTpChatPriv *priv; + EmpathyMessage *message; - if (g_queue_get_length (priv->messages_queue) > 0) { - DEBUG ("Message queue not empty"); - g_queue_push_tail (priv->messages_queue, g_object_ref (message)); - return; - } + priv = GET_PRIV (chat); + message = empathy_message_new (message_body); + empathy_message_set_tptype (message, type); + empathy_message_set_receiver (message, priv->user); + empathy_message_set_timestamp (message, timestamp); + empathy_message_set_id (message, id); + g_queue_push_tail (priv->messages_queue, message); - sender = empathy_message_get_sender (message); - ready = empathy_contact_get_ready (sender); - if ((ready & EMPATHY_CONTACT_READY_NAME) && - (ready & EMPATHY_CONTACT_READY_ID)) { - DEBUG ("Message queue empty and sender ready"); - g_queue_push_tail (priv->pending_messages_queue, g_object_ref (message)); - g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message); - return; + if (from_handle == 0) { + empathy_message_set_sender (message, priv->user); + tp_chat_emit_queued_messages (chat); + } else { + empathy_tp_contact_factory_get_from_handle (priv->factory, + from_handle, + tp_chat_got_sender_cb, + message, NULL, G_OBJECT (chat)); } - - DEBUG ("Sender not ready"); - g_queue_push_tail (priv->messages_queue, g_object_ref (message)); - g_signal_connect (sender, "notify::ready", - G_CALLBACK (tp_chat_sender_ready_notify_cb), - chat); } static void @@ -422,7 +268,6 @@ tp_chat_received_cb (TpChannel *channel, { EmpathyTpChat *chat = EMPATHY_TP_CHAT (chat_); EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyMessage *message; if (priv->channel == NULL) return; @@ -447,15 +292,12 @@ tp_chat_received_cb (TpChannel *channel, return; } - message = tp_chat_build_message (chat, - message_id, - message_type, - timestamp, - from_handle, - message_body); - - tp_chat_emit_or_queue_message (chat, message); - g_object_unref (message); + tp_chat_build_message (chat, + message_id, + message_type, + timestamp, + from_handle, + message_body); } static void @@ -468,22 +310,18 @@ tp_chat_sent_cb (TpChannel *channel, { EmpathyTpChat *chat = EMPATHY_TP_CHAT (chat_); EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyMessage *message; if (priv->channel == NULL) return; DEBUG ("Message sent: %s", message_body); - message = tp_chat_build_message (chat, - 0, - message_type, - timestamp, - 0, - message_body); - - tp_chat_emit_or_queue_message (chat, message); - g_object_unref (message); + tp_chat_build_message (chat, + 0, + message_type, + timestamp, + 0, + message_body); } static void @@ -495,7 +333,6 @@ tp_chat_send_error_cb (TpChannel *channel, gpointer user_data, GObject *chat) { - EmpathyMessage *message; EmpathyTpChatPriv *priv = GET_PRIV (chat); if (priv->channel == NULL) @@ -503,15 +340,12 @@ tp_chat_send_error_cb (TpChannel *channel, DEBUG ("Message sent error: %s (%d)", message_body, error_code); - message = tp_chat_build_message (EMPATHY_TP_CHAT (chat), - 0, - message_type, - timestamp, - 0, - message_body); - - g_signal_emit (chat, signals[SEND_ERROR], 0, message, error_code); - g_object_unref (message); + tp_chat_build_message (EMPATHY_TP_CHAT (chat), + 0, + message_type, + timestamp, + 0, + message_body); } static void @@ -529,28 +363,45 @@ tp_chat_send_cb (TpChannel *proxy, } } +typedef struct { + EmpathyTpChat *chat; + TpChannelChatState state; +} StateChangedData; + static void -tp_chat_state_changed_cb (TpChannel *channel, - guint handle, - guint state, - gpointer user_data, - GObject *chat) +tp_chat_state_changed_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *chat) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyContact *contact; + TpChannelChatState state; - if (priv->channel == NULL) + if (error) { + DEBUG ("Error: %s", error->message); return; + } - contact = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - handle); - + state = GPOINTER_TO_UINT (user_data); DEBUG ("Chat state changed for %s (%d): %d", - empathy_contact_get_name (contact), handle, state); + empathy_contact_get_name (contact), + empathy_contact_get_handle (contact), state); g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state); - g_object_unref (contact); +} + +static void +tp_chat_state_changed_cb (TpChannel *channel, + TpHandle handle, + TpChannelChatState state, + gpointer user_data, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + empathy_tp_contact_factory_get_from_handle (priv->factory, handle, + tp_chat_state_changed_got_contact_cb, GUINT_TO_POINTER (state), + NULL, chat); } static void @@ -576,7 +427,6 @@ tp_chat_list_pending_messages_cb (TpChannel *channel, } for (i = 0; i < messages_list->len; i++) { - EmpathyMessage *message; GValueArray *message_struct; const gchar *message_body; guint message_id; @@ -608,15 +458,12 @@ tp_chat_list_pending_messages_cb (TpChannel *channel, continue; } - message = tp_chat_build_message (chat, - message_id, - message_type, - timestamp, - from_handle, - message_body); - - tp_chat_emit_or_queue_message (chat, message); - g_object_unref (message); + tp_chat_build_message (chat, + message_id, + message_type, + timestamp, + from_handle, + message_body); } if (empty_non_text_content_ids != NULL) { @@ -781,8 +628,6 @@ empathy_tp_chat_set_property (EmpathyTpChat *chat, TpChatProperty *property; guint i; - g_return_if_fail (priv->ready); - for (i = 0; i < priv->properties->len; i++) { property = g_ptr_array_index (priv->properties, i); if (!tp_strdiff (property->name, name)) { @@ -824,64 +669,90 @@ empathy_tp_chat_set_property (EmpathyTpChat *chat, } static void -tp_chat_channel_ready_cb (EmpathyTpChat *chat) +tp_chat_dispose (GObject *object) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - TpConnection *connection; - guint handle, handle_type; + EmpathyTpChat *self = EMPATHY_TP_CHAT (object); + EmpathyTpChatPriv *priv = GET_PRIV (self); - if (priv->channel == NULL) + if (priv->dispose_has_run) return; - DEBUG ("Channel ready"); - - g_object_get (priv->channel, - "connection", &connection, - "handle", &handle, - "handle_type", &handle_type, - NULL); + priv->dispose_has_run = TRUE; - if (handle_type == TP_HANDLE_TYPE_CONTACT && handle != 0) { - priv->remote_contact = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - handle); - g_object_notify (G_OBJECT (chat), "remote-contact"); + if (priv->channel != NULL) { + g_signal_handlers_disconnect_by_func (priv->channel, + tp_chat_invalidated_cb, self); + g_object_unref (priv->channel); } + priv->channel = NULL; - if (tp_proxy_has_interface_by_id (priv->channel, - TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) { - priv->group = empathy_tp_group_new (priv->channel); - - g_signal_connect (priv->group, "member-added", - G_CALLBACK (tp_chat_member_added_cb), - chat); - g_signal_connect (priv->group, "member-removed", - G_CALLBACK (tp_chat_member_removed_cb), - chat); - g_signal_connect (priv->group, "local-pending", - G_CALLBACK (tp_chat_local_pending_cb), - chat); - empathy_run_until_ready (priv->group); - } else { - priv->members_count = 2; + if (priv->remote_contact != NULL) + g_object_unref (priv->remote_contact); + priv->remote_contact = NULL; + + if (priv->factory != NULL) + g_object_unref (priv->factory); + priv->factory = NULL; + + if (priv->user != NULL); + g_object_unref (priv->user); + priv->user = NULL; + + if (priv->contact_monitor) + g_object_unref (priv->contact_monitor); + priv->contact_monitor = NULL; + + g_queue_foreach (priv->messages_queue, (GFunc) g_object_unref, NULL); + g_queue_clear (priv->messages_queue); + + g_queue_foreach (priv->pending_messages_queue, + (GFunc) g_object_unref, NULL); + g_queue_clear (priv->pending_messages_queue); + + if (G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose) + G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose (object); +} + +static void +tp_chat_finalize (GObject *object) +{ + EmpathyTpChatPriv *priv = GET_PRIV (object); + guint i; + + DEBUG ("Finalize: %p", object); + + if (priv->properties) { + for (i = 0; i < priv->properties->len; i++) { + TpChatProperty *property; + + property = g_ptr_array_index (priv->properties, i); + g_free (property->name); + if (property->value) { + tp_g_value_slice_free (property->value); + } + g_slice_free (TpChatProperty, property); + } + g_ptr_array_free (priv->properties, TRUE); } - - if (tp_proxy_has_interface_by_id (priv->channel, - TP_IFACE_QUARK_PROPERTIES_INTERFACE)) { - tp_cli_properties_interface_call_list_properties (priv->channel, -1, - tp_chat_list_properties_cb, - NULL, NULL, - G_OBJECT (chat)); - tp_cli_properties_interface_connect_to_properties_changed (priv->channel, - tp_chat_properties_changed_cb, - NULL, NULL, - G_OBJECT (chat), NULL); - tp_cli_properties_interface_connect_to_property_flags_changed (priv->channel, - tp_chat_property_flags_changed_cb, - NULL, NULL, - G_OBJECT (chat), NULL); + + g_queue_free (priv->messages_queue); + g_queue_free (priv->pending_messages_queue); + + G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object); +} + +static void +tp_chat_check_if_ready (EmpathyTpChat *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + if (priv->ready || priv->user == NULL || + (priv->members == NULL && priv->remote_contact == NULL)) { + return; } + DEBUG ("Ready!"); + priv->listing_pending_messages = TRUE; tp_cli_channel_type_text_call_list_pending_messages (priv->channel, -1, FALSE, @@ -909,101 +780,184 @@ tp_chat_channel_ready_cb (EmpathyTpChat *chat) tp_chat_state_changed_cb, NULL, NULL, G_OBJECT (chat), NULL); - priv->ready = TRUE; g_object_notify (G_OBJECT (chat), "ready"); } static void -tp_chat_dispose (GObject *object) +tp_chat_update_remote_contact (EmpathyTpChat *chat) { - EmpathyTpChat *self = EMPATHY_TP_CHAT (object); - EmpathyTpChatPriv *priv = GET_PRIV (self); + EmpathyTpChatPriv *priv = GET_PRIV (chat); + EmpathyContact *contact = NULL; + TpHandle self_handle; + TpHandleType handle_type; + GList *l; - if (priv->dispose_has_run) + /* If this is a named chatroom, never pretend it is a private chat */ + tp_channel_get_handle (priv->channel, &handle_type); + if (handle_type == TP_HANDLE_TYPE_ROOM) { return; + } - priv->dispose_has_run = TRUE; - - if (priv->channel != NULL) - { - g_signal_handlers_disconnect_by_func (priv->channel, - tp_chat_invalidated_cb, self); - g_object_unref (priv->channel); - priv->channel = NULL; + /* This is an MSN-like chat where anyone can join the chat at anytime. + * If there is only one non-self contact member, we are in a private + * chat and we set the "remote-contact" property to that contact. If + * there are more, set the "remote-contact" property to NULL and the + * UI will display a contact list. */ + self_handle = tp_channel_group_get_self_handle (priv->channel); + for (l = priv->members; l; l = l->next) { + /* Skip self contact if member */ + if (empathy_contact_get_handle (l->data) == self_handle) { + continue; } - if (priv->remote_contact != NULL) - g_object_unref (priv->remote_contact); + /* We have more than one remote contact, break */ + if (contact != NULL) { + contact = NULL; + break; + } - priv->remote_contact = NULL; + /* If we didn't find yet a remote contact, keep this one */ + contact = l->data; + } - if (priv->group != NULL) - g_object_unref (priv->group); - priv->group = NULL; + if (priv->remote_contact == contact) { + return; + } - if (priv->factory != NULL) - g_object_unref (priv->factory); - priv->factory = NULL; + DEBUG ("Changing remote contact from %p to %p", + priv->remote_contact, contact); - if (priv->user != NULL); - g_object_unref (priv->user); - priv->user = NULL; + if (priv->remote_contact) { + g_object_unref (priv->remote_contact); + } - if (priv->account != NULL); - g_object_unref (priv->account); - priv->account = NULL; + priv->remote_contact = contact ? g_object_ref (contact) : NULL; + g_object_notify (G_OBJECT (chat), "remote-contact"); +} - if (priv->contact_monitor) - g_object_unref (priv->contact_monitor); - priv->contact_monitor = NULL; +static void +tp_chat_got_added_contacts_cb (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + guint i; + const TpIntSet *members; + TpHandle handle; + EmpathyContact *contact; - if (!g_queue_is_empty (priv->messages_queue)) { - EmpathyMessage *message; - EmpathyContact *contact; + if (error) { + DEBUG ("Error: %s", error->message); + return; + } - message = g_queue_peek_head (priv->messages_queue); - contact = empathy_message_get_sender (message); - g_signal_handlers_disconnect_by_func (contact, - tp_chat_sender_ready_notify_cb, object); + members = tp_channel_group_get_members (priv->channel); + for (i = 0; i < n_contacts; i++) { + contact = contacts[i]; + handle = empathy_contact_get_handle (contact); + + /* Make sure the contact is still member */ + if (tp_intset_is_member (members, handle)) { + priv->members = g_list_prepend (priv->members, + g_object_ref (contact)); + g_signal_emit_by_name (chat, "members-changed", + contact, NULL, 0, NULL, FALSE); + } } - g_list_foreach (priv->messages_queue->head, - (GFunc) g_object_unref, NULL); + tp_chat_update_remote_contact (EMPATHY_TP_CHAT (chat)); + tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat)); +} - g_list_foreach (priv->pending_messages_queue->head, - (GFunc) g_object_unref, NULL); +static void +tp_chat_group_members_changed_cb (TpChannel *self, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpChat *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + EmpathyContact *contact; + TpHandle handle; + guint i; + GList *l; - if (G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose) - G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose (object); + /* Remove contacts that are not members anymore */ + for (i = 0; i < removed->len; i++) { + for (l = priv->members; l; l = l->next) { + contact = l->data; + handle = empathy_contact_get_handle (contact); + if (handle == g_array_index (removed, TpHandle, i)) { + priv->members = g_list_delete_link (priv->members, l); + g_signal_emit_by_name (chat, "members-changed", + contact, NULL, reason, + message, FALSE); + g_object_unref (contact); + break; + } + } + } + + /* Request added contacts */ + if (added->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + added->len, (TpHandle*) added->data, + tp_chat_got_added_contacts_cb, NULL, NULL, + G_OBJECT (chat)); + } + + tp_chat_update_remote_contact (chat); } static void -tp_chat_finalize (GObject *object) +tp_chat_got_remote_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *chat) { - EmpathyTpChatPriv *priv = GET_PRIV (object); - guint i; + EmpathyTpChatPriv *priv = GET_PRIV (chat); - DEBUG ("Finalize: %p", object); + if (error) { + DEBUG ("Error: %s", error->message); + empathy_tp_chat_close (EMPATHY_TP_CHAT (chat)); + return; + } - if (priv->properties) { - for (i = 0; i < priv->properties->len; i++) { - TpChatProperty *property; + priv->remote_contact = g_object_ref (contact); + g_object_notify (chat, "remote-contact"); - property = g_ptr_array_index (priv->properties, i); - g_free (property->name); - if (property->value) { - tp_g_value_slice_free (property->value); - } - g_slice_free (TpChatProperty, property); - } - g_ptr_array_free (priv->properties, TRUE); - } + tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat)); +} - g_queue_free (priv->messages_queue); - g_queue_free (priv->pending_messages_queue); +static void +tp_chat_got_self_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); - G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object); + if (error) { + DEBUG ("Error: %s", error->message); + empathy_tp_chat_close (EMPATHY_TP_CHAT (chat)); + return; + } + + priv->user = g_object_ref (contact); + empathy_contact_set_is_user (priv->user, TRUE); + tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat)); } static GObject * @@ -1013,26 +967,67 @@ tp_chat_constructor (GType type, { GObject *chat; EmpathyTpChatPriv *priv; - gboolean channel_ready; + TpConnection *connection; + TpHandle handle; chat = G_OBJECT_CLASS (empathy_tp_chat_parent_class)->constructor (type, n_props, props); priv = GET_PRIV (chat); - priv->account = empathy_channel_get_account (priv->channel); - priv->factory = empathy_contact_factory_dup_singleton (); - priv->user = empathy_contact_factory_get_user (priv->factory, priv->account); + connection = tp_channel_borrow_connection (priv->channel); + priv->factory = empathy_tp_contact_factory_dup_singleton (connection); g_signal_connect (priv->channel, "invalidated", G_CALLBACK (tp_chat_invalidated_cb), chat); - g_object_get (priv->channel, "channel-ready", &channel_ready, NULL); - if (channel_ready) { - tp_chat_channel_ready_cb (EMPATHY_TP_CHAT (chat)); + if (tp_proxy_has_interface_by_id (priv->channel, + TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) { + const TpIntSet *members; + GArray *handles; + + /* Get self contact from the group's self handle */ + handle = tp_channel_group_get_self_handle (priv->channel); + empathy_tp_contact_factory_get_from_handle (priv->factory, + handle, tp_chat_got_self_contact_cb, + NULL, NULL, chat); + + /* Get initial member contacts */ + members = tp_channel_group_get_members (priv->channel); + handles = tp_intset_to_array (members); + empathy_tp_contact_factory_get_from_handles (priv->factory, + handles->len, (TpHandle*) handles->data, + tp_chat_got_added_contacts_cb, NULL, NULL, chat); + + g_signal_connect (priv->channel, "group-members-changed", + G_CALLBACK (tp_chat_group_members_changed_cb), chat); } else { - g_signal_connect_swapped (priv->channel, "notify::channel-ready", - G_CALLBACK (tp_chat_channel_ready_cb), - chat); + /* Get the self contact from the connection's self handle */ + handle = tp_connection_get_self_handle (connection); + empathy_tp_contact_factory_get_from_handle (priv->factory, + handle, tp_chat_got_self_contact_cb, + NULL, NULL, chat); + + /* Get the remote contact */ + handle = tp_channel_get_handle (priv->channel, NULL); + empathy_tp_contact_factory_get_from_handle (priv->factory, + handle, tp_chat_got_remote_contact_cb, + NULL, NULL, chat); + } + + if (tp_proxy_has_interface_by_id (priv->channel, + TP_IFACE_QUARK_PROPERTIES_INTERFACE)) { + tp_cli_properties_interface_call_list_properties (priv->channel, -1, + tp_chat_list_properties_cb, + NULL, NULL, + G_OBJECT (chat)); + tp_cli_properties_interface_connect_to_properties_changed (priv->channel, + tp_chat_properties_changed_cb, + NULL, NULL, + G_OBJECT (chat), NULL); + tp_cli_properties_interface_connect_to_property_flags_changed (priv->channel, + tp_chat_property_flags_changed_cb, + NULL, NULL, + G_OBJECT (chat), NULL); } return chat; @@ -1107,6 +1102,7 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass) "The remote contact if there is no group iface on the channel", EMPATHY_TYPE_CONTACT, G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_READY, g_param_spec_boolean ("ready", @@ -1203,17 +1199,9 @@ empathy_tp_chat_close (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); /* If there are still messages left, it'll come back.. - We loose the ordering of sent messages though */ - g_signal_handlers_disconnect_by_func (priv->channel, - tp_chat_invalidated_cb, chat); - + * We loose the ordering of sent messages though */ tp_cli_channel_call_close (priv->channel, -1, tp_chat_async_cb, "closing channel", NULL, NULL); - - g_object_unref (priv->channel); - priv->channel = NULL; - - g_signal_emit (chat, signals[DESTROY], 0); } const gchar * @@ -1222,7 +1210,6 @@ empathy_tp_chat_get_id (EmpathyTpChat *chat) EmpathyTpChatPriv *priv = GET_PRIV (chat); g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); - g_return_val_if_fail (priv->ready, NULL); return tp_channel_get_identifier (priv->channel); } @@ -1233,28 +1220,29 @@ empathy_tp_chat_get_remote_contact (EmpathyTpChat *chat) EmpathyTpChatPriv *priv = GET_PRIV (chat); g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); + g_return_val_if_fail (priv->ready, NULL); return priv->remote_contact; } -McAccount * -empathy_tp_chat_get_account (EmpathyTpChat *chat) +TpChannel * +empathy_tp_chat_get_channel (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); - g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), FALSE); + g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); - return priv->account; + return priv->channel; } -TpChannel * -empathy_tp_chat_get_channel (EmpathyTpChat *chat) +TpConnection * +empathy_tp_chat_get_connection (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); - return priv->channel; + return tp_channel_borrow_connection (priv->channel); } gboolean @@ -1267,16 +1255,6 @@ empathy_tp_chat_is_ready (EmpathyTpChat *chat) return priv->ready; } -guint -empathy_tp_chat_get_members_count (EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - - g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), 0); - - return priv->members_count; -} - void empathy_tp_chat_send (EmpathyTpChat *chat, EmpathyMessage *message) @@ -1326,6 +1304,9 @@ empathy_tp_chat_get_pending_messages (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); + g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); + g_return_val_if_fail (priv->ready, NULL); + return priv->pending_messages_queue->head; } @@ -1346,6 +1327,9 @@ empathy_tp_chat_acknowledge_message (EmpathyTpChat *chat, GList *m; guint id; + g_return_if_fail (EMPATHY_IS_TP_CHAT (chat)); + g_return_if_fail (priv->ready); + if (empathy_message_get_sender (message) == priv->user) goto out; @@ -1373,6 +1357,9 @@ empathy_tp_chat_acknowledge_messages (EmpathyTpChat *chat, guint length; GArray *message_ids; + g_return_if_fail (EMPATHY_IS_TP_CHAT (chat)); + g_return_if_fail (priv->ready); + length = g_list_length ((GList *)messages); if (length == 0) @@ -1402,3 +1389,4 @@ empathy_tp_chat_acknowledge_messages (EmpathyTpChat *chat, g_array_free (message_ids, TRUE); g_list_free (msgs); } + diff --git a/libempathy/empathy-tp-chat.h b/libempathy/empathy-tp-chat.h index 353052923..fadc5f636 100644 --- a/libempathy/empathy-tp-chat.h +++ b/libempathy/empathy-tp-chat.h @@ -57,10 +57,9 @@ EmpathyTpChat *empathy_tp_chat_new (TpChannel *channel void empathy_tp_chat_close (EmpathyTpChat *chat); const gchar * empathy_tp_chat_get_id (EmpathyTpChat *chat); EmpathyContact*empathy_tp_chat_get_remote_contact (EmpathyTpChat *chat); -McAccount * empathy_tp_chat_get_account (EmpathyTpChat *chat); TpChannel * empathy_tp_chat_get_channel (EmpathyTpChat *chat); +TpConnection * empathy_tp_chat_get_connection (EmpathyTpChat *chat); gboolean empathy_tp_chat_is_ready (EmpathyTpChat *chat); -guint empathy_tp_chat_get_members_count (EmpathyTpChat *chat); void empathy_tp_chat_send (EmpathyTpChat *chat, EmpathyMessage *message); void empathy_tp_chat_set_state (EmpathyTpChat *chat, diff --git a/libempathy/empathy-tp-contact-factory.c b/libempathy/empathy-tp-contact-factory.c index f72cc77d1..7735b0f1a 100644 --- a/libempathy/empathy-tp-contact-factory.c +++ b/libempathy/empathy-tp-contact-factory.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,28 +24,20 @@ #include <string.h> #include <telepathy-glib/util.h> -#include <telepathy-glib/connection.h> #include <telepathy-glib/gtypes.h> -#include <libmissioncontrol/mission-control.h> #include <extensions/extensions.h> #include "empathy-tp-contact-factory.h" #include "empathy-utils.h" -#include "empathy-account-manager.h" #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT #include "empathy-debug.h" #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpContactFactory) typedef struct { - EmpathyAccountManager *account_manager; - McAccount *account; TpConnection *connection; - gboolean ready; - GList *contacts; - EmpathyContact *user; gchar **avatar_mime_types; guint avatar_min_width; @@ -53,15 +45,14 @@ typedef struct { guint avatar_max_width; guint avatar_max_height; guint avatar_max_size; - gboolean can_request_ft; + gboolean can_request_ft; } EmpathyTpContactFactoryPriv; G_DEFINE_TYPE (EmpathyTpContactFactory, empathy_tp_contact_factory, G_TYPE_OBJECT); enum { PROP_0, - PROP_ACCOUNT, - PROP_READY, + PROP_CONNECTION, PROP_MIME_TYPES, PROP_MIN_WIDTH, @@ -71,6 +62,11 @@ enum { PROP_MAX_SIZE }; +static TpContactFeature contact_features[] = { + TP_CONTACT_FEATURE_ALIAS, + TP_CONTACT_FEATURE_PRESENCE, +}; + static EmpathyContact * tp_contact_factory_find_by_handle (EmpathyTpContactFactory *tp_factory, guint handle) @@ -88,14 +84,14 @@ tp_contact_factory_find_by_handle (EmpathyTpContactFactory *tp_factory, } static EmpathyContact * -tp_contact_factory_find_by_id (EmpathyTpContactFactory *tp_factory, - const gchar *id) +tp_contact_factory_find_by_tp_contact (EmpathyTpContactFactory *tp_factory, + TpContact *tp_contact) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); GList *l; for (l = priv->contacts; l; l = l->next) { - if (!tp_strdiff (empathy_contact_get_id (l->data), id)) { + if (empathy_contact_get_tp_contact (l->data) == tp_contact) { return l->data; } } @@ -115,196 +111,13 @@ tp_contact_factory_weak_notify (gpointer data, } static void -tp_contact_factory_presences_table_foreach (const gchar *state_str, - GHashTable *presences_table, - EmpathyContact *contact) -{ - const GValue *message; - const gchar *message_str = NULL; - - empathy_contact_set_presence (contact, - empathy_presence_from_str (state_str)); - - message = g_hash_table_lookup (presences_table, "message"); - if (message) { - message_str = g_value_get_string (message); - } - - if (!EMP_STR_EMPTY (message_str)) { - empathy_contact_set_presence_message (contact, message_str); - } else { - empathy_contact_set_presence_message (contact, NULL); - } -} - -static void -tp_contact_factory_parse_presence_foreach (guint handle, - GValueArray *presence_struct, - EmpathyTpContactFactory *tp_factory) -{ - GHashTable *presences_table; - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle (tp_factory, handle); - if (!contact) { - return; - } - - presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1)); - - g_hash_table_foreach (presences_table, - (GHFunc) tp_contact_factory_presences_table_foreach, - contact); - - DEBUG ("Changing presence for contact %s (%d) to '%s' (%d)", - empathy_contact_get_id (contact), - handle, - empathy_contact_get_presence_message (contact), - empathy_contact_get_presence (contact)); -} - -static void -tp_contact_factory_get_presence_cb (TpConnection *connection, - GHashTable *handle_table, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - if (error) { - DEBUG ("Error getting presence: %s", error->message); - if (error->domain == TP_DBUS_ERRORS && - error->code == TP_DBUS_ERROR_NO_INTERFACE) { - guint *handles = user_data; - - /* We have no presence iface, set default presence - * to available */ - while (*handles != 0) { - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle ( - (EmpathyTpContactFactory*) tp_factory, - *handles); - if (contact) { - empathy_contact_set_presence (contact, - MC_PRESENCE_AVAILABLE); - } - - handles++; - } - } - - return; - } - - g_hash_table_foreach (handle_table, - (GHFunc) tp_contact_factory_parse_presence_foreach, - EMPATHY_TP_CONTACT_FACTORY (tp_factory)); -} - -static void -tp_contact_factory_presence_update_cb (TpConnection *connection, - GHashTable *handle_table, - gpointer user_data, - GObject *tp_factory) -{ - g_hash_table_foreach (handle_table, - (GHFunc) tp_contact_factory_parse_presence_foreach, - EMPATHY_TP_CONTACT_FACTORY (tp_factory)); -} - -static void tp_contact_factory_set_aliases_cb (TpConnection *connection, const GError *error, gpointer user_data, GObject *tp_factory) { if (error) { - DEBUG ("Error setting alias: %s", error->message); - } -} - -static void -tp_contact_factory_request_aliases_cb (TpConnection *connection, - const gchar **contact_names, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - guint *handles = user_data; - guint i = 0; - const gchar **name; - - if (error) { - DEBUG ("Error requesting aliases: %s", error->message); - - /* If we failed to get alias set it to NULL, like that if - * someone is waiting for the name to be ready it won't wait - * infinitely */ - while (*handles != 0) { - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle ( - (EmpathyTpContactFactory*) tp_factory, - *handles); - if (contact) { - empathy_contact_set_name (contact, NULL); - } - - handles++; - } - return; - } - - for (name = contact_names; *name; name++) { - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle (EMPATHY_TP_CONTACT_FACTORY (tp_factory), - handles[i]); - if (!contact) { - continue; - } - - DEBUG ("Renaming contact %s (%d) to %s (request cb)", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - *name); - - empathy_contact_set_name (contact, *name); - - i++; - } -} - -static void -tp_contact_factory_aliases_changed_cb (TpConnection *connection, - const GPtrArray *renamed_handlers, - gpointer user_data, - GObject *weak_object) -{ - EmpathyTpContactFactory *tp_factory = EMPATHY_TP_CONTACT_FACTORY (weak_object); - guint i; - - for (i = 0; renamed_handlers->len > i; i++) { - guint handle; - const gchar *alias; - GValueArray *renamed_struct; - EmpathyContact *contact; - - renamed_struct = g_ptr_array_index (renamed_handlers, i); - handle = g_value_get_uint (g_value_array_get_nth (renamed_struct, 0)); - alias = g_value_get_string (g_value_array_get_nth (renamed_struct, 1)); - contact = tp_contact_factory_find_by_handle (tp_factory, handle); - - if (!contact) { - /* We don't know this contact, skip */ - continue; - } - - DEBUG ("Renaming contact %s (%d) to %s (changed cb)", - empathy_contact_get_id (contact), - handle, alias); - - empathy_contact_set_name (contact, alias); + DEBUG ("Error: %s", error->message); } } @@ -316,7 +129,7 @@ tp_contact_factory_set_avatar_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error setting avatar: %s", error->message); + DEBUG ("Error: %s", error->message); } } @@ -327,7 +140,7 @@ tp_contact_factory_clear_avatar_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error clearing avatar: %s", error->message); + DEBUG ("Error: %s", error->message); } } @@ -366,7 +179,7 @@ tp_contact_factory_request_avatars_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error requesting avatars: %s", error->message); + DEBUG ("Error: %s", error->message); } } @@ -426,20 +239,19 @@ tp_contact_factory_avatar_tokens_foreach (gpointer key, } static void -tp_contact_factory_get_known_avatar_tokens_cb (TpConnection *connection, - GHashTable *tokens, - const GError *error, - gpointer user_data, - GObject *tp_factory) +tp_contact_factory_got_known_avatar_tokens (EmpathyTpContactFactory *tp_factory, + GHashTable *tokens, + const GError *error) { + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); TokensData data; if (error) { - DEBUG ("Error getting known avatars tokens: %s", error->message); + DEBUG ("Error: %s", error->message); return; } - data.tp_factory = EMPATHY_TP_CONTACT_FACTORY (tp_factory); + data.tp_factory = tp_factory; data.handles = g_array_new (FALSE, FALSE, sizeof (guint)); g_hash_table_foreach (tokens, tp_contact_factory_avatar_tokens_foreach, @@ -450,15 +262,16 @@ tp_contact_factory_get_known_avatar_tokens_cb (TpConnection *connection, /* Request needed avatars */ if (data.handles->len > 0) { - tp_cli_connection_interface_avatars_call_request_avatars (connection, + tp_cli_connection_interface_avatars_call_request_avatars (priv->connection, -1, data.handles, tp_contact_factory_request_avatars_cb, NULL, NULL, - tp_factory); + G_OBJECT (tp_factory)); } g_array_free (data.handles, TRUE); + g_hash_table_destroy (tokens); } static void @@ -528,17 +341,14 @@ tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory, } static void -tp_contact_factory_get_capabilities_cb (TpConnection *connection, - const GPtrArray *capabilities, - const GError *error, - gpointer user_data, - GObject *weak_object) +tp_contact_factory_got_capabilities (EmpathyTpContactFactory *tp_factory, + GPtrArray *capabilities, + const GError *error) { - EmpathyTpContactFactory *tp_factory = EMPATHY_TP_CONTACT_FACTORY (weak_object); - guint i; + guint i; if (error) { - DEBUG ("Error getting capabilities: %s", error->message); + DEBUG ("Error: %s", error->message); /* FIXME Should set the capabilities of the contacts for which this request * originated to NONE */ return; @@ -562,7 +372,11 @@ tp_contact_factory_get_capabilities_cb (TpConnection *connection, channel_type, generic, specific); + + g_value_array_free (values); } + + g_ptr_array_free (capabilities, TRUE); } static void @@ -596,231 +410,6 @@ tp_contact_factory_capabilities_changed_cb (TpConnection *connection, } static void -tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory, - const GArray *handles) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - guint *dup_handles; - - g_return_if_fail (priv->ready); - - dup_handles = g_malloc0 ((handles->len + 1) * sizeof (guint)); - g_memmove (dup_handles, handles->data, handles->len * sizeof (guint)); - tp_cli_connection_interface_presence_call_get_presence (priv->connection, - -1, - handles, - tp_contact_factory_get_presence_cb, - dup_handles, g_free, - G_OBJECT (tp_factory)); - - /* FIXME: Sometimes the dbus call timesout because CM takes - * too much time to request all aliases from the server, - * that's why we increase the timeout here. See fd.o bug #14795 */ - dup_handles = g_malloc0 ((handles->len + 1) * sizeof (guint)); - g_memmove (dup_handles, handles->data, handles->len * sizeof (guint)); - tp_cli_connection_interface_aliasing_call_request_aliases (priv->connection, - 5*60*1000, - handles, - tp_contact_factory_request_aliases_cb, - dup_handles, g_free, - G_OBJECT (tp_factory)); - - tp_cli_connection_interface_avatars_call_get_known_avatar_tokens (priv->connection, - -1, - handles, - tp_contact_factory_get_known_avatar_tokens_cb, - NULL, NULL, - G_OBJECT (tp_factory)); - - tp_cli_connection_interface_capabilities_call_get_capabilities (priv->connection, - -1, - handles, - tp_contact_factory_get_capabilities_cb, - NULL, NULL, - G_OBJECT (tp_factory)); -} - -static void -tp_contact_factory_list_free (gpointer data) -{ - GList *l = data; - - g_list_foreach (l, (GFunc) g_object_unref, NULL); - g_list_free (l); -} - -static void -tp_contact_factory_request_handles_cb (TpConnection *connection, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - GList *contacts = user_data; - GList *l; - guint i = 0; - - if (error) { - DEBUG ("Failed to request handles: %s", error->message); - return; - } - - for (l = contacts; l; l = l->next) { - guint handle; - - handle = g_array_index (handles, guint, i); - empathy_contact_set_handle (l->data, handle); - - i++; - } - - tp_contact_factory_request_everything (EMPATHY_TP_CONTACT_FACTORY (tp_factory), - handles); -} - -static void -tp_contact_factory_inspect_handles_cb (TpConnection *connection, - const gchar **ids, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - const gchar **id; - GList *contacts = user_data; - GList *l; - - if (error) { - DEBUG ("Failed to inspect handles: %s", error->message); - return; - } - - id = ids; - for (l = contacts; l; l = l->next) { - empathy_contact_set_id (l->data, *id); - id++; - } -} - -static void -tp_contact_factory_disconnect_contact_foreach (gpointer data, - gpointer user_data) -{ - EmpathyContact *contact = data; - - empathy_contact_set_presence (contact, MC_PRESENCE_UNSET); - empathy_contact_set_handle (contact, 0); -} - -static void -tp_contact_factory_connection_invalidated_cb (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - - DEBUG ("Connection invalidated"); - - g_object_unref (priv->connection); - priv->connection = NULL; - priv->ready = FALSE; - g_object_notify (G_OBJECT (tp_factory), "ready"); - - - g_list_foreach (priv->contacts, - tp_contact_factory_disconnect_contact_foreach, - tp_factory); -} - -static void -tp_contact_factory_ready (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - GList *l; - GArray *handle_needed; - GArray *id_needed; - GList *handle_needed_contacts = NULL; - GList *id_needed_contacts = NULL; - - DEBUG ("Connection ready"); - - priv->ready = TRUE; - g_object_notify (G_OBJECT (tp_factory), "ready"); - - /* Connect signals */ - tp_cli_connection_interface_aliasing_connect_to_aliases_changed (priv->connection, - tp_contact_factory_aliases_changed_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_avatars_connect_to_avatar_updated (priv->connection, - tp_contact_factory_avatar_updated_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_avatars_connect_to_avatar_retrieved (priv->connection, - tp_contact_factory_avatar_retrieved_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_presence_connect_to_presence_update (priv->connection, - tp_contact_factory_presence_update_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_capabilities_connect_to_capabilities_changed (priv->connection, - tp_contact_factory_capabilities_changed_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - - /* Request needed info for all existing contacts */ - handle_needed = g_array_new (TRUE, FALSE, sizeof (gchar*)); - id_needed = g_array_new (FALSE, FALSE, sizeof (guint)); - for (l = priv->contacts; l; l = l->next) { - EmpathyContact *contact; - guint handle; - const gchar *id; - - contact = l->data; - handle = empathy_contact_get_handle (contact); - id = empathy_contact_get_id (contact); - if (handle == 0) { - g_assert (!EMP_STR_EMPTY (id)); - g_array_append_val (handle_needed, id); - handle_needed_contacts = g_list_prepend (handle_needed_contacts, - g_object_ref (contact)); - } - if (EMP_STR_EMPTY (id)) { - g_array_append_val (id_needed, handle); - id_needed_contacts = g_list_prepend (id_needed_contacts, - g_object_ref (contact)); - } - } - handle_needed_contacts = g_list_reverse (handle_needed_contacts); - id_needed_contacts = g_list_reverse (id_needed_contacts); - - tp_cli_connection_call_request_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - (const gchar**) handle_needed->data, - tp_contact_factory_request_handles_cb, - handle_needed_contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - - tp_cli_connection_call_inspect_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - id_needed, - tp_contact_factory_inspect_handles_cb, - id_needed_contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - - tp_contact_factory_request_everything ((EmpathyTpContactFactory*) tp_factory, - id_needed); - - g_array_free (handle_needed, TRUE); - g_array_free (id_needed, TRUE); -} - -static void get_requestable_channel_classes_cb (TpProxy *connection, const GValue *value, const GError *error, @@ -834,7 +423,6 @@ get_requestable_channel_classes_cb (TpProxy *connection, if (error != NULL) { DEBUG ("Error: %s", error->message); - tp_contact_factory_ready (self); return; } @@ -877,8 +465,6 @@ get_requestable_channel_classes_cb (TpProxy *connection, } break; } - - tp_contact_factory_ready (self); } static void @@ -909,303 +495,377 @@ tp_contact_factory_got_avatar_requirements_cb (TpConnection *proxy, priv->avatar_max_height = max_height; priv->avatar_max_size = max_size; } - - /* Can we request file transfer channels? */ - tp_cli_dbus_properties_call_get (priv->connection, -1, - TP_IFACE_CONNECTION_INTERFACE_REQUESTS, - "RequestableChannelClasses", - get_requestable_channel_classes_cb, NULL, NULL, - G_OBJECT (tp_factory)); } static void -tp_contact_factory_got_self_handle_cb (TpConnection *proxy, - guint handle, - const GError *error, - gpointer user_data, - GObject *tp_factory) +tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory, + EmpathyContact *contact) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + TpHandle self_handle; + TpHandle handle; + GArray handles = {(gchar*) &handle, 1}; + GHashTable *tokens; + GPtrArray *capabilities; + GError *error = NULL; + + /* Keep a weak ref to that contact */ + g_object_weak_ref (G_OBJECT (contact), + tp_contact_factory_weak_notify, + tp_factory); + priv->contacts = g_list_prepend (priv->contacts, contact); - if (error) { - DEBUG ("Failed to get self handles: %s", error->message); - return; + /* The contact keeps a ref to its factory */ + g_object_set_data_full (G_OBJECT (contact), "empathy-factory", + g_object_ref (tp_factory), + g_object_unref); + + /* Set the FT capability */ + if (priv->can_request_ft) { + EmpathyCapabilities caps; + + caps = empathy_contact_get_capabilities (contact); + caps |= EMPATHY_CAPABILITIES_FT; + + empathy_contact_set_capabilities (contact, caps); } - empathy_contact_set_handle (priv->user, handle); + /* Set is-user property. Note that it could still be the handle is + * different from the connection's self handle, in the case the handle + * comes from a group interface. */ + self_handle = tp_connection_get_self_handle (priv->connection); + handle = empathy_contact_get_handle (contact); + empathy_contact_set_is_user (contact, self_handle == handle); + + /* FIXME: This should be done by TpContact */ + tp_cli_connection_interface_avatars_run_get_known_avatar_tokens (priv->connection, + -1, + &handles, + &tokens, + &error, + NULL); + tp_contact_factory_got_known_avatar_tokens (tp_factory, tokens, error); + g_clear_error (&error); + + tp_cli_connection_interface_capabilities_run_get_capabilities (priv->connection, + -1, + &handles, + &capabilities, + &error, + NULL); + tp_contact_factory_got_capabilities (tp_factory, capabilities, error); + g_clear_error (&error); - /* Get avatar requirements for this connection */ - tp_cli_connection_interface_avatars_call_get_avatar_requirements ( - priv->connection, - -1, - tp_contact_factory_got_avatar_requirements_cb, - NULL, NULL, - tp_factory); + DEBUG ("Contact added: %s (%d)", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact)); } -static void -tp_contact_factory_connection_ready_cb (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); +typedef union { + EmpathyTpContactFactoryContactsByIdCb ids_cb; + EmpathyTpContactFactoryContactsByHandleCb handles_cb; + EmpathyTpContactFactoryContactCb contact_cb; +} GetContactsCb; - /* Get our own handle */ - tp_cli_connection_call_get_self_handle (priv->connection, - -1, - tp_contact_factory_got_self_handle_cb, - NULL, NULL, - G_OBJECT (tp_factory)); -} +typedef struct { + EmpathyTpContactFactory *tp_factory; + GetContactsCb callback; + gpointer user_data; + GDestroyNotify destroy; +} GetContactsData; static void -tp_contact_factory_status_updated (EmpathyTpContactFactory *tp_factory) +get_contacts_data_free (gpointer user_data) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - gboolean connection_ready; - MissionControl *mc; + GetContactsData *data = user_data; - if (priv->connection) { - /* We already have our connection object */ - return; + if (data->destroy) { + data->destroy (data->user_data); } + g_object_unref (data->tp_factory); - mc = empathy_mission_control_dup_singleton (); - priv->connection = mission_control_get_tpconnection (mc, priv->account, NULL); - if (!priv->connection) { - return; - } + g_slice_free (GetContactsData, data); +} - /* We got a new connection, wait for it to be ready */ - g_signal_connect_swapped (priv->connection, "invalidated", - G_CALLBACK (tp_contact_factory_connection_invalidated_cb), - tp_factory); +static EmpathyContact * +dup_contact_for_tp_contact (EmpathyTpContactFactory *tp_factory, + TpContact *tp_contact) +{ + EmpathyContact *contact; + + contact = tp_contact_factory_find_by_tp_contact (tp_factory, + tp_contact); - g_object_get (priv->connection, "connection-ready", &connection_ready, NULL); - if (connection_ready) { - tp_contact_factory_connection_ready_cb (tp_factory); + if (contact != NULL) { + g_object_ref (contact); } else { - g_signal_connect_swapped (priv->connection, "notify::connection-ready", - G_CALLBACK (tp_contact_factory_connection_ready_cb), - tp_factory); + contact = empathy_contact_new (tp_contact); + tp_contact_factory_add_contact (tp_factory, contact); } - g_object_unref (mc); + return contact; } -static void -tp_contact_factory_account_connection_cb (EmpathyAccountManager *account_manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus current, - TpConnectionStatus previous, - EmpathyTpContactFactory *tp_factory) +static EmpathyContact ** +contacts_array_new (EmpathyTpContactFactory *tp_factory, + guint n_contacts, + TpContact * const * contacts) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + EmpathyContact **ret; + guint i; - if (account && empathy_account_equal (account, priv->account)) { - tp_contact_factory_status_updated (tp_factory); + ret = g_new0 (EmpathyContact *, n_contacts); + for (i = 0; i < n_contacts; i++) { + ret[i] = dup_contact_for_tp_contact (tp_factory, contacts[i]); } + + return ret; } static void -tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory, - EmpathyContact *contact) +contacts_array_free (guint n_contacts, + EmpathyContact **contacts) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - - g_object_weak_ref (G_OBJECT (contact), - tp_contact_factory_weak_notify, - tp_factory); - priv->contacts = g_list_prepend (priv->contacts, contact); + guint i; - DEBUG ("Contact added: %s (%d)", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact)); + for (i = 0; i < n_contacts; i++) { + g_object_unref (contacts[i]); + } + g_free (contacts); } static void -tp_contact_factory_hold_handles_cb (TpConnection *connection, - const GError *error, - gpointer userdata, - GObject *tp_factory) +get_contacts_by_id_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + const gchar * const *requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object) { - if (error) { - DEBUG ("Failed to hold handles: %s", error->message); + GetContactsData *data = user_data; + EmpathyContact **empathy_contacts; + + empathy_contacts = contacts_array_new (data->tp_factory, + n_contacts, contacts); + if (data->callback.ids_cb) { + data->callback.ids_cb (data->tp_factory, + n_contacts, empathy_contacts, + requested_ids, + failed_id_errors, + error, + data->user_data, weak_object); } + + contacts_array_free (n_contacts, empathy_contacts); } -EmpathyContact * -empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory) +void +empathy_tp_contact_factory_get_from_ids (EmpathyTpContactFactory *tp_factory, + guint n_ids, + const gchar * const *ids, + EmpathyTpContactFactoryContactsByIdCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GetContactsData *data; - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - - return g_object_ref (priv->user); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (ids != NULL); + + data = g_slice_new (GetContactsData); + data->callback.ids_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_id (priv->connection, + n_ids, ids, + G_N_ELEMENTS (contact_features), + contact_features, + get_contacts_by_id_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } static void -contact_created (EmpathyTpContactFactory *self, - EmpathyContact *contact) +get_contact_by_id_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + const gchar * const *requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (self); - - if (priv->can_request_ft) - { - /* Set the FT capability */ - /* FIXME: We should use the futur ContactCapabilities interface */ - EmpathyCapabilities caps; - - caps = empathy_contact_get_capabilities (contact); - caps |= EMPATHY_CAPABILITIES_FT; + GetContactsData *data = user_data; + EmpathyContact *contact = NULL; - empathy_contact_set_capabilities (contact, caps); - } + if (n_contacts == 1) { + contact = dup_contact_for_tp_contact (data->tp_factory, + contacts[0]); + } + else if (error == NULL) { + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, failed_id_errors); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + if (value) { + error = value; + break; + } + } + } - tp_contact_factory_add_contact (self, contact); + if (data->callback.contact_cb) { + data->callback.contact_cb (data->tp_factory, + contact, + error, + data->user_data, weak_object); + } } -EmpathyContact * +void empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, - const gchar *id) + const gchar *id, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - EmpathyContact *contact; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - g_return_val_if_fail (id != NULL, NULL); - - /* Check if the contact already exists */ - contact = tp_contact_factory_find_by_id (tp_factory, id); - if (contact) { - return g_object_ref (contact); - } - - /* Create new contact */ - contact = g_object_new (EMPATHY_TYPE_CONTACT, - "account", priv->account, - "id", id, - NULL); - contact_created (tp_factory, contact); - - if (priv->ready) { - const gchar *contact_ids[] = {id, NULL}; - GList *contacts; - - contacts = g_list_prepend (NULL, g_object_ref (contact)); - tp_cli_connection_call_request_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - contact_ids, - tp_contact_factory_request_handles_cb, - contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - } + GetContactsData *data; - return contact; + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (id != NULL); + + data = g_slice_new (GetContactsData); + data->callback.contact_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_id (priv->connection, + 1, &id, + G_N_ELEMENTS (contact_features), + contact_features, + get_contact_by_id_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } -EmpathyContact * -empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, - guint handle) +static void +get_contacts_by_handle_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object) { - EmpathyContact *contact; - GArray *handles; - GList *contacts; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, handle); - - contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles); - g_array_free (handles, TRUE); - - contact = contacts ? contacts->data : NULL; - g_list_free (contacts); + GetContactsData *data = user_data; + EmpathyContact **empathy_contacts; + + empathy_contacts = contacts_array_new (data->tp_factory, + n_contacts, contacts); + if (data->callback.handles_cb) { + data->callback.handles_cb (data->tp_factory, + n_contacts, empathy_contacts, + n_failed, failed, + error, + data->user_data, weak_object); + } - return contact; + contacts_array_free (n_contacts, empathy_contacts); } -GList * +void empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, - const GArray *handles) + guint n_handles, + const TpHandle *handles, + EmpathyTpContactFactoryContactsByHandleCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - GList *contacts = NULL; - GArray *new_handles; - GList *new_contacts = NULL; - guint i; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - g_return_val_if_fail (handles != NULL, NULL); + GetContactsData *data; - /* Search all contacts we already have */ - new_handles = g_array_new (FALSE, FALSE, sizeof (guint)); - for (i = 0; i < handles->len; i++) { - EmpathyContact *contact; - guint handle; + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (handles != NULL); + + data = g_slice_new (GetContactsData); + data->callback.handles_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_handle (priv->connection, + n_handles, handles, + G_N_ELEMENTS (contact_features), + contact_features, + get_contacts_by_handle_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); +} - handle = g_array_index (handles, guint, i); - if (handle == 0) { - continue; - } +static void +get_contact_by_handle_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + GetContactsData *data = user_data; + EmpathyContact *contact = NULL; - contact = tp_contact_factory_find_by_handle (tp_factory, handle); - if (contact) { - contacts = g_list_prepend (contacts, g_object_ref (contact)); - } else { - g_array_append_val (new_handles, handle); - } + if (n_contacts == 1) { + contact = dup_contact_for_tp_contact (data->tp_factory, + contacts[0]); } - if (new_handles->len == 0) { - g_array_free (new_handles, TRUE); - return contacts; + if (data->callback.contact_cb) { + data->callback.contact_cb (data->tp_factory, + contact, + error, + data->user_data, weak_object); } +} - /* Create new contacts */ - for (i = 0; i < new_handles->len; i++) { - EmpathyContact *contact; - guint handle; - - handle = g_array_index (new_handles, guint, i); - - contact = g_object_new (EMPATHY_TYPE_CONTACT, - "account", priv->account, - "handle", handle, - NULL); - contact_created (tp_factory, contact); - contacts = g_list_prepend (contacts, contact); - new_contacts = g_list_prepend (new_contacts, g_object_ref (contact)); - } - new_contacts = g_list_reverse (new_contacts); - - if (priv->ready) { - /* Get the IDs of all new handles */ - tp_cli_connection_call_inspect_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - new_handles, - tp_contact_factory_inspect_handles_cb, - new_contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - - /* Hold all new handles. */ - /* FIXME: Should be unholded when removed from the factory */ - tp_cli_connection_call_hold_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - new_handles, - tp_contact_factory_hold_handles_cb, - NULL, NULL, - G_OBJECT (tp_factory)); - - tp_contact_factory_request_everything (tp_factory, new_handles); - } +void +empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, + TpHandle handle, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GetContactsData *data; - g_array_free (new_handles, TRUE); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); - return contacts; + data = g_slice_new (GetContactsData); + data->callback.contact_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_handle (priv->connection, + 1, &handle, + G_N_ELEMENTS (contact_features), + contact_features, + get_contact_by_handle_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } void @@ -1219,9 +879,6 @@ empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - g_return_if_fail (priv->ready); - g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact), - priv->account)); handle = empathy_contact_get_handle (contact); @@ -1257,7 +914,6 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); - g_return_if_fail (priv->ready); if (data && size > 0 && size < G_MAXUINT) { GArray avatar; @@ -1265,8 +921,8 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, avatar.data = (gchar*) data; avatar.len = size; - DEBUG ("Setting avatar on account %s", - mc_account_get_unique_name (priv->account)); + DEBUG ("Setting avatar on connection %s", + tp_proxy_get_object_path (TP_PROXY (priv->connection))); tp_cli_connection_interface_avatars_call_set_avatar (priv->connection, -1, @@ -1276,8 +932,8 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, NULL, NULL, G_OBJECT (tp_factory)); } else { - DEBUG ("Clearing avatar on account %s", - mc_account_get_unique_name (priv->account)); + DEBUG ("Clearing avatar on connection %s", + tp_proxy_get_object_path (TP_PROXY (priv->connection))); tp_cli_connection_interface_avatars_call_clear_avatar (priv->connection, -1, @@ -1287,16 +943,6 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, } } -gboolean -empathy_tp_contact_factory_is_ready (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), FALSE); - - return priv->ready; -} - static void tp_contact_factory_get_property (GObject *object, guint param_id, @@ -1306,11 +952,8 @@ tp_contact_factory_get_property (GObject *object, EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); - break; - case PROP_READY: - g_value_set_boolean (value, priv->ready); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); break; case PROP_MIME_TYPES: g_value_set_boxed (value, priv->avatar_mime_types); @@ -1345,8 +988,8 @@ tp_contact_factory_set_property (GObject *object, EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - priv->account = g_object_ref (g_value_get_object (value)); + case PROP_CONNECTION: + priv->connection = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -1360,12 +1003,7 @@ tp_contact_factory_finalize (GObject *object) EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); GList *l; - DEBUG ("Finalized: %p (%s)", object, - mc_account_get_normalized_name (priv->account)); - - g_signal_handlers_disconnect_by_func (priv->account_manager, - tp_contact_factory_account_connection_cb, - object); + DEBUG ("Finalized: %p", object); for (l = priv->contacts; l; l = l->next) { g_object_weak_unref (G_OBJECT (l->data), @@ -1374,16 +1012,8 @@ tp_contact_factory_finalize (GObject *object) } g_list_free (priv->contacts); - g_object_unref (priv->account_manager); - g_object_unref (priv->account); - g_object_unref (priv->user); - - if (priv->connection) { - g_signal_handlers_disconnect_by_func (priv->connection, - tp_contact_factory_connection_invalidated_cb, - object); - g_object_unref (priv->connection); - } + + g_object_unref (priv->connection); g_strfreev (priv->avatar_mime_types); @@ -1401,11 +1031,35 @@ tp_contact_factory_constructor (GType type, tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props); priv = GET_PRIV (tp_factory); - priv->ready = FALSE; - priv->user = empathy_contact_new (priv->account); - empathy_contact_set_is_user (priv->user, TRUE); - tp_contact_factory_add_contact ((EmpathyTpContactFactory*) tp_factory, priv->user); - tp_contact_factory_status_updated (EMPATHY_TP_CONTACT_FACTORY (tp_factory)); + /* FIXME: This should be moved to TpContact */ + tp_cli_connection_interface_avatars_connect_to_avatar_updated (priv->connection, + tp_contact_factory_avatar_updated_cb, + NULL, NULL, + tp_factory, + NULL); + tp_cli_connection_interface_avatars_connect_to_avatar_retrieved (priv->connection, + tp_contact_factory_avatar_retrieved_cb, + NULL, NULL, + tp_factory, + NULL); + tp_cli_connection_interface_capabilities_connect_to_capabilities_changed (priv->connection, + tp_contact_factory_capabilities_changed_cb, + NULL, NULL, + tp_factory, + NULL); + + + /* FIXME: This should be moved to TpConnection */ + tp_cli_connection_interface_avatars_call_get_avatar_requirements (priv->connection, + -1, + tp_contact_factory_got_avatar_requirements_cb, + NULL, NULL, + tp_factory); + tp_cli_dbus_properties_call_get (priv->connection, -1, + TP_IFACE_CONNECTION_INTERFACE_REQUESTS, + "RequestableChannelClasses", + get_requestable_channel_classes_cb, NULL, NULL, + G_OBJECT (tp_factory)); return tp_factory; } @@ -1421,29 +1075,20 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) object_class->set_property = tp_contact_factory_set_property; g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "Factory's Account", - "The account associated with the factory", - MC_TYPE_ACCOUNT, + PROP_CONNECTION, + g_param_spec_object ("connection", + "Factory's Connection", + "The connection associated with the factory", + TP_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, - PROP_READY, - g_param_spec_boolean ("ready", - "Whether the factory is ready", - "TRUE once the factory is ready to be used", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, PROP_MIME_TYPES, g_param_spec_boxed ("avatar-mime-types", "Supported MIME types for avatars", "Types of images that may be set as " - "avatars on this connection. Only valid " - "once 'ready' becomes TRUE.", + "avatars on this connection.", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -1451,8 +1096,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) PROP_MIN_WIDTH, g_param_spec_uint ("avatar-min-width", "Minimum width for avatars", - "Minimum width of avatar that may be set. " - "Only valid once 'ready' becomes TRUE.", + "Minimum width of avatar that may be set.", 0, G_MAXUINT, 0, @@ -1462,8 +1106,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) PROP_MIN_HEIGHT, g_param_spec_uint ("avatar-min-height", "Minimum height for avatars", - "Minimum height of avatar that may be set. " - "Only valid once 'ready' becomes TRUE.", + "Minimum height of avatar that may be set.", 0, G_MAXUINT, 0, @@ -1474,8 +1117,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) g_param_spec_uint ("avatar-max-width", "Maximum width for avatars", "Maximum width of avatar that may be set " - "or 0 if there is no maximum. " - "Only valid once 'ready' becomes TRUE.", + "or 0 if there is no maximum.", 0, G_MAXUINT, 0, @@ -1486,8 +1128,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) g_param_spec_uint ("avatar-max-height", "Maximum height for avatars", "Maximum height of avatar that may be set " - "or 0 if there is no maximum. " - "Only valid once 'ready' becomes TRUE.", + "or 0 if there is no maximum.", 0, G_MAXUINT, 0, @@ -1498,8 +1139,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) g_param_spec_uint ("avatar-max-size", "Maximum size for avatars in bytes", "Maximum file size of avatar that may be " - "set or 0 if there is no maximum. " - "Only valid once 'ready' becomes TRUE.", + "set or 0 if there is no maximum.", 0, G_MAXUINT, 0, @@ -1517,20 +1157,68 @@ empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory) EMPATHY_TYPE_TP_CONTACT_FACTORY, EmpathyTpContactFactoryPriv); tp_factory->priv = priv; - priv->account_manager = empathy_account_manager_dup_singleton (); + priv->can_request_ft = FALSE; +} - g_signal_connect (priv->account_manager, "account-connection-changed", - G_CALLBACK (tp_contact_factory_account_connection_cb), - tp_factory); +static GHashTable *factories = NULL; - priv->can_request_ft = FALSE; +static void +tp_contact_factory_connection_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + gpointer user_data) +{ + DEBUG ("Message: %s", message); + g_hash_table_remove (factories, connection); +} + +static void +tp_contact_factory_connection_weak_notify_cb (gpointer connection, + GObject *where_the_object_was) +{ + g_hash_table_remove (factories, connection); +} + +static void +tp_contact_factory_remove_connection (gpointer connection) +{ + g_signal_handlers_disconnect_by_func (connection, + tp_contact_factory_connection_invalidated_cb, NULL); + g_object_unref (connection); } EmpathyTpContactFactory * -empathy_tp_contact_factory_new (McAccount *account) +empathy_tp_contact_factory_dup_singleton (TpConnection *connection) { - return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY, - "account", account, - NULL); + EmpathyTpContactFactory *tp_factory; + + g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL); + + if (factories == NULL) { + factories = g_hash_table_new_full (empathy_proxy_hash, + empathy_proxy_equal, + tp_contact_factory_remove_connection, + NULL); + } + + tp_factory = g_hash_table_lookup (factories, connection); + if (tp_factory == NULL) { + tp_factory = g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY, + "connection", connection, + NULL); + g_hash_table_insert (factories, g_object_ref (connection), + tp_factory); + g_object_weak_ref (G_OBJECT (tp_factory), + tp_contact_factory_connection_weak_notify_cb, + connection); + g_signal_connect (connection, "invalidated", + G_CALLBACK (tp_contact_factory_connection_invalidated_cb), + NULL); + } else { + g_object_ref (tp_factory); + } + + return tp_factory; } diff --git a/libempathy/empathy-tp-contact-factory.h b/libempathy/empathy-tp-contact-factory.h index 92e7c2980..91ff2f9e7 100644 --- a/libempathy/empathy-tp-contact-factory.h +++ b/libempathy/empathy-tp-contact-factory.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,7 +24,7 @@ #include <glib.h> -#include <libmissioncontrol/mc-account.h> +#include <telepathy-glib/connection.h> #include "empathy-contact.h" @@ -49,15 +49,58 @@ struct _EmpathyTpContactFactoryClass { GObjectClass parent_class; }; +typedef void (*EmpathyTpContactFactoryContactsByIdCb) (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + const gchar * const * requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object); + +typedef void (*EmpathyTpContactFactoryContactsByHandleCb) (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object); + +typedef void (*EmpathyTpContactFactoryContactCb) (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object); + GType empathy_tp_contact_factory_get_type (void) G_GNUC_CONST; -EmpathyTpContactFactory *empathy_tp_contact_factory_new (McAccount *account); -EmpathyContact * empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory); -EmpathyContact * empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, - const gchar *id); -EmpathyContact * empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, - guint handle); -GList * empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, - const GArray *handles); +EmpathyTpContactFactory *empathy_tp_contact_factory_dup_singleton (TpConnection *connection); +void empathy_tp_contact_factory_get_from_ids (EmpathyTpContactFactory *tp_factory, + guint n_ids, + const gchar * const *ids, + EmpathyTpContactFactoryContactsByIdCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); +void empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, + guint n_handles, + const TpHandle *handles, + EmpathyTpContactFactoryContactsByHandleCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); +void empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, + const gchar *id, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); +void empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, + TpHandle handle, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); void empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, EmpathyContact *contact, const gchar *alias); @@ -65,7 +108,6 @@ void empathy_tp_contact_factory_set_avatar (EmpathyTpC const gchar *data, gsize size, const gchar *mime_type); -gboolean empathy_tp_contact_factory_is_ready (EmpathyTpContactFactory *tp_factory); G_END_DECLS diff --git a/libempathy/empathy-tp-contact-list.c b/libempathy/empathy-tp-contact-list.c index d4b99e4c4..dd160224c 100644 --- a/libempathy/empathy-tp-contact-list.c +++ b/libempathy/empathy-tp-contact-list.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2007 Xavier Claessens <xclaesse@gmail.com> - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,8 +31,8 @@ #include <telepathy-glib/dbus.h> #include "empathy-tp-contact-list.h" +#include "empathy-tp-contact-factory.h" #include "empathy-contact-list.h" -#include "empathy-tp-group.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT @@ -40,18 +40,16 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpContactList) typedef struct { - McAccount *account; + EmpathyTpContactFactory *factory; TpConnection *connection; const gchar *protocol_group; - gboolean ready; - EmpathyTpGroup *publish; - EmpathyTpGroup *subscribe; - GList *members; - GList *pendings; - - GList *groups; - GHashTable *contacts_groups; + TpChannel *publish; + TpChannel *subscribe; + GHashTable *members; /* handle -> EmpathyContact */ + GHashTable *pendings; /* handle -> EmpathyContact */ + GHashTable *groups; /* group name -> TpChannel */ + GHashTable *add_to_group; /* group name -> GArray of handles */ } EmpathyTpContactListPriv; typedef enum { @@ -63,376 +61,535 @@ typedef enum { static void tp_contact_list_iface_init (EmpathyContactListIface *iface); enum { - DESTROY, - LAST_SIGNAL -}; - -enum { PROP_0, - PROP_ACCOUNT, + PROP_CONNECTION, }; -static guint signals[LAST_SIGNAL]; - G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST, tp_contact_list_iface_init)); static void -tp_contact_list_group_destroy_cb (EmpathyTpGroup *group, - EmpathyTpContactList *list) +tp_contact_list_group_invalidated_cb (TpChannel *channel, + guint domain, + gint code, + gchar *message, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + const TpIntSet *members; + TpIntSetIter iter; + const gchar *group_name; + + group_name = tp_channel_get_identifier (channel); + DEBUG ("Group %s invalidated. Message: %s", group_name, message); + + /* Signal that all members are not in that group anymore */ + members = tp_channel_group_get_members (channel); + tp_intset_iter_init (&iter, members); + while (tp_intset_iter_next (&iter)) { + EmpathyContact *contact; + + contact = g_hash_table_lookup (priv->members, + GUINT_TO_POINTER (iter.element)); + if (contact == NULL) { + continue; + } - DEBUG ("Group destroyed: %s", empathy_tp_group_get_name (group)); + DEBUG ("Contact %s (%d) removed from group %s", + empathy_contact_get_id (contact), iter.element, + group_name); + g_signal_emit_by_name (list, "groups-changed", contact, + group_name, + FALSE); + } - priv->groups = g_list_remove (priv->groups, group); - g_object_unref (group); + g_hash_table_remove (priv->groups, group_name); } static void -tp_contact_list_group_member_added_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_group_ready_cb (TpChannel *channel, + const GError *error, + gpointer list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - const gchar *group_name; - GList **groups; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + const gchar *group_name; - if (!g_list_find (priv->members, contact)) { + if (error) { + DEBUG ("Error: %s", error->message); + g_object_unref (channel); return; } + + group_name = tp_channel_get_identifier (channel); + g_hash_table_insert (priv->groups, (gpointer) group_name, channel); + DEBUG ("Group %s added", group_name); - groups = g_hash_table_lookup (priv->contacts_groups, contact); - if (!groups) { - groups = g_slice_new0 (GList*); - g_hash_table_insert (priv->contacts_groups, - g_object_ref (contact), - groups); - } + g_signal_connect (channel, "invalidated", + G_CALLBACK (tp_contact_list_group_invalidated_cb), + list); - group_name = empathy_tp_group_get_name (group); - if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) { - DEBUG ("Contact %s (%d) added to group %s", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - group_name); - *groups = g_list_prepend (*groups, g_strdup (group_name)); - g_signal_emit_by_name (list, "groups-changed", contact, - group_name, - TRUE); + if (priv->add_to_group) { + GArray *handles; + + handles = g_hash_table_lookup (priv->add_to_group, group_name); + if (handles) { + DEBUG ("Adding initial members to group %s", group_name); + tp_cli_channel_interface_group_call_add_members (channel, + -1, handles, NULL, NULL, NULL, NULL, NULL); + g_hash_table_remove (priv->add_to_group, group_name); + } } } static void -tp_contact_list_group_member_removed_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_group_members_changed_cb (TpChannel *channel, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - const gchar *group_name; - GList **groups, *l; + const gchar *group_name; + gint i; - if (!g_list_find (priv->members, contact)) { - return; - } + group_name = tp_channel_get_identifier (channel); - groups = g_hash_table_lookup (priv->contacts_groups, contact); - if (!groups) { - return; - } + for (i = 0; i < added->len; i++) { + EmpathyContact *contact; + TpHandle handle; + + handle = g_array_index (added, TpHandle, i); + contact = g_hash_table_lookup (priv->members, + GUINT_TO_POINTER (handle)); + if (contact == NULL) { + continue; + } + + DEBUG ("Contact %s (%d) added to group %s", + empathy_contact_get_id (contact), handle, group_name); + g_signal_emit_by_name (list, "groups-changed", contact, + group_name, + TRUE); + } + + for (i = 0; i < removed->len; i++) { + EmpathyContact *contact; + TpHandle handle; + + handle = g_array_index (removed, TpHandle, i); + contact = g_hash_table_lookup (priv->members, + GUINT_TO_POINTER (handle)); + if (contact == NULL) { + continue; + } - group_name = empathy_tp_group_get_name (group); - if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) { DEBUG ("Contact %s (%d) removed from group %s", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - group_name); - g_free (l->data); - *groups = g_list_delete_link (*groups, l); + empathy_contact_get_id (contact), handle, group_name); + g_signal_emit_by_name (list, "groups-changed", contact, group_name, FALSE); - } + } } -static EmpathyTpGroup * -tp_contact_list_find_group (EmpathyTpContactList *list, - const gchar *group) +static void +tp_contact_list_group_add_channel (EmpathyTpContactList *list, + const gchar *object_path, + const gchar *channel_type, + TpHandleType handle_type, + guint handle) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *l; + TpChannel *channel; - for (l = priv->groups; l; l = l->next) { - if (!tp_strdiff (group, empathy_tp_group_get_name (l->data))) { - return l->data; - } + /* Only accept server-side contact groups */ + if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) || + handle_type != TP_HANDLE_TYPE_GROUP) { + return; + } + + channel = tp_channel_new (priv->connection, + object_path, channel_type, + handle_type, handle, NULL); + + /* TpChannel emits initial set of members just before being ready */ + g_signal_connect (channel, "group-members-changed", + G_CALLBACK (tp_contact_list_group_members_changed_cb), + list); + + /* Give the ref to the callback */ + tp_channel_call_when_ready (channel, + tp_contact_list_group_ready_cb, + list); +} + +static void +tp_contact_list_group_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *list) +{ + /* The new channel will be handled in NewChannel cb. Here we only + * handle the error if RequestChannel failed */ + if (error) { + DEBUG ("Error: %s", error->message); + return; } - return NULL; } -static TpContactListType -tp_contact_list_get_type (EmpathyTpContactList *list, - EmpathyTpGroup *group) +static void +tp_contact_list_group_request_handles_cb (TpConnection *connection, + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *list) { - const gchar *name; + TpHandle channel_handle; - name = empathy_tp_group_get_name (group); - if (!tp_strdiff (name, "subscribe")) { - return TP_CONTACT_LIST_TYPE_SUBSCRIBE; - } else if (!tp_strdiff (name, "publish")) { - return TP_CONTACT_LIST_TYPE_PUBLISH; + if (error) { + DEBUG ("Error: %s", error->message); + return; } - return TP_CONTACT_LIST_TYPE_UNKNOWN; + channel_handle = g_array_index (handles, TpHandle, 0); + tp_cli_connection_call_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_GROUP, + channel_handle, + TRUE, + tp_contact_list_group_request_channel_cb, + NULL, NULL, + list); } +/* This function takes ownership of handles array */ static void -tp_contact_list_add_member (EmpathyTpContactList *list, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message) +tp_contact_list_group_add (EmpathyTpContactList *list, + const gchar *group_name, + GArray *handles) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *l; + TpChannel *channel; + const gchar *names[] = {group_name, NULL}; + + /* Search the channel for that group name */ + channel = g_hash_table_lookup (priv->groups, group_name); + if (channel) { + tp_cli_channel_interface_group_call_add_members (channel, -1, + handles, NULL, NULL, NULL, NULL, NULL); + g_array_free (handles, TRUE); + return; + } - /* Add to the list and emit signal */ - priv->members = g_list_prepend (priv->members, g_object_ref (contact)); - g_signal_emit_by_name (list, "members-changed", - contact, actor, reason, message, - TRUE); + /* That group does not exist yet, we have to: + * 1) Request an handle for the group name + * 2) Request a channel + * 3) When NewChannel is emitted, add handles in members + */ + g_hash_table_insert (priv->add_to_group, + g_strdup (group_name), + handles); + tp_cli_connection_call_request_handles (priv->connection, -1, + TP_HANDLE_TYPE_GROUP, names, + tp_contact_list_group_request_handles_cb, + NULL, NULL, + G_OBJECT (list)); +} + +static void +tp_contact_list_got_added_members_cb (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + guint i; - /* This contact is now member, implicitly accept pending. */ - if (g_list_find (priv->pendings, contact)) { - empathy_tp_group_add_member (priv->publish, contact, ""); + if (error) { + DEBUG ("Error: %s", error->message); + return; } - /* Update groups of the contact */ - for (l = priv->groups; l; l = l->next) { - if (empathy_tp_group_is_member (l->data, contact)) { - tp_contact_list_group_member_added_cb (l->data, contact, - NULL, 0, NULL, - list); + for (i = 0; i < n_contacts; i++) { + EmpathyContact *contact = contacts[i]; + TpHandle handle; + + handle = empathy_contact_get_handle (contact); + if (g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle))) + continue; + + /* Add to the list and emit signal */ + g_hash_table_insert (priv->members, GUINT_TO_POINTER (handle), + g_object_ref (contact)); + g_signal_emit_by_name (list, "members-changed", contact, + 0, 0, NULL, TRUE); + + /* This contact is now member, implicitly accept pending. */ + if (g_hash_table_lookup (priv->pendings, GUINT_TO_POINTER (handle))) { + GArray handles = {(gchar*) &handle, 1}; + + tp_cli_channel_interface_group_call_add_members (priv->publish, + -1, &handles, NULL, NULL, NULL, NULL, NULL); } } } static void -tp_contact_list_added_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_got_local_pending_cb (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpContactListType list_type; - - list_type = tp_contact_list_get_type (list, group); - DEBUG ("Contact %s (%d) added to list type %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - list_type); - - /* We now get the presence of that contact, add it to members */ - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && - !g_list_find (priv->members, contact)) { - tp_contact_list_add_member (list, contact, actor, reason, message); + guint i; + + if (error) { + DEBUG ("Error: %s", error->message); + return; } - /* We now send our presence to that contact, remove it from pendings */ - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && - g_list_find (priv->pendings, contact)) { - g_signal_emit_by_name (list, "pendings-changed", - contact, actor, reason, message, - FALSE); - priv->pendings = g_list_remove (priv->pendings, contact); - g_object_unref (contact); + for (i = 0; i < n_contacts; i++) { + EmpathyContact *contact = contacts[i]; + TpHandle handle; + const gchar *message; + TpChannelGroupChangeReason reason; + + handle = empathy_contact_get_handle (contact); + if (g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle))) { + GArray handles = {(gchar*) &handle, 1}; + + /* This contact is already member, auto accept. */ + tp_cli_channel_interface_group_call_add_members (priv->publish, + -1, &handles, NULL, NULL, NULL, NULL, NULL); + } + else if (tp_channel_group_get_local_pending_info (priv->publish, + handle, + NULL, + &reason, + &message)) { + /* Add contact to pendings */ + g_hash_table_insert (priv->pendings, GUINT_TO_POINTER (handle), + g_object_ref (contact)); + g_signal_emit_by_name (list, "pendings-changed", contact, + contact, reason, message, TRUE); + } } } static void -tp_contact_list_removed_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_remove_handle (EmpathyTpContactList *list, + GHashTable *table, + TpHandle handle) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpContactListType list_type; - - list_type = tp_contact_list_get_type (list, group); - DEBUG ("Contact %s (%d) removed from list type %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - list_type); - - /* This contact refuses to send us his presence, remove from members. */ - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && - g_list_find (priv->members, contact)) { - g_signal_emit_by_name (list, "members-changed", - contact, actor, reason, message, - FALSE); - priv->members = g_list_remove (priv->members, contact); - g_object_unref (contact); - } + EmpathyContact *contact; + const gchar *signal; + + if (table == priv->pendings) + signal = "pendings-changed"; + else if (table == priv->members) + signal = "members-changed"; + else + return; - /* We refuse to send our presence to that contact, remove from pendings */ - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && - g_list_find (priv->pendings, contact)) { - g_signal_emit_by_name (list, "pendings-changed", - contact, actor, reason, message, + contact = g_hash_table_lookup (table, GUINT_TO_POINTER (handle)); + if (contact) { + g_object_ref (contact); + g_hash_table_remove (table, GUINT_TO_POINTER (handle)); + g_signal_emit_by_name (list, signal, contact, 0, 0, NULL, FALSE); - priv->pendings = g_list_remove (priv->pendings, contact); g_object_unref (contact); } } static void -tp_contact_list_pending_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_publish_group_members_changed_cb (TpChannel *channel, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + TpHandle actor, + TpChannelGroupChangeReason reason, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpContactListType list_type; + guint i; - list_type = tp_contact_list_get_type (list, group); - DEBUG ("Contact %s (%d) pending in list type %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - list_type); + /* We now send our presence to those contacts, remove them from pendings */ + for (i = 0; i < added->len; i++) { + tp_contact_list_remove_handle (list, priv->pendings, + g_array_index (added, TpHandle, i)); + } - /* We want this contact in our contact list but we don't get its - * presence yet. Add to members anyway. */ - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && - !g_list_find (priv->members, contact)) { - tp_contact_list_add_member (list, contact, actor, reason, message); + /* We refuse to send our presence to those contacts, remove from pendings */ + for (i = 0; i < removed->len; i++) { + tp_contact_list_remove_handle (list, priv->pendings, + g_array_index (added, TpHandle, i)); } - /* This contact wants our presence, auto accept if he is member, - * otherwise he is pending. */ - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && - !g_list_find (priv->pendings, contact)) { - if (g_list_find (priv->members, contact)) { - empathy_tp_group_add_member (priv->publish, contact, ""); - } else { - priv->pendings = g_list_prepend (priv->pendings, - g_object_ref (contact)); - g_signal_emit_by_name (list, "pendings-changed", - contact, actor, reason, message, - TRUE); - } + /* Those contacts want our presence, auto accept those that are already + * member, otherwise add in pendings. */ + if (local_pending->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + local_pending->len, (TpHandle*) local_pending->data, + tp_contact_list_got_local_pending_cb, NULL, NULL, + G_OBJECT (list)); } } static void -tp_contact_list_invalidated_cb (TpConnection *connection, - guint domain, - gint code, - gchar *message, - EmpathyTpContactList *list) +tp_contact_list_publish_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *l; - DEBUG ("Connection invalidated"); - - /* Remove all contacts */ - for (l = priv->members; l; l = l->next) { - g_signal_emit_by_name (list, "members-changed", l->data, - NULL, 0, NULL, - FALSE); - g_object_unref (l->data); - } - for (l = priv->pendings; l; l = l->next) { - g_signal_emit_by_name (list, "pendings-changed", l->data, - NULL, 0, NULL, - FALSE); - g_object_unref (l->data); + if (error) { + DEBUG ("Error: %s", error->message); + return; } - g_list_free (priv->members); - g_list_free (priv->pendings); - priv->members = NULL; - priv->pendings = NULL; - /* Tell the world to not use us anymore */ - g_signal_emit (list, signals[DESTROY], 0); + priv->publish = tp_channel_new (connection, object_path, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + GPOINTER_TO_UINT (user_data), + NULL); + + /* TpChannel emits initial set of members just before being ready */ + g_signal_connect (priv->publish, "group-members-changed", + G_CALLBACK (tp_contact_list_publish_group_members_changed_cb), + list); } static void -tp_contact_list_group_list_free (GList **groups) +tp_contact_list_publish_request_handle_cb (TpConnection *connection, + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *list) { - g_list_foreach (*groups, (GFunc) g_free, NULL); - g_list_free (*groups); - g_slice_free (GList*, groups); + TpHandle handle; + + if (error) { + DEBUG ("Error: %s", error->message); + return; + } + + handle = g_array_index (handles, TpHandle, 0); + tp_cli_connection_call_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + handle, + TRUE, + tp_contact_list_publish_request_channel_cb, + GUINT_TO_POINTER (handle), NULL, + list); } static void -tp_contact_list_add_channel (EmpathyTpContactList *list, - const gchar *object_path, - const gchar *channel_type, - TpHandleType handle_type, - guint handle) +tp_contact_list_subscribe_group_members_changed_cb (TpChannel *channel, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpChannel *channel; - EmpathyTpGroup *group; - const gchar *group_name; - GList *contacts, *l; + guint i; + + /* We now get the presence of those contacts, add them to members */ + if (added->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + added->len, (TpHandle*) added->data, + tp_contact_list_got_added_members_cb, NULL, NULL, + G_OBJECT (list)); + } - if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 || - handle_type != TP_HANDLE_TYPE_GROUP) { - return; + /* Those contacts refuse to send us their presence, remove from members. */ + for (i = 0; i < removed->len; i++) { + tp_contact_list_remove_handle (list, priv->members, + g_array_index (added, TpHandle, i)); } - channel = tp_channel_new (priv->connection, - object_path, channel_type, - handle_type, handle, NULL); + /* We want those contacts in our contact list but we don't get their + * presence yet. Add to members anyway. */ + if (remote_pending->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + remote_pending->len, (TpHandle*) remote_pending->data, + tp_contact_list_got_added_members_cb, NULL, NULL, + G_OBJECT (list)); + } +} - group = empathy_tp_group_new (channel); - empathy_run_until_ready (group); - g_object_unref (channel); +static void +tp_contact_list_subscribe_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); - /* Check if already exists */ - group_name = empathy_tp_group_get_name (group); - if (tp_contact_list_find_group (list, group_name)) { - g_object_unref (group); + if (error) { + DEBUG ("Error: %s", error->message); return; } - /* Add the group */ - DEBUG ("New server-side group: %s", group_name); - priv->groups = g_list_prepend (priv->groups, group); - g_signal_connect (group, "member-added", - G_CALLBACK (tp_contact_list_group_member_added_cb), - list); - g_signal_connect (group, "member-removed", - G_CALLBACK (tp_contact_list_group_member_removed_cb), - list); - g_signal_connect (group, "destroy", - G_CALLBACK (tp_contact_list_group_destroy_cb), + priv->subscribe = tp_channel_new (connection, object_path, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + GPOINTER_TO_UINT (user_data), + NULL); + + /* TpChannel emits initial set of members just before being ready */ + g_signal_connect (priv->subscribe, "group-members-changed", + G_CALLBACK (tp_contact_list_subscribe_group_members_changed_cb), list); +} - /* Get initial members */ - contacts = empathy_tp_group_get_members (group); - for (l = contacts; l; l = l->next) { - tp_contact_list_group_member_added_cb (group, l->data, - NULL, 0, NULL, - list); - g_object_unref (l->data); +static void +tp_contact_list_subscribe_request_handle_cb (TpConnection *connection, + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *list) +{ + TpHandle handle; + + if (error) { + DEBUG ("Error: %s", error->message); + return; } - g_list_free (contacts); + + handle = g_array_index (handles, TpHandle, 0); + tp_cli_connection_call_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + handle, + TRUE, + tp_contact_list_subscribe_request_channel_cb, + GUINT_TO_POINTER (handle), NULL, + list); } static void @@ -445,13 +602,9 @@ tp_contact_list_new_channel_cb (TpConnection *proxy, gpointer user_data, GObject *list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - - if (!suppress_handler && priv->ready) { - tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list), - object_path, channel_type, - handle_type, handle); - } + tp_contact_list_group_add_channel (EMPATHY_TP_CONTACT_LIST (list), + object_path, channel_type, + handle_type, handle); } static void @@ -461,8 +614,7 @@ tp_contact_list_list_channels_cb (TpConnection *connection, gpointer user_data, GObject *list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - guint i; + guint i; if (error) { DEBUG ("Error: %s", error->message); @@ -482,151 +634,10 @@ tp_contact_list_list_channels_cb (TpConnection *connection, handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2)); handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3)); - tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list), - object_path, channel_type, - handle_type, handle); - } - - priv->ready = TRUE; -} - -static void -tp_contact_list_request_channel_cb (TpConnection *connection, - const gchar *object_path, - const GError *error, - gpointer user_data, - GObject *weak_object) -{ - EmpathyTpContactList *list = EMPATHY_TP_CONTACT_LIST (weak_object); - EmpathyTpContactListPriv *priv = GET_PRIV (list); - EmpathyTpGroup *group; - TpChannel *channel; - TpContactListType list_type; - GList *contacts, *l; - - if (error) { - DEBUG ("Error: %s", error->message); - return; - } - - channel = tp_channel_new (connection, object_path, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_LIST, - GPOINTER_TO_UINT (user_data), - NULL); - group = empathy_tp_group_new (channel); - empathy_run_until_ready (group); - - list_type = tp_contact_list_get_type (list, group); - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) { - DEBUG ("Got publish list"); - priv->publish = group; - - /* Publish is the list of contacts to who we send our - * presence. Makes no sense to be in remote-pending */ - g_signal_connect (group, "local-pending", - G_CALLBACK (tp_contact_list_pending_cb), - list); - - contacts = empathy_tp_group_get_local_pendings (group); - for (l = contacts; l; l = l->next) { - EmpathyPendingInfo *info = l->data; - tp_contact_list_pending_cb (group, - info->member, - info->actor, - 0, - info->message, - list); - empathy_pending_info_free (info); - } - g_list_free (contacts); - } - else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) { - DEBUG ("Got subscribe list"); - priv->subscribe = group; - - /* Subscribe is the list of contacts from who we - * receive presence. Makes no sense to be in - * local-pending */ - g_signal_connect (group, "remote-pending", - G_CALLBACK (tp_contact_list_pending_cb), - list); - - contacts = empathy_tp_group_get_remote_pendings (group); - for (l = contacts; l; l = l->next) { - tp_contact_list_pending_cb (group, - l->data, - NULL, 0, - NULL, list); - g_object_unref (l->data); - } - g_list_free (contacts); - } else { - DEBUG ("Type of contact list channel unknown or aleady " - "have that list: %s", - empathy_tp_group_get_name (group)); - g_object_unref (group); - return; + tp_contact_list_group_add_channel (EMPATHY_TP_CONTACT_LIST (list), + object_path, channel_type, + handle_type, handle); } - - /* For all list types when need to get members */ - g_signal_connect (group, "member-added", - G_CALLBACK (tp_contact_list_added_cb), - list); - g_signal_connect (group, "member-removed", - G_CALLBACK (tp_contact_list_removed_cb), - list); - - contacts = empathy_tp_group_get_members (group); - for (l = contacts; l; l = l->next) { - tp_contact_list_added_cb (group, - l->data, - NULL, 0, NULL, - list); - g_object_unref (l->data); - } - g_list_free (contacts); -} - -static void -tp_contact_list_request_handle_cb (TpConnection *connection, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *list) -{ - guint handle; - - if (error) { - DEBUG ("Error: %s", error->message); - return; - } - - handle = g_array_index (handles, guint, 0); - tp_cli_connection_call_request_channel (connection, -1, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_LIST, - handle, - TRUE, - tp_contact_list_request_channel_cb, - GUINT_TO_POINTER (handle), NULL, - list); -} - -static void -tp_contact_list_request_list (EmpathyTpContactList *list, - const gchar *type) -{ - EmpathyTpContactListPriv *priv = GET_PRIV (list); - const gchar *names[] = {type, NULL}; - - tp_cli_connection_call_request_handles (priv->connection, - -1, - TP_HANDLE_TYPE_LIST, - names, - tp_contact_list_request_handle_cb, - NULL, NULL, - G_OBJECT (list)); } static void @@ -634,6 +645,8 @@ tp_contact_list_finalize (GObject *object) { EmpathyTpContactListPriv *priv; EmpathyTpContactList *list; + GHashTableIter iter; + gpointer channel; list = EMPATHY_TP_CONTACT_LIST (object); priv = GET_PRIV (list); @@ -646,49 +659,55 @@ tp_contact_list_finalize (GObject *object) if (priv->publish) { g_object_unref (priv->publish); } - if (priv->account) { - g_object_unref (priv->account); - } + if (priv->connection) { - g_signal_handlers_disconnect_by_func (priv->connection, - tp_contact_list_invalidated_cb, - object); g_object_unref (priv->connection); } - g_hash_table_destroy (priv->contacts_groups); - g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL); - g_list_free (priv->groups); - g_list_foreach (priv->members, (GFunc) g_object_unref, NULL); - g_list_free (priv->members); - g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL); - g_list_free (priv->pendings); + if (priv->factory) { + g_object_unref (priv->factory); + } + + g_hash_table_iter_init (&iter, priv->groups); + while (g_hash_table_iter_next (&iter, NULL, &channel)) { + g_signal_handlers_disconnect_by_func (channel, + tp_contact_list_group_invalidated_cb, list); + } + + g_hash_table_destroy (priv->groups); + g_hash_table_destroy (priv->members); + g_hash_table_destroy (priv->pendings); + g_hash_table_destroy (priv->add_to_group); G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object); } static void -tp_contact_list_connection_ready (TpConnection *connection, - const GError *error, - gpointer list) +tp_contact_list_constructed (GObject *list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - if (error) { - tp_contact_list_invalidated_cb (connection, - error->domain, - error->code, - error->message, - EMPATHY_TP_CONTACT_LIST (list)); - return; - } + EmpathyTpContactListPriv *priv = GET_PRIV (list); + gchar *protocol_name = NULL; + const gchar *names[] = {NULL, NULL}; - g_signal_connect (priv->connection, "invalidated", - G_CALLBACK (tp_contact_list_invalidated_cb), - list); + priv->factory = empathy_tp_contact_factory_dup_singleton (priv->connection); - tp_contact_list_request_list (list, "publish"); - tp_contact_list_request_list (list, "subscribe"); + names[0] = "publish"; + tp_cli_connection_call_request_handles (priv->connection, + -1, + TP_HANDLE_TYPE_LIST, + names, + tp_contact_list_publish_request_handle_cb, + NULL, NULL, + G_OBJECT (list)); + names[0] = "subscribe"; + tp_cli_connection_call_request_handles (priv->connection, + -1, + TP_HANDLE_TYPE_LIST, + names, + tp_contact_list_subscribe_request_handle_cb, + NULL, NULL, + G_OBJECT (list)); tp_cli_connection_call_list_channels (priv->connection, -1, tp_contact_list_list_channels_cb, @@ -699,39 +718,15 @@ tp_contact_list_connection_ready (TpConnection *connection, tp_contact_list_new_channel_cb, NULL, NULL, list, NULL); -} - -static void -tp_contact_list_constructed (GObject *list) -{ - - EmpathyTpContactListPriv *priv = GET_PRIV (list); - MissionControl *mc; - guint status; - McProfile *profile; - const gchar *protocol_name; - - /* Get the connection. status==0 means CONNECTED */ - mc = empathy_mission_control_dup_singleton (); - status = mission_control_get_connection_status (mc, priv->account, NULL); - g_return_if_fail (status == 0); - priv->connection = mission_control_get_tpconnection (mc, priv->account, NULL); - g_return_if_fail (priv->connection != NULL); - g_object_unref (mc); - - tp_connection_call_when_ready (priv->connection, - tp_contact_list_connection_ready, - list); /* Check for protocols that does not support contact groups. We can * put all contacts into a special group in that case. * FIXME: Default group should be an information in the profile */ - profile = mc_account_get_profile (priv->account); - protocol_name = mc_profile_get_protocol_name (profile); - if (strcmp (protocol_name, "local-xmpp") == 0) { + tp_connection_parse_object_path (priv->connection, &protocol_name, NULL); + if (!tp_strdiff (protocol_name, "local-xmpp")) { priv->protocol_group = _("People nearby"); } - g_object_unref (profile); + g_free (protocol_name); } static void @@ -743,8 +738,8 @@ tp_contact_list_get_property (GObject *object, EmpathyTpContactListPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -761,8 +756,8 @@ tp_contact_list_set_property (GObject *object, EmpathyTpContactListPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - priv->account = g_object_ref (g_value_get_object (value)); + case PROP_CONNECTION: + priv->connection = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -781,50 +776,63 @@ empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass) object_class->set_property = tp_contact_list_set_property; g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "The Account", - "The account associated with the contact list", - MC_TYPE_ACCOUNT, + PROP_CONNECTION, + g_param_spec_object ("connection", + "The Connection", + "The connection associated with the contact list", + TP_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - signals[DESTROY] = - g_signal_new ("destroy", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv)); } static void +tp_contact_list_array_free (gpointer handles) +{ + g_array_free (handles, TRUE); +} + +static void empathy_tp_contact_list_init (EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (list, EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv); list->priv = priv; - priv->contacts_groups = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - (GDestroyNotify) g_object_unref, - (GDestroyNotify) tp_contact_list_group_list_free); + + /* Map group's name to group's TpChannel. The group name string is owned + * by the TpChannel object */ + priv->groups = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, + (GDestroyNotify) g_object_unref); + + /* Map contact's handle to EmpathyContact object */ + priv->members = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + /* Map contact's handle to EmpathyContact object */ + priv->pendings = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + /* Map group's name to GArray of handle */ + priv->add_to_group = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + tp_contact_list_array_free); } EmpathyTpContactList * -empathy_tp_contact_list_new (McAccount *account) +empathy_tp_contact_list_new (TpConnection *connection) { return g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST, - "account", account, + "connection", connection, NULL); } -McAccount * -empathy_tp_contact_list_get_account (EmpathyTpContactList *list) +TpConnection * +empathy_tp_contact_list_get_connection (EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv; @@ -832,7 +840,7 @@ empathy_tp_contact_list_get_account (EmpathyTpContactList *list) priv = GET_PRIV (list); - return priv->account; + return priv->connection; } static void @@ -841,15 +849,18 @@ tp_contact_list_add (EmpathyContactList *list, const gchar *message) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpHandle handle; + GArray handles = {(gchar *) &handle, 1}; - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - + handle = empathy_contact_get_handle (contact); if (priv->subscribe) { - empathy_tp_group_add_member (priv->subscribe, contact, message); + tp_cli_channel_interface_group_call_add_members (priv->subscribe, + -1, &handles, message, NULL, NULL, NULL, NULL); } - - if (priv->publish && g_list_find (priv->pendings, contact)) { - empathy_tp_group_add_member (priv->publish, contact, message); + if (priv->publish && + g_hash_table_lookup (priv->pendings, GUINT_TO_POINTER (handle))) { + tp_cli_channel_interface_group_call_add_members (priv->publish, + -1, &handles, message, NULL, NULL, NULL, NULL); } } @@ -859,14 +870,17 @@ tp_contact_list_remove (EmpathyContactList *list, const gchar *message) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpHandle handle; + GArray handles = {(gchar *) &handle, 1}; - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - + handle = empathy_contact_get_handle (contact); if (priv->subscribe) { - empathy_tp_group_remove_member (priv->subscribe, contact, message); + tp_cli_channel_interface_group_call_remove_members (priv->subscribe, + -1, &handles, message, NULL, NULL, NULL, NULL); } if (priv->publish) { - empathy_tp_group_remove_member (priv->publish, contact, message); + tp_cli_channel_interface_group_call_remove_members (priv->publish, + -1, &handles, message, NULL, NULL, NULL, NULL); } } @@ -874,44 +888,40 @@ static GList * tp_contact_list_get_members (EmpathyContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *ret; - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - g_list_foreach (priv->members, (GFunc) g_object_ref, NULL); - return g_list_copy (priv->members); + ret = g_hash_table_get_values (priv->members); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + return ret; } static GList * tp_contact_list_get_pendings (EmpathyContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *ret; - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL); - return g_list_copy (priv->pendings); + ret = g_hash_table_get_values (priv->pendings); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + return ret; } static GList * tp_contact_list_get_all_groups (EmpathyContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *groups = NULL, *l; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); + GList *ret, *l; - if (priv->protocol_group) { - groups = g_list_prepend (groups, g_strdup (priv->protocol_group)); + ret = g_hash_table_get_keys (priv->groups); + for (l = ret; l; l = l->next) { + l->data = g_strdup (l->data); } - for (l = priv->groups; l; l = l->next) { - const gchar *name; - - name = empathy_tp_group_get_name (l->data); - groups = g_list_prepend (groups, g_strdup (name)); + if (priv->protocol_group) { + ret = g_list_prepend (ret, g_strdup (priv->protocol_group)); } - return groups; + return ret; } static GList * @@ -919,174 +929,119 @@ tp_contact_list_get_groups (EmpathyContactList *list, EmpathyContact *contact) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList **groups; - GList *ret = NULL, *l; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); + GList *ret = NULL; + GHashTableIter iter; + gpointer group_name; + gpointer channel; + TpHandle handle; + + handle = empathy_contact_get_handle (contact); + g_hash_table_iter_init (&iter, priv->groups); + while (g_hash_table_iter_next (&iter, &group_name, &channel)) { + const TpIntSet *members; + + members = tp_channel_group_get_members (channel); + if (tp_intset_is_member (members, handle)) { + ret = g_list_prepend (ret, g_strdup (group_name)); + } + } if (priv->protocol_group) { ret = g_list_prepend (ret, g_strdup (priv->protocol_group)); } - groups = g_hash_table_lookup (priv->contacts_groups, contact); - if (!groups) { - return ret; - } - - for (l = *groups; l; l = l->next) { - ret = g_list_prepend (ret, g_strdup (l->data)); - } - - return ret; } -static EmpathyTpGroup * -tp_contact_list_get_group (EmpathyTpContactList *list, - const gchar *group) -{ - EmpathyTpContactListPriv *priv = GET_PRIV (list); - EmpathyTpGroup *tp_group; - gchar *object_path; - guint handle; - GArray *handles; - const char *names[2] = {group, NULL}; - GError *error = NULL; - - tp_group = tp_contact_list_find_group (list, group); - if (tp_group) { - return tp_group; - } - - DEBUG ("creating new group: %s", group); - - if (!tp_cli_connection_run_request_handles (priv->connection, -1, - TP_HANDLE_TYPE_GROUP, - names, - &handles, - &error, NULL)) { - DEBUG ("Failed to RequestHandles: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - handle = g_array_index (handles, guint, 0); - g_array_free (handles, TRUE); - - if (!tp_cli_connection_run_request_channel (priv->connection, -1, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_GROUP, - handle, - TRUE, - &object_path, - &error, NULL)) { - DEBUG ("Failed to RequestChannel: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - - tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list), - object_path, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_GROUP, handle); - - g_free (object_path); - - return tp_contact_list_find_group (list, group); -} - static void tp_contact_list_add_to_group (EmpathyContactList *list, EmpathyContact *contact, - const gchar *group) + const gchar *group_name) { - EmpathyTpGroup *tp_group; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - - tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list), - group); - - if (tp_group) { - empathy_tp_group_add_member (tp_group, contact, ""); - } + TpHandle handle; + GArray *handles; + + handle = empathy_contact_get_handle (contact); + handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1); + g_array_append_val (handles, handle); + tp_contact_list_group_add (EMPATHY_TP_CONTACT_LIST (list), + group_name, handles); } static void tp_contact_list_remove_from_group (EmpathyContactList *list, EmpathyContact *contact, - const gchar *group) + const gchar *group_name) { - EmpathyTpGroup *tp_group; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpChannel *channel; + TpHandle handle; + GArray handles = {(gchar *) &handle, 1}; - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + channel = g_hash_table_lookup (priv->groups, group_name); + if (channel == NULL) { + return; + } - tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), - group); + handle = empathy_contact_get_handle (contact); + DEBUG ("remove contact %s (%d) from group %s", + empathy_contact_get_id (contact), handle, group_name); - if (tp_group) { - empathy_tp_group_remove_member (tp_group, contact, ""); - } + tp_cli_channel_interface_group_call_remove_members (channel, -1, + &handles, NULL, NULL, NULL, NULL, NULL); } static void tp_contact_list_rename_group (EmpathyContactList *list, - const gchar *old_group, - const gchar *new_group) + const gchar *old_group_name, + const gchar *new_group_name) { - EmpathyTpGroup *tp_group; - GList *members; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpChannel *channel; + const TpIntSet *members; + GArray *handles; - tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), - old_group); - if (!tp_group) { + channel = g_hash_table_lookup (priv->groups, old_group_name); + if (channel == NULL) { return; } - DEBUG ("rename group %s to %s", old_group, new_group); - - /* Remove all members from the old group */ - members = empathy_tp_group_get_members (tp_group); - empathy_tp_group_remove_members (tp_group, members, ""); - empathy_tp_group_close (tp_group); + DEBUG ("rename group %s to %s", old_group_name, new_group_name); - /* Add all members to the new group */ - tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list), - new_group); - empathy_tp_group_add_members (tp_group, members, ""); + /* Remove all members and close the old channel */ + members = tp_channel_group_get_members (channel); + handles = tp_intset_to_array (members); + tp_cli_channel_interface_group_call_remove_members (channel, -1, + handles, NULL, NULL, NULL, NULL, NULL); + tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); - g_list_foreach (members, (GFunc) g_object_unref, NULL); - g_list_free (members); + tp_contact_list_group_add (EMPATHY_TP_CONTACT_LIST (list), + new_group_name, handles); } static void tp_contact_list_remove_group (EmpathyContactList *list, - const gchar *group) + const gchar *group_name) { - EmpathyTpGroup *tp_group; - GList *members; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpChannel *channel; + const TpIntSet *members; + GArray *handles; - tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), - group); - - if (!tp_group) { + channel = g_hash_table_lookup (priv->groups, group_name); + if (channel == NULL) { return; } - DEBUG ("remove group %s", group); + DEBUG ("remove group %s", group_name); - /* Remove all members of the group */ - members = empathy_tp_group_get_members (tp_group); - empathy_tp_group_remove_members (tp_group, members, ""); - empathy_tp_group_close (tp_group); - - g_list_foreach (members, (GFunc) g_object_unref, NULL); - g_list_free (members); + /* Remove all members and close the channel */ + members = tp_channel_group_get_members (channel); + handles = tp_intset_to_array (members); + tp_cli_channel_interface_group_call_remove_members (channel, -1, + handles, NULL, NULL, NULL, NULL, NULL); + tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); + g_array_free (handles, TRUE); } static void @@ -1117,6 +1072,34 @@ empathy_tp_contact_list_can_add (EmpathyTpContactList *list) if (priv->subscribe == NULL) return FALSE; - flags = empathy_tp_group_get_flags (priv->subscribe); + flags = tp_channel_group_get_flags (priv->subscribe); return (flags & TP_CHANNEL_GROUP_FLAG_CAN_ADD) != 0; } + +void +empathy_tp_contact_list_remove_all (EmpathyTpContactList *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + GHashTableIter iter; + gpointer contact; + + g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + + /* Remove all contacts */ + g_hash_table_iter_init (&iter, priv->members); + while (g_hash_table_iter_next (&iter, NULL, &contact)) { + g_signal_emit_by_name (list, "members-changed", contact, + NULL, 0, NULL, + FALSE); + } + g_hash_table_remove_all (priv->members); + + g_hash_table_iter_init (&iter, priv->pendings); + while (g_hash_table_iter_next (&iter, NULL, &contact)) { + g_signal_emit_by_name (list, "pendings-changed", contact, + NULL, 0, NULL, + FALSE); + } + g_hash_table_remove_all (priv->pendings); +} + diff --git a/libempathy/empathy-tp-contact-list.h b/libempathy/empathy-tp-contact-list.h index e8edcface..c6cf6cb4a 100644 --- a/libempathy/empathy-tp-contact-list.h +++ b/libempathy/empathy-tp-contact-list.h @@ -24,7 +24,7 @@ #define __EMPATHY_TP_CONTACT_LIST_H__ #include <glib.h> -#include <libmissioncontrol/mc-account.h> +#include <telepathy-glib/connection.h> G_BEGIN_DECLS @@ -49,9 +49,10 @@ struct _EmpathyTpContactListClass { }; GType empathy_tp_contact_list_get_type (void) G_GNUC_CONST; -EmpathyTpContactList * empathy_tp_contact_list_new (McAccount *account); -McAccount * empathy_tp_contact_list_get_account (EmpathyTpContactList *list); +EmpathyTpContactList * empathy_tp_contact_list_new (TpConnection *connection); +TpConnection * empathy_tp_contact_list_get_connection (EmpathyTpContactList *list); gboolean empathy_tp_contact_list_can_add (EmpathyTpContactList *list); +void empathy_tp_contact_list_remove_all (EmpathyTpContactList *list); G_END_DECLS diff --git a/libempathy/empathy-tp-file.c b/libempathy/empathy-tp-file.c index 1f6bedfb2..913c27bbf 100644 --- a/libempathy/empathy-tp-file.c +++ b/libempathy/empathy-tp-file.c @@ -39,7 +39,7 @@ #include <telepathy-glib/util.h> #include "empathy-tp-file.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-marshal.h" #include "empathy-time.h" #include "empathy-utils.h" @@ -277,9 +277,10 @@ copy_stream (GInputStream *in, /* EmpathyTpFile object */ struct _EmpathyTpFilePriv { - EmpathyContactFactory *factory; + EmpathyTpContactFactory *factory; MissionControl *mc; TpChannel *channel; + gboolean ready; EmpathyContact *contact; GInputStream *in_stream; @@ -307,6 +308,7 @@ enum { PROP_CHANNEL, PROP_STATE, PROP_INCOMING, + PROP_READY, PROP_FILENAME, PROP_SIZE, PROP_CONTENT_TYPE, @@ -493,81 +495,154 @@ tp_file_transferred_bytes_changed_cb (TpChannel *channel, g_object_notify (G_OBJECT (tp_file), "transferred-bytes"); } -static GObject * -tp_file_constructor (GType type, - guint n_props, - GObjectConstructParam *props) +static void +tp_file_check_if_ready (EmpathyTpFile *tp_file) { - GObject *file_obj; - EmpathyTpFile *tp_file; - TpHandle handle; - GHashTable *properties; - McAccount *account; - GValue *requested; - - file_obj = G_OBJECT_CLASS (empathy_tp_file_parent_class)->constructor (type, - n_props, props); - - tp_file = EMPATHY_TP_FILE (file_obj); - - tp_file->priv->factory = empathy_contact_factory_dup_singleton (); - tp_file->priv->mc = empathy_mission_control_dup_singleton (); - - g_signal_connect (tp_file->priv->channel, "invalidated", - G_CALLBACK (tp_file_invalidated_cb), tp_file); + if (tp_file->priv->ready || tp_file->priv->contact == NULL || + tp_file->priv->state == 0) + return; - tp_cli_channel_type_file_transfer_connect_to_file_transfer_state_changed ( - tp_file->priv->channel, tp_file_state_changed_cb, NULL, NULL, - G_OBJECT (tp_file), NULL); + tp_file->priv->ready = TRUE; + g_object_notify (G_OBJECT (tp_file), "ready"); +} - tp_cli_channel_type_file_transfer_connect_to_transferred_bytes_changed ( - tp_file->priv->channel, tp_file_transferred_bytes_changed_cb, - NULL, NULL, G_OBJECT (tp_file), NULL); +static void +tp_file_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (weak_object); - account = empathy_channel_get_account (tp_file->priv->channel); + if (error) + { + DEBUG ("Error: %s", error->message); + empathy_tp_file_close (tp_file); + return; + } - handle = tp_channel_get_handle (tp_file->priv->channel, NULL); - tp_file->priv->contact = empathy_contact_factory_get_from_handle ( - tp_file->priv->factory, account, (guint) handle); + tp_file->priv->contact = g_object_ref (contact); + tp_file_check_if_ready (tp_file); +} - tp_cli_dbus_properties_run_get_all (tp_file->priv->channel, - -1, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, &properties, NULL, NULL); +static void +tp_file_get_all_cb (TpProxy *proxy, + GHashTable *properties, + const GError *error, + gpointer user_data, + GObject *file_obj) +{ + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (file_obj); - tp_cli_dbus_properties_run_get (tp_file->priv->channel, - -1, TP_IFACE_CHANNEL, "Requested", &requested, NULL, NULL); + if (error) + { + DEBUG ("Error: %s", error->message); + tp_cli_channel_call_close (tp_file->priv->channel, -1, NULL, NULL, NULL, + NULL); + return; + } tp_file->priv->size = g_value_get_uint64 ( g_hash_table_lookup (properties, "Size")); + g_object_notify (file_obj, "size"); tp_file->priv->state = g_value_get_uint ( g_hash_table_lookup (properties, "State")); - - tp_file->priv->state_change_reason = - TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE; + g_object_notify (file_obj, "state"); tp_file->priv->transferred_bytes = g_value_get_uint64 ( g_hash_table_lookup (properties, "TransferredBytes")); + g_object_notify (file_obj, "transferred-bytes"); tp_file->priv->filename = g_value_dup_string ( g_hash_table_lookup (properties, "Filename")); + g_object_notify (file_obj, "filename"); tp_file->priv->content_hash = g_value_dup_string ( g_hash_table_lookup (properties, "ContentHash")); + g_object_notify (file_obj, "content-hash"); tp_file->priv->content_hash_type = g_value_get_uint ( g_hash_table_lookup (properties, "ContentHashType")); + g_object_notify (file_obj, "content-hash-type"); tp_file->priv->content_type = g_value_dup_string ( g_hash_table_lookup (properties, "ContentType")); + g_object_notify (file_obj, "content-type"); tp_file->priv->description = g_value_dup_string ( g_hash_table_lookup (properties, "Description")); + tp_file_check_if_ready (tp_file); +} + +static void +tp_file_get_requested_cb (TpProxy *proxy, + const GValue *requested, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (weak_object); + + if (error) + { + DEBUG ("Error: %s", error->message); + tp_cli_channel_call_close (tp_file->priv->channel, -1, NULL, NULL, NULL, + NULL); + return; + } + tp_file->priv->incoming = !g_value_get_boolean (requested); + g_object_notify (G_OBJECT (tp_file), "incoming"); + + tp_file_check_if_ready (tp_file); +} + +static GObject * +tp_file_constructor (GType type, + guint n_props, + GObjectConstructParam *props) +{ + GObject *file_obj; + EmpathyTpFile *tp_file; + TpHandle handle; + TpConnection *connection; + + file_obj = G_OBJECT_CLASS (empathy_tp_file_parent_class)->constructor (type, + n_props, props); + + tp_file = EMPATHY_TP_FILE (file_obj); + + connection = tp_channel_borrow_connection (tp_file->priv->channel); + tp_file->priv->factory = empathy_tp_contact_factory_dup_singleton (connection); + tp_file->priv->mc = empathy_mission_control_dup_singleton (); + tp_file->priv->state_change_reason = + TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE; + + g_signal_connect (tp_file->priv->channel, "invalidated", + G_CALLBACK (tp_file_invalidated_cb), tp_file); + + tp_cli_channel_type_file_transfer_connect_to_file_transfer_state_changed ( + tp_file->priv->channel, tp_file_state_changed_cb, NULL, NULL, + G_OBJECT (tp_file), NULL); + + tp_cli_channel_type_file_transfer_connect_to_transferred_bytes_changed ( + tp_file->priv->channel, tp_file_transferred_bytes_changed_cb, + NULL, NULL, G_OBJECT (tp_file), NULL); + + tp_cli_dbus_properties_call_get (tp_file->priv->channel, -1, + TP_IFACE_CHANNEL, "Requested", + tp_file_get_requested_cb, NULL, NULL, file_obj); - g_hash_table_destroy (properties); - g_object_unref (account); - g_value_unset (requested); + tp_cli_dbus_properties_call_get_all (tp_file->priv->channel, -1, + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, + tp_file_get_all_cb, NULL, NULL, file_obj); + + handle = tp_channel_get_handle (tp_file->priv->channel, NULL); + empathy_tp_contact_factory_get_from_handle (tp_file->priv->factory, + handle, tp_file_got_contact_cb, NULL, NULL, file_obj); return file_obj; } @@ -956,6 +1031,14 @@ empathy_tp_file_close (EmpathyTpFile *tp_file) empathy_tp_file_cancel (tp_file); } +gboolean +empathy_tp_file_is_ready (EmpathyTpFile *tp_file) +{ + g_return_val_if_fail (EMPATHY_IS_TP_FILE (tp_file), FALSE); + + return tp_file->priv->ready; +} + static void empathy_tp_file_class_init (EmpathyTpFileClass *klass) { @@ -997,6 +1080,15 @@ empathy_tp_file_class_init (EmpathyTpFileClass *klass) G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, + PROP_READY, + g_param_spec_boolean ("ready", + "ready", + "Whether the object is ready", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_FILENAME, g_param_spec_string ("filename", "name of the transfer", diff --git a/libempathy/empathy-tp-file.h b/libempathy/empathy-tp-file.h index 42c54e4f0..5f239c8e0 100644 --- a/libempathy/empathy-tp-file.h +++ b/libempathy/empathy-tp-file.h @@ -81,6 +81,7 @@ guint64 empathy_tp_file_get_size (EmpathyTpFile *tp_file); guint64 empathy_tp_file_get_transferred_bytes (EmpathyTpFile *tp_file); gint empathy_tp_file_get_remaining_time (EmpathyTpFile *tp_file); const gchar *empathy_tp_file_get_content_type (EmpathyTpFile *tp_file); +gboolean empathy_tp_file_is_ready (EmpathyTpFile *tp_file); G_END_DECLS diff --git a/libempathy/empathy-tp-group.c b/libempathy/empathy-tp-group.c deleted file mode 100644 index c3471c157..000000000 --- a/libempathy/empathy-tp-group.c +++ /dev/null @@ -1,981 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Xavier Claessens <xclaesse@gmail.com> - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Xavier Claessens <xclaesse@gmail.com> - */ - -#include <config.h> - -#include <libmissioncontrol/mc-account.h> - -#include <telepathy-glib/util.h> -#include <telepathy-glib/interfaces.h> - -#include "empathy-tp-group.h" -#include "empathy-contact-factory.h" -#include "empathy-utils.h" -#include "empathy-marshal.h" - -#define DEBUG_FLAG EMPATHY_DEBUG_TP -#include "empathy-debug.h" - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpGroup) -typedef struct { - TpChannel *channel; - gboolean ready; - - EmpathyContactFactory *factory; - McAccount *account; - gchar *group_name; - guint self_handle; - GList *members; - GList *local_pendings; - GList *remote_pendings; -} EmpathyTpGroupPriv; - -enum { - MEMBER_ADDED, - MEMBER_REMOVED, - LOCAL_PENDING, - REMOTE_PENDING, - DESTROY, - LAST_SIGNAL -}; - -enum { - PROP_0, - PROP_CHANNEL, - PROP_READY -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_TYPE (EmpathyTpGroup, empathy_tp_group, G_TYPE_OBJECT); - -static EmpathyContact * -tp_group_get_contact (EmpathyTpGroup *group, - guint handle) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyContact *contact = NULL; - - if (handle != 0) { - contact = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - handle); - } - - if (contact && handle == priv->self_handle) { - empathy_contact_set_is_user (contact, TRUE); - } - - return contact; -} - -static GList * -tp_group_get_contacts (EmpathyTpGroup *group, - const GArray *handles) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GList *contacts, *l; - - if (!handles) { - return NULL; - } - - contacts = empathy_contact_factory_get_from_handles (priv->factory, - priv->account, - handles); - - /* FIXME: Only useful if the group has a different self handle than - * the connection, otherwise the contact factory already set that - * property. That can be known using group flags. */ - for (l = contacts; l; l = l->next) { - if (empathy_contact_get_handle (l->data) == priv->self_handle) { - empathy_contact_set_is_user (l->data, TRUE); - } - } - - return contacts; -} - -EmpathyPendingInfo * -empathy_pending_info_new (EmpathyContact *member, - EmpathyContact *actor, - const gchar *message) -{ - EmpathyPendingInfo *info; - - info = g_slice_new0 (EmpathyPendingInfo); - - if (member) { - info->member = g_object_ref (member); - } - if (actor) { - info->actor = g_object_ref (actor); - } - if (message) { - info->message = g_strdup (message); - } - - return info; -} - -void -empathy_pending_info_free (EmpathyPendingInfo *info) -{ - if (!info) { - return; - } - - if (info->member) { - g_object_unref (info->member); - } - if (info->actor) { - g_object_unref (info->actor); - } - g_free (info->message); - - g_slice_free (EmpathyPendingInfo, info); -} - -static gint -tp_group_local_pending_find (gconstpointer a, - gconstpointer b) -{ - const EmpathyPendingInfo *info = a; - - return (info->member != b); -} - -static void -tp_group_remove_from_pendings (EmpathyTpGroup *group, - EmpathyContact *contact) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GList *l; - - /* local pending */ - l = g_list_find_custom (priv->local_pendings, - contact, - tp_group_local_pending_find); - if (l) { - empathy_pending_info_free (l->data); - priv->local_pendings = g_list_delete_link (priv->local_pendings, l); - } - - /* remote pending */ - l = g_list_find (priv->remote_pendings, contact); - if (l) { - g_object_unref (l->data); - priv->remote_pendings = g_list_delete_link (priv->remote_pendings, l); - } -} - -static void -tp_group_update_members (EmpathyTpGroup *group, - const gchar *message, - const GArray *added, - const GArray *removed, - const GArray *local_pending, - const GArray *remote_pending, - guint actor, - guint reason) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyContact *actor_contact = NULL; - GList *contacts, *l, *ll; - - actor_contact = tp_group_get_contact (group, actor); - - DEBUG ("Members changed for list %s:\n" - " added-len=%d, current-len=%d\n" - " removed-len=%d\n" - " local-pending-len=%d, current-len=%d\n" - " remote-pending-len=%d, current-len=%d", - priv->group_name, added ? added->len : 0, - g_list_length (priv->members), removed ? removed->len : 0, - local_pending ? local_pending->len : 0, - g_list_length (priv->local_pendings), - remote_pending ? remote_pending->len : 0, - g_list_length (priv->remote_pendings)); - - /* Contacts added */ - contacts = tp_group_get_contacts (group, added); - for (l = contacts; l; l = l->next) { - tp_group_remove_from_pendings (group, l->data); - - /* If the contact is not yet member, add it and emit signal */ - if (!g_list_find (priv->members, l->data)) { - priv->members = g_list_prepend (priv->members, - g_object_ref (l->data)); - g_signal_emit (group, signals[MEMBER_ADDED], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - /* Contacts removed */ - contacts = tp_group_get_contacts (group, removed); - for (l = contacts; l; l = l->next) { - tp_group_remove_from_pendings (group, l->data); - - /* If the contact is member, remove it and emit signal */ - if ((ll = g_list_find (priv->members, l->data))) { - g_object_unref (ll->data); - priv->members = g_list_delete_link (priv->members, ll); - g_signal_emit (group, signals[MEMBER_REMOVED], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - /* Contacts local pending */ - contacts = tp_group_get_contacts (group, local_pending); - for (l = contacts; l; l = l->next) { - /* If the contact is not yet local-pending, add it and emit signal */ - if (!g_list_find_custom (priv->local_pendings, l->data, - tp_group_local_pending_find)) { - EmpathyPendingInfo *info; - - info = empathy_pending_info_new (l->data, - actor_contact, - message); - - priv->local_pendings = g_list_prepend (priv->local_pendings, info); - g_signal_emit (group, signals[LOCAL_PENDING], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - /* Contacts remote pending */ - contacts = tp_group_get_contacts (group, remote_pending); - for (l = contacts; l; l = l->next) { - /* If the contact is not yet remote-pending, add it and emit signal */ - if (!g_list_find (priv->remote_pendings, l->data)) { - priv->remote_pendings = g_list_prepend (priv->remote_pendings, - g_object_ref (l->data)); - g_signal_emit (group, signals[REMOTE_PENDING], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - if (actor_contact) { - g_object_unref (actor_contact); - } - - DEBUG ("Members changed done for list %s:\n" - " members-len=%d\n" - " local-pendings-len=%d\n" - " remote-pendings-len=%d", - priv->group_name, g_list_length (priv->members), - g_list_length (priv->local_pendings), - g_list_length (priv->remote_pendings)); -} - -static void -tp_group_members_changed_cb (TpChannel *channel, - const gchar *message, - const GArray *added, - const GArray *removed, - const GArray *local_pending, - const GArray *remote_pending, - guint actor, - guint reason, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - if (priv->ready) { - tp_group_update_members (EMPATHY_TP_GROUP (group), message, - added, removed, - local_pending, remote_pending, - actor, reason); - } -} - -static void -tp_group_get_members_cb (TpChannel *channel, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - if (error) { - DEBUG ("Failed to get members: %s", error->message); - return; - } - - tp_group_update_members (EMPATHY_TP_GROUP (group), - NULL, /* message */ - handles, /* added */ - NULL, /* removed */ - NULL, /* local_pending */ - NULL, /* remote_pending */ - 0, /* actor */ - 0); /* reason */ - - DEBUG ("Ready"); - priv->ready = TRUE; - g_object_notify (group, "ready"); -} - -static void -tp_group_get_local_pending_cb (TpChannel *channel, - const GPtrArray *array, - const GError *error, - gpointer user_data, - GObject *group) -{ - GArray *handles; - guint i = 0; - - if (error) { - DEBUG ("Failed to get local pendings: %s", error->message); - return; - } - - handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - g_array_append_val (handles, i); - for (i = 0; array->len > i; i++) { - GValueArray *pending_struct; - const gchar *message; - guint member_handle; - guint actor_handle; - guint reason; - - pending_struct = g_ptr_array_index (array, i); - member_handle = g_value_get_uint (g_value_array_get_nth (pending_struct, 0)); - actor_handle = g_value_get_uint (g_value_array_get_nth (pending_struct, 1)); - reason = g_value_get_uint (g_value_array_get_nth (pending_struct, 2)); - message = g_value_get_string (g_value_array_get_nth (pending_struct, 3)); - - g_array_index (handles, guint, 0) = member_handle; - - tp_group_update_members (EMPATHY_TP_GROUP (group), - message, /* message */ - NULL, /* added */ - NULL, /* removed */ - handles, /* local_pending */ - NULL, /* remote_pending */ - actor_handle, /* actor */ - reason); /* reason */ - } - g_array_free (handles, TRUE); -} - -static void -tp_group_get_remote_pending_cb (TpChannel *channel, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *group) -{ - if (error) { - DEBUG ("Failed to get remote pendings: %s", error->message); - return; - } - - tp_group_update_members (EMPATHY_TP_GROUP (group), - NULL, /* message */ - NULL, /* added */ - NULL, /* removed */ - NULL, /* local_pending */ - handles, /* remote_pending */ - 0, /* actor */ - 0); /* reason */ -} - -static void -tp_group_inspect_handles_cb (TpConnection *connection, - const gchar **names, - const GError *error, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - if (error) { - DEBUG ("Failed to inspect channel handle: %s", error->message); - return; - } - - priv->group_name = g_strdup (*names); -} - -static void -tp_group_invalidated_cb (TpProxy *proxy, - guint domain, - gint code, - gchar *message, - EmpathyTpGroup *group) -{ - DEBUG ("Channel invalidated: %s", message); - g_signal_emit (group, signals[DESTROY], 0); -} - -static void -tp_group_get_self_handle_cb (TpChannel *proxy, - guint handle, - const GError *error, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - TpConnection *connection; - guint channel_handle; - guint channel_handle_type; - GArray *handles; - - if (error) { - DEBUG ("Failed to get self handle: %s", error->message); - return; - } - - priv->self_handle = handle; - tp_cli_channel_interface_group_connect_to_members_changed (priv->channel, - tp_group_members_changed_cb, - NULL, NULL, - group, NULL); - - /* GetMembers is called last, so it will be the last to get the reply, - * so we'll be ready once that call return. */ - g_object_get (priv->channel, - "connection", &connection, - "handle-type", &channel_handle_type, - "handle", &channel_handle, - NULL); - handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - g_array_prepend_val (handles, channel_handle); - tp_cli_connection_call_inspect_handles (connection, -1, - channel_handle_type, - handles, - tp_group_inspect_handles_cb, - NULL, NULL, - group); - g_array_free (handles, TRUE); - - tp_cli_channel_interface_group_call_get_local_pending_members_with_info - (priv->channel, -1, - tp_group_get_local_pending_cb, - NULL, NULL, - group); - tp_cli_channel_interface_group_call_get_remote_pending_members - (priv->channel, -1, - tp_group_get_remote_pending_cb, - NULL, NULL, - group); - tp_cli_channel_interface_group_call_get_members (priv->channel, -1, - tp_group_get_members_cb, - NULL, NULL, - group); -} - -static void -tp_group_factory_ready_cb (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (priv->factory, priv->account); - g_signal_handlers_disconnect_by_func (tp_factory, tp_group_factory_ready_cb, group); - tp_cli_channel_interface_group_call_get_self_handle (priv->channel, -1, - tp_group_get_self_handle_cb, - NULL, NULL, - G_OBJECT (group)); -} - -static void -tp_group_channel_ready_cb (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (priv->factory, - priv->account); - if (empathy_tp_contact_factory_is_ready (tp_factory)) { - tp_group_factory_ready_cb (group); - } else { - g_signal_connect_swapped (tp_factory, "notify::ready", - G_CALLBACK (tp_group_factory_ready_cb), - group); - } -} - -static void -tp_group_finalize (GObject *object) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (object); - EmpathyTpContactFactory *tp_factory; - - DEBUG ("finalize: %p", object); - - tp_factory = empathy_contact_factory_get_tp_factory (priv->factory, priv->account); - g_signal_handlers_disconnect_by_func (tp_factory, tp_group_factory_ready_cb, object); - - if (priv->channel) { - g_signal_handlers_disconnect_by_func (priv->channel, - tp_group_invalidated_cb, - object); - g_object_unref (priv->channel); - } - if (priv->account) { - g_object_unref (priv->account); - } - if (priv->factory) { - g_object_unref (priv->factory); - } - g_free (priv->group_name); - - g_list_foreach (priv->members, (GFunc) g_object_unref, NULL); - g_list_free (priv->members); - - g_list_foreach (priv->local_pendings, (GFunc) empathy_pending_info_free, NULL); - g_list_free (priv->local_pendings); - - g_list_foreach (priv->remote_pendings, (GFunc) g_object_unref, NULL); - g_list_free (priv->remote_pendings); - - G_OBJECT_CLASS (empathy_tp_group_parent_class)->finalize (object); -} - -static void -tp_group_constructed (GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - gboolean channel_ready; - - priv->factory = empathy_contact_factory_dup_singleton (); - priv->account = empathy_channel_get_account (priv->channel); - - g_signal_connect (priv->channel, "invalidated", - G_CALLBACK (tp_group_invalidated_cb), - group); - - g_object_get (priv->channel, "channel-ready", &channel_ready, NULL); - if (channel_ready) { - tp_group_channel_ready_cb (EMPATHY_TP_GROUP (group)); - } else { - g_signal_connect_swapped (priv->channel, "notify::channel-ready", - G_CALLBACK (tp_group_channel_ready_cb), - group); - } -} - -static void -tp_group_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (object); - - switch (param_id) { - case PROP_CHANNEL: - g_value_set_object (value, priv->channel); - break; - case PROP_READY: - g_value_set_boolean (value, priv->ready); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -tp_group_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (object); - - switch (param_id) { - case PROP_CHANNEL: - priv->channel = g_object_ref (g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -empathy_tp_group_class_init (EmpathyTpGroupClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = tp_group_finalize; - object_class->constructed = tp_group_constructed; - object_class->get_property = tp_group_get_property; - object_class->set_property = tp_group_set_property; - - g_object_class_install_property (object_class, - PROP_CHANNEL, - g_param_spec_object ("channel", - "telepathy channel", - "The channel for the group", - TP_TYPE_CHANNEL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, - PROP_READY, - g_param_spec_boolean ("ready", - "Is the object ready", - "This object can't be used until this becomes true", - FALSE, - G_PARAM_READABLE)); - - signals[MEMBER_ADDED] = - g_signal_new ("member-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[MEMBER_REMOVED] = - g_signal_new ("member-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[LOCAL_PENDING] = - g_signal_new ("local-pending", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[REMOTE_PENDING] = - g_signal_new ("remote-pending", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[DESTROY] = - g_signal_new ("destroy", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_type_class_add_private (object_class, sizeof (EmpathyTpGroupPriv)); -} - -static void -empathy_tp_group_init (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (group, - EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupPriv); - - group->priv = priv; -} - -EmpathyTpGroup * -empathy_tp_group_new (TpChannel *channel) -{ - g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL); - - return g_object_new (EMPATHY_TYPE_TP_GROUP, - "channel", channel, - NULL); -} - -static void -tp_group_async_cb (TpChannel *channel, - const GError *error, - gpointer user_data, - GObject *weak_object) -{ - if (error) { - DEBUG ("%s: %s", (gchar*) user_data, error->message); - } -} - -void -empathy_tp_group_close (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (priv->ready); - - tp_cli_channel_call_close (priv->channel, -1, - tp_group_async_cb, - "Failed to close", NULL, - G_OBJECT (group)); -} - -static GArray * -tp_group_get_handles (GList *contacts) -{ - GArray *handles; - guint length; - GList *l; - - length = g_list_length (contacts); - handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), length); - - for (l = contacts; l; l = l->next) { - guint handle; - - handle = empathy_contact_get_handle (l->data); - g_array_append_val (handles, handle); - } - - return handles; -} - -void -empathy_tp_group_add_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GArray *handles; - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (contacts != NULL); - g_return_if_fail (priv->ready); - - handles = tp_group_get_handles (contacts); - tp_cli_channel_interface_group_call_add_members (priv->channel, -1, - handles, - message, - tp_group_async_cb, - "Failed to add members", NULL, - G_OBJECT (group)); - g_array_free (handles, TRUE); -} - -void -empathy_tp_group_remove_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GArray *handles; - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (contacts != NULL); - g_return_if_fail (priv->ready); - - handles = tp_group_get_handles (contacts); - tp_cli_channel_interface_group_call_remove_members (priv->channel, -1, - handles, - message, - tp_group_async_cb, - "Failed to remove members", NULL, - G_OBJECT (group)); - g_array_free (handles, TRUE); -} - -void -empathy_tp_group_add_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message) -{ - GList *contacts; - - contacts = g_list_prepend (NULL, contact); - empathy_tp_group_add_members (group, contacts, message); - g_list_free (contacts); -} - -void -empathy_tp_group_remove_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message) -{ - GList *contacts; - - contacts = g_list_prepend (NULL, contact); - empathy_tp_group_remove_members (group, contacts, message); - g_list_free (contacts); -} - -GList * -empathy_tp_group_get_members (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - g_list_foreach (priv->members, (GFunc) g_object_ref, NULL); - - return g_list_copy (priv->members); -} - -GList * -empathy_tp_group_get_local_pendings (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GList *pendings = NULL, *l; - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - for (l = priv->local_pendings; l; l = l->next) { - EmpathyPendingInfo *info; - EmpathyPendingInfo *new_info; - - info = l->data; - new_info = empathy_pending_info_new (info->member, - info->actor, - info->message); - pendings = g_list_prepend (pendings, new_info); - } - - return pendings; -} - -GList * -empathy_tp_group_get_remote_pendings (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - g_list_foreach (priv->remote_pendings, (GFunc) g_object_ref, NULL); - - return g_list_copy (priv->remote_pendings); -} - -const gchar * -empathy_tp_group_get_name (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - g_return_val_if_fail (priv->ready, NULL); - - return priv->group_name; -} - -EmpathyContact * -empathy_tp_group_get_self_contact (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - g_return_val_if_fail (priv->ready, NULL); - - return tp_group_get_contact (group, priv->self_handle); -} - -gboolean -empathy_tp_group_is_member (EmpathyTpGroup *group, - EmpathyContact *contact) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), FALSE); - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - - return g_list_find (priv->members, contact) != NULL; -} - -gboolean -empathy_tp_group_is_ready (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), FALSE); - - return priv->ready; -} - -EmpathyPendingInfo * -empathy_tp_group_get_invitation (EmpathyTpGroup *group, - EmpathyContact **remote_contact) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyContact *contact = NULL; - EmpathyPendingInfo *invitation = NULL; - GList *l; - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), FALSE); - g_return_val_if_fail (priv->ready, NULL); - - for (l = priv->local_pendings; l; l = l->next) { - EmpathyPendingInfo *info = l->data; - - if (empathy_contact_is_user (info->member)) { - invitation = info; - break; - } - } - - if (invitation) { - contact = invitation->actor; - } - if (!invitation) { - if (priv->remote_pendings) { - contact = priv->remote_pendings->data; - } - else if (priv->members) { - contact = priv->members->data; - } - } - - if (remote_contact && contact) { - *remote_contact = g_object_ref (contact); - } - - return invitation; -} - -TpChannelGroupFlags -empathy_tp_group_get_flags (EmpathyTpGroup *self) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (self); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (self), 0); - - if (priv->channel == NULL) - return 0; - - return tp_channel_group_get_flags (priv->channel); -} diff --git a/libempathy/empathy-tp-group.h b/libempathy/empathy-tp-group.h deleted file mode 100644 index 9e0dd53ef..000000000 --- a/libempathy/empathy-tp-group.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Xavier Claessens <xclaesse@gmail.com> - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Xavier Claessens <xclaesse@gmail.com> - */ - -#ifndef __EMPATHY_TP_GROUP_H__ -#define __EMPATHY_TP_GROUP_H__ - -#include <glib.h> - -#include <telepathy-glib/channel.h> - -#include "empathy-contact.h" - -G_BEGIN_DECLS - -#define EMPATHY_TYPE_TP_GROUP (empathy_tp_group_get_type ()) -#define EMPATHY_TP_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroup)) -#define EMPATHY_TP_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupClass)) -#define EMPATHY_IS_TP_GROUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_TP_GROUP)) -#define EMPATHY_IS_TP_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_TP_GROUP)) -#define EMPATHY_TP_GROUP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupClass)) - -typedef struct _EmpathyTpGroup EmpathyTpGroup; -typedef struct _EmpathyTpGroupClass EmpathyTpGroupClass; - -struct _EmpathyTpGroup { - GObject parent; - gpointer priv; -}; - -struct _EmpathyTpGroupClass { - GObjectClass parent_class; -}; - -typedef struct { - EmpathyContact *member; - EmpathyContact *actor; - gchar *message; - guint reason; -} EmpathyPendingInfo; - -GType empathy_tp_group_get_type (void) G_GNUC_CONST; -EmpathyTpGroup * empathy_tp_group_new (TpChannel *channel); -void empathy_tp_group_close (EmpathyTpGroup *group); -void empathy_tp_group_add_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message); -void empathy_tp_group_add_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message); -void empathy_tp_group_remove_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message); -void empathy_tp_group_remove_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message); -GList * empathy_tp_group_get_members (EmpathyTpGroup *group); -GList * empathy_tp_group_get_local_pendings (EmpathyTpGroup *group); -GList * empathy_tp_group_get_remote_pendings (EmpathyTpGroup *group); -const gchar * empathy_tp_group_get_name (EmpathyTpGroup *group); -EmpathyContact * empathy_tp_group_get_self_contact (EmpathyTpGroup *group); -gboolean empathy_tp_group_is_member (EmpathyTpGroup *group, - EmpathyContact *contact); -gboolean empathy_tp_group_is_ready (EmpathyTpGroup *group); -EmpathyPendingInfo *empathy_tp_group_get_invitation (EmpathyTpGroup *group, - EmpathyContact **remote_contact); -EmpathyPendingInfo *empathy_pending_info_new (EmpathyContact *member, - EmpathyContact *actor, - const gchar *message); -void empathy_pending_info_free (EmpathyPendingInfo *info); -TpChannelGroupFlags empathy_tp_group_get_flags (EmpathyTpGroup *group); - -G_END_DECLS - -#endif /* __EMPATHY_TP_GROUP_H__ */ diff --git a/libempathy/empathy-tp-tube.c b/libempathy/empathy-tp-tube.c index 64e45962d..5979615ef 100644 --- a/libempathy/empathy-tp-tube.c +++ b/libempathy/empathy-tp-tube.c @@ -254,8 +254,6 @@ empathy_tp_tube_new_stream_tube (EmpathyContact *contact, const gchar *service, GHashTable *parameters) { - MissionControl *mc; - McAccount *account; TpConnection *connection; TpChannel *channel; gchar *object_path; @@ -272,12 +270,7 @@ empathy_tp_tube_new_stream_tube (EmpathyContact *contact, g_return_val_if_fail (hostname != NULL, NULL); g_return_val_if_fail (service != NULL, NULL); - mc = empathy_mission_control_dup_singleton (); - account = empathy_contact_get_account (contact); - connection = mission_control_get_tpconnection (mc, account, NULL); - g_object_unref (mc); - - tp_connection_run_until_ready (connection, FALSE, NULL, NULL); + connection = empathy_contact_get_connection (contact); request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); diff --git a/libempathy/empathy-utils.c b/libempathy/empathy-utils.c index a476d9e54..210c35048 100644 --- a/libempathy/empathy-utils.c +++ b/libempathy/empathy-utils.c @@ -37,7 +37,6 @@ #include <telepathy-glib/dbus.h> #include "empathy-utils.h" -#include "empathy-contact-factory.h" #include "empathy-contact-manager.h" #include "empathy-dispatcher.h" #include "empathy-dispatch-operation.h" @@ -332,97 +331,6 @@ empathy_file_lookup (const gchar *filename, const gchar *subdir) return path; } -typedef struct { - EmpathyRunUntilReadyFunc func; - gpointer user_data; - GObject *object; - GMainLoop *loop; -} RunUntilReadyData; - -static void -run_until_ready_cb (RunUntilReadyData *data) -{ - if (!data->func || data->func (data->object, data->user_data)) { - DEBUG ("Object %p is ready", data->object); - g_main_loop_quit (data->loop); - } -} - -static gboolean -object_is_ready (GObject *object, - gpointer user_data) -{ - gboolean ready; - - g_object_get (object, "ready", &ready, NULL); - - return ready; -} - -void -empathy_run_until_ready_full (gpointer object, - const gchar *signal, - EmpathyRunUntilReadyFunc func, - gpointer user_data, - GMainLoop **loop) -{ - RunUntilReadyData data; - gulong signal_id; - - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (signal != NULL); - - if (func && func (object, user_data)) { - return; - } - - DEBUG ("Starting run until ready for object %p", object); - - data.func = func; - data.user_data = user_data; - data.object = object; - data.loop = g_main_loop_new (NULL, FALSE); - - signal_id = g_signal_connect_swapped (object, signal, - G_CALLBACK (run_until_ready_cb), - &data); - if (loop != NULL) { - *loop = data.loop; - } - - g_main_loop_run (data.loop); - - if (loop != NULL) { - *loop = NULL; - } - - g_signal_handler_disconnect (object, signal_id); - g_main_loop_unref (data.loop); -} - -void -empathy_run_until_ready (gpointer object) -{ - empathy_run_until_ready_full (object, "notify::ready", object_is_ready, - NULL, NULL); -} - -McAccount * -empathy_channel_get_account (TpChannel *channel) -{ - TpConnection *connection; - McAccount *account; - MissionControl *mc; - - g_object_get (channel, "connection", &connection, NULL); - mc = empathy_mission_control_dup_singleton (); - account = mission_control_get_account_for_tpconnection (mc, connection, NULL); - g_object_unref (connection); - g_object_unref (mc); - - return account; -} - guint empathy_proxy_hash (gconstpointer key) { @@ -470,3 +378,4 @@ empathy_check_available_state (void) return TRUE; } + diff --git a/libempathy/empathy-utils.h b/libempathy/empathy-utils.h index 8684acc00..e6bcfebfc 100644 --- a/libempathy/empathy-utils.h +++ b/libempathy/empathy-utils.h @@ -74,16 +74,6 @@ const gchar * empathy_presence_to_str (McPresence presence); McPresence empathy_presence_from_str (const gchar *str); gchar * empathy_file_lookup (const gchar *filename, const gchar *subdir); - -typedef gboolean (*EmpathyRunUntilReadyFunc) (GObject *object, - gpointer user_data); -void empathy_run_until_ready (gpointer object); -void empathy_run_until_ready_full (gpointer object, - const gchar *signal, - EmpathyRunUntilReadyFunc func, - gpointer user_data, - GMainLoop **loop); -McAccount * empathy_channel_get_account (TpChannel *channel); gboolean empathy_proxy_equal (gconstpointer a, gconstpointer b); guint empathy_proxy_hash (gconstpointer key); diff --git a/megaphone/src/megaphone-applet.c b/megaphone/src/megaphone-applet.c index 79eaac4d8..0879e75a5 100644 --- a/megaphone/src/megaphone-applet.c +++ b/megaphone/src/megaphone-applet.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2007 Raphaël Slinckx <raphael@slinckx.net> - * Copyright (C) 2007 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,8 @@ #include <libmissioncontrol/mission-control.h> #include <libmissioncontrol/mc-account.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> +#include <libempathy/empathy-account-manager.h> #include <libempathy/empathy-contact.h> #include <libempathy/empathy-contact-list.h> #include <libempathy/empathy-contact-manager.h> @@ -52,107 +53,19 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, MegaphoneApplet) typedef struct { - EmpathyContactFactory *factory; - GtkWidget *image; - gint image_size; - EmpathyContact *contact; - GConfClient *gconf; - guint gconf_cnxn; + EmpathyTpContactFactory *factory; + EmpathyAccountManager *account_manager; + McAccount *account; + gchar *id; + GtkWidget *image; + gint image_size; + EmpathyContact *contact; + GConfClient *gconf; + guint gconf_cnxn; } MegaphoneAppletPriv; -static void megaphone_applet_finalize (GObject *object); -static void megaphone_applet_size_allocate_cb (GtkWidget *widget, - GtkAllocation *allocation, - MegaphoneApplet *applet); -static gboolean megaphone_applet_button_press_event_cb (GtkWidget *widget, - GdkEventButton *event, - MegaphoneApplet *applet); -static void megaphone_applet_information_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name); -static void megaphone_applet_preferences_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name); -static void megaphone_applet_about_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name); - G_DEFINE_TYPE(MegaphoneApplet, megaphone_applet, PANEL_TYPE_APPLET) -static const BonoboUIVerb megaphone_applet_menu_verbs [] = { - BONOBO_UI_UNSAFE_VERB ("information", megaphone_applet_information_cb), - BONOBO_UI_UNSAFE_VERB ("preferences", megaphone_applet_preferences_cb), - BONOBO_UI_UNSAFE_VERB ("about", megaphone_applet_about_cb), - BONOBO_UI_VERB_END -}; - -static const char* authors[] = { - "Raphaël Slinckx <raphael@slinckx.net>", - "Xavier Claessens <xclaesse@gmail.com>", - NULL -}; - -static void -megaphone_applet_class_init (MegaphoneAppletClass *class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (class); - - object_class->finalize = megaphone_applet_finalize; - - g_type_class_add_private (object_class, sizeof (MegaphoneAppletPriv)); - empathy_gtk_init (); -} - -static void -megaphone_applet_init (MegaphoneApplet *applet) -{ - MegaphoneAppletPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (applet, - MEGAPHONE_TYPE_APPLET, MegaphoneAppletPriv); - - applet->priv = priv; - priv->factory = empathy_contact_factory_dup_singleton (); - priv->gconf = gconf_client_get_default (); - - /* Image holds the contact avatar */ - priv->image = gtk_image_new (); - gtk_widget_show (priv->image); - gtk_container_add (GTK_CONTAINER (applet), priv->image); - - /* We want transparency */ - panel_applet_set_flags (PANEL_APPLET (applet), PANEL_APPLET_EXPAND_MINOR); - panel_applet_set_background_widget (PANEL_APPLET (applet), GTK_WIDGET (applet)); - - /* Listen for clicks on the applet to dispatch a channel */ - g_signal_connect (applet, "button-press-event", - G_CALLBACK (megaphone_applet_button_press_event_cb), - applet); - - /* Allow to resize our avatar when needed */ - g_signal_connect (applet, "size-allocate", - G_CALLBACK (megaphone_applet_size_allocate_cb), - applet); -} - -static void -megaphone_applet_finalize (GObject *object) -{ - MegaphoneAppletPriv *priv = GET_PRIV (object); - - if (priv->contact) { - g_object_unref (priv->contact); - } - g_object_unref (priv->factory); - - if (priv->gconf_cnxn != 0) { - gconf_client_notify_remove (priv->gconf, priv->gconf_cnxn); - } - g_object_unref (priv->gconf); - - G_OBJECT_CLASS (megaphone_applet_parent_class)->finalize (object); -} - static void megaphone_applet_update_icon (MegaphoneApplet *applet) { @@ -258,46 +171,42 @@ megaphone_applet_update_contact (MegaphoneApplet *applet) } static void -megaphone_applet_set_contact (MegaphoneApplet *applet, - const gchar *str) +megaphone_applet_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *applet) { MegaphoneAppletPriv *priv = GET_PRIV (applet); - McAccount *account = NULL; - gchar **strv = NULL; - - DEBUG ("Setting new contact %s", str); - /* Release old contact, if any */ - if (priv->contact) { - g_signal_handlers_disconnect_by_func (priv->contact, - megaphone_applet_update_contact, - applet); - g_object_unref (priv->contact), - priv->contact = NULL; + if (error != NULL) { + DEBUG ("Error: %s", error->message); + return; } - /* Lookup the new contact */ - if (str) { - strv = g_strsplit (str, "/", 2); - account = mc_account_lookup (strv[0]); - } - if (account) { - priv->contact = empathy_contact_factory_get_from_id (priv->factory, - account, - strv[1]); - g_object_unref (account); - } - g_strfreev (strv); + priv->contact = g_object_ref (contact); + g_signal_connect_swapped (priv->contact, "notify", + G_CALLBACK (megaphone_applet_update_contact), + applet); + megaphone_applet_update_contact (MEGAPHONE_APPLET (applet)); +} - /* Take hold of the new contact if any */ - if (priv->contact) { - /* Listen for updates on the contact, and force a first update */ - g_signal_connect_swapped (priv->contact, "notify", - G_CALLBACK (megaphone_applet_update_contact), - applet); +static void +megaphone_applet_new_connection_cb (EmpathyAccountManager *manager, + TpConnection *connection, + McAccount *account, + MegaphoneApplet *applet) +{ + MegaphoneAppletPriv *priv = GET_PRIV (applet); + + if (priv->contact || !empathy_account_equal (account, priv->account)) { + return; } - megaphone_applet_update_contact (applet); + priv->factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_id (priv->factory, priv->id, + megaphone_applet_got_contact_cb, + NULL, NULL, G_OBJECT (applet)); } static void @@ -312,7 +221,7 @@ megaphone_applet_preferences_response_cb (GtkWidget *dialog, /* Retrieve the selected contact, if any and set it up in gconf. * GConf will notify us from the change and we will adjust ourselves */ contact_list = g_object_get_data (G_OBJECT (dialog), "contact-list"); - contact = empathy_contact_list_view_get_selected (contact_list); + contact = empathy_contact_list_view_dup_selected (contact_list); if (contact) { McAccount *account; const gchar *account_id; @@ -331,6 +240,7 @@ megaphone_applet_preferences_response_cb (GtkWidget *dialog, "contact_id", str, NULL); g_free (str); + g_object_unref (contact); } } gtk_widget_destroy (dialog); @@ -384,42 +294,6 @@ megaphone_applet_show_preferences (MegaphoneApplet *applet) gtk_widget_show (dialog); } -static void -megaphone_applet_information_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name) -{ - MegaphoneAppletPriv *priv = GET_PRIV (applet); - - /* FIXME: We should grey out the menu item if there are no available contact */ - if (priv->contact) { - empathy_contact_information_dialog_show (priv->contact, NULL, FALSE, FALSE); - } -} - -static void -megaphone_applet_preferences_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name) -{ - megaphone_applet_show_preferences (applet); -} - -static void -megaphone_applet_about_cb (BonoboUIComponent *uic, - MegaphoneApplet *applet, - const gchar *verb_name) -{ - gtk_show_about_dialog (NULL, - "name", "Megaphone", - "version", PACKAGE_VERSION, - "copyright", "Raphaël Slinckx 2007\nCollabora Ltd 2007", - "comments", _("Talk!"), - "authors", authors, - "logo-icon-name", "stock_people", - NULL); -} - static gboolean megaphone_applet_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, @@ -479,6 +353,144 @@ megaphone_applet_size_allocate_cb (GtkWidget *widget, } static void +megaphone_applet_finalize (GObject *object) +{ + MegaphoneAppletPriv *priv = GET_PRIV (object); + + if (priv->contact) { + g_object_unref (priv->contact); + } + if (priv->factory) { + g_object_unref (priv->factory); + } + if (priv->account_manager) { + g_signal_handlers_disconnect_by_func (priv->account_manager, + megaphone_applet_new_connection_cb, object); + g_object_unref (priv->account_manager); + } + + if (priv->gconf_cnxn != 0) { + gconf_client_notify_remove (priv->gconf, priv->gconf_cnxn); + } + g_object_unref (priv->gconf); + g_free (priv->id); + + G_OBJECT_CLASS (megaphone_applet_parent_class)->finalize (object); +} + +static void +megaphone_applet_class_init (MegaphoneAppletClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + + object_class->finalize = megaphone_applet_finalize; + + g_type_class_add_private (object_class, sizeof (MegaphoneAppletPriv)); + empathy_gtk_init (); +} + +static void +megaphone_applet_init (MegaphoneApplet *applet) +{ + MegaphoneAppletPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (applet, + MEGAPHONE_TYPE_APPLET, MegaphoneAppletPriv); + + applet->priv = priv; + priv->gconf = gconf_client_get_default (); + priv->account_manager = empathy_account_manager_dup_singleton (); + g_signal_connect (priv->account_manager, "new-connection", + G_CALLBACK (megaphone_applet_new_connection_cb), applet); + + /* Image holds the contact avatar */ + priv->image = gtk_image_new (); + gtk_widget_show (priv->image); + gtk_container_add (GTK_CONTAINER (applet), priv->image); + + /* We want transparency */ + panel_applet_set_flags (PANEL_APPLET (applet), PANEL_APPLET_EXPAND_MINOR); + panel_applet_set_background_widget (PANEL_APPLET (applet), GTK_WIDGET (applet)); + + /* Listen for clicks on the applet to dispatch a channel */ + g_signal_connect (applet, "button-press-event", + G_CALLBACK (megaphone_applet_button_press_event_cb), + applet); + + /* Allow to resize our avatar when needed */ + g_signal_connect (applet, "size-allocate", + G_CALLBACK (megaphone_applet_size_allocate_cb), + applet); +} + +static void +megaphone_applet_set_contact (MegaphoneApplet *applet, + const gchar *str) +{ + MegaphoneAppletPriv *priv = GET_PRIV (applet); + TpConnection *connection; + gchar **strv = NULL; + + DEBUG ("Setting new contact %s", str); + + /* Release old contact, if any */ + if (priv->contact) { + g_signal_handlers_disconnect_by_func (priv->contact, + megaphone_applet_update_contact, + applet); + g_object_unref (priv->contact), + priv->contact = NULL; + } + if (priv->account) { + g_object_unref (priv->account), + priv->account = NULL; + } + if (priv->factory) { + g_object_unref (priv->factory), + priv->factory = NULL; + } + + /* Lookup the new contact */ + if (str) { + strv = g_strsplit (str, "/", 2); + priv->account = mc_account_lookup (strv[0]); + priv->id = strv[1]; + g_free (strv[0]); + g_free (strv); + } + + if (priv->account) { + connection = empathy_account_manager_get_connection ( + priv->account_manager, priv->account); + if (connection) { + megaphone_applet_new_connection_cb (priv->account_manager, + connection, priv->account, applet); + } + } +} + +static void +megaphone_applet_information_cb (BonoboUIComponent *uic, + MegaphoneApplet *applet, + const gchar *verb_name) +{ + MegaphoneAppletPriv *priv = GET_PRIV (applet); + + /* FIXME: We should grey out the menu item if there are no available contact */ + if (priv->contact) { + empathy_contact_information_dialog_show (priv->contact, NULL); + } +} + +static void +megaphone_applet_preferences_cb (BonoboUIComponent *uic, + MegaphoneApplet *applet, + const gchar *verb_name) +{ + megaphone_applet_show_preferences (applet); +} + +static void megaphone_applet_gconf_notify_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, @@ -497,6 +509,34 @@ megaphone_applet_gconf_notify_cb (GConfClient *client, } } +static void +megaphone_applet_about_cb (BonoboUIComponent *uic, + MegaphoneApplet *applet, + const gchar *verb_name) +{ + const char* authors[] = { + "Raphaël Slinckx <raphael@slinckx.net>", + "Xavier Claessens <xclaesse@gmail.com>", + NULL + }; + + gtk_show_about_dialog (NULL, + "name", "Megaphone", + "version", PACKAGE_VERSION, + "copyright", "Raphaël Slinckx 2007\nCollabora Ltd 2007", + "comments", _("Talk!"), + "authors", authors, + "logo-icon-name", "stock_people", + NULL); +} + +static const BonoboUIVerb megaphone_applet_menu_verbs [] = { + BONOBO_UI_UNSAFE_VERB ("information", megaphone_applet_information_cb), + BONOBO_UI_UNSAFE_VERB ("preferences", megaphone_applet_preferences_cb), + BONOBO_UI_UNSAFE_VERB ("about", megaphone_applet_about_cb), + BONOBO_UI_VERB_END +}; + static gboolean megaphone_applet_factory (PanelApplet *applet, const gchar *iid, diff --git a/po/POTFILES.in b/po/POTFILES.in index 1fbad0bc6..c29bb60c7 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -37,7 +37,8 @@ libempathy-gtk/empathy-log-window.c [type: gettext/glade]libempathy-gtk/empathy-log-window.ui [type: gettext/glade]libempathy-gtk/empathy-new-message-dialog.ui libempathy-gtk/empathy-presence-chooser.c -[type: gettext/glade]libempathy-gtk/empathy-presence-chooser.ui +libempathy-gtk/empathy-status-preset-dialog.c +[type: gettext/glade]libempathy-gtk/empathy-status-preset-dialog.ui libempathy-gtk/empathy-theme-boxes.c libempathy-gtk/empathy-theme-irc.c libempathy-gtk/empathy-theme-manager.c diff --git a/python/pyempathy/pyempathy.defs b/python/pyempathy/pyempathy.defs index 09849b986..3e9fd624c 100644 --- a/python/pyempathy/pyempathy.defs +++ b/python/pyempathy/pyempathy.defs @@ -42,13 +42,6 @@ (gtype-id "EMPATHY_TYPE_CONTACT") ) -(define-object ContactFactory - (in-module "Empathy") - (parent "GObject") - (c-name "EmpathyContactFactory") - (gtype-id "EMPATHY_TYPE_CONTACT_FACTORY") -) - (define-interface ContactList (in-module "Empathy") (c-name "EmpathyContactList") @@ -169,13 +162,6 @@ (gtype-id "EMPATHY_TYPE_TP_FILE") ) -(define-object TpGroup - (in-module "Empathy") - (parent "GObject") - (c-name "EmpathyTpGroup") - (gtype-id "EMPATHY_TYPE_TP_GROUP") -) - (define-object TpRoomlist (in-module "Empathy") (parent "GObject") @@ -212,19 +198,6 @@ ) ) -(define-flags ContactReady - (in-module "Empathy") - (c-name "EmpathyContactReady") - (gtype-id "EMPATHY_TYPE_CONTACT_READY") - (values - '("none" "EMPATHY_CONTACT_READY_NONE") - '("id" "EMPATHY_CONTACT_READY_ID") - '("handle" "EMPATHY_CONTACT_READY_HANDLE") - '("name" "EMPATHY_CONTACT_READY_NAME") - '("all" "EMPATHY_CONTACT_READY_ALL") - ) -) - (define-flags DebugFlags (in-module "Empathy") (c-name "EmpathyDebugFlags") @@ -307,6 +280,36 @@ (return-type "int") ) +(define-method get_account + (of-object "EmpathyAccountManager") + (c-name "empathy_account_manager_get_account") + (return-type "McAccount*") + (parameters + '("TpConnection*" "connection") + ) +) + +(define-method dup_accounts + (of-object "EmpathyAccountManager") + (c-name "empathy_account_manager_dup_accounts") + (return-type "GList*") +) + +(define-method get_connection + (of-object "EmpathyAccountManager") + (c-name "empathy_account_manager_get_connection") + (return-type "TpConnection*") + (parameters + '("McAccount*" "account") + ) +) + +(define-method dup_connections + (of-object "EmpathyAccountManager") + (c-name "empathy_account_manager_dup_connections") + (return-type "GList*") +) + ;; From empathy-chatroom.h @@ -635,18 +638,14 @@ (is-constructor-of "EmpathyContact") (return-type "EmpathyContact*") (parameters - '("McAccount*" "account") + '("TpContact*" "tp_contact") ) ) -(define-function contact_new_full - (c-name "empathy_contact_new_full") - (return-type "EmpathyContact*") - (parameters - '("McAccount*" "account") - '("const-gchar*" "id") - '("const-gchar*" "name") - ) +(define-method get_tp_contact + (of-object "EmpathyContact") + (c-name "empathy_contact_get_tp_contact") + (return-type "TpContact*") ) (define-method get_id @@ -700,13 +699,10 @@ (return-type "McAccount*") ) -(define-method set_account +(define-method get_connection (of-object "EmpathyContact") - (c-name "empathy_contact_set_account") - (return-type "none") - (parameters - '("McAccount*" "account") - ) + (c-name "empathy_contact_get_connection") + (return-type "TpConnection*") ) (define-method get_presence @@ -769,12 +765,6 @@ ) ) -(define-method get_ready - (of-object "EmpathyContact") - (c-name "empathy_contact_get_ready") - (return-type "EmpathyContactReady") -) - (define-method is_user (of-object "EmpathyContact") (c-name "empathy_contact_is_user") @@ -814,15 +804,6 @@ (return-type "gboolean") ) -(define-function contact_equal - (c-name "empathy_contact_equal") - (return-type "gboolean") - (parameters - '("gconstpointer" "v1") - '("gconstpointer" "v2") - ) -) - (define-function contact_hash (c-name "empathy_contact_hash") (return-type "guint") @@ -831,29 +812,6 @@ ) ) -(define-method call_when_ready - (of-object "EmpathyContact") - (c-name "empathy_contact_call_when_ready") - (return-type "none") - (parameters - '("EmpathyContactReady" "ready") - '("EmpathyContactReadyCb*" "callback") - '("gpointer" "user_data") - '("GDestroyNotify" "destroy") - '("GObject*" "weak_object") - ) -) - -(define-method run_until_ready - (of-object "EmpathyContact") - (c-name "empathy_contact_run_until_ready") - (return-type "none") - (parameters - '("EmpathyContactReady" "ready") - '("GMainLoop**" "loop") - ) -) - (define-method load_avatar_data (of-object "EmpathyContact") (c-name "empathy_contact_load_avatar_data") @@ -916,90 +874,6 @@ -;; From empathy-contact-factory.h - -(define-function contact_factory_get_type - (c-name "empathy_contact_factory_get_type") - (return-type "GType") -) - -(define-function contact_factory_dup_singleton - (c-name "empathy_contact_factory_dup_singleton") - (return-type "EmpathyContactFactory*") -) - -(define-method get_tp_factory - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_tp_factory") - (return-type "EmpathyTpContactFactory*") - (parameters - '("McAccount*" "account") - ) -) - -(define-method get_user - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_user") - (return-type "EmpathyContact*") - (parameters - '("McAccount*" "account") - ) -) - -(define-method get_from_id - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_from_id") - (return-type "EmpathyContact*") - (parameters - '("McAccount*" "account") - '("const-gchar*" "id") - ) -) - -(define-method get_from_handle - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_from_handle") - (return-type "EmpathyContact*") - (parameters - '("McAccount*" "account") - '("guint" "handle") - ) -) - -(define-method get_from_handles - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_get_from_handles") - (return-type "GList*") - (parameters - '("McAccount*" "account") - '("const-GArray*" "handles") - ) -) - -(define-method set_alias - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_set_alias") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "alias") - ) -) - -(define-method set_avatar - (of-object "EmpathyContactFactory") - (c-name "empathy_contact_factory_set_avatar") - (return-type "none") - (parameters - '("McAccount*" "account") - '("const-gchar*" "data") - '("gsize" "size") - '("const-gchar*" "mime_type") - ) -) - - - ;; From empathy-contact-groups.h (define-function contact_groups_get_all @@ -1144,7 +1018,7 @@ (c-name "empathy_contact_manager_get_list") (return-type "EmpathyTpContactList*") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") ) ) @@ -1153,7 +1027,7 @@ (c-name "empathy_contact_manager_can_add") (return-type "gboolean") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") ) ) @@ -1227,28 +1101,18 @@ (c-name "empathy_dispatcher_create_channel") (return-type "none") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") '("GHashTable*" "request") '("EmpathyDispatcherRequestCb*" "callback") '("gpointer" "user_data") ) ) -(define-function dispatcher_call_with_contact - (c-name "empathy_dispatcher_call_with_contact") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("EmpathyDispatcherRequestCb*" "callback") - '("gpointer" "user_data") - ) -) - (define-function dispatcher_chat_with_contact_id (c-name "empathy_dispatcher_chat_with_contact_id") (return-type "none") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") '("const-gchar*" "contact_id") '("EmpathyDispatcherRequestCb*" "callback") '("gpointer" "user_data") @@ -1283,7 +1147,7 @@ (c-name "empathy_dispatcher_join_muc") (return-type "none") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") '("const-gchar*" "roomname") '("EmpathyDispatcherRequestCb*" "callback") '("gpointer" "user_data") @@ -1295,7 +1159,7 @@ (c-name "empathy_dispatcher_find_channel_class") (return-type "GStrv") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") '("const-gchar*" "channel_type") '("guint" "handle_type") ) @@ -2229,28 +2093,22 @@ (return-type "EmpathyContact*") ) -(define-method get_account - (of-object "EmpathyTpChat") - (c-name "empathy_tp_chat_get_account") - (return-type "McAccount*") -) - (define-method get_channel (of-object "EmpathyTpChat") (c-name "empathy_tp_chat_get_channel") (return-type "TpChannel*") ) -(define-method is_ready +(define-method get_connection (of-object "EmpathyTpChat") - (c-name "empathy_tp_chat_is_ready") - (return-type "gboolean") + (c-name "empathy_tp_chat_get_connection") + (return-type "TpConnection*") ) -(define-method get_members_count +(define-method is_ready (of-object "EmpathyTpChat") - (c-name "empathy_tp_chat_get_members_count") - (return-type "guint") + (c-name "empathy_tp_chat_is_ready") + (return-type "gboolean") ) (define-method send @@ -2314,45 +2172,39 @@ (return-type "GType") ) -(define-function tp_contact_factory_new - (c-name "empathy_tp_contact_factory_new") - (is-constructor-of "EmpathyTpContactFactory") +(define-function tp_contact_factory_dup_singleton + (c-name "empathy_tp_contact_factory_dup_singleton") (return-type "EmpathyTpContactFactory*") (parameters - '("McAccount*" "account") - ) -) - -(define-method get_user - (of-object "EmpathyTpContactFactory") - (c-name "empathy_tp_contact_factory_get_user") - (return-type "EmpathyContact*") -) - -(define-method get_from_id - (of-object "EmpathyTpContactFactory") - (c-name "empathy_tp_contact_factory_get_from_id") - (return-type "EmpathyContact*") - (parameters - '("const-gchar*" "id") + '("TpConnection*" "connection") ) ) -(define-method get_from_handle +(define-method get_from_ids (of-object "EmpathyTpContactFactory") - (c-name "empathy_tp_contact_factory_get_from_handle") - (return-type "EmpathyContact*") + (c-name "empathy_tp_contact_factory_get_from_ids") + (return-type "none") (parameters - '("guint" "handle") + '("guint" "n_ids") + '("const-gchar*-const*" "ids") + '("EmpathyTpContactFactoryGotContactsCb" "callback") + '("gpointer" "user_data") + '("GDestroyNotify" "destroy") + '("GObject*" "weak_object") ) ) (define-method get_from_handles (of-object "EmpathyTpContactFactory") (c-name "empathy_tp_contact_factory_get_from_handles") - (return-type "GList*") + (return-type "none") (parameters - '("const-GArray*" "handles") + '("guint" "n_handles") + '("const-TpHandle*" "handles") + '("EmpathyTpContactFactoryGotContactsCb" "callback") + '("gpointer" "user_data") + '("GDestroyNotify" "destroy") + '("GObject*" "weak_object") ) ) @@ -2377,12 +2229,6 @@ ) ) -(define-method is_ready - (of-object "EmpathyTpContactFactory") - (c-name "empathy_tp_contact_factory_is_ready") - (return-type "gboolean") -) - ;; From empathy-tp-contact-list.h @@ -2397,14 +2243,14 @@ (is-constructor-of "EmpathyTpContactList") (return-type "EmpathyTpContactList*") (parameters - '("McAccount*" "account") + '("TpConnection*" "connection") ) ) -(define-method get_account +(define-method get_connection (of-object "EmpathyTpContactList") - (c-name "empathy_tp_contact_list_get_account") - (return-type "McAccount*") + (c-name "empathy_tp_contact_list_get_connection") + (return-type "TpConnection*") ) (define-method can_add @@ -2413,6 +2259,12 @@ (return-type "gboolean") ) +(define-method remove_all + (of-object "EmpathyTpContactList") + (c-name "empathy_tp_contact_list_remove_all") + (return-type "none") +) + ;; From empathy-tp-file.h @@ -2521,147 +2373,12 @@ (return-type "const-gchar*") ) - - -;; From empathy-tp-group.h - -(define-function tp_group_get_type - (c-name "empathy_tp_group_get_type") - (return-type "GType") -) - -(define-function tp_group_new - (c-name "empathy_tp_group_new") - (is-constructor-of "EmpathyTpGroup") - (return-type "EmpathyTpGroup*") - (parameters - '("TpChannel*" "channel") - ) -) - -(define-method close - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_close") - (return-type "none") -) - -(define-method add_members - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_add_members") - (return-type "none") - (parameters - '("GList*" "contacts") - '("const-gchar*" "message") - ) -) - -(define-method add_member - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_add_member") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "message") - ) -) - -(define-method remove_members - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_remove_members") - (return-type "none") - (parameters - '("GList*" "contacts") - '("const-gchar*" "message") - ) -) - -(define-method remove_member - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_remove_member") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "message") - ) -) - -(define-method get_members - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_members") - (return-type "GList*") -) - -(define-method get_local_pendings - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_local_pendings") - (return-type "GList*") -) - -(define-method get_remote_pendings - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_remote_pendings") - (return-type "GList*") -) - -(define-method get_name - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_name") - (return-type "const-gchar*") -) - -(define-method get_self_contact - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_self_contact") - (return-type "EmpathyContact*") -) - -(define-method is_member - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_is_member") - (return-type "gboolean") - (parameters - '("EmpathyContact*" "contact") - ) -) - (define-method is_ready - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_is_ready") + (of-object "EmpathyTpFile") + (c-name "empathy_tp_file_is_ready") (return-type "gboolean") ) -(define-method get_invitation - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_invitation") - (return-type "EmpathyPendingInfo*") - (parameters - '("EmpathyContact**" "remote_contact") - ) -) - -(define-function pending_info_new - (c-name "empathy_pending_info_new") - (is-constructor-of "EmpathyPendingInfo") - (return-type "EmpathyPendingInfo*") - (parameters - '("EmpathyContact*" "member") - '("EmpathyContact*" "actor") - '("const-gchar*" "message") - ) -) - -(define-method free - (of-object "EmpathyPendingInfo") - (c-name "empathy_pending_info_free") - (return-type "none") -) - -(define-method get_flags - (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_flags") - (return-type "TpChannelGroupFlags") -) - ;; From empathy-tp-roomlist.h @@ -2911,34 +2628,6 @@ ) ) -(define-function run_until_ready - (c-name "empathy_run_until_ready") - (return-type "none") - (parameters - '("gpointer" "object") - ) -) - -(define-function run_until_ready_full - (c-name "empathy_run_until_ready_full") - (return-type "none") - (parameters - '("gpointer" "object") - '("const-gchar*" "signal") - '("EmpathyRunUntilReadyFunc" "func") - '("gpointer" "user_data") - '("GMainLoop**" "loop") - ) -) - -(define-function channel_get_account - (c-name "empathy_channel_get_account") - (return-type "McAccount*") - (parameters - '("TpChannel*" "channel") - ) -) - (define-function proxy_equal (c-name "empathy_proxy_equal") (return-type "gboolean") diff --git a/python/pyempathy/pyempathy.override b/python/pyempathy/pyempathy.override index 72d7ccb0e..e4c99086c 100644 --- a/python/pyempathy/pyempathy.override +++ b/python/pyempathy/pyempathy.override @@ -7,7 +7,6 @@ headers #include "empathy-chatroom.h" #include "empathy-chatroom-manager.h" #include "empathy-contact.h" -#include "empathy-contact-factory.h" #include "empathy-contact-groups.h" #include "empathy-contact-list.h" #include "empathy-contact-manager.h" @@ -29,7 +28,6 @@ headers #include "empathy-tp-contact-factory.h" #include "empathy-tp-contact-list.h" #include "empathy-tp-file.h" -#include "empathy-tp-group.h" #include "empathy-tp-roomlist.h" #include "empathy-tp-tube.h" #include "empathy-tube-handler.h" @@ -66,25 +64,3 @@ _wrap_empathy_contact_list_get_members(PyGObject *self, PyObject *args, PyObject } %% -override empathy_dispatcher_chat_with_contact_id kwargs -static PyObject * -_wrap_empathy_dispatcher_chat_with_contact_id(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = { "account_id", "contact_id", NULL }; - char *account_id, *contact_id; - McAccount *account; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs,"ss:dispatcher_chat_with_contact_id", kwlist, &account_id, &contact_id)) - return NULL; - - account = mc_account_lookup (account_id); - if (account) { - empathy_dispatcher_chat_with_contact_id(account, contact_id, - NULL, NULL); - g_object_unref (account); - } - - Py_INCREF(Py_None); - return Py_None; -} -%% diff --git a/python/pyempathygtk/pyempathygtk.defs b/python/pyempathygtk/pyempathygtk.defs index e12da4859..df829a031 100644 --- a/python/pyempathygtk/pyempathygtk.defs +++ b/python/pyempathygtk/pyempathygtk.defs @@ -284,6 +284,12 @@ (return-type "McAccount*") ) +(define-method get_connection + (of-object "EmpathyAccountChooser") + (c-name "empathy_account_chooser_get_connection") + (return-type "TpConnection*") +) + (define-method set_account (of-object "EmpathyAccountChooser") (c-name "empathy_account_chooser_set_account") @@ -618,12 +624,6 @@ (return-type "EmpathyContact*") ) -(define-method get_members_count - (of-object "EmpathyChat") - (c-name "empathy_chat_get_members_count") - (return-type "guint") -) - (define-method get_contact_menu (of-object "EmpathyChat") (c-name "empathy_chat_get_contact_menu") @@ -966,8 +966,23 @@ (return-type "none") (parameters '("GtkWindow*" "parent") - '("gboolean" "edit") - '("gboolean" "is_user") + ) +) + +(define-method edit_dialog_show + (of-object "EmpathyContact") + (c-name "empathy_contact_edit_dialog_show") + (return-type "none") + (parameters + '("GtkWindow*" "parent") + ) +) + +(define-function contact_personal_dialog_show + (c-name "empathy_contact_personal_dialog_show") + (return-type "none") + (parameters + '("GtkWindow*" "parent") ) ) diff --git a/python/update-binding.sh b/python/update-binding.sh index 9023be21a..14a5ddec3 100755 --- a/python/update-binding.sh +++ b/python/update-binding.sh @@ -11,7 +11,6 @@ python /usr/share/pygobject/2.0/codegen/h2def.py \ empathy-call-factory.h \ empathy-call-handler.h \ empathy-contact.h \ - empathy-contact-factory.h \ empathy-contact-groups.h \ empathy-contact-list.h \ empathy-contact-manager.h \ @@ -34,7 +33,6 @@ python /usr/share/pygobject/2.0/codegen/h2def.py \ empathy-tp-contact-factory.h \ empathy-tp-contact-list.h \ empathy-tp-file.h \ - empathy-tp-group.h \ empathy-tp-roomlist.h \ empathy-tp-tube.h \ empathy-tube-handler.h \ diff --git a/src/empathy-accounts-dialog.c b/src/empathy-accounts-dialog.c index 036c7f86b..e15c0eab1 100644 --- a/src/empathy-accounts-dialog.c +++ b/src/empathy-accounts-dialog.c @@ -819,13 +819,14 @@ accounts_dialog_button_create_clicked_cb (GtkWidget *button, gchar *str; McProfileCapabilityFlags cap; - profile = empathy_profile_chooser_get_selected (dialog->combobox_profile); + profile = empathy_profile_chooser_dup_selected (dialog->combobox_profile); /* Create account */ account = mc_account_create (profile); if (account == NULL) { /* We can't display an error to the user as MC doesn't give us * any clue about the reason of the failure... */ + g_object_unref (profile); return; } @@ -869,7 +870,7 @@ accounts_dialog_profile_changed_cb (GtkWidget *widget, McProfile *profile; McProfileCapabilityFlags cap; - profile = empathy_profile_chooser_get_selected (dialog->combobox_profile); + profile = empathy_profile_chooser_dup_selected (dialog->combobox_profile); cap = mc_profile_get_capabilities (profile); if (cap & MC_PROFILE_CAPABILITY_REGISTRATION_UI) { diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index d7d79df90..01c2c4f5c 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -107,6 +107,7 @@ struct _EmpathyCallWindowPriv GMutex *lock; gboolean call_started; + gboolean sending_video; }; #define GET_PRIV(o) \ @@ -757,6 +758,7 @@ empathy_call_window_disconnected (EmpathyCallWindow *self) gtk_widget_set_sensitive (priv->camera_button, FALSE); gtk_action_set_sensitive (priv->send_video, FALSE); + priv->sending_video = FALSE; } @@ -1157,20 +1159,35 @@ static void empathy_call_window_camera_toggled_cb (GtkToggleToolButton *toggle, EmpathyCallWindow *window) { + EmpathyCallWindowPriv *priv = GET_PRIV (window); gboolean active; active = (gtk_toggle_tool_button_get_active (toggle)); + + if (priv->sending_video == active) + return; + empathy_call_window_set_send_video (window, active); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), active); + priv->sending_video = active; } static void empathy_call_window_send_video_toggled_cb (GtkToggleAction *toggle, EmpathyCallWindow *window) { + EmpathyCallWindowPriv *priv = GET_PRIV (window); gboolean active; active = (gtk_toggle_action_get_active (toggle)); + + if (priv->sending_video == active) + return; + empathy_call_window_set_send_video (window, active); + gtk_toggle_tool_button_set_active ( + GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), active); + priv->sending_video = active; } static void diff --git a/src/empathy-call-window.ui b/src/empathy-call-window.ui index 00b8ffa88..ce3d85b56 100644 --- a/src/empathy-call-window.ui +++ b/src/empathy-call-window.ui @@ -14,6 +14,7 @@ <object class="GtkToggleAction" id="send_video"> <property name="name">send_video</property> <property name="label" translatable="yes">Send video</property> + <property name="sensitive">False</property> </object> </child> <child> diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index 145d45e7f..0738f6e52 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -37,11 +37,11 @@ #include <telepathy-glib/util.h> #include <libmissioncontrol/mission-control.h> -#include <libempathy/empathy-contact-factory.h> #include <libempathy/empathy-contact.h> #include <libempathy/empathy-message.h> #include <libempathy/empathy-dispatcher.h> #include <libempathy/empathy-chatroom-manager.h> +#include <libempathy/empathy-account-manager.h> #include <libempathy/empathy-utils.h> #include <libempathy-gtk/empathy-images.h> @@ -953,7 +953,7 @@ chat_window_new_message_cb (EmpathyChat *chat, if (has_focus && priv->current_chat == chat) { return; } - + /* If empathy_chat_is_room() returns TRUE, that means it's a named MUC. * If empathy_chat_get_remote_contact() returns NULL, that means it's * an unamed MUC (msn-like). @@ -1161,17 +1161,33 @@ chat_window_drag_data_received (GtkWidget *widget, McAccount *account; const gchar *id; gchar **strv; + const gchar *account_id; + const gchar *contact_id; id = (const gchar*) selection->data; DEBUG ("DND contact from roster with id:'%s'", id); strv = g_strsplit (id, "/", 2); - account = mc_account_lookup (strv[0]); - chat = empathy_chat_window_find_chat (account, strv[1]); + account_id = strv[0]; + contact_id = strv[1]; + account = mc_account_lookup (account_id); + chat = empathy_chat_window_find_chat (account, contact_id); if (!chat) { - empathy_dispatcher_chat_with_contact_id (account, strv[2], NULL, NULL); + EmpathyAccountManager *account_manager; + TpConnection *connection; + + account_manager = empathy_account_manager_dup_singleton (); + connection = empathy_account_manager_get_connection ( + account_manager, account); + + if (connection) { + empathy_dispatcher_chat_with_contact_id ( + connection, contact_id, NULL, NULL); + } + + g_object_unref (account_manager); g_object_unref (account); g_strfreev (strv); return; @@ -1700,17 +1716,3 @@ empathy_chat_window_present_chat (EmpathyChat *chat) gtk_widget_grab_focus (chat->input_text_view); } -#if 0 -static gboolean -chat_window_should_play_sound (EmpathyChatWindow *window) -{ - EmpathyChatWindowPriv *priv = GET_PRIV (window); - gboolean has_focus = FALSE; - - g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (window), FALSE); - - g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL); - - return !has_focus; -} -#endif diff --git a/src/empathy-chatrooms-window.c b/src/empathy-chatrooms-window.c index acd559e5f..fa63d5a51 100644 --- a/src/empathy-chatrooms-window.c +++ b/src/empathy-chatrooms-window.c @@ -318,7 +318,7 @@ chatrooms_window_model_refresh_data (EmpathyChatroomsWindow *window, /* Look up chatrooms */ account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); chatrooms = empathy_chatroom_manager_get_chatrooms (window->manager, account); @@ -509,7 +509,7 @@ chatrooms_window_chatroom_added_cb (EmpathyChatroomManager *manager, McAccount *account; account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); if (!account) { chatrooms_window_model_add (window, chatroom, FALSE); diff --git a/src/empathy-event-manager.c b/src/empathy-event-manager.c index adb5e73f9..7d8721c3e 100644 --- a/src/empathy-event-manager.c +++ b/src/empathy-event-manager.c @@ -27,10 +27,11 @@ #include <telepathy-glib/util.h> #include <libempathy/empathy-dispatcher.h> -#include <libempathy/empathy-contact-factory.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-contact-manager.h> #include <libempathy/empathy-tp-chat.h> #include <libempathy/empathy-tp-call.h> +#include <libempathy/empathy-tp-file.h> #include <libempathy/empathy-utils.h> #include <libempathy/empathy-call-factory.h> @@ -500,21 +501,12 @@ event_manager_operation_invalidated_cb (EmpathyDispatchOperation *operation, } static void -event_manager_media_channel_got_name_cb (EmpathyContact *contact, - const GError *error, gpointer user_data, GObject *object) +event_manager_media_channel_got_contact (EventManagerApproval *approval) { - EventManagerApproval *approval = user_data; gchar *header; - if (error != NULL) - { - /* FIXME just returning assuming the operation will be invalidated as - * well */ - return; - } - header = g_strdup_printf (_("Incoming call from %s"), - empathy_contact_get_name (contact)); + empathy_contact_get_name (approval->contact)); event_manager_add (approval->manager, approval->contact, EMPATHY_IMAGE_VOIP, header, NULL, @@ -525,14 +517,6 @@ event_manager_media_channel_got_name_cb (EmpathyContact *contact, } static void -event_manager_media_channel_got_contact (EventManagerApproval *approval) -{ - empathy_contact_call_when_ready (approval->contact, - EMPATHY_CONTACT_READY_NAME, event_manager_media_channel_got_name_cb, - approval, NULL, G_OBJECT (approval->manager)); -} - -static void event_manager_media_channel_contact_changed_cb (EmpathyTpCall *call, GParamSpec *param, EventManagerApproval *approval) { @@ -604,23 +588,27 @@ event_manager_tube_dispatch_ability_cb (GObject *object, } static void -event_manager_tube_got_contact_name_cb (EmpathyContact *contact, - const GError *error, gpointer user_data, GObject *object) +event_manager_tube_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *object) { EventManagerApproval *approval = (EventManagerApproval *)user_data; EmpathyTubeDispatchAbility dispatchability; if (error != NULL) { - /* FIXME?, we assume that the operation gets invalidated as well (if it - * didn't already */ - return; + /* FIXME: We should probably still display the event */ + DEBUG ("Error: %s", error->message); + return; } + approval->contact = g_object_ref (contact); + dispatchability = empathy_tube_dispatch_is_dispatchable (approval->tube_dispatch); - switch (dispatchability) { case EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN: @@ -724,10 +712,11 @@ event_room_channel_process_func (EventPriv *event) } static void -event_manager_muc_invite_got_contact_name_cb (EmpathyContact *contact, - const GError *error, - gpointer user_data, - GObject *object) +event_manager_muc_invite_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *object) { EventManagerApproval *approval = (EventManagerApproval *) user_data; TpChannel *channel; @@ -735,6 +724,14 @@ event_manager_muc_invite_got_contact_name_cb (EmpathyContact *contact, gchar *msg; TpHandle self_handle; + if (error != NULL) + { + /* FIXME: We should probably still display the event */ + DEBUG ("Error: %s", error->message); + return; + } + + approval->contact = g_object_ref (contact); channel = empathy_dispatch_operation_get_channel (approval->operation); self_handle = tp_channel_group_get_self_handle (channel); @@ -795,24 +792,20 @@ event_manager_approve_channel_cb (EmpathyDispatcher *dispatcher, channel, self_handle, &inviter, NULL, NULL)) { /* We are invited to a room */ - EmpathyContactFactory *contact_factory; - McAccount *account; + EmpathyTpContactFactory *factory; + TpConnection *connection; DEBUG ("Have been invited to %s. Ask user if he wants to accept", tp_channel_get_identifier (channel)); - account = empathy_tp_chat_get_account (tp_chat); - contact_factory = empathy_contact_factory_dup_singleton (); + connection = empathy_tp_chat_get_connection (tp_chat); + factory = empathy_tp_contact_factory_dup_singleton (connection); - approval->contact = empathy_contact_factory_get_from_handle ( - contact_factory, account, inviter); + empathy_tp_contact_factory_get_from_handle (factory, + inviter, event_manager_muc_invite_got_contact_cb, + approval, NULL, G_OBJECT (manager)); - empathy_contact_call_when_ready (approval->contact, - EMPATHY_CONTACT_READY_NAME, - event_manager_muc_invite_got_contact_name_cb, approval, NULL, - G_OBJECT (manager)); - - g_object_unref (contact_factory); + g_object_unref (factory); return; } @@ -847,73 +840,45 @@ event_manager_approve_channel_cb (EmpathyDispatcher *dispatcher, } else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) { - EmpathyContact *contact; - gchar *header; - TpHandle handle; - McAccount *account; - EmpathyContactFactory *factory; - TpChannel *channel = empathy_dispatch_operation_get_channel (operation); - - factory = empathy_contact_factory_dup_singleton (); - handle = tp_channel_get_handle (channel, NULL); - account = empathy_channel_get_account (channel); + EmpathyTpFile *file; + gchar *header; - contact = empathy_contact_factory_get_from_handle (factory, account, - handle); - - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_NAME, NULL); + file = EMPATHY_TP_FILE (empathy_dispatch_operation_get_channel_wrapper (operation)); + approval->contact = g_object_ref (empathy_tp_file_get_contact (file)); header = g_strdup_printf (_("Incoming file transfer from %s"), - empathy_contact_get_name (contact)); + empathy_contact_get_name (approval->contact)); - event_manager_add (manager, contact, EMPATHY_IMAGE_DOCUMENT_SEND, + event_manager_add (manager, approval->contact, EMPATHY_IMAGE_DOCUMENT_SEND, header, NULL, approval, event_channel_process_func, NULL); /* FIXME better sound for incoming file transfers ?*/ empathy_sound_play (empathy_main_window_get (), EMPATHY_SOUND_CONVERSATION_NEW); - g_object_unref (factory); - g_object_unref (account); g_free (header); } else if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE) || !tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) { - EmpathyContact *contact; - TpHandle handle; - TpHandleType handle_type; - McAccount *account; - EmpathyContactFactory *factory; - EmpathyTubeDispatch *tube_dispatch; TpChannel *channel; + TpHandle handle; + TpHandleType handle_type; + TpConnection *connection; + EmpathyTpContactFactory *factory; channel = empathy_dispatch_operation_get_channel (operation); - handle = tp_channel_get_handle (channel, &handle_type); /* Only understand p2p tubes */ if (handle_type != TP_HANDLE_TYPE_CONTACT) return; - factory = empathy_contact_factory_dup_singleton (); - account = empathy_channel_get_account (channel); - - contact = empathy_contact_factory_get_from_handle (factory, account, - handle); - - tube_dispatch = empathy_tube_dispatch_new (operation); - - approval->contact = contact; - approval->tube_dispatch = tube_dispatch; - - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_NAME, event_manager_tube_got_contact_name_cb, - approval, NULL, G_OBJECT (manager)); - - g_object_unref (factory); - g_object_unref (account); + approval->tube_dispatch = empathy_tube_dispatch_new (operation); + connection = tp_channel_borrow_connection (channel); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_handle (factory, handle, + event_manager_tube_got_contact_cb, approval, NULL, G_OBJECT (manager)); } else { @@ -945,19 +910,17 @@ event_manager_pendings_changed_cb (EmpathyContactList *list, { EventPriv *event = l->data; - if (event->public.contact == contact && - event->func == event_pending_subscribe_func) - { - event_remove (event); - break; + if (event->public.contact == contact && + event->func == event_pending_subscribe_func) + { + event_remove (event); + break; + } } - } return; } - empathy_contact_run_until_ready (contact, EMPATHY_CONTACT_READY_NAME, NULL); - header = g_strdup_printf (_("Subscription requested by %s"), empathy_contact_get_name (contact)); diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c index 6c5f1fa2c..b9993a8f5 100644 --- a/src/empathy-main-window.c +++ b/src/empathy-main-window.c @@ -35,7 +35,6 @@ #include <libempathy/empathy-chatroom.h> #include <libempathy/empathy-contact-list.h> #include <libempathy/empathy-contact-manager.h> -#include <libempathy/empathy-contact-factory.h> #include <libempathy/empathy-status-presets.h> #include <libempathy-gtk/empathy-contact-dialogs.h> @@ -703,23 +702,21 @@ main_window_chat_show_offline_cb (GtkToggleAction *action, static void main_window_favorite_chatroom_join (EmpathyChatroom *chatroom) { - MissionControl *mc; + EmpathyAccountManager *manager; McAccount *account; + TpConnection *connection; const gchar *room; - mc = empathy_mission_control_dup_singleton (); + manager = empathy_account_manager_dup_singleton (); account = empathy_chatroom_get_account (chatroom); + connection = empathy_account_manager_get_connection (manager, account); room = empathy_chatroom_get_room (chatroom); + g_object_unref (manager); - if (mission_control_get_connection_status (mc, account, NULL) != - TP_CONNECTION_STATUS_CONNECTED) { - return; + if (connection != NULL) { + DEBUG ("Requesting channel for '%s'", room); + empathy_dispatcher_join_muc (connection, room, NULL, NULL); } - - DEBUG ("Requesting channel for '%s'", room); - empathy_dispatcher_join_muc (account, room, NULL, NULL); - - g_object_unref (mc); } static void @@ -906,31 +903,7 @@ static void main_window_edit_personal_information_cb (GtkAction *action, EmpathyMainWindow *window) { - GSList *accounts; - - accounts = mission_control_get_online_connections (window->mc, NULL); - if (accounts) { - EmpathyContactFactory *factory; - EmpathyContact *contact; - McAccount *account; - - account = accounts->data; - factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_user (factory, account); - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_HANDLE | - EMPATHY_CONTACT_READY_ID, - NULL); - - empathy_contact_information_dialog_show (contact, - GTK_WINDOW (window->window), - TRUE, TRUE); - - g_slist_foreach (accounts, (GFunc) g_object_unref, NULL); - g_slist_free (accounts); - g_object_unref (factory); - g_object_unref (contact); - } + empathy_contact_personal_dialog_show (GTK_WINDOW (window->window)); } static void diff --git a/src/empathy-new-chatroom-dialog.c b/src/empathy-new-chatroom-dialog.c index bf107d1b6..837d9acfe 100644 --- a/src/empathy-new-chatroom-dialog.c +++ b/src/empathy-new-chatroom-dialog.c @@ -342,7 +342,7 @@ new_chatroom_dialog_update_widgets (EmpathyNewChatroomDialog *dialog) const gchar *room; account_chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); profile = mc_account_get_profile (account); protocol = mc_profile_get_protocol_name (profile); @@ -388,7 +388,7 @@ new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, new_chatroom_dialog_model_clear (dialog); account_chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + account = empathy_account_chooser_dup_account (account_chooser); dialog->room_list = empathy_tp_roomlist_new (account); if (dialog->room_list) { @@ -409,6 +409,8 @@ new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, } new_chatroom_dialog_update_widgets (dialog); + + g_object_unref (account); } static void @@ -533,7 +535,7 @@ static void new_chatroom_dialog_join (EmpathyNewChatroomDialog *dialog) { EmpathyAccountChooser *account_chooser; - McAccount *account; + TpConnection *connection; const gchar *room; const gchar *server = NULL; gchar *room_name = NULL; @@ -542,7 +544,7 @@ new_chatroom_dialog_join (EmpathyNewChatroomDialog *dialog) server = gtk_entry_get_text (GTK_ENTRY (dialog->entry_server)); account_chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); - account = empathy_account_chooser_get_account (account_chooser); + connection = empathy_account_chooser_get_connection (account_chooser); if (!EMP_STR_EMPTY (server)) { room_name = g_strconcat (room, "@", server, NULL); @@ -551,7 +553,7 @@ new_chatroom_dialog_join (EmpathyNewChatroomDialog *dialog) } DEBUG ("Requesting channel for '%s'", room_name); - empathy_dispatcher_join_muc (account, room_name, NULL, NULL); + empathy_dispatcher_join_muc (connection, room_name, NULL, NULL); g_free (room_name); } diff --git a/src/empathy.c b/src/empathy.c index a2115a6cf..817b9bc37 100644 --- a/src/empathy.c +++ b/src/empathy.c @@ -42,6 +42,7 @@ #include <libempathy/empathy-utils.h> #include <libempathy/empathy-call-factory.h> #include <libempathy/empathy-chatroom-manager.h> +#include <libempathy/empathy-account-manager.h> #include <libempathy/empathy-dispatcher.h> #include <libempathy/empathy-dispatch-operation.h> #include <libempathy/empathy-log-manager.h> @@ -96,10 +97,16 @@ dispatch_cb (EmpathyDispatcher *dispatcher, } if (id) { + EmpathyAccountManager *manager; + TpConnection *connection; McAccount *account; - account = empathy_tp_chat_get_account (tp_chat); + manager = empathy_account_manager_dup_singleton (); + connection = empathy_tp_chat_get_connection (tp_chat); + account = empathy_account_manager_get_account (manager, + connection); chat = empathy_chat_window_find_chat (account, id); + g_object_unref (manager); } if (chat) { diff --git a/tests/.gitignore b/tests/.gitignore index 442cafd51..a37f3e5a0 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -5,3 +5,4 @@ contact-run-until-ready-2 *.log empetit test-empathy-presence-chooser +test-empathy-status-preset-dialog diff --git a/tests/Makefile.am b/tests/Makefile.am index 67f6ec9af..7740d1f8b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,16 +24,14 @@ LDADD = \ noinst_PROGRAMS = \ contact-manager \ - contact-run-until-ready \ - contact-run-until-ready-2 \ empetit \ - test-empathy-presence-chooser + test-empathy-presence-chooser \ + test-empathy-status-preset-dialog contact_manager_SOURCES = contact-manager.c -contact_run_until_ready_SOURCES = contact-run-until-ready.c -contact_run_until_ready_2_SOURCES = contact-run-until-ready-2.c empetit_SOURCES = empetit.c test_empathy_presence_chooser_SOURCES = test-empathy-presence-chooser.c +test_empathy_status_preset_dialog_SOURCES = test-empathy-status-preset-dialog.c check_PROGRAMS = check-main TESTS = check-main diff --git a/tests/check-empathy-helpers.c b/tests/check-empathy-helpers.c index 2e808c0e7..65273f8c8 100644 --- a/tests/check-empathy-helpers.c +++ b/tests/check-empathy-helpers.c @@ -143,7 +143,7 @@ destroy_test_account (McAccount *account) error = NULL; } - gconf_entry_free (entry); + gconf_entry_unref (entry); } g_slist_free (entries); diff --git a/tests/contact-run-until-ready-2.c b/tests/contact-run-until-ready-2.c deleted file mode 100644 index 426534116..000000000 --- a/tests/contact-run-until-ready-2.c +++ /dev/null @@ -1,63 +0,0 @@ -#include <stdlib.h> - -#include <glib.h> -#include <gtk/gtk.h> -#include <libempathy/empathy-contact-factory.h> -#include <libempathy/empathy-contact-manager.h> -#include <libmissioncontrol/mc-account.h> - -static void -pending_cb (EmpathyContactManager *manager, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - gchar *message, - gboolean is_pending, - gpointer data) -{ - if (!is_pending) { - return; - } - - g_print ("Contact handle=%d alias=%s\n", - empathy_contact_get_handle (contact), - empathy_contact_get_name (contact)); - - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_NAME, - NULL); - - g_print ("Contact ready: handle=%d alias=%s ready=%d\n", - empathy_contact_get_handle (contact), - empathy_contact_get_name (contact), - empathy_contact_get_ready (contact)); - - g_object_unref (manager); - gtk_main_quit (); -} - -static gboolean -callback (gpointer data) -{ - EmpathyContactManager *manager; - - manager = empathy_contact_manager_dup_singleton (); - g_signal_connect (manager, "pendings-changed", - G_CALLBACK (pending_cb), - NULL); - - return FALSE; -} - -int -main (int argc, char **argv) -{ - gtk_init (&argc, &argv); - - g_idle_add (callback, NULL); - - gtk_main (); - - return EXIT_SUCCESS; -} - diff --git a/tests/contact-run-until-ready.c b/tests/contact-run-until-ready.c deleted file mode 100644 index 13fad63a7..000000000 --- a/tests/contact-run-until-ready.c +++ /dev/null @@ -1,53 +0,0 @@ -#include <stdlib.h> - -#include <glib.h> -#include <gtk/gtk.h> -#include <libempathy/empathy-contact-factory.h> -#include <libmissioncontrol/mc-account.h> - -static gboolean -callback (gpointer data) -{ - EmpathyContactFactory *factory; - McAccount *account; - EmpathyContact *contact; - EmpathyContactReady ready_flags; - - factory = empathy_contact_factory_dup_singleton (); - account = mc_account_lookup ("jabber0"); - contact = empathy_contact_factory_get_from_handle (factory, account, 2); - - g_print ("Contact handle=%d alias=%s\n", - empathy_contact_get_handle (contact), - empathy_contact_get_name (contact)); - - ready_flags = EMPATHY_CONTACT_READY_HANDLE | EMPATHY_CONTACT_READY_NAME; - empathy_contact_run_until_ready (contact, ready_flags, NULL); - - g_print ("Contact ready: handle=%d alias=%s ready=%d needed-ready=%d\n", - empathy_contact_get_handle (contact), - empathy_contact_get_name (contact), - empathy_contact_get_ready (contact), - ready_flags); - - g_object_unref (factory); - g_object_unref (account); - g_object_unref (contact); - - gtk_main_quit (); - - return FALSE; -} - -int -main (int argc, char **argv) -{ - gtk_init (&argc, &argv); - - g_idle_add (callback, NULL); - - gtk_main (); - - return EXIT_SUCCESS; -} - diff --git a/tests/test-empathy-presence-chooser.c b/tests/test-empathy-presence-chooser.c index 02991e859..12d35b4c6 100644 --- a/tests/test-empathy-presence-chooser.c +++ b/tests/test-empathy-presence-chooser.c @@ -24,6 +24,8 @@ #include <gtk/gtk.h> +#include <libempathy/empathy-status-presets.h> + #include <libempathy-gtk/empathy-ui-utils.h> #include <libempathy-gtk/empathy-presence-chooser.h> @@ -36,6 +38,8 @@ main (int argc, char **argv) gtk_init (&argc, &argv); empathy_gtk_init (); + empathy_status_presets_get_all (); + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); chooser = empathy_presence_chooser_new (); gtk_container_add (GTK_CONTAINER (window), chooser); diff --git a/tests/test-empathy-status-preset-dialog.c b/tests/test-empathy-status-preset-dialog.c new file mode 100644 index 000000000..6602e4f28 --- /dev/null +++ b/tests/test-empathy-status-preset-dialog.c @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2009 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Davyd Madeley <davyd.madeley@collabora.co.uk> + */ + +#include <config.h> + +#include <gtk/gtk.h> + +#include <libempathy/empathy-status-presets.h> + +#include <libempathy-gtk/empathy-ui-utils.h> +#include <libempathy-gtk/empathy-status-preset-dialog.h> + +int +main (int argc, char **argv) +{ + GtkWidget *dialog; + + gtk_init (&argc, &argv); + empathy_gtk_init (); + + empathy_status_presets_get_all (); + + dialog = empathy_status_preset_dialog_new (NULL); + + gtk_widget_show (dialog); + + gtk_main (); + + return 0; +} |