* Martyn Russell <martyn@imendio.com>
* Geert-Jan Van den Bogaerde <geertjan@gnome.org>
* Xavier Claessens <xclaesse@gmail.com>
+ * RĂ´mulo Fernandes Machado <romulo@castorgroup.net>
*/
#include <config.h>
#include <glib/gi18n.h>
#include <libnotify/notification.h>
-#include <telepathy-glib/util.h>
+#include <telepathy-glib/telepathy-glib.h>
#include <libempathy/empathy-contact.h>
#include <libempathy/empathy-message.h>
-#include <libempathy/empathy-dispatcher.h>
#include <libempathy/empathy-chatroom-manager.h>
-#include <libempathy/empathy-account-manager.h>
#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-tp-contact-factory.h>
+#include <libempathy/empathy-contact-list.h>
#include <libempathy-gtk/empathy-images.h>
#include <libempathy-gtk/empathy-conf.h>
#include <libempathy-gtk/empathy-smiley-manager.h>
#include <libempathy-gtk/empathy-sound.h>
#include <libempathy-gtk/empathy-ui-utils.h>
+#include <libempathy-gtk/empathy-notify-manager.h>
#include "empathy-chat-window.h"
#include "empathy-about-dialog.h"
-#include "empathy-misc.h"
+#include "empathy-invite-participant-dialog.h"
#define DEBUG_FLAG EMPATHY_DEBUG_CHAT
#include <libempathy/empathy-debug.h>
GList *chats_composing;
gboolean page_added;
gboolean dnd_same_window;
- guint save_geometry_id;
EmpathyChatroomManager *chatroom_manager;
+ EmpathyNotifyManager *notify_mgr;
GtkWidget *dialog;
GtkWidget *notebook;
NotifyNotification *notification;
NotificationData *notification_data;
+ GtkTargetList *contact_targets;
+ GtkTargetList *file_targets;
+
/* Menu items. */
GtkUIManager *ui_manager;
GtkAction *menu_conv_insert_smiley;
GtkAction *menu_edit_cut;
GtkAction *menu_edit_copy;
GtkAction *menu_edit_paste;
+ GtkAction *menu_edit_find;
GtkAction *menu_tabs_next;
GtkAction *menu_tabs_prev;
typedef enum {
DND_DRAG_TYPE_CONTACT_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 },
{ "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 },
+};
+
+static const GtkTargetEntry drag_types_dest_file[] = {
+ /* must be first to be prioritized, in order to receive the
+ * note's file path from Tomboy instead of an URI */
+ { "text/path-list", 0, DND_DRAG_TYPE_URI_LIST },
+ { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
};
static void chat_window_update (EmpathyChatWindow *window);
/* 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);
+ 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");
}
static void
-chat_window_update (EmpathyChatWindow *window)
+chat_window_menu_context_update (EmpathyChatWindowPriv *priv,
+ gint num_pages)
{
- EmpathyChatWindowPriv *priv = GET_PRIV (window);
- gboolean first_page;
- gboolean last_page;
- gboolean is_connected;
- gint num_pages;
- gint page_num;
- gint i;
- const gchar *name;
- guint n_chats;
- GdkPixbuf *icon;
- EmpathyContact *remote_contact;
- gboolean avatar_in_icon;
- GtkWidget *chat;
- GtkWidget *chat_close_button;
- GtkWidget *menu, *submenu, *orig_submenu;
+ gboolean first_page;
+ gboolean last_page;
+ gboolean is_connected;
+ gint page_num;
- /* Get information */
page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
- num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
first_page = (page_num == 0);
last_page = (page_num == (num_pages - 1));
is_connected = empathy_chat_get_tp_chat (priv->current_chat) != NULL;
- name = empathy_chat_get_name (priv->current_chat);
- n_chats = g_list_length (priv->chats);
- DEBUG ("Update window");
+ DEBUG ("Update window : Menu Contexts (Tabs & Conv)");
- /* Update menu */
- 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_next, TRUE);
+ gtk_action_set_sensitive (priv->menu_tabs_prev, TRUE);
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);
+}
+
+static void
+chat_window_conversation_menu_update (EmpathyChatWindowPriv *priv,
+ EmpathyChatWindow *self)
+{
+ EmpathyTpChat *tp_chat;
+ TpConnection *connection;
+ GtkAction *action;
+ gboolean sensitive = FALSE;
+
+ g_return_if_fail (priv->current_chat != NULL);
+
+ action = gtk_ui_manager_get_action (priv->ui_manager,
+ "/chats_menubar/menu_conv/menu_conv_invite_participant");
+ tp_chat = empathy_chat_get_tp_chat (priv->current_chat);
+
+ if (tp_chat != NULL) {
+ connection = empathy_tp_chat_get_connection (tp_chat);
+
+ sensitive = empathy_tp_chat_can_add_contact (tp_chat) &&
+ (tp_connection_get_status (connection, NULL) ==
+ TP_CONNECTION_STATUS_CONNECTED);
+ }
+
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+static void
+chat_window_contact_menu_update (EmpathyChatWindowPriv *priv,
+ EmpathyChatWindow *window)
+{
+ GtkWidget *menu, *submenu, *orig_submenu;
- /* Update Contact menu */
menu = gtk_ui_manager_get_widget (priv->ui_manager,
"/chats_menubar/menu_contact");
orig_submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu));
- if (!GTK_WIDGET_VISIBLE (orig_submenu))
- {
+
+ DEBUG ("Update window : Contact Menu");
+
+ if (orig_submenu == NULL || !GTK_WIDGET_VISIBLE (orig_submenu)) {
submenu = empathy_chat_get_contact_menu (priv->current_chat);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu);
gtk_widget_show (menu);
(GCallback)_submenu_notify_visible_changed_cb,
G_OBJECT (window));
}
+}
+
+static guint
+get_all_unread_messages (EmpathyChatWindowPriv *priv)
+{
+ GList *l;
+ guint nb = 0;
- /* Update window title */
- if (n_chats == 1) {
- gtk_window_set_title (GTK_WINDOW (priv->dialog), name);
+ for (l = priv->chats_new_msg; l != NULL; l = g_list_next (l)) {
+ EmpathyChat *chat = l->data;
+
+ nb += empathy_chat_get_nb_unread_messages (chat);
+ }
+
+ return nb;
+}
+
+static gchar *
+get_window_title_name (EmpathyChatWindowPriv *priv)
+{
+ const gchar *active_name;
+ 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);
+
+ 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);
+ else
+ return g_strdup_printf (ngettext (
+ "%s (%d unread)",
+ "%s (%d unread)", current_unread_msgs),
+ active_name, current_unread_msgs);
} else {
- gchar *title;
+ guint nb_others = nb_chats - 1;
+ guint all_unread_msgs;
+
+ all_unread_msgs = get_all_unread_messages (priv);
+
+ if (all_unread_msgs == 0) {
+ /* no unread message */
+ return g_strdup_printf (ngettext (
+ "%s (and %u other)",
+ "%s (and %u others)", nb_others),
+ active_name, nb_others);
+ }
- title = g_strdup_printf (_("Conversations (%d)"), n_chats);
- gtk_window_set_title (GTK_WINDOW (priv->dialog), title);
- g_free (title);
+ else if (all_unread_msgs == current_unread_msgs) {
+ /* unread messages are in the current tab */
+ return 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 (
+ "%s (%d unread from others)",
+ "%s (%d unread from others)",
+ all_unread_msgs),
+ active_name, all_unread_msgs);
+ }
+
+ else {
+ /* unread messages are in all the tabs */
+ return g_strdup_printf (ngettext (
+ "%s (%d unread from all)",
+ "%s (%d unread from all)",
+ all_unread_msgs),
+ active_name, all_unread_msgs);
+ }
}
+}
+
+static void
+chat_window_title_update (EmpathyChatWindowPriv *priv)
+{
+ gchar *name;
+
+ DEBUG ("Update window : Title");
+
+ name = get_window_title_name (priv);
+ gtk_window_set_title (GTK_WINDOW (priv->dialog), name);
+ g_free (name);
+}
+
+static void
+chat_window_icon_update (EmpathyChatWindowPriv *priv)
+{
+ GdkPixbuf *icon;
+ EmpathyContact *remote_contact;
+ gboolean avatar_in_icon;
+ guint n_chats;
+
+ n_chats = g_list_length (priv->chats);
+
+ DEBUG ("Update window : Icon");
/* Update window icon */
if (priv->chats_new_msg) {
gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), NULL);
}
}
+}
+
+static void
+chat_window_close_button_update (EmpathyChatWindowPriv *priv,
+ gint num_pages)
+{
+ GtkWidget *chat;
+ GtkWidget *chat_close_button;
+ gint i;
+
+ DEBUG ("Update window : Close Button");
if (num_pages == 1) {
chat = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), 0);
}
}
+static void
+chat_window_update (EmpathyChatWindow *window)
+{
+ EmpathyChatWindowPriv *priv = GET_PRIV (window);
+ gint num_pages;
+
+ num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+
+ DEBUG ("Update window");
+
+ /* Update Tab menu */
+ chat_window_menu_context_update (priv,
+ num_pages);
+
+ chat_window_conversation_menu_update (priv, window);
+
+ chat_window_contact_menu_update (priv,
+ window);
+
+ chat_window_title_update (priv);
+
+ chat_window_icon_update (priv);
+
+ chat_window_close_button_update (priv,
+ num_pages);
+}
+
static void
append_markup_printf (GString *string,
const char *format,
EmpathyContact *remote_contact;
const gchar *name;
const gchar *id;
- EmpathyAccount *account;
+ TpAccount *account;
const gchar *subject;
const gchar *status = NULL;
GtkWidget *widget;
remote_contact = empathy_chat_get_remote_contact (chat);
DEBUG ("Updating chat tab, name=%s, account=%s, subject=%s, remote_contact=%p",
- name, empathy_account_get_unique_name (account), subject, remote_contact);
+ name, tp_proxy_get_object_path (account), subject, remote_contact);
/* Update tab image */
if (empathy_chat_get_tp_chat (chat) == NULL) {
append_markup_printf (tooltip,
"<b>%s</b><small> (%s)</small>",
id,
- empathy_account_get_display_name (account));
+ tp_account_get_display_name (account));
if (!EMP_STR_EMPTY (status)) {
append_markup_printf (tooltip, "\n<i>%s</i>", status);
chat);
}
- g_object_set_data (G_OBJECT (chat), "chat-window-remote-contact",
- remote_contact);
+ g_object_set_data_full (G_OBJECT (chat), "chat-window-remote-contact",
+ g_object_ref (remote_contact), (GDestroyNotify) g_object_unref);
}
chat_window_update_chat_tab (chat);
is_room = empathy_chat_is_room (priv->current_chat);
if (is_room) {
const gchar *room;
- EmpathyAccount *account;
+ TpAccount *account;
gboolean found = FALSE;
EmpathyChatroom *chatroom;
{
EmpathyChatWindowPriv *priv = GET_PRIV (window);
gboolean active;
- EmpathyAccount *account;
+ TpAccount *account;
const gchar *room;
EmpathyChatroom *chatroom;
empathy_chat_set_show_contacts (priv->current_chat, active);
}
-static const gchar *
-chat_get_window_id_for_geometry (EmpathyChat *chat)
+static void
+got_contact_cb (EmpathyTpContactFactory *factory,
+ EmpathyContact *contact,
+ const GError *error,
+ gpointer user_data,
+ GObject *object)
{
- const gchar *res = NULL;
- gboolean separate_windows;
+ EmpathyTpChat *tp_chat = EMPATHY_TP_CHAT (user_data);
- empathy_conf_get_bool (empathy_conf_get (),
- EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS,
- &separate_windows);
-
- if (separate_windows) {
- res = empathy_chat_get_id (chat);
+ 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"));
}
-
- return res ? res : "chat-window";
}
-static gboolean
-chat_window_save_geometry_timeout_cb (EmpathyChatWindow *window)
+static void
+chat_window_invite_participant_activate_cb (GtkAction *action,
+ EmpathyChatWindow *window)
{
EmpathyChatWindowPriv *priv;
- gint x, y, w, h;
+ GtkWidget *dialog;
+ EmpathyTpChat *tp_chat;
+ TpChannel *channel;
+ int response;
+ TpAccount *account;
priv = GET_PRIV (window);
- gtk_window_get_size (GTK_WINDOW (priv->dialog), &w, &h);
- gtk_window_get_position (GTK_WINDOW (priv->dialog), &x, &y);
+ g_return_if_fail (priv->current_chat != NULL);
- empathy_geometry_save (chat_get_window_id_for_geometry (priv->current_chat),
- x, y, w, h);
+ 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);
- priv->save_geometry_id = 0;
+ dialog = empathy_invite_participant_dialog_new (
+ GTK_WINDOW (priv->dialog), account);
+ gtk_widget_show (dialog);
- return FALSE;
-}
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
-static gboolean
-chat_window_configure_event_cb (GtkWidget *widget,
- GdkEventConfigure *event,
- EmpathyChatWindow *window)
-{
- EmpathyChatWindowPriv *priv;
+ if (response == GTK_RESPONSE_ACCEPT) {
+ TpConnection *connection;
+ EmpathyTpContactFactory *factory;
+ const char *id;
- priv = GET_PRIV (window);
+ id = empathy_contact_selector_dialog_get_selected (
+ EMPATHY_CONTACT_SELECTOR_DIALOG (dialog), NULL);
+ if (EMP_STR_EMPTY (id)) goto out;
- if (priv->save_geometry_id != 0) {
- g_source_remove (priv->save_geometry_id);
- }
+ connection = tp_channel_borrow_connection (channel);
+ factory = empathy_tp_contact_factory_dup_singleton (connection);
- priv->save_geometry_id =
- g_timeout_add_seconds (1,
- (GSourceFunc) chat_window_save_geometry_timeout_cb,
- window);
+ empathy_tp_contact_factory_get_from_id (factory, id,
+ got_contact_cb, tp_chat, NULL, NULL);
- return FALSE;
+ g_object_unref (factory);
+ }
+
+out:
+ gtk_widget_destroy (dialog);
}
static void
empathy_chat_paste (priv->current_chat);
}
+static void
+chat_window_find_activate_cb (GtkAction *action,
+ EmpathyChatWindow *window)
+{
+ EmpathyChatWindowPriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (window));
+
+ priv = GET_PRIV (window);
+
+ empathy_chat_find (priv->current_chat);
+}
+
+static void
+chat_window_tabs_next_activate_cb (GtkAction *action,
+ EmpathyChatWindow *window)
+{
+ EmpathyChatWindowPriv *priv;
+ EmpathyChat *chat;
+ gint index_, numPages;
+
+ priv = GET_PRIV (window);
+
+ chat = priv->current_chat;
+ index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+ numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+
+ if (index_ == (numPages - 1)) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), 0);
+ return;
+ }
+
+ gtk_notebook_next_page (GTK_NOTEBOOK (priv->notebook));
+}
+
+static void
+chat_window_tabs_previous_activate_cb (GtkAction *action,
+ EmpathyChatWindow *window)
+{
+ EmpathyChatWindowPriv *priv;
+ EmpathyChat *chat;
+ gint index_, numPages;
+
+ priv = GET_PRIV (window);
+
+ chat = priv->current_chat;
+ index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+ numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+
+ if (index_ <= 0) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), numPages - 1);
+ return;
+ }
+
+ gtk_notebook_prev_page (GTK_NOTEBOOK (priv->notebook));
+}
+
static void
chat_window_tabs_left_activate_cb (GtkAction *action,
EmpathyChatWindow *window)
EmpathyChatWindowPriv *priv = GET_PRIV (window);
gboolean res;
- if (!empathy_notification_is_enabled ()) {
+ if (!empathy_notify_manager_notification_is_enabled (priv->notify_mgr)) {
return;
} else {
empathy_conf_get_bool (empathy_conf_get (),
G_CALLBACK (chat_window_notification_closed_cb), cb_data);
}
- pixbuf = empathy_misc_get_pixbuf_for_notification (sender, EMPATHY_IMAGE_NEW_MESSAGE);
+ pixbuf = empathy_notify_manager_get_pixbuf_for_notification (priv->notify_mgr,
+ sender, EMPATHY_IMAGE_NEW_MESSAGE);
if (pixbuf != NULL) {
notify_notification_set_icon_from_pixbuf (priv->notification, pixbuf);
}
if (has_focus && priv->current_chat == chat) {
+ /* window and tab are focused so consider the message to be read */
+
+ /* FIXME: see Bug#610994 and coments about it in EmpathyChatPriv */
+ empathy_chat_messages_read (chat);
return;
}
EMPATHY_SOUND_MESSAGE_INCOMING);
chat_window_show_or_update_notification (window, message, chat);
}
+
+ /* update the number of unread messages */
+ chat_window_title_update (priv);
}
static GtkNotebook *
priv->current_chat = chat;
priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat);
+ empathy_chat_messages_read (chat);
chat_window_update_chat_tab (chat);
}
/* Keep list of chats up to date */
priv->chats = g_list_remove (priv->chats, chat);
priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat);
+ empathy_chat_messages_read (chat);
priv->chats_composing = g_list_remove (priv->chats_composing, chat);
if (priv->chats == NULL) {
priv = GET_PRIV (window);
priv->chats_new_msg = g_list_remove (priv->chats_new_msg, priv->current_chat);
+ empathy_chat_messages_read (priv->current_chat);
chat_window_set_urgency_hint (window, FALSE);
return FALSE;
}
+static gboolean
+chat_window_drag_drop (GtkWidget *widget,
+ GdkDragContext *context,
+ int x,
+ int y,
+ guint time_,
+ EmpathyChatWindow *window)
+{
+ GdkAtom target;
+ EmpathyChatWindowPriv *priv;
+
+ priv = GET_PRIV (window);
+
+ target = gtk_drag_dest_find_target (widget, context, priv->file_targets);
+ if (target == GDK_NONE)
+ target = gtk_drag_dest_find_target (widget, context, priv->contact_targets);
+
+ if (target != GDK_NONE) {
+ gtk_drag_get_data (widget, context, target, time_);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+chat_window_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ int x,
+ int y,
+ guint time_,
+ EmpathyChatWindow *window)
+{
+ GdkAtom target;
+ EmpathyChatWindowPriv *priv;
+
+ priv = GET_PRIV (window);
+
+ target = gtk_drag_dest_find_target (widget, context, priv->file_targets);
+ if (target != GDK_NONE) {
+ /* This is a file drag. Ensure the contact is online and set the
+ drag type to COPY. Note that it's possible that the tab will
+ be switched by GTK+ after a timeout from drag_motion without
+ getting another drag_motion to disable the drop. You have
+ to hold your mouse really still.
+ */
+ EmpathyContact *contact;
+
+ priv = GET_PRIV (window);
+ contact = empathy_chat_get_remote_contact (priv->current_chat);
+ /* contact is NULL for multi-user chats. We don't do
+ * file transfers to MUCs. We also don't send files
+ * to offline contacts or contacts that don't support
+ * file transfer.
+ */
+ if ((contact == NULL) || !empathy_contact_is_online (contact)) {
+ gdk_drag_status (context, 0, time_);
+ return FALSE;
+ }
+ if (!(empathy_contact_get_capabilities (contact)
+ & EMPATHY_CAPABILITIES_FT)) {
+ gdk_drag_status (context, 0, time_);
+ return FALSE;
+ }
+ gdk_drag_status (context, GDK_ACTION_COPY, time_);
+ return TRUE;
+ }
+
+ target = gtk_drag_dest_find_target (widget, context, priv->contact_targets);
+ if (target != GDK_NONE) {
+ /* This is a drag of a contact from a contact list. Set to COPY.
+ FIXME: If this drag is to a MUC window, it invites the user.
+ Otherwise, it opens a chat. Should we use a different drag
+ type for invites? Should we allow ASK?
+ */
+ gdk_drag_status (context, GDK_ACTION_COPY, time_);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static void
chat_window_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
if (info == DND_DRAG_TYPE_CONTACT_ID) {
EmpathyChat *chat = NULL;
EmpathyChatWindow *old_window;
- EmpathyAccount *account = NULL;
- EmpathyAccountManager *account_manager;
+ TpAccount *account = NULL;
+ TpAccountManager *account_manager;
const gchar *id;
gchar **strv;
const gchar *account_id;
const gchar *contact_id;
id = (const gchar*) gtk_selection_data_get_data (selection);
- account_manager = empathy_account_manager_dup_singleton ();
+
+ /* FIXME: Perhaps should be sure that the account manager is
+ * prepared before calling _ensure_account on it. */
+ account_manager = tp_account_manager_dup ();
DEBUG ("DND contact from roster with id:'%s'", id);
account_id = strv[0];
contact_id = strv[1];
account =
- empathy_account_manager_get_account (account_manager, account_id);
+ tp_account_manager_ensure_account (account_manager, account_id);
if (account != NULL)
chat = empathy_chat_window_find_chat (account, contact_id);
}
if (!chat) {
TpConnection *connection;
- connection = empathy_account_get_connection (account);
+ connection = tp_account_get_connection (account);
if (connection) {
empathy_dispatcher_chat_with_contact_id (
*/
gtk_drag_finish (context, TRUE, FALSE, time_);
}
+ else if (info == DND_DRAG_TYPE_URI_LIST) {
+ EmpathyChatWindowPriv *priv;
+ EmpathyContact *contact;
+ const gchar *data;
+
+ priv = GET_PRIV (window);
+ contact = empathy_chat_get_remote_contact (priv->current_chat);
+
+ /* contact is NULL when current_chat is a multi-user chat.
+ * We don't do file transfers to MUCs, so just cancel the drag.
+ */
+ if (contact == NULL) {
+ gtk_drag_finish (context, TRUE, FALSE, time_);
+ return;
+ }
+
+ data = (const gchar *) gtk_selection_data_get_data (selection);
+ empathy_send_file_from_uri_list (contact, data);
+
+ gtk_drag_finish (context, TRUE, FALSE, time_);
+ }
else if (info == DND_DRAG_TYPE_TAB) {
EmpathyChat **chat;
EmpathyChatWindow *old_window = NULL;
EmpathyChatWindowPriv *priv;
priv = GET_PRIV (window);
-
- if (old_window == window) {
- DEBUG ("DND tab (within same window)");
- priv->dnd_same_window = TRUE;
- gtk_drag_finish (context, TRUE, FALSE, time_);
- return;
- }
-
- priv->dnd_same_window = FALSE;
+ priv->dnd_same_window = (old_window == window);
+ DEBUG ("DND tab (within same window: %s)",
+ priv->dnd_same_window ? "Yes" : "No");
}
-
- /* 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 ().
- */
- gtk_drag_finish (context, TRUE, FALSE, time_);
} else {
DEBUG ("DND from unknown source");
gtk_drag_finish (context, FALSE, FALSE, time_);
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);
- }
+ g_object_unref (priv->notify_mgr);
if (priv->notification != NULL) {
notify_notification_close (priv->notification, NULL);
}
}
+ if (priv->contact_targets) {
+ gtk_target_list_unref (priv->contact_targets);
+ }
+ if (priv->file_targets) {
+ gtk_target_list_unref (priv->file_targets);
+ }
+
chat_windows = g_list_remove (chat_windows, window);
gtk_widget_destroy (priv->dialog);
"menu_edit_cut", &priv->menu_edit_cut,
"menu_edit_copy", &priv->menu_edit_copy,
"menu_edit_paste", &priv->menu_edit_paste,
+ "menu_edit_find", &priv->menu_edit_find,
"menu_tabs_next", &priv->menu_tabs_next,
"menu_tabs_prev", &priv->menu_tabs_prev,
"menu_tabs_left", &priv->menu_tabs_left,
g_free (filename);
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_invite_participant", "activate", chat_window_invite_participant_activate_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,
"menu_edit_copy", "activate", chat_window_copy_activate_cb,
"menu_edit_paste", "activate", chat_window_paste_activate_cb,
+ "menu_edit_find", "activate", chat_window_find_activate_cb,
+ "menu_tabs_next", "activate", chat_window_tabs_next_activate_cb,
+ "menu_tabs_prev", "activate", chat_window_tabs_previous_activate_cb,
"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,
g_object_unref (accel_group);
+ /* Set up drag target lists */
+ priv->contact_targets = gtk_target_list_new (drag_types_dest_contact,
+ G_N_ELEMENTS (drag_types_dest_contact));
+ priv->file_targets = gtk_target_list_new (drag_types_dest_file,
+ G_N_ELEMENTS (drag_types_dest_file));
+
/* Set up smiley menu */
smiley_manager = empathy_smiley_manager_dup_singleton ();
submenu = empathy_smiley_menu_new (smiley_manager,
"delete_event",
G_CALLBACK (chat_window_delete_event_cb),
window);
-
- g_signal_connect_swapped (priv->menu_tabs_prev,
- "activate",
- G_CALLBACK (gtk_notebook_prev_page),
- priv->notebook);
- g_signal_connect_swapped (priv->menu_tabs_next,
- "activate",
- G_CALLBACK (gtk_notebook_next_page),
- priv->notebook);
-
g_signal_connect (priv->dialog,
"focus_in_event",
G_CALLBACK (chat_window_focus_in_event_cb),
/* Set up drag and drop */
gtk_drag_dest_set (GTK_WIDGET (priv->notebook),
- GTK_DEST_DEFAULT_ALL,
+ GTK_DEST_DEFAULT_HIGHLIGHT,
drag_types_dest,
G_N_ELEMENTS (drag_types_dest),
- GDK_ACTION_MOVE);
+ GDK_ACTION_MOVE | GDK_ACTION_COPY);
+ /* connect_after to allow GtkNotebook's built-in tab switching */
+ g_signal_connect_after (priv->notebook,
+ "drag-motion",
+ G_CALLBACK (chat_window_drag_motion),
+ window);
g_signal_connect (priv->notebook,
"drag-data-received",
G_CALLBACK (chat_window_drag_data_received),
window);
+ g_signal_connect (priv->notebook,
+ "drag-drop",
+ G_CALLBACK (chat_window_drag_drop),
+ window);
chat_windows = g_list_prepend (chat_windows, window);
priv->chats_new_msg = NULL;
priv->chats_composing = NULL;
priv->current_chat = NULL;
+
+ priv->notify_mgr = empathy_notify_manager_dup_singleton ();
}
EmpathyChatWindow *
* be added.
*/
EmpathyChatWindow *
-empathy_chat_window_get_default (void)
+empathy_chat_window_get_default (gboolean room)
{
GList *l;
gboolean separate_windows = TRUE;
}
for (l = chat_windows; l; l = l->next) {
+ EmpathyChatWindowPriv *priv;
EmpathyChatWindow *chat_window;
GtkWidget *dialog;
chat_window = l->data;
+ priv = GET_PRIV (chat_window);
dialog = empathy_chat_window_get_dialog (chat_window);
if (empathy_window_get_is_visible (GTK_WINDOW (dialog))) {
+ guint nb_rooms, nb_private;
+ empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private);
+
+ /* Skip the window if there aren't any rooms in it */
+ if (room && nb_rooms == 0)
+ continue;
+
+ /* Skip the window if there aren't any 1-1 chats in it */
+ if (!room && nb_private == 0)
+ continue;
+
/* Found a visible window on this desktop */
return chat_window;
}
GtkWidget *label;
GtkWidget *popup_label;
GtkWidget *child;
- gint x, y, w, h;
+ GValue value = { 0, };
g_return_if_fail (window != NULL);
g_return_if_fail (EMPATHY_IS_CHAT (chat));
/* 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);
+ const gchar *name = "chat-window";
+ gboolean separate_windows;
- 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);
- }
+ empathy_conf_get_bool (empathy_conf_get (),
+ EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS,
+ &separate_windows);
- if (w > 0 && h > 0) {
- /* 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);
+ if (separate_windows) {
+ name = empathy_chat_get_id (chat);
+ }
+ else if (empathy_chat_is_room (chat)) {
+ name = "room-window";
}
+
+ empathy_geometry_bind (GTK_WINDOW (priv->dialog), name);
}
child = GTK_WIDGET (chat);
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);
+ g_value_init (&value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&value, TRUE);
+ gtk_container_child_set_property (GTK_CONTAINER (priv->notebook),
+ child, "tab-expand" , &value);
+ gtk_container_child_set_property (GTK_CONTAINER (priv->notebook),
+ child, "tab-fill" , &value);
+ g_value_unset (&value);
DEBUG ("Chat added (%d references)", G_OBJECT (chat)->ref_count);
}
}
EmpathyChat *
-empathy_chat_window_find_chat (EmpathyAccount *account,
+empathy_chat_window_find_chat (TpAccount *account,
const gchar *id)
{
GList *l;
/* If the chat has no window, create one */
if (window == NULL) {
- window = empathy_chat_window_get_default ();
+ window = empathy_chat_window_get_default (empathy_chat_is_room (chat));
if (!window) {
window = empathy_chat_window_new ();
}
priv = GET_PRIV (window);
empathy_chat_window_switch_to_chat (window, chat);
- empathy_window_present (GTK_WINDOW (priv->dialog), TRUE);
+ empathy_window_present (GTK_WINDOW (priv->dialog));
gtk_widget_grab_focus (chat->input_text_view);
}
+void
+empathy_chat_window_get_nb_chats (EmpathyChatWindow *self,
+ guint *nb_rooms,
+ guint *nb_private)
+{
+ EmpathyChatWindowPriv *priv = GET_PRIV (self);
+ GList *l;
+ guint _nb_rooms = 0, _nb_private = 0;
+
+ for (l = priv->chats; l != NULL; l = g_list_next (l)) {
+ if (empathy_chat_is_room (EMPATHY_CHAT (l->data)))
+ _nb_rooms++;
+ else
+ _nb_private++;
+ }
+
+ if (nb_rooms != NULL)
+ *nb_rooms = _nb_rooms;
+ if (nb_private != NULL)
+ *nb_private = _nb_private;
+}