aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy-gtk
diff options
context:
space:
mode:
Diffstat (limited to 'libempathy-gtk')
-rw-r--r--libempathy-gtk/empathy-cell-renderer-text.c4
-rw-r--r--libempathy-gtk/empathy-chat.c227
-rw-r--r--libempathy-gtk/empathy-individual-widget.c4
-rw-r--r--libempathy-gtk/empathy-irc-network-chooser-dialog.c66
-rw-r--r--libempathy-gtk/empathy-irc-network-dialog.c15
-rw-r--r--libempathy-gtk/empathy-notify-manager.c16
-rw-r--r--libempathy-gtk/empathy-notify-manager.h8
-rw-r--r--libempathy-gtk/empathy-roster-contact.c42
-rw-r--r--libempathy-gtk/empathy-theme-adium.c288
-rw-r--r--libempathy-gtk/empathy-theme-adium.h4
-rw-r--r--libempathy-gtk/empathy-webkit-utils.c78
-rw-r--r--libempathy-gtk/empathy-webkit-utils.h17
12 files changed, 564 insertions, 205 deletions
diff --git a/libempathy-gtk/empathy-cell-renderer-text.c b/libempathy-gtk/empathy-cell-renderer-text.c
index d52abb485..d96ccc403 100644
--- a/libempathy-gtk/empathy-cell-renderer-text.c
+++ b/libempathy-gtk/empathy-cell-renderer-text.c
@@ -364,8 +364,8 @@ cell_renderer_text_update_text (EmpathyCellRendererText *cell,
status = empathy_presence_get_default_message (priv->presence_type);
}
- if (!priv->is_group && priv->types != NULL && g_strv_length (priv->types) > 0
- && !tp_strdiff (priv->types[0], "phone")) {
+ if (!priv->is_group &&
+ empathy_client_types_contains_mobile_device (priv->types)) {
on_a_phone = TRUE;
/* We want the phone black. */
if (attr_color)
diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c
index 9a12d1f09..1c0e11a3a 100644
--- a/libempathy-gtk/empathy-chat.c
+++ b/libempathy-gtk/empathy-chat.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2002-2007 Imendio AB
* Copyright (C) 2007-2010 Collabora Ltd.
+ * Copyright (C) 2012 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -80,6 +81,17 @@ struct _EmpathyChatPriv {
GSettings *gsettings_ui;
TplLogManager *log_manager;
+ TplLogWalker *log_walker;
+ /* Are we watching for scrolling movements? */
+ gboolean watch_scroll;
+ /* Maximum page size of the chat->view. */
+ guint max_page_size;
+ /* The offset from the lower edge of the chat->view before it
+ * expanded to fit in the newly fetched logs. This is to
+ * restore the chat->view to the page it was on before the
+ * latest batch of logs were inserted. */
+ guint scroll_offset;
+
TpAccountManager *account_manager;
GList *input_history;
GList *input_history_current;
@@ -197,6 +209,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (EmpathyChat, empathy_chat, GTK_TYPE_BOX);
+static gboolean chat_scrollable_connect (gpointer user_data);
static gboolean update_misspelled_words (gpointer data);
static void
@@ -2494,21 +2507,15 @@ static gboolean
chat_log_filter (TplEvent *event,
gpointer user_data)
{
- TpWeakRef *wr = user_data;
- EmpathyChat *chat = tp_weak_ref_dup_object (wr);
+ EmpathyChat *chat = EMPATHY_CHAT (user_data);
+ EmpathyChatPriv *priv = GET_PRIV (chat);
EmpathyMessage *message;
- EmpathyChatPriv *priv;
const GList *pending;
bool retval = FALSE;
- if (chat == NULL)
- return FALSE;
-
g_return_val_if_fail (TPL_IS_EVENT (event), FALSE);
g_return_val_if_fail (EMPATHY_IS_CHAT (chat), FALSE);
- priv = GET_PRIV (chat);
-
pending = empathy_tp_chat_get_pending_messages (priv->tp_chat);
message = empathy_message_from_tpl_log_event (event);
@@ -2521,7 +2528,6 @@ chat_log_filter (TplEvent *event,
out:
g_object_unref (message);
- g_object_unref (chat);
return retval;
}
@@ -2548,26 +2554,38 @@ show_pending_messages (EmpathyChat *chat) {
}
+static gboolean
+chat_scrollable_set_value (gpointer user_data)
+{
+ EmpathyChat *chat = EMPATHY_CHAT (user_data);
+ EmpathyChatPriv *priv = GET_PRIV (chat);
+ GtkAdjustment *adjustment;
+ guint upper;
+
+ adjustment = gtk_scrollable_get_vadjustment (
+ GTK_SCROLLABLE (chat->view));
+
+ /* Set the chat->view's adjustment back to the value it had
+ * before it grew as a result of new logs being inserted.
+ */
+ upper = (guint) gtk_adjustment_get_upper (adjustment);
+ gtk_adjustment_set_value (adjustment, upper - priv->scroll_offset);
+
+ return G_SOURCE_REMOVE;
+}
+
static void
-got_filtered_messages_cb (GObject *manager,
+got_filtered_messages_cb (GObject *walker,
GAsyncResult *result,
gpointer user_data)
{
GList *l;
GList *messages;
- TpWeakRef *wr = user_data;
- EmpathyChat *chat = tp_weak_ref_dup_object (wr);
- EmpathyChatPriv *priv;
+ EmpathyChat *chat = EMPATHY_CHAT (user_data);
+ EmpathyChatPriv *priv = GET_PRIV (chat);
GError *error = NULL;
- if (chat == NULL) {
- tp_weak_ref_destroy (wr);
- return;
- }
-
- priv = GET_PRIV (chat);
-
- if (!tpl_log_manager_get_filtered_events_finish (TPL_LOG_MANAGER (manager),
+ if (!tpl_log_walker_get_events_finish (TPL_LOG_WALKER (walker),
result, &messages, &error)) {
DEBUG ("%s. Aborting.", error->message);
empathy_theme_adium_append_event (chat->view,
@@ -2576,7 +2594,7 @@ got_filtered_messages_cb (GObject *manager,
goto out;
}
- for (l = messages; l; l = g_list_next (l)) {
+ for (l = g_list_last (messages); l; l = g_list_previous (l)) {
EmpathyMessage *message;
g_assert (TPL_IS_EVENT (l->data));
@@ -2601,14 +2619,14 @@ got_filtered_messages_cb (GObject *manager,
"sender", empathy_message_get_sender (message),
NULL);
- empathy_theme_adium_append_message (chat->view, syn_msg,
+ empathy_theme_adium_prepend_message (chat->view, syn_msg,
chat_should_highlight (chat, syn_msg));
empathy_theme_adium_edit_message (chat->view, message);
g_object_unref (syn_msg);
} else {
/* append the latest message */
- empathy_theme_adium_append_message (chat->view, message,
+ empathy_theme_adium_prepend_message (chat->view, message,
chat_should_highlight (chat, message));
}
@@ -2617,10 +2635,6 @@ got_filtered_messages_cb (GObject *manager,
g_list_free (messages);
out:
- /* in case of TPL error, skip backlog and show pending messages */
- priv->can_show_pending = TRUE;
- show_pending_messages (chat);
-
/* FIXME: See Bug#610994, we are forcing the ACK of the queue. See comments
* about it in EmpathyChatPriv definition */
priv->retrieving_backlogs = FALSE;
@@ -2629,43 +2643,146 @@ out:
/* Turn back on scrolling */
empathy_theme_adium_scroll (chat->view, TRUE);
+ /* We start watching the scrolling movements only after the first
+ * batch of logs have been fetched. Otherwise, if the
+ * chat->view's page size is too small the scrollbar might hit
+ * the upper edge and trigger another batch of logs to be
+ * fetched.
+ */
+ if (G_UNLIKELY (!priv->watch_scroll &&
+ !tpl_log_walker_is_end (priv->log_walker))) {
+ /* The pending messages need not be shown after the
+ * first batch of logs have been displayed */
+ priv->can_show_pending = TRUE;
+ show_pending_messages (chat);
+
+ priv->watch_scroll = TRUE;
+ g_idle_add_full (G_PRIORITY_LOW, chat_scrollable_connect,
+ g_object_ref (chat), g_object_unref);
+ }
+ else {
+ GtkAdjustment *adjustment;
+ guint upper;
+ guint value;
+
+ /* The chat->view's adjustment won't change unless we
+ * return to the main loop. Save the current offset
+ * from the lower edge (or the upper value of the
+ * adjustment) so that we can restore it later once the
+ * adjustment grows.
+ */
+ adjustment = gtk_scrollable_get_vadjustment (
+ GTK_SCROLLABLE (chat->view));
+ upper = (guint) gtk_adjustment_get_upper (adjustment);
+ value = (guint) gtk_adjustment_get_value (adjustment);
+ priv->scroll_offset = upper - value;
+
+ g_idle_add_full (G_PRIORITY_LOW, chat_scrollable_set_value,
+ g_object_ref (chat), g_object_unref);
+ }
+
g_object_unref (chat);
- tp_weak_ref_destroy (wr);
}
-static void
+static gboolean
chat_add_logs (EmpathyChat *chat)
{
EmpathyChatPriv *priv = GET_PRIV (chat);
- TplEntity *target;
- TpWeakRef *wr;
if (!priv->id) {
- return;
+ return G_SOURCE_REMOVE;
}
/* Turn off scrolling temporarily */
empathy_theme_adium_scroll (chat->view, FALSE);
- /* Add messages from last conversation */
- if (priv->handle_type == TP_HANDLE_TYPE_ROOM)
- target = tpl_entity_new_from_room_id (priv->id);
- else
- target = tpl_entity_new (priv->id, TPL_ENTITY_CONTACT, NULL, NULL);
+ tpl_log_walker_get_events_async (priv->log_walker, 5,
+ got_filtered_messages_cb, g_object_ref (chat));
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+chat_schedule_logs (EmpathyChat *chat)
+{
+ EmpathyChatPriv *priv = GET_PRIV (chat);
+
+ if (priv->retrieving_backlogs)
+ return;
priv->retrieving_backlogs = TRUE;
- wr = tp_weak_ref_new (chat, NULL, NULL);
- tpl_log_manager_get_filtered_events_async (priv->log_manager,
- priv->account,
- target,
- TPL_EVENT_MASK_TEXT,
- 5,
- chat_log_filter,
- wr,
- got_filtered_messages_cb,
- wr);
+ g_timeout_add_full (G_PRIORITY_LOW, 500, /* ms */
+ (GSourceFunc) chat_add_logs, g_object_ref (chat), g_object_unref);
+}
- g_object_unref (target);
+static void
+chat_view_adjustment_changed_cb (GtkAdjustment *adjustment,
+ gpointer user_data)
+{
+ EmpathyChat *chat = EMPATHY_CHAT (user_data);
+ EmpathyChatPriv *priv = GET_PRIV (chat);
+ guint page_size;
+
+ if (tpl_log_walker_is_end (priv->log_walker)) {
+ g_signal_handlers_disconnect_by_func (adjustment,
+ chat_view_adjustment_changed_cb, user_data);
+ return;
+ }
+
+ page_size = (guint) gtk_adjustment_get_page_size (adjustment);
+ if (page_size <= priv->max_page_size)
+ return;
+
+ /* We need to fetch more logs if the page size of the view
+ * increases, so that there is no empty space at the top.
+ */
+ if (G_LIKELY (priv->max_page_size != 0))
+ chat_schedule_logs (chat);
+
+ priv->max_page_size = page_size;
+}
+
+static void
+chat_view_adjustment_value_changed_cb (GtkAdjustment *adjustment,
+ gpointer user_data)
+{
+ EmpathyChat *chat = EMPATHY_CHAT (user_data);
+ EmpathyChatPriv *priv = GET_PRIV (chat);
+ guint lower;
+ guint value;
+
+ if (tpl_log_walker_is_end (priv->log_walker)) {
+ g_signal_handlers_disconnect_by_func (adjustment,
+ chat_view_adjustment_value_changed_cb, user_data);
+ return;
+ }
+
+ lower = (guint) gtk_adjustment_get_lower (adjustment);
+ value = (guint) gtk_adjustment_get_value (adjustment);
+ if (value != lower)
+ return;
+
+ /* Request for more logs to be fetched if the user hit the
+ * upper edge of the chat->view.
+ */
+ chat_schedule_logs (chat);
+}
+
+static gboolean
+chat_scrollable_connect (gpointer user_data)
+{
+ EmpathyChat *chat = EMPATHY_CHAT (user_data);
+ GtkAdjustment *adjustment;
+
+ adjustment = gtk_scrollable_get_vadjustment (
+ GTK_SCROLLABLE (chat->view));
+
+ g_signal_connect (adjustment, "changed",
+ G_CALLBACK (chat_view_adjustment_changed_cb), chat);
+ g_signal_connect (adjustment, "value-changed",
+ G_CALLBACK (chat_view_adjustment_value_changed_cb), chat);
+
+ return G_SOURCE_REMOVE;
}
static gint
@@ -3278,6 +3395,7 @@ chat_finalize (GObject *object)
g_object_unref (priv->account_manager);
g_object_unref (priv->log_manager);
+ g_object_unref (priv->log_walker);
if (priv->tp_chat) {
g_signal_handlers_disconnect_by_func (priv->tp_chat,
@@ -3335,6 +3453,7 @@ chat_constructed (GObject *object)
{
EmpathyChat *chat = EMPATHY_CHAT (object);
EmpathyChatPriv *priv = GET_PRIV (chat);
+ TplEntity *target;
if (priv->tp_chat != NULL) {
TpChannel *channel = TP_CHANNEL (priv->tp_chat);
@@ -3347,6 +3466,16 @@ chat_constructed (GObject *object)
supports_avatars);
}
+ /* Add messages from last conversation */
+ if (priv->handle_type == TP_HANDLE_TYPE_ROOM)
+ target = tpl_entity_new_from_room_id (priv->id);
+ else
+ target = tpl_entity_new (priv->id, TPL_ENTITY_CONTACT, NULL, NULL);
+
+ priv->log_walker = tpl_log_manager_walk_filtered_events (priv->log_manager, priv->account, target,
+ TPL_EVENT_MASK_TEXT, chat_log_filter, chat);
+ g_object_unref (target);
+
if (priv->handle_type != TP_HANDLE_TYPE_ROOM) {
/* First display logs from the logger and then display pending messages */
chat_add_logs (chat);
diff --git a/libempathy-gtk/empathy-individual-widget.c b/libempathy-gtk/empathy-individual-widget.c
index 735397456..4dab7390c 100644
--- a/libempathy-gtk/empathy-individual-widget.c
+++ b/libempathy-gtk/empathy-individual-widget.c
@@ -808,9 +808,7 @@ client_types_update (EmpathyIndividualWidget *self)
types = tp_contact_get_client_types (priv->contact);
- if (types != NULL
- && g_strv_length ((gchar **) types) > 0
- && !tp_strdiff (types[0], "phone"))
+ if (empathy_client_types_contains_mobile_device ((GStrv) types))
{
gtk_widget_show (priv->hbox_client_types);
}
diff --git a/libempathy-gtk/empathy-irc-network-chooser-dialog.c b/libempathy-gtk/empathy-irc-network-chooser-dialog.c
index 755eb584e..5e4cb3583 100644
--- a/libempathy-gtk/empathy-irc-network-chooser-dialog.c
+++ b/libempathy-gtk/empathy-irc-network-chooser-dialog.c
@@ -303,7 +303,7 @@ display_irc_network_dialog (EmpathyIrcNetworkChooserDialog *self,
{
GtkWidget *dialog;
- dialog = empathy_irc_network_dialog_show (network, NULL);
+ dialog = empathy_irc_network_dialog_show (network, GTK_WIDGET (self));
g_signal_connect (dialog, "destroy",
G_CALLBACK (irc_network_dialog_destroy_cb), self);
@@ -427,13 +427,7 @@ dialog_response_cb (GtkDialog *dialog,
gint response,
EmpathyIrcNetworkChooserDialog *self)
{
- if (response == GTK_RESPONSE_OK)
- add_network (self);
- else if (response == GTK_RESPONSE_APPLY)
- edit_network (self);
- else if (response == GTK_RESPONSE_REJECT)
- remove_network (self);
- else if (response == RESPONSE_RESET)
+ if (response == RESPONSE_RESET)
reset_networks (self);
}
@@ -515,6 +509,27 @@ dialog_destroy_cb (GtkWidget *widget,
}
static void
+add_clicked_cb (GtkToolButton *button,
+ EmpathyIrcNetworkChooserDialog *self)
+{
+ add_network (self);
+}
+
+static void
+remove_clicked_cb (GtkToolButton *button,
+ EmpathyIrcNetworkChooserDialog *self)
+{
+ remove_network (self);
+}
+
+static void
+edit_clicked_cb (GtkToolButton *button,
+ EmpathyIrcNetworkChooserDialog *self)
+{
+ edit_network (self);
+}
+
+static void
empathy_irc_network_chooser_dialog_constructed (GObject *object)
{
EmpathyIrcNetworkChooserDialog *self = (EmpathyIrcNetworkChooserDialog *) object;
@@ -524,6 +539,9 @@ empathy_irc_network_chooser_dialog_constructed (GObject *object)
GtkWidget *vbox;
GtkTreeViewColumn *column;
GtkWidget *scroll;
+ GtkWidget *toolbar;
+ GtkToolItem *item;
+ GtkStyleContext *context;
g_assert (priv->settings != NULL);
@@ -560,6 +578,35 @@ empathy_irc_network_chooser_dialog_constructed (GObject *object)
gtk_container_add (GTK_CONTAINER (scroll), priv->treeview);
gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 6);
+ /* Treeview toolbar */
+ toolbar = gtk_toolbar_new ();
+ gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU);
+ gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, TRUE, 0);
+
+ item = gtk_tool_button_new (NULL, "");
+ gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "list-add-symbolic");
+ g_signal_connect (item, "clicked", G_CALLBACK (add_clicked_cb), self);
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+
+ item = gtk_tool_button_new (NULL, "");
+ gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item),
+ "list-remove-symbolic");
+ g_signal_connect (item, "clicked", G_CALLBACK (remove_clicked_cb), self);
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+
+ item = gtk_tool_button_new (NULL, "");
+ gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item),
+ "preferences-system-symbolic");
+ g_signal_connect (item, "clicked", G_CALLBACK (edit_clicked_cb), self);
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+
+ context = gtk_widget_get_style_context (scroll);
+ gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
+
+ context = gtk_widget_get_style_context (toolbar);
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_INLINE_TOOLBAR);
+ gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
+
/* Live search */
priv->search = empathy_live_search_new (priv->treeview);
@@ -581,9 +628,6 @@ empathy_irc_network_chooser_dialog_constructed (GObject *object)
/* Add buttons */
gtk_dialog_add_buttons (dialog,
- GTK_STOCK_ADD, GTK_RESPONSE_OK,
- GTK_STOCK_EDIT, GTK_RESPONSE_APPLY,
- GTK_STOCK_REMOVE, GTK_RESPONSE_REJECT,
_("Reset _Networks List"), RESPONSE_RESET,
NULL);
diff --git a/libempathy-gtk/empathy-irc-network-dialog.c b/libempathy-gtk/empathy-irc-network-dialog.c
index 8164f6c74..65f0a41bb 100644
--- a/libempathy-gtk/empathy-irc-network-dialog.c
+++ b/libempathy-gtk/empathy-irc-network-dialog.c
@@ -512,6 +512,8 @@ empathy_irc_network_dialog_show (EmpathyIrcNetwork *network,
NULL);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_servers),
0);
+
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_column_set_expand (column, TRUE);
/* port */
@@ -524,11 +526,17 @@ empathy_irc_network_dialog_show (EmpathyIrcNetwork *network,
NULL);
g_signal_connect (renderer, "edited",
G_CALLBACK (irc_network_dialog_port_edited_cb), dialog);
+
gtk_tree_view_insert_column_with_attributes (
GTK_TREE_VIEW (dialog->treeview_servers),
-1, _("Port"), renderer, "text", COL_PORT,
NULL);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_servers),
+ 1);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_expand (column, TRUE);
+
/* SSL */
renderer = gtk_cell_renderer_toggle_new ();
g_object_set (renderer, "activatable", TRUE, NULL);
@@ -543,6 +551,11 @@ empathy_irc_network_dialog_show (EmpathyIrcNetwork *network,
GTK_TREE_VIEW (dialog->treeview_servers));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_servers),
+ 2);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+
+ gtk_tree_view_column_set_expand (column, TRUE);
/* charset */
totem_subtitle_encoding_init (GTK_COMBO_BOX (dialog->combobox_charset));
@@ -582,5 +595,7 @@ empathy_irc_network_dialog_show (EmpathyIrcNetwork *network,
irc_network_dialog_network_update_buttons (dialog);
gtk_widget_show_all (dialog->dialog);
+ gtk_window_set_resizable (GTK_WINDOW (dialog->dialog), FALSE);
+
return dialog->dialog;
}
diff --git a/libempathy-gtk/empathy-notify-manager.c b/libempathy-gtk/empathy-notify-manager.c
index 250354282..b37c1f59a 100644
--- a/libempathy-gtk/empathy-notify-manager.c
+++ b/libempathy-gtk/empathy-notify-manager.c
@@ -216,3 +216,19 @@ empathy_notify_manager_notification_is_enabled (EmpathyNotifyManager *self)
return TRUE;
}
+
+NotifyNotification *
+empathy_notify_manager_create_notification (const gchar *summary,
+ const char *body,
+ const gchar *icon)
+{
+ NotifyNotification *notification;
+
+ notification = notify_notification_new (summary, body, icon);
+
+ notify_notification_set_hint (notification,
+ EMPATHY_NOTIFY_MANAGER_CAP_DESKTOP_ENTRY,
+ g_variant_new_string ("empathy"));
+
+ return notification;
+}
diff --git a/libempathy-gtk/empathy-notify-manager.h b/libempathy-gtk/empathy-notify-manager.h
index 0b937e1d5..923ab4a54 100644
--- a/libempathy-gtk/empathy-notify-manager.h
+++ b/libempathy-gtk/empathy-notify-manager.h
@@ -25,6 +25,8 @@
#include <libempathy/empathy-contact.h>
+#include <libnotify/notification.h>
+
G_BEGIN_DECLS
#define EMPATHY_NOTIFY_MANAGER_CAP_ACTIONS "actions"
@@ -37,6 +39,7 @@ G_BEGIN_DECLS
#define EMPATHY_NOTIFY_MANAGER_CAP_ICON_STATIC "icon-static"
#define EMPATHY_NOTIFY_MANAGER_CAP_IMAGE_SVG_XML "image/svg+xml"
#define EMPATHY_NOTIFY_MANAGER_CAP_SOUND "sound"
+#define EMPATHY_NOTIFY_MANAGER_CAP_DESKTOP_ENTRY "desktop-entry"
/* notify-osd specific */
#define EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND "x-canonical-append"
#define EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_PRIVATE_ICON_ONLY "x-canonical-private-icon-only"
@@ -104,6 +107,11 @@ GdkPixbuf * empathy_notify_manager_get_pixbuf_for_notification (
EmpathyContact *contact,
const char *icon_name);
+NotifyNotification * empathy_notify_manager_create_notification (
+ const gchar *summary,
+ const char *body,
+ const gchar *icon);
+
G_END_DECLS
#endif /* __EMPATHY_NOTIFY_MANAGER_H__ */
diff --git a/libempathy-gtk/empathy-roster-contact.c b/libempathy-gtk/empathy-roster-contact.c
index e72ae4494..7ab808746 100644
--- a/libempathy-gtk/empathy-roster-contact.c
+++ b/libempathy-gtk/empathy-roster-contact.c
@@ -1,5 +1,7 @@
#include "config.h"
+#include <glib/gi18n-lib.h>
+
#include "empathy-roster-contact.h"
#include <telepathy-glib/telepathy-glib.h>
@@ -171,25 +173,11 @@ alias_changed_cb (FolksIndividual *individual,
update_alias (self);
}
-static gboolean
-is_phone (FolksIndividual *individual)
-{
- const gchar * const *types;
-
- types = empathy_individual_get_client_types (individual);
- if (types == NULL)
- return FALSE;
-
- if (g_strv_length ((GStrv) types) <= 0)
- return FALSE;
-
- return !tp_strdiff (types[0], "phone");
-}
-
static void
update_presence_msg (EmpathyRosterContact *self)
{
const gchar *msg;
+ GStrv types;
msg = folks_presence_details_get_presence_message (
FOLKS_PRESENCE_DETAILS (self->priv->individual));
@@ -204,7 +192,25 @@ update_presence_msg (EmpathyRosterContact *self)
}
else
{
- gtk_label_set_text (GTK_LABEL (self->priv->presence_msg), msg);
+ FolksPresenceType type;
+
+ type = folks_presence_details_get_presence_type (
+ FOLKS_PRESENCE_DETAILS (self->priv->individual));
+ if (type == FOLKS_PRESENCE_TYPE_ERROR)
+ {
+ gchar *tmp;
+
+ /* Add a prefix explaining that something goes wrong when trying to
+ * fetch contact's presence. */
+ tmp = g_strdup_printf (_("Server cannot find contact: %s"), msg);
+ gtk_label_set_text (GTK_LABEL (self->priv->presence_msg), tmp);
+
+ g_free (tmp);
+ }
+ else
+ {
+ gtk_label_set_text (GTK_LABEL (self->priv->presence_msg), msg);
+ }
gtk_alignment_set (GTK_ALIGNMENT (self->priv->first_line_alig),
0, 0.75, 1, 1);
@@ -213,8 +219,10 @@ update_presence_msg (EmpathyRosterContact *self)
gtk_widget_show (self->priv->presence_msg);
}
+ types = (GStrv) empathy_individual_get_client_types (self->priv->individual);
+
gtk_widget_set_visible (self->priv->phone_icon,
- is_phone (self->priv->individual));
+ empathy_client_types_contains_mobile_device (types));
}
static void
diff --git a/libempathy-gtk/empathy-theme-adium.c b/libempathy-gtk/empathy-theme-adium.c
index 37c8698e4..d304c5e19 100644
--- a/libempathy-gtk/empathy-theme-adium.c
+++ b/libempathy-gtk/empathy-theme-adium.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008-2012 Collabora Ltd.
+ * Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -52,8 +53,11 @@ struct _EmpathyThemeAdiumPriv
{
EmpathyAdiumData *data;
EmpathySmileyManager *smiley_manager;
+ EmpathyContact *first_contact;
EmpathyContact *last_contact;
+ gint64 first_timestamp;
gint64 last_timestamp;
+ gboolean first_is_backlog;
gboolean last_is_backlog;
guint pages_loading;
/* Queue of QueuedItem*s containing an EmpathyMessage or string */
@@ -140,7 +144,8 @@ queue_item (GQueue *queue,
guint type,
EmpathyMessage *msg,
const char *str,
- gboolean should_highlight)
+ gboolean should_highlight,
+ gboolean prepend)
{
QueuedItem *item = g_slice_new0 (QueuedItem);
@@ -150,7 +155,10 @@ queue_item (GQueue *queue,
item->str = g_strdup (str);
item->should_highlight = should_highlight;
- g_queue_push_tail (queue, item);
+ if (prepend)
+ g_queue_push_head (queue, item);
+ else
+ g_queue_push_tail (queue, item);
return item;
}
@@ -164,30 +172,6 @@ free_queued_item (QueuedItem *item)
g_slice_free (QueuedItem, item);
}
-static void
-theme_adium_update_enable_webkit_developer_tools (EmpathyThemeAdium *self)
-{
- WebKitWebView *web_view = WEBKIT_WEB_VIEW (self);
- gboolean enable_webkit_developer_tools;
-
- enable_webkit_developer_tools = g_settings_get_boolean (
- self->priv->gsettings_chat,
- EMPATHY_PREFS_CHAT_WEBKIT_DEVELOPER_TOOLS);
-
- g_object_set (G_OBJECT (webkit_web_view_get_settings (web_view)),
- "enable-developer-extras", enable_webkit_developer_tools, NULL);
-}
-
-static void
-theme_adium_notify_enable_webkit_developer_tools_cb (GSettings *gsettings,
- const gchar *key,
- gpointer user_data)
-{
- EmpathyThemeAdium *self = user_data;
-
- theme_adium_update_enable_webkit_developer_tools (self);
-}
-
static gboolean
theme_adium_navigation_policy_decision_requested_cb (WebKitWebView *view,
WebKitWebFrame *web_frame,
@@ -542,9 +526,8 @@ nsdate_to_strftime (EmpathyAdiumData *data, const gchar *nsdate)
return g_string_free (string, FALSE);
}
-
static void
-theme_adium_append_html (EmpathyThemeAdium *self,
+theme_adium_add_html (EmpathyThemeAdium *self,
const gchar *func,
const gchar *html,
const gchar *message,
@@ -555,10 +538,13 @@ theme_adium_append_html (EmpathyThemeAdium *self,
const gchar *message_classes,
gint64 timestamp,
gboolean is_backlog,
- gboolean outgoing)
+ gboolean outgoing,
+ PangoDirection direction)
{
+ GBytes *bytes;
GString *string;
const gchar *cur = NULL;
+ const gchar *js;
gchar *script;
/* Make some search-and-replace in the html code */
@@ -614,9 +600,22 @@ theme_adium_append_html (EmpathyThemeAdium *self,
}
else if (theme_adium_match (&cur, "%messageDirection%"))
{
- /* FIXME: The text direction of the message
- * (either rtl or ltr)
- */
+ switch (direction)
+ {
+ case PANGO_DIRECTION_LTR:
+ case PANGO_DIRECTION_TTB_LTR:
+ case PANGO_DIRECTION_WEAK_LTR:
+ replace = "ltr";
+ break;
+ case PANGO_DIRECTION_RTL:
+ case PANGO_DIRECTION_TTB_RTL:
+ case PANGO_DIRECTION_WEAK_RTL:
+ replace = "rtl";
+ break;
+ case PANGO_DIRECTION_NEUTRAL:
+ default:
+ break;
+ }
}
else if (theme_adium_match (&cur, "%senderDisplayName%"))
{
@@ -735,6 +734,13 @@ theme_adium_append_html (EmpathyThemeAdium *self,
}
g_string_append (string, "\")");
+ bytes = g_resources_lookup_data ("/org/gnome/Empathy/Chat/empathy-chat.js",
+ G_RESOURCE_LOOKUP_FLAGS_NONE,
+ NULL);
+ js = (const gchar *) g_bytes_get_data (bytes, NULL);
+ g_string_prepend (string, js);
+ g_bytes_unref (bytes);
+
script = g_string_free (string, FALSE);
webkit_web_view_execute_script (WEBKIT_WEB_VIEW (self), script);
g_free (script);
@@ -742,11 +748,12 @@ theme_adium_append_html (EmpathyThemeAdium *self,
static void
theme_adium_append_event_escaped (EmpathyThemeAdium *self,
- const gchar *escaped)
+ const gchar *escaped,
+ PangoDirection direction)
{
- theme_adium_append_html (self, "appendMessage",
+ theme_adium_add_html (self, "appendMessage",
self->priv->data->status_html, escaped, NULL, NULL, NULL,
- NULL, "event", empathy_time_get_current (), FALSE, FALSE);
+ NULL, "event", empathy_time_get_current (), FALSE, FALSE, direction);
/* There is no last contact */
if (self->priv->last_contact)
@@ -830,10 +837,55 @@ theme_adium_remove_all_focus_marks (EmpathyThemeAdium *self)
theme_adium_remove_focus_marks (self, nodes);
}
-void
-empathy_theme_adium_append_message (EmpathyThemeAdium *self,
+enum
+{
+ ADD_CONSECUTIVE_MSG_SCROLL = 0,
+ ADD_CONSECUTIVE_MSG_NO_SCROLL = 1,
+ ADD_MSG_SCROLL = 2,
+ ADD_MSG_NO_SCROLL = 3
+};
+
+/*
+ * theme_adium_add_message:
+ * @self: The #EmpathyThemeAdium used by the view.
+ * @msg: An #EmpathyMessage that is to be added to the view.
+ * @prev_contact: (out): The #EmpathyContact that sent the previous message.
+ * @prev_timestamp: (out): Timestamp of the previous message.
+ * @prev_is_backlog: (out): Whether the previous message was fetched
+ * from the logs.
+ * @should_highlight: Whether the message should be highlighted. eg.,
+ * if it matches the user's username in multi-user chat.
+ * @js_funcs: An array of JavaScript function names
+ *
+ * Shows @msg in the chat view by adding to @self. Addition is defined
+ * by the JavaScript functions listed in @js_funcs. Common examples
+ * are appending new incoming messages or prepending old messages from
+ * the logs.
+ *
+ * @js_funcs should be an array with exactly 4 entries. The entries
+ * should be the names of JavaScript functions that take the raw HTML
+ * that is to be added to the view as an argument and take the following
+ * actions, in this order:
+ * - add a new consecutive message and scroll to it if needed,
+ * - add a new consecutive message and do not scroll,
+ * - add a new non-consecutive message and scroll to it if needed, and
+ * - add a new non-consecutive message and do not scroll
+ *
+ * A message is considered to be consecutive with the previous one if
+ * all the following conditions are met:
+ * - senders are the same contact,
+ * - last message was recieved recently,
+ * - last message and this message both are/aren't backlog, and
+ * - DisableCombineConsecutive is not set in theme's settings
+ */
+static void
+theme_adium_add_message (EmpathyThemeAdium *self,
EmpathyMessage *msg,
- gboolean should_highlight)
+ EmpathyContact **prev_contact,
+ gint64 *prev_timestamp,
+ gboolean *prev_is_backlog,
+ gboolean should_highlight,
+ const gchar *js_funcs[])
{
EmpathyContact *sender;
TpMessage *tp_msg;
@@ -851,13 +903,8 @@ empathy_theme_adium_append_message (EmpathyThemeAdium *self,
gboolean is_backlog;
gboolean consecutive;
gboolean action;
+ PangoDirection direction;
- if (self->priv->pages_loading != 0)
- {
- queue_item (&self->priv->message_queue, QUEUED_MESSAGE, msg, NULL,
- should_highlight);
- return;
- }
/* Get information */
sender = empathy_message_get_sender (msg);
@@ -920,15 +967,10 @@ empathy_theme_adium_append_message (EmpathyThemeAdium *self,
}
}
- /* We want to join this message with the last one if
- * - senders are the same contact,
- * - last message was recieved recently,
- * - last message and this message both are/aren't backlog, and
- * - DisableCombineConsecutive is not set in theme's settings */
is_backlog = empathy_message_is_backlog (msg);
- consecutive = empathy_contact_equal (self->priv->last_contact, sender) &&
- (timestamp - self->priv->last_timestamp < MESSAGE_JOIN_PERIOD) &&
- (is_backlog == self->priv->last_is_backlog) &&
+ consecutive = empathy_contact_equal (*prev_contact, sender) &&
+ (ABS (timestamp - *prev_timestamp) < MESSAGE_JOIN_PERIOD) &&
+ (is_backlog == *prev_is_backlog) &&
!tp_asv_get_boolean (self->priv->data->info,
"DisableCombineConsecutive", NULL);
@@ -969,7 +1011,7 @@ empathy_theme_adium_append_message (EmpathyThemeAdium *self,
* status - the message is a status change
* event - the message is a notification of something happening
* (for example, encryption being turned on)
- * %status% - See %status% in theme_adium_append_html ()
+ * %status% - See %status% in theme_adium_add_html ()
*/
/* This is slightly a hack, but it's the only way to add
@@ -991,10 +1033,11 @@ empathy_theme_adium_append_message (EmpathyThemeAdium *self,
/* Define javascript function to use */
if (consecutive)
- func = self->priv->allow_scrolling ? "appendNextMessage" :
- "appendNextMessageNoScroll";
+ func = self->priv->allow_scrolling ? js_funcs[ADD_CONSECUTIVE_MSG_SCROLL] :
+ js_funcs[ADD_CONSECUTIVE_MSG_NO_SCROLL];
else
- func = self->priv->allow_scrolling ? "appendMessage" : "appendMessageNoScroll";
+ func = self->priv->allow_scrolling ? js_funcs[ADD_MSG_SCROLL] :
+ js_funcs[ADD_MSG_NO_SCROLL];
if (empathy_contact_is_user (sender))
{
@@ -1024,18 +1067,20 @@ empathy_theme_adium_append_message (EmpathyThemeAdium *self,
self->priv->data->in_content_html;
}
- theme_adium_append_html (self, func, html, body_escaped,
+ direction = pango_find_base_dir (empathy_message_get_body (msg), -1);
+
+ theme_adium_add_html (self, func, html, body_escaped,
avatar_filename, name_escaped, contact_id,
service_name, message_classes->str,
- timestamp, is_backlog, empathy_contact_is_user (sender));
+ timestamp, is_backlog, empathy_contact_is_user (sender), direction);
/* Keep the sender of the last displayed message */
- if (self->priv->last_contact)
- g_object_unref (self->priv->last_contact);
+ if (*prev_contact)
+ g_object_unref (*prev_contact);
- self->priv->last_contact = g_object_ref (sender);
- self->priv->last_timestamp = timestamp;
- self->priv->last_is_backlog = is_backlog;
+ *prev_contact = g_object_ref (sender);
+ *prev_timestamp = timestamp;
+ *prev_is_backlog = is_backlog;
g_free (body_escaped);
g_free (name_escaped);
@@ -1043,19 +1088,43 @@ empathy_theme_adium_append_message (EmpathyThemeAdium *self,
}
void
+empathy_theme_adium_append_message (EmpathyThemeAdium *self,
+ EmpathyMessage *msg,
+ gboolean should_highlight)
+{
+ const gchar *js_funcs[] = { "appendNextMessage",
+ "appendNextMessageNoScroll",
+ "appendMessage",
+ "appendMessageNoScroll" };
+
+ if (self->priv->pages_loading != 0)
+ {
+ queue_item (&self->priv->message_queue, QUEUED_MESSAGE, msg, NULL,
+ should_highlight, FALSE);
+ return;
+ }
+
+ theme_adium_add_message (self, msg, &self->priv->last_contact,
+ &self->priv->last_timestamp, &self->priv->last_is_backlog,
+ should_highlight, js_funcs);
+}
+
+void
empathy_theme_adium_append_event (EmpathyThemeAdium *self,
const gchar *str)
{
gchar *str_escaped;
+ PangoDirection direction;
if (self->priv->pages_loading != 0)
{
- queue_item (&self->priv->message_queue, QUEUED_EVENT, NULL, str, FALSE);
+ queue_item (&self->priv->message_queue, QUEUED_EVENT, NULL, str, FALSE, FALSE);
return;
}
+ direction = pango_find_base_dir (str, -1);
str_escaped = g_markup_escape_text (str, -1);
- theme_adium_append_event_escaped (self, str_escaped);
+ theme_adium_append_event_escaped (self, str_escaped, direction);
g_free (str_escaped);
}
@@ -1064,7 +1133,32 @@ empathy_theme_adium_append_event_markup (EmpathyThemeAdium *self,
const gchar *markup_text,
const gchar *fallback_text)
{
- theme_adium_append_event_escaped (self, markup_text);
+ PangoDirection direction;
+
+ direction = pango_find_base_dir (fallback_text, -1);
+ theme_adium_append_event_escaped (self, markup_text, direction);
+}
+
+void
+empathy_theme_adium_prepend_message (EmpathyThemeAdium *self,
+ EmpathyMessage *msg,
+ gboolean should_highlight)
+{
+ const gchar *js_funcs[] = { "prependPrev",
+ "prependPrev",
+ "prepend",
+ "prepend" };
+
+ if (self->priv->pages_loading != 0)
+ {
+ queue_item (&self->priv->message_queue, QUEUED_MESSAGE, msg, NULL,
+ should_highlight, TRUE);
+ return;
+ }
+
+ theme_adium_add_message (self, msg, &self->priv->first_contact,
+ &self->priv->first_timestamp, &self->priv->first_is_backlog,
+ should_highlight, js_funcs);
}
void
@@ -1080,7 +1174,7 @@ empathy_theme_adium_edit_message (EmpathyThemeAdium *self,
if (self->priv->pages_loading != 0)
{
- queue_item (&self->priv->message_queue, QUEUED_EDIT, message, NULL, FALSE);
+ queue_item (&self->priv->message_queue, QUEUED_EDIT, message, NULL, FALSE, FALSE);
return;
}
@@ -1353,31 +1447,28 @@ empathy_theme_adium_message_acknowledged (EmpathyThemeAdium *self,
}
static gboolean
-theme_adium_button_press_event (GtkWidget *widget,
- GdkEventButton *event)
+theme_adium_context_menu_cb (EmpathyThemeAdium *self,
+ GtkWidget *default_menu,
+ WebKitHitTestResult *hit_test_result,
+ gboolean triggered_with_keyboard,
+ gpointer user_data)
{
- if (event->button == 3)
- {
- gboolean developer_tools_enabled;
+ GtkWidget *menu;
+ EmpathyWebKitMenuFlags flags = EMPATHY_WEBKIT_MENU_CLEAR;
- g_object_get (
- G_OBJECT (webkit_web_view_get_settings (WEBKIT_WEB_VIEW (widget))),
- "enable-developer-extras", &developer_tools_enabled, NULL);
+ if (g_settings_get_boolean (self->priv->gsettings_chat,
+ EMPATHY_PREFS_CHAT_WEBKIT_DEVELOPER_TOOLS))
+ flags |= EMPATHY_WEBKIT_MENU_INSPECT;
- /* We currently have no way to add an inspector menu
- * item ourselves, so we disable our customized menu
- * if the developer extras are enabled. */
- if (!developer_tools_enabled)
- {
- empathy_webkit_context_menu_for_event (
- WEBKIT_WEB_VIEW (widget), event,
- EMPATHY_WEBKIT_MENU_CLEAR);
- return TRUE;
- }
- }
+ menu = empathy_webkit_create_context_menu (
+ WEBKIT_WEB_VIEW (self), hit_test_result, flags);
+
+ gtk_widget_show_all (menu);
- return GTK_WIDGET_CLASS (
- empathy_theme_adium_parent_class)->button_press_event (widget, event);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3,
+ gtk_get_current_event_time ());
+
+ return TRUE;
}
void
@@ -1454,6 +1545,8 @@ theme_adium_dispose (GObject *object)
self->priv->smiley_manager = NULL;
}
+ g_clear_object (&self->priv->first_contact);
+
if (self->priv->last_contact)
{
g_object_unref (self->priv->last_contact);
@@ -1631,7 +1724,6 @@ static void
empathy_theme_adium_class_init (EmpathyThemeAdiumClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = theme_adium_finalize;
object_class->dispose = theme_adium_dispose;
@@ -1639,8 +1731,6 @@ empathy_theme_adium_class_init (EmpathyThemeAdiumClass *klass)
object_class->get_property = theme_adium_get_property;
object_class->set_property = theme_adium_set_property;
- widget_class->button_press_event = theme_adium_button_press_event;
-
g_object_class_install_property (object_class, PROP_ADIUM_DATA,
g_param_spec_boxed ("adium-data",
"The theme data",
@@ -1680,17 +1770,12 @@ empathy_theme_adium_init (EmpathyThemeAdium *self)
G_CALLBACK (theme_adium_load_finished_cb), NULL);
g_signal_connect (self, "navigation-policy-decision-requested",
G_CALLBACK (theme_adium_navigation_policy_decision_requested_cb), NULL);
+ g_signal_connect (self, "context-menu",
+ G_CALLBACK (theme_adium_context_menu_cb), NULL);
self->priv->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
self->priv->gsettings_desktop = g_settings_new (
EMPATHY_PREFS_DESKTOP_INTERFACE_SCHEMA);
-
- g_signal_connect (self->priv->gsettings_chat,
- "changed::" EMPATHY_PREFS_CHAT_WEBKIT_DEVELOPER_TOOLS,
- G_CALLBACK (theme_adium_notify_enable_webkit_developer_tools_cb),
- self);
-
- theme_adium_update_enable_webkit_developer_tools (self);
}
EmpathyThemeAdium *
@@ -1739,13 +1824,8 @@ void
empathy_theme_adium_show_inspector (EmpathyThemeAdium *self)
{
WebKitWebView *web_view = WEBKIT_WEB_VIEW (self);
- WebKitWebInspector *inspector;
-
- g_object_set (G_OBJECT (webkit_web_view_get_settings (web_view)),
- "enable-developer-extras", TRUE, NULL);
- inspector = webkit_web_view_get_inspector (web_view);
- webkit_web_inspector_show (inspector);
+ empathy_webkit_show_inspector (web_view);
}
gboolean
diff --git a/libempathy-gtk/empathy-theme-adium.h b/libempathy-gtk/empathy-theme-adium.h
index f1ad48ec8..880667615 100644
--- a/libempathy-gtk/empathy-theme-adium.h
+++ b/libempathy-gtk/empathy-theme-adium.h
@@ -87,6 +87,10 @@ void empathy_theme_adium_append_event_markup (EmpathyThemeAdium *self,
const gchar *markup_text,
const gchar *fallback_text);
+void empathy_theme_adium_prepend_message (EmpathyThemeAdium *self,
+ EmpathyMessage *msg,
+ gboolean should_highlight);
+
void empathy_theme_adium_edit_message (EmpathyThemeAdium *self,
EmpathyMessage *message);
diff --git a/libempathy-gtk/empathy-webkit-utils.c b/libempathy-gtk/empathy-webkit-utils.c
index c8c585a9b..d221e5f98 100644
--- a/libempathy-gtk/empathy-webkit-utils.c
+++ b/libempathy-gtk/empathy-webkit-utils.c
@@ -161,6 +161,7 @@ empathy_webkit_bind_font_setting (WebKitWebView *webview,
webkit_get_font_family,
NULL,
NULL, NULL);
+
g_settings_bind_with_mapping (gsettings, key,
settings, "default-font-size",
G_SETTINGS_BIND_GET,
@@ -171,11 +172,11 @@ empathy_webkit_bind_font_setting (WebKitWebView *webview,
static void
empathy_webkit_copy_address_cb (GtkMenuItem *menuitem,
- gpointer user_data)
+ gpointer user_data)
{
- WebKitHitTestResult *hit_test_result = WEBKIT_HIT_TEST_RESULT (user_data);
- gchar *uri;
- GtkClipboard *clipboard;
+ WebKitHitTestResult *hit_test_result = WEBKIT_HIT_TEST_RESULT (user_data);
+ gchar *uri;
+ GtkClipboard *clipboard;
g_object_get (G_OBJECT (hit_test_result),
"link-uri", &uri,
@@ -194,8 +195,8 @@ static void
empathy_webkit_open_address_cb (GtkMenuItem *menuitem,
gpointer user_data)
{
- WebKitHitTestResult *hit_test_result = WEBKIT_HIT_TEST_RESULT (user_data);
- gchar *uri;
+ WebKitHitTestResult *hit_test_result = WEBKIT_HIT_TEST_RESULT (user_data);
+ gchar *uri;
g_object_get (G_OBJECT (hit_test_result),
"link-uri", &uri,
@@ -207,6 +208,13 @@ empathy_webkit_open_address_cb (GtkMenuItem *menuitem,
}
static void
+empathy_webkit_inspect_cb (GtkMenuItem *menuitem,
+ WebKitWebView *view)
+{
+ empathy_webkit_show_inspector (view);
+}
+
+static void
empathy_webkit_context_menu_selection_done_cb (GtkMenuShell *menu,
gpointer user_data)
{
@@ -215,17 +223,15 @@ empathy_webkit_context_menu_selection_done_cb (GtkMenuShell *menu,
g_object_unref (hit_test_result);
}
-void
-empathy_webkit_context_menu_for_event (WebKitWebView *view,
- GdkEventButton *event,
+GtkWidget *
+empathy_webkit_create_context_menu (WebKitWebView *view,
+ WebKitHitTestResult *hit_test_result,
EmpathyWebKitMenuFlags flags)
{
- WebKitHitTestResult *hit_test_result;
- WebKitHitTestResultContext context;
- GtkWidget *menu;
- GtkWidget *item;
+ WebKitHitTestResultContext context;
+ GtkWidget *menu;
+ GtkWidget *item;
- hit_test_result = webkit_web_view_get_hit_test_result (view, event);
g_object_get (G_OBJECT (hit_test_result),
"context", &context,
NULL);
@@ -289,13 +295,53 @@ empathy_webkit_context_menu_for_event (WebKitWebView *view,
gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
}
+ if ((flags & EMPATHY_WEBKIT_MENU_INSPECT) != 0)
+ {
+ /* Separator */
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ /* Inspector */
+ item = gtk_menu_item_new_with_mnemonic (_("Inspect HTML"));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (empathy_webkit_inspect_cb), view);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ }
+
g_signal_connect (GTK_MENU_SHELL (menu), "selection-done",
G_CALLBACK (empathy_webkit_context_menu_selection_done_cb),
- hit_test_result);
+ g_object_ref (hit_test_result));
+
+ return menu;
+}
+
+void
+empathy_webkit_context_menu_for_event (WebKitWebView *view,
+ GdkEventButton *event,
+ EmpathyWebKitMenuFlags flags)
+{
+ GtkWidget *menu;
+ WebKitHitTestResult *hit_test_result;
+
+ hit_test_result = webkit_web_view_get_hit_test_result (view, event);
+
+ menu = empathy_webkit_create_context_menu (view, hit_test_result, flags);
- /* Display the menu */
gtk_widget_show_all (menu);
gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
event->button, event->time);
+
+ g_object_unref (hit_test_result);
}
+void
+empathy_webkit_show_inspector (WebKitWebView *view)
+{
+ WebKitWebInspector *inspector;
+
+ g_object_set (G_OBJECT (webkit_web_view_get_settings (view)),
+ "enable-developer-extras", TRUE, NULL);
+
+ inspector = webkit_web_view_get_inspector (view);
+ webkit_web_inspector_show (inspector);
+}
diff --git a/libempathy-gtk/empathy-webkit-utils.h b/libempathy-gtk/empathy-webkit-utils.h
index 322f94c32..034e3bf55 100644
--- a/libempathy-gtk/empathy-webkit-utils.h
+++ b/libempathy-gtk/empathy-webkit-utils.h
@@ -29,13 +29,24 @@ G_BEGIN_DECLS
typedef enum {
EMPATHY_WEBKIT_MENU_CLEAR = 1 << 0,
+ EMPATHY_WEBKIT_MENU_INSPECT = 1 << 1,
} EmpathyWebKitMenuFlags;
-EmpathyStringParser *empathy_webkit_get_string_parser (gboolean smileys);
+EmpathyStringParser * empathy_webkit_get_string_parser (gboolean smileys);
+
void empathy_webkit_bind_font_setting (WebKitWebView *webview,
- GSettings *gsettings, const char *key);
+ GSettings *gsettings,
+ const char *key);
+
+GtkWidget * empathy_webkit_create_context_menu (WebKitWebView *view,
+ WebKitHitTestResult *hit_test_result,
+ EmpathyWebKitMenuFlags flags);
+
void empathy_webkit_context_menu_for_event (WebKitWebView *view,
- GdkEventButton *event, EmpathyWebKitMenuFlags flags);
+ GdkEventButton *event,
+ EmpathyWebKitMenuFlags flags);
+
+void empathy_webkit_show_inspector (WebKitWebView *view);
G_END_DECLS