diff options
Diffstat (limited to 'libview')
-rw-r--r-- | libview/Makefile.am | 6 | ||||
-rw-r--r-- | libview/ev-document-model.h | 4 | ||||
-rw-r--r-- | libview/ev-job-scheduler.c | 34 | ||||
-rw-r--r-- | libview/ev-jobs.c | 216 | ||||
-rw-r--r-- | libview/ev-jobs.h | 13 | ||||
-rwxr-xr-x[-rw-r--r--] | libview/ev-view.c | 41 | ||||
-rwxr-xr-x[-rw-r--r--] | libview/ev-view.h | 2 | ||||
-rw-r--r-- | libview/ev-web-view.c | 875 | ||||
-rw-r--r-- | libview/ev-web-view.h | 92 |
9 files changed, 1240 insertions, 43 deletions
diff --git a/libview/Makefile.am b/libview/Makefile.am index 7dd0a950..96e80ea3 100644 --- a/libview/Makefile.am +++ b/libview/Makefile.am @@ -19,6 +19,7 @@ INST_H_SRC_FILES = \ ev-print-operation.h \ ev-stock-icons.h \ ev-view.h \ + ev-web-view.h \ ev-view-presentation.h INST_H_FILES = \ @@ -41,6 +42,7 @@ libatrilview_la_SOURCES = \ ev-timeline.c \ ev-transition-animation.c \ ev-view.c \ + ev-web-view.c \ ev-view-accessible.c \ ev-view-marshal.c \ ev-view-cursor.c \ @@ -63,6 +65,7 @@ libatrilview_la_CFLAGS = \ $(LIBVIEW_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED) \ + $(WEBKIT_CFLAGS) \ $(AM_CFLAGS) libatrilview_la_LDFLAGS = \ @@ -73,7 +76,8 @@ libatrilview_la_LDFLAGS = \ libatrilview_la_LIBADD = \ $(top_builddir)/libdocument/libatrildocument.la \ - $(LIBVIEW_LIBS) + $(LIBVIEW_LIBS) \ + $(WEBKIT_LIBS) BUILT_SOURCES = \ ev-view-marshal.h \ diff --git a/libview/ev-document-model.h b/libview/ev-document-model.h index b8bea62c..f9d175c0 100644 --- a/libview/ev-document-model.h +++ b/libview/ev-document-model.h @@ -69,7 +69,9 @@ EvSizingMode ev_document_model_get_sizing_mode (EvDocumentModel *model); void ev_document_model_set_rotation (EvDocumentModel *model, gint rotation); gint ev_document_model_get_rotation (EvDocumentModel *model); -void ev_document_model_set_inverted_colors (EvDocumentModel *model, +void ev_document_model_set_inverted_colors (EvDocumentModel *model, + gboolean inverted_colors); +void atril_web_document_set_inverted_colors(EvDocumentModel *model, gboolean inverted_colors); gboolean ev_document_model_get_inverted_colors (EvDocumentModel *model); void ev_document_model_set_continuous (EvDocumentModel *model, diff --git a/libview/ev-job-scheduler.c b/libview/ev-job-scheduler.c index 9d028b0a..4cb6864c 100644 --- a/libview/ev-job-scheduler.c +++ b/libview/ev-job-scheduler.c @@ -40,8 +40,8 @@ static GQueue queue_high = G_QUEUE_INIT; static GQueue queue_low = G_QUEUE_INIT; static GQueue queue_none = G_QUEUE_INIT; -static GCond *job_queue_cond = NULL; -static GMutex *job_queue_mutex = NULL; +static GCond job_queue_cond; +static GMutex job_queue_mutex; static GQueue *job_queue[EV_JOB_N_PRIORITIES] = { &queue_urgent, &queue_high, @@ -55,12 +55,12 @@ ev_job_queue_push (EvSchedulerJob *job, { ev_debug_message (DEBUG_JOBS, "%s priority %d", EV_GET_TYPE_NAME (job->job), priority); - g_mutex_lock (job_queue_mutex); + g_mutex_lock (&job_queue_mutex); g_queue_push_tail (job_queue[priority], job); - g_cond_broadcast (job_queue_cond); + g_cond_broadcast (&job_queue_cond); - g_mutex_unlock (job_queue_mutex); + g_mutex_unlock (&job_queue_mutex); } static EvSchedulerJob * @@ -83,9 +83,7 @@ ev_job_queue_get_next_unlocked (void) static gpointer ev_job_scheduler_init (gpointer data) { - job_queue_cond = g_cond_new (); - job_queue_mutex = g_mutex_new (); - g_thread_create (ev_job_thread_proxy, NULL, FALSE, NULL); + g_thread_new ("EvJobScheduler", ev_job_thread_proxy, NULL); return NULL; } @@ -152,7 +150,7 @@ ev_scheduler_thread_job_cancelled (EvSchedulerJob *job, ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job->job)); - g_mutex_lock (job_queue_mutex); + g_mutex_lock (&job_queue_mutex); /* If the job is not still running, * remove it from the job queue and job list. @@ -162,10 +160,10 @@ ev_scheduler_thread_job_cancelled (EvSchedulerJob *job, list = g_queue_find (job_queue[job->priority], job); if (list) { g_queue_delete_link (job_queue[job->priority], list); - g_mutex_unlock (job_queue_mutex); + g_mutex_unlock (&job_queue_mutex); ev_scheduler_job_destroy (job); } else { - g_mutex_unlock (job_queue_mutex); + g_mutex_unlock (&job_queue_mutex); } } @@ -201,14 +199,14 @@ ev_job_thread_proxy (gpointer data) while (TRUE) { EvSchedulerJob *job; - g_mutex_lock (job_queue_mutex); + g_mutex_lock (&job_queue_mutex); job = ev_job_queue_get_next_unlocked (); if (!job) { - g_cond_wait (job_queue_cond, job_queue_mutex); - g_mutex_unlock (job_queue_mutex); + g_cond_wait (&job_queue_cond, &job_queue_mutex); + g_mutex_unlock (&job_queue_mutex); continue; } - g_mutex_unlock (job_queue_mutex); + g_mutex_unlock (&job_queue_mutex); ev_job_thread (job->job); ev_scheduler_job_destroy (job); @@ -288,7 +286,7 @@ ev_job_scheduler_update_job (EvJob *job, if (need_resort) { GList *list; - g_mutex_lock (job_queue_mutex); + g_mutex_lock (&job_queue_mutex); list = g_queue_find (job_queue[s_job->priority], s_job); if (list) { @@ -296,10 +294,10 @@ ev_job_scheduler_update_job (EvJob *job, EV_GET_TYPE_NAME (job), s_job->priority, priority); g_queue_delete_link (job_queue[s_job->priority], list); g_queue_push_tail (job_queue[priority], s_job); - g_cond_broadcast (job_queue_cond); + g_cond_broadcast (&job_queue_cond); } - g_mutex_unlock (job_queue_mutex); + g_mutex_unlock (&job_queue_mutex); } } diff --git a/libview/ev-jobs.c b/libview/ev-jobs.c index d8d3043d..281ad782 100644 --- a/libview/ev-jobs.c +++ b/libview/ev-jobs.c @@ -24,6 +24,7 @@ #include "ev-document-thumbnails.h" #include "ev-document-links.h" #include "ev-document-images.h" +#include "ev-job-scheduler.h" #include "ev-document-forms.h" #include "ev-file-exporter.h" #include "ev-document-factory.h" @@ -39,6 +40,14 @@ #include "ev-document-text.h" #include "ev-debug.h" +#include <gtk/gtk.h> +#if ENABLE_EPUB +#if GTK_CHECK_VERSION(3, 0, 0) +#include <webkit2/webkit2.h> +#else +#include <webkit/webkit.h> +#endif +#endif #include <errno.h> #include <glib/gstdio.h> #include <glib/gi18n-lib.h> @@ -58,8 +67,8 @@ static void ev_job_page_data_init (EvJobPageData *job); static void ev_job_page_data_class_init (EvJobPageDataClass *class); static void ev_job_thumbnail_init (EvJobThumbnail *job); static void ev_job_thumbnail_class_init (EvJobThumbnailClass *class); -static void ev_job_load_init (EvJobLoad *job); -static void ev_job_load_class_init (EvJobLoadClass *class); +static void ev_job_load_init (EvJobLoad *job); +static void ev_job_load_class_init (EvJobLoadClass *class); static void ev_job_save_init (EvJobSave *job); static void ev_job_save_class_init (EvJobSaveClass *class); static void ev_job_find_init (EvJobFind *job); @@ -87,6 +96,11 @@ enum { FIND_LAST_SIGNAL }; +#if ENABLE_EPUB +static GtkWidget* webview; +static GtkWidget* offscreenwindow; +#endif + static guint job_signals[LAST_SIGNAL] = { 0 }; static guint job_fonts_signals[FONTS_LAST_SIGNAL] = { 0 }; static guint job_find_signals[FIND_LAST_SIGNAL] = { 0 }; @@ -211,7 +225,7 @@ ev_job_run (EvJob *job) { EvJobClass *class = EV_JOB_GET_CLASS (job); - return class->run (job); + return class-> run (job); } void @@ -568,6 +582,24 @@ ev_job_render_run (EvJob *job) ev_document_fc_mutex_lock (); ev_page = ev_document_get_page (job->document, job_render->page); + + if ( job->document->iswebdocument == TRUE ) + { + return TRUE; + + if (g_cancellable_is_cancelled (job->cancellable)) { + ev_document_fc_mutex_unlock (); + ev_document_doc_mutex_unlock (); + g_object_unref (rc); + + return FALSE; + } + + ev_document_fc_mutex_unlock (); + ev_document_doc_mutex_unlock (); + ev_job_succeeded (job); + return FALSE; + } rc = ev_render_context_new (ev_page, job_render->rotation, job_render->scale); g_object_unref (ev_page); @@ -740,7 +772,7 @@ ev_job_page_data_new (EvDocument *document, static void ev_job_thumbnail_init (EvJobThumbnail *job) { - EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; + EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; } static void @@ -760,28 +792,144 @@ ev_job_thumbnail_dispose (GObject *object) (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object); } +#if ENABLE_EPUB +#if !GTK_CHECK_VERSION(3, 0, 0) +static gboolean +web_thumbnail_get_screenshot_cb(EvJobThumbnail *job_thumb) +{ + if (webkit_web_view_get_load_status (WEBKIT_WEB_VIEW(webview)) != WEBKIT_LOAD_FINISHED) { + return TRUE; + } + + EvPage *page = ev_document_get_page (EV_JOB(job_thumb)->document, job_thumb->page); + job_thumb->surface = webkit_web_view_get_snapshot (WEBKIT_WEB_VIEW(webview)); + EvRenderContext *rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + EvPage *screenshotpage; + screenshotpage = ev_page_new(job_thumb->page); + screenshotpage->backend_page = (EvBackendPage)job_thumb->surface; + screenshotpage->backend_destroy_func = (EvBackendPageDestroyFunc)cairo_surface_destroy ; + ev_render_context_set_page(rc,screenshotpage); + + job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB(job_thumb)->document), + rc, TRUE); + g_object_unref(screenshotpage); + g_object_unref(rc); + + ev_document_doc_mutex_unlock(); + ev_job_succeeded(EV_JOB(job_thumb)); + return FALSE; +} +#else + +static void +snapshot_callback(WebKitWebView *webview, + GAsyncResult *results, + EvJobThumbnail *job_thumb) +{ + EvPage *page = ev_document_get_page (EV_JOB(job_thumb)->document, job_thumb->page); + job_thumb->surface = webkit_web_view_get_snapshot_finish (webview, + results, + NULL); + EvRenderContext *rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + EvPage *screenshotpage; + screenshotpage = ev_page_new(job_thumb->page); + screenshotpage->backend_page = (EvBackendPage)job_thumb->surface; + screenshotpage->backend_destroy_func = (EvBackendPageDestroyFunc)cairo_surface_destroy ; + ev_render_context_set_page(rc,screenshotpage); + + job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB(job_thumb)->document), + rc, TRUE); + g_object_unref(screenshotpage); + g_object_unref(rc); + + ev_document_doc_mutex_unlock(); + ev_job_succeeded(EV_JOB(job_thumb)); +} + +static void +web_thumbnail_get_screenshot_cb (WebKitWebView *webview, + WebKitLoadEvent event, + EvJobThumbnail *job_thumb) +{ + if (event != WEBKIT_LOAD_FINISHED) { + return; + } + + webkit_web_view_get_snapshot (webview, + WEBKIT_SNAPSHOT_REGION_VISIBLE, + WEBKIT_SNAPSHOT_OPTIONS_NONE, + NULL, + (GAsyncReadyCallback)snapshot_callback, + g_object_ref(job_thumb)); +} +#endif +#endif static gboolean ev_job_thumbnail_run (EvJob *job) { EvJobThumbnail *job_thumb = EV_JOB_THUMBNAIL (job); EvRenderContext *rc; EvPage *page; - ev_debug_message (DEBUG_JOBS, "%d (%p)", job_thumb->page, job); ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); - - ev_document_doc_mutex_lock (); + + if (job->document->iswebdocument) { + /* Do not block the main loop */ + if (!ev_document_doc_mutex_trylock ()) + return TRUE; + } + else { + ev_document_doc_mutex_lock (); + } page = ev_document_get_page (job->document, job_thumb->page); - rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + if (job->document->iswebdocument == TRUE ) { + rc = ev_render_context_new (page, 0, job_thumb->scale); + } + else { + rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + } g_object_unref (page); - job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (job->document), - rc, TRUE); - g_object_unref (rc); - ev_document_doc_mutex_unlock (); +#if ENABLE_EPUB + if (job->document->iswebdocument == TRUE) { + if (!webview) { + webview = webkit_web_view_new(); + } + + if (!offscreenwindow) { + offscreenwindow = gtk_offscreen_window_new(); + + gtk_container_add(GTK_CONTAINER(offscreenwindow),GTK_WIDGET(webview)); + + gtk_window_set_default_size (GTK_WINDOW(offscreenwindow),800,1080); + + gtk_widget_show_all(offscreenwindow); + } + + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)rc->page->backend_page); +#if !GTK_CHECK_VERSION (3, 0, 0) + g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc)web_thumbnail_get_screenshot_cb, + g_object_ref (job_thumb), + (GDestroyNotify)g_object_unref); +#else + g_signal_connect(WEBKIT_WEB_VIEW(webview),"load-changed", + G_CALLBACK(web_thumbnail_get_screenshot_cb), + g_object_ref(job_thumb)); - ev_job_succeeded (job); +#endif + } + else +#endif + { + job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (job->document), + rc, TRUE); + ev_document_doc_mutex_unlock (); + + ev_job_succeeded (job); + } + g_object_unref (rc); return FALSE; } @@ -1185,6 +1333,10 @@ ev_job_find_dispose (GObject *object) g_free (job->pages); job->pages = NULL; } + + if (job->results) { + g_free(job->results); + } (* G_OBJECT_CLASS (ev_job_find_parent_class)->dispose) (object); } @@ -1196,7 +1348,6 @@ ev_job_find_run (EvJob *job) EvDocumentFind *find = EV_DOCUMENT_FIND (job->document); EvPage *ev_page; GList *matches; - ev_debug_message (DEBUG_JOBS, NULL); /* Do not block the main loop */ @@ -1210,16 +1361,30 @@ ev_job_find_run (EvJob *job) #endif ev_page = ev_document_get_page (job->document, job_find->current_page); - matches = ev_document_find_find_text (find, ev_page, job_find->text, - job_find->case_sensitive); + + if (job->document->iswebdocument) { + job_find->results[job_find->current_page] = ev_document_find_check_for_hits(find, ev_page, job_find->text, + job_find->case_sensitive); + }else { + matches = ev_document_find_find_text (find, ev_page, job_find->text, + job_find->case_sensitive); + } + g_object_unref (ev_page); ev_document_doc_mutex_unlock (); - if (!job_find->has_results) + if (!job_find->has_results && !job->document->iswebdocument) { job_find->has_results = (matches != NULL); + } + else if (!job_find->has_results && job->document->iswebdocument){ + job_find->has_results = (job_find->results[job_find->current_page] > 0); + } + + if (job->document->iswebdocument == FALSE) { + job_find->pages[job_find->current_page] = matches; + } - job_find->pages[job_find->current_page] = matches; g_signal_emit (job_find, job_find_signals[FIND_UPDATED], 0, job_find->current_page); job_find->current_page = (job_find->current_page + 1) % job_find->n_pages; @@ -1269,7 +1434,13 @@ ev_job_find_new (EvDocument *document, job->start_page = start_page; job->current_page = start_page; job->n_pages = n_pages; - job->pages = g_new0 (GList *, n_pages); + + if (document->iswebdocument) { + job->results = g_malloc0 (sizeof(guint) *n_pages); + } + else { + job->pages = g_new0 (GList *, n_pages); + } job->text = g_strdup (text); job->case_sensitive = case_sensitive; job->has_results = FALSE; @@ -1281,7 +1452,12 @@ gint ev_job_find_get_n_results (EvJobFind *job, gint page) { - return g_list_length (job->pages[page]); + if (EV_JOB(job)->document->iswebdocument) { + return job->results[page]; + } + else { + return g_list_length (job->pages[page]); + } } gdouble diff --git a/libview/ev-jobs.h b/libview/ev-jobs.h index e6ae4552..fdc23bae 100644 --- a/libview/ev-jobs.h +++ b/libview/ev-jobs.h @@ -45,6 +45,9 @@ typedef struct _EvJobPageDataClass EvJobPageDataClass; typedef struct _EvJobThumbnail EvJobThumbnail; typedef struct _EvJobThumbnailClass EvJobThumbnailClass; +typedef struct _EvJobWebThumbnail EvJobWebThumbnail; +typedef struct _EvJobWebThumbnailClass EvJobWebThumbnailClass; + typedef struct _EvJobLinks EvJobLinks; typedef struct _EvJobLinksClass EvJobLinksClass; @@ -111,6 +114,11 @@ typedef struct _EvJobPrintClass EvJobPrintClass; #define EV_JOB_THUMBNAIL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_THUMBNAIL, EvJobThumbnailClass)) #define EV_IS_JOB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_THUMBNAIL)) +#define EV_TYPE_JOB_WEB_THUMBNAIL (ev_job_web_thumbnail_get_type()) +#define EV_JOB_WEB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_WEB_THUMBNAIL, EvJobWebThumbnail)) +#define EV_JOB_WEB_THUMBNAIL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_WEB_THUMBNAIL, EvJobWebThumbnailClass)) +#define EV_IS_JOB_WEB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_WEB_THUMBNAIL)) + #define EV_TYPE_JOB_FONTS (ev_job_fonts_get_type()) #define EV_JOB_FONTS(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_FONTS, EvJobFonts)) #define EV_JOB_FONTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_FONTS, EvJobFontsClass)) @@ -281,11 +289,10 @@ struct _EvJobPageDataClass struct _EvJobThumbnail { EvJob parent; - gint page; gint rotation; gdouble scale; - + cairo_surface_t *surface; GdkPixbuf *thumbnail; }; @@ -343,6 +350,7 @@ struct _EvJobFind gint current_page; gint n_pages; GList **pages; + guint *results; gchar *text; gboolean case_sensitive; gboolean has_results; @@ -450,6 +458,7 @@ EvJob *ev_job_thumbnail_new (EvDocument *document, gint page, gint rotation, gdouble scale); + /* EvJobFonts */ GType ev_job_fonts_get_type (void) G_GNUC_CONST; EvJob *ev_job_fonts_new (EvDocument *document); diff --git a/libview/ev-view.c b/libview/ev-view.c index 7bb56cae..c39137c1 100644..100755 --- a/libview/ev-view.c +++ b/libview/ev-view.c @@ -840,6 +840,7 @@ set_scroll_adjustment (EvView *view, } #if !GTK_CHECK_VERSION (3, 0, 0) +void ev_view_set_scroll_adjustments (GtkLayout *layout, GtkAdjustment *hadjustment, GtkAdjustment *vadjustment) @@ -2242,7 +2243,7 @@ ev_view_form_field_choice_changed (GtkWidget *widget, { EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field); - if (GTK_IS_COMBO_BOX (widget)) { + if (gtk_combo_box_get_has_entry ( GTK_COMBO_BOX (widget))) { gint item; item = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); @@ -6568,3 +6569,41 @@ ev_view_previous_page (EvView *view) } } +/** + * ev_view_disconnect_handlers + * @view: #EvView instance + * + * Disconnect all signal handlers from the model, to ensure error free operation of the webview, + * we have an equivalent function for the webview. + */ +void +ev_view_disconnect_handlers(EvView *view) +{ + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_rotation_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_inverted_colors_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_sizing_mode_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_scale_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_continuous_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_dual_page_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_fullscreen_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_page_changed_cb), + view); + g_signal_handlers_disconnect_by_func(view->model, + G_CALLBACK (ev_view_document_changed_cb), + view); +} diff --git a/libview/ev-view.h b/libview/ev-view.h index 402b9895..0a9e1718 100644..100755 --- a/libview/ev-view.h +++ b/libview/ev-view.h @@ -110,6 +110,8 @@ void ev_view_begin_add_annotation (EvView *view, EvAnnotationType annot_type); void ev_view_cancel_add_annotation (EvView *view); +/*For epub*/ +void ev_view_disconnect_handlers (EvView *view); G_END_DECLS #endif /* __EV_VIEW_H__ */ diff --git a/libview/ev-web-view.c b/libview/ev-web-view.c new file mode 100644 index 00000000..40e525ea --- /dev/null +++ b/libview/ev-web-view.c @@ -0,0 +1,875 @@ +/* this file is part of atril, a mate document viewer + * + * Copyright (C) 2014 Avishkar Gupta + * Based on ev-view.c, also a part of atril, a mate document viewer. + * + * Atril 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. + * + * Atril 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE_EPUB +#include <glib/gi18n-lib.h> +#include <gtk/gtk.h> +#include <stdlib.h> + +#if GTK_CHECK_VERSION (3, 0, 0) +#include <webkit2/webkit2.h> +#else +#include <webkit/webkit.h> +#endif + +#include "ev-web-view.h" +#include "ev-document-model.h" +#include "ev-jobs.h" + +#define EV_WEB_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_WEB_VIEW, EvWebViewClass)) +#define EV_IS_WEB_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_WEB_VIEW)) +#define EV_WEB_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_WEB_VIEW, EvWebViewClass)) + + typedef enum { + EV_WEB_VIEW_FIND_NEXT, + EV_WEB_VIEW_FIND_PREV + } EvWebViewFindDirection; + +typedef struct _SearchParams { + gboolean case_sensitive; + gchar* search_string; + EvWebViewFindDirection direction; + gboolean search_jump; + gint on_result; + guint *results; +}SearchParams; + +struct _EvWebView +{ + WebKitWebView web_view; + EvDocument *document; + EvDocumentModel *model; + gint current_page; + gboolean inverted_stylesheet ; + gboolean fullscreen; + SearchParams *search; +#if GTK_CHECK_VERSION (3, 0, 0) + WebKitFindController *findcontroller; + WebKitFindOptions findoptions; + gdouble zoom_level; +#endif + gchar *hlink; +}; + +struct _EvWebViewClass +{ + WebKitWebViewClass base_class; +}; + +/*** Callbacks ***/ +static void ev_web_view_change_page (EvWebView *webview, + gint new_page); + +static void ev_web_view_page_changed_cb (EvDocumentModel *model, + gint old_page, + gint new_page, + EvWebView *webview); +/*** GObject ***/ +static void ev_web_view_dispose (GObject *object); + +static void ev_web_view_finalize (GObject *object); +static void ev_web_view_class_init (EvWebViewClass *klass); +static void ev_web_view_init (EvWebView *webview); + +G_DEFINE_TYPE (EvWebView, ev_web_view, WEBKIT_TYPE_WEB_VIEW) + +static void +web_view_update_range_and_current_page (EvWebView *webview) +{ + g_return_if_fail(EV_IS_WEB_VIEW(webview)); + + if (ev_document_get_n_pages (webview->document) <= 0) + return; + + ev_document_model_set_page(webview->model, 0); + webview->current_page = 0; + EvPage *webpage = ev_document_get_page(webview->document,0); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); +} + +static void +ev_web_view_dispose (GObject *object) +{ + EvWebView *webview = EV_WEB_VIEW (object); + + if (webview->document) { + g_object_unref(webview->document); + webview->document = NULL ; + } + + if (webview->model) { + g_object_unref(webview->model); + webview->model = NULL; + } + + if (webview->hlink) { + g_free(webview->hlink); + webview->hlink = NULL; + } + + if (webview->search) { + g_free(webview->search); + webview->search = NULL; + } + + G_OBJECT_CLASS (ev_web_view_parent_class)->dispose (object); +} + +static void +ev_web_view_class_init (EvWebViewClass *klass) +{ + G_OBJECT_CLASS(klass)->finalize = ev_web_view_finalize; + G_OBJECT_CLASS(klass)->dispose = ev_web_view_dispose; +} + +static void +ev_web_view_init (EvWebView *webview) +{ + gtk_widget_set_can_focus (GTK_WIDGET (webview), TRUE); + + gtk_widget_set_has_window (GTK_WIDGET (webview), TRUE); + + webview->current_page = 0; + + webview->search = g_new0(SearchParams, 1); + webview->search->search_string = NULL; + + webview->search->on_result = -1 ; + webview->search->results = NULL; + webview->search->search_jump = TRUE ; + + webview->fullscreen = FALSE; + webview->inverted_stylesheet = FALSE; + webview->hlink = NULL; +} + +static void +ev_web_view_finalize (GObject *object) +{ + G_OBJECT_CLASS(ev_web_view_parent_class)->finalize(object); +} + +/*** Callbacks ***/ + +static void +ev_web_view_change_page (EvWebView *webview, + gint new_page) +{ + g_return_if_fail(EV_IS_WEB_VIEW(webview)); + + EvDocumentClass *klass = EV_DOCUMENT_GET_CLASS(webview->document); + + webview->current_page = new_page; + ev_document_model_set_page(webview->model,new_page); +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_find_controller_search_finish(webview->findcontroller); +#else + webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(webview)); +#endif + if (webview->hlink) { + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webview->hlink); + g_free(webview->hlink); + webview->hlink = NULL; + } + else { + EvPage *page = klass->get_page(webview->document,new_page); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)page->backend_page); + } +} + +static void +ev_web_view_page_changed_cb (EvDocumentModel *model, + gint old_page, + gint new_page, + EvWebView *webview) +{ + if (!webview->document) + return; + + if (webview->current_page != new_page) { + ev_web_view_change_page (webview, new_page); + } else { + webkit_web_view_reload (WEBKIT_WEB_VIEW(webview)); + } +} + +GtkWidget* +ev_web_view_new (void) +{ + GtkWidget *webview; + + webview = g_object_new (EV_TYPE_WEB_VIEW, NULL); + + #if GTK_CHECK_VERSION (3, 0, 0) + EV_WEB_VIEW(webview)->findcontroller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW(webview)); + EV_WEB_VIEW(webview)->findoptions = webkit_find_controller_get_options (EV_WEB_VIEW(webview)->findcontroller); + + EV_WEB_VIEW(webview)->zoom_level = 1.0; + + EV_WEB_VIEW(webview)->findoptions |= WEBKIT_FIND_OPTIONS_NONE; + #endif + + return webview; +} + +static void +ev_web_view_document_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvWebView *webview) +{ + g_return_if_fail(EV_IS_WEB_VIEW(webview)); + + EvDocument *document = ev_document_model_get_document (model); + + if (document != webview->document) { + + if (webview->document ) + g_object_unref(webview->document); + + webview->document = document ; + + if(webview->document) { + g_object_ref(webview->document); + } + webview->inverted_stylesheet = FALSE; + gint current_page = ev_document_model_get_page(model); + + ev_web_view_change_page (webview, current_page); + + } +} + +static void +ev_web_view_inverted_colors_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvWebView *webview) +{ + EvDocument *document = ev_document_model_get_document(model); + + if (ev_document_model_get_inverted_colors(model) == TRUE) { + if (document == NULL) { + ev_document_model_set_inverted_colors(model,FALSE); + return; + } + if (webview->inverted_stylesheet == FALSE) { + ev_document_check_add_night_sheet(document); + webview->inverted_stylesheet = TRUE; + } + ev_document_toggle_night_mode(document,TRUE); + webkit_web_view_reload(WEBKIT_WEB_VIEW(webview)); + } + else { + if (document != NULL) { + ev_document_toggle_night_mode(document,FALSE); + webkit_web_view_reload(WEBKIT_WEB_VIEW(webview)); + } + } +} + +void +ev_web_view_set_model (EvWebView *webview, + EvDocumentModel *model) +{ + g_return_if_fail (EV_IS_WEB_VIEW (webview)); + g_return_if_fail (EV_IS_DOCUMENT_MODEL (model)); + + if (model == webview->model) + return; + + if (webview->model) { + g_signal_handlers_disconnect_by_func (webview->model, + ev_web_view_document_changed_cb, + webview); + g_signal_handlers_disconnect_by_func (webview->model, + ev_web_view_page_changed_cb, + webview); + g_object_unref (webview->model); + } + webview->model = g_object_ref (model); + + /* Initialize webview from model */ + webview->fullscreen = ev_document_model_get_fullscreen (webview->model); + webview->document = ev_document_model_get_document(webview->model); + + ev_web_view_document_changed_cb (webview->model, NULL, webview); + + g_signal_connect (webview->model, "notify::document", + G_CALLBACK (ev_web_view_document_changed_cb), + webview); + g_signal_connect (webview->model, "notify::inverted-colors", + G_CALLBACK (ev_web_view_inverted_colors_changed_cb), + webview); + g_signal_connect (webview->model,"page-changed", + G_CALLBACK(ev_web_view_page_changed_cb), + webview); +} + +void +ev_web_view_reload_page (EvWebView *webview, + gint page) +{ + webkit_web_view_reload (WEBKIT_WEB_VIEW(webview)); +} + +void +ev_web_view_reload (EvWebView *webview) +{ + web_view_update_range_and_current_page (webview); +} + + +gboolean +ev_web_view_next_page (EvWebView *webview) +{ + int page, n_pages; + + g_return_val_if_fail (EV_IS_WEB_VIEW (webview), FALSE); + + if (!webview->document) + return FALSE; + + page = ev_document_model_get_page (webview->model); + n_pages = ev_document_get_n_pages (webview->document); + + page = page + 1; + + if (page < n_pages) { + ev_document_model_set_page (webview->model, page); + EvPage *webpage = ev_document_get_page(webview->document,page); + webview->current_page = page ; + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); + return TRUE; + } else if (page == n_pages) { + ev_document_model_set_page (webview->model, page - 1); + EvPage *webpage = ev_document_get_page(webview->document,page); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); + return TRUE; + } else { + return FALSE; + } +} + +gboolean +ev_web_view_previous_page (EvWebView *webview) +{ + int page; + + g_return_val_if_fail (EV_IS_WEB_VIEW (webview), FALSE); + + if (!webview->document) + return FALSE; + + page = ev_document_model_get_page (webview->model); + + page = page - 1 ; + + if (page >= 0) { + ev_document_model_set_page (webview->model, page); + EvPage *webpage = ev_document_get_page(webview->document,page); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); + return TRUE; + } else if (page == -1) { + ev_document_model_set_page (webview->model, 0); + EvPage *webpage = ev_document_get_page(webview->document,page); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),(gchar*)webpage->backend_page); + return TRUE; + } else { + return FALSE; + } +} + +void +ev_web_view_handle_link(EvWebView *webview,EvLink *link) +{ + EvLinkAction *action = NULL; + EvLinkDest *dest = NULL; + EvLinkDestType dest_type ; + action = ev_link_get_action(link); + + if (action == NULL) + return; + + dest = ev_link_action_get_dest(action); + + if (dest == NULL) + return; + + dest_type = ev_link_dest_get_dest_type(dest); + + switch(dest_type) { + case EV_LINK_DEST_TYPE_PAGE: { + ev_document_model_set_page(webview->model,ev_link_dest_get_page(dest)); + break; + } + + case EV_LINK_DEST_TYPE_PAGE_LABEL: { + const gchar *text = ev_link_dest_get_page_label (dest); + gint page = atoi(text); + + if (page <= ev_document_get_n_pages(webview->document) && page > 0) { + ev_document_model_set_page(webview->model,page-1); + } + break; + } + case EV_LINK_DEST_TYPE_HLINK: { + const gchar *uri = ev_link_dest_get_named_dest(dest); + ev_document_model_set_page(webview->model,ev_link_dest_get_page(dest)); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview),uri); + break; + + default:return; + } + } +} +/* Searching */ + +#if !GTK_CHECK_VERSION (3, 0, 0) +static void +jump_to_find_result_on_page(EvWebView *webview, + EvWebViewFindDirection direction) +{ + gboolean forward,wrap; + + if (direction == EV_WEB_VIEW_FIND_NEXT) { + forward = TRUE; + wrap = FALSE; + } + else { + forward = FALSE; + wrap = FALSE; + } + + if (webview->search->search_jump) { + wrap = TRUE; + } + webkit_web_view_search_text (WEBKIT_WEB_VIEW(webview), + webview->search->search_string, + webview->search->case_sensitive, + forward, + wrap); + + webview->search->search_jump = FALSE; +} +#endif + +#if GTK_CHECK_VERSION (3, 0, 0) +static void +results_counted_cb(WebKitFindController *findcontroller, + guint match_count, + EvWebView *webview) +{ + if (match_count > 0 && webview->search->on_result < match_count) { + webkit_find_controller_search(findcontroller, + webview->search->search_string, + webview->findoptions, + match_count); + webview->search->search_jump = FALSE; + } +} +#endif +/* + * Jump to find results once we have changed the page in the webview. + */ +#if GTK_CHECK_VERSION (3, 0, 0) +static void +jump_to_find_results(EvWebView *webview, + WebKitLoadEvent load_event, + gpointer data) +#else +static void +jump_to_find_results(EvWebView *webview, + GParamSpec *pspec, + gpointer data) +#endif +{ + #if !GTK_CHECK_VERSION (3, 0, 0) + gint n_results; + gboolean forward ; + gboolean wrap ; + + if (webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(webview)) != WEBKIT_LOAD_FINISHED) { + return; + } +#else + if ( load_event != WEBKIT_LOAD_FINISHED) { + return; + } +#endif + if (!webview->search->search_string) { + return; + } + +#if GTK_CHECK_VERSION (3, 0, 0) + if (webview->search->direction == EV_WEB_VIEW_FIND_NEXT) { + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_BACKWARDS; + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_WRAP_AROUND; + } + else { + webview->findoptions |= WEBKIT_FIND_OPTIONS_BACKWARDS; + webview->findoptions |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + } + + webkit_find_controller_count_matches (webview->findcontroller, + webview->search->search_string, + webview->findoptions, + G_MAXUINT); +#else + n_results = webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW(webview), + webview->search->search_string, + webview->search->case_sensitive, + 0); + + ev_web_view_find_set_highlight_search(webview,TRUE); + + if (webview->search->direction == EV_WEB_VIEW_FIND_NEXT) { + forward = TRUE ; + wrap = FALSE; + } + else { + forward = FALSE; + wrap = TRUE ; + } + + if (n_results > 0 && webview->search->on_result < n_results) { + webkit_web_view_search_text (WEBKIT_WEB_VIEW(webview), + webview->search->search_string, + webview->search->case_sensitive, + forward, + wrap); + + webview->search->search_jump = FALSE; + } +#endif + webview->search->search_jump = FALSE; +} + +static gint +ev_web_view_find_get_n_results (EvWebView *webview, gint page) +{ + return webview->search->results[page]; +} + +/** + * jump_to_find_page + * @webview: #EvWebView instance + * @direction: Direction to look + * @shift: Shift from current page + * + * Jumps to the first page that has occurences of searched word. + * Uses a direction where to look and a shift from current page. +**/ +static void +jump_to_find_page (EvWebView *webview, EvWebViewFindDirection direction, gint shift) +{ + int n_pages, i; + + n_pages = ev_document_get_n_pages (webview->document); + + for (i = 0; i < n_pages; i++) { + int page; + + if (direction == EV_WEB_VIEW_FIND_NEXT) + page = webview->current_page + i; + else + page = webview->current_page - i; + page += shift; + + if (page >= n_pages) { + page = page - n_pages; + } else if (page < 0) + page = page + n_pages; + + if (page == webview->current_page && ev_web_view_find_get_n_results(webview,page) > 0) { +#if !GTK_CHECK_VERSION (3, 0, 0) + jump_to_find_result_on_page(webview,EV_WEB_VIEW_FIND_NEXT); +#else + if (direction == EV_WEB_VIEW_FIND_PREV) { + webview->findoptions |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + webview->findoptions |= WEBKIT_FIND_OPTIONS_BACKWARDS; + } + else { + if (webview->search->search_jump) + webview->findoptions |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + else + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_WRAP_AROUND; + + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_BACKWARDS; + } + + webkit_find_controller_search (webview->findcontroller, + webview->search->search_string, + webview->findoptions, + /*Highlight all the results.*/ + G_MAXUINT); + webview->search->search_jump = FALSE; +#endif + break; + } + + if (ev_web_view_find_get_n_results (webview, page) > 0) { + webview->search->direction = direction; +#if !GTK_CHECK_VERSION (3, 0, 0) + webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(webview)); +#else + webkit_find_controller_search_finish(webview->findcontroller); +#endif + ev_document_model_set_page (webview->model, page); + break; + } + } +} + +void +ev_web_view_find_changed (EvWebView *webview, guint *results, gchar *text,gboolean case_sensitive) +{ + webview->search->results = results; + webview->search->on_result = 0; + webview->search->search_string = g_strdup(text); + webview->search->case_sensitive = case_sensitive; + if (webview->search->search_jump == TRUE) { +#if GTK_CHECK_VERSION (3, 0, 0) + if (!case_sensitive) { + webview->findoptions |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE; + } + else { + webview->findoptions &= ~WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE; + } +#endif + jump_to_find_page (webview, EV_WEB_VIEW_FIND_NEXT, 0); + } +} + +void +ev_web_view_find_next (EvWebView *webview) +{ + gint n_results; + + n_results = ev_web_view_find_get_n_results (webview, webview->current_page); + webview->search->on_result++; + + if (webview->search->on_result >= n_results) { + webview->search->on_result = 0; + jump_to_find_page (webview, EV_WEB_VIEW_FIND_NEXT, 1); + } + else { +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_find_controller_search_next(webview->findcontroller); +#else + jump_to_find_result_on_page (webview, EV_WEB_VIEW_FIND_NEXT); +#endif + } +} + +void +ev_web_view_find_previous (EvWebView *webview) +{ + webview->search->on_result--; + + if (webview->search->on_result < 0) { + jump_to_find_page (webview, EV_WEB_VIEW_FIND_PREV, -1); + webview->search->on_result = MAX (0, ev_web_view_find_get_n_results (webview, webview->current_page) - 1); + } else { +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_find_controller_search_previous(webview->findcontroller); +#else + jump_to_find_result_on_page (webview,EV_WEB_VIEW_FIND_PREV); +#endif + } +} + +void +ev_web_view_find_search_changed (EvWebView *webview) +{ + /* search string has changed, focus on new search result */ +#if !GTK_CHECK_VERSION(3, 0, 0) + webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webview)); +#endif + if (webview->search->search_string) { + g_free(webview->search->search_string); + webview->search->search_string = NULL; + } +#if GTK_CHECK_VERSION(3, 0, 0) + webkit_find_controller_search_finish(webview->findcontroller); +#endif + + webview->search->search_jump = TRUE; +} + +#if !GTK_CHECK_VERSION (3, 0, 0) +void +ev_web_view_find_set_highlight_search (EvWebView *webview, gboolean value) +{ + webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW(webview),value); +} +#endif + +void +ev_web_view_find_cancel (EvWebView *webview) +{ +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_find_controller_search_finish (webview->findcontroller); +#else + webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webview)); + ev_web_view_find_set_highlight_search(webview,FALSE); +#endif +} + + + +void +ev_web_view_set_handler(EvWebView *webview,gboolean visible) +{ + if (visible) { + g_signal_connect(webview, +#if GTK_CHECK_VERSION (3, 0, 0) + "load-changed", +#else + "notify::load-status", +#endif + G_CALLBACK(jump_to_find_results), + NULL); +#if GTK_CHECK_VERSION (3, 0, 0) + g_signal_connect(webview->findcontroller, + "counted-matches", + G_CALLBACK(results_counted_cb), + webview); +#endif + } + else { + g_signal_handlers_disconnect_by_func(webview, + jump_to_find_results, + NULL); +#if GTK_CHECK_VERSION (3, 0, 0) + g_signal_handlers_disconnect_by_func(webview, + results_counted_cb, + NULL); +#endif + } +} + +/* Selection and copying*/ +#if !GTK_CHECK_VERSION (3, 0, 0) +gboolean +ev_web_view_get_has_selection(EvWebView *webview) +{ + return webkit_web_view_has_selection(WEBKIT_WEB_VIEW(webview)); +} +#endif + +void +ev_web_view_select_all(EvWebView *webview) +{ +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_web_view_execute_editing_command(WEBKIT_WEB_VIEW(webview), + WEBKIT_EDITING_COMMAND_SELECT_ALL); +#else + webkit_web_view_select_all(WEBKIT_WEB_VIEW(webview)); +#endif +} + +#if GTK_CHECK_VERSION (3, 0, 0) +static void +copy_text_cb(WebKitWebView *webview, + GAsyncResult *res, + gpointer data) +{ + gboolean okay_to_copy = webkit_web_view_can_execute_editing_command_finish (WEBKIT_WEB_VIEW(webview), + res, + NULL); + + if (okay_to_copy) { + webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW(webview), + WEBKIT_EDITING_COMMAND_COPY); + } +} +#endif + +void +ev_web_view_copy(EvWebView *webview) +{ +#if !GTK_CHECK_VERSION (3, 0, 0) + /* If for some reason we don't have a selection any longer,best to be safe */ + if (ev_web_view_get_has_selection(webview) == FALSE) + return; + if (webkit_web_view_can_copy_clipboard(WEBKIT_WEB_VIEW(webview))) { + webkit_web_view_copy_clipboard(WEBKIT_WEB_VIEW(webview)); + } +#else + webkit_web_view_can_execute_editing_command(WEBKIT_WEB_VIEW(webview), + WEBKIT_EDITING_COMMAND_COPY, + NULL, + (GAsyncReadyCallback)copy_text_cb, + NULL); + +#endif + +} + +/*Zoom control*/ +gboolean +ev_web_view_zoom_in(EvWebView *webview) +{ +#if GTK_CHECK_VERSION (3, 0, 0) + webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW(webview), + (webview->zoom_level+= 0.1)); +#else + webkit_web_view_zoom_in(WEBKIT_WEB_VIEW(webview)); +#endif + return TRUE; +} + +gboolean +ev_web_view_zoom_out(EvWebView *webview) +{ +#if GTK_CHECK_VERSION (3, 0, 0) + if (webview->zoom_level == 1) + return FALSE; + + webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW(webview), + (webview->zoom_level -= 0.1)); +#else + webkit_web_view_zoom_out(WEBKIT_WEB_VIEW(webview)); +#endif + return TRUE; +} + +/** + * ev_web_view_disconnect_handlers + * @webview : #EvWebView instance + * + * This function call will disconnect all model signal handlers from the webview, to ensure smooth operation of the Atril-view. + * Equivalent to function ev_view_disconnect_handlers in ev-view.c + */ +void +ev_web_view_disconnect_handlers(EvWebView *webview) +{ + g_signal_handlers_disconnect_by_func(webview->model, + ev_web_view_document_changed_cb, + webview); + g_signal_handlers_disconnect_by_func(webview->model, + ev_web_view_inverted_colors_changed_cb, + webview); + g_signal_handlers_disconnect_by_func(webview->model, + ev_web_view_page_changed_cb, + webview); +} +#endif diff --git a/libview/ev-web-view.h b/libview/ev-web-view.h new file mode 100644 index 00000000..42345ca1 --- /dev/null +++ b/libview/ev-web-view.h @@ -0,0 +1,92 @@ +/* this file is part of atril, a mate document viewer + * + * Copyright (C) 2014 Avishkar Gupta + * Based on ev-view.h, also a part of atril, a mate document viewer + * + * Atril 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. + * + * Atril 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#if !defined (__EV_ATRIL_VIEW_H_INSIDE__) && !defined (ATRIL_COMPILATION) +#error "Only <atril-view.h> can be included directly." +#endif + +#include "config.h" +#if ENABLE_EPUB +#ifndef __EV_WEB_VIEW_H__ +#define __EV_WEB_VIEW_H__ + +#include <gtk/gtk.h> + +#include <atril-document.h> +#include "ev-jobs.h" +#include "ev-document-model.h" +#include <glib-object.h> +G_BEGIN_DECLS + + +typedef struct _EvWebView EvWebView; +typedef struct _EvWebViewClass EvWebViewClass; + +#define EV_TYPE_WEB_VIEW (ev_web_view_get_type ()) +#define EV_WEB_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_WEB_VIEW, EvWebView)) +#define EV_IS_WEB_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_WEB_VIEW)) + +GType ev_web_view_get_type (void) G_GNUC_CONST; + +GtkWidget* ev_web_view_new (void); + +void ev_web_view_set_model (EvWebView *webview, + EvDocumentModel *model); + +void ev_web_view_reload (EvWebView *webview); + +void ev_web_view_reload_page (EvWebView *webview, + gint page); + +/* Navigation */ +gboolean ev_web_view_next_page (EvWebView *webview); +gboolean ev_web_view_previous_page (EvWebView *webview); + +/* Sidebar links */ +void ev_web_view_handle_link (EvWebView *webview, EvLink* link); + +/* Searching */ +void ev_web_view_find_next (EvWebView *webview); +void ev_web_view_find_previous (EvWebView *webview); + +void ev_web_view_find_changed (EvWebView *webview, + guint *results, + gchar *text, + gboolean case_sensitive); + +void ev_web_view_find_search_changed (EvWebView *webview); +void ev_web_view_find_cancel (EvWebView *webview); +void ev_web_view_find_set_highlight_search (EvWebView *webview,gboolean visible); +void ev_web_view_set_handler (EvWebView *webview,gboolean visible); +/* Selection */ +gboolean ev_web_view_get_has_selection (EvWebView *webview); +void ev_web_view_select_all (EvWebView *webview); +void ev_web_view_copy (EvWebView *webview); + +/* Zoom control */ +gboolean ev_web_view_zoom_in (EvWebView *webview); +gboolean ev_web_view_zoom_out (EvWebView *webview); + +/*For safe replacement by an EvView*/ +void ev_web_view_disconnect_handlers (EvWebView *webview); +G_END_DECLS + +#endif /* __EV_WEB_VIEW_H__ */ +#endif /* ENABLE_EPUB */ |