48
48
#include <libempathy/empathy-utils.h>
49
49
#include <libempathy/empathy-tp-contact-factory.h>
50
50
#include <libempathy/empathy-contact-list.h>
51
#include <libempathy/empathy-request-util.h>
52
53
#include <libempathy-gtk/empathy-images.h>
53
54
#include <libempathy-gtk/empathy-contact-dialogs.h>
54
55
#include <libempathy-gtk/empathy-log-window.h>
55
56
#include <libempathy-gtk/empathy-geometry.h>
56
57
#include <libempathy-gtk/empathy-smiley-manager.h>
57
#include <libempathy-gtk/empathy-sound.h>
58
#include <libempathy-gtk/empathy-sound-manager.h>
58
59
#include <libempathy-gtk/empathy-ui-utils.h>
59
60
#include <libempathy-gtk/empathy-notify-manager.h>
62
63
#include "empathy-chat-window.h"
63
64
#include "empathy-about-dialog.h"
64
65
#include "empathy-invite-participant-dialog.h"
66
#ifdef HAVE_LIBINDICATE
67
#include "empathy-indicator.h"
68
#include "empathy-indicator-manager.h"
66
#include "gedit-close-button.h"
71
68
#define DEBUG_FLAG EMPATHY_DEBUG_CHAT
72
69
#include <libempathy/empathy-debug.h>
78
71
/* Macro to compare guint32 X timestamps, while accounting for wrapping around
80
73
#define X_EARLIER_OR_EQL(t1, t2) \
131
115
/* Last user action time we acted upon to show a tab */
132
116
guint32 x_user_action_time;
118
GSettings *gsettings_chat;
119
GSettings *gsettings_notif;
120
GSettings *gsettings_ui;
122
EmpathySoundManager *sound_mgr;
133
123
} EmpathyChatWindowPriv;
135
125
static GList *chat_windows = NULL;
137
127
static const guint tab_accel_keys[] = {
138
GDK_1, GDK_2, GDK_3, GDK_4, GDK_5,
139
GDK_6, GDK_7, GDK_8, GDK_9, GDK_0
128
GDK_KEY_1, GDK_KEY_2, GDK_KEY_3, GDK_KEY_4, GDK_KEY_5,
129
GDK_KEY_6, GDK_KEY_7, GDK_KEY_8, GDK_KEY_9, GDK_KEY_0
166
156
static void chat_window_update (EmpathyChatWindow *window,
167
157
gboolean update_contact_menu);
159
static void empathy_chat_window_add_chat (EmpathyChatWindow *window,
162
static void empathy_chat_window_remove_chat (EmpathyChatWindow *window,
165
static void empathy_chat_window_move_chat (EmpathyChatWindow *old_window,
166
EmpathyChatWindow *new_window,
169
static void empathy_chat_window_get_nb_chats (EmpathyChatWindow *self,
169
173
G_DEFINE_TYPE (EmpathyChatWindow, empathy_chat_window, G_TYPE_OBJECT);
224
chat_tab_style_set_cb (GtkWidget *hbox,
225
GtkStyle *previous_style,
228
chat_tab_style_updated_cb (GtkWidget *hbox,
228
231
GtkWidget *button;
229
232
int char_width, h, w;
230
233
PangoContext *context;
234
const PangoFontDescription *font_desc;
231
235
PangoFontMetrics *metrics;
233
237
button = g_object_get_data (G_OBJECT (user_data),
234
238
"chat-window-tab-close-button");
235
239
context = gtk_widget_get_pango_context (hbox);
237
metrics = pango_context_get_metrics (context, gtk_widget_get_style (hbox)->font_desc,
241
font_desc = gtk_style_context_get_font (gtk_widget_get_style_context (hbox),
242
GTK_STATE_FLAG_NORMAL);
244
metrics = pango_context_get_metrics (context, font_desc,
238
245
pango_context_get_language (context));
239
246
char_width = pango_font_metrics_get_approximate_char_width (metrics);
240
247
pango_font_metrics_unref (metrics);
311
313
gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0);
313
315
if (is_tab_label) {
314
close_button = gtk_button_new ();
315
gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
316
GtkWidget *close_button;
317
GtkWidget *sending_spinner;
319
sending_spinner = gtk_spinner_new ();
321
gtk_box_pack_start (GTK_BOX (hbox), sending_spinner,
323
g_object_set_data (G_OBJECT (chat),
324
"chat-window-tab-sending-spinner",
327
close_button = gedit_close_button_new ();
316
328
g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button);
318
330
/* We don't want focus/keynav for the button to avoid clutter, and
321
333
gtk_widget_set_can_focus (close_button, FALSE);
322
334
gtk_widget_set_can_default (close_button, FALSE);
324
/* Set the name to make the special rc style match. */
325
gtk_widget_set_name (close_button, "empathy-close-button");
327
close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
329
gtk_container_add (GTK_CONTAINER (close_button), close_image);
331
336
gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
333
338
g_signal_connect (close_button,
462
463
get_window_title_name (EmpathyChatWindowPriv *priv)
464
const gchar *active_name;
465
gchar *active_name, *ret;
466
467
guint current_unread_msgs;
468
469
nb_chats = g_list_length (priv->chats);
469
470
g_assert (nb_chats > 0);
471
active_name = empathy_chat_get_name (priv->current_chat);
472
active_name = empathy_chat_dup_name (priv->current_chat);
473
474
current_unread_msgs = empathy_chat_get_nb_unread_messages (
474
475
priv->current_chat);
545
550
n_chats = g_list_length (priv->chats);
547
552
/* Update window icon */
548
if (priv->chats_new_msg) {
549
554
gtk_window_set_icon_name (GTK_WINDOW (priv->dialog),
550
555
EMPATHY_IMAGE_MESSAGE);
552
GSettings *gsettings = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
554
avatar_in_icon = g_settings_get_boolean (gsettings,
557
avatar_in_icon = g_settings_get_boolean (priv->gsettings_chat,
555
558
EMPATHY_PREFS_CHAT_AVATAR_IN_ICON);
557
560
if (n_chats == 1 && avatar_in_icon) {
681
684
/* No TpChat, we are disconnected */
682
685
icon_name = NULL;
684
else if (g_list_find (priv->chats_new_msg, chat)) {
687
else if (empathy_chat_get_nb_unread_messages (chat) > 0) {
685
688
icon_name = EMPATHY_IMAGE_MESSAGE;
687
else if (g_list_find (priv->chats_composing, chat)) {
690
else if (remote_contact && empathy_chat_is_composing (chat)) {
688
691
icon_name = EMPATHY_IMAGE_TYPING;
693
else if (empathy_chat_is_sms_channel (chat)) {
694
icon_name = EMPATHY_IMAGE_SMS;
690
696
else if (remote_contact) {
691
697
icon_name = empathy_icon_name_for_contact (remote_contact);
705
711
gtk_widget_hide (menu_image);
714
/* Update the sending spinner */
715
nb_sending = empathy_chat_get_n_messages_sending (chat);
716
sending_spinner = g_object_get_data (G_OBJECT (chat),
717
"chat-window-tab-sending-spinner");
719
g_object_set (sending_spinner,
720
"active", nb_sending > 0,
721
"visible", nb_sending > 0,
708
724
/* Update tab tooltip */
709
725
tooltip = g_string_new (NULL);
734
if (empathy_chat_is_sms_channel (chat)) {
735
append_markup_printf (tooltip, "%s ", _("SMS:"));
718
738
append_markup_printf (tooltip,
719
739
"<b>%s</b><small> (%s)</small>",
721
741
tp_account_get_display_name (account));
743
if (nb_sending > 0) {
744
char *tmp = g_strdup_printf (
745
ngettext ("Sending %d message",
746
"Sending %d messages",
750
g_string_append (tooltip, "\n");
751
g_string_append (tooltip, tmp);
753
gtk_widget_set_tooltip_text (sending_spinner, tmp);
723
757
if (!EMP_STR_EMPTY (status)) {
724
758
append_markup_printf (tooltip, "\n<i>%s</i>", status);
877
913
EmpathyChatWindowPriv *priv = GET_PRIV (window);
879
915
TpAccount *account;
880
917
const gchar *room;
881
918
EmpathyChatroom *chatroom;
883
920
active = gtk_toggle_action_get_active (toggle_action);
884
921
account = empathy_chat_get_account (priv->current_chat);
885
922
room = empathy_chat_get_id (priv->current_chat);
923
name = empathy_chat_dup_name (priv->current_chat);
887
925
chatroom = empathy_chatroom_manager_ensure_chatroom (
888
926
priv->chatroom_manager,
891
empathy_chat_get_name (priv->current_chat));
893
931
empathy_chatroom_set_favorite (chatroom, active);
894
932
g_object_unref (chatroom);
901
940
EmpathyChatWindowPriv *priv = GET_PRIV (window);
903
942
TpAccount *account;
904
944
const gchar *room;
905
945
EmpathyChatroom *chatroom;
907
947
active = gtk_toggle_action_get_active (toggle_action);
908
948
account = empathy_chat_get_account (priv->current_chat);
909
949
room = empathy_chat_get_id (priv->current_chat);
950
name = empathy_chat_dup_name (priv->current_chat);
911
952
chatroom = empathy_chatroom_manager_ensure_chatroom (
912
953
priv->chatroom_manager,
915
empathy_chat_get_name (priv->current_chat));
917
958
empathy_chatroom_set_always_urgent (chatroom, active);
918
959
g_object_unref (chatroom);
1297
#ifdef HAVE_LIBINDICATE
1299
chat_window_indicator_activate_cb (EmpathyIndicator *indicator, guint timestamp,
1302
empathy_chat_window_present_chat (chat, timestamp);
1303
empathy_indicator_hide (indicator);
1307
chat_window_add_indicator (EmpathyChatWindow *window,
1308
EmpathyMessage *message,
1311
EmpathyChatWindowPriv *priv = GET_PRIV (window);
1312
EmpathyContact *sender;
1314
gboolean use_libindicate;
1315
EmpathyIndicator *indicator = NULL;
1316
GSettings *gsettings;
1318
gsettings = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
1319
use_libindicate = g_settings_get_boolean (gsettings, EMPATHY_PREFS_UI_USE_LIBINDICATE);
1320
g_object_unref (gsettings);
1322
if (!use_libindicate) {
1326
sender = empathy_message_get_sender (message);
1327
body = empathy_message_get_body (message);
1329
indicator = g_hash_table_lookup (priv->indicators, chat);
1330
if (indicator != NULL) {
1331
DEBUG ("indicator exists");
1332
empathy_indicator_update (indicator, body);
1334
DEBUG ("indicator doesn't exist yet, creating a new indicator");
1335
indicator = empathy_indicator_manager_create_indicator (priv->indicator_manager,
1337
g_signal_connect (indicator, "activate",
1338
G_CALLBACK (chat_window_indicator_activate_cb), chat);
1339
g_hash_table_insert (priv->indicators, chat, indicator);
1341
if (priv->launcher != NULL)
1343
gint count = g_hash_table_size (priv->indicators);
1344
DEBUG ("unity launcher: count is now %d", count);
1347
unity_launcher_entry_set_count (priv->launcher, count);
1348
unity_launcher_entry_set_count_visible (priv->launcher, TRUE);
1353
empathy_indicator_show (indicator);
1357
chat_window_remove_indicator (EmpathyChatWindow *window, EmpathyChat *chat)
1359
EmpathyIndicator *indicator = NULL;
1360
EmpathyChatWindowPriv *priv = GET_PRIV (window);
1362
indicator = g_hash_table_lookup (priv->indicators, chat);
1364
if ((indicator) && (indicator != NULL)) {
1365
DEBUG ("indicator is %p", indicator);
1366
empathy_indicator_hide (indicator);
1367
g_hash_table_remove (priv->indicators, chat);
1369
if (priv->launcher != NULL)
1371
gint count = g_hash_table_size (priv->indicators);
1372
DEBUG ("unity launcher: count is %d", count);
1375
DEBUG ("unity launcher: setting count to %d", count);
1376
unity_launcher_entry_set_count (priv->launcher, count);
1377
unity_launcher_entry_set_count_visible (priv->launcher, TRUE);
1379
unity_launcher_entry_set_count (priv->launcher, count);
1380
DEBUG ("unity launcher: hiding count");
1381
unity_launcher_entry_set_count_visible (priv->launcher, FALSE);
1388
DEBUG ("indicator is NULL, nothing to remove");
1394
1332
chat_window_show_or_update_notification (EmpathyChatWindow *window,
1395
1333
EmpathyMessage *message,
1475
chat_window_set_highlight_room_tab_label (EmpathyChat *chat)
1408
chat_window_set_highlight_room_labels (EmpathyChat *chat)
1410
gchar *markup, *name;
1478
1411
GtkWidget *widget;
1480
1413
if (!empathy_chat_is_room (chat))
1416
name = empathy_chat_dup_name (chat);
1483
1417
markup = g_markup_printf_escaped (
1484
1418
"<span color=\"red\" weight=\"bold\">%s</span>",
1485
empathy_chat_get_name (chat));
1487
1421
widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label");
1488
1422
gtk_label_set_markup (GTK_LABEL (widget), markup);
1424
widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-label");
1425
gtk_label_set_markup (GTK_LABEL (widget), markup);
1489
1428
g_free (markup);
1432
empathy_chat_window_has_focus (EmpathyChatWindow *window)
1434
EmpathyChatWindowPriv *priv;
1437
g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (window), FALSE);
1439
priv = GET_PRIV (window);
1441
g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL);
1493
1447
chat_window_new_message_cb (EmpathyChat *chat,
1494
1448
EmpathyMessage *message,
1562
1516
if (needs_urgency) {
1517
chat_window_set_highlight_room_labels (chat);
1563
1519
if (!has_focus) {
1564
1520
chat_window_set_urgency_hint (window, TRUE);
1565
chat_window_set_highlight_room_tab_label (chat);
1568
empathy_sound_play (GTK_WIDGET (priv->dialog),
1569
EMPATHY_SOUND_MESSAGE_INCOMING);
1570
#ifdef HAVE_LIBINDICATE
1571
chat_window_add_indicator (window, message, chat);
1523
/* Pending messages have already been displayed and notified in the
1524
* approver, so we don't display a notification and play a sound for those */
1526
empathy_sound_manager_play (priv->sound_mgr, GTK_WIDGET (priv->dialog),
1527
EMPATHY_SOUND_MESSAGE_INCOMING);
1574
/* Pending messages have already been displayed in the approver, so we don't
1575
* display a notification for those. */
1577
1529
chat_window_show_or_update_notification (window, message, chat);
1580
1533
/* update the number of unread messages and the window icon */
1581
1534
chat_window_title_update (priv);
1582
chat_window_icon_update (priv);
1535
chat_window_icon_update (priv, TRUE);
1585
1538
static GtkNotebook *
1586
chat_window_detach_hook (GtkNotebook *source,
1539
notebook_create_window_cb (GtkNotebook *source,
1587
1540
GtkWidget *page,
1613
1566
chat_window_page_switched_cb (GtkNotebook *notebook,
1614
gpointer ignore, /* see note below */
1616
1569
EmpathyChatWindow *window)
1618
EmpathyChatWindowPriv *priv;
1571
EmpathyChatWindowPriv *priv = GET_PRIV (window);
1572
EmpathyChat *chat = EMPATHY_CHAT (child);
1622
1574
DEBUG ("Page switched");
1624
priv = GET_PRIV (window);
1626
/* N.B. in GTK+ 3 child is passed as the first argument to the signal,
1627
* but we can't use that while trying to retain GTK+ 2.x compatibility.
1629
child = gtk_notebook_get_nth_page (notebook, page_num);
1630
chat = EMPATHY_CHAT (child);
1632
1576
if (priv->page_added) {
1633
1577
priv->page_added = FALSE;
1634
1578
empathy_chat_scroll_down (chat);
1998
1929
g_object_unref (priv->ui_manager);
1999
1930
g_object_unref (priv->chatroom_manager);
2000
1931
g_object_unref (priv->notify_mgr);
1932
g_object_unref (priv->gsettings_chat);
1933
g_object_unref (priv->gsettings_notif);
1934
g_object_unref (priv->gsettings_ui);
1935
g_object_unref (priv->sound_mgr);
2002
1937
if (priv->notification != NULL) {
2003
1938
notify_notification_close (priv->notification, NULL);
2037
1967
object_class->finalize = chat_window_finalize;
2039
1969
g_type_class_add_private (object_class, sizeof (EmpathyChatWindowPriv));
2041
/* Set up a style for the close button with no focus padding. */
2042
gtk_rc_parse_string (
2043
"style \"empathy-close-button-style\"\n"
2045
" GtkWidget::focus-padding = 0\n"
2049
"widget \"*.empathy-close-button\" style \"empathy-close-button-style\"");
2051
gtk_notebook_set_window_creation_hook (chat_window_detach_hook, NULL, NULL);
2115
2033
g_object_ref (priv->ui_manager);
2116
2034
g_object_unref (gui);
2036
priv->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
2037
priv->gsettings_notif = g_settings_new (EMPATHY_PREFS_NOTIFICATIONS_SCHEMA);
2038
priv->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
2118
2039
priv->chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL);
2119
#ifdef HAVE_LIBINDICATE
2120
priv->indicator_manager = empathy_indicator_manager_dup_singleton ();
2121
priv->indicators = g_hash_table_new_full (g_direct_hash, g_direct_equal,
2122
NULL, g_object_unref);
2125
priv->launcher = unity_launcher_entry_get_for_desktop_id ("empathy.desktop");
2041
priv->sound_mgr = empathy_sound_manager_dup_singleton ();
2128
2043
priv->notebook = gtk_notebook_new ();
2129
gtk_notebook_set_group (GTK_NOTEBOOK (priv->notebook), "EmpathyChatWindow");
2045
g_signal_connect (priv->notebook, "create-window",
2046
G_CALLBACK (notebook_create_window_cb), window);
2048
gtk_notebook_set_group_name (GTK_NOTEBOOK (priv->notebook),
2049
"EmpathyChatWindow");
2130
2050
gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE);
2131
2051
gtk_notebook_popup_enable (GTK_NOTEBOOK (priv->notebook));
2132
2052
gtk_box_pack_start (GTK_BOX (chat_vbox), priv->notebook, TRUE, TRUE, 0);
2225
2143
priv->chat_manager = empathy_chat_manager_dup_singleton ();
2226
2144
priv->chat_manager_chats_changed_id =
2227
g_signal_connect (priv->chat_manager, "chats-changed",
2145
g_signal_connect (priv->chat_manager, "closed-chats-changed",
2228
2146
G_CALLBACK (chat_window_chat_manager_chats_changed_cb),
2231
2149
chat_window_chat_manager_chats_changed_cb (priv->chat_manager,
2232
empathy_chat_manager_get_num_chats (priv->chat_manager),
2150
empathy_chat_manager_get_num_closed_chats (priv->chat_manager),
2235
2153
/* Add launchpad hooks */
2236
2154
launchpad_integration_add_ui (priv->ui_manager, "/chats_menubar/menu_help/LaunchpadItems");
2240
empathy_chat_window_new (void)
2158
empathy_chat_window_get_dialog (EmpathyChatWindow *window)
2242
return EMPATHY_CHAT_WINDOW (g_object_new (EMPATHY_TYPE_CHAT_WINDOW, NULL));
2160
EmpathyChatWindowPriv *priv;
2162
g_return_val_if_fail (window != NULL, NULL);
2164
priv = GET_PRIV (window);
2166
return priv->dialog;
2245
/* Returns the window to open a new tab in if there is only one window
2246
* visble, otherwise, returns NULL indicating that a new window should
2169
/* Returns the window to open a new tab in if there is a suitable window,
2170
* otherwise, returns NULL indicating that a new window should be added.
2172
static EmpathyChatWindow *
2250
2173
empathy_chat_window_get_default (gboolean room)
2252
2175
GSettings *gsettings = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
2266
2189
for (l = chat_windows; l; l = l->next) {
2267
EmpathyChatWindowPriv *priv;
2268
2190
EmpathyChatWindow *chat_window;
2269
2191
GtkWidget *dialog;
2192
guint nb_rooms, nb_private;
2271
2194
chat_window = l->data;
2272
priv = GET_PRIV (chat_window);
2274
2196
dialog = empathy_chat_window_get_dialog (chat_window);
2275
if (empathy_window_get_is_visible (GTK_WINDOW (dialog))) {
2276
guint nb_rooms, nb_private;
2277
empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private);
2279
/* Skip the window if there aren't any rooms in it */
2280
if (room && nb_rooms == 0)
2283
/* Skip the window if there aren't any 1-1 chats in it */
2284
if (!room && nb_private == 0)
2287
/* Found a visible window on this desktop */
2198
empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private);
2200
/* Skip the window if there aren't any rooms in it */
2201
if (room && nb_rooms == 0)
2204
/* Skip the window if there aren't any 1-1 chats in it */
2205
if (!room && nb_private == 0)
2208
/* Found a window on this desktop, make it visible if necessary */
2209
if (!empathy_window_get_is_visible (GTK_WINDOW (dialog)))
2210
empathy_window_present (GTK_WINDOW (dialog));
2296
empathy_chat_window_get_dialog (EmpathyChatWindow *window)
2298
EmpathyChatWindowPriv *priv;
2300
g_return_val_if_fail (window != NULL, NULL);
2302
priv = GET_PRIV (window);
2304
return priv->dialog;
2308
2218
empathy_chat_window_add_chat (EmpathyChatWindow *window,
2309
2219
EmpathyChat *chat)
2325
2235
/* If this window has just been created, position it */
2326
2236
if (priv->chats == NULL) {
2327
GSettings *gsettings = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
2328
2237
const gchar *name = "chat-window";
2329
2238
gboolean separate_windows;
2331
separate_windows = g_settings_get_boolean (gsettings,
2240
separate_windows = g_settings_get_boolean (priv->gsettings_ui,
2332
2241
EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS);
2334
g_object_unref (gsettings);
2243
if (empathy_chat_is_room (chat))
2244
name = "room-window";
2336
2246
if (separate_windows) {
2249
/* Save current position of the window */
2250
gtk_window_get_position (GTK_WINDOW (priv->dialog), &x, &y);
2252
/* First bind to the 'generic' name. So new window for which we didn't
2253
* save a geometry yet will have the geometry of the last saved
2254
* window (bgo #601191). */
2255
empathy_geometry_bind (GTK_WINDOW (priv->dialog), name);
2257
/* Restore previous position of the window so the newly created window
2258
* won't be in the same position as the latest saved window and so
2259
* completely hide it. */
2260
gtk_window_move (GTK_WINDOW (priv->dialog), x, y);
2262
/* Then bind it to the name of the contact/room so we'll save the
2263
* geometry specific to this window */
2337
2264
name = empathy_chat_get_id (chat);
2339
else if (empathy_chat_is_room (chat)) {
2340
name = "room-window";
2343
2267
empathy_geometry_bind (GTK_WINDOW (priv->dialog), name);
2357
2281
g_signal_connect (chat, "notify::remote-contact",
2358
2282
G_CALLBACK (chat_window_chat_notify_cb),
2284
g_signal_connect (chat, "notify::sms-channel",
2285
G_CALLBACK (chat_window_chat_notify_cb),
2287
g_signal_connect (chat, "notify::n-messages-sending",
2288
G_CALLBACK (chat_window_chat_notify_cb),
2360
2290
chat_window_chat_notify_cb (chat);
2362
2292
gtk_notebook_append_page_menu (GTK_NOTEBOOK (priv->notebook), child, label, popup_label);