1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
3 * Copyright (C) 2007-2009 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
20 * Jonny Lamb <jonny.lamb@collabora.co.uk>
29 #include <glib/gi18n-lib.h>
31 #include <libempathy/empathy-utils.h>
32 #include <libempathy/empathy-connection-managers.h>
34 #include "empathy-protocol-chooser.h"
35 #include "empathy-ui-utils.h"
37 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
38 #include <libempathy/empathy-debug.h>
41 * SECTION:empathy-protocol-chooser
42 * @title: EmpathyProtocolChooser
43 * @short_description: A widget used to choose from a list of protocols
44 * @include: libempathy-gtk/empathy-protocol-chooser.h
46 * #EmpathyProtocolChooser is a widget which extends #GtkComboBox to provides a
47 * chooser of available protocols.
51 * EmpathyProtocolChooser:
52 * @parent: parent object
54 * Widget which extends #GtkComboBox to provide a chooser of available
58 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyProtocolChooser)
64 EmpathyConnectionManagers
*cms
;
66 EmpathyProtocolChooserFilterFunc filter_func
;
67 gpointer filter_user_data
;
69 GHashTable
*protocols
;
70 } EmpathyProtocolChooserPriv
;
82 G_DEFINE_TYPE (EmpathyProtocolChooser
, empathy_protocol_chooser
,
86 protocol_chooser_sort_protocol_value (const gchar
*protocol_name
)
89 const gchar
*names
[] = {
96 for (i
= 0 ; names
[i
]; i
++)
98 if (strcmp (protocol_name
, names
[i
]) == 0)
106 protocol_chooser_sort_func (GtkTreeModel
*model
,
115 gtk_tree_model_get (model
, iter_a
,
116 COL_PROTOCOL_NAME
, &protocol_a
,
118 gtk_tree_model_get (model
, iter_b
,
119 COL_PROTOCOL_NAME
, &protocol_b
,
122 cmp
= protocol_chooser_sort_protocol_value (protocol_a
);
123 cmp
-= protocol_chooser_sort_protocol_value (protocol_b
);
126 cmp
= strcmp (protocol_a
, protocol_b
);
127 /* only happens for jabber where there is one entry for gtalk and one for
133 gtk_tree_model_get (model
, iter_a
,
134 COL_SERVICE
, &service
,
152 protocol_choosers_add_cm (EmpathyProtocolChooser
*chooser
,
153 TpConnectionManager
*cm
)
155 EmpathyProtocolChooserPriv
*priv
= GET_PRIV (chooser
);
156 GList
*protocols
, *l
;
157 const gchar
*cm_name
;
159 cm_name
= tp_connection_manager_get_name (cm
);
161 protocols
= tp_connection_manager_dup_protocols (cm
);
163 for (l
= protocols
; l
!= NULL
; l
= g_list_next (l
))
165 TpProtocol
*protocol
= l
->data
;
167 const gchar
*display_name
;
168 const gchar
*saved_cm_name
;
169 const gchar
*proto_name
;
172 proto_name
= tp_protocol_get_name (protocol
);
173 saved_cm_name
= g_hash_table_lookup (priv
->protocols
, proto_name
);
175 if (!tp_strdiff (cm_name
, "haze") && saved_cm_name
!= NULL
&&
176 tp_strdiff (saved_cm_name
, "haze"))
177 /* the CM we're adding is a haze implementation of something we already
182 if (!tp_strdiff (cm_name
, "haze") &&
183 !tp_strdiff (proto_name
, "facebook"))
184 /* Facebook now supports XMPP so drop the purple facebook plugin; user
185 * should use Gabble */
188 if (!tp_strdiff (cm_name
, "haze") &&
189 !tp_strdiff (proto_name
, "sip"))
190 /* Haze's SIP implementation is pretty useless (bgo #629736) */
193 if (!tp_strdiff (cm_name
, "butterfly"))
194 /* Butterfly isn't supported any more */
197 if (tp_strdiff (cm_name
, "haze") && !tp_strdiff (saved_cm_name
, "haze"))
201 TpConnectionManager
*haze_cm
;
203 /* let's this CM replace the haze implementation */
204 valid
= gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv
->store
),
209 gchar
*haze_proto_name
= NULL
;
211 gtk_tree_model_get (GTK_TREE_MODEL (priv
->store
), &titer
,
212 COL_PROTOCOL_NAME
, &haze_proto_name
,
213 COL_CM
, &haze_cm
, -1);
218 if (!tp_strdiff (tp_connection_manager_get_name (haze_cm
), "haze")
219 && !tp_strdiff (haze_proto_name
, proto_name
))
221 gtk_list_store_remove (priv
->store
, &titer
);
222 g_object_unref (haze_cm
);
223 g_free (haze_proto_name
);
227 g_object_unref (haze_cm
);
228 g_free (haze_proto_name
);
229 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (priv
->store
),
234 g_hash_table_insert (priv
->protocols
,
235 g_strdup (proto_name
), g_strdup (cm_name
));
237 icon_name
= empathy_protocol_icon_name (proto_name
);
238 pixbuf
= empathy_pixbuf_from_icon_name (icon_name
, GTK_ICON_SIZE_BUTTON
);
240 display_name
= empathy_protocol_name_to_display_name (proto_name
);
242 gtk_list_store_insert_with_values (priv
->store
,
245 COL_LABEL
, display_name
,
247 COL_PROTOCOL_NAME
, proto_name
,
250 g_clear_object (&pixbuf
);
252 if (!tp_strdiff (proto_name
, "jabber") &&
253 !tp_strdiff (cm_name
, "gabble"))
255 display_name
= empathy_service_name_to_display_name ("google-talk");
256 pixbuf
= empathy_pixbuf_from_icon_name ("im-google-talk",
257 GTK_ICON_SIZE_BUTTON
);
259 gtk_list_store_insert_with_values (priv
->store
,
262 COL_LABEL
, display_name
,
264 COL_PROTOCOL_NAME
, proto_name
,
265 COL_SERVICE
, "google-talk",
268 g_clear_object (&pixbuf
);
270 display_name
= empathy_service_name_to_display_name ("facebook");
271 pixbuf
= empathy_pixbuf_from_icon_name ("im-facebook",
272 GTK_ICON_SIZE_BUTTON
);
274 gtk_list_store_insert_with_values (priv
->store
,
277 COL_LABEL
, display_name
,
279 COL_PROTOCOL_NAME
, proto_name
,
280 COL_SERVICE
, "facebook",
283 g_clear_object (&pixbuf
);
289 g_list_free_full (protocols
, g_object_unref
);
293 protocol_chooser_add_cms_list (EmpathyProtocolChooser
*protocol_chooser
,
298 for (l
= cms
; l
!= NULL
; l
= l
->next
)
299 protocol_choosers_add_cm (protocol_chooser
, l
->data
);
301 gtk_combo_box_set_active (GTK_COMBO_BOX (protocol_chooser
), 0);
305 protocol_chooser_cms_prepare_cb (GObject
*source
,
306 GAsyncResult
*result
,
309 EmpathyConnectionManagers
*cms
= EMPATHY_CONNECTION_MANAGERS (source
);
310 EmpathyProtocolChooser
*protocol_chooser
= user_data
;
312 if (!empathy_connection_managers_prepare_finish (cms
, result
, NULL
))
315 protocol_chooser_add_cms_list (protocol_chooser
,
316 empathy_connection_managers_get_cms (cms
));
320 protocol_chooser_constructed (GObject
*object
)
322 EmpathyProtocolChooser
*protocol_chooser
;
323 EmpathyProtocolChooserPriv
*priv
;
324 GtkCellRenderer
*renderer
;
326 priv
= GET_PRIV (object
);
327 protocol_chooser
= EMPATHY_PROTOCOL_CHOOSER (object
);
329 /* set up combo box with new store */
330 priv
->store
= gtk_list_store_new (COL_COUNT
,
331 GDK_TYPE_PIXBUF
, /* Icon */
332 G_TYPE_STRING
, /* Label */
333 G_TYPE_OBJECT
, /* CM */
334 G_TYPE_STRING
, /* protocol name */
335 G_TYPE_STRING
); /* service */
337 /* Set the protocol sort function */
338 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv
->store
),
340 protocol_chooser_sort_func
,
342 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv
->store
),
346 gtk_combo_box_set_model (GTK_COMBO_BOX (object
),
347 GTK_TREE_MODEL (priv
->store
));
349 renderer
= gtk_cell_renderer_pixbuf_new ();
350 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (object
), renderer
, FALSE
);
351 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (object
), renderer
,
355 renderer
= gtk_cell_renderer_text_new ();
356 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (object
), renderer
, TRUE
);
357 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (object
), renderer
,
361 empathy_connection_managers_prepare_async (priv
->cms
,
362 protocol_chooser_cms_prepare_cb
, protocol_chooser
);
364 if (G_OBJECT_CLASS (empathy_protocol_chooser_parent_class
)->constructed
)
366 (empathy_protocol_chooser_parent_class
)->constructed (object
);
370 empathy_protocol_chooser_init (EmpathyProtocolChooser
*protocol_chooser
)
372 EmpathyProtocolChooserPriv
*priv
=
373 G_TYPE_INSTANCE_GET_PRIVATE (protocol_chooser
,
374 EMPATHY_TYPE_PROTOCOL_CHOOSER
, EmpathyProtocolChooserPriv
);
376 priv
->dispose_run
= FALSE
;
377 priv
->cms
= empathy_connection_managers_dup_singleton ();
378 priv
->protocols
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
381 protocol_chooser
->priv
= priv
;
385 protocol_chooser_finalize (GObject
*object
)
387 EmpathyProtocolChooser
*protocol_chooser
= EMPATHY_PROTOCOL_CHOOSER (object
);
388 EmpathyProtocolChooserPriv
*priv
= GET_PRIV (protocol_chooser
);
392 g_hash_table_unref (priv
->protocols
);
393 priv
->protocols
= NULL
;
396 (G_OBJECT_CLASS (empathy_protocol_chooser_parent_class
)->finalize
) (object
);
400 protocol_chooser_dispose (GObject
*object
)
402 EmpathyProtocolChooser
*protocol_chooser
= EMPATHY_PROTOCOL_CHOOSER (object
);
403 EmpathyProtocolChooserPriv
*priv
= GET_PRIV (protocol_chooser
);
405 if (priv
->dispose_run
)
408 priv
->dispose_run
= TRUE
;
412 g_object_unref (priv
->store
);
418 g_object_unref (priv
->cms
);
422 (G_OBJECT_CLASS (empathy_protocol_chooser_parent_class
)->dispose
) (object
);
426 empathy_protocol_chooser_class_init (EmpathyProtocolChooserClass
*klass
)
428 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
430 object_class
->constructed
= protocol_chooser_constructed
;
431 object_class
->dispose
= protocol_chooser_dispose
;
432 object_class
->finalize
= protocol_chooser_finalize
;
434 g_type_class_add_private (object_class
, sizeof (EmpathyProtocolChooserPriv
));
438 protocol_chooser_filter_visible_func (GtkTreeModel
*model
,
442 EmpathyProtocolChooser
*protocol_chooser
= user_data
;
443 EmpathyProtocolChooserPriv
*priv
= GET_PRIV (protocol_chooser
);
444 TpConnectionManager
*cm
= NULL
;
445 gchar
*protocol_name
= NULL
;
446 gboolean visible
= FALSE
;
449 gtk_tree_model_get (model
, iter
,
451 COL_PROTOCOL_NAME
, &protocol_name
,
452 COL_SERVICE
, &service
,
455 if (cm
!= NULL
&& protocol_name
!= NULL
)
457 TpProtocol
*protocol
;
459 protocol
= tp_connection_manager_get_protocol_object (cm
, protocol_name
);
461 if (protocol
!= NULL
)
463 visible
= priv
->filter_func (cm
, protocol
, service
,
464 priv
->filter_user_data
);
478 * empathy_protocol_chooser_get_selected_protocol:
479 * @protocol_chooser: an #EmpathyProtocolChooser
481 * Returns a pointer to the selected #TpConnectionManagerProtocol in
484 * Return value: a pointer to the selected #TpConnectionManagerProtocol
486 TpConnectionManager
*
487 empathy_protocol_chooser_dup_selected (
488 EmpathyProtocolChooser
*protocol_chooser
,
489 TpProtocol
**protocol
,
493 TpConnectionManager
*cm
= NULL
;
494 GtkTreeModel
*cur_model
;
496 g_return_val_if_fail (EMPATHY_IS_PROTOCOL_CHOOSER (protocol_chooser
), NULL
);
498 /* get the current model from the chooser, as we could either be filtering
501 cur_model
= gtk_combo_box_get_model (GTK_COMBO_BOX (protocol_chooser
));
503 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (protocol_chooser
), &iter
))
505 gtk_tree_model_get (GTK_TREE_MODEL (cur_model
), &iter
,
509 if (protocol
!= NULL
)
511 gchar
*protocol_name
= NULL
;
513 gtk_tree_model_get (GTK_TREE_MODEL (cur_model
), &iter
,
514 COL_PROTOCOL_NAME
, &protocol_name
,
517 *protocol
= tp_connection_manager_get_protocol_object (cm
,
520 g_free (protocol_name
);
522 if (*protocol
== NULL
)
524 /* For some reason the CM doesn't know about this protocol
533 gtk_tree_model_get (GTK_TREE_MODEL (cur_model
), &iter
,
534 COL_SERVICE
, service
,
543 * empathy_protocol_chooser_new:
545 * Triggers the creation of a new #EmpathyProtocolChooser.
547 * Return value: a new #EmpathyProtocolChooser widget
551 empathy_protocol_chooser_new (void)
553 return GTK_WIDGET (g_object_new (EMPATHY_TYPE_PROTOCOL_CHOOSER
, NULL
));
557 empathy_protocol_chooser_set_visible (EmpathyProtocolChooser
*protocol_chooser
,
558 EmpathyProtocolChooserFilterFunc func
,
561 EmpathyProtocolChooserPriv
*priv
;
562 GtkTreeModel
*filter_model
;
564 g_return_if_fail (EMPATHY_IS_PROTOCOL_CHOOSER (protocol_chooser
));
566 priv
= GET_PRIV (protocol_chooser
);
567 priv
->filter_func
= func
;
568 priv
->filter_user_data
= user_data
;
570 filter_model
= gtk_tree_model_filter_new (GTK_TREE_MODEL (priv
->store
),
572 gtk_combo_box_set_model (GTK_COMBO_BOX (protocol_chooser
), filter_model
);
573 g_object_unref (filter_model
);
575 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER
576 (filter_model
), protocol_chooser_filter_visible_func
,
577 protocol_chooser
, NULL
);
579 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model
));
581 gtk_combo_box_set_active (GTK_COMBO_BOX (protocol_chooser
), 0);
584 EmpathyAccountSettings
*
585 empathy_protocol_chooser_create_account_settings (EmpathyProtocolChooser
*self
)
587 EmpathyAccountSettings
*settings
= NULL
;
589 const gchar
*display_name
;
590 TpConnectionManager
*cm
;
592 gchar
*service
= NULL
;
594 cm
= empathy_protocol_chooser_dup_selected (self
, &proto
, &service
);
595 if (cm
== NULL
|| proto
== NULL
)
599 display_name
= empathy_service_name_to_display_name (service
);
601 display_name
= empathy_protocol_name_to_display_name (
602 tp_protocol_get_name (proto
));
605 /* To translator: %s is the name of the protocol, such as "Google Talk" or
608 str
= g_strdup_printf (_("New %s account"), display_name
);
610 settings
= empathy_account_settings_new (tp_connection_manager_get_name (cm
),
611 tp_protocol_get_name (proto
), service
, str
);
615 if (!tp_strdiff (service
, "google-talk"))
617 const gchar
*fallback_servers
[] = {
618 "talkx.l.google.com",
619 "talkx.l.google.com:443,oldssl",
620 "talkx.l.google.com:80",
623 const gchar
*extra_certificate_identities
[] = {
627 empathy_account_settings_set_icon_name_async (settings
, "im-google-talk",
629 empathy_account_settings_set (settings
, "server",
630 g_variant_new_string (extra_certificate_identities
[0]));
631 empathy_account_settings_set (settings
, "require-encryption",
632 g_variant_new_boolean (TRUE
));
633 empathy_account_settings_set (settings
, "fallback-servers",
634 g_variant_new_strv (fallback_servers
, -1));
636 if (empathy_account_settings_have_tp_param (settings
,
637 "extra-certificate-identities"))
639 empathy_account_settings_set (settings
,
640 "extra-certificate-identities",
641 g_variant_new_strv (extra_certificate_identities
, -1));
644 else if (!tp_strdiff (service
, "facebook"))
646 const gchar
*fallback_servers
[] = {
647 "chat.facebook.com:443",
650 empathy_account_settings_set_icon_name_async (settings
, "im-facebook",
652 empathy_account_settings_set (settings
, "require-encryption",
653 g_variant_new_boolean (TRUE
));
654 empathy_account_settings_set (settings
, "server",
655 g_variant_new_string ("chat.facebook.com"));
656 empathy_account_settings_set (settings
, "fallback-servers",
657 g_variant_new_strv (fallback_servers
, -1));
661 tp_clear_object (&cm
);