X-Git-Url: https://git.0d.be/?p=empathy.git;a=blobdiff_plain;f=src%2Fempathy-chat-window.c;h=8dcb68d2f62ea70799eb03ac9ae142b8515271ae;hp=98a266141b50c117dc3ed6a4aa535f81419c9d0b;hb=2a6048e015b83b22eb2c771412b2e4770c4ada01;hpb=d3bb39fc883b0c4d53fe54469f2128456a820371 diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index 98a26614..8dcb68d2 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -15,9 +15,9 @@ * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Mikael Hallendal * Richard Hult * Martyn Russell @@ -31,17 +31,17 @@ #include #include -#include #include +#include #include #include -#include #include #include #include #include +#include #include #include @@ -49,10 +49,13 @@ #include #include #include +#include +#include #include #include "empathy-chat-window.h" #include "empathy-about-dialog.h" +#include "empathy-misc.h" #define DEBUG_FLAG EMPATHY_DEBUG_CHAT #include @@ -69,26 +72,23 @@ typedef struct { EmpathyChatroomManager *chatroom_manager; GtkWidget *dialog; GtkWidget *notebook; + NotifyNotification *notification; /* Menu items. */ - GtkWidget *menu_conv_clear; - GtkWidget *menu_conv_insert_smiley; - GtkWidget *menu_conv_contact; - GtkWidget *menu_conv_favorite; - GtkWidget *menu_conv_close; - - GtkWidget *menu_edit_cut; - GtkWidget *menu_edit_copy; - GtkWidget *menu_edit_paste; - - GtkWidget *menu_tabs_next; - GtkWidget *menu_tabs_prev; - GtkWidget *menu_tabs_left; - GtkWidget *menu_tabs_right; - GtkWidget *menu_tabs_detach; - - GtkWidget *menu_help_contents; - GtkWidget *menu_help_about; + GtkUIManager *ui_manager; + GtkAction *menu_conv_insert_smiley; + GtkAction *menu_conv_favorite; + GtkAction *menu_conv_toggle_contacts; + + GtkAction *menu_edit_cut; + GtkAction *menu_edit_copy; + GtkAction *menu_edit_paste; + + GtkAction *menu_tabs_next; + GtkAction *menu_tabs_prev; + GtkAction *menu_tabs_left; + GtkAction *menu_tabs_right; + GtkAction *menu_tabs_detach; } EmpathyChatWindowPriv; static GList *chat_windows = NULL; @@ -153,7 +153,7 @@ chat_window_find_chat (EmpathyChat *chat) } static void -chat_window_close_clicked_cb (GtkWidget *button, +chat_window_close_clicked_cb (GtkAction *action, EmpathyChat *chat) { EmpathyChatWindow *window; @@ -163,21 +163,39 @@ chat_window_close_clicked_cb (GtkWidget *button, } static void -chat_window_close_button_style_set_cb (GtkWidget *button, +chat_tab_style_set_cb (GtkWidget *hbox, GtkStyle *previous_style, gpointer user_data) { - gint h, w; + GtkWidget *button; + int char_width, h, w; + PangoContext *context; + PangoFontMetrics *metrics; + + button = g_object_get_data (G_OBJECT (user_data), + "chat-window-tab-close-button"); + context = gtk_widget_get_pango_context (hbox); + + metrics = pango_context_get_metrics (context, gtk_widget_get_style (hbox)->font_desc, + pango_context_get_language (context)); + char_width = pango_font_metrics_get_approximate_char_width (metrics); + pango_font_metrics_unref (metrics); gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button), GTK_ICON_SIZE_MENU, &w, &h); + /* Request at least about 12 chars width plus at least space for the status + * image and the close button */ + gtk_widget_set_size_request (hbox, + 12 * PANGO_PIXELS (char_width) + 2 * w, -1); + gtk_widget_set_size_request (button, w, h); } static GtkWidget * chat_window_create_label (EmpathyChatWindow *window, - EmpathyChat *chat) + EmpathyChat *chat, + gboolean is_tab_label) { EmpathyChatWindowPriv *priv; GtkWidget *hbox; @@ -199,7 +217,8 @@ chat_window_create_label (EmpathyChatWindow *window, gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); name_label = gtk_label_new (NULL); - gtk_label_set_ellipsize (GTK_LABEL (name_label), PANGO_ELLIPSIZE_END); + if (is_tab_label) + gtk_label_set_ellipsize (GTK_LABEL (name_label), PANGO_ELLIPSIZE_END); attr_list = pango_attr_list_new (); attr = pango_attr_scale_new (1/1.2); @@ -211,7 +230,9 @@ chat_window_create_label (EmpathyChatWindow *window, gtk_misc_set_padding (GTK_MISC (name_label), 2, 0); gtk_misc_set_alignment (GTK_MISC (name_label), 0.0, 0.5); - g_object_set_data (G_OBJECT (chat), "chat-window-tab-label", name_label); + g_object_set_data (G_OBJECT (chat), + is_tab_label ? "chat-window-tab-label" : "chat-window-menu-label", + name_label); status_image = gtk_image_new (); @@ -221,42 +242,47 @@ chat_window_create_label (EmpathyChatWindow *window, gtk_box_pack_start (GTK_BOX (event_box_hbox), status_image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (event_box_hbox), name_label, TRUE, TRUE, 0); - g_object_set_data (G_OBJECT (chat), "chat-window-tab-image", status_image); - g_object_set_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget", event_box); + g_object_set_data (G_OBJECT (chat), + is_tab_label ? "chat-window-tab-image" : "chat-window-menu-image", + status_image); + g_object_set_data (G_OBJECT (chat), + is_tab_label ? "chat-window-tab-tooltip-widget" : "chat-window-menu-tooltip-widget", + event_box); - close_button = gtk_button_new (); - gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE); - g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button); + gtk_container_add (GTK_CONTAINER (event_box), event_box_hbox); + gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0); - /* We don't want focus/keynav for the button to avoid clutter, and - * Ctrl-W works anyway. - */ - GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_FOCUS); - GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_DEFAULT); + if (is_tab_label) { + close_button = gtk_button_new (); + gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE); + g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button); - /* Set the name to make the special rc style match. */ - gtk_widget_set_name (close_button, "empathy-close-button"); + /* We don't want focus/keynav for the button to avoid clutter, and + * Ctrl-W works anyway. + */ + GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_FOCUS); + GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_DEFAULT); - close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); + /* Set the name to make the special rc style match. */ + gtk_widget_set_name (close_button, "empathy-close-button"); - gtk_container_add (GTK_CONTAINER (close_button), close_image); + close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); - gtk_container_add (GTK_CONTAINER (event_box), event_box_hbox); - gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0); - gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (close_button), close_image); - /* React to theme changes and also used to setup the initial size - * correctly. - */ - g_signal_connect (close_button, - "style-set", - G_CALLBACK (chat_window_close_button_style_set_cb), - chat); + gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); + + g_signal_connect (close_button, + "clicked", + G_CALLBACK (chat_window_close_clicked_cb), + chat); - g_signal_connect (close_button, - "clicked", - G_CALLBACK (chat_window_close_clicked_cb), - chat); + /* React to theme changes and also setup the size correctly. */ + g_signal_connect (hbox, + "style-set", + G_CALLBACK (chat_tab_style_set_cb), + chat); + } gtk_widget_show_all (hbox); @@ -280,6 +306,8 @@ chat_window_update (EmpathyChatWindow *window) gboolean avatar_in_icon; GtkWidget *chat; GtkWidget *chat_close_button; + GtkWidget *submenu; + GtkWidget *menu; /* Get information */ page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); @@ -293,12 +321,19 @@ chat_window_update (EmpathyChatWindow *window) DEBUG ("Update window"); /* Update menu */ - gtk_widget_set_sensitive (priv->menu_tabs_next, !last_page); - gtk_widget_set_sensitive (priv->menu_tabs_prev, !first_page); - gtk_widget_set_sensitive (priv->menu_tabs_detach, num_pages > 1); - gtk_widget_set_sensitive (priv->menu_tabs_left, !first_page); - gtk_widget_set_sensitive (priv->menu_tabs_right, !last_page); - gtk_widget_set_sensitive (priv->menu_conv_insert_smiley, is_connected); + gtk_action_set_sensitive (priv->menu_tabs_next, !last_page); + gtk_action_set_sensitive (priv->menu_tabs_prev, !first_page); + gtk_action_set_sensitive (priv->menu_tabs_detach, num_pages > 1); + gtk_action_set_sensitive (priv->menu_tabs_left, !first_page); + gtk_action_set_sensitive (priv->menu_tabs_right, !last_page); + gtk_action_set_sensitive (priv->menu_conv_insert_smiley, is_connected); + + /* Update Contact menu */ + menu = gtk_ui_manager_get_widget (priv->ui_manager, + "/chats_menubar/menu_contact"); + submenu = empathy_chat_get_contact_menu (priv->current_chat); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu); + gtk_widget_show (menu); /* Update window title */ if (n_chats == 1) { @@ -324,7 +359,10 @@ chat_window_update (EmpathyChatWindow *window) remote_contact = empathy_chat_get_remote_contact (priv->current_chat); icon = empathy_pixbuf_avatar_from_contact_scaled (remote_contact, 0, 0); gtk_window_set_icon (GTK_WINDOW (priv->dialog), icon); - g_object_unref (icon); + + if (icon != NULL) { + g_object_unref (icon); + } } else { gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), NULL); } @@ -345,6 +383,23 @@ chat_window_update (EmpathyChatWindow *window) } } +static void +append_markup_printf (GString *string, + const char *format, + ...) +{ + gchar *tmp; + va_list args; + + va_start (args, format); + + tmp = g_markup_vprintf_escaped (format, args); + g_string_append (string, tmp); + g_free (tmp); + + va_end (args); +} + static void chat_window_update_chat_tab (EmpathyChat *chat) { @@ -352,7 +407,10 @@ chat_window_update_chat_tab (EmpathyChat *chat) EmpathyChatWindowPriv *priv; EmpathyContact *remote_contact; const gchar *name; + const gchar *id; + EmpathyAccount *account; const gchar *subject; + const gchar *status = NULL; GtkWidget *widget; GString *tooltip; gchar *markup; @@ -366,11 +424,12 @@ chat_window_update_chat_tab (EmpathyChat *chat) /* Get information */ name = empathy_chat_get_name (chat); + account = empathy_chat_get_account (chat); subject = empathy_chat_get_subject (chat); remote_contact = empathy_chat_get_remote_contact (chat); - DEBUG ("Updating chat tab, name=%s, subject=%s, remote_contact=%p", - name, subject, remote_contact); + DEBUG ("Updating chat tab, name=%s, account=%s, subject=%s, remote_contact=%p", + name, empathy_account_get_unique_name (account), subject, remote_contact); /* Update tab image */ if (g_list_find (priv->chats_new_msg, chat)) { @@ -386,42 +445,49 @@ chat_window_update_chat_tab (EmpathyChat *chat) } widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-image"); gtk_image_set_from_icon_name (GTK_IMAGE (widget), icon_name, GTK_ICON_SIZE_MENU); + widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-image"); + gtk_image_set_from_icon_name (GTK_IMAGE (widget), icon_name, GTK_ICON_SIZE_MENU); /* Update tab tooltip */ tooltip = g_string_new (NULL); if (remote_contact) { - markup = g_markup_printf_escaped ("%s\n%s", - empathy_contact_get_id (remote_contact), - empathy_contact_get_status (remote_contact)); - g_string_append (tooltip, markup); - g_free (markup); + id = empathy_contact_get_id (remote_contact); + status = empathy_contact_get_presence_message (remote_contact); + } else { + id = name; } - else { - markup = g_markup_printf_escaped ("%s", name); - g_string_append (tooltip, markup); - g_free (markup); + + append_markup_printf (tooltip, + "%s (%s)", + id, + empathy_account_get_display_name (account)); + + if (!EMP_STR_EMPTY (status)) { + append_markup_printf (tooltip, "\n%s", status); } if (subject) { - markup = g_markup_printf_escaped ("\n%s %s", _("Topic:"), subject); - g_string_append (tooltip, markup); - g_free (markup); + append_markup_printf (tooltip, "\n%s %s", + _("Topic:"), subject); } + if (g_list_find (priv->chats_composing, chat)) { - markup = g_markup_printf_escaped ("\n%s", _("Typing a message.")); - g_string_append (tooltip, markup); - g_free (markup); + append_markup_printf (tooltip, "\n%s", _("Typing a message.")); } markup = g_string_free (tooltip, FALSE); widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget"); gtk_widget_set_tooltip_markup (widget, markup); + widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-tooltip-widget"); + gtk_widget_set_tooltip_markup (widget, markup); g_free (markup); - /* Update tab label */ + /* Update tab and menu label */ widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label"); gtk_label_set_text (GTK_LABEL (widget), name); + widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-label"); + gtk_label_set_text (GTK_LABEL (widget), name); /* Update the window if it's the current chat */ if (priv->current_chat == chat) { @@ -461,67 +527,71 @@ chat_window_chat_notify_cb (EmpathyChat *chat) } static void -chat_window_insert_smiley_activate_cb (GtkWidget *menuitem, - EmpathyChatWindow *window) +chat_window_insert_smiley_activate_cb (EmpathySmileyManager *manager, + EmpathySmiley *smiley, + gpointer window) { - EmpathyChatWindowPriv *priv; + EmpathyChatWindowPriv *priv = GET_PRIV (window); EmpathyChat *chat; - GtkTextBuffer *buffer; - GtkTextIter iter; - const gchar *smiley; - - priv = GET_PRIV (window); + GtkTextBuffer *buffer; + GtkTextIter iter; chat = priv->current_chat; - smiley = g_object_get_data (G_OBJECT (menuitem), "smiley_text"); - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); gtk_text_buffer_get_end_iter (buffer, &iter); - gtk_text_buffer_insert (buffer, &iter, - smiley, -1); + gtk_text_buffer_insert (buffer, &iter, smiley->str, -1); } static void -chat_window_conv_activate_cb (GtkWidget *menuitem, +chat_window_conv_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv = GET_PRIV (window); - GtkWidget *submenu = NULL; - - /* Contact submenu */ - submenu = empathy_chat_get_contact_menu (priv->current_chat); - if (submenu) { - gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->menu_conv_contact), - submenu); - gtk_widget_show (priv->menu_conv_contact); - gtk_widget_show (submenu); - } else { - gtk_widget_hide (priv->menu_conv_contact); - } + gboolean is_room; + gboolean active; + EmpathyContact *remote_contact = NULL; /* Favorite room menu */ - if (empathy_chat_is_room (priv->current_chat)) { + is_room = empathy_chat_is_room (priv->current_chat); + if (is_room) { const gchar *room; - McAccount *account; - gboolean found; + EmpathyAccount *account; + gboolean found = FALSE; + EmpathyChatroom *chatroom; room = empathy_chat_get_id (priv->current_chat); account = empathy_chat_get_account (priv->current_chat); - found = empathy_chatroom_manager_find (priv->chatroom_manager, - account, room) != NULL; + chatroom = empathy_chatroom_manager_find (priv->chatroom_manager, + account, room); + if (chatroom != NULL) + found = empathy_chatroom_is_favorite (chatroom); DEBUG ("This room %s favorite", found ? "is" : "is not"); - gtk_check_menu_item_set_active ( - GTK_CHECK_MENU_ITEM (priv->menu_conv_favorite), found); - gtk_widget_show (priv->menu_conv_favorite); - } else { - gtk_widget_hide (priv->menu_conv_favorite); + gtk_toggle_action_set_active ( + GTK_TOGGLE_ACTION (priv->menu_conv_favorite), found); + } + gtk_action_set_visible (priv->menu_conv_favorite, is_room); + + /* Show contacts menu */ + g_object_get (priv->current_chat, + "remote-contact", &remote_contact, + "show-contacts", &active, + NULL); + if (remote_contact == NULL) { + gtk_toggle_action_set_active ( + GTK_TOGGLE_ACTION (priv->menu_conv_toggle_contacts), + active); + } + gtk_action_set_visible (priv->menu_conv_toggle_contacts, + (remote_contact == NULL)); + if (remote_contact != NULL) { + g_object_unref (remote_contact); } } static void -chat_window_clear_activate_cb (GtkWidget *menuitem, +chat_window_clear_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv = GET_PRIV (window); @@ -530,35 +600,44 @@ chat_window_clear_activate_cb (GtkWidget *menuitem, } static void -chat_window_favorite_toggled_cb (GtkCheckMenuItem *menuitem, +chat_window_favorite_toggled_cb (GtkToggleAction *toggle_action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv = GET_PRIV (window); gboolean active; - McAccount *account; + EmpathyAccount *account; const gchar *room; EmpathyChatroom *chatroom; - active = gtk_check_menu_item_get_active (menuitem); + active = gtk_toggle_action_get_active (toggle_action); account = empathy_chat_get_account (priv->current_chat); room = empathy_chat_get_id (priv->current_chat); chatroom = empathy_chatroom_manager_find (priv->chatroom_manager, account, room); - if (active && !chatroom) { + if (chatroom == NULL) { const gchar *name; name = empathy_chat_get_name (priv->current_chat); chatroom = empathy_chatroom_new_full (account, room, name, FALSE); empathy_chatroom_manager_add (priv->chatroom_manager, chatroom); g_object_unref (chatroom); - return; - } - - if (!active && chatroom) { - empathy_chatroom_manager_remove (priv->chatroom_manager, chatroom); - } + } + + empathy_chatroom_set_favorite (chatroom, active); +} + +static void +chat_window_contacts_toggled_cb (GtkToggleAction *toggle_action, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv = GET_PRIV (window); + gboolean active; + + active = gtk_toggle_action_get_active (toggle_action); + + empathy_chat_set_show_contacts (priv->current_chat, active); } static const gchar * @@ -619,7 +698,7 @@ chat_window_configure_event_cb (GtkWidget *widget, } static void -chat_window_close_activate_cb (GtkWidget *menuitem, +chat_window_close_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv; @@ -632,7 +711,7 @@ chat_window_close_activate_cb (GtkWidget *menuitem, } static void -chat_window_edit_activate_cb (GtkWidget *menuitem, +chat_window_edit_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv; @@ -645,33 +724,32 @@ chat_window_edit_activate_cb (GtkWidget *menuitem, g_return_if_fail (priv->current_chat != NULL); if (!empathy_chat_get_tp_chat (priv->current_chat)) { - gtk_widget_set_sensitive (priv->menu_edit_copy, FALSE); - gtk_widget_set_sensitive (priv->menu_edit_cut, FALSE); - gtk_widget_set_sensitive (priv->menu_edit_paste, FALSE); + gtk_action_set_sensitive (priv->menu_edit_copy, FALSE); + gtk_action_set_sensitive (priv->menu_edit_cut, FALSE); + gtk_action_set_sensitive (priv->menu_edit_paste, FALSE); return; } buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->current_chat->input_text_view)); - if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) { - gtk_widget_set_sensitive (priv->menu_edit_copy, TRUE); - gtk_widget_set_sensitive (priv->menu_edit_cut, TRUE); + if (gtk_text_buffer_get_has_selection (buffer)) { + gtk_action_set_sensitive (priv->menu_edit_copy, TRUE); + gtk_action_set_sensitive (priv->menu_edit_cut, TRUE); } else { gboolean selection; - selection = empathy_chat_view_get_selection_bounds (priv->current_chat->view, - NULL, NULL); + selection = empathy_chat_view_get_has_selection (priv->current_chat->view); - gtk_widget_set_sensitive (priv->menu_edit_cut, FALSE); - gtk_widget_set_sensitive (priv->menu_edit_copy, selection); + gtk_action_set_sensitive (priv->menu_edit_cut, FALSE); + gtk_action_set_sensitive (priv->menu_edit_copy, selection); } clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); text_available = gtk_clipboard_wait_is_text_available (clipboard); - gtk_widget_set_sensitive (priv->menu_edit_paste, text_available); + gtk_action_set_sensitive (priv->menu_edit_paste, text_available); } static void -chat_window_cut_activate_cb (GtkWidget *menuitem, +chat_window_cut_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv; @@ -684,7 +762,7 @@ chat_window_cut_activate_cb (GtkWidget *menuitem, } static void -chat_window_copy_activate_cb (GtkWidget *menuitem, +chat_window_copy_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv; @@ -697,7 +775,7 @@ chat_window_copy_activate_cb (GtkWidget *menuitem, } static void -chat_window_paste_activate_cb (GtkWidget *menuitem, +chat_window_paste_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv; @@ -710,7 +788,7 @@ chat_window_paste_activate_cb (GtkWidget *menuitem, } static void -chat_window_tabs_left_activate_cb (GtkWidget *menuitem, +chat_window_tabs_left_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv; @@ -731,7 +809,7 @@ chat_window_tabs_left_activate_cb (GtkWidget *menuitem, } static void -chat_window_tabs_right_activate_cb (GtkWidget *menuitem, +chat_window_tabs_right_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv; @@ -749,7 +827,7 @@ chat_window_tabs_right_activate_cb (GtkWidget *menuitem, } static void -chat_window_detach_activate_cb (GtkWidget *menuitem, +chat_window_detach_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv; @@ -768,15 +846,17 @@ chat_window_detach_activate_cb (GtkWidget *menuitem, } static void -chat_window_help_contents_cb (GtkWidget *menuitem, - EmpathyChatWindow *window) +chat_window_help_contents_activate_cb (GtkAction *action, + EmpathyChatWindow *window) { - empathy_url_show ("ghelp:empathy?chat"); + EmpathyChatWindowPriv *priv = GET_PRIV (window); + + empathy_url_show (priv->dialog, "ghelp:empathy?chat"); } static void -chat_window_help_about_cb (GtkWidget *menuitem, - EmpathyChatWindow *window) +chat_window_help_about_activate_cb (GtkAction *action, + EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv = GET_PRIV (window); @@ -831,6 +911,107 @@ chat_window_set_urgency_hint (EmpathyChatWindow *window, gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), urgent); } +typedef struct { + EmpathyChatWindow *window; + EmpathyChat *chat; +} NotificationData; + +static void +chat_window_notification_closed_cb (NotifyNotification *notify, + NotificationData *cb_data) +{ + EmpathyNotificationClosedReason reason = 0; + EmpathyChatWindowPriv *priv = GET_PRIV (cb_data->window); + +#ifdef notify_notification_get_closed_reason + reason = notify_notification_get_closed_reason (notify); +#endif + if (reason == EMPATHY_NOTIFICATION_CLOSED_DISMISSED) { + empathy_chat_window_present_chat (cb_data->chat); + } + + g_object_unref (notify); + priv->notification = NULL; + g_object_unref (cb_data->chat); + g_slice_free (NotificationData, cb_data); +} + +static void +chat_window_show_or_update_notification (EmpathyChatWindow *window, + EmpathyMessage *message, + EmpathyChat *chat) +{ + EmpathyContact *sender; + const gchar *header; + char *escaped; + const char *body; + GdkPixbuf *pixbuf; + NotificationData *cb_data; + EmpathyChatWindowPriv *priv = GET_PRIV (window); + gboolean res; + + if (!empathy_notification_is_enabled ()) { + return; + } else { + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_NOTIFICATIONS_FOCUS, &res); + if (!res) { + return; + } + } + + cb_data = g_slice_new0 (NotificationData); + cb_data->chat = g_object_ref (chat); + cb_data->window = window; + + sender = empathy_message_get_sender (message); + header = empathy_contact_get_name (sender); + body = empathy_message_get_body (message); + escaped = g_markup_escape_text (body, -1); + + pixbuf = empathy_misc_get_pixbuf_for_notification (sender, EMPATHY_IMAGE_NEW_MESSAGE); + + if (priv->notification != NULL) { + notify_notification_update (priv->notification, + header, escaped, NULL); + /* if icon doesn't exist libnotify will crash */ + if (pixbuf != NULL) + notify_notification_set_icon_from_pixbuf (priv->notification, pixbuf); + } else { + priv->notification = notify_notification_new (header, escaped, NULL, NULL); + notify_notification_set_timeout (priv->notification, NOTIFY_EXPIRES_DEFAULT); + /* if icon doesn't exist libnotify will crash */ + if (pixbuf != NULL) + notify_notification_set_icon_from_pixbuf (priv->notification, pixbuf); + + g_signal_connect (priv->notification, "closed", + G_CALLBACK (chat_window_notification_closed_cb), cb_data); + } + + notify_notification_show (priv->notification, NULL); + + g_object_unref (pixbuf); + g_free (escaped); +} + +static void +chat_window_set_highlight_room_tab_label (EmpathyChat *chat) +{ + gchar *markup; + GtkWidget *widget; + + if (empathy_chat_is_room (chat) == FALSE) + return; + + markup = g_markup_printf_escaped ("%s", + "red", + empathy_chat_get_name (chat)); + + widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label"); + gtk_label_set_markup (GTK_LABEL (widget), markup); + g_free (markup); +} + static void chat_window_new_message_cb (EmpathyChat *chat, EmpathyMessage *message, @@ -839,28 +1020,56 @@ chat_window_new_message_cb (EmpathyChat *chat, EmpathyChatWindowPriv *priv; gboolean has_focus; gboolean needs_urgency; + EmpathyContact *sender; priv = GET_PRIV (window); has_focus = empathy_chat_window_has_focus (window); + /* - if we're the sender, we play the sound if it's specified in the + * preferences and we're not away. + * - if we receive a message, we play the sound if it's specified in the + * preferences and the window does not have focus on the chat receiving + * the message. + */ + + sender = empathy_message_get_sender (message); + + if (empathy_contact_is_user (sender)) { + empathy_sound_play (GTK_WIDGET (priv->dialog), + EMPATHY_SOUND_MESSAGE_OUTGOING); + } + if (has_focus && priv->current_chat == chat) { return; } - - if (empathy_chat_get_members_count (chat) > 2) { + + if (!g_list_find (priv->chats_new_msg, chat)) { + priv->chats_new_msg = g_list_prepend (priv->chats_new_msg, chat); + chat_window_update_chat_tab (chat); + } + + /* If empathy_chat_is_room () returns TRUE, that means it's a named MUC. + * If empathy_chat_get_remote_contact () returns NULL, that means it's + * an unamed MUC (msn-like). + * In case of a MUC, we set urgency only if the message contains our + * alias. */ + if (empathy_chat_is_room (chat) || + empathy_chat_get_remote_contact (chat) == NULL) { needs_urgency = empathy_message_should_highlight (message); } else { needs_urgency = TRUE; } - if (needs_urgency && !has_focus) { - chat_window_set_urgency_hint (window, TRUE); - } + if (needs_urgency) { + if (!has_focus) { + chat_window_set_urgency_hint (window, TRUE); + chat_window_set_highlight_room_tab_label (chat); + } - if (!g_list_find (priv->chats_new_msg, chat)) { - priv->chats_new_msg = g_list_prepend (priv->chats_new_msg, chat); - chat_window_update_chat_tab (chat); + empathy_sound_play (GTK_WIDGET (priv->dialog), + EMPATHY_SOUND_MESSAGE_INCOMING); + chat_window_show_or_update_notification (window, message, chat); } } @@ -1026,7 +1235,7 @@ chat_window_focus_in_event_cb (GtkWidget *widget, priv->chats_new_msg = g_list_remove (priv->chats_new_msg, priv->current_chat); chat_window_set_urgency_hint (window, FALSE); - + /* Update the title, since we now mark all unread messages as read. */ chat_window_update_chat_tab (priv->current_chat); @@ -1046,46 +1255,61 @@ chat_window_drag_data_received (GtkWidget *widget, if (info == DND_DRAG_TYPE_CONTACT_ID) { EmpathyChat *chat; EmpathyChatWindow *old_window; - McAccount *account; + EmpathyAccount *account; + EmpathyAccountManager *account_manager; const gchar *id; gchar **strv; + const gchar *account_id; + const gchar *contact_id; - id = (const gchar*) selection->data; + id = (const gchar*) gtk_selection_data_get_data (selection); + account_manager = empathy_account_manager_dup_singleton (); DEBUG ("DND contact from roster with id:'%s'", id); - + strv = g_strsplit (id, "/", 2); - account = mc_account_lookup (strv[0]); - chat = empathy_chat_window_find_chat (account, strv[1]); + account_id = strv[0]; + contact_id = strv[1]; + account = empathy_account_manager_lookup (account_manager, account_id); + chat = empathy_chat_window_find_chat (account, contact_id); if (!chat) { - empathy_dispatcher_chat_with_contact_id (account, strv[2]); + TpConnection *connection; + + connection = empathy_account_get_connection (account); + + if (connection) { + empathy_dispatcher_chat_with_contact_id ( + connection, contact_id, NULL, NULL); + } + g_object_unref (account); g_strfreev (strv); return; } g_object_unref (account); + g_object_unref (account_manager); g_strfreev (strv); - old_window = chat_window_find_chat (chat); + old_window = chat_window_find_chat (chat); if (old_window) { if (old_window == window) { gtk_drag_finish (context, TRUE, FALSE, time); return; } - + empathy_chat_window_move_chat (old_window, window, chat); } else { empathy_chat_window_add_chat (window, chat); } - + /* Added to take care of any outstanding chat events */ empathy_chat_window_present_chat (chat); /* We should return TRUE to remove the data when doing * GDK_ACTION_MOVE, but we don't here otherwise it has * weird consequences, and we handle that internally - * anyway with add_chat() and remove_chat(). + * anyway with add_chat () and remove_chat (). */ gtk_drag_finish (context, TRUE, FALSE, time); } @@ -1095,7 +1319,7 @@ chat_window_drag_data_received (GtkWidget *widget, DEBUG ("DND tab"); - chat = (void*) selection->data; + chat = (void *) gtk_selection_data_get_data (selection); old_window = chat_window_find_chat (*chat); if (old_window) { @@ -1109,14 +1333,14 @@ chat_window_drag_data_received (GtkWidget *widget, gtk_drag_finish (context, TRUE, FALSE, time); return; } - + priv->dnd_same_window = FALSE; } /* We should return TRUE to remove the data when doing * GDK_ACTION_MOVE, but we don't here otherwise it has * weird consequences, and we handle that internally - * anyway with add_chat() and remove_chat(). + * anyway with add_chat () and remove_chat (). */ gtk_drag_finish (context, TRUE, FALSE, time); } else { @@ -1136,11 +1360,18 @@ chat_window_finalize (GObject *object) DEBUG ("Finalized: %p", object); + g_object_unref (priv->ui_manager); g_object_unref (priv->chatroom_manager); if (priv->save_geometry_id != 0) { g_source_remove (priv->save_geometry_id); } + if (priv->notification != NULL) { + notify_notification_close (priv->notification, NULL); + g_object_unref (priv->notification); + priv->notification = NULL; + } + chat_windows = g_list_remove (chat_windows, window); gtk_widget_destroy (priv->dialog); @@ -1172,30 +1403,27 @@ empathy_chat_window_class_init (EmpathyChatWindowClass *klass) static void empathy_chat_window_init (EmpathyChatWindow *window) { - GladeXML *glade; + GtkBuilder *gui; GtkAccelGroup *accel_group; GClosure *closure; - GtkWidget *menu_conv; GtkWidget *menu; + GtkWidget *submenu; gint i; GtkWidget *chat_vbox; gchar *filename; + EmpathySmileyManager *smiley_manager; EmpathyChatWindowPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (window, EMPATHY_TYPE_CHAT_WINDOW, EmpathyChatWindowPriv); window->priv = priv; - filename = empathy_file_lookup ("empathy-chat-window.glade", "src"); - glade = empathy_glade_get_file (filename, - "chat_window", - NULL, + filename = empathy_file_lookup ("empathy-chat-window.ui", "src"); + gui = empathy_builder_get_file (filename, "chat_window", &priv->dialog, "chat_vbox", &chat_vbox, - "menu_conv", &menu_conv, - "menu_conv_clear", &priv->menu_conv_clear, + "ui_manager", &priv->ui_manager, "menu_conv_insert_smiley", &priv->menu_conv_insert_smiley, - "menu_conv_contact", &priv->menu_conv_contact, "menu_conv_favorite", &priv->menu_conv_favorite, - "menu_conv_close", &priv->menu_conv_close, + "menu_conv_toggle_contacts", &priv->menu_conv_toggle_contacts, "menu_edit_cut", &priv->menu_edit_cut, "menu_edit_copy", &priv->menu_edit_copy, "menu_edit_paste", &priv->menu_edit_paste, @@ -1204,17 +1432,15 @@ empathy_chat_window_init (EmpathyChatWindow *window) "menu_tabs_left", &priv->menu_tabs_left, "menu_tabs_right", &priv->menu_tabs_right, "menu_tabs_detach", &priv->menu_tabs_detach, - "menu_help_contents", &priv->menu_help_contents, - "menu_help_about", &priv->menu_help_about, NULL); g_free (filename); - empathy_glade_connect (glade, - window, + empathy_builder_connect (gui, window, "chat_window", "configure-event", chat_window_configure_event_cb, "menu_conv", "activate", chat_window_conv_activate_cb, "menu_conv_clear", "activate", chat_window_clear_activate_cb, "menu_conv_favorite", "toggled", chat_window_favorite_toggled_cb, + "menu_conv_toggle_contacts", "toggled", chat_window_contacts_toggled_cb, "menu_conv_close", "activate", chat_window_close_activate_cb, "menu_edit", "activate", chat_window_edit_activate_cb, "menu_edit_cut", "activate", chat_window_cut_activate_cb, @@ -1223,16 +1449,19 @@ empathy_chat_window_init (EmpathyChatWindow *window) "menu_tabs_left", "activate", chat_window_tabs_left_activate_cb, "menu_tabs_right", "activate", chat_window_tabs_right_activate_cb, "menu_tabs_detach", "activate", chat_window_detach_activate_cb, - "menu_help_contents", "activate", chat_window_help_contents_cb, - "menu_help_about", "activate", chat_window_help_about_cb, + "menu_help_contents", "activate", chat_window_help_contents_activate_cb, + "menu_help_about", "activate", chat_window_help_about_activate_cb, NULL); - g_object_unref (glade); + g_object_ref (priv->ui_manager); + g_object_unref (gui); - priv->chatroom_manager = empathy_chatroom_manager_new (NULL); + priv->chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL); priv->notebook = gtk_notebook_new (); - gtk_notebook_set_group (GTK_NOTEBOOK (priv->notebook), "EmpathyChatWindow"); + gtk_notebook_set_group (GTK_NOTEBOOK (priv->notebook), "EmpathyChatWindow"); + gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE); + gtk_notebook_popup_enable (GTK_NOTEBOOK (priv->notebook)); gtk_box_pack_start (GTK_BOX (chat_vbox), priv->notebook, TRUE, TRUE, 0); gtk_widget_show (priv->notebook); @@ -1254,12 +1483,16 @@ empathy_chat_window_init (EmpathyChatWindow *window) g_object_unref (accel_group); /* Set up smiley menu */ - menu = empathy_chat_view_get_smiley_menu ( - G_CALLBACK (chat_window_insert_smiley_activate_cb), - window); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->menu_conv_insert_smiley), menu); - - /* Set up signals we can't do with glade since we may need to + smiley_manager = empathy_smiley_manager_dup_singleton (); + submenu = empathy_smiley_menu_new (smiley_manager, + chat_window_insert_smiley_activate_cb, + window); + menu = gtk_ui_manager_get_widget (priv->ui_manager, + "/chats_menubar/menu_conv/menu_conv_insert_smiley"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu); + g_object_unref (smiley_manager); + + /* Set up signals we can't do with ui file since we may need to * block/unblock them at some later stage. */ @@ -1374,6 +1607,7 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window, { EmpathyChatWindowPriv *priv; GtkWidget *label; + GtkWidget *popup_label; GtkWidget *child; gint x, y, w, h; @@ -1388,16 +1622,16 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window, /* If this window has just been created, position it */ if (priv->chats == NULL) { empathy_geometry_load (chat_get_window_id_for_geometry (chat), &x, &y, &w, &h); - + if (x >= 0 && y >= 0) { /* Let the window manager position it if we don't have * good x, y coordinates. */ gtk_window_move (GTK_WINDOW (priv->dialog), x, y); } - + if (w > 0 && h > 0) { - /* Use the defaults from the glade file if we don't have + /* Use the defaults from the ui file if we don't have * good w, h geometry. */ gtk_window_resize (GTK_WINDOW (priv->dialog), w, h); @@ -1405,7 +1639,8 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window, } child = GTK_WIDGET (chat); - label = chat_window_create_label (window, chat); + label = chat_window_create_label (window, chat, TRUE); + popup_label = chat_window_create_label (window, chat, FALSE); gtk_widget_show (child); g_signal_connect (chat, "notify::name", @@ -1419,11 +1654,11 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window, NULL); chat_window_chat_notify_cb (chat); - gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), child, label); + gtk_notebook_append_page_menu (GTK_NOTEBOOK (priv->notebook), child, label, popup_label); gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook), child, TRUE); gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook), child, TRUE); gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (priv->notebook), child, - TRUE, TRUE, GTK_PACK_START); + TRUE, TRUE, GTK_PACK_START); DEBUG ("Chat added (%d references)", G_OBJECT (chat)->ref_count); } @@ -1524,13 +1759,12 @@ empathy_chat_window_has_focus (EmpathyChatWindow *window) } EmpathyChat * -empathy_chat_window_find_chat (McAccount *account, +empathy_chat_window_find_chat (EmpathyAccount *account, const gchar *id) { GList *l; - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (!G_STR_EMPTY (id), NULL); + g_return_val_if_fail (!EMP_STR_EMPTY (id), NULL); for (l = chat_windows; l; l = l->next) { EmpathyChatWindowPriv *priv; @@ -1579,20 +1813,6 @@ empathy_chat_window_present_chat (EmpathyChat *chat) empathy_chat_window_switch_to_chat (window, chat); empathy_window_present (GTK_WINDOW (priv->dialog), TRUE); - gtk_widget_grab_focus (chat->input_text_view); + gtk_widget_grab_focus (chat->input_text_view); } -#if 0 -static gboolean -chat_window_should_play_sound (EmpathyChatWindow *window) -{ - EmpathyChatWindowPriv *priv = GET_PRIV (window); - gboolean has_focus = FALSE; - - g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (window), FALSE); - - g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL); - - return !has_focus; -} -#endif