aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2013-07-26 21:33:29 +0800
committerMatthew Barnes <mbarnes@redhat.com>2013-07-28 09:24:01 +0800
commit3eda7a50de7059e7898944d74ab1fc7c707e089b (patch)
tree7432f364f57ce7279e0939d527386e9bbd011f6d
parentc71f615a7f1d4f4c5df1d8a0a11af8f2319bdf20 (diff)
downloadgsoc2013-evolution-3eda7a50de7059e7898944d74ab1fc7c707e089b.tar
gsoc2013-evolution-3eda7a50de7059e7898944d74ab1fc7c707e089b.tar.gz
gsoc2013-evolution-3eda7a50de7059e7898944d74ab1fc7c707e089b.tar.bz2
gsoc2013-evolution-3eda7a50de7059e7898944d74ab1fc7c707e089b.tar.lz
gsoc2013-evolution-3eda7a50de7059e7898944d74ab1fc7c707e089b.tar.xz
gsoc2013-evolution-3eda7a50de7059e7898944d74ab1fc7c707e089b.tar.zst
gsoc2013-evolution-3eda7a50de7059e7898944d74ab1fc7c707e089b.zip
Add e_web_view_cursor_image_copy().
Asynchronously copies the image under the cursor to the clipboard. This replaces the "cursor-image" property, which attempts to match the image URI to a subresource from WebKitWebDataSource. The problem with that approach is EMailDisplay redirects several URI schemes to its own custom request handlers which further mutate the URI. So for example, a text/html message may use a "cid:" URI to refer to an embedded image, which EMailDisplay transforms to a "mail:" URI and finally to a "data:" URI. The final image URI might not be derivable from the original URI without retracing the SoupRequest. The "image-copy" action now calls e_web_view_cursor_image_copy(). This also adds an explicit requirement on gdk-pixbuf-2.0 >= 2.24 for gdk_pixbuf_new_from_stream_async() / finish(). New functions: e_web_view_cursor_image_copy() Removed functions: e_web_view_get_cursor_image() e_web_view_set_cursor_image()
-rw-r--r--configure.ac2
-rw-r--r--doc/reference/evolution-util/evolution-util-sections.txt3
-rw-r--r--e-util/e-web-view.c300
-rw-r--r--e-util/e-web-view.h5
-rw-r--r--e-util/widgets.error.xml5
-rw-r--r--mail/e-mail-browser.c2
-rw-r--r--modules/mail/e-mail-shell-view-private.c2
7 files changed, 158 insertions, 161 deletions
diff --git a/configure.ac b/configure.ac
index aa032f246c..6b2515e36f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,6 +46,7 @@ m4_define([soup_encoded_version], [SOUP_VERSION_2_40])
m4_define([eds_minimum_version], [evo_version])
m4_define([gtkhtml_minimum_version], [4.5.2])
+m4_define([gdk_pixbuf_minimum_version], [2.24.0])
m4_define([gnome_desktop_minimum_version], [2.91.3])
m4_define([gnome_icon_theme_minimum_version], [2.30.2.1])
m4_define([gsettings_desktop_schemas_minimum_version], [2.91.92])
@@ -281,6 +282,7 @@ PKG_CHECK_MODULES([GNOME_PLATFORM],
cairo-gobject
gtk+-3.0 >= gdk_minimum_version
gail-3.0 >= gdk_minimum_version
+ gdk-pixbuf-2.0 >= gdk_pixbuf_minimum_version
libxml-2.0 >= libxml_minimum_version
shared-mime-info >= shared_mime_info_minimum_version
gnome-desktop-3.0 >= gnome_desktop_minimum_version
diff --git a/doc/reference/evolution-util/evolution-util-sections.txt b/doc/reference/evolution-util/evolution-util-sections.txt
index 5d3f070540..ed4a25dd3b 100644
--- a/doc/reference/evolution-util/evolution-util-sections.txt
+++ b/doc/reference/evolution-util/evolution-util-sections.txt
@@ -4376,8 +4376,6 @@ e_web_view_get_magic_smileys
e_web_view_set_magic_smileys
e_web_view_get_selected_uri
e_web_view_set_selected_uri
-e_web_view_get_cursor_image
-e_web_view_set_cursor_image
e_web_view_get_cursor_image_src
e_web_view_set_cursor_image_src
e_web_view_get_open_proxy
@@ -4412,6 +4410,7 @@ e_web_view_stop_loading
e_web_view_update_actions
e_web_view_get_selection_html
e_web_view_update_fonts
+e_web_view_cursor_image_copy
e_web_view_request
e_web_view_request_finish
e_web_view_install_request_handler
diff --git a/e-util/e-web-view.c b/e-util/e-web-view.c
index de190c5eea..45b48c4e19 100644
--- a/e-util/e-web-view.c
+++ b/e-util/e-web-view.c
@@ -52,7 +52,6 @@ typedef struct _AsyncContext AsyncContext;
struct _EWebViewPrivate {
GtkUIManager *ui_manager;
gchar *selected_uri;
- GdkPixbufAnimation *cursor_image;
gchar *cursor_image_src;
GQueue highlights;
@@ -83,7 +82,6 @@ enum {
PROP_0,
PROP_CARET_MODE,
PROP_COPY_TARGET_LIST,
- PROP_CURSOR_IMAGE,
PROP_CURSOR_IMAGE_SRC,
PROP_DISABLE_PRINTING,
PROP_DISABLE_SAVE_TO_DISK,
@@ -263,22 +261,9 @@ action_uri_copy_cb (GtkAction *action,
static void
action_image_copy_cb (GtkAction *action,
- EWebView *web_view)
+ EWebView *web_view)
{
- GtkClipboard *clipboard;
- GdkPixbufAnimation *animation;
- GdkPixbuf *pixbuf;
-
- clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
- animation = e_web_view_get_cursor_image (web_view);
- g_return_if_fail (animation != NULL);
-
- pixbuf = gdk_pixbuf_animation_get_static_image (animation);
- if (pixbuf == NULL)
- return;
-
- gtk_clipboard_set_image (clipboard, pixbuf);
- gtk_clipboard_store (clipboard);
+ e_web_view_cursor_image_copy (web_view);
}
static GtkActionEntry uri_entries[] = {
@@ -448,32 +433,6 @@ web_view_connect_proxy_cb (EWebView *web_view,
G_CALLBACK (web_view_menu_item_deselect_cb), web_view);
}
-static GdkPixbufAnimation *
-web_view_load_cursor_image (EWebView *web_view,
- const guchar *buffer,
- gsize length,
- GError **error)
-{
- GdkPixbufLoader *loader;
- GdkPixbufAnimation *animation = NULL;
- gboolean success;
-
- loader = gdk_pixbuf_loader_new ();
-
- success =
- gdk_pixbuf_loader_write (loader, buffer, length, error) &&
- gdk_pixbuf_loader_close (loader, error);
-
- if (success) {
- animation = gdk_pixbuf_loader_get_animation (loader);
- g_object_ref (animation);
- }
-
- g_object_unref (loader);
-
- return animation;
-}
-
static gboolean
web_view_context_menu_cb (WebKitWebView *webkit_web_view,
GtkWidget *default_menu,
@@ -487,8 +446,6 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
web_view = E_WEB_VIEW (webkit_web_view);
- g_clear_object (&web_view->priv->cursor_image);
-
g_free (web_view->priv->cursor_image_src);
web_view->priv->cursor_image_src = NULL;
@@ -498,60 +455,14 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
g_object_get (hit_test_result, "context", &context, NULL);
if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
- WebKitWebDataSource *data_source;
- WebKitWebFrame *frame;
- GList *list, *link;
gchar *image_uri = NULL;
g_object_get (hit_test_result, "image-uri", &image_uri, NULL);
- if (image_uri == NULL)
- return FALSE;
-
- g_free (web_view->priv->cursor_image_src);
- web_view->priv->cursor_image_src = image_uri;
-
- /* Iterate through all resources of the loaded webpage and
- * try to find resource with URI matching cursor_image_src */
- frame = webkit_web_view_get_main_frame (
- WEBKIT_WEB_VIEW (web_view));
- data_source = webkit_web_frame_get_data_source (frame);
- list = webkit_web_data_source_get_subresources (data_source);
-
- for (link = list; link != NULL; link = g_list_next (link)) {
- WebKitWebResource *resource;
- GString *data;
- const gchar *resource_uri;
- GError *local_error = NULL;
-
- resource = WEBKIT_WEB_RESOURCE (link->data);
- resource_uri = webkit_web_resource_get_uri (resource);
-
- if (g_strcmp0 (resource_uri, image_uri) != 0)
- continue;
-
- data = webkit_web_resource_get_data (resource);
- if (data == NULL)
- break;
-
- g_clear_object (&web_view->priv->cursor_image);
-
- web_view->priv->cursor_image =
- web_view_load_cursor_image (
- web_view, (guchar *) data->str,
- data->len, &local_error);
-
- if (local_error != NULL) {
- g_warning (
- "%s: %s", G_STRFUNC,
- local_error->message);
- g_error_free (local_error);
- }
-
- break;
+ if (image_uri != NULL) {
+ g_free (web_view->priv->cursor_image_src);
+ web_view->priv->cursor_image_src = image_uri;
}
-
- g_list_free (list);
}
if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
@@ -668,12 +579,6 @@ web_view_set_property (GObject *object,
g_value_get_boolean (value));
return;
- case PROP_CURSOR_IMAGE:
- e_web_view_set_cursor_image (
- E_WEB_VIEW (object),
- g_value_get_object (value));
- return;
-
case PROP_CURSOR_IMAGE_SRC:
e_web_view_set_cursor_image_src (
E_WEB_VIEW (object),
@@ -750,12 +655,6 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
- case PROP_CURSOR_IMAGE:
- g_value_set_object (
- value, e_web_view_get_cursor_image (
- E_WEB_VIEW (object)));
- return;
-
case PROP_CURSOR_IMAGE_SRC:
g_value_set_string (
value, e_web_view_get_cursor_image_src (
@@ -853,7 +752,6 @@ web_view_dispose (GObject *object)
g_clear_object (&priv->open_proxy);
g_clear_object (&priv->print_proxy);
g_clear_object (&priv->save_as_proxy);
- g_clear_object (&priv->cursor_image);
g_clear_object (&priv->aliasing_settings);
g_clear_object (&priv->font_settings);
@@ -1145,15 +1043,14 @@ web_view_update_actions (EWebView *web_view)
gboolean scheme_is_http = FALSE;
gboolean scheme_is_mailto = FALSE;
gboolean uri_is_valid = FALSE;
- gboolean has_cursor_image;
gboolean visible;
+ const gchar *cursor_image_src;
const gchar *group_name;
const gchar *uri;
uri = e_web_view_get_selected_uri (web_view);
can_copy = webkit_web_view_can_copy_clipboard (WEBKIT_WEB_VIEW (web_view));
- has_cursor_image = e_web_view_get_cursor_image_src (web_view) ||
- e_web_view_get_cursor_image (web_view);
+ cursor_image_src = e_web_view_get_cursor_image_src (web_view);
/* Parse the URI early so we know if the actions will work. */
if (uri != NULL) {
@@ -1188,7 +1085,7 @@ web_view_update_actions (EWebView *web_view)
gtk_action_group_set_visible (action_group, visible);
group_name = "image";
- visible = has_cursor_image;
+ visible = (cursor_image_src != NULL);
action_group = e_web_view_get_action_group (web_view, group_name);
gtk_action_group_set_visible (action_group, visible);
@@ -1221,6 +1118,8 @@ web_view_submit_alert (EAlertSink *alert_sink,
GtkWidget *dialog;
GString *buffer;
const gchar *icon_name = NULL;
+ const gchar *primary_text;
+ const gchar *secondary_text;
gpointer parent;
web_view = E_WEB_VIEW (alert_sink);
@@ -1248,6 +1147,15 @@ web_view_submit_alert (EAlertSink *alert_sink,
return;
}
+ /* Primary text is required. */
+ primary_text = e_alert_get_primary_text (alert);
+ g_return_if_fail (primary_text != NULL);
+
+ /* Secondary text is optional. */
+ secondary_text = e_alert_get_secondary_text (alert);
+ if (secondary_text == NULL)
+ secondary_text = "";
+
buffer = g_string_sized_new (512);
g_string_append (
@@ -1281,8 +1189,8 @@ web_view_submit_alert (EAlertSink *alert_sink,
"</tr>",
icon_name,
GTK_ICON_SIZE_DIALOG,
- e_alert_get_primary_text (alert),
- e_alert_get_secondary_text (alert));
+ primary_text,
+ secondary_text);
g_string_append (
buffer,
@@ -1426,16 +1334,6 @@ e_web_view_class_init (EWebViewClass *class)
g_object_class_install_property (
object_class,
- PROP_CURSOR_IMAGE,
- g_param_spec_object (
- "cursor-image",
- "Image animation at the mouse cursor",
- NULL,
- GDK_TYPE_PIXBUF_ANIMATION,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (
- object_class,
PROP_CURSOR_IMAGE_SRC,
g_param_spec_string (
"cursor-image-src",
@@ -2170,34 +2068,6 @@ e_web_view_set_selected_uri (EWebView *web_view,
g_object_notify (G_OBJECT (web_view), "selected-uri");
}
-GdkPixbufAnimation *
-e_web_view_get_cursor_image (EWebView *web_view)
-{
- g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
-
- return web_view->priv->cursor_image;
-}
-
-void
-e_web_view_set_cursor_image (EWebView *web_view,
- GdkPixbufAnimation *image)
-{
- g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
- if (web_view->priv->cursor_image == image)
- return;
-
- if (image != NULL)
- g_object_ref (image);
-
- if (web_view->priv->cursor_image != NULL)
- g_object_unref (web_view->priv->cursor_image);
-
- web_view->priv->cursor_image = image;
-
- g_object_notify (G_OBJECT (web_view), "cursor-image");
-}
-
const gchar *
e_web_view_get_cursor_image_src (EWebView *web_view)
{
@@ -2828,6 +2698,132 @@ e_web_view_update_fonts (EWebView *web_view)
pango_font_description_free (vw);
}
+/* Helper for e_web_view_cursor_image_copy() */
+static void
+web_view_cursor_image_copy_pixbuf_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ GdkPixbuf *pixbuf;
+ GError *local_error = NULL;
+
+ activity = E_ACTIVITY (user_data);
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ pixbuf = gdk_pixbuf_new_from_stream_finish (result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((pixbuf != NULL) && (local_error == NULL)) ||
+ ((pixbuf == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "widgets:no-image-copy",
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ GtkClipboard *clipboard;
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_image (clipboard, pixbuf);
+ gtk_clipboard_store (clipboard);
+
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ }
+
+ g_clear_object (&activity);
+ g_clear_object (&pixbuf);
+}
+
+/* Helper for e_web_view_cursor_image_copy() */
+static void
+web_view_cursor_image_copy_request_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ GCancellable *cancellable;
+ GInputStream *input_stream;
+ GError *local_error = NULL;
+
+ activity = E_ACTIVITY (user_data);
+ alert_sink = e_activity_get_alert_sink (activity);
+ cancellable = e_activity_get_cancellable (activity);
+
+ input_stream = e_web_view_request_finish (
+ E_WEB_VIEW (source_object), result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((input_stream != NULL) && (local_error == NULL)) ||
+ ((input_stream == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "widgets:no-image-copy",
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ gdk_pixbuf_new_from_stream_async (
+ input_stream, cancellable,
+ web_view_cursor_image_copy_pixbuf_cb,
+ g_object_ref (activity));
+ }
+
+ g_clear_object (&activity);
+ g_clear_object (&input_stream);
+}
+
+/**
+ * e_web_view_cursor_image_copy:
+ * @web_view: an #EWebView
+ *
+ * Asynchronously copies the image under the cursor to the clipboard.
+ *
+ * This function triggers a #EWebView::new-activity signal emission so
+ * the asynchronous operation can be tracked and/or cancelled.
+ **/
+void
+e_web_view_cursor_image_copy (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (web_view->priv->cursor_image_src != NULL) {
+ EActivity *activity;
+ GCancellable *cancellable;
+ const gchar *text;
+
+ activity = e_web_view_new_activity (web_view);
+ cancellable = e_activity_get_cancellable (activity);
+
+ text = _("Copying image to clipboard");
+ e_activity_set_text (activity, text);
+
+ e_web_view_request (
+ web_view,
+ web_view->priv->cursor_image_src,
+ cancellable,
+ web_view_cursor_image_copy_request_cb,
+ g_object_ref (activity));
+
+ g_object_unref (activity);
+ }
+}
+
/* Helper for e_web_view_request() */
static void
web_view_request_send_cb (GObject *source_object,
@@ -2848,8 +2844,6 @@ web_view_request_send_cb (GObject *source_object,
g_simple_async_result_take_error (simple, local_error);
g_simple_async_result_complete (simple);
-
- g_object_unref (simple);
}
/**
diff --git a/e-util/e-web-view.h b/e-util/e-web-view.h
index 7897257e87..3f7b4e10b5 100644
--- a/e-util/e-web-view.h
+++ b/e-util/e-web-view.h
@@ -142,10 +142,6 @@ void e_web_view_set_magic_smileys (EWebView *web_view,
const gchar * e_web_view_get_selected_uri (EWebView *web_view);
void e_web_view_set_selected_uri (EWebView *web_view,
const gchar *selected_uri);
-GdkPixbufAnimation *
- e_web_view_get_cursor_image (EWebView *web_view);
-void e_web_view_set_cursor_image (EWebView *web_view,
- GdkPixbufAnimation *animation);
const gchar * e_web_view_get_cursor_image_src (EWebView *web_view);
void e_web_view_set_cursor_image_src (EWebView *web_view,
const gchar *src_uri);
@@ -189,6 +185,7 @@ void e_web_view_stop_loading (EWebView *web_view);
void e_web_view_update_actions (EWebView *web_view);
gchar * e_web_view_get_selection_html (EWebView *web_view);
void e_web_view_update_fonts (EWebView *web_view);
+void e_web_view_cursor_image_copy (EWebView *web_view);
void e_web_view_request (EWebView *web_view,
const gchar *uri,
GCancellable *cancellable,
diff --git a/e-util/widgets.error.xml b/e-util/widgets.error.xml
index efaa41c42e..60dc78080f 100644
--- a/e-util/widgets.error.xml
+++ b/e-util/widgets.error.xml
@@ -14,6 +14,11 @@
<_secondary>Please provide an unique name to identify this signature.</_secondary>
</error>
+ <error id="no-image-copy" type="warning">
+ <_primary>Unable to copy image to clipboard.</_primary>
+ <secondary xml:space="preserve">{0}</secondary>
+ </error>
+
<error id="no-load-signature" type="error">
<_primary>Could not load signature.</_primary>
<secondary xml:space="preserve">{0}</secondary>
diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c
index 2df99d618e..052d08a0dc 100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@ -333,7 +333,7 @@ mail_browser_popup_event_cb (EMailBrowser *browser,
reader = E_MAIL_READER (browser);
web_view = E_WEB_VIEW (e_mail_reader_get_mail_display (reader));
- if (e_web_view_get_cursor_image (web_view) != NULL)
+ if (e_web_view_get_cursor_image_src (web_view) != NULL)
return FALSE;
menu = e_mail_reader_get_popup_menu (reader);
diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c
index aa75643f9f..0578727641 100644
--- a/modules/mail/e-mail-shell-view-private.c
+++ b/modules/mail/e-mail-shell-view-private.c
@@ -415,7 +415,7 @@ mail_shell_view_popup_event_cb (EMailShellView *mail_shell_view,
reader = E_MAIL_READER (mail_view);
display = e_mail_reader_get_mail_display (reader);
- if (e_web_view_get_cursor_image (E_WEB_VIEW (display)) != NULL)
+ if (e_web_view_get_cursor_image_src (E_WEB_VIEW (display)) != NULL)
return FALSE;
menu = e_mail_reader_get_popup_menu (reader);