From e71d27db284ccf431167816167bf72f1e23c334d Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Sun, 3 Aug 2008 11:01:28 +0000 Subject: [PATCH] Rework the jobs system in order to make it simpler and more extensible. It 2008-08-03 Carlos Garcia Campos * libdocument/ev-document.[ch]: (ev_document_doc_mutex_trylock), (ev_document_fc_mutex_trylock): * shell/Makefile.am: * shell/ev-job-queue.[ch]: * shell/ev-job-scheduler.[ch]: * shell/ev-jobs.[ch]: (ev_job_init), (ev_job_dispose), (ev_job_class_init), (emit_finished), (ev_job_emit_finished), (ev_job_run), (ev_job_cancel), (ev_job_failed), (ev_job_failed_from_error), (ev_job_succeeded), (ev_job_is_finished), (ev_job_is_failed), (ev_job_get_run_mode), (ev_job_set_run_mode), (ev_job_links_init), (ev_job_links_run), (ev_job_links_class_init), (ev_job_render_init), (notify_page_ready), (ev_job_render_page_ready), (ev_job_render_run), (ev_job_render_class_init), (ev_job_thumbnail_init), (ev_job_thumbnail_run), (ev_job_thumbnail_class_init), (ev_job_fonts_init), (ev_job_fonts_run), (ev_job_fonts_class_init), (ev_job_load_init), (ev_job_load_run), (ev_job_load_class_init), (ev_job_save_init), (ev_job_save_dispose), (ev_job_save_run), (ev_job_save_class_init), (ev_job_print_init), (ev_job_print_dispose), (ev_job_print_run), (ev_job_print_class_init): * shell/ev-page-cache.c: * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info), (check_job_size_and_unref), (move_one_job), (copy_job_to_job_info), (add_job), (ev_pixbuf_cache_add_jobs_if_needed): * shell/ev-properties-fonts.c: (ev_properties_fonts_dispose), (job_fonts_finished_cb), (job_fonts_updated_cb), (ev_properties_fonts_set_document): * shell/ev-sidebar-links.c: (ev_sidebar_links_dispose), (ev_sidebar_links_set_document): * shell/ev-sidebar-thumbnails.c: (clear_range), (add_range), (ev_sidebar_thumbnails_set_document), (ev_sidebar_thumbnails_clear_job): * shell/ev-view-private.h: * shell/ev-view.c: * shell/ev-window.c: (ev_window_clear_thumbnail_job), (ev_window_refresh_window_thumbnail), (password_dialog_response), (ev_window_clear_load_job), (ev_window_clear_reload_job), (ev_window_load_job_cb), (ev_window_reload_job_cb), (window_open_file_copy_ready_cb), (ev_window_open_uri), (ev_window_reload_document), (ev_window_clear_save_job), (ev_window_save_job_cb), (file_save_dialog_response_cb), (ev_window_clear_print_job), (ev_window_print_job_cb), (ev_window_print_dialog_response_cb): * shell/main.c: (main): Rework the jobs system in order to make it simpler and more extensible. It allows to run jobs in the main loop instead of using a thread when it's appropriate like the fonts job. Now it's also possible to cancel jobs that are currently running. svn path=/trunk/; revision=3092 --- ChangeLog | 55 + libdocument/ev-document.c | 12 + libdocument/ev-document.h | 2 + shell/Makefile.am | 4 +- shell/ev-job-queue.c | 517 --------- shell/ev-job-scheduler.c | 305 +++++ shell/{ev-job-queue.h => ev-job-scheduler.h} | 31 +- shell/ev-jobs.c | 1058 +++++++++++------- shell/ev-jobs.h | 61 +- shell/ev-page-cache.c | 1 - shell/ev-pixbuf-cache.c | 28 +- shell/ev-pixbuf-cache.h | 1 - shell/ev-properties-fonts.c | 51 +- shell/ev-sidebar-links.c | 6 +- shell/ev-sidebar-thumbnails.c | 12 +- shell/ev-view-private.h | 1 + shell/ev-view.c | 1 - shell/ev-window.c | 107 +- shell/main.c | 2 - 19 files changed, 1187 insertions(+), 1068 deletions(-) delete mode 100644 shell/ev-job-queue.c create mode 100644 shell/ev-job-scheduler.c rename shell/{ev-job-queue.h => ev-job-scheduler.h} (51%) diff --git a/ChangeLog b/ChangeLog index efd08f17..1f45cec0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,58 @@ +2008-08-03 Carlos Garcia Campos + + * libdocument/ev-document.[ch]: (ev_document_doc_mutex_trylock), + (ev_document_fc_mutex_trylock): + * shell/Makefile.am: + * shell/ev-job-queue.[ch]: + * shell/ev-job-scheduler.[ch]: + * shell/ev-jobs.[ch]: (ev_job_init), (ev_job_dispose), + (ev_job_class_init), (emit_finished), (ev_job_emit_finished), + (ev_job_run), (ev_job_cancel), (ev_job_failed), + (ev_job_failed_from_error), (ev_job_succeeded), + (ev_job_is_finished), (ev_job_is_failed), (ev_job_get_run_mode), + (ev_job_set_run_mode), (ev_job_links_init), (ev_job_links_run), + (ev_job_links_class_init), (ev_job_render_init), + (notify_page_ready), (ev_job_render_page_ready), + (ev_job_render_run), (ev_job_render_class_init), + (ev_job_thumbnail_init), (ev_job_thumbnail_run), + (ev_job_thumbnail_class_init), (ev_job_fonts_init), + (ev_job_fonts_run), (ev_job_fonts_class_init), (ev_job_load_init), + (ev_job_load_run), (ev_job_load_class_init), (ev_job_save_init), + (ev_job_save_dispose), (ev_job_save_run), + (ev_job_save_class_init), (ev_job_print_init), + (ev_job_print_dispose), (ev_job_print_run), + (ev_job_print_class_init): + * shell/ev-page-cache.c: + * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info), + (check_job_size_and_unref), (move_one_job), + (copy_job_to_job_info), (add_job), + (ev_pixbuf_cache_add_jobs_if_needed): + * shell/ev-properties-fonts.c: (ev_properties_fonts_dispose), + (job_fonts_finished_cb), (job_fonts_updated_cb), + (ev_properties_fonts_set_document): + * shell/ev-sidebar-links.c: (ev_sidebar_links_dispose), + (ev_sidebar_links_set_document): + * shell/ev-sidebar-thumbnails.c: (clear_range), (add_range), + (ev_sidebar_thumbnails_set_document), + (ev_sidebar_thumbnails_clear_job): + * shell/ev-view-private.h: + * shell/ev-view.c: + * shell/ev-window.c: (ev_window_clear_thumbnail_job), + (ev_window_refresh_window_thumbnail), (password_dialog_response), + (ev_window_clear_load_job), (ev_window_clear_reload_job), + (ev_window_load_job_cb), (ev_window_reload_job_cb), + (window_open_file_copy_ready_cb), (ev_window_open_uri), + (ev_window_reload_document), (ev_window_clear_save_job), + (ev_window_save_job_cb), (file_save_dialog_response_cb), + (ev_window_clear_print_job), (ev_window_print_job_cb), + (ev_window_print_dialog_response_cb): + * shell/main.c: (main): + + Rework the jobs system in order to make it simpler and more + extensible. It allows to run jobs in the main loop instead of + using a thread when it's appropriate like the fonts job. Now it's + also possible to cancel jobs that are currently running. + 2008-07-27 Carlos Garcia Campos * libdocument/ev-debug.c: (profile_init): diff --git a/libdocument/ev-document.c b/libdocument/ev-document.c index 7bb86be9..1171509a 100644 --- a/libdocument/ev-document.c +++ b/libdocument/ev-document.c @@ -89,6 +89,12 @@ ev_document_doc_mutex_unlock (void) g_mutex_unlock (ev_document_get_doc_mutex ()); } +gboolean +ev_document_doc_mutex_trylock (void) +{ + return g_mutex_trylock (ev_document_get_doc_mutex ()); +} + GMutex * ev_document_get_fc_mutex (void) { @@ -110,6 +116,12 @@ ev_document_fc_mutex_unlock (void) g_mutex_unlock (ev_document_get_fc_mutex ()); } +gboolean +ev_document_fc_mutex_trylock (void) +{ + return g_mutex_trylock (ev_document_get_fc_mutex ()); +} + gboolean ev_document_load (EvDocument *document, const char *uri, diff --git a/libdocument/ev-document.h b/libdocument/ev-document.h index cfcccdbe..367d6e6a 100644 --- a/libdocument/ev-document.h +++ b/libdocument/ev-document.h @@ -101,11 +101,13 @@ GQuark ev_document_error_quark (void); GMutex *ev_document_get_doc_mutex (void); void ev_document_doc_mutex_lock (void); void ev_document_doc_mutex_unlock (void); +gboolean ev_document_doc_mutex_trylock(void); /* FontConfig mutex */ GMutex *ev_document_get_fc_mutex (void); void ev_document_fc_mutex_lock (void); void ev_document_fc_mutex_unlock (void); +gboolean ev_document_fc_mutex_trylock (void); EvDocumentInfo *ev_document_get_info (EvDocument *document); gboolean ev_document_load (EvDocument *document, diff --git a/shell/Makefile.am b/shell/Makefile.am index 3d857716..d2c14a9d 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -28,8 +28,8 @@ evince_SOURCES= \ eggfindbar.h \ ev-application.c \ ev-application.h \ - ev-job-queue.h \ - ev-job-queue.c \ + ev-job-scheduler.h \ + ev-job-scheduler.c \ ev-jobs.h \ ev-jobs.c \ ev-file-monitor.h \ diff --git a/shell/ev-job-queue.c b/shell/ev-job-queue.c deleted file mode 100644 index 8280aab4..00000000 --- a/shell/ev-job-queue.c +++ /dev/null @@ -1,517 +0,0 @@ -#include -#include "ev-job-queue.h" - -/* Like glib calling convention, all functions with _locked in their name assume - * that we've already locked the doc mutex and can freely and safely access - * data. - */ -GCond *render_cond = NULL; -GMutex *ev_queue_mutex = NULL; - -static GQueue *links_queue = NULL; -static GQueue *render_queue_high = NULL; -static GQueue *render_queue_low = NULL; -static GQueue *thumbnail_queue_high = NULL; -static GQueue *thumbnail_queue_low = NULL; -static GQueue *load_queue = NULL; -static GQueue *save_queue = NULL; -static GQueue *fonts_queue = NULL; -static GQueue *print_queue = NULL; - -/* Queues used for backends supporting EvAsyncRender interface, - they are executed on the main thread */ -static GQueue *async_render_queue_high = NULL; -static GQueue *async_render_queue_low = NULL; -static gboolean async_rendering = FALSE; - -static void ev_job_queue_run_next (void); - -static gboolean -remove_job_from_queue_locked (GQueue *queue, EvJob *job) -{ - GList *list; - - list = g_queue_find (queue, job); - if (list) { - g_object_unref (G_OBJECT (job)); - g_queue_delete_link (queue, list); - - return TRUE; - } - return FALSE; -} - -static gboolean -remove_job_from_async_queue (GQueue *queue, EvJob *job) -{ - return remove_job_from_queue_locked (queue, job); -} - -static void -add_job_to_async_queue (GQueue *queue, EvJob *job) -{ - g_object_ref (job); - g_queue_push_tail (queue, job); -} - -/** - * add_job_to_queue_locked: - * @queue: a #GQueue where the #EvJob will be added. - * @job: an #EvJob to be added to the specified #GQueue. - * - * Add the #EvJob to the specified #GQueue and woke up the ev_render_thread who - * is waiting for render_cond. - */ -static void -add_job_to_queue_locked (GQueue *queue, - EvJob *job) -{ - g_object_ref (job); - g_queue_push_tail (queue, job); - g_cond_broadcast (render_cond); -} - -/** - * notify_finished: - * @job: the object that signal will be reseted. - * - * It does emit the job finished signal and returns %FALSE. - * - * Returns: %FALSE. - */ -static gboolean -notify_finished (GObject *job) -{ - ev_job_finished (EV_JOB (job)); - - return FALSE; -} - -/** - * job_finished_cb: - * @job: the #EvJob that has been handled. - * - * It does finish the job last work and look if there is any more job to be - * handled. - */ -static void -job_finished_cb (EvJob *job) -{ - g_object_unref (job); - async_rendering = FALSE; - ev_job_queue_run_next (); -} - -/** - * handle_job: - * @job: the #EvJob to be handled. - * - * First, it does check if the job is async and then it does attend it if - * possible giving a failed assertion otherwise. If the job isn't async it does - * attend it and notify that the job has been finished. - */ -static void -handle_job (EvJob *job) -{ - g_object_ref (G_OBJECT (job)); - - if (EV_JOB (job)->async) { - async_rendering = TRUE; - if (EV_IS_JOB_RENDER (job)) { - g_signal_connect (job, "finished", - G_CALLBACK (job_finished_cb), NULL); - } else { - g_assert_not_reached (); - } - } - - if (EV_IS_JOB_THUMBNAIL (job)) - ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job)); - else if (EV_IS_JOB_LINKS (job)) - ev_job_links_run (EV_JOB_LINKS (job)); - else if (EV_IS_JOB_LOAD (job)) - ev_job_load_run (EV_JOB_LOAD (job)); - else if (EV_IS_JOB_SAVE (job)) - ev_job_save_run (EV_JOB_SAVE (job)); - else if (EV_IS_JOB_RENDER (job)) - ev_job_render_run (EV_JOB_RENDER (job)); - else if (EV_IS_JOB_FONTS (job)) - ev_job_fonts_run (EV_JOB_FONTS (job)); - else if (EV_IS_JOB_PRINT (job)) - ev_job_print_run (EV_JOB_PRINT (job)); - - if (!EV_JOB (job)->async) { - /* We let the idle own a ref, as we (the queue) are done with the job. */ - g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, - (GSourceFunc) notify_finished, - job, - g_object_unref); - } -} - -/** - * search_for_jobs_unlocked: - * - * Check if there is any job at the synchronized queues and return any existing - * job in them taking in account the next priority: - * - * render_queue_high > - * thumbnail_queue_high > - * render_queue_low > - * links_queue > - * load_queue > - * thumbnail_queue_low > - * fonts_queue > - * print_queue > - * - * Returns: an available #EvJob in the queues taking in account stablished queue - * priorities. - */ -static EvJob * -search_for_jobs_unlocked (void) -{ - EvJob *job; - - job = (EvJob *) g_queue_pop_head (render_queue_high); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (thumbnail_queue_high); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (render_queue_low); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (links_queue); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (load_queue); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (save_queue); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (thumbnail_queue_low); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (fonts_queue); - if (job) - return job; - - job = (EvJob *) g_queue_pop_head (print_queue); - if (job) - return job; - - return NULL; -} - -/** - * no_jobs_available_unlocked: - * - * Looks if there is any job at render, links, load, thumbnail. fonts and print - * queues. - * - * Returns: %TRUE if the render, links, load, thumbnail, fonts and print queues - * are empty, %FALSE in other case. - */ -static gboolean -no_jobs_available_unlocked (void) -{ - return g_queue_is_empty (render_queue_high) - && g_queue_is_empty (render_queue_low) - && g_queue_is_empty (links_queue) - && g_queue_is_empty (load_queue) - && g_queue_is_empty (save_queue) - && g_queue_is_empty (thumbnail_queue_high) - && g_queue_is_empty (thumbnail_queue_low) - && g_queue_is_empty (fonts_queue) - && g_queue_is_empty (print_queue); -} - -/* the thread mainloop function */ -/** - * ev_render_thread: - * @data: data passed to the thread. - * - * The thread mainloop function. It does wait for any available job in synced - * queues to handle it. - * - * Returns: the return value of the thread, which will be returned by - * g_thread_join(). - */ -static gpointer -ev_render_thread (gpointer data) -{ - while (TRUE) { - EvJob *job; - - g_mutex_lock (ev_queue_mutex); - if (no_jobs_available_unlocked ()) { - g_cond_wait (render_cond, ev_queue_mutex); - } - - job = search_for_jobs_unlocked (); - g_mutex_unlock (ev_queue_mutex); - - /* Now that we have our job, we handle it */ - if (job) { - handle_job (job); - g_object_unref (G_OBJECT (job)); - } - } - return NULL; - -} - -/** - * ev_job_queue_run_next: - * - * It does look for any job on the render high priority queue first and after - * in the render low priority one, and then it does handle it. - */ -static void -ev_job_queue_run_next (void) -{ - EvJob *job; - - job = (EvJob *) g_queue_pop_head (async_render_queue_high); - - if (job == NULL) { - job = (EvJob *) g_queue_pop_head (async_render_queue_low); - } - - /* Now that we have our job, we handle it */ - if (job) { - handle_job (job); - g_object_unref (G_OBJECT (job)); - } -} - -/* Public Functions */ -/** - * ev_job_queue_init: - * - * Creates a new cond, new mutex, a thread for evince job handling and inits - * every queue. - */ -void -ev_job_queue_init (void) -{ - if (!g_thread_supported ()) g_thread_init (NULL); - - render_cond = g_cond_new (); - ev_queue_mutex = g_mutex_new (); - - links_queue = g_queue_new (); - load_queue = g_queue_new (); - save_queue = g_queue_new (); - render_queue_high = g_queue_new (); - render_queue_low = g_queue_new (); - async_render_queue_high = g_queue_new (); - async_render_queue_low = g_queue_new (); - thumbnail_queue_high = g_queue_new (); - thumbnail_queue_low = g_queue_new (); - fonts_queue = g_queue_new (); - print_queue = g_queue_new (); - - g_thread_create (ev_render_thread, NULL, FALSE, NULL); - -} - -static GQueue * -find_queue (EvJob *job, - EvJobPriority priority) -{ - if (EV_JOB (job)->async) { - if (EV_IS_JOB_RENDER (job)) { - if (priority == EV_JOB_PRIORITY_HIGH) - return async_render_queue_high; - else - return async_render_queue_low; - } - } else { - if (EV_IS_JOB_RENDER (job)) { - if (priority == EV_JOB_PRIORITY_HIGH) - return render_queue_high; - else - return render_queue_low; - } else if (EV_IS_JOB_THUMBNAIL (job)) { - if (priority == EV_JOB_PRIORITY_HIGH) - return thumbnail_queue_high; - else - return thumbnail_queue_low; - } else if (EV_IS_JOB_LOAD (job)) { - /* the priority doesn't effect load */ - return load_queue; - } else if (EV_IS_JOB_SAVE (job)) { - /* the priority doesn't effect save */ - return save_queue; - } else if (EV_IS_JOB_LINKS (job)) { - /* the priority doesn't effect links */ - return links_queue; - } else if (EV_IS_JOB_FONTS (job)) { - /* the priority doesn't effect fonts */ - return fonts_queue; - } else if (EV_IS_JOB_PRINT (job)) { - /* the priority doesn't effect print */ - return print_queue; - } - } - - g_assert_not_reached (); - return NULL; -} - -void -ev_job_queue_add_job (EvJob *job, - EvJobPriority priority) -{ - GQueue *queue; - - g_return_if_fail (EV_IS_JOB (job)); - - queue = find_queue (job, priority); - - if (!EV_JOB (job)->async) { - g_mutex_lock (ev_queue_mutex); - add_job_to_queue_locked (queue, job); - g_mutex_unlock (ev_queue_mutex); - } else { - add_job_to_async_queue (queue, job); - if (!async_rendering) { - ev_job_queue_run_next (); - } - } -} - -static gboolean -move_job_async (EvJob *job, GQueue *old_queue, GQueue *new_queue) -{ - gboolean retval = FALSE; - - g_object_ref (job); - - if (remove_job_from_queue_locked (old_queue, job)) { - add_job_to_async_queue (new_queue, job); - retval = TRUE; - } - - g_object_unref (job); - - return retval; -} - -static gboolean -move_job (EvJob *job, GQueue *old_queue, GQueue *new_queue) -{ - gboolean retval = FALSE; - - g_mutex_lock (ev_queue_mutex); - g_object_ref (job); - - if (remove_job_from_queue_locked (old_queue, job)) { - add_job_to_queue_locked (new_queue, job); - retval = TRUE; - } - - g_object_unref (job); - g_mutex_unlock (ev_queue_mutex); - - return retval; -} - -gboolean -ev_job_queue_update_job (EvJob *job, - EvJobPriority new_priority) -{ - gboolean retval = FALSE; - - g_return_val_if_fail (EV_IS_JOB (job), FALSE); - - if (EV_JOB (job)->async) { - if (EV_IS_JOB_RENDER (job)) { - if (new_priority == EV_JOB_PRIORITY_LOW) { - retval = move_job_async (job, async_render_queue_high, - async_render_queue_low); - } else if (new_priority == EV_JOB_PRIORITY_HIGH) { - retval = move_job_async (job, async_render_queue_low, - async_render_queue_high); - } - } else { - g_assert_not_reached (); - } - } else { - if (EV_IS_JOB_THUMBNAIL (job)) { - if (new_priority == EV_JOB_PRIORITY_LOW) { - retval = move_job (job, thumbnail_queue_high, - thumbnail_queue_low); - } else if (new_priority == EV_JOB_PRIORITY_HIGH) { - retval = move_job (job, thumbnail_queue_low, - thumbnail_queue_high); - } - } else if (EV_IS_JOB_RENDER (job)) { - if (new_priority == EV_JOB_PRIORITY_LOW) { - retval = move_job (job, render_queue_high, - render_queue_low); - } else if (new_priority == EV_JOB_PRIORITY_HIGH) { - retval = move_job (job, render_queue_low, - render_queue_high); - } - } else { - g_assert_not_reached (); - } - } - - return retval; -} - -gboolean -ev_job_queue_remove_job (EvJob *job) -{ - gboolean retval = FALSE; - - g_return_val_if_fail (EV_IS_JOB (job), FALSE); - - if (EV_JOB (job)->async) { - if (EV_IS_JOB_RENDER (job)) { - retval = remove_job_from_async_queue (async_render_queue_high, job); - retval = retval || remove_job_from_async_queue (async_render_queue_low, job); - } else { - g_assert_not_reached (); - } - } else { - g_mutex_lock (ev_queue_mutex); - - if (EV_IS_JOB_THUMBNAIL (job)) { - retval = remove_job_from_queue_locked (thumbnail_queue_high, job); - retval = retval || remove_job_from_queue_locked (thumbnail_queue_low, job); - } else if (EV_IS_JOB_RENDER (job)) { - retval = remove_job_from_queue_locked (render_queue_high, job); - retval = retval || remove_job_from_queue_locked (render_queue_low, job); - } else if (EV_IS_JOB_LINKS (job)) { - retval = remove_job_from_queue_locked (links_queue, job); - } else if (EV_IS_JOB_LOAD (job)) { - retval = remove_job_from_queue_locked (load_queue, job); - } else if (EV_IS_JOB_SAVE (job)) { - retval = remove_job_from_queue_locked (save_queue, job); - } else if (EV_IS_JOB_FONTS (job)) { - retval = remove_job_from_queue_locked (fonts_queue, job); - } else if (EV_IS_JOB_PRINT (job)) { - retval = remove_job_from_queue_locked (print_queue, job); - } else { - g_assert_not_reached (); - } - - g_mutex_unlock (ev_queue_mutex); - } - - return retval; -} - - diff --git a/shell/ev-job-scheduler.c b/shell/ev-job-scheduler.c new file mode 100644 index 00000000..900714ee --- /dev/null +++ b/shell/ev-job-scheduler.c @@ -0,0 +1,305 @@ +/* ev-job-scheduler.c + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2008 Carlos Garcia Campos + * + * Evince is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Evince is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ev-debug.h" +#include "ev-job-scheduler.h" + +typedef struct _EvSchedulerJob { + EvJob *job; + EvJobPriority priority; + GSList *job_link; +} EvSchedulerJob; + +G_LOCK_DEFINE_STATIC(job_list); +static GSList *job_list = NULL; + +static gpointer ev_job_thread_proxy (gpointer data); +static void ev_scheduler_thread_job_cancelled (EvSchedulerJob *job, + GCancellable *cancellable); + +/* EvJobQueue */ +static GQueue queue_urgent = G_QUEUE_INIT; +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 GQueue *job_queue[EV_JOB_N_PRIORITIES] = { + &queue_urgent, + &queue_high, + &queue_low, + &queue_none +}; + +static void +ev_job_queue_push (EvSchedulerJob *job, + EvJobPriority priority) +{ + ev_debug_message (DEBUG_JOBS, "%s priority %d", EV_GET_TYPE_NAME (job->job), priority); + + g_mutex_lock (job_queue_mutex); + + g_queue_push_tail (job_queue[priority], job); + g_cond_broadcast (job_queue_cond); + + g_mutex_unlock (job_queue_mutex); +} + +static EvSchedulerJob * +ev_job_queue_get_next_unlocked (void) +{ + gint i; + EvSchedulerJob *job = NULL; + + for (i = EV_JOB_PRIORITY_URGENT; i < EV_JOB_N_PRIORITIES; i++) { + job = (EvSchedulerJob *) g_queue_pop_head (job_queue[i]); + if (job) + break; + } + + ev_debug_message (DEBUG_JOBS, "%s", job ? EV_GET_TYPE_NAME (job->job) : "No jobs in queue"); + + return job; +} + +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); + + return NULL; +} + +static void +ev_scheduler_job_list_add (EvSchedulerJob *job) +{ + ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job->job)); + + G_LOCK (job_list); + + job_list = g_slist_prepend (job_list, job); + job->job_link = job_list; + + G_UNLOCK (job_list); +} + +static void +ev_scheduler_job_list_remove (EvSchedulerJob *job) +{ + ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job->job)); + + G_LOCK (job_list); + + job_list = g_slist_delete_link (job_list, job->job_link); + + G_UNLOCK (job_list); +} + +static void +ev_scheduler_job_free (EvSchedulerJob *job) +{ + if (!job) + return; + + g_object_unref (job->job); + g_free (job); +} + +static void +ev_scheduler_job_destroy (EvSchedulerJob *job) +{ + ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job->job)); + + if (job->job->run_mode == EV_JOB_RUN_MAIN_LOOP) { + g_signal_handlers_disconnect_by_func (job->job, + G_CALLBACK (ev_scheduler_job_destroy), + job); + } else { + g_signal_handlers_disconnect_by_func (job->job->cancellable, + G_CALLBACK (ev_scheduler_thread_job_cancelled), + job); + } + + ev_scheduler_job_list_remove (job); + ev_scheduler_job_free (job); +} + +static void +ev_scheduler_thread_job_cancelled (EvSchedulerJob *job, + GCancellable *cancellable) +{ + GList *list; + + ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job->job)); + + g_mutex_lock (job_queue_mutex); + + /* If the job is not still running, + * remove it from the job queue and job list. + * If the job is currently running, it will be + * destroyed as soon as it finishes. + */ + 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); + ev_scheduler_job_destroy (job); + } else { + g_mutex_unlock (job_queue_mutex); + } +} + +static void +ev_job_thread (EvJob *job) +{ + gboolean result; + + ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job)); + + do { + if (g_cancellable_is_cancelled (job->cancellable)) + result = FALSE; + else + result = ev_job_run (job); + } while (result); +} + +static gboolean +ev_job_idle (EvJob *job) +{ + ev_debug_message (DEBUG_JOBS, "%s", EV_GET_TYPE_NAME (job)); + + if (g_cancellable_is_cancelled (job->cancellable)) + return FALSE; + + return ev_job_run (job); +} + +static gpointer +ev_job_thread_proxy (gpointer data) +{ + while (TRUE) { + EvSchedulerJob *job; + + 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); + continue; + } + g_mutex_unlock (job_queue_mutex); + + ev_job_thread (job->job); + ev_scheduler_job_destroy (job); + } + + return NULL; +} + +void +ev_job_scheduler_push_job (EvJob *job, + EvJobPriority priority) +{ + static GOnce once_init = G_ONCE_INIT; + EvSchedulerJob *s_job; + + g_once (&once_init, ev_job_scheduler_init, NULL); + + ev_debug_message (DEBUG_JOBS, "%s pirority %d", EV_GET_TYPE_NAME (job), priority); + + s_job = g_new0 (EvSchedulerJob, 1); + s_job->job = g_object_ref (job); + s_job->priority = priority; + + ev_scheduler_job_list_add (s_job); + + switch (ev_job_get_run_mode (job)) { + case EV_JOB_RUN_THREAD: + g_signal_connect_swapped (job->cancellable, "cancelled", + G_CALLBACK (ev_scheduler_thread_job_cancelled), + s_job); + ev_job_queue_push (s_job, priority); + break; + case EV_JOB_RUN_MAIN_LOOP: + g_signal_connect_swapped (job, "finished", + G_CALLBACK (ev_scheduler_job_destroy), + s_job); + g_signal_connect_swapped (job, "cancelled", + G_CALLBACK (ev_scheduler_job_destroy), + s_job); + g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc)ev_job_idle, + g_object_ref (job), + (GDestroyNotify)g_object_unref); + break; + default: + g_assert_not_reached (); + } +} + +void +ev_job_scheduler_update_job (EvJob *job, + EvJobPriority priority) +{ + GSList *l; + EvSchedulerJob *s_job = NULL; + gboolean need_resort = FALSE; + + /* Main loop jobs are scheduled inmediately */ + if (ev_job_get_run_mode (job) == EV_JOB_RUN_MAIN_LOOP) + return; + + ev_debug_message (DEBUG_JOBS, "%s pirority %d", EV_GET_TYPE_NAME (job), priority); + + G_LOCK (job_list); + + for (l = job_list; l; l = l->next) { + s_job = (EvSchedulerJob *)l->data; + + if (s_job->job == job) { + need_resort = (s_job->priority != priority); + break; + } + } + + G_UNLOCK (job_list); + + if (need_resort) { + GList *list; + + g_mutex_lock (job_queue_mutex); + + list = g_queue_find (job_queue[s_job->priority], s_job); + if (list) { + ev_debug_message (DEBUG_JOBS, "Moving job %s from pirority %d to %d", + 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_mutex_unlock (job_queue_mutex); + } +} + diff --git a/shell/ev-job-queue.h b/shell/ev-job-scheduler.h similarity index 51% rename from shell/ev-job-queue.h rename to shell/ev-job-scheduler.h index e6e4c0ef..66f9f80c 100644 --- a/shell/ev-job-queue.h +++ b/shell/ev-job-scheduler.h @@ -1,6 +1,7 @@ -/* this file is part of evince, a gnome document viewer +/* ev-job-scheduler.h + * this file is part of evince, a gnome document viewer * - * Copyright (C) 2005 Red Hat, Inc + * Copyright (C) 2008 Carlos Garcia Campos * * Evince is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by @@ -17,23 +18,27 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __EV_JOB_QUEUE_H__ -#define __EV_JOB_QUEUE_H__ +#ifndef EV_JOB_SCHEDULER_H +#define EV_JOB_SCHEDULER_H -#include +#include #include "ev-jobs.h" G_BEGIN_DECLS +typedef enum { + EV_JOB_PRIORITY_URGENT, /* Rendering current page range */ + EV_JOB_PRIORITY_HIGH, /* Rendering current thumbnail range */ + EV_JOB_PRIORITY_LOW, /* Rendering pages not in current range */ + EV_JOB_PRIORITY_NONE, /* Any other job: load, save, print, ... */ + EV_JOB_N_PRIORITIES +} EvJobPriority; -void ev_job_queue_init (void); - -void ev_job_queue_add_job (EvJob *job, - EvJobPriority priority); -gboolean ev_job_queue_update_job (EvJob *job, - EvJobPriority new_priority); -gboolean ev_job_queue_remove_job (EvJob *job); +void ev_job_scheduler_push_job (EvJob *job, + EvJobPriority priority); +void ev_job_scheduler_update_job (EvJob *job, + EvJobPriority priority); G_END_DECLS -#endif /* __EV_JOB_QUEUE_H__ */ +#endif /* EV_JOB_SCHEDULER_H */ diff --git a/shell/ev-jobs.c b/shell/ev-jobs.c index 196bad68..7371dd1a 100644 --- a/shell/ev-jobs.c +++ b/shell/ev-jobs.c @@ -1,6 +1,26 @@ +/* this file is part of evince, a gnome document viewer + * + * Copyright (C) 2008 Carlos Garcia Campos + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + #include + #include "ev-jobs.h" -#include "ev-job-queue.h" #include "ev-document-thumbnails.h" #include "ev-document-links.h" #include "ev-document-images.h" @@ -34,6 +54,7 @@ static void ev_job_print_init (EvJobPrint *job); static void ev_job_print_class_init (EvJobPrintClass *class); enum { + CANCELLED, FINISHED, LAST_SIGNAL }; @@ -43,10 +64,16 @@ enum { RENDER_LAST_SIGNAL }; +enum { + UPDATED, + FONTS_LAST_SIGNAL +}; + static guint job_signals[LAST_SIGNAL] = { 0 }; static guint job_render_signals[RENDER_LAST_SIGNAL] = { 0 }; +static guint job_fonts_signals[FONTS_LAST_SIGNAL] = { 0 }; -G_DEFINE_TYPE (EvJob, ev_job, G_TYPE_OBJECT) +G_DEFINE_ABSTRACT_TYPE (EvJob, ev_job, G_TYPE_OBJECT) G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB) @@ -55,7 +82,12 @@ G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB) -static void ev_job_init (EvJob *job) { /* Do Nothing */ } +/* EvJob */ +static void +ev_job_init (EvJob *job) +{ + job->cancellable = g_cancellable_new (); +} static void ev_job_dispose (GObject *object) @@ -69,6 +101,16 @@ ev_job_dispose (GObject *object) job->document = NULL; } + if (job->cancellable) { + g_object_unref (job->cancellable); + job->cancellable = NULL; + } + + if (job->error) { + g_error_free (job->error); + job->error = NULL; + } + (* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object); } @@ -81,18 +123,173 @@ ev_job_class_init (EvJobClass *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_LAST, + 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); -static void ev_job_links_init (EvJobLinks *job) { /* Do Nothing */ } + 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 FALSE; +} + +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 || (job->finished && job->idle_finished_id == 0)) + 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); + 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 (domain, code, message); + g_free (message); + + ev_job_emit_finished (job); +} + +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) @@ -111,18 +308,52 @@ ev_job_links_dispose (GObject *object) (* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object); } +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 (); + + ev_job_succeeded (job); + + return FALSE; +} + static void ev_job_links_class_init (EvJobLinksClass *class) { - GObjectClass *oclass; - - oclass = G_OBJECT_CLASS (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; -static void ev_job_render_init (EvJobRender *job) { /* Do Nothing */ } + ev_debug_message (DEBUG_JOBS, NULL); + + job = g_object_new (EV_TYPE_JOB_LINKS, 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) @@ -132,7 +363,7 @@ ev_job_render_dispose (GObject *object) job = EV_JOB_RENDER (object); if (job->ev_page) { - ev_debug_message (DEBUG_JOBS, "page: %d", job->ev_page->index); + ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job->ev_page->index, job); g_object_unref (job->ev_page); job->ev_page = NULL; } @@ -155,132 +386,121 @@ ev_job_render_dispose (GObject *object) (* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object); } -static void -ev_job_render_class_init (EvJobRenderClass *class) +static gboolean +notify_page_ready (EvJobRender *job) { - GObjectClass *oclass; - - oclass = G_OBJECT_CLASS (class); + ev_debug_message (DEBUG_JOBS, "%d (%p)", job->ev_page->index, job); + ev_profiler_stop (EV_PROFILE_JOBS, "Rendering page %d", job->ev_page->index); - job_render_signals [PAGE_READY] = - g_signal_new ("page-ready", - EV_TYPE_JOB_RENDER, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EvJobRenderClass, page_ready), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + if (EV_JOB (job)->cancelled) { + ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, do not emit page_ready", EV_GET_TYPE_NAME (job), job); + } else { + g_signal_emit (job, job_render_signals[PAGE_READY], 0); + } - oclass->dispose = ev_job_render_dispose; + return FALSE; } -static void ev_job_thumbnail_init (EvJobThumbnail *job) { /* Do Nothing */ } - static void -ev_job_thumbnail_dispose (GObject *object) +ev_job_render_page_ready (EvJobRender *job) { - EvJobThumbnail *job; - - job = EV_JOB_THUMBNAIL (object); - - ev_debug_message (DEBUG_JOBS, "%d", job->page); + ev_debug_message (DEBUG_JOBS, "%d (%p)", job->ev_page->index, job); - if (job->thumbnail) { - g_object_unref (job->thumbnail); - job->thumbnail = NULL; - } - - (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object); + job->page_ready = TRUE; + g_idle_add_full (G_PRIORITY_HIGH_IDLE, + (GSourceFunc)notify_page_ready, + g_object_ref (job), + (GDestroyNotify)g_object_unref); } -static void -ev_job_thumbnail_class_init (EvJobThumbnailClass *class) +static gboolean +ev_job_render_run (EvJob *job) { - GObjectClass *oclass; - - oclass = G_OBJECT_CLASS (class); - - oclass->dispose = ev_job_thumbnail_dispose; -} - -static void ev_job_print_init (EvJobPrint *job) { /* Do Nothing */ } + EvJobRender *job_render = EV_JOB_RENDER (job); + EvRenderContext *rc; -static void -ev_job_print_dispose (GObject *object) -{ - EvJobPrint *job; + 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 (); - job = EV_JOB_PRINT (object); + ev_profiler_start (EV_PROFILE_JOBS, "Rendering page %d", job_render->page); + + ev_document_fc_mutex_lock (); - ev_debug_message (DEBUG_JOBS, NULL); - - if (job->temp_file) { - g_unlink (job->temp_file); - g_free (job->temp_file); - job->temp_file = NULL; - } + job_render->ev_page = ev_document_get_page (job->document, job_render->page); + rc = ev_render_context_new (job_render->ev_page, job_render->rotation, job_render->scale); + + job_render->surface = ev_document_render (job->document, rc); + /* 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); - if (job->error) { - g_error_free (job->error); - job->error = NULL; + return FALSE; } - - if (job->ranges) { - g_free (job->ranges); - job->ranges = NULL; - job->n_ranges = 0; + + if ((job_render->flags & EV_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_CLASS (ev_job_print_parent_class)->dispose) (object); -} - -static void -ev_job_print_class_init (EvJobPrintClass *class) -{ - GObjectClass *oclass; - - oclass = G_OBJECT_CLASS (class); - - oclass->dispose = ev_job_print_dispose; -} - -/* Public functions */ -void -ev_job_finished (EvJob *job) -{ - ev_debug_message (DEBUG_JOBS, EV_GET_TYPE_NAME (job)); - ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); + ev_job_render_page_ready (job_render); + + ev_document_fc_mutex_unlock (); + + if ((job_render->flags & EV_RENDER_INCLUDE_TEXT) && EV_IS_SELECTION (job->document)) + job_render->text_mapping = + ev_selection_get_selection_map (EV_SELECTION (job->document), rc); + if ((job_render->flags & EV_RENDER_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (job->document)) + job_render->link_mapping = + ev_document_links_get_links (EV_DOCUMENT_LINKS (job->document), job_render->page); + if ((job_render->flags & EV_RENDER_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (job->document)) + job_render->form_field_mapping = + ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (job->document), + job_render->ev_page); + if ((job_render->flags & EV_RENDER_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (job->document)) + job_render->image_mapping = + ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (job->document), + job_render->page); + g_object_unref (rc); + ev_document_doc_mutex_unlock (); - g_return_if_fail (EV_IS_JOB (job)); + ev_job_succeeded (job); - g_signal_emit (job, job_signals[FINISHED], 0); + return FALSE; } -EvJob * -ev_job_links_new (EvDocument *document) +static void +ev_job_render_class_init (EvJobRenderClass *class) { - 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; -} + GObjectClass *oclass = G_OBJECT_CLASS (class); + EvJobClass *job_class = EV_JOB_CLASS (class); -void -ev_job_links_run (EvJobLinks *job) -{ - ev_debug_message (DEBUG_JOBS, NULL); - ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); - - g_return_if_fail (EV_IS_JOB_LINKS (job)); + job_render_signals [PAGE_READY] = + g_signal_new ("page-ready", + EV_TYPE_JOB_RENDER, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EvJobRenderClass, page_ready), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); - ev_document_doc_mutex_lock (); - job->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (EV_JOB (job)->document)); - EV_JOB (job)->finished = TRUE; - ev_document_doc_mutex_unlock (); + oclass->dispose = ev_job_render_dispose; + job_class->run = ev_job_render_run; } EvJob * @@ -306,10 +526,6 @@ ev_job_render_new (EvDocument *document, job->target_height = height; job->flags = flags; - if (EV_IS_ASYNC_RENDERER (document)) { - EV_JOB (job)->async = TRUE; - } - return EV_JOB (job); } @@ -328,111 +544,64 @@ ev_job_render_set_selection_info (EvJobRender *job, job->base = *base; } +/* EvJobThumbnail */ static void -render_finished_cb (EvDocument *document, - GdkPixbuf *pixbuf, - EvJobRender *job) +ev_job_thumbnail_init (EvJobThumbnail *job) { - g_signal_handlers_disconnect_by_func (EV_JOB (job)->document, - render_finished_cb, job); - - job->surface = ev_document_misc_surface_from_pixbuf (pixbuf); - job->page_ready = TRUE; - g_signal_emit (job, job_render_signals[PAGE_READY], 0); - EV_JOB (job)->finished = TRUE; - ev_job_finished (EV_JOB (job)); + EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; } -static gboolean -notify_page_ready (EvJobRender *job) +static void +ev_job_thumbnail_dispose (GObject *object) { - ev_debug_message (DEBUG_JOBS, "%d", job->ev_page->index); - ev_profiler_stop (EV_PROFILE_JOBS, "Rendering page %d", job->ev_page->index); - - g_signal_emit (job, job_render_signals[PAGE_READY], 0); + EvJobThumbnail *job; - return FALSE; -} + job = EV_JOB_THUMBNAIL (object); -static void -ev_job_render_page_ready (EvJobRender *job) -{ - ev_debug_message (DEBUG_JOBS, "%d", job->ev_page->index); + ev_debug_message (DEBUG_JOBS, "%d (%p)", job->page, job); - job->page_ready = TRUE; - g_idle_add_full (G_PRIORITY_HIGH_IDLE, - (GSourceFunc)notify_page_ready, - g_object_ref (job), - (GDestroyNotify)g_object_unref); + if (job->thumbnail) { + g_object_unref (job->thumbnail); + job->thumbnail = NULL; + } + + (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object); } -void -ev_job_render_run (EvJobRender *job) +static gboolean +ev_job_thumbnail_run (EvJob *job) { - g_return_if_fail (EV_IS_JOB_RENDER (job)); + EvJobThumbnail *job_thumb = EV_JOB_THUMBNAIL (job); + EvRenderContext *rc; + EvPage *page; - ev_debug_message (DEBUG_JOBS, "page: %d", job->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 (EV_JOB (job)->async) { - EvAsyncRenderer *renderer = EV_ASYNC_RENDERER (EV_JOB (job)->document); - ev_async_renderer_render_pixbuf (renderer, job->page, job->scale, - job->rotation); - g_signal_connect (EV_JOB (job)->document, "render_finished", - G_CALLBACK (render_finished_cb), job); - } else { - EvRenderContext *rc; - - ev_profiler_start (EV_PROFILE_JOBS, "Rendering page %d", job->page); - - ev_document_fc_mutex_lock (); + page = ev_document_get_page (job->document, job_thumb->page); + rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + g_object_unref (page); - job->ev_page = ev_document_get_page (EV_JOB (job)->document, job->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 (); - rc = ev_render_context_new (job->ev_page, job->rotation, job->scale); - - job->surface = ev_document_render (EV_JOB (job)->document, rc); - if ((job->flags & EV_RENDER_INCLUDE_SELECTION) && EV_IS_SELECTION (EV_JOB (job)->document)) { - ev_selection_render_selection (EV_SELECTION (EV_JOB (job)->document), - rc, - &(job->selection), - &(job->selection_points), - NULL, - job->selection_style, - &(job->text), &(job->base)); - job->selection_region = - ev_selection_get_selection_region (EV_SELECTION (EV_JOB (job)->document), - rc, - job->selection_style, - &(job->selection_points)); - } + ev_job_succeeded (job); + + return FALSE; +} - ev_job_render_page_ready (job); - - ev_document_fc_mutex_unlock (); - - if ((job->flags & EV_RENDER_INCLUDE_TEXT) && EV_IS_SELECTION (EV_JOB (job)->document)) - job->text_mapping = - ev_selection_get_selection_map (EV_SELECTION (EV_JOB (job)->document), rc); - if ((job->flags & EV_RENDER_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (EV_JOB (job)->document)) - job->link_mapping = - ev_document_links_get_links (EV_DOCUMENT_LINKS (EV_JOB (job)->document), job->page); - if ((job->flags & EV_RENDER_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (EV_JOB (job)->document)) - job->form_field_mapping = - ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (EV_JOB (job)->document), - job->ev_page); - if ((job->flags & EV_RENDER_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (EV_JOB (job)->document)) - job->image_mapping = - ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (EV_JOB (job)->document), - job->page); - g_object_unref (rc); - - EV_JOB (job)->finished = TRUE; - } +static void +ev_job_thumbnail_class_init (EvJobThumbnailClass *class) +{ + GObjectClass *oclass = G_OBJECT_CLASS (class); + EvJobClass *job_class = EV_JOB_CLASS (class); - ev_document_doc_mutex_unlock (); + oclass->dispose = ev_job_thumbnail_dispose; + job_class->run = ev_job_thumbnail_run; } EvJob * @@ -455,35 +624,64 @@ ev_job_thumbnail_new (EvDocument *document, return EV_JOB (job); } -void -ev_job_thumbnail_run (EvJobThumbnail *job) +/* EvJobFonts */ +static void +ev_job_fonts_init (EvJobFonts *job) { - EvRenderContext *rc; - EvPage *page; + EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP; +} - ev_debug_message (DEBUG_JOBS, "%d", job->page); - ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); +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; - g_return_if_fail (EV_IS_JOB_THUMBNAIL (job)); + if (!ev_document_fc_mutex_trylock ()) + return TRUE; - ev_document_doc_mutex_lock (); +#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 - page = ev_document_get_page (EV_JOB (job)->document, job->page); - rc = ev_render_context_new (page, job->rotation, job->scale); - g_object_unref (page); + job_fonts->scan_completed = !ev_document_fonts_scan (fonts, 20); + g_signal_emit (job_fonts, job_fonts_signals[UPDATED], 0, + ev_document_fonts_get_progress (fonts)); - job->thumbnail = - ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB (job)->document), - rc, TRUE); - g_object_unref (rc); + ev_document_fc_mutex_unlock (); ev_document_doc_mutex_unlock (); + + if (job_fonts->scan_completed) + ev_job_succeeded (job); - EV_JOB (job)->finished = TRUE; + return !job_fonts->scan_completed; } -static void ev_job_fonts_init (EvJobFonts *job) { /* Do Nothing */ } - -static void ev_job_fonts_class_init (EvJobFontsClass *class) { /* Do Nothing */ } +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[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) @@ -499,30 +697,13 @@ ev_job_fonts_new (EvDocument *document) return EV_JOB (job); } -void -ev_job_fonts_run (EvJobFonts *job) +/* EvJobLoad */ +static void +ev_job_load_init (EvJobLoad *job) { - EvDocumentFonts *fonts; - - ev_debug_message (DEBUG_JOBS, NULL); - ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); - - g_return_if_fail (EV_IS_JOB_FONTS (job)); - - ev_document_doc_mutex_lock (); - - fonts = EV_DOCUMENT_FONTS (EV_JOB (job)->document); - ev_document_fc_mutex_lock (); - job->scan_completed = !ev_document_fonts_scan (fonts, 20); - ev_document_fc_mutex_unlock (); - - EV_JOB (job)->finished = TRUE; - - ev_document_doc_mutex_unlock (); + EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; } -static void ev_job_load_init (EvJobLoad *job) { /* Do Nothing */ } - static void ev_job_load_dispose (GObject *object) { @@ -535,11 +716,6 @@ ev_job_load_dispose (GObject *object) job->uri = NULL; } - if (job->error) { - g_error_free (job->error); - job->error = NULL; - } - if (job->dest) { g_object_unref (job->dest); job->dest = NULL; @@ -553,17 +729,52 @@ ev_job_load_dispose (GObject *object) (* 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 (); + + /* TODO: reuse the job!!! */ + /* 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) { + ev_document_load (job->document, + 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; - - oclass = G_OBJECT_CLASS (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, EvLinkDest *dest, @@ -577,12 +788,9 @@ ev_job_load_new (const gchar *uri, job = g_object_new (EV_TYPE_JOB_LOAD, NULL); job->uri = g_strdup (uri); - if (dest) - job->dest = g_object_ref (dest); - + job->dest = dest ? g_object_ref (dest) : NULL; job->mode = mode; - if (search_string) - job->search_string = g_strdup (search_string); + job->search_string = search_string ? g_strdup (search_string) : NULL; return EV_JOB (job); } @@ -597,40 +805,13 @@ ev_job_load_set_uri (EvJobLoad *job, const gchar *uri) job->uri = g_strdup (uri); } -void -ev_job_load_run (EvJobLoad *job) +/* EvJobSave */ +static void +ev_job_save_init (EvJobSave *job) { - g_return_if_fail (EV_IS_JOB_LOAD (job)); - - ev_debug_message (DEBUG_JOBS, "%s", job->uri); - ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); - - if (job->error) { - g_error_free (job->error); - job->error = NULL; - } - - 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 (EV_JOB (job)->document) { - ev_document_load (EV_JOB (job)->document, - job->uri, - &job->error); - } else { - EV_JOB(job)->document = - ev_document_factory_get_document (job->uri, - &job->error); - } - - ev_document_fc_mutex_unlock (); - EV_JOB (job)->finished = TRUE; + EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; } -static void ev_job_save_init (EvJobSave *job) { /* Do Nothing */ } - static void ev_job_save_dispose (GObject *object) { @@ -648,52 +829,20 @@ ev_job_save_dispose (GObject *object) job->document_uri = NULL; } - if (job->error) { - g_error_free (job->error); - job->error = NULL; - } - (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object); } -static void -ev_job_save_class_init (EvJobSaveClass *class) -{ - GObjectClass *oclass; - - oclass = G_OBJECT_CLASS (class); - - oclass->dispose = ev_job_save_dispose; -} - -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); - job->error = NULL; - - return EV_JOB (job); -} - -void -ev_job_save_run (EvJobSave *job) +static gboolean +ev_job_save_run (EvJob *job) { - gint fd; - gchar *filename; - gchar *tmp_filename; - gchar *local_uri; - - ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job->uri, job->document_uri); + EvJobSave *job_save = EV_JOB_SAVE (job); + gint fd; + gchar *filename; + gchar *tmp_filename; + 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); filename = ev_tmp_filename ("saveacopy"); @@ -706,53 +855,55 @@ ev_job_save_run (EvJobSave *job) gint save_errno = errno; display_name = g_filename_display_name (tmp_filename); - g_set_error (&(job->error), - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to create file “%s”: %s"), - display_name, g_strerror (save_errno)); + ev_job_failed (job, + G_FILE_ERROR, + g_file_error_from_errno (save_errno), + _("Failed to create file “%s”: %s"), + display_name, g_strerror (save_errno)); g_free (display_name); g_free (tmp_filename); - return; + return FALSE; } ev_document_doc_mutex_lock (); /* Save document to temp filename */ local_uri = g_filename_to_uri (tmp_filename, NULL, NULL); - ev_document_save (EV_JOB (job)->document, local_uri, &(job->error)); + ev_document_save (job->document, local_uri, &error); close (fd); ev_document_doc_mutex_unlock (); - if (job->error) { + if (error) { g_free (local_uri); - return; + 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 (EV_JOB (job)->document), - "uri-uncompressed")) { + 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->document_uri, ".gz"); + ext = g_strrstr (job_save->document_uri, ".gz"); if (ext && g_ascii_strcasecmp (ext, ".gz") == 0) ctype = EV_COMPRESSION_GZIP; - ext = g_strrstr (job->document_uri, ".bz2"); + 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, &(job->error)); + uri_comp = ev_file_compress (local_uri, ctype, &error); g_free (local_uri); ev_tmp_filename_unlink (tmp_filename); - if (!uri_comp || job->error) { + if (!uri_comp || error) { local_uri = NULL; } else { local_uri = uri_comp; @@ -761,63 +912,87 @@ ev_job_save_run (EvJobSave *job) g_free (tmp_filename); - if (job->error) { + if (error) { g_free (local_uri); - return; + ev_job_failed_from_error (job, error); + g_error_free (error); + + return FALSE; } if (!local_uri) - return; + return FALSE; - ev_xfer_uri_simple (local_uri, job->uri, &(job->error)); + ev_xfer_uri_simple (local_uri, job_save->uri, &error); ev_tmp_uri_unlink (local_uri); + + 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_print_new (EvDocument *document, - const gchar *format, - gdouble width, - gdouble height, - EvPrintRange *ranges, - gint n_ranges, - EvPrintPageSet page_set, - gint pages_per_sheet, - gint copies, - gdouble collate, - gdouble reverse) +ev_job_save_new (EvDocument *document, + const gchar *uri, + const gchar *document_uri) { - EvJobPrint *job; + EvJobSave *job; - ev_debug_message (DEBUG_JOBS, "format: %s, width: %f, height:%f," - "n_ranges: %d, pages_per_sheet: %d, copies: %d," - "collate: %s, reverse: %s", - format, width, height, n_ranges, pages_per_sheet, copies, - collate ? "True" : "False", reverse ? "True" : "False"); + ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri); - job = g_object_new (EV_TYPE_JOB_PRINT, NULL); + 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); - job->format = format; - - job->temp_file = NULL; - job->error = NULL; + return EV_JOB (job); +} - job->width = width; - job->height = height; +/* EvJobPrint */ +static void +ev_job_print_init (EvJobPrint *job) +{ + EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; +} - job->ranges = ranges; - job->n_ranges = n_ranges; +static void +ev_job_print_dispose (GObject *object) +{ + EvJobPrint *job; - job->page_set = page_set; + job = EV_JOB_PRINT (object); - job->pages_per_sheet = CLAMP (pages_per_sheet, 1, 16); - - job->copies = copies; - job->collate = collate; - job->reverse = reverse; + ev_debug_message (DEBUG_JOBS, NULL); - return EV_JOB (job); + if (job->temp_file) { + g_unlink (job->temp_file); + g_free (job->temp_file); + job->temp_file = NULL; + } + + if (job->ranges) { + g_free (job->ranges); + job->ranges = NULL; + job->n_ranges = 0; + } + + (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object); } static gint @@ -933,10 +1108,11 @@ ev_job_print_get_page_list (EvJobPrint *job, return page_list; } -void -ev_job_print_run (EvJobPrint *job) +static gboolean +ev_job_print_run (EvJob *job) { EvDocument *document = EV_JOB (job)->document; + EvJobPrint *job_print = EV_JOB_PRINT (job); EvFileExporterContext fc; EvRenderContext *rc; gint fd; @@ -946,68 +1122,67 @@ ev_job_print_run (EvJobPrint *job) gint first_page; gint i, j; gchar *filename; + GError *error = NULL; - g_return_if_fail (EV_IS_JOB_PRINT (job)); - ev_debug_message (DEBUG_JOBS, NULL); ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); - if (job->temp_file) - g_free (job->temp_file); - job->temp_file = NULL; + if (job_print->temp_file) + g_free (job_print->temp_file); + job_print->temp_file = NULL; - if (job->error) - g_error_free (job->error); - job->error = NULL; - - filename = g_strdup_printf ("evince_print.%s.XXXXXX", job->format); - fd = g_file_open_tmp (filename, &job->temp_file, &job->error); + filename = g_strdup_printf ("evince_print.%s.XXXXXX", job_print->format); + fd = g_file_open_tmp (filename, &job_print->temp_file, &error); g_free (filename); if (fd <= -1) { - EV_JOB (job)->finished = TRUE; - return; + ev_job_failed_from_error (job, error); + g_error_free (error); + + return FALSE; } - page_list = ev_job_print_get_page_list (job, &n_pages); + page_list = ev_job_print_get_page_list (job_print, &n_pages); if (n_pages == 0) { close (fd); - EV_JOB (job)->finished = TRUE; - return; + /* TODO: error */ + ev_job_succeeded (job); + + return FALSE; } - first_page = ev_print_job_get_first_page (job); - last_page = ev_print_job_get_last_page (job); + first_page = ev_print_job_get_first_page (job_print); + last_page = ev_print_job_get_last_page (job_print); - fc.format = g_ascii_strcasecmp (job->format, "pdf") == 0 ? + fc.format = g_ascii_strcasecmp (job_print->format, "pdf") == 0 ? EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS; - fc.filename = job->temp_file; + fc.filename = job_print->temp_file; fc.first_page = MIN (first_page, last_page); fc.last_page = MAX (first_page, last_page); - fc.paper_width = job->width; - fc.paper_height = job->height; + fc.paper_width = job_print->width; + fc.paper_height = job_print->height; fc.duplex = FALSE; - fc.pages_per_sheet = MAX (1, job->pages_per_sheet); + fc.pages_per_sheet = MAX (1, job_print->pages_per_sheet); rc = ev_render_context_new (NULL, 0, 1.0); ev_document_doc_mutex_lock (); ev_file_exporter_begin (EV_FILE_EXPORTER (document), &fc); - for (i = 0; i < job->copies; i++) { + for (i = 0; i < job_print->copies; i++) { gint page, step; gint n_copies; - step = job->reverse ? -1 * job->pages_per_sheet : job->pages_per_sheet; - page = job->reverse ? ((n_pages - 1) / job->pages_per_sheet) * job->pages_per_sheet : 0; - n_copies = job->collate ? 1 : job->copies; + step = job_print->reverse ? -1 * job_print->pages_per_sheet : job_print->pages_per_sheet; + page = job_print->reverse ? ((n_pages - 1) / job_print->pages_per_sheet) * job_print->pages_per_sheet : 0; + n_copies = job_print->collate ? 1 : job_print->copies; - while ((job->reverse && (page >= 0)) || (!job->reverse && (page < n_pages))) { + while ((job_print->reverse && (page >= 0)) || (!job_print->reverse && (page < n_pages))) { gint k; for (k = 0; k < n_copies; k++) { ev_file_exporter_begin_page (EV_FILE_EXPORTER (document)); - for (j = 0; j < job->pages_per_sheet; j++) { + for (j = 0; j < job_print->pages_per_sheet; j++) { EvPage *ev_page; gint p = page + j; @@ -1028,7 +1203,7 @@ ev_job_print_run (EvJobPrint *job) page += step; } - if (!job->collate) + if (!job_print->collate) break; } @@ -1039,5 +1214,64 @@ ev_job_print_run (EvJobPrint *job) close (fd); g_object_unref (rc); - EV_JOB (job)->finished = TRUE; + ev_job_succeeded (job); + + 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, + const gchar *format, + gdouble width, + gdouble height, + EvPrintRange *ranges, + gint n_ranges, + EvPrintPageSet page_set, + gint pages_per_sheet, + gint copies, + gdouble collate, + gdouble reverse) +{ + EvJobPrint *job; + + ev_debug_message (DEBUG_JOBS, "format: %s, width: %f, height:%f," + "n_ranges: %d, pages_per_sheet: %d, copies: %d," + "collate: %s, reverse: %s", + format, width, height, n_ranges, pages_per_sheet, copies, + collate ? "True" : "False", reverse ? "True" : "False"); + + job = g_object_new (EV_TYPE_JOB_PRINT, NULL); + + EV_JOB (job)->document = g_object_ref (document); + + job->format = format; + + job->temp_file = NULL; + + job->width = width; + job->height = height; + + job->ranges = ranges; + job->n_ranges = n_ranges; + + job->page_set = page_set; + + job->pages_per_sheet = CLAMP (pages_per_sheet, 1, 16); + + job->copies = copies; + job->collate = collate; + job->reverse = reverse; + + return EV_JOB (job); } + diff --git a/shell/ev-jobs.h b/shell/ev-jobs.h index c63a32c4..c0f95721 100644 --- a/shell/ev-jobs.h +++ b/shell/ev-jobs.h @@ -1,5 +1,6 @@ /* this file is part of evince, a gnome document viewer * + * Copyright (C) 2008 Carlos Garcia Campos * Copyright (C) 2005 Red Hat, Inc * * Evince is free software; you can redistribute it and/or modify it @@ -55,6 +56,7 @@ typedef struct _EvJobPrintClass EvJobPrintClass; #define EV_JOB(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB, EvJob)) #define EV_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB, EvJobClass)) #define EV_IS_JOB(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB)) +#define EV_JOB_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_JOB, EvJobClass)) #define EV_TYPE_JOB_LINKS (ev_job_links_get_type()) #define EV_JOB_LINKS(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_LINKS, EvJobLinks)) @@ -92,23 +94,38 @@ typedef struct _EvJobPrintClass EvJobPrintClass; #define EV_IS_JOB_PRINT(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_PRINT)) typedef enum { - EV_JOB_PRIORITY_LOW, - EV_JOB_PRIORITY_HIGH, -} EvJobPriority; + EV_JOB_RUN_THREAD, + EV_JOB_RUN_MAIN_LOOP +} EvJobRunMode; struct _EvJob { GObject parent; + EvDocument *document; - gboolean finished; - gboolean async; + + EvJobRunMode run_mode; + + guint cancelled : 1; + guint finished : 1; + guint failed : 1; + + GError *error; + GCancellable *cancellable; + + guint idle_finished_id; + guint idle_cancelled_id; }; struct _EvJobClass { GObjectClass parent_class; - void (* finished) (EvJob *job); + gboolean (*run) (EvJob *job); + + /* Signals */ + void (* cancelled) (EvJob *job); + void (* finished) (EvJob *job); }; struct _EvJobLinks @@ -194,6 +211,9 @@ struct _EvJobFonts struct _EvJobFontsClass { EvJobClass parent_class; + + /* Signals */ + void (* updated) (EvJobFonts *job); }; struct _EvJobLoad @@ -203,7 +223,6 @@ struct _EvJobLoad EvLinkDest *dest; EvWindowRunMode mode; gchar *search_string; - GError *error; gchar *uri; }; @@ -216,7 +235,6 @@ struct _EvJobSave { EvJob parent; - GError *error; gchar *uri; gchar *document_uri; }; @@ -230,7 +248,6 @@ struct _EvJobPrint { EvJob parent; - GError *error; const gchar *format; gchar *temp_file; EvPrintRange *ranges; @@ -251,12 +268,26 @@ struct _EvJobPrintClass /* Base job class */ GType ev_job_get_type (void) G_GNUC_CONST; -void ev_job_finished (EvJob *job); +gboolean ev_job_run (EvJob *job); +void ev_job_cancel (EvJob *job); +void ev_job_failed (EvJob *job, + GQuark domain, + gint code, + const gchar *format, + ...); +void ev_job_failed_from_error (EvJob *job, + GError *error); +void ev_job_succeeded (EvJob *job); +gboolean ev_job_is_cancelled (EvJob *job); +gboolean ev_job_is_finished (EvJob *job); +gboolean ev_job_is_failed (EvJob *job); +EvJobRunMode ev_job_get_run_mode (EvJob *job); +void ev_job_set_run_mode (EvJob *job, + EvJobRunMode run_mode); /* EvJobLinks */ GType ev_job_links_get_type (void) G_GNUC_CONST; EvJob *ev_job_links_new (EvDocument *document); -void ev_job_links_run (EvJobLinks *thumbnail); /* EvJobRender */ GType ev_job_render_get_type (void) G_GNUC_CONST; @@ -272,20 +303,15 @@ void ev_job_render_set_selection_info (EvJobRender *job, EvSelectionStyle selection_style, GdkColor *text, GdkColor *base); -void ev_job_render_run (EvJobRender *thumbnail); - /* EvJobThumbnail */ GType ev_job_thumbnail_get_type (void) G_GNUC_CONST; EvJob *ev_job_thumbnail_new (EvDocument *document, gint page, gint rotation, gdouble scale); -void ev_job_thumbnail_run (EvJobThumbnail *thumbnail); - /* EvJobFonts */ GType ev_job_fonts_get_type (void) G_GNUC_CONST; EvJob *ev_job_fonts_new (EvDocument *document); -void ev_job_fonts_run (EvJobFonts *fonts); /* EvJobLoad */ GType ev_job_load_get_type (void) G_GNUC_CONST; @@ -295,14 +321,12 @@ EvJob *ev_job_load_new (const gchar *uri, const gchar *search_string); void ev_job_load_set_uri (EvJobLoad *load, const gchar *uri); -void ev_job_load_run (EvJobLoad *load); /* EvJobSave */ GType ev_job_save_get_type (void) G_GNUC_CONST; EvJob *ev_job_save_new (EvDocument *document, const gchar *uri, const gchar *document_uri); -void ev_job_save_run (EvJobSave *save); /* EvJobPrint */ GType ev_job_print_get_type (void) G_GNUC_CONST; @@ -317,7 +341,6 @@ EvJob *ev_job_print_new (EvDocument *document, gint copies, gdouble collate, gdouble reverse); -void ev_job_print_run (EvJobPrint *print); G_END_DECLS diff --git a/shell/ev-page-cache.c b/shell/ev-page-cache.c index 8b8bedc9..bbddbbc0 100644 --- a/shell/ev-page-cache.c +++ b/shell/ev-page-cache.c @@ -1,6 +1,5 @@ #include #include "ev-page-cache.h" -#include "ev-job-queue.h" #include "ev-document-thumbnails.h" #include "ev-page.h" #include diff --git a/shell/ev-pixbuf-cache.c b/shell/ev-pixbuf-cache.c index 25b6f2cf..91c24780 100644 --- a/shell/ev-pixbuf-cache.c +++ b/shell/ev-pixbuf-cache.c @@ -1,6 +1,6 @@ #include #include "ev-pixbuf-cache.h" -#include "ev-job-queue.h" +#include "ev-job-scheduler.h" #include "ev-page-cache.h" #include "ev-document-images.h" #include "ev-document-forms.h" @@ -163,8 +163,8 @@ dispose_cache_job_info (CacheJobInfo *job_info, g_signal_handlers_disconnect_by_func (job_info->job, G_CALLBACK (job_finished_cb), data); - ev_job_queue_remove_job (job_info->job); - g_object_unref (G_OBJECT (job_info->job)); + ev_job_cancel (job_info->job); + g_object_unref (job_info->job); job_info->job = NULL; } if (job_info->surface) { @@ -313,7 +313,7 @@ check_job_size_and_unref (EvPixbufCache *pixbuf_cache, g_signal_handlers_disconnect_by_func (job_info->job, G_CALLBACK (job_finished_cb), pixbuf_cache); - ev_job_queue_remove_job (job_info->job); + ev_job_cancel (job_info->job); g_object_unref (job_info->job); job_info->job = NULL; } @@ -330,11 +330,11 @@ move_one_job (CacheJobInfo *job_info, CacheJobInfo *new_next_job, int start_page, int end_page, - EvJobPriority priority) + gint priority) { CacheJobInfo *target_page = NULL; int page_offset; - EvJobPriority new_priority; + gint new_priority; if (page < (start_page - pixbuf_cache->preload_cache_size) || page > (end_page + pixbuf_cache->preload_cache_size)) { @@ -361,7 +361,7 @@ move_one_job (CacheJobInfo *job_info, page_offset = page - start_page; g_assert (page_offset >= 0 && page_offset <= ((end_page - start_page) + 1)); - new_priority = EV_JOB_PRIORITY_HIGH; + new_priority = EV_JOB_PRIORITY_URGENT; target_page = new_job_list + page_offset; } @@ -374,7 +374,7 @@ move_one_job (CacheJobInfo *job_info, job_info->form_field_mapping = NULL; if (new_priority != priority && target_page->job) { - ev_job_queue_update_job (target_page->job, new_priority); + ev_job_scheduler_update_job (target_page->job, new_priority); } } @@ -421,7 +421,7 @@ ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, move_one_job (pixbuf_cache->job_list + i, pixbuf_cache, page, new_job_list, new_prev_job, new_next_job, - start_page, end_page, EV_JOB_PRIORITY_HIGH); + start_page, end_page, EV_JOB_PRIORITY_URGENT); page ++; } @@ -529,8 +529,8 @@ copy_job_to_job_info (EvJobRender *job_render, g_signal_handlers_disconnect_by_func (job_info->job, G_CALLBACK (job_finished_cb), pixbuf_cache); - ev_job_queue_remove_job (job_info->job); - g_object_unref (G_OBJECT (job_info->job)); + ev_job_cancel (job_info->job); + g_object_unref (job_info->job); job_info->job = NULL; } } @@ -647,13 +647,13 @@ add_job (EvPixbufCache *pixbuf_cache, text, base); } - ev_job_queue_add_job (job_info->job, priority); g_signal_connect (G_OBJECT (job_info->job), "page-ready", G_CALLBACK (job_page_ready_cb), pixbuf_cache); g_signal_connect (G_OBJECT (job_info->job), "finished", G_CALLBACK (job_finished_cb), pixbuf_cache); + ev_job_scheduler_push_job (job_info->job, priority); } static void @@ -701,7 +701,7 @@ ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache, add_job_if_needed (pixbuf_cache, job_info, page_cache, page, rotation, scale, - EV_JOB_PRIORITY_HIGH); + EV_JOB_PRIORITY_URGENT); } for (i = FIRST_VISABLE_PREV(pixbuf_cache); i < pixbuf_cache->preload_cache_size; i++) { @@ -1235,7 +1235,7 @@ ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache, add_job (pixbuf_cache, job_info, page_cache, region, width, height, page, rotation, scale, - EV_JOB_PRIORITY_HIGH); + EV_JOB_PRIORITY_URGENT); } diff --git a/shell/ev-pixbuf-cache.h b/shell/ev-pixbuf-cache.h index ed1c1ec9..0b65bf8c 100644 --- a/shell/ev-pixbuf-cache.h +++ b/shell/ev-pixbuf-cache.h @@ -27,7 +27,6 @@ #include #include "ev-document.h" #include "ev-selection.h" -#include "ev-job-queue.h" G_BEGIN_DECLS diff --git a/shell/ev-properties-fonts.c b/shell/ev-properties-fonts.c index 54ed063d..385cda10 100644 --- a/shell/ev-properties-fonts.c +++ b/shell/ev-properties-fonts.c @@ -25,7 +25,7 @@ #include "ev-properties-fonts.h" #include "ev-document-fonts.h" #include "ev-jobs.h" -#include "ev-job-queue.h" +#include "ev-job-scheduler.h" #include #include @@ -63,12 +63,10 @@ ev_properties_fonts_dispose (GObject *object) } if (properties->fonts_job) { - - g_signal_handlers_disconnect_by_func - (properties->fonts_job, - job_fonts_finished_cb, - properties); - ev_job_queue_remove_job (properties->fonts_job); + g_signal_handlers_disconnect_by_func (properties->fonts_job, + job_fonts_finished_cb, + properties); + ev_job_cancel (properties->fonts_job); g_object_unref (properties->fonts_job); properties->fonts_job = NULL; @@ -161,29 +159,23 @@ update_progress_label (GtkWidget *label, double progress) static void job_fonts_finished_cb (EvJob *job, EvPropertiesFonts *properties) -{ - EvDocumentFonts *document_fonts = EV_DOCUMENT_FONTS (job->document); - double progress; - - progress = ev_document_fonts_get_progress (document_fonts); - update_progress_label (properties->fonts_progress_label, progress); +{ + g_signal_handlers_disconnect_by_func (job, job_fonts_finished_cb, properties); + g_object_unref (properties->fonts_job); + properties->fonts_job = NULL; +} - if (EV_JOB_FONTS (job)->scan_completed) { - g_signal_handlers_disconnect_by_func - (job, job_fonts_finished_cb, properties); - g_object_unref (properties->fonts_job); - properties->fonts_job = NULL; - } else { - GtkTreeModel *model; +static void +job_fonts_updated_cb (EvJobFonts *job, gdouble progress, EvPropertiesFonts *properties) +{ + GtkTreeModel *model; + EvDocumentFonts *document_fonts = EV_DOCUMENT_FONTS (properties->document); - model = gtk_tree_view_get_model - (GTK_TREE_VIEW (properties->fonts_treeview)); - ev_document_doc_mutex_lock (); - ev_document_fonts_fill_model (document_fonts, model); - ev_document_doc_mutex_unlock (); + update_progress_label (properties->fonts_progress_label, progress); - ev_job_queue_add_job (job, EV_JOB_PRIORITY_LOW); - } + model = gtk_tree_view_get_model (GTK_TREE_VIEW (properties->fonts_treeview)); + /* Documen lock is already held by the jop */ + ev_document_fonts_fill_model (document_fonts, model); } void @@ -200,10 +192,13 @@ ev_properties_fonts_set_document (EvPropertiesFonts *properties, gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (list_store)); properties->fonts_job = ev_job_fonts_new (properties->document); + g_signal_connect (properties->fonts_job, "updated", + G_CALLBACK (job_fonts_updated_cb), + properties); g_signal_connect (properties->fonts_job, "finished", G_CALLBACK (job_fonts_finished_cb), properties); - ev_job_queue_add_job (properties->fonts_job, EV_JOB_PRIORITY_LOW); + ev_job_scheduler_push_job (properties->fonts_job, EV_JOB_PRIORITY_NONE); } GtkWidget * diff --git a/shell/ev-sidebar-links.c b/shell/ev-sidebar-links.c index f623f1e2..1389edd4 100644 --- a/shell/ev-sidebar-links.c +++ b/shell/ev-sidebar-links.c @@ -30,7 +30,7 @@ #include "ev-sidebar-page.h" #include "ev-sidebar-links.h" -#include "ev-job-queue.h" +#include "ev-job-scheduler.h" #include "ev-document-links.h" #include "ev-window.h" @@ -145,7 +145,7 @@ ev_sidebar_links_dispose (GObject *object) if (sidebar->priv->job) { g_signal_handlers_disconnect_by_func (sidebar->priv->job, job_finished_callback, sidebar); - ev_job_queue_remove_job (sidebar->priv->job); + ev_job_cancel (sidebar->priv->job); g_object_unref (sidebar->priv->job); sidebar->priv->job = NULL; } @@ -702,7 +702,7 @@ ev_sidebar_links_set_document (EvSidebarPage *sidebar_page, G_CALLBACK (job_finished_callback), sidebar_links); /* The priority doesn't matter for this job */ - ev_job_queue_add_job (priv->job, EV_JOB_PRIORITY_LOW); + ev_job_scheduler_push_job (priv->job, EV_JOB_PRIORITY_NONE); } static gboolean diff --git a/shell/ev-sidebar-thumbnails.c b/shell/ev-sidebar-thumbnails.c index 74b4ab73..7fe62f16 100644 --- a/shell/ev-sidebar-thumbnails.c +++ b/shell/ev-sidebar-thumbnails.c @@ -34,7 +34,7 @@ #include "ev-sidebar-thumbnails.h" #include "ev-document-thumbnails.h" #include "ev-document-misc.h" -#include "ev-job-queue.h" +#include "ev-job-scheduler.h" #include "ev-window.h" #include "ev-utils.h" @@ -207,7 +207,7 @@ clear_range (EvSidebarThumbnails *sidebar_thumbnails, if (job) { g_signal_handlers_disconnect_by_func (job, thumbnail_job_completed_callback, sidebar_thumbnails); - ev_job_queue_remove_job (EV_JOB (job)); + ev_job_cancel (EV_JOB (job)); g_object_unref (job); } @@ -263,7 +263,7 @@ add_range (EvSidebarThumbnails *sidebar_thumbnails, job = ev_job_thumbnail_new (priv->document, page, priv->rotation, get_scale_for_page (sidebar_thumbnails, page)); - ev_job_queue_add_job (EV_JOB (job), EV_JOB_PRIORITY_HIGH); + ev_job_scheduler_push_job (EV_JOB (job), EV_JOB_PRIORITY_HIGH); g_object_set_data_full (G_OBJECT (job), "tree_iter", gtk_tree_iter_copy (&iter), @@ -688,8 +688,8 @@ ev_sidebar_thumbnails_set_document (EvSidebarPage *sidebar_page, static gboolean ev_sidebar_thumbnails_clear_job (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, + GtkTreePath *path, + GtkTreeIter *iter, gpointer data) { EvJob *job; @@ -697,7 +697,7 @@ ev_sidebar_thumbnails_clear_job (GtkTreeModel *model, gtk_tree_model_get (model, iter, COLUMN_JOB, &job, -1); if (job != NULL) { - ev_job_queue_remove_job (job); + ev_job_cancel (job); g_signal_handlers_disconnect_by_func (job, thumbnail_job_completed_callback, data); g_object_unref (job); } diff --git a/shell/ev-view-private.h b/shell/ev-view-private.h index 3e72e82a..1618417d 100644 --- a/shell/ev-view-private.h +++ b/shell/ev-view-private.h @@ -24,6 +24,7 @@ #include "ev-view.h" #include "ev-pixbuf-cache.h" #include "ev-page-cache.h" +#include "ev-jobs.h" #include "ev-image.h" #include "ev-form-field.h" #include "ev-selection.h" diff --git a/shell/ev-view.c b/shell/ev-view.c index bc3cb980..49b604b0 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -39,7 +39,6 @@ #include "ev-document-transition.h" #include "ev-document-forms.h" #include "ev-document-misc.h" -#include "ev-job-queue.h" #include "ev-page-cache.h" #include "ev-pixbuf-cache.h" #include "ev-transition-animation.h" diff --git a/shell/ev-window.c b/shell/ev-window.c index 7d08ebf4..4c312ea4 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -49,7 +49,7 @@ #include "ev-document-images.h" #include "ev-document-security.h" #include "ev-document-factory.h" -#include "ev-job-queue.h" +#include "ev-job-scheduler.h" #include "ev-jobs.h" #include "ev-sidebar-page.h" #include "eggfindbar.h" @@ -221,16 +221,16 @@ static void ev_window_sidebar_visibility_changed_cb (EvSidebar *ev_si EvWindow *ev_window); static void ev_window_set_page_mode (EvWindow *window, EvWindowPageMode page_mode); -static void ev_window_load_job_cb (EvJobLoad *job, +static void ev_window_load_job_cb (EvJob *job, gpointer data); static void ev_window_reload_document (EvWindow *window); -static void ev_window_reload_job_cb (EvJobLoad *job, +static void ev_window_reload_job_cb (EvJob *job, EvWindow *window); static void ev_window_set_icon_from_thumbnail (EvJobThumbnail *job, EvWindow *ev_window); -static void ev_window_print_job_cb (EvJobPrint *job, +static void ev_window_print_job_cb (EvJob *job, EvWindow *window); -static void ev_window_save_job_cb (EvJobSave *save, +static void ev_window_save_job_cb (EvJob *save, EvWindow *window); static void ev_window_sizing_mode_changed_cb (EvView *view, GParamSpec *pspec, @@ -1080,8 +1080,9 @@ static void ev_window_clear_thumbnail_job (EvWindow *ev_window) { if (ev_window->priv->thumbnail_job != NULL) { - ev_job_queue_remove_job (ev_window->priv->thumbnail_job); - + if (!ev_job_is_finished (ev_window->priv->thumbnail_job)) + ev_job_cancel (ev_window->priv->thumbnail_job); + g_signal_handlers_disconnect_by_func (ev_window->priv->thumbnail_job, ev_window_set_icon_from_thumbnail, ev_window); @@ -1125,7 +1126,7 @@ ev_window_refresh_window_thumbnail (EvWindow *ev_window, int rotation) g_signal_connect (ev_window->priv->thumbnail_job, "finished", G_CALLBACK (ev_window_set_icon_from_thumbnail), ev_window); - ev_job_queue_add_job (EV_JOB (ev_window->priv->thumbnail_job), EV_JOB_PRIORITY_LOW); + ev_job_scheduler_push_job (ev_window->priv->thumbnail_job, EV_JOB_PRIORITY_NONE); } static gboolean @@ -1231,7 +1232,7 @@ password_dialog_response (GtkWidget *password_dialog, ev_password_dialog_save_password (EV_PASSWORD_DIALOG (password_dialog)); ev_window_title_set_type (ev_window->priv->title, EV_WINDOW_TITLE_DOCUMENT); - ev_job_queue_add_job (ev_window->priv->load_job, EV_JOB_PRIORITY_HIGH); + ev_job_scheduler_push_job (ev_window->priv->load_job, EV_JOB_PRIORITY_NONE); gtk_widget_destroy (password_dialog); @@ -1277,9 +1278,8 @@ static void ev_window_clear_load_job (EvWindow *ev_window) { if (ev_window->priv->load_job != NULL) { - - if (!ev_window->priv->load_job->finished) - ev_job_queue_remove_job (ev_window->priv->load_job); + if (!ev_job_is_finished (ev_window->priv->load_job)) + ev_job_cancel (ev_window->priv->load_job); g_signal_handlers_disconnect_by_func (ev_window->priv->load_job, ev_window_load_job_cb, ev_window); g_object_unref (ev_window->priv->load_job); @@ -1291,9 +1291,8 @@ static void ev_window_clear_reload_job (EvWindow *ev_window) { if (ev_window->priv->reload_job != NULL) { - - if (!ev_window->priv->reload_job->finished) - ev_job_queue_remove_job (ev_window->priv->reload_job); + if (!ev_job_is_finished (ev_window->priv->reload_job)) + ev_job_cancel (ev_window->priv->reload_job); g_signal_handlers_disconnect_by_func (ev_window->priv->reload_job, ev_window_reload_job_cb, ev_window); g_object_unref (ev_window->priv->reload_job); @@ -1349,21 +1348,22 @@ ev_window_clear_temp_file (EvWindow *ev_window) * function should _not_ necessarily expect those to exist after being * called. */ static void -ev_window_load_job_cb (EvJobLoad *job, +ev_window_load_job_cb (EvJob *job, gpointer data) { EvWindow *ev_window = EV_WINDOW (data); EvDocument *document = EV_JOB (job)->document; + EvJobLoad *job_load = EV_JOB_LOAD (job); - g_assert (job->uri); + g_assert (job_load->uri); ev_view_set_loading (EV_VIEW (ev_window->priv->view), FALSE); /* Success! */ - if (job->error == NULL) { + if (!ev_job_is_failed (job)) { ev_window_set_document (ev_window, document); - if (job->mode != EV_WINDOW_MODE_PREVIEW) { + if (job_load->mode != EV_WINDOW_MODE_PREVIEW) { setup_view_from_metadata (ev_window); } @@ -1371,17 +1371,17 @@ ev_window_load_job_cb (EvJobLoad *job, ev_window_add_recent (ev_window, ev_window->priv->uri); } - if (job->dest) { + if (job_load->dest) { EvLink *link; EvLinkAction *link_action; - link_action = ev_link_action_new_dest (g_object_ref (job->dest)); + link_action = ev_link_action_new_dest (g_object_ref (job_load->dest)); link = ev_link_new (NULL, link_action); ev_view_handle_link (EV_VIEW (ev_window->priv->view), link); g_object_unref (link); } - switch (job->mode) { + switch (job_load->mode) { case EV_WINDOW_MODE_FULLSCREEN: ev_window_run_fullscreen (ev_window); break; @@ -1395,14 +1395,23 @@ ev_window_load_job_cb (EvJobLoad *job, break; } - if (job->search_string && EV_IS_DOCUMENT_FIND (document)) { + /* Restart the search after reloading */ + if (ev_window->priv->in_reload) { + GtkWidget *widget; + + widget = gtk_window_get_focus (GTK_WINDOW (ev_window)); + if (widget && gtk_widget_get_ancestor (widget, EGG_TYPE_FIND_BAR)) { + find_bar_search_changed_cb (EGG_FIND_BAR (ev_window->priv->find_bar), + NULL, ev_window); + } + } else if (job_load->search_string && EV_IS_DOCUMENT_FIND (document)) { ev_window_cmd_edit_find (NULL, ev_window); egg_find_bar_set_search_string (EGG_FIND_BAR (ev_window->priv->find_bar), - job->search_string); + job_load->search_string); } /* Create a monitor for the document */ - ev_window->priv->monitor = ev_file_monitor_new (job->uri); + ev_window->priv->monitor = ev_file_monitor_new (job_load->uri); g_signal_connect_swapped (G_OBJECT (ev_window->priv->monitor), "changed", G_CALLBACK (ev_window_document_changed), ev_window); @@ -1418,7 +1427,7 @@ ev_window_load_job_cb (EvJobLoad *job, setup_view_from_metadata (ev_window); - file = g_file_new_for_uri (job->uri); + file = g_file_new_for_uri (job_load->uri); base_name = g_file_get_basename (file); ev_password_view_set_file_name (EV_PASSWORD_VIEW (ev_window->priv->password_view), base_name); @@ -1436,18 +1445,18 @@ ev_window_load_job_cb (EvJobLoad *job, } static void -ev_window_reload_job_cb (EvJobLoad *job, - EvWindow *ev_window) +ev_window_reload_job_cb (EvJob *job, + EvWindow *ev_window) { GtkWidget *widget; - - if (job->error) { + + if (ev_job_is_failed (job)) { ev_window_clear_reload_job (ev_window); ev_window->priv->in_reload = FALSE; return; } - ev_window_set_document (ev_window, EV_JOB (job)->document); + ev_window_set_document (ev_window, job->document); /* Restart the search after reloading */ widget = gtk_window_get_focus (GTK_WINDOW (ev_window)); @@ -1539,7 +1548,7 @@ window_open_file_copy_ready_cb (GFile *source, g_file_copy_finish (source, async_result, &error); if (!error) { - ev_job_queue_add_job (ev_window->priv->load_job, EV_JOB_PRIORITY_HIGH); + ev_job_scheduler_push_job (ev_window->priv->load_job, EV_JOB_PRIORITY_NONE); g_object_unref (source); return; @@ -1649,7 +1658,7 @@ ev_window_open_uri (EvWindow *ev_window, ev_window_load_file_remote (ev_window, source_file); } else { g_object_unref (source_file); - ev_job_queue_add_job (ev_window->priv->load_job, EV_JOB_PRIORITY_HIGH); + ev_job_scheduler_push_job (ev_window->priv->load_job, EV_JOB_PRIORITY_NONE); } } @@ -1666,7 +1675,7 @@ ev_window_reload_document (EvWindow *ev_window) g_signal_connect (ev_window->priv->reload_job, "finished", G_CALLBACK (ev_window_reload_job_cb), ev_window); - ev_job_queue_add_job (ev_window->priv->reload_job, EV_JOB_PRIORITY_LOW); + ev_job_scheduler_push_job (ev_window->priv->reload_job, EV_JOB_PRIORITY_NONE); } static void @@ -2067,8 +2076,8 @@ static void ev_window_clear_save_job (EvWindow *ev_window) { if (ev_window->priv->save_job != NULL) { - if (!ev_window->priv->save_job->finished) - ev_job_queue_remove_job (ev_window->priv->save_job); + if (!ev_job_is_finished (ev_window->priv->save_job)) + ev_job_cancel (ev_window->priv->save_job); g_signal_handlers_disconnect_by_func (ev_window->priv->save_job, ev_window_save_job_cb, @@ -2079,13 +2088,14 @@ ev_window_clear_save_job (EvWindow *ev_window) } static void -ev_window_save_job_cb (EvJobSave *job, +ev_window_save_job_cb (EvJob *job, EvWindow *window) { - if (job->error) { + if (ev_job_is_failed (job)) { gchar *msg; - msg = g_strdup_printf (_("The file could not be saved as “%s”."), job->uri); + msg = g_strdup_printf (_("The file could not be saved as “%s”."), + EV_JOB_SAVE (job)->uri); ev_window_error_message (GTK_WINDOW (window), msg, job->error); g_free (msg); } @@ -2114,10 +2124,9 @@ file_save_dialog_response_cb (GtkWidget *fc, G_CALLBACK (ev_window_save_job_cb), ev_window); /* The priority doesn't matter for this job */ - ev_job_queue_add_job (ev_window->priv->save_job, EV_JOB_PRIORITY_LOW); + ev_job_scheduler_push_job (ev_window->priv->save_job, EV_JOB_PRIORITY_NONE); g_free (uri); - gtk_widget_destroy (fc); } @@ -2187,8 +2196,8 @@ static void ev_window_clear_print_job (EvWindow *window) { if (window->priv->print_job) { - if (!window->priv->print_job->finished) - ev_job_queue_remove_job (window->priv->print_job); + if (!ev_job_is_finished (window->priv->print_job)) + ev_job_cancel (window->priv->print_job); g_signal_handlers_disconnect_by_func (window->priv->print_job, ev_window_print_job_cb, @@ -2349,18 +2358,18 @@ ev_window_print_send (EvWindow *window, } static void -ev_window_print_job_cb (EvJobPrint *job, - EvWindow *window) +ev_window_print_job_cb (EvJob *job, + EvWindow *window) { - if (job->error) { + if (ev_job_is_failed (job)) { g_warning ("%s", job->error->message); ev_window_clear_print_job (window); return; } - g_assert (job->temp_file != NULL); + g_assert (EV_JOB_PRINT (job)->temp_file != NULL); - ev_window_print_send (window, job->temp_file); + ev_window_print_send (window, EV_JOB_PRINT (job)->temp_file); } static gboolean @@ -2494,7 +2503,7 @@ ev_window_print_dialog_response_cb (GtkDialog *dialog, G_CALLBACK (ev_window_print_job_cb), window); /* The priority doesn't matter for this job */ - ev_job_queue_add_job (window->priv->print_job, EV_JOB_PRIORITY_LOW); + ev_job_scheduler_push_job (window->priv->print_job, EV_JOB_PRIORITY_NONE); gtk_widget_destroy (GTK_WIDGET (dialog)); window->priv->print_dialog = NULL; diff --git a/shell/main.c b/shell/main.c index f230ea86..eb5c08ab 100644 --- a/shell/main.c +++ b/shell/main.c @@ -41,7 +41,6 @@ #endif #include "ev-stock-icons.h" -#include "ev-job-queue.h" #include "ev-file-helpers.h" #include "ev-backends-manager.h" @@ -391,7 +390,6 @@ main (int argc, char *argv[]) ev_metadata_manager_init (); } - ev_job_queue_init (); g_set_application_name (_("Evince Document Viewer")); ev_file_helpers_init (); -- 2.43.5