From 18d649cbfd8eda7678957a3d2a76b9bb8681a981 Mon Sep 17 00:00:00 2001 From: Vitaly Minko Date: Wed, 10 Nov 2010 20:23:39 +0300 Subject: Make AccountChooser filters asynchronous to let them handle newly connected accounts properly (#633481). --- libempathy-gtk/empathy-account-chooser.c | 87 ++++++++++++++++++------ libempathy-gtk/empathy-account-chooser.h | 26 ++++++- libempathy-gtk/empathy-contact-dialogs.c | 16 +++-- libempathy-gtk/empathy-contact-selector-dialog.c | 12 +++- libempathy-gtk/empathy-contact-selector-dialog.h | 6 +- libempathy-gtk/empathy-individual-dialogs.c | 11 ++- libempathy-gtk/empathy-new-call-dialog.c | 86 +++++++++++++++++------ libempathy-gtk/empathy-new-message-dialog.c | 85 ++++++++++++++++++----- 8 files changed, 254 insertions(+), 75 deletions(-) (limited to 'libempathy-gtk') diff --git a/libempathy-gtk/empathy-account-chooser.c b/libempathy-gtk/empathy-account-chooser.c index 5e261ebdb..f077827fb 100644 --- a/libempathy-gtk/empathy-account-chooser.c +++ b/libempathy-gtk/empathy-account-chooser.c @@ -74,6 +74,12 @@ typedef struct { gboolean set; } SetAccountData; +typedef struct { + EmpathyAccountChooser *chooser; + TpAccount *account; + GtkTreeIter *iter; +} FilterResultCallbackData; + /* Distinguishes between store entries which are actually accounts, and special * items like the "All" entry and the separator below it, so they can be sorted * correctly. Higher-numbered entries will sort earlier. @@ -724,33 +730,26 @@ account_chooser_account_remove_foreach (TpAccount *account, } static void -account_chooser_update_iter (EmpathyAccountChooser *chooser, - GtkTreeIter *iter) +account_chooser_filter_ready_cb (gboolean is_enabled, + gpointer data) { + FilterResultCallbackData *fr_data = data; + EmpathyAccountChooser *chooser; EmpathyAccountChooserPriv *priv; + TpAccount *account; + GtkTreeIter *iter; GtkListStore *store; GtkComboBox *combobox; - TpAccount *account; const gchar *icon_name; - gboolean is_enabled = TRUE; + chooser = fr_data->chooser; priv = GET_PRIV (chooser); - + account = fr_data->account; + iter = fr_data->iter; combobox = GTK_COMBO_BOX (chooser); store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox)); - gtk_tree_model_get (GTK_TREE_MODEL (store), iter, - COL_ACCOUNT_POINTER, &account, - -1); - - /* Skip rows without account associated */ - if (account == NULL) - return; - icon_name = tp_account_get_icon_name (account); - if (priv->filter) { - is_enabled = priv->filter (account, priv->filter_data); - } gtk_list_store_set (store, iter, COL_ACCOUNT_IMAGE, icon_name, @@ -766,6 +765,43 @@ account_chooser_update_iter (EmpathyAccountChooser *chooser, } g_object_unref (account); + g_free (iter); + g_slice_free (FilterResultCallbackData, fr_data); +} + +static void +account_chooser_update_iter (EmpathyAccountChooser *chooser, + GtkTreeIter *iter) +{ + EmpathyAccountChooserPriv *priv; + GtkListStore *store; + GtkComboBox *combobox; + TpAccount *account; + FilterResultCallbackData *data; + + priv = GET_PRIV (chooser); + + combobox = GTK_COMBO_BOX (chooser); + store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox)); + + gtk_tree_model_get (GTK_TREE_MODEL (store), iter, + COL_ACCOUNT_POINTER, &account, + -1); + + /* Skip rows without account associated */ + if (account == NULL) + return; + + data = g_slice_new0 (FilterResultCallbackData); + data->chooser = chooser; + data->account = account; + data->iter = g_memdup (iter, sizeof (GtkTreeIter)); + + if (priv->filter) + priv->filter (account, account_chooser_filter_ready_cb, + (gpointer) data, priv->filter_data); + else + account_chooser_filter_ready_cb (TRUE, (gpointer) data); } static void @@ -879,19 +915,26 @@ empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser, /** * empathy_account_chooser_filter_is_connected: * @account: a #TpAccount + * @callback: an #EmpathyAccountChooserFilterResultCallback accepting the result + * @callback_data: data passed to the @callback * @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 + * Returns (via the callback) TRUE is @account is connected */ -gboolean -empathy_account_chooser_filter_is_connected (TpAccount *account, - gpointer user_data) +void +empathy_account_chooser_filter_is_connected ( + TpAccount *account, + EmpathyAccountChooserFilterResultCallback callback, + gpointer callback_data, + gpointer user_data) { - return (tp_account_get_connection_status (account, NULL) - == TP_CONNECTION_STATUS_CONNECTED); + gboolean is_connected = + tp_account_get_connection_status (account, NULL) + == TP_CONNECTION_STATUS_CONNECTED; + callback (is_connected, callback_data); } gboolean diff --git a/libempathy-gtk/empathy-account-chooser.h b/libempathy-gtk/empathy-account-chooser.h index f80d7003c..dfd372c3e 100644 --- a/libempathy-gtk/empathy-account-chooser.h +++ b/libempathy-gtk/empathy-account-chooser.h @@ -38,8 +38,26 @@ G_BEGIN_DECLS #define EMPATHY_IS_ACCOUNT_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_ACCOUNT_CHOOSER)) #define EMPATHY_ACCOUNT_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserClass)) -typedef gboolean (* EmpathyAccountChooserFilterFunc) (TpAccount *account, - gpointer user_data); +/** + * EmpathyAccountChooserFilterResultCallback: + * @is_enabled: indicated whether the account should be enabled + * @user_data: user data passed to the callback + */ +typedef void (* EmpathyAccountChooserFilterResultCallback) (gboolean is_enabled, + gpointer user_data); + +/** + * EmpathyAccountChooserFilterFunc: + * @account: a #TpAccount + * @callback: an #EmpathyAccountChooserFilterResultCallback accepting the result + * @callback_data: data passed to the @callback + * @user_data: user data passed to the callback + */ +typedef void (* EmpathyAccountChooserFilterFunc) ( + TpAccount *account, + EmpathyAccountChooserFilterResultCallback callback, + gpointer callback_data, + gpointer user_data); typedef struct _EmpathyAccountChooser EmpathyAccountChooser; @@ -69,7 +87,9 @@ void empathy_account_chooser_set_has_all_option (EmpathyAccountChooser void empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser, EmpathyAccountChooserFilterFunc filter, gpointer user_data); -gboolean empathy_account_chooser_filter_is_connected (TpAccount *account, +void empathy_account_chooser_filter_is_connected (TpAccount *account, + EmpathyAccountChooserFilterResultCallback callback, + gpointer callback_data, gpointer user_data); gboolean empathy_account_chooser_is_ready (EmpathyAccountChooser *chooser); diff --git a/libempathy-gtk/empathy-contact-dialogs.c b/libempathy-gtk/empathy-contact-dialogs.c index a5ae51d03..fb57f348b 100644 --- a/libempathy-gtk/empathy-contact-dialogs.c +++ b/libempathy-gtk/empathy-contact-dialogs.c @@ -354,24 +354,28 @@ empathy_contact_personal_dialog_show (GtkWindow *parent) * New contact dialog */ -static gboolean -can_add_contact_to_account (TpAccount *account, - gpointer user_data) +static void +can_add_contact_to_account (TpAccount *account, + EmpathyAccountChooserFilterResultCallback callback, + gpointer callback_data, + gpointer user_data) { EmpathyContactManager *contact_manager; TpConnection *connection; gboolean result; connection = tp_account_get_connection (account); - if (connection == NULL) - return FALSE; + if (connection == NULL) { + callback (FALSE, callback_data); + return; + } contact_manager = empathy_contact_manager_dup_singleton (); result = empathy_contact_manager_get_flags_for_connection ( contact_manager, connection) & EMPATHY_CONTACT_LIST_CAN_ADD; g_object_unref (contact_manager); - return result; + callback (result, callback_data); } static void diff --git a/libempathy-gtk/empathy-contact-selector-dialog.c b/libempathy-gtk/empathy-contact-selector-dialog.c index 62b902746..3ed7f30e5 100644 --- a/libempathy-gtk/empathy-contact-selector-dialog.c +++ b/libempathy-gtk/empathy-contact-selector-dialog.c @@ -243,8 +243,10 @@ entry_activate_cb (GtkEntry *entry, gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_ACCEPT); } -static gboolean +static void account_chooser_filter (TpAccount *account, + EmpathyAccountChooserFilterResultCallback callback, + gpointer callback_data, gpointer user_data) { EmpathyContactSelectorDialog *self = user_data; @@ -252,9 +254,13 @@ account_chooser_filter (TpAccount *account, EMPATHY_CONTACT_SELECTOR_DIALOG_GET_CLASS (self); if (class->account_filter == NULL) - return empathy_account_chooser_filter_is_connected (account, user_data); + { + empathy_account_chooser_filter_is_connected ( + account,callback, callback_data, user_data); + return; + } - return class->account_filter (self, account); + class->account_filter (self, callback, callback_data, account); } static gboolean diff --git a/libempathy-gtk/empathy-contact-selector-dialog.h b/libempathy-gtk/empathy-contact-selector-dialog.h index 402f1c766..27d689c5a 100644 --- a/libempathy-gtk/empathy-contact-selector-dialog.h +++ b/libempathy-gtk/empathy-contact-selector-dialog.h @@ -29,6 +29,8 @@ #include #include +#include "empathy-account-chooser.h" + G_BEGIN_DECLS typedef struct _EmpathyContactSelectorDialog EmpathyContactSelectorDialog; @@ -38,7 +40,9 @@ typedef struct _EmpathyContactSelectorDialogClass \ struct _EmpathyContactSelectorDialogClass { GtkDialogClass parent_class; - gboolean (*account_filter) (EmpathyContactSelectorDialog *self, + void (*account_filter) (EmpathyContactSelectorDialog *self, + EmpathyAccountChooserFilterResultCallback callback, + gpointer callback_data, TpAccount *account); gboolean (*contact_filter) (EmpathyContactSelectorDialog *self, const char *id); diff --git a/libempathy-gtk/empathy-individual-dialogs.c b/libempathy-gtk/empathy-individual-dialogs.c index 85ed7d1d4..2c9801059 100644 --- a/libempathy-gtk/empathy-individual-dialogs.c +++ b/libempathy-gtk/empathy-individual-dialogs.c @@ -43,8 +43,10 @@ static GtkWidget *new_individual_dialog = NULL; * New contact dialog */ -static gboolean +static void can_add_contact_to_account (TpAccount *account, + EmpathyAccountChooserFilterResultCallback callback, + gpointer callback_data, gpointer user_data) { EmpathyIndividualManager *individual_manager; @@ -53,13 +55,16 @@ can_add_contact_to_account (TpAccount *account, connection = tp_account_get_connection (account); if (connection == NULL) - return FALSE; + { + callback (FALSE, callback_data); + return; + } individual_manager = empathy_individual_manager_dup_singleton (); result = empathy_connection_can_add_personas (connection); g_object_unref (individual_manager); - return result; + callback (result, callback_data); } static void diff --git a/libempathy-gtk/empathy-new-call-dialog.c b/libempathy-gtk/empathy-new-call-dialog.c index 3d51283b1..ab9a86a6f 100644 --- a/libempathy-gtk/empathy-new-call-dialog.c +++ b/libempathy-gtk/empathy-new-call-dialog.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT @@ -50,6 +49,11 @@ G_DEFINE_TYPE(EmpathyNewCallDialog, empathy_new_call_dialog, typedef struct _EmpathyNewCallDialogPriv EmpathyNewCallDialogPriv; +typedef struct { + EmpathyAccountChooserFilterResultCallback callback; + gpointer user_data; +} FilterCallbackData; + struct _EmpathyNewCallDialogPriv { GtkWidget *check_video; }; @@ -136,36 +140,80 @@ out: gtk_widget_destroy (GTK_WIDGET (dialog)); } -static gboolean +static void +conn_prepared_cb (GObject *conn, + GAsyncResult *result, + gpointer user_data) +{ + FilterCallbackData *data = user_data; + GError *myerr = NULL; + TpCapabilities *caps; + GPtrArray *classes; + guint i; + + if (!tp_proxy_prepare_finish (conn, result, &myerr)) + goto out; + + caps = tp_connection_get_capabilities (TP_CONNECTION (conn)); + classes = tp_capabilities_get_channel_classes (caps); + + for (i = 0; i < classes->len; i++) + { + GHashTable *fixed; + GStrv allowed; + const gchar *chan_type; + + tp_value_array_unpack (g_ptr_array_index (classes, i), 2, + &fixed, &allowed); + + chan_type = tp_asv_get_string (fixed, TP_PROP_CHANNEL_CHANNEL_TYPE); + + if (tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) + continue; + + if (tp_asv_get_uint32 (fixed, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != + TP_HANDLE_TYPE_CONTACT) + continue; + + data->callback (TRUE, data->user_data); + g_slice_free (FilterCallbackData, data); + return; + } + +out: + data->callback (FALSE, data->user_data); + g_slice_free (FilterCallbackData, data); +} + +static void empathy_new_call_dialog_account_filter (EmpathyContactSelectorDialog *dialog, + EmpathyAccountChooserFilterResultCallback callback, + gpointer callback_data, TpAccount *account) { TpConnection *connection; - EmpathyDispatcher *dispatcher; - GList *classes; + FilterCallbackData *cb_data; + GQuark features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 }; if (tp_account_get_connection_status (account, NULL) != TP_CONNECTION_STATUS_CONNECTED) - return FALSE; + { + callback (FALSE, callback_data); + return; + } /* check if CM supports calls */ connection = tp_account_get_connection (account); if (connection == NULL) - return FALSE; - - dispatcher = empathy_dispatcher_dup_singleton (); - - classes = empathy_dispatcher_find_requestable_channel_classes - (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - TP_HANDLE_TYPE_CONTACT, NULL); - - g_object_unref (dispatcher); - - if (classes == NULL) - return FALSE; + { + callback (FALSE, callback_data); + return; + } - g_list_free (classes); - return TRUE; + cb_data = g_slice_new0 (FilterCallbackData); + cb_data->callback = callback; + cb_data->user_data = callback_data; + tp_proxy_prepare_async (connection, features, conn_prepared_cb, cb_data); } static GObject * diff --git a/libempathy-gtk/empathy-new-message-dialog.c b/libempathy-gtk/empathy-new-message-dialog.c index a17481437..8249b8693 100644 --- a/libempathy-gtk/empathy-new-message-dialog.c +++ b/libempathy-gtk/empathy-new-message-dialog.c @@ -42,6 +42,11 @@ #include "empathy-new-message-dialog.h" #include "empathy-account-chooser.h" +typedef struct { + EmpathyAccountChooserFilterResultCallback callback; + gpointer user_data; +} FilterCallbackData; + static EmpathyNewMessageDialog *dialog_singleton = NULL; G_DEFINE_TYPE(EmpathyNewMessageDialog, empathy_new_message_dialog, @@ -77,36 +82,80 @@ out: gtk_widget_destroy (GTK_WIDGET (dialog)); } -static gboolean +static void +conn_prepared_cb (GObject *conn, + GAsyncResult *result, + gpointer user_data) +{ + FilterCallbackData *data = user_data; + GError *myerr = NULL; + TpCapabilities *caps; + GPtrArray *classes; + guint i; + + if (!tp_proxy_prepare_finish (conn, result, &myerr)) + goto out; + + caps = tp_connection_get_capabilities (TP_CONNECTION (conn)); + classes = tp_capabilities_get_channel_classes (caps); + + for (i = 0; i < classes->len; i++) + { + GHashTable *fixed; + GStrv allowed; + const gchar *chan_type; + + tp_value_array_unpack (g_ptr_array_index (classes, i), 2, + &fixed, &allowed); + + chan_type = tp_asv_get_string (fixed, TP_PROP_CHANNEL_CHANNEL_TYPE); + + if (tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_TEXT)) + continue; + + if (tp_asv_get_uint32 (fixed, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != + TP_HANDLE_TYPE_CONTACT) + continue; + + data->callback (TRUE, data->user_data); + g_slice_free (FilterCallbackData, data); + return; + } + +out: + data->callback (FALSE, data->user_data); + g_slice_free (FilterCallbackData, data); +} + +static void empathy_new_message_account_filter (EmpathyContactSelectorDialog *dialog, + EmpathyAccountChooserFilterResultCallback callback, + gpointer callback_data, TpAccount *account) { TpConnection *connection; - EmpathyDispatcher *dispatcher; - GList *classes; + FilterCallbackData *cb_data; + GQuark features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 }; if (tp_account_get_connection_status (account, NULL) != TP_CONNECTION_STATUS_CONNECTED) - return FALSE; + { + callback (FALSE, callback_data); + return; + } /* check if CM supports 1-1 text chat */ connection = tp_account_get_connection (account); if (connection == NULL) - return FALSE; - - dispatcher = empathy_dispatcher_dup_singleton (); - - classes = empathy_dispatcher_find_requestable_channel_classes - (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_TEXT, - TP_HANDLE_TYPE_CONTACT, NULL); - - g_object_unref (dispatcher); - - if (classes == NULL) - return FALSE; + { + callback (FALSE, callback_data); + return; + } - g_list_free (classes); - return TRUE; + cb_data = g_slice_new0 (FilterCallbackData); + cb_data->callback = callback; + cb_data->user_data = callback_data; + tp_proxy_prepare_async (connection, features, conn_prepared_cb, cb_data); } static GObject * -- cgit v1.2.3 From 875bf697d54f1c4ca98478ded849bc733828f758 Mon Sep 17 00:00:00 2001 From: Vitaly Minko Date: Fri, 12 Nov 2010 17:47:51 +0300 Subject: Make AccountChooser-related code simpler and clearer (re #633481). --- libempathy-gtk/empathy-account-chooser.c | 32 ++++++++++++++++++++++------ libempathy-gtk/empathy-new-message-dialog.c | 33 +++++------------------------ 2 files changed, 31 insertions(+), 34 deletions(-) (limited to 'libempathy-gtk') diff --git a/libempathy-gtk/empathy-account-chooser.c b/libempathy-gtk/empathy-account-chooser.c index f077827fb..f1c0ec6b4 100644 --- a/libempathy-gtk/empathy-account-chooser.c +++ b/libempathy-gtk/empathy-account-chooser.c @@ -80,6 +80,30 @@ typedef struct { GtkTreeIter *iter; } FilterResultCallbackData; +static FilterResultCallbackData * +filter_result_callback_data_new (EmpathyAccountChooser *chooser, + TpAccount *account, + GtkTreeIter *iter) +{ + FilterResultCallbackData *data; + + data = g_slice_new0 (FilterResultCallbackData); + data->chooser = g_object_ref (chooser); + data->account = g_object_ref (account); + data->iter = gtk_tree_iter_copy (iter); + + return data; +} + +static void +filter_result_callback_data_free (FilterResultCallbackData *data) +{ + g_object_unref (data->chooser); + g_object_unref (data->account); + gtk_tree_iter_free (data->iter); + g_slice_free (FilterResultCallbackData, data); +} + /* Distinguishes between store entries which are actually accounts, and special * items like the "All" entry and the separator below it, so they can be sorted * correctly. Higher-numbered entries will sort earlier. @@ -765,8 +789,7 @@ account_chooser_filter_ready_cb (gboolean is_enabled, } g_object_unref (account); - g_free (iter); - g_slice_free (FilterResultCallbackData, fr_data); + filter_result_callback_data_free (fr_data); } static void @@ -792,10 +815,7 @@ account_chooser_update_iter (EmpathyAccountChooser *chooser, if (account == NULL) return; - data = g_slice_new0 (FilterResultCallbackData); - data->chooser = chooser; - data->account = account; - data->iter = g_memdup (iter, sizeof (GtkTreeIter)); + data = filter_result_callback_data_new (chooser, account, iter); if (priv->filter) priv->filter (account, account_chooser_filter_ready_cb, diff --git a/libempathy-gtk/empathy-new-message-dialog.c b/libempathy-gtk/empathy-new-message-dialog.c index 8249b8693..4747dfbb9 100644 --- a/libempathy-gtk/empathy-new-message-dialog.c +++ b/libempathy-gtk/empathy-new-message-dialog.c @@ -90,40 +90,17 @@ conn_prepared_cb (GObject *conn, FilterCallbackData *data = user_data; GError *myerr = NULL; TpCapabilities *caps; - GPtrArray *classes; - guint i; if (!tp_proxy_prepare_finish (conn, result, &myerr)) - goto out; - - caps = tp_connection_get_capabilities (TP_CONNECTION (conn)); - classes = tp_capabilities_get_channel_classes (caps); - - for (i = 0; i < classes->len; i++) { - GHashTable *fixed; - GStrv allowed; - const gchar *chan_type; - - tp_value_array_unpack (g_ptr_array_index (classes, i), 2, - &fixed, &allowed); - - chan_type = tp_asv_get_string (fixed, TP_PROP_CHANNEL_CHANNEL_TYPE); - - if (tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_TEXT)) - continue; - - if (tp_asv_get_uint32 (fixed, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != - TP_HANDLE_TYPE_CONTACT) - continue; - - data->callback (TRUE, data->user_data); + data->callback (FALSE, data->user_data); g_slice_free (FilterCallbackData, data); - return; } -out: - data->callback (FALSE, data->user_data); + caps = tp_connection_get_capabilities (TP_CONNECTION (conn)); + data->callback (tp_capabilities_supports_text_chats (caps), + data->user_data); + g_slice_free (FilterCallbackData, data); } -- cgit v1.2.3