#include <telepathy-glib/telepathy-glib.h>
+#include <libempathy/empathy-client-factory.h>
#include <libempathy/empathy-contact.h>
#include <libempathy/empathy-message.h>
#include <libempathy/empathy-chatroom-manager.h>
#include <libempathy/empathy-utils.h>
#include <libempathy/empathy-tp-contact-factory.h>
#include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-request-util.h>
+#include <libempathy/empathy-individual-manager.h>
#include <libempathy-gtk/empathy-images.h>
#include <libempathy-gtk/empathy-contact-dialogs.h>
#include "empathy-chat-window.h"
#include "empathy-about-dialog.h"
#include "empathy-invite-participant-dialog.h"
+#include "gedit-close-button.h"
#define DEBUG_FLAG EMPATHY_DEBUG_CHAT
#include <libempathy/empathy-debug.h>
typedef enum {
DND_DRAG_TYPE_CONTACT_ID,
+ DND_DRAG_TYPE_INDIVIDUAL_ID,
DND_DRAG_TYPE_URI_LIST,
DND_DRAG_TYPE_TAB
} DndDragType;
static const GtkTargetEntry drag_types_dest[] = {
{ "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
+ { "text/x-individual-id", 0, DND_DRAG_TYPE_INDIVIDUAL_ID },
{ "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, DND_DRAG_TYPE_TAB },
{ "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
{ "text/path-list", 0, DND_DRAG_TYPE_URI_LIST },
static const GtkTargetEntry drag_types_dest_contact[] = {
{ "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
+ { "text/x-individual-id", 0, DND_DRAG_TYPE_INDIVIDUAL_ID },
};
static const GtkTargetEntry drag_types_dest_file[] = {
{ "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
};
-static void chat_window_update (EmpathyChatWindow *window);
+static void chat_window_update (EmpathyChatWindow *window,
+ gboolean update_contact_menu);
static void empathy_chat_window_add_chat (EmpathyChatWindow *window,
EmpathyChat *chat);
return NULL;
}
+static void
+remove_all_chats (EmpathyChatWindow *window)
+{
+ EmpathyChatWindowPriv *priv;
+
+ priv = GET_PRIV (window);
+ g_object_ref (window);
+
+ while (priv->chats) {
+ empathy_chat_window_remove_chat (window, priv->chats->data);
+ }
+
+ g_object_unref (window);
+}
+
+static void
+confirm_close_response_cb (GtkWidget *dialog,
+ int response,
+ EmpathyChatWindow *window)
+{
+ EmpathyChat *chat;
+
+ chat = g_object_get_data (G_OBJECT (dialog), "chat");
+
+ gtk_widget_destroy (dialog);
+
+ if (response != GTK_RESPONSE_ACCEPT)
+ return;
+
+ if (chat != NULL) {
+ empathy_chat_window_remove_chat (window, chat);
+ } else {
+ remove_all_chats (window);
+ }
+}
+
+static void
+confirm_close (EmpathyChatWindow *window,
+ gboolean close_window,
+ guint n_rooms,
+ EmpathyChat *chat)
+{
+ EmpathyChatWindowPriv *priv;
+ GtkWidget *dialog;
+ gchar *primary, *secondary;
+
+ g_return_if_fail (n_rooms > 0);
+
+ if (n_rooms > 1) {
+ g_return_if_fail (chat == NULL);
+ } else {
+ g_return_if_fail (chat != NULL);
+ }
+
+ priv = GET_PRIV (window);
+
+ /* If there are no chats in this window, how could we possibly have got
+ * here?
+ */
+ g_return_if_fail (priv->chats != NULL);
+
+ /* Treat closing a window which only has one tab exactly like closing
+ * that tab.
+ */
+ if (close_window && priv->chats->next == NULL) {
+ close_window = FALSE;
+ chat = priv->chats->data;
+ }
+
+ if (close_window) {
+ primary = g_strdup (_("Close this window?"));
+
+ if (n_rooms == 1) {
+ gchar *chat_name = empathy_chat_dup_name (chat);
+ secondary = g_strdup_printf (
+ _("Closing this window will leave %s. You will "
+ "not receive any further messages until you "
+ "rejoin it."),
+ chat_name);
+ g_free (chat_name);
+ } else {
+ secondary = g_strdup_printf (
+ /* Note to translators: the number of chats will
+ * always be at least 2.
+ */
+ ngettext (
+ "Closing this window will leave a chat room. You will "
+ "not receive any further messages until you rejoin it.",
+ "Closing this window will leave %u chat rooms. You will "
+ "not receive any further messages until you rejoin them.",
+ n_rooms),
+ n_rooms);
+ }
+ } else {
+ gchar *chat_name = empathy_chat_dup_name (chat);
+ primary = g_strdup_printf (_("Leave %s?"), chat_name);
+ secondary = g_strdup (_("You will not receive any further messages from this chat "
+ "room until you rejoin it."));
+ g_free (chat_name);
+ }
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (priv->dialog),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CANCEL,
+ "%s", primary);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ g_object_set (dialog, "secondary-text", secondary, NULL);
+
+ g_free (primary);
+ g_free (secondary);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ close_window ? _("Close window") : _("Leave room"),
+ GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT);
+
+ if (!close_window) {
+ g_object_set_data (G_OBJECT (dialog), "chat", chat);
+ }
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (confirm_close_response_cb), window);
+
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+/* Returns TRUE if we should check if the user really wants to leave. If it's
+ * a multi-user chat, and it has a TpChat (so there's an underlying channel, so
+ * the user is actually in the room as opposed to having been kicked or gone
+ * offline or something), then we should check.
+ */
+static gboolean
+chat_needs_close_confirmation (EmpathyChat *chat)
+{
+ return (empathy_chat_is_room (chat)
+ && empathy_chat_get_tp_chat (chat) != NULL);
+}
+
+static void
+maybe_close_chat (EmpathyChatWindow *window,
+ EmpathyChat *chat)
+{
+ g_return_if_fail (chat != NULL);
+
+ if (chat_needs_close_confirmation (chat)) {
+ confirm_close (window, FALSE, 1, chat);
+ } else {
+ empathy_chat_window_remove_chat (window, chat);
+ }
+}
+
static void
chat_window_close_clicked_cb (GtkAction *action,
EmpathyChat *chat)
EmpathyChatWindow *window;
window = chat_window_find_chat (chat);
- empathy_chat_window_remove_chat (window, chat);
+ maybe_close_chat (window, chat);
}
static void
EmpathyChat *chat,
gboolean is_tab_label)
{
- EmpathyChatWindowPriv *priv;
GtkWidget *hbox;
GtkWidget *name_label;
GtkWidget *status_image;
- GtkWidget *close_button;
- GtkWidget *close_image;
GtkWidget *event_box;
GtkWidget *event_box_hbox;
PangoAttrList *attr_list;
PangoAttribute *attr;
- priv = GET_PRIV (window);
-
/* The spacing between the button and the label. */
- hbox = gtk_hbox_new (FALSE, 0);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
event_box = gtk_event_box_new ();
gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
status_image = gtk_image_new ();
/* Spacing between the icon and label. */
- event_box_hbox = gtk_hbox_new (FALSE, 0);
+ event_box_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
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);
gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0);
if (is_tab_label) {
- close_button = gtk_button_new ();
- gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
+ GtkWidget *close_button;
+ GtkWidget *sending_spinner;
+
+ sending_spinner = gtk_spinner_new ();
+
+ gtk_box_pack_start (GTK_BOX (hbox), sending_spinner,
+ FALSE, FALSE, 0);
+ g_object_set_data (G_OBJECT (chat),
+ "chat-window-tab-sending-spinner",
+ sending_spinner);
+
+ close_button = gedit_close_button_new ();
g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button);
/* We don't want focus/keynav for the button to avoid clutter, and
gtk_widget_set_can_focus (close_button, FALSE);
gtk_widget_set_can_default (close_button, FALSE);
- /* Set the name to make the special rc style match. */
- gtk_widget_set_name (close_button, "empathy-close-button");
-
- close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
-
- gtk_container_add (GTK_CONTAINER (close_button), close_image);
-
gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
g_signal_connect (close_button,
g_signal_handlers_disconnect_by_func (object,
_submenu_notify_visible_changed_cb,
userdata);
- chat_window_update (EMPATHY_CHAT_WINDOW (userdata));
+ chat_window_update (EMPATHY_CHAT_WINDOW (userdata), TRUE);
}
static void
tp_chat = empathy_chat_get_tp_chat (priv->current_chat);
if (tp_chat != NULL) {
- connection = empathy_tp_chat_get_connection (tp_chat);
+ connection = tp_channel_borrow_connection (TP_CHANNEL (tp_chat));
sensitive = empathy_tp_chat_can_add_contact (tp_chat) &&
(tp_connection_get_status (connection, NULL) ==
if (orig_submenu == NULL || !gtk_widget_get_visible (orig_submenu)) {
submenu = empathy_chat_get_contact_menu (priv->current_chat);
+
if (submenu != NULL) {
+ /* gtk_menu_attach_to_widget () doesn't behave nicely here */
+ g_object_set_data (G_OBJECT (submenu), "window", priv->dialog);
+
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu);
gtk_widget_show (menu);
gtk_widget_set_sensitive (menu, TRUE);
- }
- else {
+ } else {
gtk_widget_set_sensitive (menu, FALSE);
}
} else {
static gchar *
get_window_title_name (EmpathyChatWindowPriv *priv)
{
- const gchar *active_name;
+ gchar *active_name, *ret;
guint nb_chats;
guint current_unread_msgs;
nb_chats = g_list_length (priv->chats);
g_assert (nb_chats > 0);
- active_name = empathy_chat_get_name (priv->current_chat);
+ active_name = empathy_chat_dup_name (priv->current_chat);
current_unread_msgs = empathy_chat_get_nb_unread_messages (
priv->current_chat);
if (nb_chats == 1) {
/* only one tab */
if (current_unread_msgs == 0)
- return g_strdup (active_name);
+ ret = g_strdup (active_name);
else
- return g_strdup_printf (ngettext (
+ ret = g_strdup_printf (ngettext (
"%s (%d unread)",
"%s (%d unread)", current_unread_msgs),
active_name, current_unread_msgs);
if (all_unread_msgs == 0) {
/* no unread message */
- return g_strdup_printf (ngettext (
+ ret = g_strdup_printf (ngettext (
"%s (and %u other)",
"%s (and %u others)", nb_others),
active_name, nb_others);
else if (all_unread_msgs == current_unread_msgs) {
/* unread messages are in the current tab */
- return g_strdup_printf (ngettext (
+ ret = g_strdup_printf (ngettext (
"%s (%d unread)",
"%s (%d unread)", current_unread_msgs),
active_name, current_unread_msgs);
else if (current_unread_msgs == 0) {
/* unread messages are in other tabs */
- return g_strdup_printf (ngettext (
+ ret = g_strdup_printf (ngettext (
"%s (%d unread from others)",
"%s (%d unread from others)",
all_unread_msgs),
else {
/* unread messages are in all the tabs */
- return g_strdup_printf (ngettext (
+ ret = g_strdup_printf (ngettext (
"%s (%d unread from all)",
"%s (%d unread from all)",
all_unread_msgs),
active_name, all_unread_msgs);
}
}
+
+ g_free (active_name);
+
+ return ret;
}
static void
}
static void
-chat_window_update (EmpathyChatWindow *window)
+chat_window_update (EmpathyChatWindow *window,
+ gboolean update_contact_menu)
{
EmpathyChatWindowPriv *priv = GET_PRIV (window);
gint num_pages;
chat_window_conversation_menu_update (priv, window);
- chat_window_contact_menu_update (priv,
- window);
+ /* If this update is due to a focus-in event, we know the menu will be
+ the same as when we last left it, so no work to do. Besides, if we
+ swap out the menu on a focus-in, we may confuse any external global
+ menu watching. */
+ if (update_contact_menu) {
+ chat_window_contact_menu_update (priv,
+ window);
+ }
chat_window_title_update (priv);
}
static void
-chat_window_update_chat_tab (EmpathyChat *chat)
+chat_window_update_chat_tab_full (EmpathyChat *chat,
+ gboolean update_contact_menu)
{
EmpathyChatWindow *window;
EmpathyChatWindowPriv *priv;
EmpathyContact *remote_contact;
- const gchar *name;
+ gchar *name;
const gchar *id;
TpAccount *account;
const gchar *subject;
const gchar *icon_name;
GtkWidget *tab_image;
GtkWidget *menu_image;
+ GtkWidget *sending_spinner;
+ guint nb_sending;
window = chat_window_find_chat (chat);
if (!window) {
priv = GET_PRIV (window);
/* Get information */
- name = empathy_chat_get_name (chat);
+ name = empathy_chat_dup_name (chat);
account = empathy_chat_get_account (chat);
subject = empathy_chat_get_subject (chat);
remote_contact = empathy_chat_get_remote_contact (chat);
else if (empathy_chat_get_nb_unread_messages (chat) > 0) {
icon_name = EMPATHY_IMAGE_MESSAGE;
}
- else if (empathy_chat_is_composing (chat)) {
+ else if (remote_contact && empathy_chat_is_composing (chat)) {
icon_name = EMPATHY_IMAGE_TYPING;
}
+ else if (empathy_chat_is_sms_channel (chat)) {
+ icon_name = EMPATHY_IMAGE_SMS;
+ }
else if (remote_contact) {
icon_name = empathy_icon_name_for_contact (remote_contact);
} else {
gtk_widget_hide (menu_image);
}
+ /* Update the sending spinner */
+ nb_sending = empathy_chat_get_n_messages_sending (chat);
+ sending_spinner = g_object_get_data (G_OBJECT (chat),
+ "chat-window-tab-sending-spinner");
+
+ g_object_set (sending_spinner,
+ "active", nb_sending > 0,
+ "visible", nb_sending > 0,
+ NULL);
+
/* Update tab tooltip */
tooltip = g_string_new (NULL);
id = name;
}
+ if (empathy_chat_is_sms_channel (chat)) {
+ append_markup_printf (tooltip, "%s ", _("SMS:"));
+ }
+
append_markup_printf (tooltip,
"<b>%s</b><small> (%s)</small>",
id,
tp_account_get_display_name (account));
+ if (nb_sending > 0) {
+ char *tmp = g_strdup_printf (
+ ngettext ("Sending %d message",
+ "Sending %d messages",
+ nb_sending),
+ nb_sending);
+
+ g_string_append (tooltip, "\n");
+ g_string_append (tooltip, tmp);
+
+ gtk_widget_set_tooltip_text (sending_spinner, tmp);
+ g_free (tmp);
+ }
+
if (!EMP_STR_EMPTY (status)) {
append_markup_printf (tooltip, "\n<i>%s</i>", status);
}
_("Topic:"), subject);
}
- if (empathy_chat_is_composing (chat)) {
+ if (remote_contact && empathy_chat_is_composing (chat)) {
append_markup_printf (tooltip, "\n%s", _("Typing a message."));
}
+ if (remote_contact != NULL) {
+ const gchar * const *types;
+
+ types = empathy_contact_get_client_types (remote_contact);
+ if (types != NULL && !tp_strdiff (types[0], "phone")) {
+ /* I'm on a phone ! */
+ gchar *tmp = name;
+
+ name = g_strdup_printf ("☎ %s", name);
+ g_free (tmp);
+ }
+ }
+
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);
g_free (markup);
/* Update tab and menu label */
+ if (empathy_chat_is_highlighted (chat)) {
+ markup = g_markup_printf_escaped (
+ "<span color=\"red\" weight=\"bold\">%s</span>",
+ name);
+ } else {
+ markup = g_markup_escape_text (name, -1);
+ }
+
widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label");
- gtk_label_set_text (GTK_LABEL (widget), name);
+ gtk_label_set_markup (GTK_LABEL (widget), markup);
widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-label");
- gtk_label_set_text (GTK_LABEL (widget), name);
+ gtk_label_set_markup (GTK_LABEL (widget), markup);
+ g_free (markup);
/* Update the window if it's the current chat */
if (priv->current_chat == chat) {
- chat_window_update (window);
+ chat_window_update (window, update_contact_menu);
}
+
+ g_free (name);
+}
+
+static void
+chat_window_update_chat_tab (EmpathyChat *chat)
+{
+ chat_window_update_chat_tab_full (chat, TRUE);
}
static void
chat_window_chat_notify_cb (EmpathyChat *chat)
{
+ EmpathyChatWindow *window;
EmpathyContact *old_remote_contact;
EmpathyContact *remote_contact = NULL;
}
chat_window_update_chat_tab (chat);
+
+ window = chat_window_find_chat (chat);
+ if (window != NULL) {
+ chat_window_update (window, FALSE);
+ }
}
static void
EmpathyChatWindowPriv *priv = GET_PRIV (window);
gboolean active;
TpAccount *account;
+ gchar *name;
const gchar *room;
EmpathyChatroom *chatroom;
active = gtk_toggle_action_get_active (toggle_action);
account = empathy_chat_get_account (priv->current_chat);
room = empathy_chat_get_id (priv->current_chat);
+ name = empathy_chat_dup_name (priv->current_chat);
chatroom = empathy_chatroom_manager_ensure_chatroom (
priv->chatroom_manager,
account,
room,
- empathy_chat_get_name (priv->current_chat));
+ name);
empathy_chatroom_set_favorite (chatroom, active);
g_object_unref (chatroom);
+ g_free (name);
}
static void
EmpathyChatWindowPriv *priv = GET_PRIV (window);
gboolean active;
TpAccount *account;
+ gchar *name;
const gchar *room;
EmpathyChatroom *chatroom;
active = gtk_toggle_action_get_active (toggle_action);
account = empathy_chat_get_account (priv->current_chat);
room = empathy_chat_get_id (priv->current_chat);
+ name = empathy_chat_dup_name (priv->current_chat);
chatroom = empathy_chatroom_manager_ensure_chatroom (
priv->chatroom_manager,
account,
room,
- empathy_chat_get_name (priv->current_chat));
+ name);
empathy_chatroom_set_always_urgent (chatroom, active);
g_object_unref (chatroom);
+ g_free (name);
}
static void
empathy_chat_set_show_contacts (priv->current_chat, active);
}
-static void
-got_contact_cb (TpConnection *connection,
- EmpathyContact *contact,
- const GError *error,
- gpointer user_data,
- GObject *object)
-{
- EmpathyTpChat *tp_chat = EMPATHY_TP_CHAT (user_data);
-
- if (error != NULL) {
- DEBUG ("Failed: %s", error->message);
- return;
- } else {
- empathy_contact_list_add (EMPATHY_CONTACT_LIST (tp_chat),
- contact, _("Inviting you to this room"));
- }
-}
-
static void
chat_window_invite_participant_activate_cb (GtkAction *action,
EmpathyChatWindow *window)
EmpathyChatWindowPriv *priv;
GtkWidget *dialog;
EmpathyTpChat *tp_chat;
- TpChannel *channel;
int response;
- TpAccount *account;
priv = GET_PRIV (window);
g_return_if_fail (priv->current_chat != NULL);
tp_chat = empathy_chat_get_tp_chat (priv->current_chat);
- channel = empathy_tp_chat_get_channel (tp_chat);
- account = empathy_chat_get_account (priv->current_chat);
dialog = empathy_invite_participant_dialog_new (
- GTK_WINDOW (priv->dialog), account);
+ GTK_WINDOW (priv->dialog), tp_chat);
gtk_widget_show (dialog);
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (response == GTK_RESPONSE_ACCEPT) {
- TpConnection *connection;
- const char *id;
+ TpContact *tp_contact;
+ EmpathyContact *contact;
- id = empathy_contact_selector_dialog_get_selected (
- EMPATHY_CONTACT_SELECTOR_DIALOG (dialog), NULL, NULL);
- if (EMP_STR_EMPTY (id)) goto out;
+ tp_contact = empathy_invite_participant_dialog_get_selected (
+ EMPATHY_INVITE_PARTICIPANT_DIALOG (dialog));
+ if (tp_contact == NULL) goto out;
- connection = tp_channel_borrow_connection (channel);
- empathy_tp_contact_factory_get_from_id (connection, id,
- got_contact_cb, tp_chat, NULL, NULL);
+ contact = empathy_contact_dup_from_tp_contact (tp_contact);
+
+ empathy_contact_list_add (EMPATHY_CONTACT_LIST (tp_chat),
+ contact, _("Inviting you to this room"));
+
+ g_object_unref (contact);
}
out:
g_return_if_fail (priv->current_chat != NULL);
- empathy_chat_window_remove_chat (window, priv->current_chat);
+ maybe_close_chat (window, priv->current_chat);
}
static void
EmpathyChatWindow *window)
{
EmpathyChatWindowPriv *priv;
- EmpathyChat *chat;
gint index_, numPages;
gboolean wrap_around;
g_object_get (gtk_settings_get_default (), "gtk-keynav-wrap-around",
&wrap_around, NULL);
- chat = priv->current_chat;
index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
EmpathyChatWindow *window)
{
EmpathyChatWindowPriv *priv;
- EmpathyChat *chat;
gint index_, numPages;
gboolean wrap_around;
g_object_get (gtk_settings_get_default (), "gtk-keynav-wrap-around",
&wrap_around, NULL);
- chat = priv->current_chat;
index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
EmpathyChatWindow *window)
{
EmpathyChatWindowPriv *priv = GET_PRIV (window);
- empathy_chat_manager_undo_closed_chat (priv->chat_manager);
+ empathy_chat_manager_undo_closed_chat (priv->chat_manager,
+ empathy_get_current_action_time ());
}
static void
EmpathyChatWindow *window)
{
EmpathyChatWindowPriv *priv = GET_PRIV (window);
+ EmpathyChat *chat = NULL;
+ guint n_rooms = 0;
+ GList *l;
DEBUG ("Delete event received");
- g_object_ref (window);
- while (priv->chats) {
- empathy_chat_window_remove_chat (window, priv->chats->data);
+ for (l = priv->chats; l != NULL; l = l->next) {
+ if (chat_needs_close_confirmation (l->data)) {
+ chat = l->data;
+ n_rooms++;
+ }
+ }
+
+ if (n_rooms > 0) {
+ confirm_close (window, TRUE, n_rooms,
+ (n_rooms == 1 ? chat : NULL));
+ } else {
+ remove_all_chats (window);
}
- g_object_unref (window);
return TRUE;
}
G_CALLBACK (chat_window_notification_closed_cb), window, 0);
if (has_x_canonical_append) {
+ /* We have to set a not empty string to keep libnotify happy */
notify_notification_set_hint_string (notification,
- EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND, "");
+ EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND, "1");
}
+
+ notify_notification_set_hint (notification,
+ EMPATHY_NOTIFY_MANAGER_CAP_CATEGORY,
+ g_variant_new_string ("im.received"));
}
pixbuf = empathy_notify_manager_get_pixbuf_for_notification (priv->notify_mgr,
g_free (escaped);
}
-static void
-chat_window_set_highlight_room_labels (EmpathyChat *chat)
-{
- gchar *markup;
- GtkWidget *widget;
-
- if (!empathy_chat_is_room (chat))
- return;
-
- markup = g_markup_printf_escaped (
- "<span color=\"red\" weight=\"bold\">%s</span>",
- 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);
-
- widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-label");
- gtk_label_set_markup (GTK_LABEL (widget), markup);
-
- g_free (markup);
-}
-
static gboolean
empathy_chat_window_has_focus (EmpathyChatWindow *window)
{
chat_window_new_message_cb (EmpathyChat *chat,
EmpathyMessage *message,
gboolean pending,
+ gboolean should_highlight,
EmpathyChatWindow *window)
{
EmpathyChatWindowPriv *priv;
* a) the chatroom's always_urgent property is TRUE
* b) the message contains our alias
*/
- if (empathy_chat_is_room (chat) ||
- empathy_chat_get_remote_contact (chat) == NULL) {
+ if (empathy_chat_is_room (chat)) {
TpAccount *account;
const gchar *room;
EmpathyChatroom *chatroom;
chatroom = empathy_chatroom_manager_find (priv->chatroom_manager,
account, room);
- if (empathy_chatroom_is_always_urgent (chatroom)) {
+ if (chatroom != NULL && empathy_chatroom_is_always_urgent (chatroom)) {
needs_urgency = TRUE;
} else {
- needs_urgency = empathy_message_should_highlight (message);
+ needs_urgency = should_highlight;
}
} else {
needs_urgency = TRUE;
if (needs_urgency) {
if (!has_focus) {
chat_window_set_urgency_hint (window, TRUE);
- chat_window_set_highlight_room_labels (chat);
}
- empathy_sound_manager_play (priv->sound_mgr, GTK_WIDGET (priv->dialog),
- EMPATHY_SOUND_MESSAGE_INCOMING);
+ /* Pending messages have already been displayed and notified in the
+ * approver, so we don't display a notification and play a sound for those */
+ if (!pending) {
+ empathy_sound_manager_play (priv->sound_mgr, GTK_WIDGET (priv->dialog),
+ EMPATHY_SOUND_MESSAGE_INCOMING);
- /* Pending messages have already been displayed in the approver, so we don't
- * display a notification for those. */
- if (!pending)
chat_window_show_or_update_notification (window, message, chat);
+ }
}
/* update the number of unread messages and the window icon */
chat_window_icon_update (priv, TRUE);
}
+static void
+chat_window_command_part (EmpathyChat *chat,
+ GStrv strv)
+{
+ EmpathyChat *chat_to_be_parted;
+ EmpathyTpChat *tp_chat = NULL;
+
+ if (strv[1] == NULL) {
+ /* No chatroom ID specified */
+ tp_chat = empathy_chat_get_tp_chat (chat);
+ if (tp_chat)
+ empathy_tp_chat_leave (tp_chat, "");
+ return;
+ }
+ chat_to_be_parted = empathy_chat_window_find_chat (
+ empathy_chat_get_account (chat), strv[1], FALSE);
+
+ if (chat_to_be_parted != NULL) {
+ /* Found a chatroom matching the specified ID */
+ tp_chat = empathy_chat_get_tp_chat (chat_to_be_parted);
+ if (tp_chat)
+ empathy_tp_chat_leave (tp_chat, strv[2]);
+ } else {
+ gchar *message;
+
+ /* Going by the syntax of PART command:
+ *
+ * /PART [<chatroom-ID>] [<reason>]
+ *
+ * Chatroom-ID is not a must to specify a reason.
+ * If strv[1] (chatroom-ID) is not a valid identifier for a connected
+ * MUC then the current chatroom should be parted and srtv[1] should
+ * be treated as part of the optional part-message. */
+ message = g_strconcat (strv[1], " ", strv[2], NULL);
+ tp_chat = empathy_chat_get_tp_chat (chat);
+ if (tp_chat)
+ empathy_tp_chat_leave (tp_chat, message);
+
+ g_free (message);
+ }
+}
+
static GtkNotebook *
notebook_create_window_cb (GtkNotebook *source,
GtkWidget *page,
static void
chat_window_page_switched_cb (GtkNotebook *notebook,
- gpointer ignore, /* see note below */
+ GtkWidget *child,
gint page_num,
EmpathyChatWindow *window)
{
- EmpathyChatWindowPriv *priv;
- EmpathyChat *chat;
- GtkWidget *child;
+ EmpathyChatWindowPriv *priv = GET_PRIV (window);
+ EmpathyChat *chat = EMPATHY_CHAT (child);
DEBUG ("Page switched");
- priv = GET_PRIV (window);
-
- /* N.B. in GTK+ 3 child is passed as the first argument to the signal,
- * but we can't use that while trying to retain GTK+ 2.x compatibility.
- */
- child = gtk_notebook_get_nth_page (notebook, page_num);
- chat = EMPATHY_CHAT (child);
-
if (priv->page_added) {
priv->page_added = FALSE;
empathy_chat_scroll_down (chat);
g_signal_connect (chat, "new-message",
G_CALLBACK (chat_window_new_message_cb),
window);
+ g_signal_connect (chat, "part-command-entered",
+ G_CALLBACK (chat_window_command_part),
+ NULL);
g_signal_connect (chat, "notify::tp-chat",
G_CALLBACK (chat_window_update_chat_tab),
window);
if (priv->chats == NULL) {
g_object_unref (window);
} else {
- chat_window_update (window);
+ chat_window_update (window, TRUE);
}
}
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);
+ chat_window_update_chat_tab_full (priv->current_chat, FALSE);
return FALSE;
}
return FALSE;
}
+static void
+drag_data_received_individual_id (EmpathyChatWindow *self,
+ GtkWidget *widget,
+ GdkDragContext *context,
+ int x,
+ int y,
+ GtkSelectionData *selection,
+ guint info,
+ guint time_)
+{
+ const gchar *id;
+ EmpathyIndividualManager *manager = NULL;
+ FolksIndividual *individual;
+ EmpathyChatWindowPriv *priv = GET_PRIV (self);
+ EmpathyTpChat *chat;
+ TpContact *tp_contact;
+ TpConnection *conn;
+ EmpathyContact *contact;
+
+ id = (const gchar *) gtk_selection_data_get_data (selection);
+
+ DEBUG ("DND invididual %s", id);
+
+ if (priv->current_chat == NULL)
+ goto out;
+
+ chat = empathy_chat_get_tp_chat (priv->current_chat);
+ if (chat == NULL)
+ goto out;
+
+ if (!empathy_tp_chat_can_add_contact (chat)) {
+ DEBUG ("Can't invite contact to %s",
+ tp_proxy_get_object_path (chat));
+ goto out;
+ }
+
+ manager = empathy_individual_manager_dup_singleton ();
+
+ individual = empathy_individual_manager_lookup_member (manager, id);
+ if (individual == NULL) {
+ DEBUG ("Failed to find individual %s", id);
+ goto out;
+ }
+
+ conn = tp_channel_borrow_connection ((TpChannel *) chat);
+ tp_contact = empathy_get_tp_contact_for_individual (individual, conn);
+ if (tp_contact == NULL) {
+ DEBUG ("Can't find a TpContact on connection %s for %s",
+ tp_proxy_get_object_path (conn), id);
+ goto out;
+ }
+
+ DEBUG ("Inviting %s to join %s", tp_contact_get_identifier (tp_contact),
+ tp_channel_get_identifier ((TpChannel *) chat));
+
+ contact = empathy_contact_dup_from_tp_contact (tp_contact);
+ empathy_contact_list_add (EMPATHY_CONTACT_LIST (chat), contact, NULL);
+ g_object_unref (contact);
+
+out:
+ gtk_drag_finish (context, TRUE, FALSE, time_);
+ tp_clear_object (&manager);
+}
+
static void
chat_window_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
EmpathyChat *chat = NULL;
EmpathyChatWindow *old_window;
TpAccount *account = NULL;
- TpAccountManager *account_manager;
+ EmpathyClientFactory *factory;
const gchar *id;
gchar **strv;
const gchar *account_id;
id = (const gchar*) gtk_selection_data_get_data (selection);
- /* FIXME: Perhaps should be sure that the account manager is
- * prepared before calling _ensure_account on it. */
- account_manager = tp_account_manager_dup ();
+ factory = empathy_client_factory_dup ();
DEBUG ("DND contact from roster with id:'%s'", id);
account_id = strv[0];
contact_id = strv[1];
account =
- tp_account_manager_ensure_account (account_manager, account_id);
+ tp_simple_client_factory_ensure_account (
+ TP_SIMPLE_CLIENT_FACTORY (factory), account_id,
+ NULL, NULL);
+
+ g_object_unref (factory);
if (account != NULL)
- chat = empathy_chat_window_find_chat (account, contact_id);
+ chat = empathy_chat_window_find_chat (account, contact_id, FALSE);
}
if (account == NULL) {
}
if (!chat) {
- empathy_dispatcher_chat_with_contact_id (
- account, contact_id, gtk_get_current_event_time ());
+ empathy_chat_with_contact_id (
+ account, contact_id,
+ empathy_get_current_action_time (),
+ NULL, NULL);
g_strfreev (strv);
return;
}
- g_object_unref (account_manager);
g_strfreev (strv);
old_window = chat_window_find_chat (chat);
*/
gtk_drag_finish (context, TRUE, FALSE, time_);
}
+ else if (info == DND_DRAG_TYPE_INDIVIDUAL_ID) {
+ drag_data_received_individual_id (window, widget, context, x, y,
+ selection, info, time_);
+ }
else if (info == DND_DRAG_TYPE_URI_LIST) {
EmpathyChatWindowPriv *priv;
EmpathyContact *contact;
object_class->finalize = chat_window_finalize;
g_type_class_add_private (object_class, sizeof (EmpathyChatWindowPriv));
-
- /* Set up a style for the close button with no focus padding. */
- gtk_rc_parse_string (
- "style \"empathy-close-button-style\"\n"
- "{\n"
- " GtkWidget::focus-padding = 0\n"
- " xthickness = 0\n"
- " ythickness = 0\n"
- "}\n"
- "widget \"*.empathy-close-button\" style \"empathy-close-button-style\"");
}
static void
window);
}
-static GtkWidget *
-empathy_chat_window_get_dialog (EmpathyChatWindow *window)
-{
- EmpathyChatWindowPriv *priv;
-
- g_return_val_if_fail (window != NULL, NULL);
-
- priv = GET_PRIV (window);
-
- return priv->dialog;
-}
-
/* Returns the window to open a new tab in if there is a suitable window,
* otherwise, returns NULL indicating that a new window should be added.
*/
}
for (l = chat_windows; l; l = l->next) {
- EmpathyChatWindowPriv *priv;
EmpathyChatWindow *chat_window;
- GtkWidget *dialog;
guint nb_rooms, nb_private;
chat_window = l->data;
- priv = GET_PRIV (chat_window);
-
- dialog = empathy_chat_window_get_dialog (chat_window);
empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private);
if (!room && nb_private == 0)
continue;
- /* Found a window on this desktop, make it visible if necessary */
- if (!empathy_window_get_is_visible (GTK_WINDOW (dialog)))
- empathy_window_present (GTK_WINDOW (dialog));
return chat_window;
}
g_signal_connect (chat, "notify::remote-contact",
G_CALLBACK (chat_window_chat_notify_cb),
NULL);
+ g_signal_connect (chat, "notify::sms-channel",
+ G_CALLBACK (chat_window_chat_notify_cb),
+ NULL);
+ g_signal_connect (chat, "notify::n-messages-sending",
+ G_CALLBACK (chat_window_chat_notify_cb),
+ NULL);
+ g_signal_connect (chat, "notify::nb-unread-messages",
+ G_CALLBACK (chat_window_chat_notify_cb),
+ NULL);
chat_window_chat_notify_cb (chat);
gtk_notebook_append_page_menu (GTK_NOTEBOOK (priv->notebook), child, label, popup_label);
EmpathyChat *
empathy_chat_window_find_chat (TpAccount *account,
- const gchar *id)
+ const gchar *id,
+ gboolean sms_channel)
{
GList *l;
chat = ll->data;
if (account == empathy_chat_get_account (chat) &&
- !tp_strdiff (id, empathy_chat_get_id (chat))) {
+ !tp_strdiff (id, empathy_chat_get_id (chat)) &&
+ sms_channel == empathy_chat_is_sms_channel (chat)) {
return chat;
}
}
window = empathy_chat_window_get_default (empathy_chat_is_room (chat));
if (!window) {
window = empathy_chat_window_new ();
- gtk_widget_show_all (GET_PRIV (window)->dialog);
+
+ /* we want to display the newly created window even if we don't present
+ * it */
+ priv = GET_PRIV (window);
+ gtk_widget_show (priv->dialog);
}
empathy_chat_window_add_chat (window, chat);
}
empathy_chat_window_switch_to_chat (window, chat);
- empathy_window_present_with_time (GTK_WINDOW (priv->dialog),
- x_timestamp);
+
+ /* Don't use empathy_window_present_with_time () which would move the window
+ * to our current desktop but move to the window's desktop instead. This is
+ * more coherent with Shell's 'app is ready' notication which moves the view
+ * to the app desktop rather than moving the app itself. */
+ empathy_move_to_window_desktop (GTK_WINDOW (priv->dialog), x_timestamp);
gtk_widget_grab_focus (chat->input_text_view);
}