1
0
mirror of https://gitlab.gnome.org/GNOME/evince synced 2024-06-30 22:54:23 +00:00
evince/libview/ev-jobs.c
Pablo Correa Gómez 19babb9114 Use G_SOURCE_CONTINUE and G_SOURCE_REMOVE when appropriate
Instead of directly TRUE and FALSE, to improve readability. These are
used in GSourceFunc functions, and represent no change in behavior!
2023-05-20 15:35:48 +00:00

2337 lines
59 KiB
C

/* this file is part of evince, a gnome document viewer
*
* Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
* Copyright (C) 2005 Red Hat, Inc
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <config.h>
#include "ev-jobs.h"
#include "ev-document-links.h"
#include "ev-document-images.h"
#include "ev-document-forms.h"
#include "ev-file-exporter.h"
#include "ev-document-factory.h"
#include "ev-document-misc.h"
#include "ev-file-helpers.h"
#include "ev-document-fonts.h"
#include "ev-document-security.h"
#include "ev-document-find.h"
#include "ev-document-layers.h"
#include "ev-document-print.h"
#include "ev-document-annotations.h"
#include "ev-document-attachments.h"
#include "ev-document-media.h"
#include "ev-document-text.h"
#include "ev-debug.h"
#include <errno.h>
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
#include <unistd.h>
#include <fcntl.h>
typedef struct _EvJobLoadStreamPrivate EvJobLoadStreamPrivate;
struct _EvJobLoadStreamPrivate
{
char *mime_type;
};
static void ev_job_init (EvJob *job);
static void ev_job_class_init (EvJobClass *class);
static void ev_job_links_init (EvJobLinks *job);
static void ev_job_links_class_init (EvJobLinksClass *class);
static void ev_job_attachments_init (EvJobAttachments *job);
static void ev_job_attachments_class_init (EvJobAttachmentsClass *class);
static void ev_job_annots_init (EvJobAnnots *job);
static void ev_job_annots_class_init (EvJobAnnotsClass *class);
static void ev_job_render_init (EvJobRender *job);
static void ev_job_render_class_init (EvJobRenderClass *class);
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_save_init (EvJobSave *job);
static void ev_job_save_class_init (EvJobSaveClass *class);
static void ev_job_find_init (EvJobFind *job);
static void ev_job_find_class_init (EvJobFindClass *class);
static void ev_job_layers_init (EvJobLayers *job);
static void ev_job_layers_class_init (EvJobLayersClass *class);
static void ev_job_export_init (EvJobExport *job);
static void ev_job_export_class_init (EvJobExportClass *class);
static void ev_job_print_init (EvJobPrint *job);
static void ev_job_print_class_init (EvJobPrintClass *class);
enum {
CANCELLED,
FINISHED,
LAST_SIGNAL
};
enum {
FONTS_UPDATED,
FONTS_LAST_SIGNAL
};
enum {
FIND_UPDATED,
FIND_LAST_SIGNAL
};
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 };
G_DEFINE_ABSTRACT_TYPE (EvJob, ev_job, G_TYPE_OBJECT)
G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobAttachments, ev_job_attachments, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobAnnots, ev_job_annots, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobPageData, ev_job_page_data, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
G_DEFINE_TYPE_WITH_PRIVATE (EvJobLoadStream, ev_job_load_stream, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobLoadGFile, ev_job_load_gfile, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobLoadFd, ev_job_load_fd, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobFind, ev_job_find, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobLayers, ev_job_layers, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobExport, ev_job_export, EV_TYPE_JOB)
G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
/* EvJob */
static void
ev_job_init (EvJob *job)
{
job->cancellable = g_cancellable_new ();
}
static void
ev_job_dispose (GObject *object)
{
EvJob *job;
job = EV_JOB (object);
g_clear_object (&job->document);
g_clear_object (&job->cancellable);
g_clear_error (&job->error);
(* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object);
}
static void
ev_job_class_init (EvJobClass *class)
{
GObjectClass *oclass;
oclass = G_OBJECT_CLASS (class);
oclass->dispose = ev_job_dispose;
job_signals[CANCELLED] =
g_signal_new ("cancelled",
EV_TYPE_JOB,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EvJobClass, cancelled),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
job_signals [FINISHED] =
g_signal_new ("finished",
EV_TYPE_JOB,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (EvJobClass, finished),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static gboolean
emit_finished (EvJob *job)
{
ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
job->idle_finished_id = 0;
if (job->cancelled) {
ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, do not emit finished", EV_GET_TYPE_NAME (job), job);
} else {
ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
g_signal_emit (job, job_signals[FINISHED], 0);
}
return G_SOURCE_REMOVE;
}
static void
ev_job_emit_finished (EvJob *job)
{
ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
if (g_cancellable_is_cancelled (job->cancellable)) {
ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, returning", EV_GET_TYPE_NAME (job), job);
return;
}
job->finished = TRUE;
if (job->run_mode == EV_JOB_RUN_THREAD) {
job->idle_finished_id =
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
(GSourceFunc)emit_finished,
g_object_ref (job),
(GDestroyNotify)g_object_unref);
} else {
ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
g_signal_emit (job, job_signals[FINISHED], 0);
}
}
gboolean
ev_job_run (EvJob *job)
{
EvJobClass *class = EV_JOB_GET_CLASS (job);
return class->run (job);
}
void
ev_job_cancel (EvJob *job)
{
if (job->cancelled)
return;
ev_debug_message (DEBUG_JOBS, "job %s (%p) cancelled", EV_GET_TYPE_NAME (job), job);
ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
/* This should never be called from a thread */
job->cancelled = TRUE;
g_cancellable_cancel (job->cancellable);
if (job->finished && job->idle_finished_id == 0)
return;
g_signal_emit (job, job_signals[CANCELLED], 0);
}
void
ev_job_failed (EvJob *job,
GQuark domain,
gint code,
const gchar *format,
...)
{
va_list args;
gchar *message;
if (job->failed || job->finished)
return;
ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
job->failed = TRUE;
va_start (args, format);
message = g_strdup_vprintf (format, args);
va_end (args);
job->error = g_error_new_literal (domain, code, message);
g_free (message);
ev_job_emit_finished (job);
}
/**
* ev_job_failed_from_error: (rename-to ev_job_failed)
* @job: an #EvJob
* @error: a #GError
*/
void
ev_job_failed_from_error (EvJob *job,
GError *error)
{
if (job->failed || job->finished)
return;
ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
job->failed = TRUE;
job->error = g_error_copy (error);
ev_job_emit_finished (job);
}
void
ev_job_succeeded (EvJob *job)
{
if (job->finished)
return;
ev_debug_message (DEBUG_JOBS, "job %s (%p) succeeded", EV_GET_TYPE_NAME (job), job);
job->failed = FALSE;
ev_job_emit_finished (job);
}
gboolean
ev_job_is_finished (EvJob *job)
{
return job->finished;
}
gboolean
ev_job_is_failed (EvJob *job)
{
return job->failed;
}
EvJobRunMode
ev_job_get_run_mode (EvJob *job)
{
return job->run_mode;
}
void
ev_job_set_run_mode (EvJob *job,
EvJobRunMode run_mode)
{
job->run_mode = run_mode;
}
/* EvJobLinks */
static void
ev_job_links_init (EvJobLinks *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_links_dispose (GObject *object)
{
EvJobLinks *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = EV_JOB_LINKS (object);
g_clear_object (&job->model);
(* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object);
}
static gboolean
fill_page_labels (GtkTreeModel *tree_model,
GtkTreePath *path,
GtkTreeIter *iter,
EvJob *job)
{
EvDocumentLinks *document_links;
EvLink *link;
gchar *page_label;
gtk_tree_model_get (tree_model, iter,
EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
-1);
if (!link)
return FALSE;
document_links = EV_DOCUMENT_LINKS (job->document);
page_label = ev_document_links_get_link_page_label (document_links, link);
if (!page_label)
return FALSE;
gtk_tree_store_set (GTK_TREE_STORE (tree_model), iter,
EV_DOCUMENT_LINKS_COLUMN_PAGE_LABEL, page_label,
-1);
g_free (page_label);
g_object_unref (link);
return FALSE;
}
static gboolean
ev_job_links_run (EvJob *job)
{
EvJobLinks *job_links = EV_JOB_LINKS (job);
ev_debug_message (DEBUG_JOBS, NULL);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_doc_mutex_lock ();
job_links->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (job->document));
ev_document_doc_mutex_unlock ();
gtk_tree_model_foreach (job_links->model, (GtkTreeModelForeachFunc)fill_page_labels, job);
ev_job_succeeded (job);
return FALSE;
}
static void
ev_job_links_class_init (EvJobLinksClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_links_dispose;
job_class->run = ev_job_links_run;
}
EvJob *
ev_job_links_new (EvDocument *document)
{
EvJob *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
job->document = g_object_ref (document);
return job;
}
/**
* ev_job_links_get_model:
* @job: #EvJobLinks
*
* Get a #GtkTreeModel loaded with the links
*
* Return value: (transfer none): The #GtkTreeModel loaded
*
* Since: 3.6
*/
GtkTreeModel *
ev_job_links_get_model (EvJobLinks *job)
{
return job->model;
}
/* EvJobAttachments */
static void
ev_job_attachments_init (EvJobAttachments *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_attachments_dispose (GObject *object)
{
EvJobAttachments *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = EV_JOB_ATTACHMENTS (object);
g_list_free_full (g_steal_pointer (&job->attachments), g_object_unref);
(* G_OBJECT_CLASS (ev_job_attachments_parent_class)->dispose) (object);
}
static gboolean
ev_job_attachments_run (EvJob *job)
{
EvJobAttachments *job_attachments = EV_JOB_ATTACHMENTS (job);
ev_debug_message (DEBUG_JOBS, NULL);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_doc_mutex_lock ();
job_attachments->attachments =
ev_document_attachments_get_attachments (EV_DOCUMENT_ATTACHMENTS (job->document));
ev_document_doc_mutex_unlock ();
ev_job_succeeded (job);
return FALSE;
}
static void
ev_job_attachments_class_init (EvJobAttachmentsClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_attachments_dispose;
job_class->run = ev_job_attachments_run;
}
EvJob *
ev_job_attachments_new (EvDocument *document)
{
EvJob *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = g_object_new (EV_TYPE_JOB_ATTACHMENTS, NULL);
job->document = g_object_ref (document);
return job;
}
/* EvJobAnnots */
static void
ev_job_annots_init (EvJobAnnots *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_annots_dispose (GObject *object)
{
EvJobAnnots *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = EV_JOB_ANNOTS (object);
g_list_free_full (g_steal_pointer (&job->annots), (GDestroyNotify) ev_mapping_list_unref);
G_OBJECT_CLASS (ev_job_annots_parent_class)->dispose (object);
}
static gboolean
ev_job_annots_run (EvJob *job)
{
EvJobAnnots *job_annots = EV_JOB_ANNOTS (job);
gint i;
ev_debug_message (DEBUG_JOBS, NULL);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_doc_mutex_lock ();
for (i = 0; i < ev_document_get_n_pages (job->document); i++) {
EvMappingList *mapping_list;
EvPage *page;
page = ev_document_get_page (job->document, i);
mapping_list = ev_document_annotations_get_annotations (EV_DOCUMENT_ANNOTATIONS (job->document),
page);
g_object_unref (page);
if (mapping_list)
job_annots->annots = g_list_prepend (job_annots->annots, mapping_list);
}
ev_document_doc_mutex_unlock ();
job_annots->annots = g_list_reverse (job_annots->annots);
ev_job_succeeded (job);
return FALSE;
}
static void
ev_job_annots_class_init (EvJobAnnotsClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_annots_dispose;
job_class->run = ev_job_annots_run;
}
EvJob *
ev_job_annots_new (EvDocument *document)
{
EvJob *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = g_object_new (EV_TYPE_JOB_ANNOTS, NULL);
job->document = g_object_ref (document);
return job;
}
/* EvJobRender */
static void
ev_job_render_init (EvJobRender *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_render_dispose (GObject *object)
{
EvJobRender *job;
job = EV_JOB_RENDER (object);
ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job->page, job);
g_clear_pointer (&job->surface, cairo_surface_destroy);
g_clear_pointer (&job->selection, cairo_surface_destroy);
g_clear_pointer (&job->selection_region, cairo_region_destroy);
(* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
}
static gboolean
ev_job_render_run (EvJob *job)
{
EvJobRender *job_render = EV_JOB_RENDER (job);
EvPage *ev_page;
EvRenderContext *rc;
ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job_render->page, job);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_doc_mutex_lock ();
ev_profiler_start (EV_PROFILE_JOBS, "Rendering page %d", job_render->page);
ev_document_fc_mutex_lock ();
ev_page = ev_document_get_page (job->document, job_render->page);
rc = ev_render_context_new (ev_page, job_render->rotation, job_render->scale);
ev_render_context_set_target_size (rc,
job_render->target_width, job_render->target_height);
g_object_unref (ev_page);
job_render->surface = ev_document_render (job->document, rc);
if (job_render->surface == NULL ||
cairo_surface_status (job_render->surface) != CAIRO_STATUS_SUCCESS) {
ev_document_fc_mutex_unlock ();
ev_document_doc_mutex_unlock ();
g_object_unref (rc);
if (job_render->surface != NULL) {
cairo_status_t status = cairo_surface_status (job_render->surface);
ev_job_failed (job,
EV_DOCUMENT_ERROR,
EV_DOCUMENT_ERROR_INVALID,
_("Failed to render page %d: %s"),
job_render->page,
cairo_status_to_string (status));
} else {
ev_job_failed (job,
EV_DOCUMENT_ERROR,
EV_DOCUMENT_ERROR_INVALID,
_("Failed to render page %d"),
job_render->page);
}
return FALSE;
}
/* If job was cancelled during the page rendering,
* we return now, so that the thread is finished ASAP
*/
if (g_cancellable_is_cancelled (job->cancellable)) {
ev_document_fc_mutex_unlock ();
ev_document_doc_mutex_unlock ();
g_object_unref (rc);
return FALSE;
}
if (job_render->include_selection && EV_IS_SELECTION (job->document)) {
ev_selection_render_selection (EV_SELECTION (job->document),
rc,
&(job_render->selection),
&(job_render->selection_points),
NULL,
job_render->selection_style,
&(job_render->text), &(job_render->base));
job_render->selection_region =
ev_selection_get_selection_region (EV_SELECTION (job->document),
rc,
job_render->selection_style,
&(job_render->selection_points));
}
g_object_unref (rc);
ev_document_fc_mutex_unlock ();
ev_document_doc_mutex_unlock ();
ev_job_succeeded (job);
return FALSE;
}
static void
ev_job_render_class_init (EvJobRenderClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_render_dispose;
job_class->run = ev_job_render_run;
}
EvJob *
ev_job_render_new (EvDocument *document,
gint page,
gint rotation,
gdouble scale,
gint width,
gint height)
{
EvJobRender *job;
ev_debug_message (DEBUG_JOBS, "page: %d", page);
job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
EV_JOB (job)->document = g_object_ref (document);
job->page = page;
job->rotation = rotation;
job->scale = scale;
job->target_width = width;
job->target_height = height;
return EV_JOB (job);
}
void
ev_job_render_set_selection_info (EvJobRender *job,
EvRectangle *selection_points,
EvSelectionStyle selection_style,
GdkColor *text,
GdkColor *base)
{
job->include_selection = TRUE;
job->selection_points = *selection_points;
job->selection_style = selection_style;
job->text = *text;
job->base = *base;
}
/* EvJobPageData */
static void
ev_job_page_data_init (EvJobPageData *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static gboolean
ev_job_page_data_run (EvJob *job)
{
EvJobPageData *job_pd = EV_JOB_PAGE_DATA (job);
EvPage *ev_page;
ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job_pd->page, job);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_doc_mutex_lock ();
ev_page = ev_document_get_page (job->document, job_pd->page);
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_TEXT_MAPPING) && EV_IS_DOCUMENT_TEXT (job->document))
job_pd->text_mapping =
ev_document_text_get_text_mapping (EV_DOCUMENT_TEXT (job->document), ev_page);
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_TEXT) && EV_IS_DOCUMENT_TEXT (job->document))
job_pd->text =
ev_document_text_get_text (EV_DOCUMENT_TEXT (job->document), ev_page);
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT) && EV_IS_DOCUMENT_TEXT (job->document))
ev_document_text_get_text_layout (EV_DOCUMENT_TEXT (job->document),
ev_page,
&(job_pd->text_layout),
&(job_pd->text_layout_length));
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_TEXT_ATTRS) && EV_IS_DOCUMENT_TEXT (job->document))
job_pd ->text_attrs =
ev_document_text_get_text_attrs (EV_DOCUMENT_TEXT (job->document),
ev_page);
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_TEXT_LOG_ATTRS) && job_pd->text) {
job_pd->text_log_attrs_length = g_utf8_strlen (job_pd->text, -1);
job_pd->text_log_attrs = g_new0 (PangoLogAttr, job_pd->text_log_attrs_length + 1);
/* FIXME: We need API to get the language of the document */
pango_get_log_attrs (job_pd->text, -1, -1, NULL, job_pd->text_log_attrs, job_pd->text_log_attrs_length + 1);
}
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (job->document))
job_pd->link_mapping =
ev_document_links_get_links (EV_DOCUMENT_LINKS (job->document), ev_page);
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (job->document))
job_pd->form_field_mapping =
ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (job->document),
ev_page);
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (job->document))
job_pd->image_mapping =
ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (job->document),
ev_page);
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_ANNOTS) && EV_IS_DOCUMENT_ANNOTATIONS (job->document))
job_pd->annot_mapping =
ev_document_annotations_get_annotations (EV_DOCUMENT_ANNOTATIONS (job->document),
ev_page);
if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_MEDIA) && EV_IS_DOCUMENT_MEDIA (job->document))
job_pd->media_mapping =
ev_document_media_get_media_mapping (EV_DOCUMENT_MEDIA (job->document),
ev_page);
g_object_unref (ev_page);
ev_document_doc_mutex_unlock ();
ev_job_succeeded (job);
return FALSE;
}
static void
ev_job_page_data_class_init (EvJobPageDataClass *class)
{
EvJobClass *job_class = EV_JOB_CLASS (class);
job_class->run = ev_job_page_data_run;
}
EvJob *
ev_job_page_data_new (EvDocument *document,
gint page,
EvJobPageDataFlags flags)
{
EvJobPageData *job;
ev_debug_message (DEBUG_JOBS, "%d", page);
job = g_object_new (EV_TYPE_JOB_PAGE_DATA, NULL);
EV_JOB (job)->document = g_object_ref (document);
job->page = page;
job->flags = flags;
return EV_JOB (job);
}
/* EvJobThumbnail */
static void
ev_job_thumbnail_init (EvJobThumbnail *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_thumbnail_dispose (GObject *object)
{
EvJobThumbnail *job;
job = EV_JOB_THUMBNAIL (object);
ev_debug_message (DEBUG_JOBS, "%d (%p)", job->page, job);
g_clear_object (&job->thumbnail);
g_clear_pointer (&job->thumbnail_surface, cairo_surface_destroy);
(* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object);
}
static gboolean
ev_job_thumbnail_run (EvJob *job)
{
EvJobThumbnail *job_thumb = EV_JOB_THUMBNAIL (job);
EvRenderContext *rc;
GdkPixbuf *pixbuf = NULL;
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 ();
page = ev_document_get_page (job->document, job_thumb->page);
rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale);
ev_render_context_set_target_size (rc,
job_thumb->target_width, job_thumb->target_height);
g_object_unref (page);
if (job_thumb->format == EV_JOB_THUMBNAIL_PIXBUF)
pixbuf = ev_document_get_thumbnail (job->document, rc);
else
job_thumb->thumbnail_surface = ev_document_get_thumbnail_surface (job->document, rc);
g_object_unref (rc);
ev_document_doc_mutex_unlock ();
/* EV_JOB_THUMBNAIL_SURFACE is not compatible with has_frame = TRUE */
if (job_thumb->format == EV_JOB_THUMBNAIL_PIXBUF && pixbuf) {
job_thumb->thumbnail = job_thumb->has_frame ?
ev_document_misc_get_thumbnail_frame (-1, -1, pixbuf) : g_object_ref (pixbuf);
g_object_unref (pixbuf);
}
if ((job_thumb->format == EV_JOB_THUMBNAIL_PIXBUF && pixbuf == NULL) ||
(job_thumb->format != EV_JOB_THUMBNAIL_PIXBUF && job_thumb->thumbnail_surface == NULL)) {
ev_job_failed (job,
EV_DOCUMENT_ERROR,
EV_DOCUMENT_ERROR_INVALID,
_("Failed to create thumbnail for page %d"),
job_thumb->page);
} else {
ev_job_succeeded (job);
}
return FALSE;
}
static void
ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_thumbnail_dispose;
job_class->run = ev_job_thumbnail_run;
}
EvJob *
ev_job_thumbnail_new (EvDocument *document,
gint page,
gint rotation,
gdouble scale)
{
EvJobThumbnail *job;
ev_debug_message (DEBUG_JOBS, "%d", page);
job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
EV_JOB (job)->document = g_object_ref (document);
job->page = page;
job->rotation = rotation;
job->scale = scale;
job->has_frame = TRUE;
job->format = EV_JOB_THUMBNAIL_PIXBUF;
job->target_width = -1;
job->target_height = -1;
return EV_JOB (job);
}
EvJob *
ev_job_thumbnail_new_with_target_size (EvDocument *document,
gint page,
gint rotation,
gint target_width,
gint target_height)
{
EvJob *job = ev_job_thumbnail_new (document, page, rotation, 1.);
EvJobThumbnail *job_thumb = EV_JOB_THUMBNAIL (job);
job_thumb->target_width = target_width;
job_thumb->target_height = target_height;
return job;
}
/**
* ev_job_thumbnail_set_has_frame:
* @job:
* @has_frame:
*
* Since: 3.8
*/
void
ev_job_thumbnail_set_has_frame (EvJobThumbnail *job,
gboolean has_frame)
{
job->has_frame = has_frame;
}
/**
* ev_job_thumbnail_set_output_format:
* @job: a #EvJobThumbnail
* @format: a #EvJobThumbnailFormat
*
* Set the desired output format for the generated thumbnail
*
* Since: 3.14
*/
void
ev_job_thumbnail_set_output_format (EvJobThumbnail *job,
EvJobThumbnailFormat format)
{
job->format = format;
}
/* EvJobFonts */
static void
ev_job_fonts_init (EvJobFonts *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
}
static gboolean
ev_job_fonts_run (EvJob *job)
{
EvJobFonts *job_fonts = EV_JOB_FONTS (job);
EvDocumentFonts *fonts = EV_DOCUMENT_FONTS (job->document);
ev_debug_message (DEBUG_JOBS, NULL);
/* Do not block the main loop */
if (!ev_document_doc_mutex_trylock ())
return TRUE;
if (!ev_document_fc_mutex_trylock ())
return TRUE;
#ifdef EV_ENABLE_DEBUG
/* We use the #ifdef in this case because of the if */
if (ev_document_fonts_get_progress (fonts) == 0)
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
#endif
job_fonts->scan_completed = !ev_document_fonts_scan (fonts, 20);
g_signal_emit (job_fonts, job_fonts_signals[FONTS_UPDATED], 0,
ev_document_fonts_get_progress (fonts));
ev_document_fc_mutex_unlock ();
ev_document_doc_mutex_unlock ();
if (job_fonts->scan_completed)
ev_job_succeeded (job);
return !job_fonts->scan_completed;
}
static void
ev_job_fonts_class_init (EvJobFontsClass *class)
{
EvJobClass *job_class = EV_JOB_CLASS (class);
job_class->run = ev_job_fonts_run;
job_fonts_signals[FONTS_UPDATED] =
g_signal_new ("updated",
EV_TYPE_JOB_FONTS,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EvJobFontsClass, updated),
NULL, NULL,
g_cclosure_marshal_VOID__DOUBLE,
G_TYPE_NONE,
1, G_TYPE_DOUBLE);
}
EvJob *
ev_job_fonts_new (EvDocument *document)
{
EvJobFonts *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
EV_JOB (job)->document = g_object_ref (document);
return EV_JOB (job);
}
/* EvJobLoad */
static void
ev_job_load_init (EvJobLoad *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_load_dispose (GObject *object)
{
EvJobLoad *job = EV_JOB_LOAD (object);
ev_debug_message (DEBUG_JOBS, "%s", job->uri);
g_clear_pointer (&job->uri, g_free);
g_clear_pointer (&job->password, g_free);
(* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
}
static gboolean
ev_job_load_run (EvJob *job)
{
EvJobLoad *job_load = EV_JOB_LOAD (job);
GError *error = NULL;
ev_debug_message (DEBUG_JOBS, "%s", job_load->uri);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_fc_mutex_lock ();
/* This job may already have a document even if the job didn't complete
because, e.g., a password is required - if so, just reload rather than
creating a new instance */
if (job->document) {
const gchar *uncompressed_uri;
if (job_load->password) {
ev_document_security_set_password (EV_DOCUMENT_SECURITY (job->document),
job_load->password);
}
job->failed = FALSE;
job->finished = FALSE;
g_clear_error (&job->error);
uncompressed_uri = g_object_get_data (G_OBJECT (job->document),
"uri-uncompressed");
ev_document_load (job->document,
uncompressed_uri ? uncompressed_uri : job_load->uri,
&error);
} else {
job->document = ev_document_factory_get_document (job_load->uri,
&error);
}
ev_document_fc_mutex_unlock ();
if (error) {
ev_job_failed_from_error (job, error);
g_error_free (error);
} else {
ev_job_succeeded (job);
}
return FALSE;
}
static void
ev_job_load_class_init (EvJobLoadClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_load_dispose;
job_class->run = ev_job_load_run;
}
EvJob *
ev_job_load_new (const gchar *uri)
{
EvJobLoad *job;
ev_debug_message (DEBUG_JOBS, "%s", uri);
job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
job->uri = g_strdup (uri);
return EV_JOB (job);
}
void
ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
{
ev_debug_message (DEBUG_JOBS, "%s", uri);
if (job->uri)
g_free (job->uri);
job->uri = g_strdup (uri);
}
void
ev_job_load_set_password (EvJobLoad *job, const gchar *password)
{
ev_debug_message (DEBUG_JOBS, NULL);
if (job->password)
g_free (job->password);
job->password = password ? g_strdup (password) : NULL;
}
/* EvJobLoadStream */
/**
* EvJobLoadStream:
*
* A job class to load a #EvDocument from a #GInputStream.
*
* Since: 3.6
*/
static void
ev_job_load_stream_init (EvJobLoadStream *job)
{
job->flags = EV_DOCUMENT_LOAD_FLAG_NONE;
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_load_stream_dispose (GObject *object)
{
EvJobLoadStream *job = EV_JOB_LOAD_STREAM (object);
EvJobLoadStreamPrivate *priv = ev_job_load_stream_get_instance_private (job);
g_clear_object (&job->stream);
g_clear_pointer (&priv->mime_type, g_free);
g_clear_pointer (&job->password, g_free);
G_OBJECT_CLASS (ev_job_load_stream_parent_class)->dispose (object);
}
static gboolean
ev_job_load_stream_run (EvJob *job)
{
EvJobLoadStream *job_load_stream = EV_JOB_LOAD_STREAM (job);
EvJobLoadStreamPrivate *priv = ev_job_load_stream_get_instance_private (job_load_stream);
GError *error = NULL;
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_fc_mutex_lock ();
/* This job may already have a document even if the job didn't complete
because, e.g., a password is required - if so, just reload_stream rather than
creating a new instance */
/* FIXME: do we need to rewind the stream here?? */
if (job->document) {
if (job_load_stream->password) {
ev_document_security_set_password (EV_DOCUMENT_SECURITY (job->document),
job_load_stream->password);
}
job->failed = FALSE;
job->finished = FALSE;
g_clear_error (&job->error);
ev_document_load_stream (job->document,
job_load_stream->stream,
job_load_stream->flags,
job->cancellable,
&error);
} else {
job->document = ev_document_factory_get_document_for_stream (job_load_stream->stream,
priv->mime_type,
job_load_stream->flags,
job->cancellable,
&error);
}
ev_document_fc_mutex_unlock ();
if (error) {
ev_job_failed_from_error (job, error);
g_error_free (error);
} else {
ev_job_succeeded (job);
}
return FALSE;
}
static void
ev_job_load_stream_class_init (EvJobLoadStreamClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_load_stream_dispose;
job_class->run = ev_job_load_stream_run;
}
EvJob *
ev_job_load_stream_new (GInputStream *stream,
EvDocumentLoadFlags flags)
{
EvJobLoadStream *job;
job = g_object_new (EV_TYPE_JOB_LOAD_STREAM, NULL);
ev_job_load_stream_set_stream (job, stream);
ev_job_load_stream_set_load_flags (job, flags);
return EV_JOB (job);
}
void
ev_job_load_stream_set_stream (EvJobLoadStream *job,
GInputStream *stream)
{
g_return_if_fail (EV_IS_JOB_LOAD_STREAM (job));
g_return_if_fail (G_IS_INPUT_STREAM (stream));
g_object_ref (stream);
if (job->stream)
g_object_unref (job->stream);
job->stream = stream;
}
void
ev_job_load_stream_set_mime_type (EvJobLoadStream *job,
const char *mime_type)
{
EvJobLoadStreamPrivate *priv;
g_return_if_fail (EV_IS_JOB_LOAD_STREAM (job));
priv = ev_job_load_stream_get_instance_private (job);
g_free (priv->mime_type);
priv->mime_type = g_strdup (mime_type);
}
void
ev_job_load_stream_set_load_flags (EvJobLoadStream *job,
EvDocumentLoadFlags flags)
{
g_return_if_fail (EV_IS_JOB_LOAD_STREAM (job));
job->flags = flags;
}
void
ev_job_load_stream_set_password (EvJobLoadStream *job,
const char *password)
{
char *old_password;
ev_debug_message (DEBUG_JOBS, NULL);
g_return_if_fail (EV_IS_JOB_LOAD_STREAM (job));
old_password = job->password;
job->password = g_strdup (password);
g_free (old_password);
}
/* EvJobLoadGFile */
/**
* EvJobLoadGFile:
*
* A job class to load a #EvDocument from a #GFile.
*
* Since: 3.6
*/
static void
ev_job_load_gfile_init (EvJobLoadGFile *job)
{
job->flags = EV_DOCUMENT_LOAD_FLAG_NONE;
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_load_gfile_dispose (GObject *object)
{
EvJobLoadGFile *job = EV_JOB_LOAD_GFILE (object);
g_clear_object (&job->gfile);
g_clear_pointer (&job->password, g_free);
G_OBJECT_CLASS (ev_job_load_gfile_parent_class)->dispose (object);
}
static gboolean
ev_job_load_gfile_run (EvJob *job)
{
EvJobLoadGFile *job_load_gfile = EV_JOB_LOAD_GFILE (job);
GError *error = NULL;
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_fc_mutex_lock ();
/* This job may already have a document even if the job didn't complete
because, e.g., a password is required - if so, just reload_gfile rather than
creating a new instance */
if (job->document) {
if (job_load_gfile->password) {
ev_document_security_set_password (EV_DOCUMENT_SECURITY (job->document),
job_load_gfile->password);
}
job->failed = FALSE;
job->finished = FALSE;
g_clear_error (&job->error);
ev_document_load_gfile (job->document,
job_load_gfile->gfile,
job_load_gfile->flags,
job->cancellable,
&error);
} else {
job->document = ev_document_factory_get_document_for_gfile (job_load_gfile->gfile,
job_load_gfile->flags,
job->cancellable,
&error);
}
ev_document_fc_mutex_unlock ();
if (error) {
ev_job_failed_from_error (job, error);
g_error_free (error);
} else {
ev_job_succeeded (job);
}
return FALSE;
}
static void
ev_job_load_gfile_class_init (EvJobLoadGFileClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_load_gfile_dispose;
job_class->run = ev_job_load_gfile_run;
}
EvJob *
ev_job_load_gfile_new (GFile *gfile,
EvDocumentLoadFlags flags)
{
EvJobLoadGFile *job;
job = g_object_new (EV_TYPE_JOB_LOAD_GFILE, NULL);
ev_job_load_gfile_set_gfile (job, gfile);
ev_job_load_gfile_set_load_flags (job, flags);
return EV_JOB (job);
}
void
ev_job_load_gfile_set_gfile (EvJobLoadGFile *job,
GFile *gfile)
{
g_return_if_fail (EV_IS_JOB_LOAD_GFILE (job));
g_return_if_fail (G_IS_FILE (gfile));
g_object_ref (gfile);
if (job->gfile)
g_object_unref (job->gfile);
job->gfile = gfile;
}
void
ev_job_load_gfile_set_load_flags (EvJobLoadGFile *job,
EvDocumentLoadFlags flags)
{
g_return_if_fail (EV_IS_JOB_LOAD_GFILE (job));
job->flags = flags;
}
void
ev_job_load_gfile_set_password (EvJobLoadGFile *job,
const char *password)
{
char *old_password;
ev_debug_message (DEBUG_JOBS, NULL);
g_return_if_fail (EV_IS_JOB_LOAD_GFILE (job));
old_password = job->password;
job->password = g_strdup (password);
g_free (old_password);
}
/* EvJobLoadFd */
/**
* EvJobLoadFd:
*
* A job class to load a #EvDocument from a file descriptor
* referring to a regular file.
*
* Since: 42.0
*/
static int
ev_dupfd (int fd,
GError **error)
{
int new_fd;
new_fd = fcntl (fd, F_DUPFD_CLOEXEC, 3);
if (new_fd == -1) {
int errsv = errno;
g_set_error_literal (error, G_FILE_ERROR, g_file_error_from_errno (errsv),
g_strerror (errsv));
}
return new_fd;
}
static void
ev_job_load_fd_init (EvJobLoadFd *job)
{
job->flags = EV_DOCUMENT_LOAD_FLAG_NONE;
job->fd = -1;
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_load_fd_dispose (GObject *object)
{
EvJobLoadFd *job = EV_JOB_LOAD_FD (object);
if (job->fd != -1) {
close (job->fd);
job->fd = -1;
}
g_clear_pointer (&job->mime_type, g_free);
g_clear_pointer (&job->password, g_free);
G_OBJECT_CLASS (ev_job_load_fd_parent_class)->dispose (object);
}
static gboolean
ev_job_load_fd_run (EvJob *job)
{
EvJobLoadFd *job_load_fd = EV_JOB_LOAD_FD (job);
GError *error = NULL;
int fd;
if (job_load_fd->fd == -1) {
g_set_error_literal (&error, G_FILE_ERROR, G_FILE_ERROR_BADF,
"Invalid file descriptor");
goto out;
}
/* We need to dup the FD here since we may need to pass it again
* to ev_document_load_fd() if the document is encrypted,
* and the previous call to it consumes the FD.
*/
fd = ev_dupfd (job_load_fd->fd, &error);
if (fd == -1)
goto out;
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_fc_mutex_lock ();
/* This job may already have a document even if the job didn't complete
because, e.g., a password is required - if so, just reload_fd rather than
creating a new instance */
if (job->document) {
if (job_load_fd->password) {
ev_document_security_set_password (EV_DOCUMENT_SECURITY (job->document),
job_load_fd->password);
}
job->failed = FALSE;
job->finished = FALSE;
g_clear_error (&job->error);
ev_document_load_fd (job->document,
fd,
job_load_fd->flags,
job->cancellable,
&error);
fd = -1; /* consumed */
} else {
job->document = ev_document_factory_get_document_for_fd (fd,
job_load_fd->mime_type,
job_load_fd->flags,
job->cancellable,
&error);
fd = -1; /* consumed */
}
ev_document_fc_mutex_unlock ();
out:
if (error) {
ev_job_failed_from_error (job, error);
g_error_free (error);
} else {
ev_job_succeeded (job);
}
return FALSE;
}
static void
ev_job_load_fd_class_init (EvJobLoadFdClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_load_fd_dispose;
job_class->run = ev_job_load_fd_run;
}
/**
* ev_job_load_fd_new:
* @fd: a file descriptor
* @mime_type: the mime type
* @flags:flags from #EvDocumentLoadFlags
* @error: (nullable): a location to store a #GError, or %NULL
*
* Creates a new #EvJobLoadFd for @fd. If duplicating @fd fails,
* returns %NULL with @error filled in.
*
* Returns: (transfer full): the new #EvJobLoadFd, or %NULL
*
* Since: 42.0
*/
EvJob *
ev_job_load_fd_new (int fd,
const char *mime_type,
EvDocumentLoadFlags flags,
GError **error)
{
EvJobLoadFd *job;
job = g_object_new (EV_TYPE_JOB_LOAD_FD, NULL);
if (!ev_job_load_fd_set_fd (job, fd, error)) {
g_object_unref (job);
return NULL;
}
ev_job_load_fd_set_mime_type (job, mime_type);
ev_job_load_fd_set_load_flags (job, flags);
return EV_JOB (job);
}
/**
* ev_job_load_new_take:
* @fd: a file descriptor
* @mime_type: the mime type
* @flags:flags from #EvDocumentLoadFlags
*
* Creates a new #EvJobLoadFd for @fd.
* Note that the job takes ownership of @fd; you must not do anything
* with it afterwards.
*
* Returns: (transfer full): the new #EvJobLoadFd
*
* Since: 42.0
*/
EvJob *
ev_job_load_fd_new_take (int fd,
const char *mime_type,
EvDocumentLoadFlags flags)
{
EvJobLoadFd *job;
job = g_object_new (EV_TYPE_JOB_LOAD_FD, NULL);
ev_job_load_fd_take_fd (job, fd);
ev_job_load_fd_set_mime_type (job, mime_type);
ev_job_load_fd_set_load_flags (job, flags);
return EV_JOB (job);
}
/**
* ev_job_load_fd_set_fd:
* @job: an #EvJob
* @fd: a file descriptor
* @error: (nullable): a location to store a #GError, or %NULL
*
* Sets @fd as the file descriptor in @job. If duplicating @fd fails,
* returns %FALSE with @error filled in.
*
* Returns: %TRUE if the file descriptor could be set
*
* Since: 42.0
*/
gboolean
ev_job_load_fd_set_fd (EvJobLoadFd *job,
int fd,
GError **error)
{
g_return_val_if_fail (EV_IS_JOB_LOAD_FD (job), FALSE);
g_return_val_if_fail (fd != -1, FALSE);
job->fd = ev_dupfd (fd, error);
return job->fd != -1;
}
/**
* ev_job_load_fd_take_fd:
* @job: an #EvJob
* @fd: a file descriptor
*
* Sets @fd as the file descriptor in @job.
* Note that @job takes ownership of @fd; you must not do anything
* with it afterwards.
*
* Since: 42.0
*/
void
ev_job_load_fd_take_fd (EvJobLoadFd *job,
int fd)
{
g_return_if_fail (EV_IS_JOB_LOAD_FD (job));
g_return_if_fail (fd != -1);
job->fd = fd;
}
void
ev_job_load_fd_set_mime_type (EvJobLoadFd *job,
const char *mime_type)
{
g_return_if_fail (EV_IS_JOB_LOAD_FD (job));
g_return_if_fail (mime_type != NULL);
g_free (job->mime_type);
job->mime_type = g_strdup (mime_type);
}
void
ev_job_load_fd_set_load_flags (EvJobLoadFd *job,
EvDocumentLoadFlags flags)
{
g_return_if_fail (EV_IS_JOB_LOAD_FD (job));
job->flags = flags;
}
void
ev_job_load_fd_set_password (EvJobLoadFd *job,
const char *password)
{
char *old_password;
ev_debug_message (DEBUG_JOBS, NULL);
g_return_if_fail (EV_IS_JOB_LOAD_FD (job));
old_password = job->password;
job->password = g_strdup (password);
g_free (old_password);
}
/* EvJobSave */
static void
ev_job_save_init (EvJobSave *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_save_dispose (GObject *object)
{
EvJobSave *job = EV_JOB_SAVE (object);
ev_debug_message (DEBUG_JOBS, "%s", job->uri);
g_clear_pointer (&job->uri, g_free);
g_clear_pointer (&job->document_uri, g_free);
(* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
}
static gboolean
ev_job_save_run (EvJob *job)
{
EvJobSave *job_save = EV_JOB_SAVE (job);
gint fd;
gchar *tmp_filename = NULL;
gchar *local_uri;
GError *error = NULL;
ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job_save->uri, job_save->document_uri);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
fd = ev_mkstemp ("saveacopy.XXXXXX", &tmp_filename, &error);
if (fd == -1) {
ev_job_failed_from_error (job, error);
g_error_free (error);
return FALSE;
}
close (fd);
ev_document_doc_mutex_lock ();
/* Save document to temp filename */
local_uri = g_filename_to_uri (tmp_filename, NULL, &error);
if (local_uri != NULL) {
ev_document_save (job->document, local_uri, &error);
}
ev_document_doc_mutex_unlock ();
if (error) {
g_free (local_uri);
ev_job_failed_from_error (job, error);
g_error_free (error);
return FALSE;
}
/* If original document was compressed,
* compress it again before saving
*/
if (g_object_get_data (G_OBJECT (job->document), "uri-uncompressed")) {
EvCompressionType ctype = EV_COMPRESSION_NONE;
const gchar *ext;
gchar *uri_comp;
ext = g_strrstr (job_save->document_uri, ".gz");
if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
ctype = EV_COMPRESSION_GZIP;
ext = g_strrstr (job_save->document_uri, ".bz2");
if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
ctype = EV_COMPRESSION_BZIP2;
uri_comp = ev_file_compress (local_uri, ctype, &error);
g_free (local_uri);
g_unlink (tmp_filename);
if (!uri_comp || error) {
local_uri = NULL;
} else {
local_uri = uri_comp;
}
}
g_free (tmp_filename);
if (error) {
g_free (local_uri);
ev_job_failed_from_error (job, error);
g_error_free (error);
return FALSE;
}
if (!local_uri)
return FALSE;
ev_xfer_uri_simple (local_uri, job_save->uri, &error);
ev_tmp_uri_unlink (local_uri);
/* Copy the metadata from the original file */
if (!error) {
/* Ignore errors here. Failure to copy metadata is not a hard error */
ev_file_copy_metadata (job_save->document_uri, job_save->uri, NULL);
}
if (error) {
ev_job_failed_from_error (job, error);
g_error_free (error);
} else {
ev_job_succeeded (job);
}
return FALSE;
}
static void
ev_job_save_class_init (EvJobSaveClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_save_dispose;
job_class->run = ev_job_save_run;
}
EvJob *
ev_job_save_new (EvDocument *document,
const gchar *uri,
const gchar *document_uri)
{
EvJobSave *job;
ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri);
job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
EV_JOB (job)->document = g_object_ref (document);
job->uri = g_strdup (uri);
job->document_uri = g_strdup (document_uri);
return EV_JOB (job);
}
/* EvJobFind */
static void
ev_job_find_init (EvJobFind *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
}
static void
ev_job_find_dispose (GObject *object)
{
EvJobFind *job = EV_JOB_FIND (object);
ev_debug_message (DEBUG_JOBS, NULL);
g_clear_pointer (&job->text, g_free);
if (job->pages) {
gint i;
for (i = 0; i < job->n_pages; i++) {
g_list_free_full (job->pages[i], (GDestroyNotify)ev_find_rectangle_free);
}
g_clear_pointer (&job->pages, g_free);
}
(* G_OBJECT_CLASS (ev_job_find_parent_class)->dispose) (object);
}
static gboolean
ev_job_find_run (EvJob *job)
{
EvJobFind *job_find = EV_JOB_FIND (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 */
if (!ev_document_doc_mutex_trylock ())
return TRUE;
#ifdef EV_ENABLE_DEBUG
/* We use the #ifdef in this case because of the if */
if (job_find->current_page == job_find->start_page)
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
#endif
ev_page = ev_document_get_page (job->document, job_find->current_page);
matches = ev_document_find_find_text_extended (find, ev_page, job_find->text,
job_find->options);
g_object_unref (ev_page);
ev_document_doc_mutex_unlock ();
if (!job_find->has_results)
job_find->has_results = (matches != NULL);
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;
if (job_find->current_page == job_find->start_page) {
ev_job_succeeded (job);
return FALSE;
}
return TRUE;
}
static void
ev_job_find_class_init (EvJobFindClass *class)
{
EvJobClass *job_class = EV_JOB_CLASS (class);
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
job_class->run = ev_job_find_run;
gobject_class->dispose = ev_job_find_dispose;
job_find_signals[FIND_UPDATED] =
g_signal_new ("updated",
EV_TYPE_JOB_FIND,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EvJobFindClass, updated),
NULL, NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
1, G_TYPE_INT);
}
EvJob *
ev_job_find_new (EvDocument *document,
gint start_page,
gint n_pages,
const gchar *text,
gboolean case_sensitive)
{
EvJobFind *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = g_object_new (EV_TYPE_JOB_FIND, NULL);
EV_JOB (job)->document = g_object_ref (document);
job->start_page = start_page;
job->current_page = start_page;
job->n_pages = n_pages;
job->pages = g_new0 (GList *, n_pages);
job->text = g_strdup (text);
/* Keep for compatibility */
job->case_sensitive = case_sensitive;
job->has_results = FALSE;
if (case_sensitive)
job->options |= EV_FIND_CASE_SENSITIVE;
return EV_JOB (job);
}
/**
* ev_job_find_set_options:
* @job:
* @options:
*
* Since: 3.6
*/
void
ev_job_find_set_options (EvJobFind *job,
EvFindOptions options)
{
job->options = options;
/* Keep compatibility */
job->case_sensitive = options & EV_FIND_CASE_SENSITIVE;
}
/**
* ev_job_find_get_options:
* @job:
*
* Returns: the job's find options
*
* Since: 3.6
*/
EvFindOptions
ev_job_find_get_options (EvJobFind *job)
{
return job->options;
}
gint
ev_job_find_get_n_results (EvJobFind *job,
gint page)
{
return g_list_length (job->pages[page]);
}
/**
* ev_job_find_get_n_main_results:
* @job: an #EvJobFind job
* @page: number of the page we want to count its match results.
*
* This is similar to ev_job_find_get_n_results() but it takes
* care to treat any multi-line matches as being only one result.
*
* Returns: total number of match results in @page
*/
gint
ev_job_find_get_n_main_results (EvJobFind *job,
gint page)
{
GList *l;
int n = 0;
for (l = job->pages[page]; l; l = l->next) {
if ( !((EvFindRectangle *) l->data)->next_line )
n++;
}
return n;
}
gdouble
ev_job_find_get_progress (EvJobFind *job)
{
gint pages_done;
if (ev_job_is_finished (EV_JOB (job)))
return 1.0;
if (job->current_page > job->start_page) {
pages_done = job->current_page - job->start_page + 1;
} else if (job->current_page == job->start_page) {
pages_done = job->n_pages;
} else {
pages_done = job->n_pages - job->start_page + job->current_page;
}
return pages_done / (gdouble) job->n_pages;
}
gboolean
ev_job_find_has_results (EvJobFind *job)
{
return job->has_results;
}
/**
* ev_job_find_get_results: (skip)
* @job: an #EvJobFind
*
* Returns: a #GList of #GList<!-- -->s containing #EvFindRectangle<!-- -->s
*/
GList **
ev_job_find_get_results (EvJobFind *job)
{
return job->pages;
}
/* EvJobLayers */
static void
ev_job_layers_init (EvJobLayers *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
}
static void
ev_job_layers_dispose (GObject *object)
{
EvJobLayers *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = EV_JOB_LAYERS (object);
g_clear_object (&job->model);
(* G_OBJECT_CLASS (ev_job_layers_parent_class)->dispose) (object);
}
static gboolean
ev_job_layers_run (EvJob *job)
{
EvJobLayers *job_layers = EV_JOB_LAYERS (job);
ev_debug_message (DEBUG_JOBS, NULL);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_doc_mutex_lock ();
job_layers->model = ev_document_layers_get_layers (EV_DOCUMENT_LAYERS (job->document));
ev_document_doc_mutex_unlock ();
ev_job_succeeded (job);
return FALSE;
}
static void
ev_job_layers_class_init (EvJobLayersClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_layers_dispose;
job_class->run = ev_job_layers_run;
}
EvJob *
ev_job_layers_new (EvDocument *document)
{
EvJob *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = g_object_new (EV_TYPE_JOB_LAYERS, NULL);
job->document = g_object_ref (document);
return job;
}
/* EvJobExport */
static void
ev_job_export_init (EvJobExport *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
job->page = -1;
}
static void
ev_job_export_dispose (GObject *object)
{
EvJobExport *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = EV_JOB_EXPORT (object);
g_clear_object (&job->rc);
(* G_OBJECT_CLASS (ev_job_export_parent_class)->dispose) (object);
}
static gboolean
ev_job_export_run (EvJob *job)
{
EvJobExport *job_export = EV_JOB_EXPORT (job);
EvPage *ev_page;
g_assert (job_export->page != -1);
ev_debug_message (DEBUG_JOBS, NULL);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
ev_document_doc_mutex_lock ();
ev_page = ev_document_get_page (job->document, job_export->page);
if (job_export->rc) {
job->failed = FALSE;
job->finished = FALSE;
g_clear_error (&job->error);
ev_render_context_set_page (job_export->rc, ev_page);
} else {
job_export->rc = ev_render_context_new (ev_page, 0, 1.0);
}
g_object_unref (ev_page);
ev_file_exporter_do_page (EV_FILE_EXPORTER (job->document), job_export->rc);
ev_document_doc_mutex_unlock ();
ev_job_succeeded (job);
return FALSE;
}
static void
ev_job_export_class_init (EvJobExportClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_export_dispose;
job_class->run = ev_job_export_run;
}
EvJob *
ev_job_export_new (EvDocument *document)
{
EvJob *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = g_object_new (EV_TYPE_JOB_EXPORT, NULL);
job->document = g_object_ref (document);
return job;
}
void
ev_job_export_set_page (EvJobExport *job,
gint page)
{
job->page = page;
}
/* EvJobPrint */
static void
ev_job_print_init (EvJobPrint *job)
{
EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
job->page = -1;
}
static void
ev_job_print_dispose (GObject *object)
{
EvJobPrint *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = EV_JOB_PRINT (object);
g_clear_pointer (&job->cr, cairo_destroy);
(* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
}
static gboolean
ev_job_print_run (EvJob *job)
{
EvJobPrint *job_print = EV_JOB_PRINT (job);
EvPage *ev_page;
cairo_status_t cr_status;
g_assert (job_print->page != -1);
g_assert (job_print->cr != NULL);
ev_debug_message (DEBUG_JOBS, NULL);
ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
job->failed = FALSE;
job->finished = FALSE;
g_clear_error (&job->error);
ev_document_doc_mutex_lock ();
ev_page = ev_document_get_page (job->document, job_print->page);
ev_document_print_print_page (EV_DOCUMENT_PRINT (job->document),
ev_page, job_print->cr);
g_object_unref (ev_page);
ev_document_doc_mutex_unlock ();
if (g_cancellable_is_cancelled (job->cancellable))
return FALSE;
cr_status = cairo_status (job_print->cr);
if (cr_status == CAIRO_STATUS_SUCCESS) {
ev_job_succeeded (job);
} else {
ev_job_failed (job,
GTK_PRINT_ERROR,
GTK_PRINT_ERROR_GENERAL,
_("Failed to print page %d: %s"),
job_print->page,
cairo_status_to_string (cr_status));
}
return FALSE;
}
static void
ev_job_print_class_init (EvJobPrintClass *class)
{
GObjectClass *oclass = G_OBJECT_CLASS (class);
EvJobClass *job_class = EV_JOB_CLASS (class);
oclass->dispose = ev_job_print_dispose;
job_class->run = ev_job_print_run;
}
EvJob *
ev_job_print_new (EvDocument *document)
{
EvJob *job;
ev_debug_message (DEBUG_JOBS, NULL);
job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
job->document = g_object_ref (document);
return job;
}
void
ev_job_print_set_page (EvJobPrint *job,
gint page)
{
job->page = page;
}
void
ev_job_print_set_cairo (EvJobPrint *job,
cairo_t *cr)
{
if (job->cr == cr)
return;
if (job->cr)
cairo_destroy (job->cr);
job->cr = cr ? cairo_reference (cr) : NULL;
}