]> www.fi.muni.cz Git - evince.git/commitdiff
Add an async renderer interface (method + callback) which is useful for
authorMarco Pesenti Gritti <mpg@redhat.com>
Tue, 7 Jun 2005 09:20:35 +0000 (09:20 +0000)
committerMarco Pesenti Gritti <marco@src.gnome.org>
Tue, 7 Jun 2005 09:20:35 +0000 (09:20 +0000)
2005-06-07  Marco Pesenti Gritti <mpg@redhat.com>

        * backend/Makefile.am:
        * backend/ev-async-renderer.c: (ev_async_renderer_get_type),
        (ev_async_renderer_class_init), (ev_async_renderer_render_pixbuf):
        * backend/ev-async-renderer.h:

        Add an async renderer interface (method + callback) which
        is useful for backends like ps.

        * backend/ev-job-queue.c: (remove_job_from_async_queue),
        (add_job_to_async_queue), (job_finished_cb), (handle_job),
        (ev_job_queue_run_next), (ev_job_queue_init), (find_queue),
        (ev_job_queue_add_job), (move_job_async), (move_job),
        (ev_job_queue_update_job), (ev_job_queue_remove_job):

        Add queues for async renderer, these are executed on the
        main thread.

        * backend/ev-jobs.c: (ev_job_render_new), (render_finished_cb),
        (ev_job_render_run):
        * backend/ev-jobs.h:

        If the backend support async renderer interface use it.

        * ps/ps-document.c: (ps_document_init), (push_pixbuf),
        (setup_pixmap), (ps_document_get_type),
        (ps_async_renderer_render_pixbuf),
        (ps_document_document_iface_init), (ps_async_renderer_iface_init):

        Implement async renderer interface.

ChangeLog
backend/Makefile.am
backend/ev-async-renderer.c [new file with mode: 0644]
backend/ev-async-renderer.h [new file with mode: 0644]
backend/ev-job-queue.c
backend/ev-jobs.c
backend/ev-jobs.h
ps/ps-document.c

index 5612ca13f4cb0d9287d0bc9c17c73cf5b6f7a8c0..ca81c6627f6bffd6d44e7be4a7ed108cf6ca4c0f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2005-06-07  Marco Pesenti Gritti <mpg@redhat.com>
+
+       * backend/Makefile.am:
+       * backend/ev-async-renderer.c: (ev_async_renderer_get_type),
+       (ev_async_renderer_class_init), (ev_async_renderer_render_pixbuf):
+       * backend/ev-async-renderer.h:
+
+       Add an async renderer interface (method + callback) which
+       is useful for backends like ps.
+
+       * backend/ev-job-queue.c: (remove_job_from_async_queue),
+       (add_job_to_async_queue), (job_finished_cb), (handle_job),
+       (ev_job_queue_run_next), (ev_job_queue_init), (find_queue),
+       (ev_job_queue_add_job), (move_job_async), (move_job),
+       (ev_job_queue_update_job), (ev_job_queue_remove_job):
+
+       Add queues for async renderer, these are executed on the
+       main thread.
+
+       * backend/ev-jobs.c: (ev_job_render_new), (render_finished_cb),
+       (ev_job_render_run):
+       * backend/ev-jobs.h:
+
+       If the backend support async renderer interface use it.
+
+       * ps/ps-document.c: (ps_document_init), (push_pixbuf),
+       (setup_pixmap), (ps_document_get_type),
+       (ps_async_renderer_render_pixbuf),
+       (ps_document_document_iface_init), (ps_async_renderer_iface_init):
+
+       Implement async renderer interface.
+
 2005-06-07  Nickolay V. Shmyrev  <<nshmyrev@yandex.ru>>
 
        * shell/ev-sidebar-links.c: (ev_sidebar_links_dispose):
index 744c932d926ed0201618086a1c67c6ca4e53ddec..322cc7d59366d104ef3c42500984e4df6ddf1ded 100644 (file)
@@ -10,6 +10,8 @@ INCLUDES=                                     \
 noinst_LTLIBRARIES = libevbackend.la
 
 libevbackend_la_SOURCES=                       \
+       ev-async-renderer.c                     \
+       ev-async-renderer.h                     \
        ev-backend-marshal.c                    \
        ev-link.c                               \
        ev-link.h                               \
diff --git a/backend/ev-async-renderer.c b/backend/ev-async-renderer.c
new file mode 100644 (file)
index 0000000..45ca7e4
--- /dev/null
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/*
+ *  Copyright (C) 2004 Marco Pesenti Gritti
+ *
+ *  This program 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, or (at your option)
+ *  any later version.
+ *
+ *  This program 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 "config.h"
+
+#include "ev-async-renderer.h"
+
+static void ev_async_renderer_class_init (gpointer g_class);
+
+enum
+{
+       RENDER_FINISHED,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+GType
+ev_async_renderer_get_type (void)
+{
+       static GType type = 0;
+
+       if (G_UNLIKELY (type == 0))
+       {
+               static const GTypeInfo our_info =
+               {
+                       sizeof (EvAsyncRendererIface),
+                       NULL,
+                       NULL,
+                       (GClassInitFunc)ev_async_renderer_class_init
+               };
+
+               type = g_type_register_static (G_TYPE_INTERFACE,
+                                              "EvAsyncRenderer",
+                                              &our_info, (GTypeFlags)0);
+       }
+
+       return type;
+}
+
+static void
+ev_async_renderer_class_init (gpointer g_class)
+{
+       signals[RENDER_FINISHED] =
+               g_signal_new ("render_finished",
+                             EV_TYPE_ASYNC_RENDERER,
+                             G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (EvAsyncRendererIface, render_finished),
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__OBJECT,
+                             G_TYPE_NONE,
+                             1,
+                             GDK_TYPE_PIXBUF);
+}
+
+void
+ev_async_renderer_render_pixbuf (EvAsyncRenderer *async_renderer,
+                                int              page,
+                                double           scale)
+{
+       EvAsyncRendererIface *iface = EV_ASYNC_RENDERER_GET_IFACE (async_renderer);
+
+       iface->render_pixbuf (async_renderer, page, scale);
+}
diff --git a/backend/ev-async-renderer.h b/backend/ev-async-renderer.h
new file mode 100644 (file)
index 0000000..044ee62
--- /dev/null
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/*
+ *  Copyright (C) 2000-2003 Marco Pesenti Gritti
+ *
+ *  This program 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, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef EV_ASYNC_RENDERER_H
+#define EV_ASYNC_RENDERER_H
+
+#include <glib-object.h>
+#include <glib.h>
+#include <gdk/gdkpixbuf.h>
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_ASYNC_RENDERER           (ev_async_renderer_get_type ())
+#define EV_ASYNC_RENDERER(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_ASYNC_RENDERER, EvAsyncRenderer))
+#define EV_ASYNC_RENDERER_IFACE(k)       (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_ASYNC_RENDERER, EvAsyncRendererIface))
+#define EV_IS_ASYNC_RENDERER(o)                  (G_TYPE_CHECK_INSTANCE_TYPE ((o), EV_TYPE_ASYNC_RENDERER))
+#define EV_IS_ASYNC_RENDERER_IFACE(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_ASYNC_RENDERER))
+#define EV_ASYNC_RENDERER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EV_TYPE_ASYNC_RENDERER, EvAsyncRendererIface))
+
+typedef struct _EvAsyncRenderer          EvAsyncRenderer;
+typedef struct _EvAsyncRendererIface   EvAsyncRendererIface;
+
+struct _EvAsyncRendererIface
+{
+       GTypeInterface base_iface;
+
+       void        (* render_finished) (EvAsyncRenderer *renderer,
+                                        GdkPixbuf       *pixbuf);
+
+       void        (* render_pixbuf)   (EvAsyncRenderer *renderer,
+                                        int              page,
+                                        double           scale);
+};
+
+GType          ev_async_renderer_get_type       (void);
+void           ev_async_renderer_render_pixbuf  (EvAsyncRenderer *renderer,
+                                                 int              page,
+                                                 double           scale);
+
+G_END_DECLS
+
+#endif
index 72470eef40c703bb4e79be7b83c3aaad8ad8b9ae..1b3e496219ec8fe4da5bf35b6c24c83a319f8e0e 100644 (file)
@@ -13,6 +13,14 @@ static GQueue *render_queue_low = NULL;
 static GQueue *thumbnail_queue_high = NULL;
 static GQueue *thumbnail_queue_low = 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)
 {
@@ -28,6 +36,19 @@ remove_job_from_queue_locked (GQueue *queue, EvJob *job)
        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);
+}
+
 static void
 add_job_to_queue_locked (GQueue *queue,
                         EvJob  *job)
@@ -37,7 +58,6 @@ add_job_to_queue_locked (GQueue *queue,
        g_cond_broadcast (render_cond);
 }
 
-
 static gboolean
 notify_finished (GObject *job)
 {
@@ -46,12 +66,29 @@ notify_finished (GObject *job)
        return FALSE;
 }
 
+static void
+job_finished_cb (EvJob *job)
+{
+       g_object_unref (job);
+       async_rendering = FALSE;
+       ev_job_queue_run_next ();
+}
 
 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))
@@ -59,11 +96,13 @@ handle_job (EvJob *job)
        else if (EV_IS_JOB_RENDER (job))
                ev_job_render_run (EV_JOB_RENDER (job));
 
-       /* 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);
+       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);
+       }
 }
 
 static EvJob *
@@ -129,6 +168,24 @@ ev_render_thread (gpointer data)
 
 }
 
+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 */
 void
 ev_job_queue_init (void)
@@ -141,6 +198,8 @@ ev_job_queue_init (void)
        links_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 ();
 
@@ -152,19 +211,28 @@ static GQueue *
 find_queue (EvJob         *job,
            EvJobPriority  priority)
 {
-       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_LINKS (job)) {
-               /* the priority doesn't effect links */
-               return links_queue;
+       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_LINKS (job)) {
+                       /* the priority doesn't effect links */
+                       return links_queue;
+               }
        }
 
        g_assert_not_reached ();
@@ -181,9 +249,52 @@ ev_job_queue_add_job (EvJob         *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);
-       add_job_to_queue_locked (queue, job);
+       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
@@ -194,38 +305,39 @@ ev_job_queue_update_job (EvJob         *job,
        
        g_return_val_if_fail (EV_IS_JOB (job), FALSE);
 
-       g_mutex_lock (ev_queue_mutex);
-       g_object_ref (job);
-       
-       if (EV_IS_JOB_THUMBNAIL (job)) {
-               if (new_priority == EV_JOB_PRIORITY_LOW) {
-                       if (remove_job_from_queue_locked (thumbnail_queue_high, job)) {
-                               add_job_to_queue_locked (thumbnail_queue_low, job);
-                               retval = TRUE;
-                       }
-               } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
-                       if (remove_job_from_queue_locked (thumbnail_queue_low, job)) {
-                               add_job_to_queue_locked (thumbnail_queue_high, job);
-                               retval = TRUE;
+       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_RENDER (job)) {
-               if (new_priority == EV_JOB_PRIORITY_LOW) {
-                       if (remove_job_from_queue_locked (render_queue_high, job)) {
-                               add_job_to_queue_locked (render_queue_low, job);
-                               retval = TRUE;
+       } 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 (new_priority == EV_JOB_PRIORITY_HIGH) {
-                       if (remove_job_from_queue_locked (render_queue_low, job)) {
-                               add_job_to_queue_locked (render_queue_high, job);
-                               retval = TRUE;
+               } 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 ();
                }
-       } else {
-               /* We don't have a priority queue for any of the other jobs */
-       }
-       g_object_unref (job);
-       g_mutex_unlock (ev_queue_mutex);
+       }       
 
        return retval;
 }
@@ -237,22 +349,31 @@ ev_job_queue_remove_job (EvJob *job)
 
        g_return_val_if_fail (EV_IS_JOB (job), FALSE);
 
-       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);
+       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_assert_not_reached ();
+               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 {
+                       g_assert_not_reached ();
+               }
+
+               g_mutex_unlock (ev_queue_mutex);
        }
        
-       g_mutex_unlock (ev_queue_mutex);
-
        return retval;
 }
 
index c4556c95a8f506409e107e1b83860982e2c35953..73b0614a998b13c9e11c4c1e29245f13b1e1e6f8 100644 (file)
@@ -2,6 +2,7 @@
 #include "ev-job-queue.h"
 #include "ev-document-thumbnails.h"
 #include "ev-document-links.h"
+#include "ev-async-renderer.h"
 
 static void ev_job_init                 (EvJob               *job);
 static void ev_job_class_init           (EvJobClass          *class);
@@ -196,9 +197,24 @@ ev_job_render_new (EvDocument *document,
        job->target_height = height;
        job->include_links = include_links;
 
+       if (EV_IS_ASYNC_RENDERER (document)) {  
+               EV_JOB (job)->async = TRUE;
+       }
+
        return EV_JOB (job);
 }
 
+static void
+render_finished_cb (EvDocument *document, GdkPixbuf *pixbuf, EvJobRender *job)
+{
+       g_signal_handlers_disconnect_by_func (EV_JOB (job)->document,
+                                             render_finished_cb, job);
+
+       EV_JOB (job)->finished = TRUE;
+       job->pixbuf = g_object_ref (pixbuf);
+       ev_job_finished (EV_JOB (job));
+}
+
 void
 ev_job_render_run (EvJobRender *job)
 {
@@ -206,12 +222,21 @@ ev_job_render_run (EvJobRender *job)
 
        ev_document_doc_mutex_lock ();
 
-       job->pixbuf = ev_document_render_pixbuf (EV_JOB (job)->document,
-                                                job->page,
-                                                job->scale);
-       if (job->include_links)
-               job->link_mapping = ev_document_get_links (EV_JOB (job)->document, job->page);
-       EV_JOB (job)->finished = TRUE;
+       if (EV_JOB (job)->async) {
+               EvAsyncRenderer *renderer = EV_ASYNC_RENDERER (EV_JOB (job)->document);
+               ev_async_renderer_render_pixbuf (renderer, job->page, job->scale);
+               g_signal_connect (EV_JOB (job)->document, "render_finished",
+                                 G_CALLBACK (render_finished_cb), job);
+       } else {
+               job->pixbuf = ev_document_render_pixbuf (EV_JOB (job)->document,
+                                                        job->page,
+                                                        job->scale);
+               if (job->include_links)
+                       job->link_mapping = ev_document_get_links (EV_JOB (job)->document, job->page);
+
+               EV_JOB (job)->finished = TRUE;
+       }
+
        ev_document_doc_mutex_unlock ();
 }
 
index 1b64e01da3c9d7ac8ee5618220056395ca99c7d4..c89aa1e5546813306086f97f39455756ec12c84d 100644 (file)
@@ -67,6 +67,7 @@ struct _EvJob
        GObject parent;
        EvDocument *document;
        gboolean finished;
+       gboolean async;
 };
 
 struct _EvJobClass
index 3de53e3aedce51c5f13b7363a21b7664f384cbab..8d64daf924a39ede9fc37bcacdc5d557f604d75d 100644 (file)
@@ -47,6 +47,7 @@
 #include "ev-debug.h"
 #include "gsdefaults.h"
 #include "ev-ps-exporter.h"
+#include "ev-async-renderer.h"
 
 #ifdef HAVE_LOCALE_H
 #   include <locale.h>
                                         PS_DOCUMENT(gs)->gs_filename_unc : \
                                         PS_DOCUMENT(gs)->gs_filename)
 
-GCond* pixbuf_cond = NULL;
-GMutex* pixbuf_mutex = NULL;
-GdkPixbuf *current_pixbuf = NULL;
-
 /* structure to describe section of file to send to ghostscript */
 struct record_list {
   FILE *fp;
@@ -97,6 +94,7 @@ static void stop_interpreter(PSDocument * gs);
 static gint start_interpreter(PSDocument * gs);
 static void ps_document_document_iface_init (EvDocumentIface *iface);
 static void ps_document_ps_exporter_iface_init (EvPSExporterIface *iface);
+static void ps_async_renderer_iface_init (EvAsyncRendererIface *iface);
 static gboolean ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data);
 
 static GObjectClass *parent_class = NULL;
@@ -140,9 +138,6 @@ ps_document_init (PSDocument *gs)
 
        gs->ps_export_pagelist = NULL;
        gs->ps_export_filename = NULL;
-
-       pixbuf_cond = g_cond_new ();
-       pixbuf_mutex = g_mutex_new ();
 }
 
 static void
@@ -216,11 +211,8 @@ push_pixbuf (PSDocument *gs)
        pixbuf =  gdk_pixbuf_get_from_drawable (NULL, gs->bpixmap, cmap,
                                                0, 0, 0, 0,
                                                width, height);
-       g_mutex_lock (pixbuf_mutex);
-       current_pixbuf = pixbuf;
-       g_cond_signal (pixbuf_cond);
-       g_mutex_unlock (pixbuf_mutex);
-
+       g_signal_emit_by_name (gs, "render_finished", pixbuf);
+       g_object_unref (pixbuf);
 }
 
 static void
@@ -314,8 +306,8 @@ setup_pixmap (PSDocument *gs, int page, double scale)
        int pixmap_width, pixmap_height;
 
        ev_document_get_page_size (EV_DOCUMENT (gs), page, &width, &height);
-       pixmap_width = floor (width * scale);
-       pixmap_height = floor (height * scale);
+       pixmap_width = width * scale + 0.5;
+       pixmap_height = height * scale + 0.5;
 
        if(gs->bpixmap) {
                int w, h;
@@ -984,6 +976,13 @@ ps_document_get_type(void)
         NULL
     };
 
+    static const GInterfaceInfo async_renderer_info =
+    {
+        (GInterfaceInitFunc) ps_async_renderer_iface_init,
+        NULL,
+        NULL
+    };
+
     gs_type = g_type_register_static(G_TYPE_OBJECT,
                                      "PSDocument", &gs_info, 0);
 
@@ -993,6 +992,9 @@ ps_document_get_type(void)
     g_type_add_interface_static (gs_type,
                                  EV_TYPE_PS_EXPORTER,
                                  &ps_exporter_info);
+    g_type_add_interface_static (gs_type,
+                                 EV_TYPE_ASYNC_RENDERER,
+                                 &async_renderer_info);
   }
   return gs_type;
 
@@ -1316,27 +1318,15 @@ render_pixbuf_idle (PSRenderJob *job)
        return FALSE;
 }
 
-static GdkPixbuf *
-ps_document_render_pixbuf (EvDocument *document, int page, double scale)
+static void
+ps_async_renderer_render_pixbuf (EvAsyncRenderer *renderer, int page, double scale)
 {
-       GdkPixbuf *pixbuf;
        PSRenderJob job;
 
        job.page = page;
        job.scale = scale;
-       job.document = PS_DOCUMENT (document);
-       g_idle_add ((GSourceFunc)render_pixbuf_idle, &job);
-
-       g_mutex_lock (pixbuf_mutex);
-       while (!current_pixbuf)
-               g_cond_wait (pixbuf_cond, pixbuf_mutex);
-       pixbuf = current_pixbuf;
-       current_pixbuf = NULL;
-       g_mutex_unlock (pixbuf_mutex);
-
-       LOG ("Pixbuf rendered %p\n", pixbuf);
-
-       return pixbuf;
+       job.document = PS_DOCUMENT (renderer);
+       render_pixbuf_idle (&job);
 }
 
 static EvDocumentInfo *
@@ -1362,10 +1352,15 @@ ps_document_document_iface_init (EvDocumentIface *iface)
        iface->can_get_text = ps_document_can_get_text;
        iface->get_n_pages = ps_document_get_n_pages;
        iface->get_page_size = ps_document_get_page_size;
-       iface->render_pixbuf = ps_document_render_pixbuf;
        iface->get_info = ps_document_get_info;
 }
 
+static void
+ps_async_renderer_iface_init (EvAsyncRendererIface *iface)
+{
+       iface->render_pixbuf = ps_async_renderer_render_pixbuf;
+}
+
 static void
 ps_document_ps_export_begin (EvPSExporter *exporter, const char *filename,
                             int first_page, int last_page)