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