]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-group-chat.c
Updated.
[empathy.git] / libempathy-gtk / empathy-group-chat.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2002-2007 Imendio AB
4  * Copyright (C) 2007 Collabora Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * Authors: Mikael Hallendal <micke@imendio.com>
22  *          Richard Hult <richard@imendio.com>
23  *          Martyn Russell <martyn@imendio.com>
24  *          Xavier Claessens <xclaesse@gmail.com>
25  */
26
27 #include "config.h"
28
29 #include <string.h>
30
31 #include <gdk/gdkkeysyms.h>
32 #include <gtk/gtk.h>
33 #include <glade/glade.h>
34 #include <glib/gi18n.h>
35
36 #include <libempathy/empathy-tp-chat.h>
37 #include <libempathy/empathy-tp-chatroom.h>
38 #include <libempathy/empathy-contact.h>
39 #include <libempathy/empathy-utils.h>
40 #include <libempathy/empathy-debug.h>
41
42 #include "empathy-group-chat.h"
43 #include "empathy-chat.h"
44 #include "empathy-chat-view.h"
45 #include "empathy-contact-list-store.h"
46 #include "empathy-contact-list-view.h"
47 //#include "empathy-chat-invite.h"
48 //#include "empathy-sound.h"
49 #include "empathy-images.h"
50 #include "empathy-ui-utils.h"
51
52 #define DEBUG_DOMAIN "GroupChat"
53
54 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_GROUP_CHAT, EmpathyGroupChatPriv))
55
56 struct _EmpathyGroupChatPriv {
57         EmpathyContactListStore *store;
58         EmpathyContactListView  *view;
59         EmpathyTpChatroom      *tp_chat;
60
61         GtkWidget              *widget;
62         GtkWidget              *hpaned;
63         GtkWidget              *vbox_left;
64         GtkWidget              *scrolled_window_chat;
65         GtkWidget              *scrolled_window_input;
66         GtkWidget              *scrolled_window_contacts;
67         GtkWidget              *hbox_topic;
68         GtkWidget              *label_topic;
69
70         gchar                  *topic;
71         gchar                  *name;
72         GCompletion            *completion;
73
74         gint                    contacts_width;
75         gboolean                contacts_visible;
76 };
77
78 static void          group_chat_finalize                 (GObject           *object);
79 static void          group_chat_create_ui                (EmpathyGroupChat  *chat);
80 static void          group_chat_widget_destroy_cb        (GtkWidget         *widget,
81                                                           EmpathyGroupChat  *chat);
82 static void          group_chat_members_changed_cb       (EmpathyTpChatroom *tp_chat,
83                                                           EmpathyContact    *contact,
84                                                           EmpathyContact    *actor,
85                                                           guint              reason,
86                                                           gchar             *message,
87                                                           gboolean           is_member,
88                                                           EmpathyGroupChat  *chat);
89 static void          group_chat_topic_entry_activate_cb  (GtkWidget         *entry,
90                                                           GtkDialog         *dialog);
91 static void          group_chat_topic_response_cb        (GtkWidget         *dialog,
92                                                           gint               response,                        
93                                                           EmpathyGroupChat  *chat);
94 static const gchar * group_chat_get_name                 (EmpathyChat       *chat);
95 static gchar *       group_chat_get_tooltip              (EmpathyChat       *chat);
96 static const gchar * group_chat_get_status_icon_name     (EmpathyChat       *chat);
97 static GtkWidget *   group_chat_get_widget               (EmpathyChat       *chat);
98 static gboolean      group_chat_is_group_chat            (EmpathyChat       *chat);
99 static void          group_chat_set_tp_chat              (EmpathyChat       *chat,
100                                                           EmpathyTpChat     *tp_chat);
101 static void          group_chat_subject_notify_cb        (EmpathyTpChat     *tp_chat,
102                                                           GParamSpec        *param,
103                                                           EmpathyGroupChat  *chat);
104 static void          group_chat_name_notify_cb           (EmpathyTpChat     *tp_chat,
105                                                           GParamSpec        *param,
106                                                           EmpathyGroupChat  *chat);
107 static gboolean      group_chat_key_press_event          (EmpathyChat       *chat,
108                                                           GdkEventKey       *event);
109 static gint          group_chat_contacts_completion_func (const gchar       *s1,
110                                                           const gchar       *s2,
111                                                           gsize              n);
112
113 G_DEFINE_TYPE (EmpathyGroupChat, empathy_group_chat, EMPATHY_TYPE_CHAT)
114
115 static void
116 empathy_group_chat_class_init (EmpathyGroupChatClass *klass)
117 {
118         GObjectClass    *object_class;
119         EmpathyChatClass *chat_class;
120
121         object_class = G_OBJECT_CLASS (klass);
122         chat_class = EMPATHY_CHAT_CLASS (klass);
123
124         object_class->finalize           = group_chat_finalize;
125
126         chat_class->get_name             = group_chat_get_name;
127         chat_class->get_tooltip          = group_chat_get_tooltip;
128         chat_class->get_status_icon_name = group_chat_get_status_icon_name;
129         chat_class->get_widget           = group_chat_get_widget;
130         chat_class->is_group_chat        = group_chat_is_group_chat;
131         chat_class->set_tp_chat          = group_chat_set_tp_chat;
132         chat_class->key_press_event      = group_chat_key_press_event;
133
134         g_type_class_add_private (object_class, sizeof (EmpathyGroupChatPriv));
135 }
136
137 static void
138 empathy_group_chat_init (EmpathyGroupChat *chat)
139 {
140         EmpathyGroupChatPriv *priv;
141         EmpathyChatView      *chatview;
142
143         priv = GET_PRIV (chat);
144
145         priv->contacts_visible = TRUE;
146
147         chatview = EMPATHY_CHAT_VIEW (EMPATHY_CHAT (chat)->view);
148         empathy_chat_view_set_is_group_chat (chatview, TRUE);
149
150         group_chat_create_ui (chat);
151 }
152
153 static void
154 group_chat_finalize (GObject *object)
155 {
156         EmpathyGroupChat     *chat;
157         EmpathyGroupChatPriv *priv;
158
159         empathy_debug (DEBUG_DOMAIN, "Finalized:%p", object);
160
161         chat = EMPATHY_GROUP_CHAT (object);
162         priv = GET_PRIV (chat);
163         
164         g_free (priv->name);
165         g_free (priv->topic);
166         g_object_unref (priv->store);
167         g_object_unref (priv->tp_chat); 
168         g_completion_free (priv->completion);
169
170         G_OBJECT_CLASS (empathy_group_chat_parent_class)->finalize (object);
171 }
172
173 EmpathyGroupChat *
174 empathy_group_chat_new (McAccount *account,
175                         TpChan    *tp_chan)
176 {
177         EmpathyGroupChat     *chat;
178         EmpathyGroupChatPriv *priv;
179
180         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
181         g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL);
182
183         chat = g_object_new (EMPATHY_TYPE_GROUP_CHAT, NULL);
184
185         priv = GET_PRIV (chat);
186
187         EMPATHY_CHAT (chat)->account = g_object_ref (account);
188         priv->tp_chat = empathy_tp_chatroom_new (account, tp_chan);
189         empathy_chat_set_tp_chat (EMPATHY_CHAT (chat), EMPATHY_TP_CHAT (priv->tp_chat));
190
191         return chat;
192 }
193
194 gboolean
195 empathy_group_chat_get_show_contacts (EmpathyGroupChat *chat)
196 {
197         EmpathyGroupChat     *group_chat;
198         EmpathyGroupChatPriv *priv;
199
200         g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), FALSE);
201
202         group_chat = EMPATHY_GROUP_CHAT (chat);
203         priv = GET_PRIV (group_chat);
204
205         return priv->contacts_visible;
206 }
207
208 void
209 empathy_group_chat_set_show_contacts (EmpathyGroupChat *chat,
210                                      gboolean         show)
211 {
212         EmpathyGroupChat     *group_chat;
213         EmpathyGroupChatPriv *priv;
214
215         g_return_if_fail (EMPATHY_IS_GROUP_CHAT (chat));
216
217         group_chat = EMPATHY_GROUP_CHAT (chat);
218         priv = GET_PRIV (group_chat);
219
220         priv->contacts_visible = show;
221
222         if (show) {
223                 gtk_widget_show (priv->scrolled_window_contacts);
224                 gtk_paned_set_position (GTK_PANED (priv->hpaned),
225                                         priv->contacts_width);
226         } else {
227                 priv->contacts_width = gtk_paned_get_position (GTK_PANED (priv->hpaned));
228                 gtk_widget_hide (priv->scrolled_window_contacts);
229         }
230 }
231
232 void
233 empathy_group_chat_set_topic (EmpathyGroupChat *chat)
234 {
235         EmpathyGroupChatPriv *priv;
236         EmpathyChatWindow    *chat_window;
237         GtkWidget           *chat_dialog;
238         GtkWidget           *dialog;
239         GtkWidget           *entry;
240         GtkWidget           *hbox;
241         const gchar         *topic;
242
243         g_return_if_fail (EMPATHY_IS_GROUP_CHAT (chat));
244
245         priv = GET_PRIV (chat);
246
247         chat_window = empathy_chat_get_window (EMPATHY_CHAT (chat));
248         chat_dialog = empathy_chat_window_get_dialog (chat_window);
249
250         dialog = gtk_message_dialog_new (GTK_WINDOW (chat_dialog),
251                                          0,
252                                          GTK_MESSAGE_QUESTION,
253                                          GTK_BUTTONS_OK_CANCEL,
254                                          _("Enter the new topic you want to set for this room:"));
255
256         topic = gtk_label_get_text (GTK_LABEL (priv->label_topic));
257
258         hbox = gtk_hbox_new (FALSE, 0);
259         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
260                             hbox, FALSE, TRUE, 4);
261
262         entry = gtk_entry_new ();
263         gtk_entry_set_text (GTK_ENTRY (entry), topic);
264         gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
265                     
266         gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 4);
267
268         g_object_set (GTK_MESSAGE_DIALOG (dialog)->label, "use-markup", TRUE, NULL);
269         g_object_set_data (G_OBJECT (dialog), "entry", entry);
270
271         g_signal_connect (entry, "activate",
272                           G_CALLBACK (group_chat_topic_entry_activate_cb),
273                           dialog);
274         g_signal_connect (dialog, "response",
275                           G_CALLBACK (group_chat_topic_response_cb),
276                           chat);
277
278         gtk_widget_show_all (dialog);
279 }
280
281 static void
282 group_chat_create_ui (EmpathyGroupChat *chat)
283 {
284         EmpathyGroupChatPriv *priv;
285         GladeXML            *glade;
286         GList               *list = NULL; 
287
288         priv = GET_PRIV (chat);
289
290         glade = empathy_glade_get_file ("empathy-group-chat.glade",
291                                        "group_chat_widget",
292                                        NULL,
293                                        "group_chat_widget", &priv->widget,
294                                        "hpaned", &priv->hpaned,
295                                        "vbox_left", &priv->vbox_left,
296                                        "scrolled_window_chat", &priv->scrolled_window_chat,
297                                        "scrolled_window_input", &priv->scrolled_window_input,
298                                        "hbox_topic", &priv->hbox_topic,
299                                        "label_topic", &priv->label_topic,
300                                        "scrolled_window_contacts", &priv->scrolled_window_contacts,
301                                        NULL);
302
303         empathy_glade_connect (glade,
304                               chat,
305                               "group_chat_widget", "destroy", group_chat_widget_destroy_cb,
306                               NULL);
307
308         g_object_unref (glade);
309
310         g_object_set_data (G_OBJECT (priv->widget), "chat", g_object_ref (chat));
311
312         /* Add room GtkTextView. */
313         gtk_container_add (GTK_CONTAINER (priv->scrolled_window_chat),
314                            GTK_WIDGET (EMPATHY_CHAT (chat)->view));
315         gtk_widget_show (GTK_WIDGET (EMPATHY_CHAT (chat)->view));
316
317         /* Add input GtkTextView */
318         gtk_container_add (GTK_CONTAINER (priv->scrolled_window_input),
319                            EMPATHY_CHAT (chat)->input_text_view);
320         gtk_widget_show (EMPATHY_CHAT (chat)->input_text_view);
321
322         /* Add nick name completion */
323         priv->completion = g_completion_new ((GCompletionFunc) empathy_contact_get_name);
324         g_completion_set_compare (priv->completion,
325                                   group_chat_contacts_completion_func);
326
327         /* Set widget focus order */
328         list = g_list_append (NULL, priv->scrolled_window_input);
329         gtk_container_set_focus_chain (GTK_CONTAINER (priv->vbox_left), list);
330         g_list_free (list);
331
332         list = g_list_append (NULL, priv->vbox_left);
333         list = g_list_append (list, priv->scrolled_window_contacts);
334         gtk_container_set_focus_chain (GTK_CONTAINER (priv->hpaned), list);
335         g_list_free (list);
336
337         list = g_list_append (NULL, priv->hpaned);
338         list = g_list_append (list, priv->hbox_topic);
339         gtk_container_set_focus_chain (GTK_CONTAINER (priv->widget), list);
340         g_list_free (list);
341 }
342
343 static void
344 group_chat_widget_destroy_cb (GtkWidget       *widget,
345                               EmpathyGroupChat *chat)
346 {
347         empathy_debug (DEBUG_DOMAIN, "Destroyed");
348
349         g_object_unref (chat);
350 }
351
352 static void
353 group_chat_members_changed_cb (EmpathyTpChatroom *tp_chat,
354                                EmpathyContact     *contact,
355                                EmpathyContact     *actor,
356                                guint               reason,
357                                gchar              *message,
358                                gboolean            is_member,
359                                EmpathyGroupChat   *chat)
360 {
361         EmpathyGroupChatPriv *priv;
362         gchar                *str;
363
364         priv = GET_PRIV (chat);
365
366         if (is_member) {
367                 str = g_strdup_printf (_("%s has joined the room"),
368                                        empathy_contact_get_name (contact));
369         } else {
370                 str = g_strdup_printf (_("%s has left the room"),
371                                        empathy_contact_get_name (contact));
372         }
373         empathy_chat_view_append_event (EMPATHY_CHAT (chat)->view, str);
374         g_free (str);
375 }
376
377 static void
378 group_chat_topic_entry_activate_cb (GtkWidget *entry,
379                                     GtkDialog *dialog)
380 {
381         gtk_dialog_response (dialog, GTK_RESPONSE_OK);
382 }
383
384 static void
385 group_chat_topic_response_cb (GtkWidget       *dialog,
386                               gint             response,                              
387                               EmpathyGroupChat *chat)
388 {
389         if (response == GTK_RESPONSE_OK) {
390                 GtkWidget   *entry;
391                 const gchar *topic;
392
393                 entry = g_object_get_data (G_OBJECT (dialog), "entry");
394                 topic = gtk_entry_get_text (GTK_ENTRY (entry));
395                 
396                 if (!G_STR_EMPTY (topic)) {
397                         EmpathyGroupChatPriv *priv;
398
399                         priv = GET_PRIV (chat);
400
401                         empathy_tp_chatroom_set_topic (priv->tp_chat, topic);
402                 }
403         }
404
405         gtk_widget_destroy (dialog);
406 }
407
408 static const gchar *
409 group_chat_get_name (EmpathyChat *chat)
410 {
411         EmpathyGroupChat     *group_chat;
412         EmpathyGroupChatPriv *priv;
413
414         g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), NULL);
415
416         group_chat = EMPATHY_GROUP_CHAT (chat);
417         priv = GET_PRIV (group_chat);
418
419         if (!priv->name) {
420                 const gchar *id;
421                 const gchar *server;
422
423                 id = empathy_chat_get_id (chat);
424                 server = strstr (id, "@");
425
426                 if (server) {
427                         priv->name = g_strndup (id, server - id);
428                 } else {
429                         priv->name = g_strdup (id);
430                 } 
431         }
432
433         return priv->name;
434 }
435
436 static gchar *
437 group_chat_get_tooltip (EmpathyChat *chat)
438 {
439         EmpathyGroupChat     *group_chat;
440         EmpathyGroupChatPriv *priv;
441
442         g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), NULL);
443
444         group_chat = EMPATHY_GROUP_CHAT (chat);
445         priv = GET_PRIV (group_chat);
446
447         if (priv->topic) {
448                 gchar *topic, *tmp;
449
450                 topic = g_strdup_printf (_("Topic: %s"), priv->topic);
451                 tmp = g_strdup_printf ("%s\n%s", priv->name, topic);
452                 g_free (topic);
453
454                 return tmp;
455         }
456
457         return g_strdup (priv->name);
458 }
459
460 static const gchar *
461 group_chat_get_status_icon_name (EmpathyChat *chat)
462 {
463         return EMPATHY_IMAGE_GROUP_MESSAGE;
464 }
465
466 static GtkWidget *
467 group_chat_get_widget (EmpathyChat *chat)
468 {
469         EmpathyGroupChat     *group_chat;
470         EmpathyGroupChatPriv *priv;
471
472         g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), NULL);
473
474         group_chat = EMPATHY_GROUP_CHAT (chat);
475         priv = GET_PRIV (group_chat);
476
477         return priv->widget;
478 }
479
480 static gboolean
481 group_chat_is_group_chat (EmpathyChat *chat)
482 {
483         g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), FALSE);
484
485         return TRUE;
486 }
487
488 static void
489 group_chat_set_tp_chat (EmpathyChat    *chat,
490                         EmpathyTpChat *tp_chat)
491 {
492         EmpathyGroupChat     *group_chat;
493         EmpathyGroupChatPriv *priv;
494
495         g_return_if_fail (EMPATHY_IS_GROUP_CHAT (chat));
496
497         group_chat = EMPATHY_GROUP_CHAT (chat);
498         priv = GET_PRIV (group_chat);
499
500         /* Free all resources related to tp_chat */
501         if (priv->tp_chat) {
502                 g_object_unref (priv->tp_chat);
503                 priv->tp_chat = NULL;
504         }
505         if (priv->view) {
506                 gtk_widget_destroy (GTK_WIDGET (priv->view));
507                 g_object_unref (priv->store);
508         }
509         g_free (priv->name);
510         g_free (priv->topic);
511         priv->name = NULL;
512         priv->topic = NULL;
513
514         if (!tp_chat) {
515                 /* We are no more connected */
516                 gtk_widget_set_sensitive (priv->hbox_topic, FALSE);
517                 gtk_widget_set_sensitive (priv->scrolled_window_contacts, FALSE);
518                 return;
519         }
520
521         /* We are connected */
522         gtk_widget_set_sensitive (priv->hbox_topic, TRUE);
523         gtk_widget_set_sensitive (priv->scrolled_window_contacts, TRUE);
524
525         priv->tp_chat = g_object_ref (tp_chat);
526
527         if (empathy_tp_chatroom_get_invitation (priv->tp_chat, NULL, NULL)) {
528                 empathy_tp_chatroom_accept_invitation (priv->tp_chat);
529         }
530
531         /* Create contact list */
532         priv->store = empathy_contact_list_store_new (EMPATHY_CONTACT_LIST (priv->tp_chat));
533         priv->view = empathy_contact_list_view_new (priv->store);
534         empathy_contact_list_view_set_interactive (priv->view, TRUE);
535         gtk_container_add (GTK_CONTAINER (priv->scrolled_window_contacts),
536                            GTK_WIDGET (priv->view));
537         gtk_widget_show (GTK_WIDGET (priv->view));
538
539         /* Connect signals */
540         g_signal_connect (priv->tp_chat, "members-changed",
541                           G_CALLBACK (group_chat_members_changed_cb),
542                           chat);
543         g_signal_connect (priv->tp_chat, "notify::subject",
544                           G_CALLBACK (group_chat_subject_notify_cb),
545                           chat);
546         g_signal_connect (priv->tp_chat, "notify::name",
547                           G_CALLBACK (group_chat_name_notify_cb),
548                           chat);
549 }
550
551 static void
552 group_chat_subject_notify_cb (EmpathyTpChat   *tp_chat,
553                               GParamSpec      *param,
554                               EmpathyGroupChat *chat)
555 {
556         EmpathyGroupChatPriv *priv;
557         gchar                *str = NULL;
558
559         priv = GET_PRIV (chat);
560
561         g_object_get (priv->tp_chat, "subject", &str, NULL);
562         if (!empathy_strdiff (priv->topic, str)) {
563                 g_free (str);
564                 return;
565         }
566
567         g_free (priv->topic);
568         priv->topic = str;
569         gtk_label_set_text (GTK_LABEL (priv->label_topic), priv->topic);
570
571         if (!G_STR_EMPTY (priv->topic)) {
572                 str = g_strdup_printf (_("Topic set to: %s"), priv->topic);
573         } else {
574                 str = g_strdup (_("No topic defined"));
575         }
576         empathy_chat_view_append_event (EMPATHY_CHAT (chat)->view, str);
577         g_free (str);
578 }
579
580 static void
581 group_chat_name_notify_cb (EmpathyTpChat   *tp_chat,
582                            GParamSpec      *param,
583                            EmpathyGroupChat *chat)
584 {
585         EmpathyGroupChatPriv *priv;
586
587         priv = GET_PRIV (chat);
588
589         g_free (priv->name);
590         g_object_get (priv->tp_chat, "name", &priv->name, NULL);
591 }
592
593 static gboolean
594 group_chat_key_press_event (EmpathyChat *chat,
595                             GdkEventKey *event)
596 {
597         EmpathyGroupChatPriv *priv;
598         GtkTextBuffer        *buffer;
599         GtkTextIter           start, current;
600         gchar                *nick, *completed;
601         gint                  len;
602         GList                *list, *completed_list;
603         gboolean              is_start_of_buffer;
604
605         priv = GET_PRIV (chat);
606
607         if (!(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) &&
608             event->keyval == GDK_Tab) {
609                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (EMPATHY_CHAT (chat)->input_text_view));
610                 gtk_text_buffer_get_iter_at_mark (buffer, &current, gtk_text_buffer_get_insert (buffer));
611
612                 /* Get the start of the nick to complete. */
613                 gtk_text_buffer_get_iter_at_mark (buffer, &start, gtk_text_buffer_get_insert (buffer));
614                 gtk_text_iter_backward_word_start (&start);
615                 is_start_of_buffer = gtk_text_iter_is_start (&start);
616
617                 nick = gtk_text_buffer_get_text (buffer, &start, &current, FALSE);
618
619                 len = strlen (nick);
620
621                 list = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (priv->tp_chat));
622
623                 g_completion_add_items (priv->completion, list);
624
625                 completed_list = g_completion_complete (priv->completion,
626                                                         nick,
627                                                         &completed);
628
629                 g_free (nick);
630
631                 if (completed) {
632                         int          len;
633                         const gchar *text;
634
635                         gtk_text_buffer_delete (buffer, &start, &current);
636
637                         len = g_list_length (completed_list);
638
639                         if (len == 1) {
640                                 /* If we only have one hit, use that text
641                                  * instead of the text in completed since the
642                                  * completed text will use the typed string
643                                  * which might be cased all wrong.
644                                  * Fixes #120876
645                                  * */
646                                 text = empathy_contact_get_name (completed_list->data);
647                         } else {
648                                 text = completed;
649                         }
650
651                         gtk_text_buffer_insert_at_cursor (buffer, text, strlen (text));
652
653                         if (len == 1) {
654                                 if (is_start_of_buffer) {
655                                         gtk_text_buffer_insert_at_cursor (buffer, ", ", 2);
656                                 }
657                         }
658
659                         g_free (completed);
660                 }
661
662                 g_completion_clear_items (priv->completion);
663
664                 g_list_foreach (list, (GFunc) g_object_unref, NULL);
665                 g_list_free (list);
666
667                 return TRUE;
668         }
669
670         return FALSE;
671 }
672
673 static gint
674 group_chat_contacts_completion_func (const gchar *s1,
675                                      const gchar *s2,
676                                      gsize        n)
677 {
678         gchar *tmp, *nick1, *nick2;
679         gint   ret;
680
681         tmp = g_utf8_normalize (s1, -1, G_NORMALIZE_DEFAULT);
682         nick1 = g_utf8_casefold (tmp, -1);
683         g_free (tmp);
684
685         tmp = g_utf8_normalize (s2, -1, G_NORMALIZE_DEFAULT);
686         nick2 = g_utf8_casefold (tmp, -1);
687         g_free (tmp);
688
689         ret = strncmp (nick1, nick2, n);
690
691         g_free (nick1);
692         g_free (nick2);
693
694         return ret;
695 }
696