Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Garcia Campos <carlosgc@gnome.org>2007-01-07 16:28:00 (GMT)
committer Carlos Garcia Campos <carlosgc@src.gnome.org>2007-01-07 16:28:00 (GMT)
commit6b9aeb5d0b86d0002db107ad79af550a4e39f07a (patch)
tree1a26d73986f440d54647da1e1064b79990415859
parent560065af6f0b02dcb360c3115398f992354865e8 (diff)
Add image handling support. Fixes bugs #310008 and #325047. Images
2007-01-07 Carlos Garcia Campos <carlosgc@gnome.org> * configure.ac: * data/evince-ui.xml: * pdf/ev-poppler.cc: (pdf_document_images_get_images), (pdf_document_document_images_iface_init): * backend/Makefile.am: * backend/ev-document-images.[ch]: * backend/ev-image.[ch]: * lib/ev-file-helpers.[ch]: (ev_tmp_filename): * shell/ev-jobs.[ch]: (ev_job_render_new), (ev_job_render_run), (ev_job_xfer_run): * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info), (move_one_job), (copy_job_to_job_info), (add_job_if_needed), (ev_pixbuf_cache_get_image_mapping): * shell/ev-window.c: (view_menu_link_popup), (view_menu_image_popup), (view_menu_popup_cb), (ev_window_dispose), (image_save_dialog_response_cb), (ev_view_popup_cmd_save_image_as), (ev_view_popup_cmd_copy_image): * shell/ev-view-private.h: * shell/ev-view.c: (ev_view_get_image_at_location), (ev_view_do_popup_menu), (ev_view_popup_menu), (ev_view_button_press_event), (ev_view_drag_data_get), (ev_view_drag_motion), (ev_view_drag_data_received), (ev_view_motion_notify_event), (ev_view_button_release_event), (ev_view_finalize), (ev_view_class_init): Add image handling support. Fixes bugs #310008 and #325047. Images selection is not supported yet. svn path=/trunk/; revision=2194
-rw-r--r--ChangeLog30
-rw-r--r--backend/Makefile.am4
-rw-r--r--backend/ev-document-images.c55
-rw-r--r--backend/ev-document-images.h55
-rw-r--r--backend/ev-image.c167
-rw-r--r--backend/ev-image.h74
-rw-r--r--configure.ac1
-rw-r--r--data/evince-ui.xml3
-rw-r--r--lib/ev-file-helpers.c6
-rw-r--r--lib/ev-file-helpers.h2
-rw-r--r--pdf/ev-poppler.cc49
-rw-r--r--shell/ev-jobs.c9
-rw-r--r--shell/ev-jobs.h3
-rw-r--r--shell/ev-pixbuf-cache.c49
-rw-r--r--shell/ev-pixbuf-cache.h4
-rw-r--r--shell/ev-view-private.h11
-rw-r--r--shell/ev-view.c191
-rw-r--r--shell/ev-window.c186
18 files changed, 833 insertions, 66 deletions
diff --git a/ChangeLog b/ChangeLog
index b37077a..a4d8056 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,35 @@
2007-01-07 Carlos Garcia Campos <carlosgc@gnome.org>
+ * configure.ac:
+ * data/evince-ui.xml:
+ * pdf/ev-poppler.cc: (pdf_document_images_get_images),
+ (pdf_document_document_images_iface_init):
+ * backend/Makefile.am:
+ * backend/ev-document-images.[ch]:
+ * backend/ev-image.[ch]:
+ * lib/ev-file-helpers.[ch]: (ev_tmp_filename):
+ * shell/ev-jobs.[ch]: (ev_job_render_new), (ev_job_render_run),
+ (ev_job_xfer_run):
+ * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info),
+ (move_one_job), (copy_job_to_job_info), (add_job_if_needed),
+ (ev_pixbuf_cache_get_image_mapping):
+ * shell/ev-window.c: (view_menu_link_popup), (view_menu_image_popup),
+ (view_menu_popup_cb), (ev_window_dispose),
+ (image_save_dialog_response_cb), (ev_view_popup_cmd_save_image_as),
+ (ev_view_popup_cmd_copy_image):
+ * shell/ev-view-private.h:
+ * shell/ev-view.c: (ev_view_get_image_at_location),
+ (ev_view_do_popup_menu), (ev_view_popup_menu),
+ (ev_view_button_press_event), (ev_view_drag_data_get),
+ (ev_view_drag_motion), (ev_view_drag_data_received),
+ (ev_view_motion_notify_event), (ev_view_button_release_event),
+ (ev_view_finalize), (ev_view_class_init):
+
+ Add image handling support. Fixes bugs #310008 and #325047. Images
+ selection is not supported yet.
+
+2007-01-07 Carlos Garcia Campos <carlosgc@gnome.org>
+
* shell/ev-window.c: (drag_data_received_cb), (ev_window_init):
* shell/ev-view.c: (ev_view_drag_data_received), (ev_view_class_init),
(ev_view_init):
diff --git a/backend/Makefile.am b/backend/Makefile.am
index 54dbd2c..a09734d 100644
--- a/backend/Makefile.am
+++ b/backend/Makefile.am
@@ -28,6 +28,8 @@ libevbackend_la_SOURCES= \
ev-link-action.h \
ev-link-dest.c \
ev-link-dest.h \
+ ev-image.c \
+ ev-image.h \
ev-document.c \
ev-document.h \
ev-document-factory.c \
@@ -38,6 +40,8 @@ libevbackend_la_SOURCES= \
ev-document-fonts.h \
ev-document-links.c \
ev-document-links.h \
+ ev-document-images.c \
+ ev-document-images.h \
ev-document-security.c \
ev-document-security.h \
ev-document-find.c \
diff --git a/backend/ev-document-images.c b/backend/ev-document-images.c
new file mode 100644
index 0000000..117b104
--- /dev/null
+++ b/backend/ev-document-images.c
@@ -0,0 +1,55 @@
+/* ev-document-images.c
+ * this file is part of evince, a gnome document_links viewer
+ *
+ * Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ev-document-images.h"
+
+GType
+ev_document_images_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo our_info = {
+ sizeof (EvDocumentImagesIface),
+ NULL,
+ NULL,
+ };
+
+ type = g_type_register_static (G_TYPE_INTERFACE,
+ "EvDocumentImages",
+ &our_info, (GTypeFlags)0);
+ }
+
+ return type;
+}
+
+GList *
+ev_document_images_get_images (EvDocumentImages *document_images,
+ gint page)
+{
+ EvDocumentImagesIface *iface = EV_DOCUMENT_IMAGES_GET_IFACE (document_images);
+ GList *retval;
+
+ retval = iface->get_images (document_images, page);
+
+ return retval;
+}
+
+
diff --git a/backend/ev-document-images.h b/backend/ev-document-images.h
new file mode 100644
index 0000000..28eee46
--- /dev/null
+++ b/backend/ev-document-images.h
@@ -0,0 +1,55 @@
+/* ev-document-images.h
+ * this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EV_DOCUMENT_IMAGES_H
+#define EV_DOCUMENT_IMAGES_H
+
+#include <glib-object.h>
+#include <glib.h>
+
+#include "ev-document.h"
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_DOCUMENT_IMAGES (ev_document_images_get_type ())
+#define EV_DOCUMENT_IMAGES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT_IMAGES, EvDocumentImages))
+#define EV_DOCUMENT_IMAGES_IFACE(k) (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT_IMAGES, EvDocumentImagesIface))
+#define EV_IS_DOCUMENT_IMAGES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EV_TYPE_DOCUMENT_IMAGES))
+#define EV_IS_DOCUMENT_IMAGES_IFACE(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_DOCUMENT_IMAGES))
+#define EV_DOCUMENT_IMAGES_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EV_TYPE_DOCUMENT_IMAGES, EvDocumentImagesIface))
+
+typedef struct _EvDocumentImages EvDocumentImages;
+typedef struct _EvDocumentImagesIface EvDocumentImagesIface;
+
+struct _EvDocumentImagesIface {
+ GTypeInterface base_iface;
+
+ /* Methods */
+ GList *(* get_images) (EvDocumentImages *document_images,
+ gint page);
+};
+
+GType ev_document_images_get_type (void) G_GNUC_CONST;
+GList *ev_document_images_get_images (EvDocumentImages *document_images,
+ gint page);
+
+G_END_DECLS
+
+#endif /* EV_DOCUMENT_IMAGES_H */
diff --git a/backend/ev-image.c b/backend/ev-image.c
new file mode 100644
index 0000000..f906b00
--- /dev/null
+++ b/backend/ev-image.c
@@ -0,0 +1,167 @@
+/* this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gstdio.h>
+#include "ev-file-helpers.h"
+#include "ev-image.h"
+
+struct _EvImagePrivate {
+ GdkPixbuf *pixbuf;
+ gchar *tmp_uri;
+};
+
+#define EV_IMAGE_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_IMAGE, EvImagePrivate))
+
+G_DEFINE_TYPE (EvImage, ev_image, G_TYPE_OBJECT)
+
+static void
+ev_image_finalize (GObject *object)
+{
+ EvImage *image = EV_IMAGE (object);
+
+ if (image->priv->pixbuf) {
+ g_object_unref (image->priv->pixbuf);
+ image->priv->pixbuf = NULL;
+ }
+
+ if (image->priv->tmp_uri) {
+ g_unlink (image->priv->tmp_uri);
+ g_free (image->priv->tmp_uri);
+ image->priv->tmp_uri = NULL;
+ }
+
+ (* G_OBJECT_CLASS (ev_image_parent_class)->finalize) (object);
+}
+
+static void
+ev_image_class_init (EvImageClass *klass)
+{
+ GObjectClass *g_object_class;
+
+ g_object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (g_object_class, sizeof (EvImagePrivate));
+
+ g_object_class->finalize = ev_image_finalize;
+}
+
+static void
+ev_image_init (EvImage *image)
+{
+ image->priv = EV_IMAGE_GET_PRIVATE (image);
+}
+
+EvImage *
+ev_image_new_from_pixbuf (GdkPixbuf *pixbuf)
+{
+ EvImage *image;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+ image = EV_IMAGE (g_object_new (EV_TYPE_IMAGE, NULL));
+ image->priv->pixbuf = g_object_ref (pixbuf);
+
+ return image;
+}
+
+GdkPixbuf *
+ev_image_get_pixbuf (EvImage *image)
+{
+ g_return_val_if_fail (EV_IS_IMAGE (image), NULL);
+ g_return_val_if_fail (GDK_IS_PIXBUF (image->priv->pixbuf), NULL);
+
+ return image->priv->pixbuf;
+}
+
+const gchar *
+ev_image_save_tmp (EvImage *image)
+{
+ GError *error = NULL;
+
+ g_return_val_if_fail (EV_IS_IMAGE (image), NULL);
+ g_return_val_if_fail (GDK_IS_PIXBUF (image->priv->pixbuf), NULL);
+
+ if (image->priv->tmp_uri)
+ return image->priv->tmp_uri;
+
+ image->priv->tmp_uri = ev_tmp_filename ("image");
+ gdk_pixbuf_save (image->priv->pixbuf,
+ image->priv->tmp_uri, "png", &error,
+ "compression", "3", NULL);
+ if (!error)
+ return image->priv->tmp_uri;
+
+ /* Erro saving image */
+ g_warning (error->message);
+ g_error_free (error);
+ g_free (image->priv->tmp_uri);
+ image->priv->tmp_uri = NULL;
+
+ return NULL;
+}
+
+const gchar *
+ev_image_get_tmp_uri (EvImage *image)
+{
+ g_return_val_if_fail (EV_IS_IMAGE (image), NULL);
+
+ return image->priv->tmp_uri;
+}
+
+/* EvImageMapping */
+static void
+ev_image_mapping_free_foreach (EvImageMapping *mapping)
+{
+ g_object_unref (mapping->image);
+ g_free (mapping);
+}
+
+void
+ev_image_mapping_free (GList *image_mapping)
+{
+ if (!image_mapping)
+ return;
+
+ g_list_foreach (image_mapping, (GFunc) ev_image_mapping_free_foreach, NULL);
+ g_list_free (image_mapping);
+}
+
+EvImage *
+ev_image_mapping_find (GList *image_mapping,
+ gdouble x,
+ gdouble y)
+{
+ GList *list;
+
+ for (list = image_mapping; list; list = list->next) {
+ EvImageMapping *mapping = list->data;
+
+ if ((x >= mapping->x1) &&
+ (y >= mapping->y1) &&
+ (x <= mapping->x2) &&
+ (y <= mapping->y2)) {
+ return mapping->image;
+ }
+ }
+
+ return NULL;
+}
+
+
diff --git a/backend/ev-image.h b/backend/ev-image.h
new file mode 100644
index 0000000..6688e7a
--- /dev/null
+++ b/backend/ev-image.h
@@ -0,0 +1,74 @@
+/* this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EV_IMAGE_H__
+#define __EV_IMAGE_H__
+
+#include <glib-object.h>
+#include <gdk/gdkpixbuf.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EvImage EvImage;
+typedef struct _EvImageClass EvImageClass;
+typedef struct _EvImagePrivate EvImagePrivate;
+
+#define EV_TYPE_IMAGE (ev_image_get_type())
+#define EV_IMAGE(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_IMAGE, EvImage))
+#define EV_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_IMAGE, EvImageClass))
+#define EV_IS_IMAGE(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_IMAGE))
+#define EV_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_IMAGE))
+#define EV_IMAGE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_IMAGE, EvImageClass))
+
+struct _EvImage {
+ GObject base_instance;
+
+ EvImagePrivate *priv;
+};
+
+struct _EvImageClass {
+ GObjectClass base_class;
+};
+
+GType ev_image_get_type (void) G_GNUC_CONST;
+EvImage *ev_image_new_from_pixbuf (GdkPixbuf *pixbuf);
+
+GdkPixbuf *ev_image_get_pixbuf (EvImage *image);
+const gchar *ev_image_save_tmp (EvImage *image);
+const gchar *ev_image_get_tmp_uri (EvImage *image);
+
+
+/* Image Mapping stuff */
+typedef struct _EvImageMapping EvImageMapping;
+struct _EvImageMapping {
+ EvImage *image;
+ gdouble x1;
+ gdouble y1;
+ gdouble x2;
+ gdouble y2;
+};
+
+void ev_image_mapping_free (GList *image_mapping);
+EvImage *ev_image_mapping_find (GList *image_mapping,
+ gdouble x,
+ gdouble y);
+
+G_END_DECLS
+
+#endif /* __EV_IMAGE_H__ */
diff --git a/configure.ac b/configure.ac
index cfd8d66..aa7fd7d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -212,6 +212,7 @@ if test "x$enable_pdf" = "xyes"; then
LIBS="$LIBS $FRONTEND_LIBS"
AC_CHECK_FUNCS(poppler_page_render)
AC_CHECK_FUNCS(poppler_page_get_duration)
+ AC_CHECK_FUNCS(poppler_page_get_image_mapping)
LIBS=$evince_save_LIBS
PKG_CHECK_MODULES(CAIRO_PDF, cairo-pdf, enable_cairo_pdf=yes, enable_cairo_pdf=no)
diff --git a/data/evince-ui.xml b/data/evince-ui.xml
index f7d411e..fba8ac2 100644
--- a/data/evince-ui.xml
+++ b/data/evince-ui.xml
@@ -73,6 +73,9 @@
<separator/>
<menuitem name="EditCopy" action="EditCopy"/>
<menuitem name="EditSelectAllPopup" action="EditSelectAll"/>
+ <separator/>
+ <menuitem name="SaveImageAs" action="SaveImageAs"/>
+ <menuitem name="CopyImage" action="CopyImage"/>
</popup>
<popup name="AttachmentPopup" action="AttachmentPopupAction">
diff --git a/lib/ev-file-helpers.c b/lib/ev-file-helpers.c
index 9763831..044aeae 100644
--- a/lib/ev-file-helpers.c
+++ b/lib/ev-file-helpers.c
@@ -113,7 +113,7 @@ ev_file_helpers_shutdown (void)
}
gchar *
-ev_tmp_filename (void)
+ev_tmp_filename (const gchar *prefix)
{
gchar *basename;
gchar *filename = NULL;
@@ -122,7 +122,9 @@ ev_tmp_filename (void)
if (filename != NULL)
g_free (filename);
- basename = g_strdup_printf ("document-%d", count ++);
+ basename = g_strdup_printf ("%s-%d",
+ prefix ? prefix : "document",
+ count ++);
filename = g_build_filename (ev_tmp_dir (),
basename, NULL);
diff --git a/lib/ev-file-helpers.h b/lib/ev-file-helpers.h
index 69ff83d..4e75a14 100644
--- a/lib/ev-file-helpers.h
+++ b/lib/ev-file-helpers.h
@@ -33,7 +33,7 @@ void ev_file_helpers_init (void);
void ev_file_helpers_shutdown (void);
-gchar* ev_tmp_filename (void);
+gchar* ev_tmp_filename (const char *prefix);
gboolean ev_xfer_uri_simple (const char *from,
const char *to,
diff --git a/pdf/ev-poppler.cc b/pdf/ev-poppler.cc
index 479a741..2068998 100644
--- a/pdf/ev-poppler.cc
+++ b/pdf/ev-poppler.cc
@@ -35,12 +35,14 @@
#include "ev-document-find.h"
#include "ev-document-misc.h"
#include "ev-document-links.h"
+#include "ev-document-images.h"
#include "ev-document-fonts.h"
#include "ev-document-security.h"
#include "ev-document-thumbnails.h"
#include "ev-document-transition.h"
#include "ev-selection.h"
#include "ev-attachment.h"
+#include "ev-image.h"
typedef struct {
PdfDocument *document;
@@ -83,6 +85,7 @@ static void pdf_document_document_iface_init (EvDocumentIface
static void pdf_document_security_iface_init (EvDocumentSecurityIface *iface);
static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
static void pdf_document_document_links_iface_init (EvDocumentLinksIface *iface);
+static void pdf_document_document_images_iface_init (EvDocumentImagesIface *iface);
static void pdf_document_document_fonts_iface_init (EvDocumentFontsIface *iface);
static void pdf_document_find_iface_init (EvDocumentFindIface *iface);
static void pdf_document_file_exporter_iface_init (EvFileExporterIface *iface);
@@ -113,6 +116,8 @@ G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
pdf_document_document_thumbnails_iface_init);
G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS,
pdf_document_document_links_iface_init);
+ G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_IMAGES,
+ pdf_document_document_images_iface_init);
G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FONTS,
pdf_document_document_fonts_iface_init);
G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
@@ -1123,6 +1128,50 @@ pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
iface->find_link_dest = pdf_document_links_find_link_dest;
}
+static GList *
+pdf_document_images_get_images (EvDocumentImages *document_images,
+ gint page)
+{
+ GList *retval = NULL;
+#ifdef HAVE_POPPLER_PAGE_GET_IMAGE_MAPPING
+ PdfDocument *pdf_document;
+ PopplerPage *poppler_page;
+ GList *mapping_list;
+ GList *list;
+
+ pdf_document = PDF_DOCUMENT (document_images);
+ poppler_page = poppler_document_get_page (pdf_document->document, page);
+ mapping_list = poppler_page_get_image_mapping (poppler_page);
+
+ for (list = mapping_list; list; list = list->next) {
+ PopplerImageMapping *image_mapping;
+ EvImageMapping *ev_image_mapping;
+
+ image_mapping = (PopplerImageMapping *)list->data;
+
+ ev_image_mapping = g_new (EvImageMapping, 1);
+
+ ev_image_mapping->image = ev_image_new_from_pixbuf (image_mapping->image);
+ ev_image_mapping->x1 = image_mapping->area.x1;
+ ev_image_mapping->x2 = image_mapping->area.x2;
+ ev_image_mapping->y1 = image_mapping->area.y1;
+ ev_image_mapping->y2 = image_mapping->area.y2;
+
+ retval = g_list_prepend (retval, ev_image_mapping);
+ }
+
+ poppler_page_free_image_mapping (mapping_list);
+ g_object_unref (poppler_page);
+#endif /* HAVE_POPPLER_PAGE_GET_IMAGE_MAPPING */
+ return retval;
+}
+
+static void
+pdf_document_document_images_iface_init (EvDocumentImagesIface *iface)
+{
+ iface->get_images = pdf_document_images_get_images;
+}
+
static GdkPixbuf *
make_thumbnail_for_size (PdfDocument *pdf_document,
gint page,
diff --git a/shell/ev-jobs.c b/shell/ev-jobs.c
index e54812c..21beaea 100644
--- a/shell/ev-jobs.c
+++ b/shell/ev-jobs.c
@@ -2,6 +2,7 @@
#include "ev-job-queue.h"
#include "ev-document-thumbnails.h"
#include "ev-document-links.h"
+#include "ev-document-images.h"
#include "ev-document-factory.h"
#include "ev-file-helpers.h"
#include "ev-document-fonts.h"
@@ -260,6 +261,7 @@ ev_job_render_new (EvDocument *document,
GdkColor *text,
GdkColor *base,
gboolean include_links,
+ gboolean include_images,
gboolean include_text,
gboolean include_selection)
{
@@ -278,6 +280,7 @@ ev_job_render_new (EvDocument *document,
job->text = *text;
job->base = *base;
job->include_links = include_links;
+ job->include_images = include_images;
job->include_text = include_text;
job->include_selection = include_selection;
@@ -323,6 +326,10 @@ ev_job_render_run (EvJobRender *job)
job->link_mapping =
ev_document_links_get_links (EV_DOCUMENT_LINKS (EV_JOB (job)->document),
job->rc->page);
+ if (job->include_images && EV_IS_DOCUMENT_IMAGES (EV_JOB (job)->document))
+ job->image_mapping =
+ ev_document_images_get_images (EV_DOCUMENT_IMAGES (EV_JOB (job)->document),
+ job->rc->page);
if (job->include_text && EV_IS_SELECTION (EV_JOB (job)->document))
job->text_mapping =
ev_selection_get_selection_map (EV_SELECTION (EV_JOB (job)->document),
@@ -507,7 +514,7 @@ ev_job_xfer_run (EvJobXfer *job)
/* We'd like to keep extension of source uri since
* it helps to resolve some mime types, say cbz */
- tmp_name = ev_tmp_filename ();
+ tmp_name = ev_tmp_filename (NULL);
base_name = gnome_vfs_uri_extract_short_name (source_uri);
job->local_uri = g_strconcat ("file:", tmp_name, "-", base_name, NULL);
g_free (base_name);
diff --git a/shell/ev-jobs.h b/shell/ev-jobs.h
index 46a7938..bf37b67 100644
--- a/shell/ev-jobs.h
+++ b/shell/ev-jobs.h
@@ -125,6 +125,7 @@ struct _EvJobRender
GList *link_mapping;
GdkRegion *text_mapping;
+ GList *image_mapping;
GdkPixbuf *selection;
GdkRegion *selection_region;
@@ -135,6 +136,7 @@ struct _EvJobRender
gint include_links : 1;
gint include_text : 1;
gint include_selection : 1;
+ gint include_images : 1;
};
struct _EvJobRenderClass
@@ -224,6 +226,7 @@ EvJob *ev_job_render_new (EvDocument *document,
GdkColor *text,
GdkColor *base,
gboolean include_links,
+ gboolean include_images,
gboolean include_text,
gboolean include_selection);
void ev_job_render_run (EvJobRender *thumbnail);
diff --git a/shell/ev-pixbuf-cache.c b/shell/ev-pixbuf-cache.c
index 630bdde..885c11a 100644
--- a/shell/ev-pixbuf-cache.c
+++ b/shell/ev-pixbuf-cache.c
@@ -2,6 +2,8 @@
#include "ev-job-queue.h"
#include "ev-page-cache.h"
#include "ev-selection.h"
+#include "ev-document-images.h"
+#include "ev-image.h"
typedef struct _CacheJobInfo
{
@@ -11,6 +13,7 @@ typedef struct _CacheJobInfo
/* Data we get from rendering */
GdkPixbuf *pixbuf;
GList *link_mapping;
+ GList *image_mapping;
GdkRegion *text_mapping;
/* Selection data.
@@ -152,6 +155,10 @@ dispose_cache_job_info (CacheJobInfo *job_info,
ev_link_mapping_free (job_info->link_mapping);
job_info->link_mapping = NULL;
}
+ if (job_info->image_mapping) {
+ ev_image_mapping_free (job_info->image_mapping);
+ job_info->image_mapping = NULL;
+ }
if (job_info->text_mapping) {
gdk_region_destroy (job_info->text_mapping);
job_info->text_mapping = NULL;
@@ -312,6 +319,7 @@ move_one_job (CacheJobInfo *job_info,
job_info->job = NULL;
job_info->pixbuf = NULL;
job_info->link_mapping = NULL;
+ job_info->image_mapping = NULL;
if (new_priority != priority && target_page->job) {
ev_job_queue_update_job (target_page->job, new_priority);
@@ -415,15 +423,19 @@ copy_job_to_job_info (EvJobRender *job_render,
job_info->link_mapping = job_render->link_mapping;
}
+ if (job_render->include_images) {
+ if (job_info->image_mapping)
+ ev_image_mapping_free (job_info->image_mapping);
+ job_info->image_mapping = job_render->image_mapping;
+ }
+
if (job_render->include_text) {
if (job_info->text_mapping)
gdk_region_destroy (job_info->text_mapping);
job_info->text_mapping = job_render->text_mapping;
}
-
if (job_render->include_selection) {
-
if (job_info->selection) {
g_object_unref (G_OBJECT (job_info->selection));
job_info->selection = NULL;
@@ -447,10 +459,9 @@ copy_job_to_job_info (EvJobRender *job_render,
g_object_unref (G_OBJECT (job_info->job));
job_info->job = NULL;
}
-
}
-static CacheJobInfo*
+static CacheJobInfo *
find_job_cache (EvPixbufCache *pixbuf_cache,
int page)
{
@@ -528,6 +539,7 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
gboolean include_links = FALSE;
gboolean include_text = FALSE;
gboolean include_selection = FALSE;
+ gboolean include_images = FALSE;
int width, height;
GdkColor *text, *base;
@@ -554,6 +566,8 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
/* Figure out what else we need for this job */
if (job_info->link_mapping == NULL)
include_links = TRUE;
+ if (job_info->image_mapping == NULL)
+ include_images = TRUE;
if (job_info->text_mapping == NULL)
include_text = TRUE;
if (new_selection_pixbuf_needed (pixbuf_cache, job_info, page, scale)) {
@@ -570,6 +584,7 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
&(job_info->target_points),
text, base,
include_links,
+ include_images,
include_text,
include_selection);
ev_job_queue_add_job (job_info->job, priority);
@@ -690,6 +705,28 @@ ev_pixbuf_cache_get_link_mapping (EvPixbufCache *pixbuf_cache,
return job_info->link_mapping;
}
+GList *
+ev_pixbuf_cache_get_image_mapping (EvPixbufCache *pixbuf_cache,
+ gint page)
+{
+ CacheJobInfo *job_info;
+
+ if (!EV_IS_DOCUMENT_IMAGES (pixbuf_cache->document))
+ return NULL;
+
+ job_info = find_job_cache (pixbuf_cache, page);
+ if (job_info == NULL)
+ return NULL;
+
+ /* We don't need to wait for the idle to handle the callback */
+ if (job_info->job &&
+ EV_JOB (job_info->job)->finished) {
+ copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache);
+ }
+
+ return job_info->image_mapping;
+}
+
static gboolean
new_selection_pixbuf_needed (EvPixbufCache *pixbuf_cache,
CacheJobInfo *job_info,
@@ -729,8 +766,8 @@ clear_selection_if_needed (EvPixbufCache *pixbuf_cache,
}
GdkRegion *
-ev_pixbuf_cache_get_text_mapping (EvPixbufCache *pixbuf_cache,
- gint page)
+ev_pixbuf_cache_get_text_mapping (EvPixbufCache *pixbuf_cache,
+ gint page)
{
CacheJobInfo *job_info;
diff --git a/shell/ev-pixbuf-cache.h b/shell/ev-pixbuf-cache.h
index c956832..6f96dc1 100644
--- a/shell/ev-pixbuf-cache.h
+++ b/shell/ev-pixbuf-cache.h
@@ -48,7 +48,7 @@ typedef struct {
typedef struct _EvPixbufCache EvPixbufCache;
typedef struct _EvPixbufCacheClass EvPixbufCacheClass;
-GType ev_pixbuf_cache_get_type (void) G_GNUC_CONST;
+GType ev_pixbuf_cache_get_type (void) G_GNUC_CONST;
EvPixbufCache *ev_pixbuf_cache_new (GtkWidget *view,
EvDocument *document);
void ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
@@ -61,6 +61,8 @@ GdkPixbuf *ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache
gint page);
GList *ev_pixbuf_cache_get_link_mapping (EvPixbufCache *pixbuf_cache,
gint page);
+GList *ev_pixbuf_cache_get_image_mapping (EvPixbufCache *pixbuf_cache,
+ gint page);
GdkRegion *ev_pixbuf_cache_get_text_mapping (EvPixbufCache *pixbuf_cache,
gint page);
void ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache);
diff --git a/shell/ev-view-private.h b/shell/ev-view-private.h
index f1f5ad5..ec1fa02 100644
--- a/shell/ev-view-private.h
+++ b/shell/ev-view-private.h
@@ -24,6 +24,7 @@
#include "ev-view.h"
#include "ev-pixbuf-cache.h"
#include "ev-page-cache.h"
+#include "ev-image.h"
/* Information for middle clicking and moving around the doc */
typedef struct {
@@ -41,6 +42,13 @@ typedef struct {
GList *selections;
} SelectionInfo;
+/* Information for handling images DND */
+typedef struct {
+ gboolean in_drag;
+ GdkPoint start;
+ EvImage *image;
+} ImageDNDInfo;
+
typedef enum {
SCROLL_TO_KEEP_POSITION,
SCROLL_TO_PAGE_POSITION,
@@ -127,6 +135,9 @@ struct _EvView {
EvViewSelectionMode selection_mode;
SelectionInfo selection_info;
+ /* Image DND */
+ ImageDNDInfo image_dnd_info;
+
/* Links */
GtkWidget *link_tooltip;
EvLink *hovered_link;
diff --git a/shell/ev-view.c b/shell/ev-view.c
index f353f47..1e156d5 100644
--- a/shell/ev-view.c
+++ b/shell/ev-view.c
@@ -35,6 +35,7 @@
#include "ev-utils.h"
#include "ev-selection.h"
#include "ev-document-links.h"
+#include "ev-document-images.h"
#include "ev-document-find.h"
#include "ev-document-transition.h"
#include "ev-document-misc.h"
@@ -73,6 +74,12 @@ enum {
};
enum {
+ TARGET_DND_URI,
+ TARGET_DND_TEXT,
+ TARGET_DND_IMAGE
+};
+
+enum {
TARGET_STRING,
TARGET_TEXT,
TARGET_COMPOUND_TEXT,
@@ -1113,6 +1120,9 @@ ev_view_get_link_at_location (EvView *view,
gint x_offset = 0, y_offset = 0;
gint x_new = 0, y_new = 0;
GList *link_mapping;
+
+ if (!EV_IS_DOCUMENT_LINKS (view->document))
+ return NULL;
x += view->scroll_x;
y += view->scroll_y;
@@ -1508,6 +1518,40 @@ handle_link_over_xy (EvView *view, gint x, gint y)
return;
}
+/*** Images ***/
+static EvImage *
+ev_view_get_image_at_location (EvView *view,
+ gdouble x,
+ gdouble y)
+{
+ gint page = -1;
+ gint x_offset = 0, y_offset = 0;
+ gint x_new = 0, y_new = 0;
+ GList *image_mapping;
+
+ if (!EV_IS_DOCUMENT_IMAGES (view->document))
+ return NULL;
+
+ x += view->scroll_x;
+ y += view->scroll_y;
+
+ find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
+
+ if (page == -1)
+ return NULL;
+
+ if (get_doc_point_from_offset (view, page, x_offset,
+ y_offset, &x_new, &y_new) == FALSE)
+ return NULL;
+
+ image_mapping = ev_pixbuf_cache_get_image_mapping (view->pixbuf_cache, page);
+
+ if (image_mapping)
+ return ev_image_mapping_find (image_mapping, x_new, y_new);
+ else
+ return NULL;
+}
+
/*** GtkWidget implementation ***/
static void
@@ -1900,16 +1944,37 @@ ev_view_expose_event (GtkWidget *widget,
}
static gboolean
+ev_view_do_popup_menu (EvView *view,
+ gdouble x,
+ gdouble y)
+{
+ EvLink *link;
+ EvImage *image;
+
+ image = ev_view_get_image_at_location (view, x, y);
+ if (image) {
+ g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, image);
+ return TRUE;
+ }
+
+ link = ev_view_get_link_at_location (view, x, y);
+ if (link) {
+ g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, link);
+ return TRUE;
+ }
+
+ g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, NULL);
+
+ return TRUE;
+}
+
+static gboolean
ev_view_popup_menu (GtkWidget *widget)
{
- gint x, y;
- EvLink *link;
- EvView *view = EV_VIEW (widget);
-
- gtk_widget_get_pointer (widget, &x, &y);
- link = ev_view_get_link_at_location (view, x, y);
- g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, link);
- return TRUE;
+ gint x, y;
+
+ gtk_widget_get_pointer (widget, &x, &y);
+ return ev_view_do_popup_menu (EV_VIEW (widget), x, y);
}
static gboolean
@@ -1917,7 +1982,6 @@ ev_view_button_press_event (GtkWidget *widget,
GdkEventButton *event)
{
EvView *view = EV_VIEW (widget);
- EvLink *link;
if (!GTK_WIDGET_HAS_FOCUS (widget)) {
gtk_widget_grab_focus (widget);
@@ -1927,7 +1991,9 @@ ev_view_button_press_event (GtkWidget *widget,
view->selection_info.in_drag = FALSE;
switch (event->button) {
- case 1:
+ case 1: {
+ EvImage *image;
+
if (view->selection_info.selections) {
if (location_in_selected_text (view,
event->x + view->scroll_x,
@@ -1938,11 +2004,19 @@ ev_view_button_press_event (GtkWidget *widget,
}
gtk_widget_queue_draw (widget);
+ } else if ((image = ev_view_get_image_at_location (view, event->x, event->y))) {
+ if (view->image_dnd_info.image)
+ g_object_unref (view->image_dnd_info.image);
+ view->image_dnd_info.image = g_object_ref (image);
+ view->image_dnd_info.in_drag = TRUE;
+
+ view->image_dnd_info.start.x = event->x + view->scroll_x;
+ view->image_dnd_info.start.y = event->y + view->scroll_y;
}
view->selection_info.start.x = event->x + view->scroll_x;
view->selection_info.start.y = event->y + view->scroll_y;
-
+ }
return TRUE;
case 2:
/* use root coordinates as reference point because
@@ -1956,9 +2030,7 @@ ev_view_button_press_event (GtkWidget *widget,
return TRUE;
case 3:
- link = ev_view_get_link_at_location (view, event->x, event->y);
- g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, link);
- return TRUE;
+ return ev_view_do_popup_menu (view, event->x, event->y);
}
return FALSE;
@@ -1974,18 +2046,62 @@ ev_view_drag_data_get (GtkWidget *widget,
{
EvView *view = EV_VIEW (widget);
- if (view->selection_info.selections &&
- ev_document_can_get_text (view->document)) {
- gchar *text;
+ switch (info) {
+ case TARGET_DND_TEXT:
+ if (view->selection_info.selections &&
+ ev_document_can_get_text (view->document)) {
+ gchar *text;
- text = get_selected_text (view);
+ text = get_selected_text (view);
+
+ gtk_selection_data_set_text (selection_data,
+ text,
+ strlen (text));
+
+ g_free (text);
+ }
+ break;
+ case TARGET_DND_IMAGE:
+ if (view->image_dnd_info.image) {
+ GdkPixbuf *pixbuf;
+
+ pixbuf = ev_image_get_pixbuf (view->image_dnd_info.image);
+ gtk_selection_data_set_pixbuf (selection_data, pixbuf);
+ }
+ break;
+ case TARGET_DND_URI:
+ if (view->image_dnd_info.image) {
+ const gchar *tmp_uri;
+ gchar **uris;
- gtk_selection_data_set_text (selection_data, text, strlen (text));
+ tmp_uri = ev_image_save_tmp (view->image_dnd_info.image);
- g_free (text);
+ uris = g_new0 (gchar *, 2);
+ uris[0] = (gchar *)tmp_uri;
+
+ gtk_selection_data_set_uris (selection_data, uris);
+
+ /* g_free instead of g_strfreev since tmp_uri is const */
+ g_free (uris);
+ }
}
}
+static gboolean
+ev_view_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ if (gtk_drag_get_source_widget (context) == widget)
+ gdk_drag_status (context, 0, time);
+ else
+ gdk_drag_status (context, context->suggested_action, time);
+
+ return TRUE;
+}
+
static void
ev_view_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
@@ -2086,14 +2202,13 @@ ev_view_motion_notify_event (GtkWidget *widget,
view->selection_info.start.x,
view->selection_info.start.y,
x, y)) {
- GdkDragContext *context;
GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
- gtk_target_list_add_text_targets (target_list, 0);
+ gtk_target_list_add_text_targets (target_list, TARGET_DND_TEXT);
- context = gtk_drag_begin (widget, target_list,
- GDK_ACTION_COPY,
- 1, (GdkEvent *)event);
+ gtk_drag_begin (widget, target_list,
+ GDK_ACTION_COPY,
+ 1, (GdkEvent *)event);
view->selection_info.in_drag = FALSE;
@@ -2101,6 +2216,26 @@ ev_view_motion_notify_event (GtkWidget *widget,
return TRUE;
}
+ } else if (view->image_dnd_info.in_drag) {
+ if (gtk_drag_check_threshold (widget,
+ view->selection_info.start.x,
+ view->selection_info.start.y,
+ x, y)) {
+ GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
+
+ gtk_target_list_add_uri_targets (target_list, TARGET_DND_URI);
+ gtk_target_list_add_image_targets (target_list, TARGET_DND_IMAGE, TRUE);
+
+ gtk_drag_begin (widget, target_list,
+ GDK_ACTION_COPY,
+ 1, (GdkEvent *)event);
+
+ view->image_dnd_info.in_drag = FALSE;
+
+ gtk_target_list_unref (target_list);
+
+ return TRUE;
+ }
}
/* For the Evince 0.4.x release, we limit selection to un-rotated
@@ -2191,6 +2326,7 @@ ev_view_button_release_event (GtkWidget *widget,
view->pressed_button = -1;
view->drag_info.in_drag = FALSE;
+ view->image_dnd_info.in_drag = FALSE;
if (view->selection_scroll_id) {
g_source_remove (view->selection_scroll_id);
@@ -2818,6 +2954,10 @@ ev_view_finalize (GObject *object)
clear_selection (view);
+ if (view->image_dnd_info.image)
+ g_object_unref (view->image_dnd_info.image);
+ view->image_dnd_info.image = NULL;
+
G_OBJECT_CLASS (ev_view_parent_class)->finalize (object);
}
@@ -3003,6 +3143,7 @@ ev_view_class_init (EvViewClass *class)
widget_class->leave_notify_event = ev_view_leave_notify_event;
widget_class->style_set = ev_view_style_set;
widget_class->drag_data_get = ev_view_drag_data_get;
+ widget_class->drag_motion = ev_view_drag_motion;
widget_class->drag_data_received = ev_view_drag_data_received;
widget_class->popup_menu = ev_view_popup_menu;
gtk_object_class->destroy = ev_view_destroy;
diff --git a/shell/ev-window.c b/shell/ev-window.c
index ec97987..c0adf8e 100644
--- a/shell/ev-window.c
+++ b/shell/ev-window.c
@@ -70,6 +70,7 @@
#include "ev-utils.h"
#include "ev-debug.h"
#include "ev-history.h"
+#include "ev-image.h"
#ifdef WITH_GNOME_PRINT
#include "ev-print-job.h"
@@ -151,9 +152,10 @@ struct _EvWindowPrivate {
GtkWidget *fullscreen_popup;
guint fullscreen_timeout_id;
- /* Popup link */
+ /* Popup view */
GtkWidget *view_popup;
EvLink *link;
+ EvImage *image;
/* Popup attachment */
GtkWidget *attachment_popup;
@@ -242,6 +244,10 @@ static void ev_view_popup_cmd_open_link_new_window (GtkAction *actio
EvWindow *window);
static void ev_view_popup_cmd_copy_link_address (GtkAction *action,
EvWindow *window);
+static void ev_view_popup_cmd_save_image_as (GtkAction *action,
+ EvWindow *window);
+static void ev_view_popup_cmd_copy_image (GtkAction *action,
+ EvWindow *window);
static void ev_attachment_popup_cmd_open_attachment (GtkAction *action,
EvWindow *window);
static void ev_attachment_popup_cmd_save_attachment_as (GtkAction *action,
@@ -3290,18 +3296,13 @@ ev_window_sidebar_visibility_changed_cb (EvSidebar *ev_sidebar,
}
}
-static gboolean
-view_menu_popup_cb (EvView *view,
- EvLink *link,
- EvWindow *ev_window)
+static void
+view_menu_link_popup (EvWindow *ev_window,
+ EvLink *link)
{
- GtkWidget *popup;
gboolean show_external = FALSE;
gboolean show_internal = FALSE;
GtkAction *action;
-
- if (ev_view_get_presentation (EV_VIEW (ev_window->priv->view)))
- return FALSE;
if (ev_window->priv->link)
g_object_unref (ev_window->priv->link);
@@ -3311,26 +3312,23 @@ view_menu_popup_cb (EvView *view,
else
ev_window->priv->link = NULL;
- popup = ev_window->priv->view_popup;
-
if (ev_window->priv->link) {
EvLinkAction *ev_action;
ev_action = ev_link_get_action (link);
- if (!ev_action)
- return FALSE;
-
- switch (ev_link_action_get_action_type (ev_action)) {
- case EV_LINK_ACTION_TYPE_GOTO_DEST:
- case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
- show_internal = TRUE;
- break;
- case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
- case EV_LINK_ACTION_TYPE_LAUNCH:
- show_external = TRUE;
- break;
- default:
- break;
+ if (ev_action) {
+ switch (ev_link_action_get_action_type (ev_action)) {
+ case EV_LINK_ACTION_TYPE_GOTO_DEST:
+ case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
+ show_internal = TRUE;
+ break;
+ case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
+ case EV_LINK_ACTION_TYPE_LAUNCH:
+ show_external = TRUE;
+ break;
+ default:
+ break;
+ }
}
}
@@ -3349,9 +3347,49 @@ view_menu_popup_cb (EvView *view,
action = gtk_action_group_get_action (ev_window->priv->view_popup_action_group,
"OpenLinkNewWindow");
gtk_action_set_visible (action, show_internal);
+}
- gtk_menu_popup (GTK_MENU (popup), NULL, NULL,
- NULL, NULL,
+static void
+view_menu_image_popup (EvWindow *ev_window,
+ EvImage *image)
+{
+ GtkAction *action;
+ gboolean show_image = FALSE;
+
+ if (ev_window->priv->image)
+ g_object_unref (ev_window->priv->image);
+
+ if (image)
+ ev_window->priv->image = g_object_ref (image);
+ else
+ ev_window->priv->image = NULL;
+
+ show_image = (ev_window->priv->image != NULL);
+
+ action = gtk_action_group_get_action (ev_window->priv->view_popup_action_group,
+ "SaveImageAs");
+ gtk_action_set_visible (action, show_image);
+
+ action = gtk_action_group_get_action (ev_window->priv->view_popup_action_group,
+ "CopyImage");
+ gtk_action_set_visible (action, show_image);
+}
+
+static gboolean
+view_menu_popup_cb (EvView *view,
+ GObject *object,
+ EvWindow *ev_window)
+{
+ if (ev_view_get_presentation (EV_VIEW (ev_window->priv->view)))
+ return FALSE;
+
+ view_menu_link_popup (ev_window,
+ EV_IS_LINK (object) ? EV_LINK (object) : NULL);
+ view_menu_image_popup (ev_window,
+ EV_IS_IMAGE (object) ? EV_IMAGE (object) : NULL);
+
+ gtk_menu_popup (GTK_MENU (ev_window->priv->view_popup),
+ NULL, NULL, NULL, NULL,
3, gtk_get_current_event_time ());
return TRUE;
}
@@ -3617,6 +3655,11 @@ ev_window_dispose (GObject *object)
priv->link = NULL;
}
+ if (priv->image) {
+ g_object_unref (priv->image);
+ priv->image = NULL;
+ }
+
if (priv->attach_list) {
g_list_foreach (priv->attach_list,
(GFunc) g_object_unref,
@@ -3848,8 +3891,11 @@ static const GtkActionEntry view_popup_entries [] = {
{ "OpenLinkNewWindow", NULL, N_("Open in New _Window"), NULL,
NULL, G_CALLBACK (ev_view_popup_cmd_open_link_new_window) },
{ "CopyLinkAddress", NULL, N_("_Copy Link Address"), NULL,
- NULL,
- G_CALLBACK (ev_view_popup_cmd_copy_link_address) },
+ NULL, G_CALLBACK (ev_view_popup_cmd_copy_link_address) },
+ { "SaveImageAs", NULL, N_("_Save Image As..."), NULL,
+ NULL, G_CALLBACK (ev_view_popup_cmd_save_image_as) },
+ { "CopyImage", NULL, N_("Copy _Image"), NULL,
+ NULL, G_CALLBACK (ev_view_popup_cmd_copy_image) },
};
static const GtkActionEntry attachment_popup_entries [] = {
@@ -4229,6 +4275,86 @@ ev_view_popup_cmd_copy_link_address (GtkAction *action, EvWindow *window)
}
static void
+image_save_dialog_response_cb (GtkWidget *fc,
+ gint response_id,
+ EvWindow *ev_window)
+{
+ gchar *uri;
+ gchar *filename;
+ GError *error = NULL;
+
+ if (response_id != GTK_RESPONSE_OK) {
+ gtk_widget_destroy (fc);
+ return;
+ }
+
+ uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
+ filename = g_filename_from_uri (uri, NULL, NULL);
+ g_free (uri);
+
+ /* FIXME: allow saving in other image formats than png */
+ gdk_pixbuf_save (ev_image_get_pixbuf (ev_window->priv->image),
+ filename, "png", &error, NULL);
+
+ if (error) {
+ ev_window_error_dialog (GTK_WINDOW (fc),
+ _("The image could not be saved."),
+ error);
+ g_error_free (error);
+ }
+
+ g_free (filename);
+
+ gtk_widget_destroy (fc);
+}
+
+static void
+ev_view_popup_cmd_save_image_as (GtkAction *action, EvWindow *window)
+{
+ GtkWidget *fc;
+ GtkFileFilter *filter;
+
+ if (!window->priv->image)
+ return;
+
+ fc = gtk_file_chooser_dialog_new (_("Save Image"),
+ GTK_WINDOW (window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (fc), TRUE);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("Images"));
+ gtk_file_filter_add_pixbuf_formats (filter);
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fc), filter);
+
+ g_signal_connect (fc, "response",
+ G_CALLBACK (image_save_dialog_response_cb),
+ window);
+
+ gtk_widget_show (fc);
+}
+
+static void
+ev_view_popup_cmd_copy_image (GtkAction *action, EvWindow *window)
+{
+ GtkClipboard *clipboard;
+
+ if (!window->priv->image)
+ return;
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window),
+ GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_image (clipboard,
+ ev_image_get_pixbuf (window->priv->image));
+}
+
+static void
ev_attachment_popup_cmd_open_attachment (GtkAction *action, EvWindow *window)
{
GList *l;
@@ -4317,7 +4443,7 @@ ev_attachment_popup_cmd_save_attachment_as (GtkAction *action, EvWindow *window)
attachment = (EvAttachment *) window->priv->attach_list->data;
fc = gtk_file_chooser_dialog_new (
- _("Save a Copy"),
+ _("Save Attachment"),
GTK_WINDOW (window),
attachment ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
GTK_STOCK_CANCEL,