~bcurtiswx/ubuntu/precise/empathy/3.4.2.1-0ubuntu1

« back to all changes in this revision

Viewing changes to libempathy-gtk/gossip-chat-window.c

  • Committer: Bazaar Package Importer
  • Author(s): Sjoerd Simons
  • Date: 2007-05-20 15:31:42 UTC
  • Revision ID: james.westby@ubuntu.com-20070520153142-r3auwguxdgxhktqb
Tags: upstream-0.4
ImportĀ upstreamĀ versionĀ 0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
2
/*
 
3
 * Copyright (C) 2003-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
 *          Geert-Jan Van den Bogaerde <geertjan@gnome.org>
 
25
 *          Xavier Claessens <xclaesse@gmail.com>
 
26
 */
 
27
 
 
28
#include "config.h"
 
29
 
 
30
#include <string.h>
 
31
 
 
32
#include <gtk/gtk.h>
 
33
#include <gdk/gdkkeysyms.h>
 
34
#include <glade/glade.h>
 
35
#include <glib/gi18n.h>
 
36
 
 
37
#include <libempathy/gossip-contact.h>
 
38
#include <libempathy/gossip-debug.h>
 
39
#include <libempathy/gossip-message.h>
 
40
#include <libempathy/gossip-conf.h>
 
41
 
 
42
#include "gossip-chat-window.h"
 
43
#include "empathy-images.h"
 
44
//#include "gossip-add-contact-dialog.h"
 
45
//#include "gossip-chat-invite.h"
 
46
//#include "gossip-contact-info-dialog.h"
 
47
//#include "gossip-log-window.h"
 
48
//#include "gossip-new-chatroom-dialog.h"
 
49
#include "gossip-preferences.h"
 
50
#include "gossip-private-chat.h"
 
51
//#include "gossip-sound.h"
 
52
#include "gossip-ui-utils.h"
 
53
 
 
54
#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CHAT_WINDOW, GossipChatWindowPriv))
 
55
 
 
56
#define DEBUG_DOMAIN "ChatWindow"
 
57
 
 
58
#define URGENCY_TIMEOUT 60*1000
 
59
 
 
60
struct _GossipChatWindowPriv {
 
61
        GList       *chats;
 
62
        GList       *chats_new_msg;
 
63
        GList       *chats_composing;
 
64
 
 
65
        GossipChat  *current_chat;
 
66
 
 
67
        gboolean     page_added;
 
68
        gboolean     dnd_same_window;
 
69
 
 
70
        guint        urgency_timeout_id;
 
71
 
 
72
        GtkWidget   *dialog;
 
73
        GtkWidget   *notebook;
 
74
 
 
75
        GtkTooltips *tooltips;
 
76
 
 
77
        /* Menu items. */
 
78
        GtkWidget   *menu_conv_clear;
 
79
        GtkWidget   *menu_conv_insert_smiley;
 
80
        GtkWidget   *menu_conv_log;
 
81
        GtkWidget   *menu_conv_separator;
 
82
        GtkWidget   *menu_conv_add_contact;
 
83
        GtkWidget   *menu_conv_info;
 
84
        GtkWidget   *menu_conv_close;
 
85
 
 
86
        GtkWidget   *menu_room;
 
87
        GtkWidget   *menu_room_set_topic;
 
88
        GtkWidget   *menu_room_join_new;
 
89
        GtkWidget   *menu_room_invite;
 
90
        GtkWidget   *menu_room_add;
 
91
        GtkWidget   *menu_room_show_contacts;
 
92
 
 
93
        GtkWidget   *menu_edit_cut;
 
94
        GtkWidget   *menu_edit_copy;
 
95
        GtkWidget   *menu_edit_paste;
 
96
 
 
97
        GtkWidget   *menu_tabs_next;
 
98
        GtkWidget   *menu_tabs_prev;
 
99
        GtkWidget   *menu_tabs_left;
 
100
        GtkWidget   *menu_tabs_right;
 
101
        GtkWidget   *menu_tabs_detach;
 
102
 
 
103
        guint        save_geometry_id;
 
104
};
 
105
 
 
106
static void       gossip_chat_window_class_init         (GossipChatWindowClass *klass);
 
107
static void       gossip_chat_window_init               (GossipChatWindow      *window);
 
108
static void       gossip_chat_window_finalize           (GObject               *object);
 
109
static void       chat_window_accel_cb                  (GtkAccelGroup         *accelgroup,
 
110
                                                         GObject               *object,
 
111
                                                         guint                  key,
 
112
                                                         GdkModifierType        mod,
 
113
                                                         GossipChatWindow      *window);
 
114
static void       chat_window_close_clicked_cb          (GtkWidget             *button,
 
115
                                                         GossipChat            *chat);
 
116
static GtkWidget *chat_window_create_label              (GossipChatWindow      *window,
 
117
                                                         GossipChat            *chat);
 
118
static void       chat_window_update_status             (GossipChatWindow      *window,
 
119
                                                         GossipChat            *chat);
 
120
static void       chat_window_update_title              (GossipChatWindow      *window,
 
121
                                                         GossipChat            *chat);
 
122
static void       chat_window_update_menu               (GossipChatWindow      *window);
 
123
static gboolean   chat_window_save_geometry_timeout_cb  (GossipChatWindow      *window);
 
124
static gboolean   chat_window_configure_event_cb        (GtkWidget             *widget,
 
125
                                                         GdkEventConfigure     *event,
 
126
                                                         GossipChatWindow      *window);
 
127
static void       chat_window_conv_activate_cb          (GtkWidget             *menuitem,
 
128
                                                         GossipChatWindow      *window);
 
129
static void       chat_window_clear_activate_cb         (GtkWidget             *menuitem,
 
130
                                                         GossipChatWindow      *window);
 
131
static void       chat_window_info_activate_cb          (GtkWidget             *menuitem,
 
132
                                                         GossipChatWindow      *window);
 
133
static void       chat_window_add_contact_activate_cb   (GtkWidget             *menuitem,
 
134
                                                         GossipChatWindow      *window);
 
135
static void       chat_window_log_activate_cb           (GtkWidget             *menuitem,
 
136
                                                         GossipChatWindow      *window);
 
137
static void       chat_window_show_contacts_toggled_cb  (GtkWidget             *menuitem,
 
138
                                                         GossipChatWindow      *window);
 
139
static void       chat_window_edit_activate_cb          (GtkWidget             *menuitem,
 
140
                                                         GossipChatWindow      *window);
 
141
static void       chat_window_insert_smiley_activate_cb (GtkWidget             *menuitem,
 
142
                                                         GossipChatWindow      *window);
 
143
static void       chat_window_close_activate_cb         (GtkWidget             *menuitem,
 
144
                                                         GossipChatWindow      *window);
 
145
static void       chat_window_room_set_topic_activate_cb(GtkWidget             *menuitem,
 
146
                                                         GossipChatWindow      *window);
 
147
static void       chat_window_room_join_new_activate_cb (GtkWidget             *menuitem,
 
148
                                                         GossipChatWindow      *window);
 
149
static void       chat_window_room_invite_activate_cb   (GtkWidget             *menuitem,
 
150
                                                         GossipChatWindow      *window);
 
151
static void       chat_window_room_add_activate_cb      (GtkWidget             *menuitem,
 
152
                                                         GossipChatWindow      *window);
 
153
static void       chat_window_cut_activate_cb           (GtkWidget             *menuitem,
 
154
                                                         GossipChatWindow      *window);
 
155
static void       chat_window_copy_activate_cb          (GtkWidget             *menuitem,
 
156
                                                         GossipChatWindow      *window);
 
157
static void       chat_window_paste_activate_cb         (GtkWidget             *menuitem,
 
158
                                                         GossipChatWindow      *window);
 
159
static void       chat_window_tabs_left_activate_cb     (GtkWidget             *menuitem,
 
160
                                                         GossipChatWindow      *window);
 
161
static void       chat_window_tabs_right_activate_cb    (GtkWidget             *menuitem,
 
162
                                                         GossipChatWindow      *window);
 
163
static void       chat_window_detach_activate_cb        (GtkWidget             *menuitem,
 
164
                                                         GossipChatWindow      *window);
 
165
static gboolean   chat_window_delete_event_cb           (GtkWidget             *dialog,
 
166
                                                         GdkEvent              *event,
 
167
                                                         GossipChatWindow      *window);
 
168
static void       chat_window_status_changed_cb         (GossipChat            *chat,
 
169
                                                         GossipChatWindow      *window);
 
170
static void       chat_window_update_tooltip            (GossipChatWindow      *window,
 
171
                                                         GossipChat            *chat);
 
172
static void       chat_window_name_changed_cb           (GossipChat            *chat,
 
173
                                                         const gchar           *name,
 
174
                                                         GossipChatWindow      *window);
 
175
static void       chat_window_composing_cb              (GossipChat            *chat,
 
176
                                                         gboolean               is_composing,
 
177
                                                         GossipChatWindow      *window);
 
178
static void       chat_window_new_message_cb            (GossipChat            *chat,
 
179
                                                         GossipMessage         *message,
 
180
                                                         gboolean               is_backlog,
 
181
                                                         GossipChatWindow      *window);
 
182
static GtkNotebook* chat_window_detach_hook             (GtkNotebook           *source,
 
183
                                                         GtkWidget             *page,
 
184
                                                         gint                   x,
 
185
                                                         gint                   y,
 
186
                                                         gpointer               user_data);
 
187
static void       chat_window_page_switched_cb          (GtkNotebook           *notebook,
 
188
                                                         GtkNotebookPage       *page,
 
189
                                                         gint                   page_num,
 
190
                                                         GossipChatWindow      *window);
 
191
static void       chat_window_page_reordered_cb         (GtkNotebook           *notebook,
 
192
                                                         GtkWidget             *widget,
 
193
                                                         guint                  page_num,
 
194
                                                         GossipChatWindow      *window);
 
195
static void       chat_window_page_added_cb             (GtkNotebook           *notebook,
 
196
                                                         GtkWidget             *child,
 
197
                                                         guint                  page_num,
 
198
                                                         GossipChatWindow      *window);
 
199
static void       chat_window_page_removed_cb           (GtkNotebook           *notebook,
 
200
                                                         GtkWidget             *child,
 
201
                                                         guint                  page_num,
 
202
                                                         GossipChatWindow      *window);
 
203
static gboolean   chat_window_focus_in_event_cb         (GtkWidget             *widget,
 
204
                                                         GdkEvent              *event,
 
205
                                                         GossipChatWindow      *window);
 
206
static void       chat_window_drag_data_received        (GtkWidget             *widget,
 
207
                                                         GdkDragContext        *context,
 
208
                                                         int                    x,
 
209
                                                         int                    y,
 
210
                                                         GtkSelectionData      *selection,
 
211
                                                         guint                  info,
 
212
                                                         guint                  time,
 
213
                                                         GossipChatWindow      *window);
 
214
static void       chat_window_set_urgency_hint          (GossipChatWindow      *window,
 
215
                                                         gboolean               urgent);
 
216
 
 
217
 
 
218
static GList *chat_windows = NULL;
 
219
 
 
220
static const guint tab_accel_keys[] = {
 
221
        GDK_1, GDK_2, GDK_3, GDK_4, GDK_5,
 
222
        GDK_6, GDK_7, GDK_8, GDK_9, GDK_0
 
223
};
 
224
 
 
225
typedef enum {
 
226
        DND_DRAG_TYPE_CONTACT_ID,
 
227
        DND_DRAG_TYPE_TAB
 
228
} DndDragType;
 
229
 
 
230
static const GtkTargetEntry drag_types_dest[] = {
 
231
        { "text/contact-id", GTK_TARGET_SAME_APP, DND_DRAG_TYPE_CONTACT_ID },
 
232
        { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, DND_DRAG_TYPE_TAB },
 
233
};
 
234
 
 
235
G_DEFINE_TYPE (GossipChatWindow, gossip_chat_window, G_TYPE_OBJECT);
 
236
 
 
237
static void
 
238
gossip_chat_window_class_init (GossipChatWindowClass *klass)
 
239
{
 
240
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
241
 
 
242
        object_class->finalize = gossip_chat_window_finalize;
 
243
 
 
244
        g_type_class_add_private (object_class, sizeof (GossipChatWindowPriv));
 
245
 
 
246
        /* Set up a style for the close button with no focus padding. */
 
247
        gtk_rc_parse_string (
 
248
                "style \"gossip-close-button-style\"\n"
 
249
                "{\n"
 
250
                "  GtkWidget::focus-padding = 0\n"
 
251
                "  xthickness = 0\n"
 
252
                "  ythickness = 0\n"
 
253
                "}\n"
 
254
                "widget \"*.gossip-close-button\" style \"gossip-close-button-style\"");
 
255
 
 
256
        gtk_notebook_set_window_creation_hook (chat_window_detach_hook, NULL, NULL);
 
257
}
 
258
 
 
259
static void
 
260
gossip_chat_window_init (GossipChatWindow *window)
 
261
{
 
262
        GossipChatWindowPriv *priv;
 
263
        GladeXML             *glade;
 
264
        GtkAccelGroup        *accel_group;
 
265
        GtkWidget            *image;
 
266
        GClosure             *closure;
 
267
        GtkWidget            *menu_conv;
 
268
        GtkWidget            *menu;
 
269
        gint                  i;
 
270
        GtkWidget            *chat_vbox;
 
271
 
 
272
        priv = GET_PRIV (window);
 
273
 
 
274
        priv->tooltips = g_object_ref (gtk_tooltips_new ());
 
275
        gtk_object_sink (GTK_OBJECT (priv->tooltips));
 
276
 
 
277
        glade = gossip_glade_get_file ("gossip-chat.glade",
 
278
                                       "chat_window",
 
279
                                       NULL,
 
280
                                       "chat_window", &priv->dialog,
 
281
                                       "chat_vbox", &chat_vbox,
 
282
                                       "menu_conv", &menu_conv,
 
283
                                       "menu_conv_clear", &priv->menu_conv_clear,
 
284
                                       "menu_conv_insert_smiley", &priv->menu_conv_insert_smiley,
 
285
                                       "menu_conv_log", &priv->menu_conv_log,
 
286
                                       "menu_conv_separator", &priv->menu_conv_separator,
 
287
                                       "menu_conv_add_contact", &priv->menu_conv_add_contact,
 
288
                                       "menu_conv_info", &priv->menu_conv_info,
 
289
                                       "menu_conv_close", &priv->menu_conv_close,
 
290
                                       "menu_room", &priv->menu_room,
 
291
                                       "menu_room_set_topic", &priv->menu_room_set_topic,
 
292
                                       "menu_room_join_new", &priv->menu_room_join_new,
 
293
                                       "menu_room_invite", &priv->menu_room_invite,
 
294
                                       "menu_room_add", &priv->menu_room_add,
 
295
                                       "menu_room_show_contacts", &priv->menu_room_show_contacts,
 
296
                                       "menu_edit_cut", &priv->menu_edit_cut,
 
297
                                       "menu_edit_copy", &priv->menu_edit_copy,
 
298
                                       "menu_edit_paste", &priv->menu_edit_paste,
 
299
                                       "menu_tabs_next", &priv->menu_tabs_next,
 
300
                                       "menu_tabs_prev", &priv->menu_tabs_prev,
 
301
                                       "menu_tabs_left", &priv->menu_tabs_left,
 
302
                                       "menu_tabs_right", &priv->menu_tabs_right,
 
303
                                       "menu_tabs_detach", &priv->menu_tabs_detach,
 
304
                                       NULL);
 
305
 
 
306
        gossip_glade_connect (glade,
 
307
                              window,
 
308
                              "chat_window", "configure-event", chat_window_configure_event_cb,
 
309
                              "menu_conv", "activate", chat_window_conv_activate_cb,
 
310
                              "menu_conv_clear", "activate", chat_window_clear_activate_cb,
 
311
                              "menu_conv_log", "activate", chat_window_log_activate_cb,
 
312
                              "menu_conv_add_contact", "activate", chat_window_add_contact_activate_cb,
 
313
                              "menu_conv_info", "activate", chat_window_info_activate_cb,
 
314
                              "menu_conv_close", "activate", chat_window_close_activate_cb,
 
315
                              "menu_room_set_topic", "activate", chat_window_room_set_topic_activate_cb,
 
316
                              "menu_room_join_new", "activate", chat_window_room_join_new_activate_cb,
 
317
                              "menu_room_invite", "activate", chat_window_room_invite_activate_cb,
 
318
                              "menu_room_add", "activate", chat_window_room_add_activate_cb,
 
319
                              "menu_edit", "activate", chat_window_edit_activate_cb,
 
320
                              "menu_edit_cut", "activate", chat_window_cut_activate_cb,
 
321
                              "menu_edit_copy", "activate", chat_window_copy_activate_cb,
 
322
                              "menu_edit_paste", "activate", chat_window_paste_activate_cb,
 
323
                              "menu_tabs_left", "activate", chat_window_tabs_left_activate_cb,
 
324
                              "menu_tabs_right", "activate", chat_window_tabs_right_activate_cb,
 
325
                              "menu_tabs_detach", "activate", chat_window_detach_activate_cb,
 
326
                              NULL);
 
327
 
 
328
        g_object_unref (glade);
 
329
 
 
330
        priv->notebook = gtk_notebook_new ();
 
331
        gtk_notebook_set_group_id (GTK_NOTEBOOK (priv->notebook), 1); 
 
332
        gtk_box_pack_start (GTK_BOX (chat_vbox), priv->notebook, TRUE, TRUE, 0);
 
333
        gtk_widget_show (priv->notebook);
 
334
 
 
335
        /* Set up accels */
 
336
        accel_group = gtk_accel_group_new ();
 
337
        gtk_window_add_accel_group (GTK_WINDOW (priv->dialog), accel_group);
 
338
 
 
339
        for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) {
 
340
                closure =  g_cclosure_new (G_CALLBACK (chat_window_accel_cb),
 
341
                                           window,
 
342
                                           NULL);
 
343
                gtk_accel_group_connect (accel_group,
 
344
                                         tab_accel_keys[i],
 
345
                                         GDK_MOD1_MASK,
 
346
                                         0,
 
347
                                         closure);
 
348
        }
 
349
 
 
350
        g_object_unref (accel_group);
 
351
 
 
352
        /* Set the contact information menu item image to the Gossip
 
353
         * stock image
 
354
         */
 
355
        image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (priv->menu_conv_info));
 
356
        gtk_image_set_from_icon_name (GTK_IMAGE (image),
 
357
                                      EMPATHY_IMAGE_CONTACT_INFORMATION,
 
358
                                      GTK_ICON_SIZE_MENU);
 
359
 
 
360
        /* Set up smiley menu */
 
361
        menu = gossip_chat_view_get_smiley_menu (
 
362
                G_CALLBACK (chat_window_insert_smiley_activate_cb),
 
363
                window,
 
364
                priv->tooltips);
 
365
        gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->menu_conv_insert_smiley), menu);
 
366
 
 
367
        /* Set up signals we can't do with glade since we may need to
 
368
         * block/unblock them at some later stage.
 
369
         */
 
370
 
 
371
        g_signal_connect (priv->dialog,
 
372
                          "delete_event",
 
373
                          G_CALLBACK (chat_window_delete_event_cb),
 
374
                          window);
 
375
 
 
376
        g_signal_connect (priv->menu_room_show_contacts,
 
377
                          "toggled",
 
378
                          G_CALLBACK (chat_window_show_contacts_toggled_cb),
 
379
                          window);
 
380
 
 
381
        g_signal_connect_swapped (priv->menu_tabs_prev,
 
382
                                  "activate",
 
383
                                  G_CALLBACK (gtk_notebook_prev_page),
 
384
                                  priv->notebook);
 
385
        g_signal_connect_swapped (priv->menu_tabs_next,
 
386
                                  "activate",
 
387
                                  G_CALLBACK (gtk_notebook_next_page),
 
388
                                  priv->notebook);
 
389
 
 
390
        g_signal_connect (priv->dialog,
 
391
                          "focus_in_event",
 
392
                          G_CALLBACK (chat_window_focus_in_event_cb),
 
393
                          window);
 
394
        g_signal_connect_after (priv->notebook,
 
395
                                "switch_page",
 
396
                                G_CALLBACK (chat_window_page_switched_cb),
 
397
                                window);
 
398
        g_signal_connect (priv->notebook,
 
399
                          "page_reordered",
 
400
                          G_CALLBACK (chat_window_page_reordered_cb),
 
401
                          window);
 
402
        g_signal_connect (priv->notebook,
 
403
                          "page_added",
 
404
                          G_CALLBACK (chat_window_page_added_cb),
 
405
                          window);
 
406
        g_signal_connect (priv->notebook,
 
407
                          "page_removed",
 
408
                          G_CALLBACK (chat_window_page_removed_cb),
 
409
                          window);
 
410
 
 
411
        /* Set up drag and drop */
 
412
        gtk_drag_dest_set (GTK_WIDGET (priv->notebook),
 
413
                           GTK_DEST_DEFAULT_ALL,
 
414
                           drag_types_dest,
 
415
                           G_N_ELEMENTS (drag_types_dest),
 
416
                           GDK_ACTION_MOVE);
 
417
 
 
418
        g_signal_connect (priv->notebook,
 
419
                          "drag-data-received",
 
420
                          G_CALLBACK (chat_window_drag_data_received),
 
421
                          window);
 
422
 
 
423
        chat_windows = g_list_prepend (chat_windows, window);
 
424
 
 
425
        /* Set up private details */
 
426
        priv->chats = NULL;
 
427
        priv->chats_new_msg = NULL;
 
428
        priv->chats_composing = NULL;
 
429
        priv->current_chat = NULL;
 
430
}
 
431
 
 
432
/* Returns the window to open a new tab in if there is only one window
 
433
 * visble, otherwise, returns NULL indicating that a new window should
 
434
 * be added.
 
435
 */
 
436
GossipChatWindow *
 
437
gossip_chat_window_get_default (void)
 
438
{
 
439
        GList    *l;
 
440
        gboolean  separate_windows = TRUE;
 
441
 
 
442
        gossip_conf_get_bool (gossip_conf_get (),
 
443
                              GOSSIP_PREFS_UI_SEPARATE_CHAT_WINDOWS,
 
444
                              &separate_windows);
 
445
 
 
446
        if (separate_windows) {
 
447
                /* Always create a new window */
 
448
                return NULL;
 
449
        }
 
450
 
 
451
        for (l = chat_windows; l; l = l->next) {
 
452
                GossipChatWindow *chat_window;
 
453
                GtkWidget        *dialog;
 
454
                GdkWindow        *window;
 
455
                gboolean          visible;
 
456
 
 
457
                chat_window = l->data;
 
458
 
 
459
                dialog = gossip_chat_window_get_dialog (chat_window);
 
460
                window = dialog->window;
 
461
 
 
462
                g_object_get (dialog,
 
463
                              "visible", &visible,
 
464
                              NULL);
 
465
 
 
466
                visible = visible && !(gdk_window_get_state (window) & GDK_WINDOW_STATE_ICONIFIED);
 
467
 
 
468
                if (visible) {
 
469
                        /* Found a visible window on this desktop */
 
470
                        return chat_window;
 
471
                }
 
472
        }
 
473
 
 
474
        return NULL;
 
475
}
 
476
 
 
477
static void
 
478
gossip_chat_window_finalize (GObject *object)
 
479
{
 
480
        GossipChatWindow     *window;
 
481
        GossipChatWindowPriv *priv;
 
482
 
 
483
        window = GOSSIP_CHAT_WINDOW (object);
 
484
        priv = GET_PRIV (window);
 
485
 
 
486
        gossip_debug (DEBUG_DOMAIN, "Finalized: %p", object);
 
487
 
 
488
        if (priv->save_geometry_id != 0) {
 
489
                g_source_remove (priv->save_geometry_id);
 
490
        }
 
491
 
 
492
        if (priv->urgency_timeout_id != 0) {
 
493
                g_source_remove (priv->urgency_timeout_id);
 
494
        }
 
495
 
 
496
        chat_windows = g_list_remove (chat_windows, window);
 
497
        gtk_widget_destroy (priv->dialog);
 
498
 
 
499
        g_object_unref (priv->tooltips);
 
500
 
 
501
        G_OBJECT_CLASS (gossip_chat_window_parent_class)->finalize (object);
 
502
}
 
503
 
 
504
static void
 
505
chat_window_accel_cb (GtkAccelGroup    *accelgroup,
 
506
                      GObject          *object,
 
507
                      guint             key,
 
508
                      GdkModifierType   mod,
 
509
                      GossipChatWindow *window)
 
510
{
 
511
        GossipChatWindowPriv *priv;
 
512
        gint                  num = -1;
 
513
        gint                  i;
 
514
 
 
515
        priv = GET_PRIV (window);
 
516
 
 
517
        for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) {
 
518
                if (tab_accel_keys[i] == key) {
 
519
                        num = i;
 
520
                        break;
 
521
                }
 
522
        }
 
523
 
 
524
        if (num != -1) {
 
525
                gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), num);
 
526
        }
 
527
}
 
528
 
 
529
static void
 
530
chat_window_close_clicked_cb (GtkWidget  *button,
 
531
                              GossipChat *chat)
 
532
{
 
533
        GossipChatWindow *window;
 
534
 
 
535
        window = gossip_chat_get_window (chat);
 
536
        gossip_chat_window_remove_chat (window, chat);
 
537
}
 
538
 
 
539
static void
 
540
chat_window_close_button_style_set_cb (GtkWidget *button,
 
541
                                       GtkStyle  *previous_style,
 
542
                                       gpointer   user_data)
 
543
{
 
544
        gint h, w;
 
545
 
 
546
        gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
 
547
                                           GTK_ICON_SIZE_MENU, &w, &h);
 
548
 
 
549
        gtk_widget_set_size_request (button, w, h);
 
550
}
 
551
 
 
552
static GtkWidget *
 
553
chat_window_create_label (GossipChatWindow *window,
 
554
                          GossipChat       *chat)
 
555
{
 
556
        GossipChatWindowPriv *priv;
 
557
        GtkWidget            *hbox;
 
558
        GtkWidget            *name_label;
 
559
        GtkWidget            *status_image;
 
560
        GtkWidget            *close_button;
 
561
        GtkWidget            *close_image;
 
562
        GtkWidget            *event_box;
 
563
        GtkWidget            *event_box_hbox;
 
564
        PangoAttrList        *attr_list;
 
565
        PangoAttribute       *attr;
 
566
 
 
567
        priv = GET_PRIV (window);
 
568
 
 
569
        /* The spacing between the button and the label. */
 
570
        hbox = gtk_hbox_new (FALSE, 0);
 
571
 
 
572
        event_box = gtk_event_box_new ();
 
573
        gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
 
574
 
 
575
        name_label = gtk_label_new (gossip_chat_get_name (chat));
 
576
        gtk_label_set_ellipsize (GTK_LABEL (name_label), PANGO_ELLIPSIZE_END);
 
577
 
 
578
        attr_list = pango_attr_list_new ();
 
579
        attr = pango_attr_scale_new (1/1.2);
 
580
        attr->start_index = 0;
 
581
        attr->end_index = -1;
 
582
        pango_attr_list_insert (attr_list, attr);
 
583
        gtk_label_set_attributes (GTK_LABEL (name_label), attr_list);
 
584
        pango_attr_list_unref (attr_list);
 
585
 
 
586
        gtk_misc_set_padding (GTK_MISC (name_label), 2, 0);
 
587
        gtk_misc_set_alignment (GTK_MISC (name_label), 0.0, 0.5);
 
588
        g_object_set_data (G_OBJECT (chat), "chat-window-tab-label", name_label);
 
589
 
 
590
        status_image = gtk_image_new ();
 
591
 
 
592
        /* Spacing between the icon and label. */
 
593
        event_box_hbox = gtk_hbox_new (FALSE, 0);
 
594
 
 
595
        gtk_box_pack_start (GTK_BOX (event_box_hbox), status_image, FALSE, FALSE, 0);
 
596
        gtk_box_pack_start (GTK_BOX (event_box_hbox), name_label, TRUE, TRUE, 0);
 
597
 
 
598
        g_object_set_data (G_OBJECT (chat), "chat-window-tab-image", status_image);
 
599
        g_object_set_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget", event_box);
 
600
 
 
601
        close_button = gtk_button_new ();
 
602
        gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
 
603
 
 
604
        /* We don't want focus/keynav for the button to avoid clutter, and
 
605
         * Ctrl-W works anyway.
 
606
         */
 
607
        GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_FOCUS);
 
608
        GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_DEFAULT);
 
609
 
 
610
        /* Set the name to make the special rc style match. */
 
611
        gtk_widget_set_name (close_button, "gossip-close-button");
 
612
 
 
613
        close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
 
614
 
 
615
        gtk_container_add (GTK_CONTAINER (close_button), close_image);
 
616
 
 
617
        gtk_container_add (GTK_CONTAINER (event_box), event_box_hbox);
 
618
        gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0);
 
619
        gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
 
620
 
 
621
        /* React to theme changes and also used to setup the initial size
 
622
         * correctly.
 
623
         */
 
624
        g_signal_connect (close_button,
 
625
                          "style-set",
 
626
                          G_CALLBACK (chat_window_close_button_style_set_cb),
 
627
                          chat);
 
628
 
 
629
        g_signal_connect (close_button,
 
630
                          "clicked",
 
631
                          G_CALLBACK (chat_window_close_clicked_cb),
 
632
                          chat);
 
633
 
 
634
        /* Set up tooltip */
 
635
        chat_window_update_tooltip (window, chat);
 
636
 
 
637
        gtk_widget_show_all (hbox);
 
638
 
 
639
        return hbox;
 
640
}
 
641
 
 
642
static void
 
643
chat_window_update_status (GossipChatWindow *window,
 
644
                           GossipChat       *chat)
 
645
{
 
646
        GossipChatWindowPriv *priv;
 
647
        GtkImage             *image;
 
648
        const gchar          *icon_name = NULL;
 
649
 
 
650
        priv = GET_PRIV (window);
 
651
 
 
652
        if (g_list_find (priv->chats_new_msg, chat)) {
 
653
                icon_name = EMPATHY_IMAGE_MESSAGE;
 
654
        }
 
655
        else if (g_list_find (priv->chats_composing, chat)) {
 
656
                icon_name = EMPATHY_IMAGE_TYPING;
 
657
        }
 
658
        else {
 
659
                icon_name = gossip_chat_get_status_icon_name (chat);
 
660
        }
 
661
        image = g_object_get_data (G_OBJECT (chat), "chat-window-tab-image");
 
662
        gtk_image_set_from_icon_name (image, icon_name, GTK_ICON_SIZE_MENU);
 
663
 
 
664
        chat_window_update_title (window, chat);
 
665
        chat_window_update_tooltip (window, chat);
 
666
}
 
667
 
 
668
static void
 
669
chat_window_update_title (GossipChatWindow *window,
 
670
                          GossipChat       *chat)
 
671
{
 
672
        GossipChatWindowPriv    *priv;
 
673
        const gchar             *str;
 
674
        gchar                   *title;
 
675
        gint                     n_chats;
 
676
        
 
677
        priv = GET_PRIV (window);
 
678
        
 
679
        n_chats = g_list_length (priv->chats);
 
680
        if (n_chats == 1) {
 
681
                if (priv->chats_new_msg) {
 
682
                        title = g_strdup_printf (
 
683
                                "%s - %s",
 
684
                                gossip_chat_get_name (priv->current_chat),
 
685
                                _("New Message"));
 
686
                }
 
687
                else if (gossip_chat_is_group_chat (priv->current_chat)) {
 
688
                        title = g_strdup_printf (
 
689
                                "%s - %s", 
 
690
                                gossip_chat_get_name (priv->current_chat),
 
691
                                _("Chat Room"));
 
692
                } else {
 
693
                        title = g_strdup_printf (
 
694
                                "%s - %s", 
 
695
                                gossip_chat_get_name (priv->current_chat),
 
696
                                _("Conversation"));
 
697
                }
 
698
        } else {
 
699
                if (priv->chats_new_msg) {
 
700
                        GString *names;
 
701
                        GList   *l;
 
702
                        gint     n_messages = 0;
 
703
 
 
704
                        names = g_string_new (NULL);
 
705
 
 
706
                        for (l = priv->chats_new_msg; l; l = l->next) {
 
707
                                n_messages++;
 
708
                                g_string_append (names,
 
709
                                                 gossip_chat_get_name (l->data));
 
710
                                if (l->next) {
 
711
                                        g_string_append (names, ", ");
 
712
                                }
 
713
                        }
 
714
                        
 
715
                        str = ngettext ("New Message", "New Messages", n_messages);
 
716
                        title = g_strdup_printf ("%s - %s", names->str, str);
 
717
                        g_string_free (names, TRUE);
 
718
                } else {
 
719
                        str = ngettext ("Conversation", "Conversations (%d)", n_chats);
 
720
                        title = g_strdup_printf (str, n_chats);
 
721
                }
 
722
        }
 
723
 
 
724
        gtk_window_set_title (GTK_WINDOW (priv->dialog), title);
 
725
        g_free (title);
 
726
 
 
727
        if (priv->chats_new_msg) {
 
728
                gtk_window_set_icon_name (GTK_WINDOW (priv->dialog),
 
729
                                          EMPATHY_IMAGE_MESSAGE);
 
730
        } else {
 
731
                gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), NULL);
 
732
        }
 
733
}
 
734
 
 
735
static void
 
736
chat_window_update_menu (GossipChatWindow *window)
 
737
{
 
738
        GossipChatWindowPriv *priv;
 
739
        gboolean              first_page;
 
740
        gboolean              last_page;
 
741
        gboolean              is_connected;
 
742
        gint                  num_pages;
 
743
        gint                  page_num;
 
744
 
 
745
        priv = GET_PRIV (window);
 
746
 
 
747
        /* Notebook pages */
 
748
        page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
 
749
        num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
 
750
        first_page = (page_num == 0);
 
751
        last_page = (page_num == (num_pages - 1));
 
752
 
 
753
        gtk_widget_set_sensitive (priv->menu_tabs_next, !last_page);
 
754
        gtk_widget_set_sensitive (priv->menu_tabs_prev, !first_page);
 
755
        gtk_widget_set_sensitive (priv->menu_tabs_detach, num_pages > 1);
 
756
        gtk_widget_set_sensitive (priv->menu_tabs_left, !first_page);
 
757
        gtk_widget_set_sensitive (priv->menu_tabs_right, !last_page);
 
758
 
 
759
        is_connected = gossip_chat_is_connected (priv->current_chat);
 
760
 
 
761
        if (gossip_chat_is_group_chat (priv->current_chat)) {
 
762
#if 0
 
763
FIXME:
 
764
                GossipGroupChat       *group_chat;
 
765
                GossipChatroomManager *manager;
 
766
                GossipChatroom        *chatroom;
 
767
                GossipChatroomId       id;
 
768
                gboolean               saved;
 
769
 
 
770
                group_chat = GOSSIP_GROUP_CHAT (priv->current_chat);
 
771
                chatroom = gossip_group_chat_get_chatroom (group_chat);
 
772
 
 
773
                /* Show / Hide widgets */
 
774
                gtk_widget_show (priv->menu_room);
 
775
 
 
776
                gtk_widget_hide (priv->menu_conv_add_contact);
 
777
                gtk_widget_hide (priv->menu_conv_info);
 
778
                gtk_widget_hide (priv->menu_conv_separator);
 
779
 
 
780
                /* Can we add this room to our favourites and are we
 
781
                 * connected to the room?
 
782
                 */
 
783
                manager = gossip_app_get_chatroom_manager ();
 
784
                id = gossip_chatroom_get_id (chatroom);
 
785
                saved = gossip_chatroom_manager_find (manager, id) != NULL;
 
786
 
 
787
                gtk_widget_set_sensitive (priv->menu_room_add, !saved);
 
788
                gtk_widget_set_sensitive (priv->menu_conv_insert_smiley, is_connected);
 
789
                gtk_widget_set_sensitive (priv->menu_room_join_new, is_connected);
 
790
                gtk_widget_set_sensitive (priv->menu_room_invite, is_connected);
 
791
 
 
792
                /* We need to block the signal here because all we are
 
793
                 * really trying to do is check or uncheck the menu
 
794
                 * item. If we don't do this we get funny behaviour
 
795
                 * with 2 or more group chat windows where showing
 
796
                 * contacts doesn't do anything.
 
797
                 */
 
798
                show_contacts = gossip_chat_get_show_contacts (priv->current_chat);
 
799
 
 
800
                g_signal_handlers_block_by_func (priv->menu_room_show_contacts,
 
801
                                                 chat_window_show_contacts_toggled_cb,
 
802
                                                 window);
 
803
 
 
804
                g_object_set (priv->menu_room_show_contacts,
 
805
                              "active", show_contacts,
 
806
                              NULL);
 
807
 
 
808
                g_signal_handlers_unblock_by_func (priv->menu_room_show_contacts,
 
809
                                                   chat_window_show_contacts_toggled_cb,
 
810
                                                   window);
 
811
#endif
 
812
        } else {
 
813
                GossipPrivateChat  *chat;
 
814
                GossipSubscription  subscription;
 
815
                GossipContact      *contact;
 
816
 
 
817
                chat = GOSSIP_PRIVATE_CHAT (priv->current_chat);
 
818
 
 
819
                /* Show / Hide widgets */
 
820
                gtk_widget_hide (priv->menu_room);
 
821
 
 
822
                contact = gossip_private_chat_get_contact (chat);
 
823
                subscription = gossip_contact_get_subscription (contact);
 
824
                if (!(subscription & GOSSIP_SUBSCRIPTION_FROM)) {
 
825
                        gtk_widget_show (priv->menu_conv_add_contact);
 
826
                } else {
 
827
                        gtk_widget_hide (priv->menu_conv_add_contact);
 
828
                }
 
829
 
 
830
                gtk_widget_show (priv->menu_conv_separator);
 
831
                gtk_widget_show (priv->menu_conv_info);
 
832
 
 
833
                /* Are we connected? */
 
834
                gtk_widget_set_sensitive (priv->menu_conv_insert_smiley, is_connected);
 
835
                gtk_widget_set_sensitive (priv->menu_conv_add_contact, is_connected);
 
836
                gtk_widget_set_sensitive (priv->menu_conv_info, is_connected);
 
837
        }
 
838
}
 
839
 
 
840
static void
 
841
chat_window_insert_smiley_activate_cb (GtkWidget        *menuitem,
 
842
                                       GossipChatWindow *window)
 
843
{
 
844
        GossipChatWindowPriv *priv;
 
845
        GossipChat           *chat;
 
846
        GtkTextBuffer        *buffer;
 
847
        GtkTextIter           iter;
 
848
        const gchar          *smiley;
 
849
 
 
850
        priv = GET_PRIV (window);
 
851
 
 
852
        chat = priv->current_chat;
 
853
 
 
854
        smiley = g_object_get_data (G_OBJECT (menuitem), "smiley_text");
 
855
 
 
856
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view));
 
857
        gtk_text_buffer_get_end_iter (buffer, &iter);
 
858
        gtk_text_buffer_insert (buffer, &iter,
 
859
                                smiley, -1);
 
860
}
 
861
 
 
862
static void
 
863
chat_window_clear_activate_cb (GtkWidget        *menuitem,
 
864
                               GossipChatWindow *window)
 
865
{
 
866
        GossipChatWindowPriv *priv;
 
867
 
 
868
        priv = GET_PRIV (window);
 
869
 
 
870
        gossip_chat_clear (priv->current_chat);
 
871
}
 
872
 
 
873
static void
 
874
chat_window_add_contact_activate_cb (GtkWidget        *menuitem,
 
875
                                     GossipChatWindow *window)
 
876
{
 
877
        GossipChatWindowPriv *priv;
 
878
        //GossipContact        *contact;
 
879
 
 
880
        priv = GET_PRIV (window);
 
881
 
 
882
        //contact = gossip_chat_get_contact (priv->current_chat);
 
883
 
 
884
        // FIXME: gossip_add_contact_dialog_show (NULL, contact);
 
885
}
 
886
 
 
887
static void
 
888
chat_window_log_activate_cb (GtkWidget        *menuitem,
 
889
                             GossipChatWindow *window)
 
890
{
 
891
/* FIXME:
 
892
        GossipChatWindowPriv *priv;
 
893
 
 
894
        priv = GET_PRIV (window);
 
895
 
 
896
        if (gossip_chat_is_group_chat (priv->current_chat)) {
 
897
                GossipGroupChat *group_chat;
 
898
                GossipChatroom  *chatroom;
 
899
 
 
900
                group_chat = GOSSIP_GROUP_CHAT (priv->current_chat);
 
901
                chatroom = gossip_group_chat_get_chatroom (group_chat);
 
902
                gossip_log_window_show (NULL, chatroom);
 
903
        } else {
 
904
                GossipContact *contact;
 
905
 
 
906
                contact = gossip_chat_get_contact (priv->current_chat);
 
907
                gossip_log_window_show (contact, NULL);
 
908
        }
 
909
*/
 
910
}
 
911
 
 
912
static void
 
913
chat_window_info_activate_cb (GtkWidget        *menuitem,
 
914
                              GossipChatWindow *window)
 
915
{
 
916
        GossipChatWindowPriv *priv;
 
917
        //GossipContact        *contact;
 
918
 
 
919
        priv = GET_PRIV (window);
 
920
/*FIXME:
 
921
        contact = gossip_chat_get_contact (priv->current_chat);
 
922
 
 
923
        gossip_contact_info_dialog_show (contact,
 
924
                                         GTK_WINDOW (priv->dialog));*/
 
925
}
 
926
 
 
927
static gboolean
 
928
chat_window_save_geometry_timeout_cb (GossipChatWindow *window)
 
929
{
 
930
        GossipChatWindowPriv *priv;
 
931
        gint                  x, y, w, h;
 
932
 
 
933
        priv = GET_PRIV (window);
 
934
 
 
935
        gtk_window_get_size (GTK_WINDOW (priv->dialog), &w, &h);
 
936
        gtk_window_get_position (GTK_WINDOW (priv->dialog), &x, &y);
 
937
 
 
938
        gossip_chat_save_geometry (priv->current_chat, x, y, w, h);
 
939
 
 
940
        priv->save_geometry_id = 0;
 
941
 
 
942
        return FALSE;
 
943
}
 
944
 
 
945
static gboolean
 
946
chat_window_configure_event_cb (GtkWidget         *widget,
 
947
                                GdkEventConfigure *event,
 
948
                                GossipChatWindow  *window)
 
949
{
 
950
        GossipChatWindowPriv *priv;
 
951
 
 
952
        priv = GET_PRIV (window);
 
953
 
 
954
        /* Only save geometry information if there is ONE chat visible. */
 
955
        if (g_list_length (priv->chats) > 1) {
 
956
                return FALSE;
 
957
        }
 
958
 
 
959
        if (priv->save_geometry_id != 0) {
 
960
                g_source_remove (priv->save_geometry_id);
 
961
        }
 
962
 
 
963
        priv->save_geometry_id =
 
964
                g_timeout_add (500,
 
965
                               (GSourceFunc) chat_window_save_geometry_timeout_cb,
 
966
                               window);
 
967
 
 
968
        return FALSE;
 
969
}
 
970
 
 
971
static void
 
972
chat_window_conv_activate_cb (GtkWidget        *menuitem,
 
973
                              GossipChatWindow *window)
 
974
{
 
975
        GossipChatWindowPriv *priv;
 
976
        gboolean              log_exists = FALSE;
 
977
 
 
978
        priv = GET_PRIV (window);
 
979
/* FIXME:
 
980
        if (gossip_chat_is_group_chat (priv->current_chat)) {
 
981
                GossipGroupChat *group_chat;
 
982
                GossipChatroom  *chatroom;
 
983
 
 
984
                group_chat = GOSSIP_GROUP_CHAT (priv->current_chat);
 
985
                chatroom = gossip_group_chat_get_chatroom (group_chat);
 
986
                if (chatroom) {
 
987
                        log_exists = gossip_log_exists_for_chatroom (chatroom);
 
988
                }
 
989
        } else {
 
990
                GossipContact *contact;
 
991
 
 
992
                contact = gossip_chat_get_contact (priv->current_chat);
 
993
                if (contact) {
 
994
                        log_exists = gossip_log_exists_for_contact (contact);
 
995
                }
 
996
        }
 
997
*/
 
998
        gtk_widget_set_sensitive (priv->menu_conv_log, log_exists);
 
999
}
 
1000
 
 
1001
static void
 
1002
chat_window_show_contacts_toggled_cb (GtkWidget        *menuitem,
 
1003
                                      GossipChatWindow *window)
 
1004
{
 
1005
        GossipChatWindowPriv *priv;
 
1006
        gboolean              show;
 
1007
 
 
1008
        priv = GET_PRIV (window);
 
1009
 
 
1010
        g_return_if_fail (priv->current_chat != NULL);
 
1011
 
 
1012
        show = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (priv->menu_room_show_contacts));
 
1013
        //gossip_group_chat_set_show_contacts (GOSSIP_GROUP_CHAT (priv->current_chat), show);
 
1014
}
 
1015
 
 
1016
static void
 
1017
chat_window_close_activate_cb (GtkWidget        *menuitem,
 
1018
                               GossipChatWindow *window)
 
1019
{
 
1020
        GossipChatWindowPriv *priv;
 
1021
 
 
1022
        priv = GET_PRIV (window);
 
1023
 
 
1024
        g_return_if_fail (priv->current_chat != NULL);
 
1025
 
 
1026
        gossip_chat_window_remove_chat (window, priv->current_chat);
 
1027
}
 
1028
 
 
1029
static void
 
1030
chat_window_room_set_topic_activate_cb (GtkWidget        *menuitem,
 
1031
                                        GossipChatWindow *window)
 
1032
{
 
1033
/*FIXME
 
1034
        GossipChatWindowPriv *priv;
 
1035
        
 
1036
        priv = GET_PRIV (window);
 
1037
 
 
1038
        if (gossip_chat_is_group_chat (priv->current_chat)) {
 
1039
                GossipGroupChat *group_chat;
 
1040
 
 
1041
                group_chat = GOSSIP_GROUP_CHAT (priv->current_chat);
 
1042
                gossip_group_chat_set_topic (group_chat);
 
1043
        }*/
 
1044
}
 
1045
 
 
1046
static void
 
1047
chat_window_room_join_new_activate_cb (GtkWidget        *menuitem,
 
1048
                                       GossipChatWindow *window)
 
1049
{
 
1050
        GossipChatWindowPriv *priv;
 
1051
 
 
1052
        priv = GET_PRIV (window);
 
1053
 
 
1054
        // FIXME: gossip_new_chatroom_dialog_show (GTK_WINDOW (priv->dialog));
 
1055
}
 
1056
 
 
1057
static void
 
1058
chat_window_room_invite_activate_cb (GtkWidget        *menuitem,
 
1059
                                     GossipChatWindow *window)
 
1060
{
 
1061
/* FIXME:
 
1062
        GossipChatWindowPriv *priv;
 
1063
        GossipContact        *own_contact;
 
1064
        GossipChatroomId      id = 0;
 
1065
 
 
1066
        priv = GET_PRIV (window);
 
1067
        own_contact = gossip_chat_get_own_contact (priv->current_chat);
 
1068
 
 
1069
        if (gossip_chat_is_group_chat (priv->current_chat)) {
 
1070
                GossipGroupChat *group_chat;
 
1071
 
 
1072
                group_chat = GOSSIP_GROUP_CHAT (priv->current_chat);
 
1073
                id = gossip_group_chat_get_chatroom_id (group_chat);
 
1074
        }
 
1075
 
 
1076
        gossip_chat_invite_dialog_show (own_contact, id);
 
1077
*/
 
1078
}
 
1079
 
 
1080
static void
 
1081
chat_window_room_add_activate_cb (GtkWidget        *menuitem,
 
1082
                                  GossipChatWindow *window)
 
1083
{
 
1084
/* FIXME:
 
1085
        GossipChatWindowPriv  *priv;
 
1086
        GossipGroupChat       *group_chat;
 
1087
        GossipChatroomManager *manager;
 
1088
        GossipChatroom        *chatroom;
 
1089
 
 
1090
        priv = GET_PRIV (window);
 
1091
 
 
1092
        g_return_if_fail (priv->current_chat != NULL);
 
1093
 
 
1094
        if (!gossip_chat_is_group_chat (priv->current_chat)) {
 
1095
                return;
 
1096
        }
 
1097
 
 
1098
        group_chat = GOSSIP_GROUP_CHAT (priv->current_chat);
 
1099
        chatroom = gossip_group_chat_get_chatroom (group_chat);
 
1100
        gossip_chatroom_set_favourite (chatroom, TRUE);
 
1101
 
 
1102
        manager = gossip_app_get_chatroom_manager ();
 
1103
        gossip_chatroom_manager_add (manager, chatroom);
 
1104
        gossip_chatroom_manager_store (manager);
 
1105
 
 
1106
        chat_window_update_menu (window);
 
1107
*/
 
1108
}
 
1109
 
 
1110
static void
 
1111
chat_window_edit_activate_cb (GtkWidget        *menuitem,
 
1112
                              GossipChatWindow *window)
 
1113
{
 
1114
        GossipChatWindowPriv *priv;
 
1115
        GtkClipboard         *clipboard;
 
1116
        GtkTextBuffer        *buffer;
 
1117
        gboolean              text_available;
 
1118
 
 
1119
        priv = GET_PRIV (window);
 
1120
 
 
1121
        g_return_if_fail (priv->current_chat != NULL);
 
1122
 
 
1123
        if (!gossip_chat_is_connected (priv->current_chat)) {
 
1124
                gtk_widget_set_sensitive (priv->menu_edit_copy, FALSE);
 
1125
                gtk_widget_set_sensitive (priv->menu_edit_cut, FALSE);
 
1126
                gtk_widget_set_sensitive (priv->menu_edit_paste, FALSE);
 
1127
                return;
 
1128
        }
 
1129
 
 
1130
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->current_chat->input_text_view));
 
1131
        if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) {
 
1132
                gtk_widget_set_sensitive (priv->menu_edit_copy, TRUE);
 
1133
                gtk_widget_set_sensitive (priv->menu_edit_cut, TRUE);
 
1134
        } else {
 
1135
                gboolean selection;
 
1136
 
 
1137
                selection = gossip_chat_view_get_selection_bounds (priv->current_chat->view, 
 
1138
                                                                   NULL, NULL);
 
1139
 
 
1140
                gtk_widget_set_sensitive (priv->menu_edit_cut, FALSE);
 
1141
                gtk_widget_set_sensitive (priv->menu_edit_copy, selection);
 
1142
        }
 
1143
 
 
1144
        clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
 
1145
        text_available = gtk_clipboard_wait_is_text_available (clipboard);
 
1146
        gtk_widget_set_sensitive (priv->menu_edit_paste, text_available);
 
1147
}
 
1148
 
 
1149
static void
 
1150
chat_window_cut_activate_cb (GtkWidget        *menuitem,
 
1151
                             GossipChatWindow *window)
 
1152
{
 
1153
        GossipChatWindowPriv *priv;
 
1154
 
 
1155
        g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (window));
 
1156
 
 
1157
        priv = GET_PRIV (window);
 
1158
 
 
1159
        gossip_chat_cut (priv->current_chat);
 
1160
}
 
1161
 
 
1162
static void
 
1163
chat_window_copy_activate_cb (GtkWidget        *menuitem,
 
1164
                              GossipChatWindow *window)
 
1165
{
 
1166
        GossipChatWindowPriv *priv;
 
1167
 
 
1168
        g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (window));
 
1169
 
 
1170
        priv = GET_PRIV (window);
 
1171
 
 
1172
        gossip_chat_copy (priv->current_chat);
 
1173
}
 
1174
 
 
1175
static void
 
1176
chat_window_paste_activate_cb (GtkWidget        *menuitem,
 
1177
                               GossipChatWindow *window)
 
1178
{
 
1179
        GossipChatWindowPriv *priv;
 
1180
 
 
1181
        g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (window));
 
1182
 
 
1183
        priv = GET_PRIV (window);
 
1184
 
 
1185
        gossip_chat_paste (priv->current_chat);
 
1186
}
 
1187
 
 
1188
static void
 
1189
chat_window_tabs_left_activate_cb (GtkWidget        *menuitem,
 
1190
                                   GossipChatWindow *window)
 
1191
{
 
1192
        GossipChatWindowPriv *priv;
 
1193
        GossipChat           *chat;
 
1194
        gint                  index;
 
1195
 
 
1196
        priv = GET_PRIV (window);
 
1197
 
 
1198
        chat = priv->current_chat;
 
1199
        index = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
 
1200
        if (index <= 0) {
 
1201
                return;
 
1202
        }
 
1203
 
 
1204
        gtk_notebook_reorder_child (GTK_NOTEBOOK (priv->notebook),
 
1205
                                    gossip_chat_get_widget (chat),
 
1206
                                    index - 1);
 
1207
 
 
1208
        chat_window_update_menu (window);
 
1209
        chat_window_update_status (window, chat);
 
1210
}
 
1211
 
 
1212
static void
 
1213
chat_window_tabs_right_activate_cb (GtkWidget        *menuitem,
 
1214
                                    GossipChatWindow *window)
 
1215
{
 
1216
        GossipChatWindowPriv *priv;
 
1217
        GossipChat           *chat;
 
1218
        gint                  index;
 
1219
 
 
1220
        priv = GET_PRIV (window);
 
1221
 
 
1222
        chat = priv->current_chat;
 
1223
        index = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
 
1224
 
 
1225
        gtk_notebook_reorder_child (GTK_NOTEBOOK (priv->notebook),
 
1226
                                    gossip_chat_get_widget (chat),
 
1227
                                    index + 1);
 
1228
 
 
1229
        chat_window_update_menu (window);
 
1230
        chat_window_update_status (window, chat);
 
1231
}
 
1232
 
 
1233
static void
 
1234
chat_window_detach_activate_cb (GtkWidget        *menuitem,
 
1235
                                GossipChatWindow *window)
 
1236
{
 
1237
        GossipChatWindowPriv *priv;
 
1238
        GossipChatWindow     *new_window;
 
1239
        GossipChat           *chat;
 
1240
 
 
1241
        priv = GET_PRIV (window);
 
1242
 
 
1243
        chat = priv->current_chat;
 
1244
        new_window = gossip_chat_window_new ();
 
1245
 
 
1246
        gossip_chat_window_move_chat (window, new_window, chat);
 
1247
 
 
1248
        priv = GET_PRIV (new_window);
 
1249
        gtk_widget_show (priv->dialog);
 
1250
}
 
1251
 
 
1252
static gboolean
 
1253
chat_window_delete_event_cb (GtkWidget        *dialog,
 
1254
                             GdkEvent         *event,
 
1255
                             GossipChatWindow *window)
 
1256
{
 
1257
        GossipChatWindowPriv *priv;
 
1258
        GList                *list;
 
1259
        GList                *l;
 
1260
 
 
1261
        priv = GET_PRIV (window);
 
1262
 
 
1263
        gossip_debug (DEBUG_DOMAIN, "Delete event received");
 
1264
 
 
1265
        list = g_list_copy (priv->chats);
 
1266
 
 
1267
        for (l = list; l; l = l->next) {
 
1268
                gossip_chat_window_remove_chat (window, l->data);
 
1269
        }
 
1270
 
 
1271
        g_list_free (list);
 
1272
 
 
1273
        return TRUE;
 
1274
}
 
1275
 
 
1276
static void
 
1277
chat_window_status_changed_cb (GossipChat       *chat,
 
1278
                               GossipChatWindow *window)
 
1279
{
 
1280
        chat_window_update_menu (window);
 
1281
        chat_window_update_status (window, chat);
 
1282
}
 
1283
 
 
1284
static void
 
1285
chat_window_update_tooltip (GossipChatWindow *window,
 
1286
                            GossipChat       *chat)
 
1287
{
 
1288
        GossipChatWindowPriv *priv;
 
1289
        GtkWidget            *widget;
 
1290
        gchar                *current_tooltip;
 
1291
        gchar                *str;
 
1292
 
 
1293
        priv = GET_PRIV (window);
 
1294
 
 
1295
        current_tooltip = gossip_chat_get_tooltip (chat);
 
1296
 
 
1297
        if (g_list_find (priv->chats_composing, chat)) {
 
1298
                str = g_strconcat (current_tooltip, "\n", _("Typing a message."), NULL);
 
1299
                g_free (current_tooltip);
 
1300
        } else {
 
1301
                str = current_tooltip;
 
1302
        }
 
1303
 
 
1304
        widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget");
 
1305
        gtk_tooltips_set_tip (priv->tooltips,
 
1306
                              widget,
 
1307
                              str,
 
1308
                              NULL);
 
1309
 
 
1310
        g_free (str);
 
1311
}
 
1312
 
 
1313
static void
 
1314
chat_window_name_changed_cb (GossipChat       *chat,
 
1315
                             const gchar      *name,
 
1316
                             GossipChatWindow *window)
 
1317
{
 
1318
        GtkLabel *label;
 
1319
 
 
1320
        label = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label");
 
1321
 
 
1322
        gtk_label_set_text (label, name);
 
1323
}
 
1324
 
 
1325
static void
 
1326
chat_window_composing_cb (GossipChat       *chat,
 
1327
                          gboolean          is_composing,
 
1328
                          GossipChatWindow *window)
 
1329
{
 
1330
        GossipChatWindowPriv *priv;
 
1331
 
 
1332
        priv = GET_PRIV (window);
 
1333
 
 
1334
        if (is_composing && !g_list_find (priv->chats_composing, chat)) {
 
1335
                priv->chats_composing = g_list_prepend (priv->chats_composing, chat);
 
1336
        } else {
 
1337
                priv->chats_composing = g_list_remove (priv->chats_composing, chat);
 
1338
        }
 
1339
 
 
1340
        chat_window_update_status (window, chat);
 
1341
}
 
1342
 
 
1343
static void
 
1344
chat_window_new_message_cb (GossipChat       *chat,
 
1345
                            GossipMessage    *message,
 
1346
                            gboolean          is_backlog,
 
1347
                            GossipChatWindow *window)
 
1348
{
 
1349
        GossipChatWindowPriv *priv;
 
1350
        gboolean              has_focus;
 
1351
        gboolean              needs_urgency;
 
1352
 
 
1353
        priv = GET_PRIV (window);
 
1354
 
 
1355
        has_focus = gossip_chat_window_has_focus (window);
 
1356
        
 
1357
        if (has_focus && priv->current_chat == chat) {
 
1358
                gossip_debug (DEBUG_DOMAIN, "New message, we have focus");
 
1359
                return;
 
1360
        }
 
1361
        
 
1362
        gossip_debug (DEBUG_DOMAIN, "New message, no focus");
 
1363
 
 
1364
        needs_urgency = FALSE;
 
1365
        if (gossip_chat_is_group_chat (chat)) {         
 
1366
                if (!is_backlog && 
 
1367
                    gossip_chat_should_highlight_nick (message)) {
 
1368
                        gossip_debug (DEBUG_DOMAIN, "Highlight this nick");
 
1369
                        needs_urgency = TRUE;
 
1370
                }
 
1371
        } else {
 
1372
                needs_urgency = TRUE;
 
1373
        }
 
1374
 
 
1375
        if (needs_urgency && !has_focus) {
 
1376
                chat_window_set_urgency_hint (window, TRUE);
 
1377
        }
 
1378
 
 
1379
        if (!is_backlog && 
 
1380
            !g_list_find (priv->chats_new_msg, chat)) {
 
1381
                priv->chats_new_msg = g_list_prepend (priv->chats_new_msg, chat);
 
1382
                chat_window_update_status (window, chat);
 
1383
        }
 
1384
}
 
1385
 
 
1386
static GtkNotebook *
 
1387
chat_window_detach_hook (GtkNotebook *source,
 
1388
                         GtkWidget   *page,
 
1389
                         gint         x,
 
1390
                         gint         y,
 
1391
                         gpointer     user_data)
 
1392
{
 
1393
        GossipChatWindowPriv *priv;
 
1394
        GossipChatWindow     *window, *new_window;
 
1395
        GossipChat           *chat;
 
1396
 
 
1397
        chat = g_object_get_data (G_OBJECT (page), "chat");
 
1398
        window = gossip_chat_get_window (chat);
 
1399
 
 
1400
        new_window = gossip_chat_window_new ();
 
1401
        priv = GET_PRIV (new_window);
 
1402
 
 
1403
        gossip_debug (DEBUG_DOMAIN, "Detach hook called");
 
1404
 
 
1405
        gossip_chat_window_move_chat (window, new_window, chat);
 
1406
 
 
1407
        gtk_window_move (GTK_WINDOW (priv->dialog), x, y);
 
1408
        gtk_widget_show (priv->dialog);
 
1409
 
 
1410
        return NULL;
 
1411
}
 
1412
 
 
1413
static void
 
1414
chat_window_page_switched_cb (GtkNotebook      *notebook,
 
1415
                              GtkNotebookPage  *page,
 
1416
                              gint              page_num,
 
1417
                              GossipChatWindow *window)
 
1418
{
 
1419
        GossipChatWindowPriv *priv;
 
1420
        GossipChat           *chat;
 
1421
        GtkWidget            *child;
 
1422
 
 
1423
        gossip_debug (DEBUG_DOMAIN, "Page switched");
 
1424
 
 
1425
        priv = GET_PRIV (window);
 
1426
 
 
1427
        child = gtk_notebook_get_nth_page (notebook, page_num);
 
1428
        chat = g_object_get_data (G_OBJECT (child), "chat");
 
1429
 
 
1430
        if (priv->page_added) {
 
1431
                priv->page_added = FALSE;
 
1432
                gossip_chat_scroll_down (chat);
 
1433
        }
 
1434
        else if (priv->current_chat == chat) {
 
1435
                return;
 
1436
        }
 
1437
 
 
1438
        priv->current_chat = chat;
 
1439
        priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat);
 
1440
 
 
1441
        chat_window_update_menu (window);
 
1442
        chat_window_update_status (window, chat);
 
1443
}
 
1444
 
 
1445
static void
 
1446
chat_window_page_reordered_cb (GtkNotebook      *notebook,
 
1447
                               GtkWidget        *widget,
 
1448
                               guint             page_num,
 
1449
                               GossipChatWindow *window)
 
1450
{
 
1451
        gossip_debug (DEBUG_DOMAIN, "Page reordered");
 
1452
        
 
1453
        chat_window_update_menu (window);
 
1454
}
 
1455
 
 
1456
static void
 
1457
chat_window_page_added_cb (GtkNotebook      *notebook,
 
1458
                           GtkWidget        *child,
 
1459
                           guint             page_num,
 
1460
                           GossipChatWindow *window)
 
1461
{
 
1462
        GossipChatWindowPriv *priv;
 
1463
        GossipChat           *chat;
 
1464
 
 
1465
        priv = GET_PRIV (window);
 
1466
 
 
1467
        /* If we just received DND to the same window, we don't want
 
1468
         * to do anything here like removing the tab and then readding
 
1469
         * it, so we return here and in "page-added".
 
1470
         */
 
1471
        if (priv->dnd_same_window) {
 
1472
                gossip_debug (DEBUG_DOMAIN, "Page added (back to the same window)");
 
1473
                priv->dnd_same_window = FALSE;
 
1474
                return;
 
1475
        }
 
1476
 
 
1477
        gossip_debug (DEBUG_DOMAIN, "Page added");
 
1478
 
 
1479
        /* Get chat object */
 
1480
        chat = g_object_get_data (G_OBJECT (child), "chat");
 
1481
 
 
1482
        /* Set the chat window */
 
1483
        gossip_chat_set_window (chat, window);
 
1484
 
 
1485
        /* Connect chat signals for this window */
 
1486
        g_signal_connect (chat, "status-changed",
 
1487
                          G_CALLBACK (chat_window_status_changed_cb),
 
1488
                          window);
 
1489
        g_signal_connect (chat, "name-changed",
 
1490
                          G_CALLBACK (chat_window_name_changed_cb),
 
1491
                          window);
 
1492
        g_signal_connect (chat, "composing",
 
1493
                          G_CALLBACK (chat_window_composing_cb),
 
1494
                          window);
 
1495
        g_signal_connect (chat, "new-message",
 
1496
                          G_CALLBACK (chat_window_new_message_cb),
 
1497
                          window);
 
1498
 
 
1499
        /* Set flag so we know to perform some special operations on
 
1500
         * switch page due to the new page being added.
 
1501
         */
 
1502
        priv->page_added = TRUE;
 
1503
 
 
1504
        /* Get list of chats up to date */
 
1505
        priv->chats = g_list_append (priv->chats, chat);
 
1506
}
 
1507
 
 
1508
static void
 
1509
chat_window_page_removed_cb (GtkNotebook      *notebook,
 
1510
                             GtkWidget        *child,
 
1511
                             guint             page_num,
 
1512
                             GossipChatWindow *window)
 
1513
{
 
1514
        GossipChatWindowPriv *priv;
 
1515
        GossipChat           *chat;
 
1516
 
 
1517
        priv = GET_PRIV (window);
 
1518
 
 
1519
        /* If we just received DND to the same window, we don't want
 
1520
         * to do anything here like removing the tab and then readding
 
1521
         * it, so we return here and in "page-added".
 
1522
         */
 
1523
        if (priv->dnd_same_window) {
 
1524
                gossip_debug (DEBUG_DOMAIN, "Page removed (and will be readded to same window)");
 
1525
                return;
 
1526
        }
 
1527
 
 
1528
        gossip_debug (DEBUG_DOMAIN, "Page removed");
 
1529
 
 
1530
        /* Get chat object */
 
1531
        chat = g_object_get_data (G_OBJECT (child), "chat");
 
1532
 
 
1533
        /* Unset the window associated with a chat */
 
1534
        gossip_chat_set_window (chat, NULL);
 
1535
 
 
1536
        /* Disconnect all signal handlers for this chat and this window */
 
1537
        g_signal_handlers_disconnect_by_func (chat,
 
1538
                                              G_CALLBACK (chat_window_status_changed_cb),
 
1539
                                              window);
 
1540
        g_signal_handlers_disconnect_by_func (chat,
 
1541
                                              G_CALLBACK (chat_window_name_changed_cb),
 
1542
                                              window);
 
1543
        g_signal_handlers_disconnect_by_func (chat,
 
1544
                                              G_CALLBACK (chat_window_composing_cb),
 
1545
                                              window);
 
1546
        g_signal_handlers_disconnect_by_func (chat,
 
1547
                                              G_CALLBACK (chat_window_new_message_cb),
 
1548
                                              window);
 
1549
 
 
1550
        /* Keep list of chats up to date */
 
1551
        priv->chats = g_list_remove (priv->chats, chat);
 
1552
        priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat);
 
1553
        priv->chats_composing = g_list_remove (priv->chats_composing, chat);
 
1554
 
 
1555
        if (priv->chats == NULL) {
 
1556
                g_object_unref (window);
 
1557
        } else {
 
1558
                chat_window_update_menu (window);
 
1559
                chat_window_update_title (window, NULL);
 
1560
        }
 
1561
}
 
1562
 
 
1563
static gboolean
 
1564
chat_window_focus_in_event_cb (GtkWidget        *widget,
 
1565
                               GdkEvent         *event,
 
1566
                               GossipChatWindow *window)
 
1567
{
 
1568
        GossipChatWindowPriv *priv;
 
1569
 
 
1570
        gossip_debug (DEBUG_DOMAIN, "Focus in event, updating title");
 
1571
 
 
1572
        priv = GET_PRIV (window);
 
1573
 
 
1574
        priv->chats_new_msg = g_list_remove (priv->chats_new_msg, priv->current_chat);
 
1575
 
 
1576
        chat_window_set_urgency_hint (window, FALSE);
 
1577
        
 
1578
        /* Update the title, since we now mark all unread messages as read. */
 
1579
        chat_window_update_status (window, priv->current_chat);
 
1580
 
 
1581
        return FALSE;
 
1582
}
 
1583
 
 
1584
static void
 
1585
chat_window_drag_data_received (GtkWidget        *widget,
 
1586
                                GdkDragContext   *context,
 
1587
                                int               x,
 
1588
                                int               y,
 
1589
                                GtkSelectionData *selection,
 
1590
                                guint             info,
 
1591
                                guint             time,
 
1592
                                GossipChatWindow *window)
 
1593
{
 
1594
        if (info == DND_DRAG_TYPE_CONTACT_ID) {
 
1595
#if 0
 
1596
FIXME:
 
1597
                GossipChatManager *manager;
 
1598
                GossipContact     *contact;
 
1599
                GossipChat        *chat;
 
1600
                GossipChatWindow  *old_window;
 
1601
                const gchar       *id = NULL;
 
1602
 
 
1603
                if (selection) {
 
1604
                        id = (const gchar*) selection->data;
 
1605
                }
 
1606
 
 
1607
                gossip_debug (DEBUG_DOMAIN, "DND contact from roster with id:'%s'", id);
 
1608
                
 
1609
                contact = gossip_session_find_contact (gossip_app_get_session (), id);
 
1610
                if (!contact) {
 
1611
                        gossip_debug (DEBUG_DOMAIN, "DND contact from roster not found");
 
1612
                        return;
 
1613
                }
 
1614
                
 
1615
                manager = gossip_app_get_chat_manager ();
 
1616
                chat = GOSSIP_CHAT (gossip_chat_manager_get_chat (manager, contact));
 
1617
                old_window = gossip_chat_get_window (chat);
 
1618
                
 
1619
                if (old_window) {
 
1620
                        if (old_window == window) {
 
1621
                                gtk_drag_finish (context, TRUE, FALSE, time);
 
1622
                                return;
 
1623
                        }
 
1624
                        
 
1625
                        gossip_chat_window_move_chat (old_window, window, chat);
 
1626
                } else {
 
1627
                        gossip_chat_window_add_chat (window, chat);
 
1628
                }
 
1629
                
 
1630
                /* Added to take care of any outstanding chat events */
 
1631
                gossip_chat_manager_show_chat (manager, contact);
 
1632
 
 
1633
                /* We should return TRUE to remove the data when doing
 
1634
                 * GDK_ACTION_MOVE, but we don't here otherwise it has
 
1635
                 * weird consequences, and we handle that internally
 
1636
                 * anyway with add_chat() and remove_chat().
 
1637
                 */
 
1638
                gtk_drag_finish (context, TRUE, FALSE, time);
 
1639
#endif
 
1640
        }
 
1641
        else if (info == DND_DRAG_TYPE_TAB) {
 
1642
                GossipChat        *chat = NULL;
 
1643
                GossipChatWindow  *old_window;
 
1644
                GtkWidget        **child = NULL;
 
1645
 
 
1646
                gossip_debug (DEBUG_DOMAIN, "DND tab");
 
1647
 
 
1648
                if (selection) {
 
1649
                        child = (void*) selection->data;
 
1650
                }
 
1651
 
 
1652
                if (child) {
 
1653
                        chat = g_object_get_data (G_OBJECT (*child), "chat");
 
1654
                }
 
1655
 
 
1656
                old_window = gossip_chat_get_window (chat);
 
1657
                if (old_window) {
 
1658
                        GossipChatWindowPriv *priv;
 
1659
 
 
1660
                        priv = GET_PRIV (window);
 
1661
 
 
1662
                        if (old_window == window) {
 
1663
                                gossip_debug (DEBUG_DOMAIN, "DND tab (within same window)");
 
1664
                                priv->dnd_same_window = TRUE;
 
1665
                                gtk_drag_finish (context, TRUE, FALSE, time);
 
1666
                                return;
 
1667
                        }
 
1668
                        
 
1669
                        priv->dnd_same_window = FALSE;
 
1670
                }
 
1671
 
 
1672
                /* We should return TRUE to remove the data when doing
 
1673
                 * GDK_ACTION_MOVE, but we don't here otherwise it has
 
1674
                 * weird consequences, and we handle that internally
 
1675
                 * anyway with add_chat() and remove_chat().
 
1676
                 */
 
1677
                gtk_drag_finish (context, TRUE, FALSE, time);
 
1678
        } else {
 
1679
                gossip_debug (DEBUG_DOMAIN, "DND from unknown source");
 
1680
                gtk_drag_finish (context, FALSE, FALSE, time);
 
1681
        }
 
1682
}
 
1683
 
 
1684
static gboolean
 
1685
chat_window_urgency_timeout_func (GossipChatWindow *window)
 
1686
{
 
1687
        GossipChatWindowPriv *priv;
 
1688
 
 
1689
        priv = GET_PRIV (window);
 
1690
 
 
1691
        gossip_debug (DEBUG_DOMAIN, "Turning off urgency hint");
 
1692
        gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), FALSE);
 
1693
 
 
1694
        priv->urgency_timeout_id = 0;
 
1695
 
 
1696
        return FALSE;
 
1697
}
 
1698
 
 
1699
static void
 
1700
chat_window_set_urgency_hint (GossipChatWindow *window,
 
1701
                              gboolean          urgent)
 
1702
{
 
1703
        GossipChatWindowPriv *priv;
 
1704
 
 
1705
        priv = GET_PRIV (window);
 
1706
 
 
1707
        if (!urgent) {
 
1708
                /* Remove any existing hint and timeout. */
 
1709
                if (priv->urgency_timeout_id) {
 
1710
                        gossip_debug (DEBUG_DOMAIN, "Turning off urgency hint");
 
1711
                        gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), FALSE);
 
1712
                        g_source_remove (priv->urgency_timeout_id);
 
1713
                        priv->urgency_timeout_id = 0;
 
1714
                }
 
1715
                return;
 
1716
        }
 
1717
 
 
1718
        /* Add a new hint and renew any exising timeout or add a new one. */
 
1719
        if (priv->urgency_timeout_id) {
 
1720
                g_source_remove (priv->urgency_timeout_id);
 
1721
        } else {
 
1722
                gossip_debug (DEBUG_DOMAIN, "Turning on urgency hint");
 
1723
                gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), TRUE);
 
1724
        }
 
1725
 
 
1726
        priv->urgency_timeout_id = g_timeout_add (
 
1727
                URGENCY_TIMEOUT,
 
1728
                (GSourceFunc) chat_window_urgency_timeout_func,
 
1729
                window);
 
1730
}
 
1731
 
 
1732
GossipChatWindow *
 
1733
gossip_chat_window_new (void)
 
1734
{
 
1735
        return GOSSIP_CHAT_WINDOW (g_object_new (GOSSIP_TYPE_CHAT_WINDOW, NULL));
 
1736
}
 
1737
 
 
1738
GtkWidget *
 
1739
gossip_chat_window_get_dialog (GossipChatWindow *window)
 
1740
{
 
1741
        GossipChatWindowPriv *priv;
 
1742
 
 
1743
        g_return_val_if_fail (window != NULL, NULL);
 
1744
 
 
1745
        priv = GET_PRIV (window);
 
1746
 
 
1747
        return priv->dialog;
 
1748
}
 
1749
 
 
1750
void
 
1751
gossip_chat_window_add_chat (GossipChatWindow *window,
 
1752
                             GossipChat       *chat)
 
1753
{
 
1754
        GossipChatWindowPriv *priv;
 
1755
        GtkWidget            *label;
 
1756
        GtkWidget            *child;
 
1757
 
 
1758
        priv = GET_PRIV (window);
 
1759
 
 
1760
        /* Reference the chat object */
 
1761
        g_object_ref (chat);
 
1762
 
 
1763
        /* Set the chat window */
 
1764
        gossip_chat_set_window (chat, window);
 
1765
 
 
1766
        if (g_list_length (priv->chats) == 0) {
 
1767
                gint x, y, w, h;
 
1768
 
 
1769
                gossip_chat_load_geometry (chat, &x, &y, &w, &h);
 
1770
 
 
1771
                if (x >= 0 && y >= 0) {
 
1772
                        /* Let the window manager position it if we don't have
 
1773
                         * good x, y coordinates.
 
1774
                         */
 
1775
                        gtk_window_move (GTK_WINDOW (priv->dialog), x, y);
 
1776
                }
 
1777
 
 
1778
                if (w > 0 && h > 0) {
 
1779
                        /* Use the defaults from the glade file if we don't have
 
1780
                         * good w, h geometry.
 
1781
                         */
 
1782
                        gtk_window_resize (GTK_WINDOW (priv->dialog), w, h);
 
1783
                }
 
1784
        }
 
1785
 
 
1786
        child = gossip_chat_get_widget (chat);
 
1787
        label = chat_window_create_label (window, chat); 
 
1788
 
 
1789
        gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), child, label);
 
1790
        gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook), child, TRUE);
 
1791
        gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook), child, TRUE);
 
1792
        gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (priv->notebook), child,
 
1793
                                            TRUE, TRUE, GTK_PACK_START); 
 
1794
 
 
1795
        gossip_debug (DEBUG_DOMAIN, 
 
1796
                      "Chat added (%d references)",
 
1797
                      G_OBJECT (chat)->ref_count);
 
1798
}
 
1799
 
 
1800
void
 
1801
gossip_chat_window_remove_chat (GossipChatWindow *window,
 
1802
                                GossipChat       *chat)
 
1803
{
 
1804
        GossipChatWindowPriv *priv;
 
1805
        gint                  position;
 
1806
 
 
1807
        priv = GET_PRIV (window);
 
1808
 
 
1809
        position = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook),
 
1810
                                          gossip_chat_get_widget (chat));
 
1811
        gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), position);
 
1812
 
 
1813
        gossip_debug (DEBUG_DOMAIN, 
 
1814
                      "Chat removed (%d references)", 
 
1815
                      G_OBJECT (chat)->ref_count - 1);
 
1816
 
 
1817
        g_object_unref (chat);
 
1818
}
 
1819
 
 
1820
void
 
1821
gossip_chat_window_move_chat (GossipChatWindow *old_window,
 
1822
                              GossipChatWindow *new_window,
 
1823
                              GossipChat       *chat)
 
1824
{
 
1825
        GtkWidget *widget;
 
1826
 
 
1827
        g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (old_window));
 
1828
        g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (new_window));
 
1829
        g_return_if_fail (GOSSIP_IS_CHAT (chat));
 
1830
 
 
1831
        widget = gossip_chat_get_widget (chat);
 
1832
 
 
1833
        gossip_debug (DEBUG_DOMAIN,
 
1834
                      "Chat moving with widget:%p (%d references)", 
 
1835
                      widget,
 
1836
                      G_OBJECT (widget)->ref_count);
 
1837
 
 
1838
        /* We reference here to make sure we don't loose the widget
 
1839
         * and the GossipChat object during the move.
 
1840
         */
 
1841
        g_object_ref (chat);
 
1842
        g_object_ref (widget);
 
1843
 
 
1844
        gossip_chat_window_remove_chat (old_window, chat);
 
1845
        gossip_chat_window_add_chat (new_window, chat);
 
1846
 
 
1847
        g_object_unref (widget);
 
1848
        g_object_unref (chat);
 
1849
}
 
1850
 
 
1851
void
 
1852
gossip_chat_window_switch_to_chat (GossipChatWindow *window,
 
1853
                                   GossipChat       *chat)
 
1854
{
 
1855
        GossipChatWindowPriv *priv;
 
1856
        gint                  page_num;
 
1857
 
 
1858
        priv = GET_PRIV (window);
 
1859
 
 
1860
        page_num = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook),
 
1861
                                          gossip_chat_get_widget (chat));
 
1862
        gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook),
 
1863
                                       page_num);
 
1864
}
 
1865
 
 
1866
gboolean
 
1867
gossip_chat_window_has_focus (GossipChatWindow *window)
 
1868
{
 
1869
        GossipChatWindowPriv *priv;
 
1870
        gboolean              has_focus;
 
1871
 
 
1872
        g_return_val_if_fail (GOSSIP_IS_CHAT_WINDOW (window), FALSE);
 
1873
 
 
1874
        priv = GET_PRIV (window);
 
1875
 
 
1876
        g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL);
 
1877
 
 
1878
        return has_focus;
 
1879
}
 
1880
 
 
1881
GossipChat *
 
1882
gossip_chat_window_find_chat_by_id (const gchar *id)
 
1883
{
 
1884
        GList *l;
 
1885
 
 
1886
        for (l = chat_windows; l; l = l->next) {
 
1887
                GossipChatWindowPriv *priv;
 
1888
                GossipChatWindow     *window;
 
1889
                GList                *ll;
 
1890
 
 
1891
                window = l->data;
 
1892
                priv = GET_PRIV (window);
 
1893
 
 
1894
                for (ll = priv->chats; ll; ll = ll->next) {
 
1895
                        GossipChat *chat;
 
1896
 
 
1897
                        chat = ll->data;
 
1898
 
 
1899
                        if (strcmp (id, gossip_chat_get_id (chat)) == 0) {
 
1900
                                return chat;
 
1901
                        }
 
1902
                }
 
1903
        }
 
1904
 
 
1905
        return NULL;
 
1906
}
 
1907