diff options
author | Nickolay 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) |
commit | bca369672136e5ff831ece9832afd42085808fba (patch) | |
tree | f40b0b02036bb97a0d4586077298be7a02e2de03 /shell/ev-job-queue.c | |
parent | 11bd1d65957b444c7491e4fb252f3f50ce8ad3d2 (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.c | 408 |
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; +} + + |