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 | |
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')
-rw-r--r-- | shell/Makefile.am | 10 | ||||
-rw-r--r-- | shell/ev-application.c | 21 | ||||
-rw-r--r-- | shell/ev-application.h | 2 | ||||
-rw-r--r-- | shell/ev-job-queue.c | 408 | ||||
-rw-r--r-- | shell/ev-job-queue.h | 40 | ||||
-rw-r--r-- | shell/ev-job-xfer.c | 130 | ||||
-rw-r--r-- | shell/ev-job-xfer.h | 56 | ||||
-rw-r--r-- | shell/ev-jobs.c | 343 | ||||
-rw-r--r-- | shell/ev-jobs.h | 178 | ||||
-rw-r--r-- | shell/ev-page-action.c | 3 | ||||
-rw-r--r-- | shell/ev-page-cache.c | 485 | ||||
-rw-r--r-- | shell/ev-page-cache.h | 74 | ||||
-rw-r--r-- | shell/ev-pixbuf-cache.c | 9 | ||||
-rw-r--r-- | shell/ev-print-job.c | 5 | ||||
-rw-r--r-- | shell/ev-sidebar-links.c | 2 | ||||
-rw-r--r-- | shell/ev-sidebar-thumbnails.c | 4 | ||||
-rw-r--r-- | shell/ev-statusbar.c | 201 | ||||
-rw-r--r-- | shell/ev-statusbar.h | 76 | ||||
-rw-r--r-- | shell/ev-view.c | 6 | ||||
-rw-r--r-- | shell/ev-window.c | 321 | ||||
-rw-r--r-- | shell/ev-window.h | 6 | ||||
-rw-r--r-- | shell/main.c | 2 |
22 files changed, 2226 insertions, 156 deletions
diff --git a/shell/Makefile.am b/shell/Makefile.am index 7668e97..c916987 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -58,10 +58,18 @@ evince_SOURCES= \ eggfindbar.h \ ev-application.c \ ev-application.h \ + ev-job-queue.h \ + ev-job-queue.c \ + ev-jobs.h \ + ev-jobs.c \ + ev-job-xfer.c \ + ev-job-xfer.h \ ev-marshal.c \ ev-marshal.h \ ev-page-action.c \ ev-page-action.h \ + ev-page-cache.h \ + ev-page-cache.c \ ev-password.h \ ev-password.c \ ev-password-view.h \ @@ -86,6 +94,8 @@ evince_SOURCES= \ ev-sidebar-page.h \ ev-sidebar-thumbnails.c \ ev-sidebar-thumbnails.h \ + ev-statusbar.c \ + ev-statusbar.h \ ev-stock-icons.c \ ev-stock-icons.h \ main.c \ diff --git a/shell/ev-application.c b/shell/ev-application.c index 43c4068..d10914b 100644 --- a/shell/ev-application.c +++ b/shell/ev-application.c @@ -122,6 +122,7 @@ ev_application_open (EvApplication *application, GError *err) GtkFileFilter *ps_filter; GtkFileFilter *pixbuf_filter; GtkFileFilter *all_filter; + static gchar *folder = NULL; #ifdef ENABLE_DJVU GtkFileFilter *djvu_filter; #endif @@ -139,6 +140,11 @@ ev_application_open (EvApplication *application, GError *err) GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL); + if (folder) { + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), + folder); + } + documents_filter = gtk_file_filter_new (); gtk_file_filter_set_name (documents_filter, _("All Documents")); @@ -193,14 +199,17 @@ ev_application_open (EvApplication *application, GError *err) gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), documents_filter); + gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), TRUE); + if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) { - char *uri; + GSList *uris; - uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (chooser)); - ev_window_open (ev_window, uri); - gtk_widget_show (GTK_WIDGET (ev_window)); - g_free (uri); - + uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser)); + folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (chooser)); + + ev_window_open_uri_list (ev_window, uris); + + g_slist_free (uris); } else { if (!GTK_WIDGET_VISIBLE (ev_window)) gtk_widget_destroy (GTK_WIDGET (ev_window)); diff --git a/shell/ev-application.h b/shell/ev-application.h index e6a3cf5..1d70124 100644 --- a/shell/ev-application.h +++ b/shell/ev-application.h @@ -57,7 +57,7 @@ EvApplication *ev_application_get_instance (void); void ev_application_open (EvApplication *application, GError *err); EvWindow *ev_application_new_window (EvApplication *application); -EvWindow * ev_application_get_empty_window (EvApplication *application); +EvWindow * ev_application_get_empty_window (EvApplication *application); G_END_DECLS 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; +} + + diff --git a/shell/ev-job-queue.h b/shell/ev-job-queue.h new file mode 100644 index 0000000..0a2f24c --- /dev/null +++ b/shell/ev-job-queue.h @@ -0,0 +1,40 @@ +/* this file is part of evince, a gnome document viewer + * + * 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. + */ + +#ifndef __EV_JOB_QUEUE_H__ +#define __EV_JOB_QUEUE_H__ + +#include <gtk/gtk.h> +#include "ev-jobs.h" +#include "ev-job-xfer.h" + +G_BEGIN_DECLS + + +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); + +G_END_DECLS + +#endif /* __EV_JOB_QUEUE_H__ */ diff --git a/shell/ev-job-xfer.c b/shell/ev-job-xfer.c new file mode 100644 index 0000000..b75e9d1 --- /dev/null +++ b/shell/ev-job-xfer.c @@ -0,0 +1,130 @@ +/* this file is part of evince, a gnome document viewer + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "ev-job-xfer.h" +#include "ev-document-types.h" + +#include <glib/gi18n.h> +#include <glib.h> + +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libgnomevfs/gnome-vfs-utils.h> +#include <libgnomevfs/gnome-vfs-ops.h> + +static void ev_job_xfer_init (EvJobXfer *job); +static void ev_job_xfer_class_init (EvJobXferClass *class); + +G_DEFINE_TYPE (EvJobXfer, ev_job_xfer, EV_TYPE_JOB) + +static void ev_job_xfer_init (EvJobXfer *job) { /* Do Nothing */ } + +static void +ev_job_xfer_dispose (GObject *object) +{ + EvJobXfer *job = EV_JOB_XFER (object); + + if (job->uri) { + g_free (job->uri); + job->uri = NULL; + } + + if (job->error) { + g_error_free (job->error); + job->error = NULL; + } + + (* G_OBJECT_CLASS (ev_job_xfer_parent_class)->dispose) (object); +} + +static void +ev_job_xfer_class_init (EvJobXferClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = ev_job_xfer_dispose; +} + + +EvJob * +ev_job_xfer_new (const gchar *uri) +{ + EvJobXfer *job; + + job = g_object_new (EV_TYPE_JOB_XFER, NULL); + + job->uri = g_strdup (uri); + + return EV_JOB (job); +} + +void +ev_job_xfer_run (EvJobXfer *job) +{ + GnomeVFSURI *vfs_uri; + char *mime_type; + GType document_type; + + g_return_if_fail (EV_IS_JOB_XFER (job)); + + if (job->error) { + g_error_free (job->error); + job->error = NULL; + } + + vfs_uri = gnome_vfs_uri_new (job->uri); + if (vfs_uri) { + if (!gnome_vfs_uri_exists (vfs_uri)) { + g_set_error (&job->error, + EV_DOCUMENT_ERROR, + 0, + _("The file %s does not exist."), + job->uri); + + EV_JOB (job)->finished = TRUE; + return; + } + } + gnome_vfs_uri_unref (vfs_uri); + + document_type = ev_document_type_lookup (job->uri, &mime_type); + + if (document_type != G_TYPE_INVALID) { + EV_JOB (job)->document = g_object_new (document_type, NULL); + } else { + g_set_error (&job->error, + EV_DOCUMENT_ERROR, + 0, + _("Unhandled MIME type: '%s'"), + mime_type ? mime_type : "<Unknown MIME Type>"); + EV_JOB (job)->finished = TRUE; + return; + } + + EV_JOB (job)->finished = TRUE; + return; +} + + diff --git a/shell/ev-job-xfer.h b/shell/ev-job-xfer.h new file mode 100644 index 0000000..dba9901 --- /dev/null +++ b/shell/ev-job-xfer.h @@ -0,0 +1,56 @@ +/* this file is part of evince, a gnome document viewer + * + * 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. + */ + +#ifndef __EV_JOB_XFER_H__ +#define __EV_JOB_XFER_H__ + +#include <gtk/gtk.h> +#include "ev-document.h" +#include "ev-jobs.h" + +G_BEGIN_DECLS + +typedef struct _EvJobXfer EvJobXfer; +typedef struct _EvJobXferClass EvJobXferClass; + +#define EV_TYPE_JOB_XFER (ev_job_xfer_get_type()) +#define EV_JOB_XFER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_XFER, EvJobXfer)) +#define EV_JOB_XFER_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_XFER, EvJobXferClass)) +#define EV_IS_JOB_XFER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_XFER)) + +struct _EvJobXfer +{ + EvJob parent; + GError *error; + gchar *uri; +}; + +struct _EvJobXferClass +{ + EvJobClass parent_class; +}; + +/* EvJobXfer */ +GType ev_job_xfer_get_type (void); +EvJob *ev_job_xfer_new (const gchar *uri); +void ev_job_xfer_run (EvJobXfer *xfer); + +G_END_DECLS + +#endif /* __EV_JOB_XFER_H__ */ diff --git a/shell/ev-jobs.c b/shell/ev-jobs.c new file mode 100644 index 0000000..be1d3bc --- /dev/null +++ b/shell/ev-jobs.c @@ -0,0 +1,343 @@ +#include "ev-jobs.h" +#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); +static void ev_job_links_init (EvJobLinks *job); +static void ev_job_links_class_init (EvJobLinksClass *class); +static void ev_job_render_init (EvJobRender *job); +static void ev_job_render_class_init (EvJobRenderClass *class); +static void ev_job_thumbnail_init (EvJobThumbnail *job); +static void ev_job_thumbnail_class_init (EvJobThumbnailClass *class); +static void ev_job_load_init (EvJobLoad *job); +static void ev_job_load_class_init (EvJobLoadClass *class); + +enum +{ + FINISHED, + LAST_SIGNAL +}; + +static guint job_signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_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) +G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB) + +static void ev_job_init (EvJob *job) { /* Do Nothing */ } + +static void +ev_job_dispose (GObject *object) +{ + EvJob *job; + + job = EV_JOB (object); + + if (job->document) { + g_object_unref (job->document); + job->document = NULL; + } + + (* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object); +} + +static void +ev_job_class_init (EvJobClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = ev_job_dispose; + + job_signals [FINISHED] = + g_signal_new ("finished", + EV_TYPE_JOB, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EvJobClass, finished), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + + +static void ev_job_links_init (EvJobLinks *job) { /* Do Nothing */ } + +static void +ev_job_links_dispose (GObject *object) +{ + EvJobLinks *job; + + job = EV_JOB_LINKS (object); + + if (job->model) { + g_object_unref (job->model); + job->model = NULL; + } + + (* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object); +} + +static void +ev_job_links_class_init (EvJobLinksClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = ev_job_links_dispose; +} + + +static void ev_job_render_init (EvJobRender *job) { /* Do Nothing */ } + +static void +ev_job_render_dispose (GObject *object) +{ + EvJobRender *job; + + job = EV_JOB_RENDER (object); + + if (job->pixbuf) { + g_object_unref (job->pixbuf); + job->pixbuf = NULL; + } + + (* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object); +} + +static void +ev_job_render_class_init (EvJobRenderClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = ev_job_render_dispose; +} + +static void ev_job_thumbnail_init (EvJobThumbnail *job) { /* Do Nothing */ } + +static void +ev_job_thumbnail_dispose (GObject *object) +{ + EvJobThumbnail *job; + + job = EV_JOB_THUMBNAIL (object); + + if (job->thumbnail) { + g_object_unref (job->thumbnail); + job->thumbnail = NULL; + } + + (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object); +} + +static void +ev_job_thumbnail_class_init (EvJobThumbnailClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = ev_job_thumbnail_dispose; +} + +static void ev_job_load_init (EvJobLoad *job) { /* Do Nothing */ } + +static void +ev_job_load_dispose (GObject *object) +{ + EvJobLoad *job; + + job = EV_JOB_LOAD (object); + + if (job->uri) { + g_free (job->uri); + job->uri = NULL; + } + + if (job->error) { + g_error_free (job->error); + job->error = NULL; + } + + (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object); +} + +static void +ev_job_load_class_init (EvJobLoadClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = ev_job_load_dispose; +} + +/* Public functions */ +void +ev_job_finished (EvJob *job) +{ + g_return_if_fail (EV_IS_JOB (job)); + + g_signal_emit (job, job_signals[FINISHED], 0); +} + +EvJob * +ev_job_links_new (EvDocument *document) +{ + EvJob *job; + + job = g_object_new (EV_TYPE_JOB_LINKS, NULL); + job->document = g_object_ref (document); + + return job; +} + +void +ev_job_links_run (EvJobLinks *job) +{ + g_return_if_fail (EV_IS_JOB_LINKS (job)); + + 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 (); +} + + +EvJob * +ev_job_render_new (EvDocument *document, + gint page, + double scale, + gint width, + gint height, + gboolean include_links) +{ + EvJobRender *job; + + job = g_object_new (EV_TYPE_JOB_RENDER, NULL); + + EV_JOB (job)->document = g_object_ref (document); + job->page = page; + job->scale = scale; + job->target_width = width; + 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) +{ + g_return_if_fail (EV_IS_JOB_RENDER (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); + 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 (); +} + +EvJob * +ev_job_thumbnail_new (EvDocument *document, + gint page, + gint requested_width) +{ + EvJobThumbnail *job; + + job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL); + + EV_JOB (job)->document = g_object_ref (document); + job->page = page; + job->requested_width = requested_width; + + return EV_JOB (job); +} + +void +ev_job_thumbnail_run (EvJobThumbnail *job) +{ + g_return_if_fail (EV_IS_JOB_THUMBNAIL (job)); + + ev_document_doc_mutex_lock (); + + job->thumbnail = + ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB (job)->document), + job->page, + job->requested_width, + TRUE); + EV_JOB (job)->finished = TRUE; + + ev_document_doc_mutex_unlock (); +} + +EvJob * +ev_job_load_new (EvDocument *document, + const gchar *uri) +{ + EvJobLoad *job; + + job = g_object_new (EV_TYPE_JOB_LOAD, NULL); + + EV_JOB (job)->document = g_object_ref (document); + job->uri = g_strdup (uri); + + return EV_JOB (job); +} + +void +ev_job_load_run (EvJobLoad *job) +{ + g_return_if_fail (EV_IS_JOB_LOAD (job)); + + ev_document_doc_mutex_lock (); + + if (job->error) { + g_error_free (job->error); + job->error = NULL; + } + + ev_document_load (EV_JOB(job)->document, job->uri, &job->error); + + EV_JOB (job)->finished = TRUE; + + ev_document_doc_mutex_unlock (); +} + + diff --git a/shell/ev-jobs.h b/shell/ev-jobs.h new file mode 100644 index 0000000..11a3f09 --- /dev/null +++ b/shell/ev-jobs.h @@ -0,0 +1,178 @@ +/* this file is part of evince, a gnome document viewer + * + * 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. + */ + +#ifndef __EV_JOBS_H__ +#define __EV_JOBS_H__ + +#include <gtk/gtk.h> +#include "ev-document.h" + +G_BEGIN_DECLS + +typedef struct _EvJob EvJob; +typedef struct _EvJobClass EvJobClass; + +typedef struct _EvJobRender EvJobRender; +typedef struct _EvJobRenderClass EvJobRenderClass; + +typedef struct _EvJobThumbnail EvJobThumbnail; +typedef struct _EvJobThumbnailClass EvJobThumbnailClass; + +typedef struct _EvJobLinks EvJobLinks; +typedef struct _EvJobLinksClass EvJobLinksClass; + +typedef struct _EvJobLoad EvJobLoad; +typedef struct _EvJobLoadClass EvJobLoadClass; + +#define EV_TYPE_JOB (ev_job_get_type()) +#define EV_JOB(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB, EvJob)) +#define EV_JOB_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB, EvJobClass)) +#define EV_IS_JOB(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB)) + +#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)) +#define EV_JOB_LINKS_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_LINKS, EvJobLinksClass)) +#define EV_IS_JOB_LINKS(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_LINKS)) + +#define EV_TYPE_JOB_RENDER (ev_job_render_get_type()) +#define EV_JOB_RENDER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_RENDER, EvJobRender)) +#define EV_JOB_RENDER_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_RENDER, EvJobRenderClass)) +#define EV_IS_JOB_RENDER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_RENDER)) + +#define EV_TYPE_JOB_THUMBNAIL (ev_job_thumbnail_get_type()) +#define EV_JOB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_THUMBNAIL, EvJobThumbnail)) +#define EV_JOB_THUMBNAIL_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_THUMBNAIL, EvJobThumbnailClass)) +#define EV_IS_JOB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_THUMBNAIL)) + +#define EV_TYPE_JOB_LOAD (ev_job_load_get_type()) +#define EV_JOB_LOAD(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_LOAD, EvJobLoad)) +#define EV_JOB_LOAD_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_LOAD, EvJobLoadClass)) +#define EV_IS_JOB_LOAD(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_LOAD)) + +typedef enum { + EV_JOB_PRIORITY_LOW, + EV_JOB_PRIORITY_HIGH, +} EvJobPriority; + +struct _EvJob +{ + GObject parent; + EvDocument *document; + gboolean finished; + gboolean async; +}; + +struct _EvJobClass +{ + GObjectClass parent_class; + + void (* finished) (EvJob *job); +}; + +struct _EvJobLinks +{ + EvJob parent; + + GtkTreeModel *model; +}; + +struct _EvJobLinksClass +{ + EvJobClass parent_class; +}; + +struct _EvJobRender +{ + EvJob parent; + + gint page; + double scale; + gint target_width; + gint target_height; + GdkPixbuf *pixbuf; + GList *link_mapping; + gboolean include_links; +}; + +struct _EvJobRenderClass +{ + EvJobClass parent_class; +}; + +struct _EvJobThumbnail +{ + EvJob parent; + + gint page; + gint requested_width; + GdkPixbuf *thumbnail; +}; + +struct _EvJobThumbnailClass +{ + EvJobClass parent_class; +}; + +struct _EvJobLoad +{ + EvJob parent; + GError *error; + gchar *uri; +}; + +struct _EvJobLoadClass +{ + EvJobClass parent_class; +}; + +/* Base job class */ +GType ev_job_get_type (void); +void ev_job_finished (EvJob *job); + +/* EvJobLinks */ +GType ev_job_links_get_type (void); +EvJob *ev_job_links_new (EvDocument *document); +void ev_job_links_run (EvJobLinks *thumbnail); + +/* EvJobRender */ +GType ev_job_render_get_type (void); +EvJob *ev_job_render_new (EvDocument *document, + gint page, + double scale, + gint width, + gint height, + gboolean include_links); +void ev_job_render_run (EvJobRender *thumbnail); + +/* EvJobThumbnail */ +GType ev_job_thumbnail_get_type (void); +EvJob *ev_job_thumbnail_new (EvDocument *document, + gint page, + gint requested_width); +void ev_job_thumbnail_run (EvJobThumbnail *thumbnail); + +/* EvJobLoad */ +GType ev_job_load_get_type (void); +EvJob *ev_job_load_new (EvDocument *document, + const gchar *uri); +void ev_job_load_run (EvJobLoad *load); + +G_END_DECLS + +#endif /* __EV_JOBS_H__ */ diff --git a/shell/ev-page-action.c b/shell/ev-page-action.c index b1c61e6..076dff1 100644 --- a/shell/ev-page-action.c +++ b/shell/ev-page-action.c @@ -22,6 +22,7 @@ #include "config.h" #include "ev-page-action.h" +#include "ev-page-cache.h" #include "ev-window.h" #include "ev-document-links.h" #include "ev-marshal.h" @@ -569,7 +570,7 @@ ev_page_action_set_document (EvPageAction *page, EvDocument *document) EvPageCache *page_cache = NULL; if (document) - page_cache = ev_document_get_page_cache (document); + page_cache = ev_page_cache_get (document); g_object_set (page, "page-cache", page_cache, diff --git a/shell/ev-page-cache.c b/shell/ev-page-cache.c new file mode 100644 index 0000000..6c44c9f --- /dev/null +++ b/shell/ev-page-cache.c @@ -0,0 +1,485 @@ +#include "ev-page-cache.h" +#include "ev-job-queue.h" +#include <stdlib.h> +#include <string.h> + +typedef struct _EvPageCacheInfo +{ + double width; + double height; +} +EvPageCacheInfo; + + +struct _EvPageCache +{ + GObject parent; + + gint current_page; + int n_pages; + char *title; + char **page_labels; + + gint max_label_chars; + gboolean has_labels; + gboolean uniform; + + double uniform_width; + double uniform_height; + + double max_width; + double max_height; + double* height_to_page; + double* dual_height_to_page; + + EvPageCacheInfo *size_cache; + EvDocumentInfo *page_info; +}; + +struct _EvPageCacheClass +{ + GObjectClass parent_class; + + void (* page_changed) (EvPageCache *page_cache, gint page); +}; + +enum +{ + PAGE_CHANGED, + N_SIGNALS, +}; + +static guint signals[N_SIGNALS] = {0, }; + +static void ev_page_cache_init (EvPageCache *page_cache); +static void ev_page_cache_class_init (EvPageCacheClass *page_cache); +static void ev_page_cache_finalize (GObject *object); + +G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT) + +static void +ev_page_cache_init (EvPageCache *page_cache) +{ + page_cache->current_page = -1; + page_cache->max_label_chars = 0; +} + +static void +ev_page_cache_class_init (EvPageCacheClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + + object_class->finalize = ev_page_cache_finalize; + + signals [PAGE_CHANGED] = + g_signal_new ("page-changed", + EV_TYPE_PAGE_CACHE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EvPageCacheClass, page_changed), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); + +} + +static void +ev_page_cache_finalize (GObject *object) +{ + EvPageCache *page_cache; + + page_cache = EV_PAGE_CACHE (object); + + g_free (page_cache->title); + g_free (page_cache->size_cache); + g_free (page_cache->height_to_page); + g_free (page_cache->dual_height_to_page); + + ev_document_info_free (page_cache->page_info); +} + +EvPageCache * +ev_page_cache_new (EvDocument *document) +{ + EvPageCache *page_cache; + EvPageCacheInfo *info; + gint i; + double saved_height; + + page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL); + + ev_document_doc_mutex_lock (); + + /* We read page information out of the document */ + + /* Assume all pages are the same size until proven otherwise */ + page_cache->uniform = TRUE; + page_cache->has_labels = FALSE; + page_cache->n_pages = ev_document_get_n_pages (document); + page_cache->page_labels = g_new0 (char *, page_cache->n_pages); + page_cache->max_width = 0; + page_cache->max_height = 0; + page_cache->page_info = ev_document_get_info (document); + + if (page_cache->page_info->fields_mask & EV_DOCUMENT_INFO_TITLE) { + page_cache->title = g_strdup (page_cache->page_info->title); + } else { + page_cache->title = NULL; + } + + for (i = 0; i < page_cache->n_pages; i++) { + double page_width = 0; + double page_height = 0; + + ev_document_get_page_size (document, i, &page_width, &page_height); + + page_cache->page_labels[i] = ev_document_get_page_label (document, i); + + if (page_cache->page_labels[i] != NULL) { + + page_cache->max_label_chars = MAX(page_cache->max_label_chars, + g_utf8_strlen (page_cache->page_labels[i], 256)); + if (!page_cache->has_labels) { + gchar *expected_label; + + expected_label = g_strdup_printf ("%d", i + 1); + if (strcmp (expected_label, page_cache->page_labels[i])) + page_cache->has_labels = TRUE; + g_free (expected_label); + } + } + + if (page_width > page_cache->max_width) { + page_cache->max_width = page_width; + } + + if (page_height > page_cache->max_height) { + page_cache->max_height = page_height; + } + + if (i == 0) { + page_cache->uniform_width = page_width; + page_cache->uniform_height = page_height; + } else if (page_cache->uniform && + (page_cache->uniform_width != page_width || + page_cache->uniform_height != page_height)) { + /* It's a different page size. Backfill the array. */ + int j; + + page_cache->size_cache = g_new0 (EvPageCacheInfo, page_cache->n_pages); + + for (j = 0; j < i; j++) { + info = &(page_cache->size_cache [j]); + info->width = page_cache->uniform_width; + info->height = page_cache->uniform_height; + } + page_cache->uniform = FALSE; + + } + + if (! page_cache->uniform) { + info = &(page_cache->size_cache [i]); + + info->width = page_width; + info->height = page_height; + } + } + + page_cache->height_to_page = g_new0(double, page_cache->n_pages); + page_cache->dual_height_to_page = g_new0(double, page_cache->n_pages / 2 + 1); + + saved_height = 0; + for (i = 0; i < page_cache->n_pages; i++) { + + if (page_cache->uniform) { + page_cache->height_to_page [i] = (i + 1) * page_cache->uniform_height; + } else { + page_cache->height_to_page [i] = saved_height + page_cache->size_cache [i].height; + saved_height = page_cache->height_to_page [i]; + } + } + + saved_height = 0; + for (i = 0; i < page_cache->n_pages; i += 2) { + + if (page_cache->uniform) { + page_cache->dual_height_to_page [i / 2] = (i / 2 + 1) * page_cache->uniform_height; + } else { + if (i == page_cache->n_pages - 1) { + page_cache->dual_height_to_page [i / 2] = + saved_height + page_cache->size_cache [i].height; + } + else { + page_cache->dual_height_to_page [i / 2] = saved_height + + MAX(page_cache->size_cache [i].height, + page_cache->size_cache [i + 1].height); + saved_height = page_cache->dual_height_to_page [i / 2]; + } + } + } + + /* make some sanity check assertions */ + if (! page_cache->uniform) + g_assert (page_cache->size_cache != NULL); + if (page_cache->uniform) + g_assert (page_cache->uniform_width > 0 && page_cache->uniform_height > 0); + + ev_document_doc_mutex_unlock (); + + if (page_cache->n_pages > 0) + ev_page_cache_set_current_page (page_cache, 0); + + return page_cache; +} + +gint +ev_page_cache_get_n_pages (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0); + + return page_cache->n_pages; +} + +gint +ev_page_cache_get_current_page (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0); + + return page_cache->current_page; +} + +void +ev_page_cache_set_current_page (EvPageCache *page_cache, + int page) +{ + g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + g_return_if_fail (page >= 0 || page < page_cache->n_pages); + + if (page == page_cache->current_page) + return; + + page_cache->current_page = page; + g_signal_emit (page_cache, signals[PAGE_CHANGED], 0, page); +} + +gboolean +ev_page_cache_set_page_label (EvPageCache *page_cache, + const char *page_label) +{ + gint i, page; + long value; + char *endptr = NULL; + + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE); + g_return_val_if_fail (page_label != NULL, FALSE); + + /* First, look for a literal label match */ + for (i = 0; i < page_cache->n_pages; i ++) { + if (page_cache->page_labels[i] != NULL && + ! strcmp (page_label, page_cache->page_labels[i])) { + ev_page_cache_set_current_page (page_cache, i); + return TRUE; + } + } + + /* Next, parse the label, and see if the number fits */ + value = strtol (page_label, &endptr, 10); + if (endptr[0] == '\0') { + /* Page number is an integer */ + page = MIN (G_MAXINT, value); + + /* convert from a page label to a page offset */ + page --; + if (page >= 0 && + page < page_cache->n_pages && + page_cache->page_labels[page] == NULL) { + ev_page_cache_set_current_page (page_cache, page); + return TRUE; + } + } + + return FALSE; +} + +void +ev_page_cache_set_link (EvPageCache *page_cache, + EvLink *link) +{ + g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + g_return_if_fail (EV_IS_LINK (link)); + + ev_page_cache_set_current_page (page_cache, ev_link_get_page (link)); +} + +const char * +ev_page_cache_get_title (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL); + + return page_cache->title; +} + +void +ev_page_cache_get_size (EvPageCache *page_cache, + gint page, + gfloat scale, + gint *width, + gint *height) +{ + g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + g_return_if_fail (page >= 0 && page < page_cache->n_pages); + + if (page_cache->uniform) { + if (width) + *width = page_cache->uniform_width; + if (height) + *height = page_cache->uniform_height; + } else { + EvPageCacheInfo *info; + + info = &(page_cache->size_cache [page]); + + if (width) + *width = info->width; + if (height) + *height = info->height; + } + + if (width) + *width = (int) ((*width) * scale + 0.5); + if (width) + *height = (int) ((*height) * scale + 0.5); + +} + + +void +ev_page_cache_get_max_width (EvPageCache *page_cache, + gfloat scale, + gint *width) +{ + g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + + if (width) + *width = page_cache->max_width * scale; +} + +void +ev_page_cache_get_max_height (EvPageCache *page_cache, + gfloat scale, + gint *height) +{ + g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + + if (height) + *height = page_cache->max_height * scale; +} + +void +ev_page_cache_get_height_to_page (EvPageCache *page_cache, + gint page, + gfloat scale, + gint *height, + gint *dual_height) +{ + double result = 0.0; + double dual_result = 0.0; + + g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + + if (page > 0) + result = page_cache->height_to_page [page - 1]; + + if (height) + *height = result * scale; + + if (page > 1) + dual_result = page_cache->dual_height_to_page [page / 2 - 1]; + + if (dual_height) + *dual_height = dual_result * scale; +} + +gint +ev_page_cache_get_max_label_chars (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0); + + return page_cache->max_label_chars; +} + +gchar * +ev_page_cache_get_page_label (EvPageCache *page_cache, + gint page) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL); + g_return_val_if_fail (page >= 0 && page < page_cache->n_pages, NULL); + + if (page_cache->page_labels[page] == NULL) + return g_strdup_printf ("%d", page + 1); + + return g_strdup (page_cache->page_labels[page]); +} + +gboolean +ev_page_cache_has_nonnumeric_page_labels (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE); + return page_cache->has_labels; +} + +const EvDocumentInfo * +ev_page_cache_get_info (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL); + + return page_cache->page_info; +} + + +gboolean +ev_page_cache_next_page (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE); + + if (page_cache->current_page >= page_cache->n_pages - 1) + return FALSE; + + ev_page_cache_set_current_page (page_cache, page_cache->current_page + 1); + return TRUE; + +} + +gboolean +ev_page_cache_prev_page (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE); + + if (page_cache->current_page <= 0) + return FALSE; + + ev_page_cache_set_current_page (page_cache, page_cache->current_page - 1); + return TRUE; +} + +#define PAGE_CACHE_STRING "ev-page-cache" + +EvPageCache * +ev_page_cache_get (EvDocument *document) +{ + EvPageCache *page_cache; + + g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL); + + page_cache = g_object_get_data (G_OBJECT (document), PAGE_CACHE_STRING); + if (page_cache == NULL) { + page_cache = ev_page_cache_new (document); + g_object_set_data_full (G_OBJECT (document), PAGE_CACHE_STRING, page_cache, g_object_unref); + } + + return page_cache; +} + + diff --git a/shell/ev-page-cache.h b/shell/ev-page-cache.h new file mode 100644 index 0000000..b0bf6cc --- /dev/null +++ b/shell/ev-page-cache.h @@ -0,0 +1,74 @@ +/* this file is part of evince, a gnome document viewer + * + * 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. + */ + +#ifndef __EV_PAGE_CACHE_H__ +#define __EV_PAGE_CACHE_H__ + +#include <gtk/gtkwidget.h> +#include "ev-document.h" + +G_BEGIN_DECLS +#define EV_TYPE_PAGE_CACHE (ev_page_cache_get_type ()) +#define EV_PAGE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_CACHE, EvPageCache)) +#define EV_IS_PAGE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PAGE_CACHE)) + +GType ev_page_cache_get_type (void) G_GNUC_CONST; + +/* Used by ev-document.c only */ +EvPageCache *ev_page_cache_new (EvDocument *document); +gint ev_page_cache_get_n_pages (EvPageCache *page_cache); +const char *ev_page_cache_get_title (EvPageCache *page_cache); +void ev_page_cache_get_size (EvPageCache *page_cache, + gint page, + gfloat scale, + gint *width, + gint *height); +void ev_page_cache_get_max_width (EvPageCache *page_cache, + gfloat scale, + gint *width); +void ev_page_cache_get_max_height (EvPageCache *page_cache, + gfloat scale, + gint *height); +void ev_page_cache_get_height_to_page (EvPageCache *page_cache, + gint page, + gfloat scale, + gint *height, + gint *dual_height); +gint ev_page_cache_get_max_label_chars (EvPageCache *page_cache); +char *ev_page_cache_get_page_label (EvPageCache *page_cache, + gint page); +gboolean ev_page_cache_has_nonnumeric_page_labels (EvPageCache *page_cache); +const EvDocumentInfo *ev_page_cache_get_info (EvPageCache *page_cache); + +/* Navigation */ +gint ev_page_cache_get_current_page (EvPageCache *page_cache); +void ev_page_cache_set_current_page (EvPageCache *page_cache, + int page); +gboolean ev_page_cache_set_page_label (EvPageCache *page_cache, + const char *page_label); +void ev_page_cache_set_link (EvPageCache *page_cache, + EvLink *link); +gboolean ev_page_cache_next_page (EvPageCache *page_cache); +gboolean ev_page_cache_prev_page (EvPageCache *page_cache); + +EvPageCache* ev_page_cache_get (EvDocument *document); + +G_END_DECLS + +#endif /* __EV_PAGE_CACHE_H__ */ diff --git a/shell/ev-pixbuf-cache.c b/shell/ev-pixbuf-cache.c index 083825a..0601de0 100644 --- a/shell/ev-pixbuf-cache.c +++ b/shell/ev-pixbuf-cache.c @@ -1,5 +1,6 @@ #include "ev-pixbuf-cache.h" #include "ev-job-queue.h" +#include "ev-page-cache.h" typedef struct _CacheJobInfo @@ -306,7 +307,7 @@ ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, pixbuf_cache->end_page == end_page) return; - page_cache = ev_document_get_page_cache (pixbuf_cache->document); + page_cache = ev_page_cache_get (pixbuf_cache->document); new_job_list = g_new0 (CacheJobInfo, (end_page - start_page) + 1); new_prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size); @@ -417,7 +418,7 @@ ev_pixbuf_cache_clear_job_sizes (EvPixbufCache *pixbuf_cache, EvPageCache *page_cache; int i; - page_cache = ev_document_get_page_cache (pixbuf_cache->document); + page_cache = ev_page_cache_get (pixbuf_cache->document); for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) { check_job_size_and_unref (pixbuf_cache->job_list + i, page_cache, scale); @@ -473,7 +474,7 @@ ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache, int page; int i; - page_cache = ev_document_get_page_cache (pixbuf_cache->document); + page_cache = ev_page_cache_get (pixbuf_cache->document); for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) { job_info = (pixbuf_cache->job_list + i); @@ -514,7 +515,7 @@ ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache)); - page_cache = ev_document_get_page_cache (pixbuf_cache->document); + page_cache = ev_page_cache_get (pixbuf_cache->document); g_return_if_fail (start_page >= 0 && start_page < ev_page_cache_get_n_pages (page_cache)); g_return_if_fail (end_page >= 0 && end_page < ev_page_cache_get_n_pages (page_cache)); diff --git a/shell/ev-print-job.c b/shell/ev-print-job.c index e7c1ce1..f79c1fc 100644 --- a/shell/ev-print-job.c +++ b/shell/ev-print-job.c @@ -34,6 +34,7 @@ #include "ev-ps-exporter.h" #include "ev-print-job.h" +#include "ev-page-cache.h" #define EV_PRINT_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_PRINT_JOB, EvPrintJobClass)) #define EV_IS_PRINT_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_PRINT_JOB)) @@ -219,7 +220,7 @@ void ev_print_job_use_print_dialog_settings (EvPrintJob *job, GnomePrintDialog *dialog) { GnomePrintConfig *print_config; - EvPageCache *page_cache = ev_document_get_page_cache (job->document); + EvPageCache *page_cache = ev_page_cache_get (job->document); g_return_if_fail (EV_IS_PRINT_JOB (job)); g_return_if_fail (GNOME_IS_PRINT_DIALOG (dialog)); @@ -231,7 +232,7 @@ ev_print_job_use_print_dialog_settings (EvPrintJob *job, GnomePrintDialog *dialo gnome_print_config_get_boolean (print_config, (guchar *)GNOME_PRINT_KEY_DUPLEX, &job->duplex); - page_cache = ev_document_get_page_cache (job->document); + page_cache = ev_page_cache_get (job->document); /* get the printing ranges */ switch (gnome_print_dialog_get_range (dialog)) { diff --git a/shell/ev-sidebar-links.c b/shell/ev-sidebar-links.c index 6882007..ced98c8 100644 --- a/shell/ev-sidebar-links.c +++ b/shell/ev-sidebar-links.c @@ -581,7 +581,7 @@ ev_sidebar_links_set_document (EvSidebarPage *sidebar_page, } priv->document = g_object_ref (document); - priv->page_cache = ev_document_get_page_cache (document); + priv->page_cache = ev_page_cache_get (document); if (priv->job) { g_signal_handlers_disconnect_by_func (priv->job, diff --git a/shell/ev-sidebar-thumbnails.c b/shell/ev-sidebar-thumbnails.c index 7f84be1..5d228f3 100644 --- a/shell/ev-sidebar-thumbnails.c +++ b/shell/ev-sidebar-thumbnails.c @@ -298,7 +298,7 @@ ev_sidebar_tree_selection_changed (GtkTreeSelection *selection, page = gtk_tree_path_get_indices (path)[0]; gtk_tree_path_free (path); - page_cache = ev_document_get_page_cache (priv->document); + page_cache = ev_page_cache_get (priv->document); ev_page_cache_set_current_page (page_cache, page); } @@ -403,7 +403,7 @@ ev_sidebar_thumbnails_set_document (EvSidebarPage *sidebar_page, g_return_if_fail (EV_IS_DOCUMENT_THUMBNAILS (document)); - page_cache = ev_document_get_page_cache (document); + page_cache = ev_page_cache_get (document); n_pages = ev_page_cache_get_n_pages (page_cache); priv->document = document; diff --git a/shell/ev-statusbar.c b/shell/ev-statusbar.c new file mode 100644 index 0000000..b37cff7 --- /dev/null +++ b/shell/ev-statusbar.c @@ -0,0 +1,201 @@ +/* this file is part of evince, a gnome document viewer + * + * Copyright (C) 2004 Red Hat, Inc. + * + * Author: + * Jonathan Blandford <jrb@alum.mit.edu> + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <gtk/gtk.h> + +#include "ev-statusbar.h" + +struct _EvStatusbarPrivate { + GtkWidget *bar; + GtkWidget *progress; + + guint help_message_cid; + guint view_message_cid; + guint progress_message_cid; + + guint pulse_timeout_id; + guint progress_timeout_id; +}; + +G_DEFINE_TYPE (EvStatusbar, ev_statusbar, GTK_TYPE_HBOX) + +#define EV_STATUSBAR_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_STATUSBAR, EvStatusbarPrivate)) + +static void +ev_statusbar_destroy (GtkObject *object) +{ + EvStatusbar *ev_statusbar = EV_STATUSBAR (object); + + ev_statusbar_set_progress (ev_statusbar, FALSE); + + (* GTK_OBJECT_CLASS (ev_statusbar_parent_class)->destroy) (object); +} + +static void +ev_statusbar_class_init (EvStatusbarClass *ev_statusbar_class) +{ + GObjectClass *g_object_class; + GtkWidgetClass *widget_class; + GtkObjectClass *gtk_object_klass; + + g_object_class = G_OBJECT_CLASS (ev_statusbar_class); + widget_class = GTK_WIDGET_CLASS (ev_statusbar_class); + gtk_object_klass = GTK_OBJECT_CLASS (ev_statusbar_class); + + g_type_class_add_private (g_object_class, sizeof (EvStatusbarPrivate)); + + gtk_object_klass->destroy = ev_statusbar_destroy; +} + +static void +ev_statusbar_init (EvStatusbar *ev_statusbar) +{ + ev_statusbar->priv = EV_STATUSBAR_GET_PRIVATE (ev_statusbar); + + ev_statusbar->priv->progress = gtk_progress_bar_new (); + gtk_box_pack_start (GTK_BOX (ev_statusbar), ev_statusbar->priv->progress, FALSE, FALSE, 3); + ev_statusbar->priv->bar = gtk_statusbar_new (); + gtk_box_pack_start (GTK_BOX (ev_statusbar), ev_statusbar->priv->bar, TRUE, TRUE, 0); + + ev_statusbar->priv->help_message_cid = gtk_statusbar_get_context_id + (GTK_STATUSBAR (ev_statusbar->priv->bar), "help_message"); + ev_statusbar->priv->view_message_cid = gtk_statusbar_get_context_id + (GTK_STATUSBAR (ev_statusbar->priv->bar), "view_message"); + ev_statusbar->priv->progress_message_cid = gtk_statusbar_get_context_id + (GTK_STATUSBAR (ev_statusbar->priv->bar), "progress_message"); + + gtk_widget_show (GTK_WIDGET (ev_statusbar->priv->bar)); + gtk_widget_show (GTK_WIDGET (ev_statusbar)); + + ev_statusbar->priv->progress_timeout_id = 0; + ev_statusbar->priv->pulse_timeout_id = 0; +} + +/* Public functions */ + +GtkWidget * +ev_statusbar_new (void) +{ + GtkWidget *ev_statusbar; + + ev_statusbar = g_object_new (EV_TYPE_STATUSBAR, NULL); + + return ev_statusbar; +} + +static guint +ev_statusbar_get_context_id (EvStatusbar *statusbar, EvStatusbarContext context) +{ + switch (context) { + case EV_CONTEXT_HELP: + return statusbar->priv->help_message_cid; + case EV_CONTEXT_VIEW: + return statusbar->priv->view_message_cid; + case EV_CONTEXT_PROGRESS: + return statusbar->priv->progress_message_cid; + } + return -1; +} + +void +ev_statusbar_push (EvStatusbar *ev_statusbar, + EvStatusbarContext context, + const gchar *message) +{ + gtk_statusbar_push (GTK_STATUSBAR (ev_statusbar->priv->bar), + ev_statusbar_get_context_id (ev_statusbar, context), + message); + return; +} + +void +ev_statusbar_pop (EvStatusbar *ev_statusbar, + EvStatusbarContext context) +{ + gtk_statusbar_pop (GTK_STATUSBAR (ev_statusbar->priv->bar), + ev_statusbar_get_context_id (ev_statusbar, context)); + return; +} + +void +ev_statusbar_set_maximized (EvStatusbar *ev_statusbar, + gboolean maximized) +{ + gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (ev_statusbar->priv->bar), + maximized); + return; +} + +static gboolean +ev_statusbar_pulse (gpointer data) +{ + EvStatusbar *ev_statusbar = EV_STATUSBAR (data); + + gtk_progress_bar_pulse (GTK_PROGRESS_BAR (ev_statusbar->priv->progress)); + + return TRUE; +} + +static gboolean +ev_statusbar_show_progress (gpointer data) +{ + EvStatusbar *ev_statusbar = EV_STATUSBAR (data); + + gtk_widget_show (ev_statusbar->priv->progress); + ev_statusbar->priv->pulse_timeout_id = g_timeout_add (300, ev_statusbar_pulse, ev_statusbar); + ev_statusbar->priv->progress_timeout_id = 0; + + return FALSE; +} + +void +ev_statusbar_set_progress (EvStatusbar *ev_statusbar, + gboolean active) +{ + if (active){ + if (ev_statusbar->priv->progress_timeout_id == 0 + && ev_statusbar->priv->pulse_timeout_id == 0) + ev_statusbar->priv->progress_timeout_id = + g_timeout_add (500, ev_statusbar_show_progress, ev_statusbar); + } else { + if (ev_statusbar->priv->pulse_timeout_id) { + g_source_remove (ev_statusbar->priv->pulse_timeout_id); + gtk_widget_hide (ev_statusbar->priv->progress); + } + + if (ev_statusbar->priv->progress_timeout_id) + g_source_remove (ev_statusbar->priv->progress_timeout_id); + + ev_statusbar->priv->progress_timeout_id = 0; + ev_statusbar->priv->pulse_timeout_id = 0; + + } +} + + + diff --git a/shell/ev-statusbar.h b/shell/ev-statusbar.h new file mode 100644 index 0000000..e742525 --- /dev/null +++ b/shell/ev-statusbar.h @@ -0,0 +1,76 @@ +/* ev-statusbar.h + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2004 Red Hat, Inc. + * + * Author: + * Jonathan Blandford <jrb@alum.mit.edu> + * + * 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. + */ + +#ifndef __EV_STATUSBAR_H__ +#define __EV_STATUSBAR_H__ + +#include <gtk/gtkvbox.h> +#include "ev-document.h" + +G_BEGIN_DECLS + +typedef struct _EvStatusbar EvStatusbar; +typedef struct _EvStatusbarClass EvStatusbarClass; +typedef struct _EvStatusbarPrivate EvStatusbarPrivate; + +#define EV_TYPE_STATUSBAR (ev_statusbar_get_type()) +#define EV_STATUSBAR(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_STATUSBAR, EvStatusbar)) +#define EV_STATUSBAR_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_STATUSBAR, EvStatusbarClass)) +#define EV_IS_STATUSBAR(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_STATUSBAR)) +#define EV_IS_STATUSBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_STATUSBAR)) +#define EV_STATUSBAR_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_STATUSBAR, EvStatusbarClass)) + +struct _EvStatusbar { + GtkHBox base_instance; + + EvStatusbarPrivate *priv; +}; + +struct _EvStatusbarClass { + GtkHBoxClass base_class; +}; + +GType ev_statusbar_get_type (void); +GtkWidget *ev_statusbar_new (void); + +typedef enum { + EV_CONTEXT_HELP, + EV_CONTEXT_VIEW, + EV_CONTEXT_PROGRESS, +} EvStatusbarContext; + +void ev_statusbar_push (EvStatusbar *ev_statusbar, + EvStatusbarContext context, + const gchar *message); +void ev_statusbar_pop (EvStatusbar *ev_statusbar, + EvStatusbarContext context); +void ev_statusbar_set_maximized (EvStatusbar *ev_statusbar, + gboolean maximized); +void ev_statusbar_set_progress (EvStatusbar *ev_statusbar, + gboolean active); + +G_END_DECLS + +#endif /* __EV_STATUSBAR_H__ */ + + diff --git a/shell/ev-view.c b/shell/ev-view.c index a4032e9..ff05be2 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -1932,7 +1932,7 @@ ev_view_set_document (EvView *view, G_CALLBACK (find_changed_cb), view); } - view->page_cache = ev_document_get_page_cache (view->document); + view->page_cache = ev_page_cache_get (view->document); g_signal_connect (view->page_cache, "page-changed", G_CALLBACK (page_changed_cb), view); view->pixbuf_cache = ev_pixbuf_cache_new (view->document); g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view); @@ -2505,7 +2505,7 @@ ev_view_find_next (EvView *view) int n_results, n_pages; EvDocumentFind *find = EV_DOCUMENT_FIND (view->document); - page_cache = ev_document_get_page_cache (view->document); + page_cache = ev_page_cache_get (view->document); n_results = ev_document_find_get_n_results (find, view->current_page); n_pages = ev_page_cache_get_n_pages (page_cache); @@ -2534,7 +2534,7 @@ ev_view_find_previous (EvView *view) EvDocumentFind *find = EV_DOCUMENT_FIND (view->document); EvPageCache *page_cache; - page_cache = ev_document_get_page_cache (view->document); + page_cache = ev_page_cache_get (view->document); n_results = ev_document_find_get_n_results (find, view->current_page); diff --git a/shell/ev-window.c b/shell/ev-window.c index 7bdeacd..577ee4c 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -41,10 +41,11 @@ #include "ev-document-thumbnails.h" #include "ev-document-links.h" #include "ev-document-fonts.h" -#include "ev-document-types.h" #include "ev-document-find.h" #include "ev-document-security.h" #include "ev-job-queue.h" +#include "ev-jobs.h" +#include "ev-statusbar.h" #include "eggfindbar.h" #include "egg-recent-view-gtk.h" #include "egg-recent-view.h" @@ -62,12 +63,8 @@ #include <glib/gi18n.h> #include <gtk/gtk.h> #include <gnome.h> - -#include <libgnomevfs/gnome-vfs-uri.h> -#include <libgnomevfs/gnome-vfs-utils.h> -#include <libgnomevfs/gnome-vfs-ops.h> #include <libgnomeprintui/gnome-print-dialog.h> - +#include <libgnomevfs/gnome-vfs-utils.h> #include <gconf/gconf-client.h> #include <string.h> @@ -87,6 +84,9 @@ typedef enum { } EvChrome; struct _EvWindowPrivate { + /* UI */ + EvChrome chrome; + GtkWidget *main_box; GtkWidget *menubar; GtkWidget *toolbar_dock; @@ -98,31 +98,35 @@ struct _EvWindowPrivate { GtkWidget *view; GtkWidget *page_view; GtkWidget *password_view; + GtkWidget *statusbar; + /* UI Builders */ GtkActionGroup *action_group; GtkUIManager *ui_manager; gchar *toolbar_file; EggToolbarsModel *toolbar_model; - - GtkWidget *statusbar; - guint help_message_cid; - guint view_message_cid; + + /* Fullscreen mode */ GtkWidget *fullscreen_toolbar; GtkWidget *fullscreen_popup; - char *uri; + GSource *fullscreen_timeout_source; + /* Document */ + char *uri; EvDocument *document; EvPageCache *page_cache; EvWindowPageMode page_mode; + /* These members are used temporarily when in PAGE_MODE_PASSWORD */ EvDocument *password_document; GtkWidget *password_dialog; char *password_uri; - EvChrome chrome; - GSource *fullscreen_timeout_source; + /* Job used to load document */ + EvJob *xfer_job; + EvJob *load_job; /* recent file stuff */ EggRecentModel *recent_model; @@ -154,9 +158,10 @@ 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 gboolean start_loading_document (EvWindow *ev_window, - EvDocument *document, - const char *uri); +static void ev_window_load_job_cb (EvJobLoad *job, + gpointer data); +static void ev_window_xfer_job_cb (EvJobXfer *job, + gpointer data); static void ev_window_sizing_mode_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *ev_window); @@ -491,7 +496,9 @@ ev_window_is_empty (const EvWindow *ev_window) { g_return_val_if_fail (EV_IS_WINDOW (ev_window), FALSE); - return ev_window->priv->document == NULL; + return (ev_window->priv->document == NULL) && + (ev_window->priv->load_job == NULL) && + (ev_window->priv->xfer_job == NULL); } static void @@ -603,7 +610,7 @@ ev_window_setup_document (EvWindow *ev_window) GtkAction *action; document = ev_window->priv->document; - ev_window->priv->page_cache = ev_document_get_page_cache (ev_window->priv->document); + ev_window->priv->page_cache = ev_page_cache_get (ev_window->priv->document); g_signal_connect (ev_window->priv->page_cache, "page-changed", G_CALLBACK (page_changed_cb), ev_window); g_signal_connect_object (G_OBJECT (document), @@ -659,11 +666,18 @@ password_dialog_response (GtkWidget *password_dialog, ev_window->priv->password_document = NULL; ev_window->priv->password_uri = NULL; + + ev_job_queue_add_job (ev_window->priv->load_job, EV_JOB_PRIORITY_HIGH); + + ev_statusbar_push (EV_STATUSBAR (ev_window->priv->statusbar), + EV_CONTEXT_PROGRESS, + _("Loading document. Please wait")); - if (start_loading_document (ev_window, document, uri)) { - gtk_widget_destroy (password_dialog); - } - + ev_statusbar_set_progress (EV_STATUSBAR (ev_window->priv->statusbar), + TRUE); + + gtk_widget_destroy (password_dialog); + g_object_unref (document); g_free (uri); @@ -674,7 +688,7 @@ password_dialog_response (GtkWidget *password_dialog, gtk_widget_destroy (password_dialog); } -/* Called either by start_loading_document or by the "unlock" callback on the +/* Called either by ev_window_load_job_cb or by the "unlock" callback on the * password_view page. It assumes that ev_window->priv->password_* has been set * correctly. These are cleared by password_dialog_response() */ @@ -708,8 +722,32 @@ ev_window_popup_password_dialog (EvWindow *ev_window) } } -/* This wil try to load the document. It might be called multiple times on the - * same document by the password dialog. + +static void +ev_window_clear_jobs (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); + + 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); + ev_window->priv->load_job = NULL; + } + + if (ev_window->priv->xfer_job != NULL) { + + if (!ev_window->priv->xfer_job->finished) + ev_job_queue_remove_job (ev_window->priv->xfer_job); + + g_signal_handlers_disconnect_by_func (ev_window->priv->xfer_job, ev_window_xfer_job_cb, ev_window); + g_object_unref (ev_window->priv->xfer_job); + ev_window->priv->xfer_job = NULL; + } +} + +/* This callback will executed when load job will be finished. * * Since the flow of the error dialog is very confusing, we assume that both * document and uri will go away after this function is called, and thus we need @@ -717,17 +755,23 @@ ev_window_popup_password_dialog (EvWindow *ev_window) * ev_window->priv->password_{uri,document}, and thus people who call this * function should _not_ necessarily expect those to exist after being * called. */ -static gboolean -start_loading_document (EvWindow *ev_window, - EvDocument *document, - const char *uri) +static void +ev_window_load_job_cb (EvJobLoad *job, + gpointer data) { - gboolean result; - GError *error = NULL; + EvWindow *ev_window = EV_WINDOW (data); + EvDocument *document = EV_JOB (job)->document; g_assert (document); g_assert (document != ev_window->priv->document); - g_assert (uri); + g_assert (job->uri); + + ev_statusbar_pop (EV_STATUSBAR (ev_window->priv->statusbar), + EV_CONTEXT_PROGRESS); + + ev_statusbar_set_progress (EV_STATUSBAR (ev_window->priv->statusbar), + FALSE); + if (ev_window->priv->password_document) { g_object_unref (ev_window->priv->password_document); ev_window->priv->password_document = NULL; @@ -737,31 +781,27 @@ start_loading_document (EvWindow *ev_window, ev_window->priv->password_uri = NULL; } - result = ev_document_load (document, uri, &error); - /* Success! */ - if (result) { + if (job->error == NULL) { if (ev_window->priv->document) g_object_unref (ev_window->priv->document); ev_window->priv->document = g_object_ref (document); ev_window_setup_document (ev_window); - ev_window_add_recent (ev_window, uri); - - return TRUE; + ev_window_add_recent (ev_window, job->uri); + ev_window_clear_jobs (ev_window); + + return; } - /* unable to load the document */ - g_assert (error != NULL); - - if (error->domain == EV_DOCUMENT_ERROR && - error->code == EV_DOCUMENT_ERROR_ENCRYPTED) { + if (job->error->domain == EV_DOCUMENT_ERROR && + job->error->code == EV_DOCUMENT_ERROR_ENCRYPTED) { gchar *base_name, *file_name; ev_window->priv->password_document = g_object_ref (document); - ev_window->priv->password_uri = g_strdup (uri); + ev_window->priv->password_uri = g_strdup (job->uri); - base_name = g_path_get_basename (uri); + base_name = g_path_get_basename (job->uri); file_name = gnome_vfs_unescape_string_for_display (base_name); ev_password_view_set_file_name (EV_PASSWORD_VIEW (ev_window->priv->password_view), @@ -772,103 +812,102 @@ start_loading_document (EvWindow *ev_window, ev_window_popup_password_dialog (ev_window); } else { - unable_to_load (ev_window, error->message); - } - g_error_free (error); + unable_to_load (ev_window, job->error->message); + } - return FALSE; + return; } -static gboolean -sanity_check_uri (EvWindow *window, const char *uri) +static void +ev_window_xfer_job_cb (EvJobXfer *job, + gpointer data) { - gboolean result = FALSE; - GnomeVFSURI *vfs_uri; - char *err; + EvWindow *ev_window = EV_WINDOW (data); - vfs_uri = gnome_vfs_uri_new (uri); - if (vfs_uri) { - if (gnome_vfs_uri_exists (vfs_uri)) { - result = TRUE; - } - } + ev_statusbar_pop (EV_STATUSBAR (ev_window->priv->statusbar), + EV_CONTEXT_PROGRESS); - if (!result) { - err = g_strdup_printf (_("The file %s does not exist."), uri); - unable_to_load (window, err); - g_free (err); - } + ev_statusbar_set_progress (EV_STATUSBAR (ev_window->priv->statusbar), + FALSE); + + if (job->error != NULL) { + unable_to_load (ev_window, job->error->message); + ev_window_clear_jobs (ev_window); + } else { + EvDocument *document = g_object_ref (EV_JOB (job)->document); + + ev_window_clear_jobs (ev_window); + + ev_window->priv->load_job = ev_job_load_new (document, ev_window->priv->uri); + g_signal_connect (ev_window->priv->load_job, + "finished", + G_CALLBACK (ev_window_load_job_cb), + ev_window); + ev_job_queue_add_job (ev_window->priv->load_job, EV_JOB_PRIORITY_HIGH); + + ev_statusbar_push (EV_STATUSBAR (ev_window->priv->statusbar), + EV_CONTEXT_PROGRESS, + _("Loading document. Please wait")); + ev_statusbar_set_progress (EV_STATUSBAR (ev_window->priv->statusbar), + TRUE); - return result; + } } void -ev_window_open (EvWindow *ev_window, const char *uri) +ev_window_open_uri (EvWindow *ev_window, const char *uri) { - EvDocument *document = NULL; - GType document_type; - char *mime_type = NULL; - - if (!sanity_check_uri (ev_window, uri)) { - return; - } + if (ev_window->priv->password_dialog) + gtk_widget_destroy (ev_window->priv->password_dialog); g_free (ev_window->priv->uri); ev_window->priv->uri = g_strdup (uri); + + ev_window_clear_jobs (ev_window); + + ev_window->priv->xfer_job = ev_job_xfer_new (uri); + g_signal_connect (ev_window->priv->xfer_job, + "finished", + G_CALLBACK (ev_window_xfer_job_cb), + ev_window); + ev_job_queue_add_job (ev_window->priv->xfer_job, EV_JOB_PRIORITY_HIGH); - document_type = ev_document_type_lookup (uri, &mime_type); - if (document_type != G_TYPE_INVALID) { - document = g_object_new (document_type, NULL); - } - - if (document) { - start_loading_document (ev_window, document, uri); - /* See the comment on start_loading_document on ref counting. - * As the password dialog flow is confusing, we're very explicit - * on ref counting. */ - g_object_unref (document); - } else { - char *error_message; - - error_message = g_strdup_printf (_("Unhandled MIME type: '%s'"), - mime_type?mime_type:"<Unknown MIME Type>"); - unable_to_load (ev_window, error_message); - g_free (error_message); - } - - g_free (mime_type); + ev_statusbar_push (EV_STATUSBAR (ev_window->priv->statusbar), + EV_CONTEXT_PROGRESS, + _("Loading document. Please wait")); + ev_statusbar_set_progress (EV_STATUSBAR (ev_window->priv->statusbar), + TRUE); } -static void -ev_window_open_uri_list (EvWindow *ev_window, GList *uri_list) +void +ev_window_open_uri_list (EvWindow *ev_window, GSList *uri_list) { - GList *list; - gchar *uri; + GSList *list; + gchar *uri; g_return_if_fail (uri_list != NULL); list = uri_list; while (list) { - uri = gnome_vfs_uri_to_string (list->data, GNOME_VFS_URI_HIDE_NONE); + + uri = (gchar *)list->data; - if (ev_document_type_lookup (uri, NULL) != G_TYPE_INVALID) { if (ev_window_is_empty (EV_WINDOW (ev_window))) { - ev_window_open (ev_window, uri); - + ev_window_open_uri (ev_window, uri); + gtk_widget_show (GTK_WIDGET (ev_window)); } else { EvWindow *new_window; - + new_window = ev_application_new_window (EV_APP); - ev_window_open (new_window, uri); - + ev_window_open_uri (new_window, uri); + gtk_widget_show (GTK_WIDGET (new_window)); } - } g_free (uri); - list = g_list_next (list); + list = g_slist_next (list); } } @@ -889,7 +928,7 @@ ev_window_cmd_recent_file_activate (EggRecentViewGtk *view, EggRecentItem *item, window = GTK_WIDGET (ev_application_get_empty_window (EV_APP)); gtk_widget_show (window); - ev_window_open (EV_WINDOW (window), uri); + ev_window_open_uri (EV_WINDOW (window), uri); g_free (uri); } @@ -1092,7 +1131,7 @@ ev_window_print (EvWindow *window) EvPageCache *page_cache; int last_page; - page_cache = ev_document_get_page_cache (window->priv->document); + page_cache = ev_page_cache_get (window->priv->document); last_page = ev_page_cache_get_n_pages (page_cache); ev_window_print_range (window, 1, -1); @@ -1111,7 +1150,7 @@ ev_window_print_range (EvWindow *ev_window, int first_page, int last_page) g_return_if_fail (EV_IS_WINDOW (ev_window)); g_return_if_fail (ev_window->priv->document != NULL); - page_cache = ev_document_get_page_cache (ev_window->priv->document); + page_cache = ev_page_cache_get (ev_window->priv->document); if (last_page == -1) { last_page = ev_page_cache_get_n_pages (page_cache); } @@ -1641,12 +1680,12 @@ ev_window_state_event (GtkWidget *widget, GdkEventWindowState *event) EvWindow *window = EV_WINDOW (widget); if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) { - gboolean show; + gboolean maximized; - show = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) == 0; + maximized = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) == 0; - gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (window->priv->statusbar), - show); + ev_statusbar_set_maximized (EV_STATUSBAR (window->priv->statusbar), + maximized); } return FALSE; @@ -1828,7 +1867,7 @@ ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window) page = ev_page_cache_get_current_page (ev_window->priv->page_cache); uri = g_strdup (ev_window->priv->uri); - ev_window_open (ev_window, uri); + ev_window_open_uri (ev_window, uri); /* In case the number of pages in the document has changed. */ page = CLAMP (page, 0, ev_page_cache_get_n_pages (ev_window->priv->page_cache)); @@ -2130,8 +2169,8 @@ menu_item_select_cb (GtkMenuItem *proxy, EvWindow *ev_window) g_object_get (G_OBJECT (action), "tooltip", &message, NULL); if (message) { - gtk_statusbar_push (GTK_STATUSBAR (ev_window->priv->statusbar), - ev_window->priv->help_message_cid, message); + ev_statusbar_push (EV_STATUSBAR (ev_window->priv->statusbar), + EV_CONTEXT_VIEW, message); g_free (message); } } @@ -2139,8 +2178,8 @@ menu_item_select_cb (GtkMenuItem *proxy, EvWindow *ev_window) static void menu_item_deselect_cb (GtkMenuItem *proxy, EvWindow *ev_window) { - gtk_statusbar_pop (GTK_STATUSBAR (ev_window->priv->statusbar), - ev_window->priv->help_message_cid); + ev_statusbar_pop (EV_STATUSBAR (ev_window->priv->statusbar), + EV_CONTEXT_VIEW); } static void @@ -2175,13 +2214,13 @@ view_status_changed_cb (EvView *view, { const char *message; - gtk_statusbar_pop (GTK_STATUSBAR (ev_window->priv->statusbar), - ev_window->priv->view_message_cid); + ev_statusbar_pop (EV_STATUSBAR (ev_window->priv->statusbar), + EV_CONTEXT_HELP); message = ev_view_get_status (view); if (message) { - gtk_statusbar_push (GTK_STATUSBAR (ev_window->priv->statusbar), - ev_window->priv->view_message_cid, message); + ev_statusbar_push (EV_STATUSBAR (ev_window->priv->statusbar), + EV_CONTEXT_HELP, message); } } @@ -2328,6 +2367,10 @@ ev_window_dispose (GObject *object) priv->page_view = NULL; } + if (priv->load_job || priv->xfer_job) { + ev_window_clear_jobs (window); + } + if (priv->password_document) { g_object_unref (priv->password_document); priv->password_document = NULL; @@ -2338,6 +2381,10 @@ ev_window_dispose (GObject *object) priv->password_uri = NULL; } + if (priv->password_dialog) { + gtk_widget_destroy (priv->password_dialog); + } + if (priv->find_bar) { g_signal_handlers_disconnect_by_func (window->priv->find_bar, @@ -2523,14 +2570,25 @@ drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, gpointer gdata) { - GList *uri_list = NULL; + GList *uri_list = NULL; + GSList *uris = NULL; + gchar *uri; uri_list = gnome_vfs_uri_list_parse ((gchar *) selection_data->data); if (uri_list) { - ev_window_open_uri_list (EV_WINDOW (widget), uri_list); - + while (uri_list) { + uri = gnome_vfs_uri_to_string (uri_list->data, GNOME_VFS_URI_HIDE_NONE); + uris = g_slist_append (uris, (gpointer) uri); + + uri_list = g_list_next (uri_list); + } + gnome_vfs_uri_list_free (uri_list); + + ev_window_open_uri_list (EV_WINDOW (widget), uris); + + g_slist_free (uris); gtk_drag_finish (context, TRUE, FALSE, time); } @@ -2942,15 +3000,11 @@ ev_window_init (EvWindow *ev_window) G_CALLBACK (ev_window_zoom_changed_cb), ev_window); - ev_window->priv->statusbar = gtk_statusbar_new (); + ev_window->priv->statusbar = ev_statusbar_new (); gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box), ev_window->priv->statusbar, FALSE, TRUE, 0); - ev_window->priv->help_message_cid = gtk_statusbar_get_context_id - (GTK_STATUSBAR (ev_window->priv->statusbar), "help_message"); - ev_window->priv->view_message_cid = gtk_statusbar_get_context_id - (GTK_STATUSBAR (ev_window->priv->statusbar), "view_message"); - + ev_window->priv->find_bar = egg_find_bar_new (); gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box), ev_window->priv->find_bar, @@ -3009,3 +3063,4 @@ ev_window_init (EvWindow *ev_window) ev_window_sizing_mode_changed_cb (EV_VIEW (ev_window->priv->view), NULL, ev_window); update_action_sensitivity (ev_window); } + diff --git a/shell/ev-window.h b/shell/ev-window.h index 5523fdd..6864b71 100644 --- a/shell/ev-window.h +++ b/shell/ev-window.h @@ -27,6 +27,7 @@ #include <gtk/gtkwindow.h> #include "ev-link.h" +#include "ev-page-cache.h" G_BEGIN_DECLS @@ -51,15 +52,16 @@ struct _EvWindowClass { }; GType ev_window_get_type (void); -void ev_window_open (EvWindow *ev_window, +void ev_window_open_uri (EvWindow *ev_window, const char *uri); +void ev_window_open_uri_list (EvWindow *ev_window, + GSList *uris); void ev_window_open_page_label (EvWindow *ev_window, const char *label); gboolean ev_window_is_empty (const EvWindow *ev_window); void ev_window_print_range (EvWindow *ev_window, int first_page, int last_page); - G_END_DECLS #endif /* !EV_WINDOW_H */ diff --git a/shell/main.c b/shell/main.c index 827c696..b0cc803 100644 --- a/shell/main.c +++ b/shell/main.c @@ -61,7 +61,7 @@ load_files (const char **files) window = GTK_WIDGET (ev_application_new_window (EV_APP)); gtk_widget_show (window); - ev_window_open (EV_WINDOW (window), uri); + ev_window_open_uri (EV_WINDOW (window), uri); if (page_label != NULL) ev_window_open_page_label (EV_WINDOW (window), page_label); |