Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/shell/ev-job-queue.c
diff options
context:
space:
mode:
authorNickolay V. Shmyrev <nshmyrev@src.gnome.org>2005-06-07 23:28:54 (GMT)
committer Nickolay V. Shmyrev <nshmyrev@src.gnome.org>2005-06-07 23:28:54 (GMT)
commitbca369672136e5ff831ece9832afd42085808fba (patch)
treef40b0b02036bb97a0d4586077298be7a02e2de03 /shell/ev-job-queue.c
parent11bd1d65957b444c7491e4fb252f3f50ce8ad3d2 (diff)
PageCache and EvJobs are moved from backend to shell. Two new jobs to
load document in background and a statusbar to display this process. FileChooser now can select multiple uris.
Diffstat (limited to 'shell/ev-job-queue.c')
-rw-r--r--shell/ev-job-queue.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/shell/ev-job-queue.c b/shell/ev-job-queue.c
new file mode 100644
index 0000000..877aae8
--- /dev/null
+++ b/shell/ev-job-queue.c
@@ -0,0 +1,408 @@
+#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 *xfer_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);
+}
+
+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);
+}
+
+static gboolean
+notify_finished (GObject *job)
+{
+ ev_job_finished (EV_JOB (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))
+ 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_XFER (job))
+ ev_job_xfer_run (EV_JOB_XFER (job));
+ else if (EV_IS_JOB_RENDER (job))
+ ev_job_render_run (EV_JOB_RENDER (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);
+ }
+}
+
+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 (xfer_queue);
+ if (job)
+ return job;
+
+ job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
+ if (job)
+ return job;
+
+ return NULL;
+}
+
+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 (xfer_queue)
+ && g_queue_is_empty (thumbnail_queue_high)
+ && g_queue_is_empty (thumbnail_queue_low);
+}
+
+/* the thread mainloop function */
+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;
+
+}
+
+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)
+{
+ 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 ();
+ xfer_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 ();
+
+ 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_XFER (job)) {
+ /* the priority doesn't effect xfer */
+ return xfer_queue;
+ } else if (EV_IS_JOB_LINKS (job)) {
+ /* the priority doesn't effect links */
+ return links_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_XFER (job)) {
+ retval = remove_job_from_queue_locked (xfer_queue, job);
+ } else {
+ g_assert_not_reached ();
+ }
+
+ g_mutex_unlock (ev_queue_mutex);
+ }
+
+ return retval;
+}
+
+