]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-new-message-dialog.c
Make AccountChooser filters asynchronous to let them handle newly connected accounts...
[empathy.git] / libempathy-gtk / empathy-new-message-dialog.c
1 /*
2  * Copyright (C) 2007-2008 Collabora Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors: Xavier Claessens <xclaesse@gmail.com>
19  */
20
21 #include <config.h>
22
23 #include <string.h>
24 #include <stdlib.h>
25
26 #include <gtk/gtk.h>
27 #include <glib/gi18n-lib.h>
28
29 #include <telepathy-glib/interfaces.h>
30
31 #include <libempathy/empathy-tp-contact-factory.h>
32 #include <libempathy/empathy-contact-manager.h>
33 #include <libempathy/empathy-dispatcher.h>
34 #include <libempathy/empathy-utils.h>
35
36 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
37 #include <libempathy/empathy-debug.h>
38
39 #include <libempathy-gtk/empathy-ui-utils.h>
40 #include <libempathy-gtk/empathy-images.h>
41
42 #include "empathy-new-message-dialog.h"
43 #include "empathy-account-chooser.h"
44
45 typedef struct {
46   EmpathyAccountChooserFilterResultCallback callback;
47   gpointer                                  user_data;
48 } FilterCallbackData;
49
50 static EmpathyNewMessageDialog *dialog_singleton = NULL;
51
52 G_DEFINE_TYPE(EmpathyNewMessageDialog, empathy_new_message_dialog,
53                EMPATHY_TYPE_CONTACT_SELECTOR_DIALOG)
54
55 /**
56  * SECTION:empathy-new-message-dialog
57  * @title: EmpathyNewMessageDialog
58  * @short_description: A dialog to show a new message
59  * @include: libempathy-gtk/empathy-new-message-dialog.h
60  *
61  * #EmpathyNewMessageDialog is a dialog which allows a text chat
62  * to be started with any contact on any enabled account.
63  */
64
65 static void
66 empathy_new_message_dialog_response (GtkDialog *dialog, int response_id)
67 {
68   TpAccount *account;
69   const gchar *contact_id;
70
71   if (response_id != GTK_RESPONSE_ACCEPT) goto out;
72
73   contact_id = empathy_contact_selector_dialog_get_selected (
74       EMPATHY_CONTACT_SELECTOR_DIALOG (dialog), NULL, &account);
75
76   if (EMP_STR_EMPTY (contact_id) || account == NULL) goto out;
77
78   empathy_dispatcher_chat_with_contact_id (account, contact_id,
79       gtk_get_current_event_time ());
80
81 out:
82   gtk_widget_destroy (GTK_WIDGET (dialog));
83 }
84
85 static void
86 conn_prepared_cb (GObject *conn,
87     GAsyncResult *result,
88     gpointer user_data)
89 {
90   FilterCallbackData *data = user_data;
91   GError *myerr = NULL;
92   TpCapabilities *caps;
93   GPtrArray *classes;
94   guint i;
95
96   if (!tp_proxy_prepare_finish (conn, result, &myerr))
97       goto out;
98
99   caps = tp_connection_get_capabilities (TP_CONNECTION (conn));
100   classes = tp_capabilities_get_channel_classes (caps);
101
102   for (i = 0; i < classes->len; i++)
103     {
104       GHashTable *fixed;
105       GStrv allowed;
106       const gchar *chan_type;
107
108       tp_value_array_unpack (g_ptr_array_index (classes, i), 2,
109           &fixed, &allowed);
110
111       chan_type = tp_asv_get_string (fixed, TP_PROP_CHANNEL_CHANNEL_TYPE);
112
113       if (tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_TEXT))
114         continue;
115
116       if (tp_asv_get_uint32 (fixed, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) !=
117           TP_HANDLE_TYPE_CONTACT)
118         continue;
119
120       data->callback (TRUE, data->user_data);
121       g_slice_free (FilterCallbackData, data);
122       return;
123     }
124
125 out:
126   data->callback (FALSE, data->user_data);
127   g_slice_free (FilterCallbackData, data);
128 }
129
130 static void
131 empathy_new_message_account_filter (EmpathyContactSelectorDialog *dialog,
132     EmpathyAccountChooserFilterResultCallback callback,
133     gpointer callback_data,
134     TpAccount *account)
135 {
136   TpConnection *connection;
137   FilterCallbackData *cb_data;
138   GQuark features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 };
139
140   if (tp_account_get_connection_status (account, NULL) !=
141       TP_CONNECTION_STATUS_CONNECTED)
142     {
143       callback (FALSE, callback_data);
144       return;
145     }
146
147   /* check if CM supports 1-1 text chat */
148   connection = tp_account_get_connection (account);
149   if (connection == NULL)
150     {
151       callback (FALSE, callback_data);
152       return;
153     }
154
155   cb_data = g_slice_new0 (FilterCallbackData);
156   cb_data->callback = callback;
157   cb_data->user_data = callback_data;
158   tp_proxy_prepare_async (connection, features, conn_prepared_cb, cb_data);
159 }
160
161 static GObject *
162 empathy_new_message_dialog_constructor (GType type,
163     guint n_props,
164     GObjectConstructParam *props)
165 {
166   GObject *retval;
167
168   if (dialog_singleton)
169     {
170       retval = G_OBJECT (dialog_singleton);
171       g_object_ref (retval);
172     }
173   else
174     {
175       retval = G_OBJECT_CLASS (
176       empathy_new_message_dialog_parent_class)->constructor (type,
177         n_props, props);
178
179       dialog_singleton = EMPATHY_NEW_MESSAGE_DIALOG (retval);
180       g_object_add_weak_pointer (retval, (gpointer) &dialog_singleton);
181     }
182
183   return retval;
184 }
185
186 static void
187 empathy_new_message_dialog_init (EmpathyNewMessageDialog *dialog)
188 {
189   EmpathyContactSelectorDialog *parent = EMPATHY_CONTACT_SELECTOR_DIALOG (
190         dialog);
191   GtkWidget *image;
192
193   /* add chat button */
194   parent->button_action = gtk_button_new_with_mnemonic (_("C_hat"));
195   image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_NEW_MESSAGE,
196       GTK_ICON_SIZE_BUTTON);
197   gtk_button_set_image (GTK_BUTTON (parent->button_action), image);
198
199   gtk_dialog_add_action_widget (GTK_DIALOG (dialog), parent->button_action,
200       GTK_RESPONSE_ACCEPT);
201   gtk_widget_show (parent->button_action);
202
203   /* Tweak the dialog */
204   gtk_window_set_title (GTK_WINDOW (dialog), _("New Conversation"));
205   gtk_window_set_role (GTK_WINDOW (dialog), "new_message");
206
207   gtk_widget_set_sensitive (parent->button_action, FALSE);
208 }
209
210 static void
211 empathy_new_message_dialog_class_init (
212   EmpathyNewMessageDialogClass *class)
213 {
214   GObjectClass *object_class = G_OBJECT_CLASS (class);
215   GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (class);
216   EmpathyContactSelectorDialogClass *selector_dialog_class = \
217     EMPATHY_CONTACT_SELECTOR_DIALOG_CLASS (class);
218
219   object_class->constructor = empathy_new_message_dialog_constructor;
220
221   dialog_class->response = empathy_new_message_dialog_response;
222
223   selector_dialog_class->account_filter = empathy_new_message_account_filter;
224 }
225
226 /**
227  * empathy_new_message_dialog_new:
228  * @parent: parent #GtkWindow of the dialog
229  *
230  * Create a new #EmpathyNewMessageDialog it.
231  *
232  * Return value: the new #EmpathyNewMessageDialog
233  */
234 GtkWidget *
235 empathy_new_message_dialog_show (GtkWindow *parent)
236 {
237   GtkWidget *dialog;
238
239   dialog = g_object_new (EMPATHY_TYPE_NEW_MESSAGE_DIALOG, NULL);
240
241   if (parent)
242     {
243       gtk_window_set_transient_for (GTK_WINDOW (dialog),
244           GTK_WINDOW (parent));
245     }
246
247   gtk_widget_show (dialog);
248   return dialog;
249 }