summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Nicholson <dbn.lists@gmail.com>2011-02-15 07:10:14 -0800
committerDan Nicholson <dbn.lists@gmail.com>2011-02-15 07:22:00 -0800
commit6d01f3e55a4b41910fa0becb3a826e184fec9114 (patch)
tree0727772904e0a2c862eb8bcef1ea44646c4c54c0
Initial commit of previewer code for plugin
This is a dump of the evince-previewer code from the gnome-2-30 branch of evince (commit 38693288). This code will be converted into a widget in a convenience library to be used from the mozilla plugin. The source for evince's libmisc have also been copied with the previewer code.
-rw-r--r--data/evince-previewer-ui.xml34
-rw-r--r--previewer/ev-page-action-widget.c495
-rw-r--r--previewer/ev-page-action-widget.h46
-rw-r--r--previewer/ev-page-action.c239
-rw-r--r--previewer/ev-page-action.h68
-rw-r--r--previewer/ev-previewer-window.c723
-rw-r--r--previewer/ev-previewer-window.h51
-rw-r--r--previewer/ev-previewer.c208
8 files changed, 1864 insertions, 0 deletions
diff --git a/data/evince-previewer-ui.xml b/data/evince-previewer-ui.xml
new file mode 100644
index 0000000..896b472
--- /dev/null
+++ b/data/evince-previewer-ui.xml
@@ -0,0 +1,34 @@
+<ui>
+ <toolbar name="PreviewToolbar">
+ <toolitem name="GoPreviousPage" action="GoPreviousPage"/>
+ <toolitem name="GoNextPage" action="GoNextPage"/>
+ <separator/>
+ <toolitem name="PageSelector" action="PageSelector"/>
+ <separator/>
+ <toolitem name="ViewPageWidth" action="ViewPageWidth"/>
+ <toolitem name="ViewBestFit" action="ViewBestFit"/>
+ <toolitem name="ViewZoomIn" action="ViewZoomIn"/>
+ <toolitem name="ViewZoomOut" action="ViewZoomOut"/>
+ <separator/>
+ <toolitem name="PreviewPrint" action="PreviewPrint"/>
+ </toolbar>
+
+ <accelerator name="FileCloseWindowAccel" action="FileCloseWindow"/>
+ <accelerator name="SpaceAccel" action="Space"/>
+ <accelerator name="ReturnAccel" action="Return"/>
+ <accelerator name="BackSpaceAccel" action="BackSpace"/>
+ <accelerator name="ShiftSpaceAccel" action="ShiftSpace"/>
+ <accelerator name="ShiftBackSpaceAccel" action="ShiftBackSpace"/>
+ <accelerator name="pAccel" action="p"/>
+ <accelerator name="nAccel" action="n"/>
+ <accelerator name="ShiftReturnAccel" action="ShiftReturn"/>
+ <accelerator name="FocusPageSelectorAccel" action="FocusPageSelector"/>
+ <accelerator name="PlusAccel" action="Plus"/>
+ <accelerator name="MinusAccel" action="Minus"/>
+ <accelerator name="Equal" action="Equal"/>
+ <accelerator name="CtrlEqualAccel" action="CtrlEqual"/>
+ <accelerator name="KpPlusAccel" action="KpPlus"/>
+ <accelerator name="KpMinusAccel" action="KpMinus"/>
+ <accelerator name="CtrlKpPlusAccel" action="CtrlKpPlus"/>
+ <accelerator name="CtrlKpMinusAccel" action="CtrlKpMinus"/>
+</ui>
diff --git a/previewer/ev-page-action-widget.c b/previewer/ev-page-action-widget.c
new file mode 100644
index 0000000..bb8ef2e
--- /dev/null
+++ b/previewer/ev-page-action-widget.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2003, 2004 Marco Pesenti Gritti
+ * Copyright (C) 2003, 2004 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <evince-document.h>
+#include "ev-page-action.h"
+#include "ev-page-action-widget.h"
+
+/* Widget we pass back */
+static void ev_page_action_widget_init (EvPageActionWidget *action_widget);
+static void ev_page_action_widget_class_init (EvPageActionWidgetClass *action_widget);
+
+enum
+{
+ WIDGET_ACTIVATE_LINK,
+ WIDGET_N_SIGNALS
+};
+
+struct _EvPageActionWidget
+{
+ GtkToolItem parent;
+
+ EvDocument *document;
+ EvDocumentModel *doc_model;
+
+ GtkWidget *entry;
+ GtkWidget *label;
+ guint signal_id;
+ GtkTreeModel *filter_model;
+ GtkTreeModel *model;
+};
+
+static guint widget_signals[WIDGET_N_SIGNALS] = {0, };
+
+G_DEFINE_TYPE (EvPageActionWidget, ev_page_action_widget, GTK_TYPE_TOOL_ITEM)
+
+static void
+update_pages_label (EvPageActionWidget *action_widget,
+ gint page)
+{
+ char *label_text;
+ gint n_pages;
+
+ n_pages = ev_document_get_n_pages (action_widget->document);
+ if (ev_document_has_text_page_labels (action_widget->document)) {
+ label_text = g_strdup_printf (_("(%d of %d)"), page + 1, n_pages);
+ } else {
+ label_text = g_strdup_printf (_("of %d"), n_pages);
+ }
+ gtk_label_set_text (GTK_LABEL (action_widget->label), label_text);
+ g_free (label_text);
+}
+
+static void
+ev_page_action_widget_set_current_page (EvPageActionWidget *action_widget,
+ gint page)
+{
+ if (page >= 0) {
+ gchar *page_label;
+
+ gtk_entry_set_width_chars (GTK_ENTRY (action_widget->entry),
+ CLAMP (ev_document_get_max_label_len (action_widget->document),
+ 6, 12));
+
+ page_label = ev_document_get_page_label (action_widget->document, page);
+ gtk_entry_set_text (GTK_ENTRY (action_widget->entry), page_label);
+ gtk_editable_set_position (GTK_EDITABLE (action_widget->entry), -1);
+ g_free (page_label);
+
+ } else {
+ gtk_entry_set_text (GTK_ENTRY (action_widget->entry), "");
+ }
+
+ update_pages_label (action_widget, page);
+}
+
+static void
+page_changed_cb (EvDocumentModel *model,
+ gint old_page,
+ gint new_page,
+ EvPageActionWidget *action_widget)
+{
+ ev_page_action_widget_set_current_page (action_widget, new_page);
+}
+
+static gboolean
+page_scroll_cb (EvPageActionWidget *action_widget, GdkEventScroll *event)
+{
+ EvDocumentModel *model = action_widget->doc_model;
+ gint pageno;
+
+ pageno = ev_document_model_get_page (model);
+ if ((event->direction == GDK_SCROLL_DOWN) &&
+ (pageno < ev_document_get_n_pages (action_widget->document) - 1))
+ pageno++;
+ if ((event->direction == GDK_SCROLL_UP) && (pageno > 0))
+ pageno--;
+ ev_document_model_set_page (model, pageno);
+
+ return TRUE;
+}
+
+static void
+activate_cb (EvPageActionWidget *action_widget)
+{
+ EvDocumentModel *model;
+ const char *text;
+ EvLinkDest *link_dest;
+ EvLinkAction *link_action;
+ EvLink *link;
+ gchar *link_text;
+ gint current_page;
+
+ model = action_widget->doc_model;
+ current_page = ev_document_model_get_page (model);
+
+ text = gtk_entry_get_text (GTK_ENTRY (action_widget->entry));
+
+ link_dest = ev_link_dest_new_page_label (text);
+ link_action = ev_link_action_new_dest (link_dest);
+ link_text = g_strdup_printf ("Page: %s", text);
+ link = ev_link_new (link_text, link_action);
+
+ g_signal_emit (action_widget, widget_signals[WIDGET_ACTIVATE_LINK], 0, link);
+
+ g_object_unref (link);
+ g_free (link_text);
+
+ if (current_page == ev_document_model_get_page (model))
+ ev_page_action_widget_set_current_page (action_widget, current_page);
+}
+
+static void
+ev_page_action_widget_init (EvPageActionWidget *action_widget)
+{
+ GtkWidget *hbox;
+ AtkObject *obj;
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_set_spacing (GTK_BOX (hbox), 6);
+
+ action_widget->entry = gtk_entry_new ();
+ gtk_widget_add_events (action_widget->entry,
+ GDK_BUTTON_MOTION_MASK);
+ gtk_entry_set_width_chars (GTK_ENTRY (action_widget->entry), 5);
+ gtk_entry_set_text (GTK_ENTRY (action_widget->entry), "");
+ g_signal_connect_swapped (action_widget->entry, "scroll-event",
+ G_CALLBACK (page_scroll_cb),
+ action_widget);
+ g_signal_connect_swapped (action_widget->entry, "activate",
+ G_CALLBACK (activate_cb),
+ action_widget);
+
+ obj = gtk_widget_get_accessible (action_widget->entry);
+ atk_object_set_name (obj, "page-label-entry");
+
+ gtk_box_pack_start (GTK_BOX (hbox), action_widget->entry,
+ FALSE, FALSE, 0);
+ gtk_widget_show (action_widget->entry);
+
+ action_widget->label = gtk_label_new (NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), action_widget->label,
+ FALSE, FALSE, 0);
+ gtk_widget_show (action_widget->label);
+
+ gtk_container_set_border_width (GTK_CONTAINER (action_widget), 6);
+ gtk_container_add (GTK_CONTAINER (action_widget), hbox);
+ gtk_widget_show (hbox);
+
+ gtk_widget_show (GTK_WIDGET (action_widget));
+}
+
+static void
+ev_page_action_widget_document_changed_cb (EvDocumentModel *model,
+ GParamSpec *pspec,
+ EvPageActionWidget *action_widget)
+{
+ EvDocument *document = ev_document_model_get_document (model);
+
+ g_object_ref (document);
+ if (action_widget->document)
+ g_object_unref (action_widget->document);
+ action_widget->document = document;
+
+ if (action_widget->signal_id > 0) {
+ g_signal_handler_disconnect (action_widget->doc_model,
+ action_widget->signal_id);
+ action_widget->signal_id = 0;
+ }
+ action_widget->signal_id =
+ g_signal_connect_object (action_widget->doc_model,
+ "page-changed",
+ G_CALLBACK (page_changed_cb),
+ action_widget, 0);
+
+ ev_page_action_widget_set_current_page (action_widget,
+ ev_document_model_get_page (model));
+}
+
+void
+ev_page_action_widget_set_model (EvPageActionWidget *action_widget,
+ EvDocumentModel *model)
+{
+ if (action_widget->doc_model) {
+ g_object_remove_weak_pointer (G_OBJECT (action_widget->doc_model),
+ (gpointer)&action_widget->doc_model);
+ }
+ action_widget->doc_model = model;
+ g_object_add_weak_pointer (G_OBJECT (model),
+ (gpointer)&action_widget->doc_model);
+
+ g_signal_connect (model, "notify::document",
+ G_CALLBACK (ev_page_action_widget_document_changed_cb),
+ action_widget);
+}
+
+static void
+ev_page_action_widget_finalize (GObject *object)
+{
+ EvPageActionWidget *action_widget = EV_PAGE_ACTION_WIDGET (object);
+
+ if (action_widget->doc_model != NULL) {
+ if (action_widget->signal_id > 0) {
+ g_signal_handler_disconnect (action_widget->doc_model,
+ action_widget->signal_id);
+ action_widget->signal_id = 0;
+ }
+ g_object_remove_weak_pointer (G_OBJECT (action_widget->doc_model),
+ (gpointer)&action_widget->doc_model);
+ action_widget->doc_model = NULL;
+ }
+
+ if (action_widget->document) {
+ g_object_unref (action_widget->document);
+ action_widget->document = NULL;
+ }
+
+ G_OBJECT_CLASS (ev_page_action_widget_parent_class)->finalize (object);
+}
+
+static void
+ev_page_action_widget_class_init (EvPageActionWidgetClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = ev_page_action_widget_finalize;
+
+ widget_signals[WIDGET_ACTIVATE_LINK] =
+ g_signal_new ("activate_link",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EvPageActionClass, activate_link),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+
+}
+
+static gboolean
+match_selected_cb (GtkEntryCompletion *completion,
+ GtkTreeModel *filter_model,
+ GtkTreeIter *filter_iter,
+ EvPageActionWidget *proxy)
+{
+ EvLink *link;
+ GtkTreeIter *iter;
+
+ gtk_tree_model_get (filter_model, filter_iter,
+ 0, &iter,
+ -1);
+ gtk_tree_model_get (proxy->model, iter,
+ EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+ -1);
+
+ g_signal_emit (proxy, widget_signals[WIDGET_ACTIVATE_LINK], 0, link);
+
+ if (link)
+ g_object_unref (link);
+
+ gtk_tree_iter_free (iter);
+
+ return TRUE;
+}
+
+
+static void
+display_completion_text (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *filter_model,
+ GtkTreeIter *filter_iter,
+ EvPageActionWidget *proxy)
+{
+ EvLink *link;
+ GtkTreeIter *iter;
+
+ gtk_tree_model_get (filter_model, filter_iter,
+ 0, &iter,
+ -1);
+ gtk_tree_model_get (proxy->model, iter,
+ EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+ -1);
+
+ g_object_set (renderer, "text", ev_link_get_title (link), NULL);
+
+ if (link)
+ g_object_unref (link);
+
+ gtk_tree_iter_free (iter);
+}
+
+static gboolean
+match_completion (GtkEntryCompletion *completion,
+ const gchar *key,
+ GtkTreeIter *filter_iter,
+ EvPageActionWidget *proxy)
+{
+ EvLink *link;
+ GtkTreeIter *iter;
+ const gchar *text = NULL;
+
+ gtk_tree_model_get (gtk_entry_completion_get_model (completion),
+ filter_iter,
+ 0, &iter,
+ -1);
+ gtk_tree_model_get (proxy->model, iter,
+ EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+ -1);
+
+
+ if (link) {
+ text = ev_link_get_title (link);
+ g_object_unref (link);
+ }
+
+ gtk_tree_iter_free (iter);
+
+ if (text && key) {
+ gchar *normalized_text;
+ gchar *normalized_key;
+ gchar *case_normalized_text;
+ gchar *case_normalized_key;
+ gboolean retval = FALSE;
+
+ normalized_text = g_utf8_normalize (text, -1, G_NORMALIZE_ALL);
+ normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
+ case_normalized_text = g_utf8_casefold (normalized_text, -1);
+ case_normalized_key = g_utf8_casefold (normalized_key, -1);
+
+ if (strstr (case_normalized_text, case_normalized_key))
+ retval = TRUE;
+
+ g_free (normalized_text);
+ g_free (normalized_key);
+ g_free (case_normalized_text);
+ g_free (case_normalized_key);
+
+ return retval;
+ }
+
+ return FALSE;
+}
+
+/* user data to set on the widget. */
+#define EPA_FILTER_MODEL_DATA "epa-filter-model"
+
+static gboolean
+build_new_tree_cb (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GtkTreeModel *filter_model = GTK_TREE_MODEL (data);
+ EvLink *link;
+ EvLinkAction *action;
+ EvLinkActionType type;
+
+ gtk_tree_model_get (model, iter,
+ EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+ -1);
+
+ if (!link)
+ return FALSE;
+
+ action = ev_link_get_action (link);
+ if (!action) {
+ g_object_unref (link);
+ return FALSE;
+ }
+
+ type = ev_link_action_get_action_type (action);
+
+ if (type == EV_LINK_ACTION_TYPE_GOTO_DEST) {
+ GtkTreeIter filter_iter;
+
+ gtk_list_store_append (GTK_LIST_STORE (filter_model), &filter_iter);
+ gtk_list_store_set (GTK_LIST_STORE (filter_model), &filter_iter,
+ 0, iter,
+ -1);
+ }
+
+ g_object_unref (link);
+
+ return FALSE;
+}
+
+static GtkTreeModel *
+get_filter_model_from_model (GtkTreeModel *model)
+{
+ GtkTreeModel *filter_model;
+
+ filter_model =
+ (GtkTreeModel *) g_object_get_data (G_OBJECT (model), EPA_FILTER_MODEL_DATA);
+ if (filter_model == NULL) {
+ filter_model = (GtkTreeModel *) gtk_list_store_new (1, GTK_TYPE_TREE_ITER);
+
+ gtk_tree_model_foreach (model,
+ build_new_tree_cb,
+ filter_model);
+ g_object_set_data_full (G_OBJECT (model), EPA_FILTER_MODEL_DATA, filter_model, g_object_unref);
+ }
+
+ return filter_model;
+}
+
+
+void
+ev_page_action_widget_update_links_model (EvPageActionWidget *proxy, GtkTreeModel *model)
+{
+ GtkTreeModel *filter_model;
+ GtkEntryCompletion *completion;
+ GtkCellRenderer *renderer;
+
+ if (!model)
+ return;
+
+ /* Magik */
+ proxy->model = model;
+ filter_model = get_filter_model_from_model (model);
+
+ completion = gtk_entry_completion_new ();
+ g_object_set (G_OBJECT (completion),
+ "popup-set-width", FALSE,
+ "model", filter_model,
+ NULL);
+
+ g_signal_connect (completion, "match-selected", G_CALLBACK (match_selected_cb), proxy);
+ gtk_entry_completion_set_match_func (completion,
+ (GtkEntryCompletionMatchFunc) match_completion,
+ proxy, NULL);
+
+ /* Set up the layout */
+ renderer = (GtkCellRenderer *)
+ g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ "width_chars", 30,
+ NULL);
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion),
+ renderer,
+ (GtkCellLayoutDataFunc) display_completion_text,
+ proxy, NULL);
+ gtk_entry_set_completion (GTK_ENTRY (proxy->entry), completion);
+
+ g_object_unref (completion);
+}
+
+void
+ev_page_action_widget_grab_focus (EvPageActionWidget *proxy)
+{
+ gtk_widget_grab_focus (proxy->entry);
+}
+
diff --git a/previewer/ev-page-action-widget.h b/previewer/ev-page-action-widget.h
new file mode 100644
index 0000000..cf33b55
--- /dev/null
+++ b/previewer/ev-page-action-widget.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2003, 2004 Marco Pesenti Gritti
+ * Copyright (C) 2003, 2004 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <evince-view.h>
+
+#include <gtk/gtk.h>
+
+#define EV_TYPE_PAGE_ACTION_WIDGET (ev_page_action_widget_get_type ())
+#define EV_PAGE_ACTION_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_ACTION_WIDGET, EvPageActionWidget))
+
+typedef struct _EvPageActionWidget EvPageActionWidget;
+typedef struct _EvPageActionWidgetClass EvPageActionWidgetClass;
+
+struct _EvPageActionWidgetClass
+{
+ GtkToolItemClass parent_class;
+
+ void (* activate_link) (EvPageActionWidget *page_action,
+ EvLink *link);
+};
+
+GType ev_page_action_widget_get_type (void) G_GNUC_CONST;
+
+void ev_page_action_widget_update_links_model (EvPageActionWidget *proxy,
+ GtkTreeModel *model);
+
+void ev_page_action_widget_set_model (EvPageActionWidget *action_widget,
+ EvDocumentModel *doc_model);
+void ev_page_action_widget_grab_focus (EvPageActionWidget *proxy);
diff --git a/previewer/ev-page-action.c b/previewer/ev-page-action.c
new file mode 100644
index 0000000..ce01862
--- /dev/null
+++ b/previewer/ev-page-action.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2003, 2004 Marco Pesenti Gritti
+ * Copyright (C) 2003, 2004 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "ev-page-action.h"
+#include "ev-page-action-widget.h"
+
+struct _EvPageActionPrivate
+{
+ EvDocumentModel *doc_model;
+ GtkTreeModel *model;
+};
+
+
+static void ev_page_action_init (EvPageAction *action);
+static void ev_page_action_class_init (EvPageActionClass *class);
+
+enum
+{
+ ACTIVATE_LINK,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = {0, };
+
+G_DEFINE_TYPE (EvPageAction, ev_page_action, GTK_TYPE_ACTION)
+
+#define EV_PAGE_ACTION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_PAGE_ACTION, EvPageActionPrivate))
+
+enum {
+ PROP_0,
+ PROP_MODEL
+};
+
+static GtkWidget *
+create_tool_item (GtkAction *action)
+{
+ GtkWidget *proxy;
+
+ proxy = g_object_new (EV_TYPE_PAGE_ACTION_WIDGET, NULL);
+
+ return proxy;
+}
+
+static void
+update_model (EvPageAction *page, GParamSpec *pspec, EvPageActionWidget *proxy)
+{
+ ev_page_action_widget_update_links_model (proxy, page->priv->model);
+}
+
+static void
+activate_link_cb (EvPageActionWidget *proxy, EvLink *link, EvPageAction *action)
+{
+ g_signal_emit (action, signals[ACTIVATE_LINK], 0, link);
+}
+
+static void
+connect_proxy (GtkAction *action, GtkWidget *proxy)
+{
+ EvPageAction *page = EV_PAGE_ACTION (action);
+
+ if (GTK_IS_TOOL_ITEM (proxy)) {
+ ev_page_action_widget_set_model (EV_PAGE_ACTION_WIDGET (proxy),
+ page->priv->doc_model);
+ g_signal_connect (proxy, "activate_link",
+ G_CALLBACK (activate_link_cb),
+ action);
+ g_signal_connect_object (action, "notify::model",
+ G_CALLBACK (update_model),
+ proxy, 0);
+ }
+
+ GTK_ACTION_CLASS (ev_page_action_parent_class)->connect_proxy (action, proxy);
+}
+
+static void
+ev_page_action_dispose (GObject *object)
+{
+ EvPageAction *page = EV_PAGE_ACTION (object);
+
+ if (page->priv->model) {
+ g_object_unref (page->priv->model);
+ page->priv->model = NULL;
+ }
+
+ page->priv->doc_model = NULL;
+
+ G_OBJECT_CLASS (ev_page_action_parent_class)->dispose (object);
+}
+
+static void
+ev_page_action_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EvPageAction *page = EV_PAGE_ACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_MODEL:
+ ev_page_action_set_links_model (page, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ev_page_action_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EvPageAction *page = EV_PAGE_ACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_MODEL:
+ g_value_set_object (value, page->priv->model);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+void
+ev_page_action_set_model (EvPageAction *page,
+ EvDocumentModel *model)
+{
+ g_return_if_fail (EV_IS_PAGE_ACTION (page));
+ g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+ if (page->priv->doc_model == model)
+ return;
+
+ page->priv->doc_model = model;
+}
+
+void
+ev_page_action_set_links_model (EvPageAction *page,
+ GtkTreeModel *links_model)
+{
+ g_return_if_fail (EV_IS_PAGE_ACTION (page));
+ g_return_if_fail (GTK_IS_TREE_MODEL (links_model));
+
+ if (page->priv->model == links_model)
+ return;
+
+ if (page->priv->model)
+ g_object_unref (page->priv->model);
+ page->priv->model = g_object_ref (links_model);
+
+ g_object_notify (G_OBJECT (page), "model");
+}
+
+void
+ev_page_action_grab_focus (EvPageAction *page_action)
+{
+ GSList *proxies;
+
+ proxies = gtk_action_get_proxies (GTK_ACTION (page_action));
+ for (; proxies != NULL; proxies = proxies->next) {
+ EvPageActionWidget *proxy;
+
+ proxy = EV_PAGE_ACTION_WIDGET (proxies->data);
+
+ if (GTK_WIDGET_MAPPED (GTK_WIDGET (proxy)))
+ ev_page_action_widget_grab_focus (proxy);
+ }
+}
+
+static void
+ev_page_action_init (EvPageAction *page)
+{
+ page->priv = EV_PAGE_ACTION_GET_PRIVATE (page);
+}
+
+static void
+ev_page_action_class_init (EvPageActionClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkActionClass *action_class = GTK_ACTION_CLASS (class);
+
+ object_class->dispose = ev_page_action_dispose;
+ object_class->set_property = ev_page_action_set_property;
+ object_class->get_property = ev_page_action_get_property;
+
+ action_class->toolbar_item_type = GTK_TYPE_TOOL_ITEM;
+ action_class->create_tool_item = create_tool_item;
+ action_class->connect_proxy = connect_proxy;
+
+ signals[ACTIVATE_LINK] = g_signal_new ("activate_link",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EvPageActionClass, activate_link),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+
+ g_object_class_install_property (object_class,
+ PROP_MODEL,
+ g_param_spec_object ("model",
+ "Model",
+ "Current Links Model",
+ GTK_TYPE_TREE_MODEL,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (object_class, sizeof (EvPageActionPrivate));
+}
diff --git a/previewer/ev-page-action.h b/previewer/ev-page-action.h
new file mode 100644
index 0000000..b18db61
--- /dev/null
+++ b/previewer/ev-page-action.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2003, 2004 Marco Pesenti Gritti
+ * Copyright (C) 2003, 2004 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EV_PAGE_ACTION_H
+#define EV_PAGE_ACTION_H
+
+#include <gtk/gtk.h>
+
+#include <evince-document.h>
+#include <evince-view.h>
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_PAGE_ACTION (ev_page_action_get_type ())
+#define EV_PAGE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_ACTION, EvPageAction))
+#define EV_PAGE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_PAGE_ACTION, EvPageActionClass))
+#define EV_IS_PAGE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PAGE_ACTION))
+#define EV_IS_PAGE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EV_TYPE_PAGE_ACTION))
+#define EV_PAGE_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EV_TYPE_PAGE_ACTION, EvPageActionClass))
+
+typedef struct _EvPageAction EvPageAction;
+typedef struct _EvPageActionPrivate EvPageActionPrivate;
+typedef struct _EvPageActionClass EvPageActionClass;
+
+struct _EvPageAction
+{
+ GtkAction parent;
+
+ /*< private >*/
+ EvPageActionPrivate *priv;
+};
+
+struct _EvPageActionClass
+{
+ GtkActionClass parent_class;
+
+ void (* activate_link) (EvPageAction *page_action,
+ EvLink *link);
+};
+
+GType ev_page_action_get_type (void) G_GNUC_CONST;
+
+void ev_page_action_set_model (EvPageAction *page_action,
+ EvDocumentModel *model);
+void ev_page_action_set_links_model (EvPageAction *page_action,
+ GtkTreeModel *links_model);
+void ev_page_action_grab_focus (EvPageAction *page_action);
+
+G_END_DECLS
+
+#endif
diff --git a/previewer/ev-previewer-window.c b/previewer/ev-previewer-window.c
new file mode 100644
index 0000000..67c1708
--- /dev/null
+++ b/previewer/ev-previewer-window.c
@@ -0,0 +1,723 @@
+/* ev-previewer-window.c:
+ * this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#if GTKUNIXPRINT_ENABLED
+#include <gtk/gtkunixprint.h>
+#endif
+#include <glib/gi18n.h>
+#include <evince-view.h>
+#include "ev-page-action.h"
+
+#include "ev-previewer-window.h"
+
+struct _EvPreviewerWindow {
+ GtkWindow base_instance;
+
+ EvDocumentModel *model;
+ EvDocument *document;
+
+ GtkActionGroup *action_group;
+ GtkActionGroup *accels_group;
+ GtkUIManager *ui_manager;
+
+ GtkWidget *swindow;
+ EvView *view;
+ gdouble dpi;
+
+ /* Printing */
+ GtkPrintSettings *print_settings;
+ GtkPageSetup *print_page_setup;
+#if GTKUNIXPRINT_ENABLED
+ GtkPrinter *printer;
+#endif
+ gchar *print_job_title;
+ gchar *source_file;
+};
+
+struct _EvPreviewerWindowClass {
+ GtkWindowClass base_class;
+};
+
+enum {
+ PROP_0,
+ PROP_MODEL
+};
+
+#define MIN_SCALE 0.05409
+#define MAX_SCALE 4.0
+
+G_DEFINE_TYPE (EvPreviewerWindow, ev_previewer_window, GTK_TYPE_WINDOW)
+
+static gdouble
+get_screen_dpi (EvPreviewerWindow *window)
+{
+ GdkScreen *screen;
+
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+ return ev_document_misc_get_screen_dpi (screen);
+}
+
+#if GTKUNIXPRINT_ENABLED
+static void
+ev_previewer_window_error_dialog_run (EvPreviewerWindow *window,
+ GError *error)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "%s", _("Failed to print document"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", error->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+#endif
+
+static void
+ev_previewer_window_close (GtkAction *action,
+ EvPreviewerWindow *window)
+{
+ gtk_widget_destroy (GTK_WIDGET (window));
+}
+
+static void
+ev_previewer_window_previous_page (GtkAction *action,
+ EvPreviewerWindow *window)
+{
+ ev_view_previous_page (window->view);
+}
+
+static void
+ev_previewer_window_next_page (GtkAction *action,
+ EvPreviewerWindow *window)
+{
+ ev_view_next_page (window->view);
+}
+
+static void
+ev_previewer_window_zoom_in (GtkAction *action,
+ EvPreviewerWindow *window)
+{
+ ev_document_model_set_sizing_mode (window->model, EV_SIZING_FREE);
+ ev_view_zoom_in (window->view);
+}
+
+static void
+ev_previewer_window_zoom_out (GtkAction *action,
+ EvPreviewerWindow *window)
+{
+ ev_document_model_set_sizing_mode (window->model, EV_SIZING_FREE);
+ ev_view_zoom_out (window->view);
+}
+
+static void
+ev_previewer_window_zoom_best_fit (GtkToggleAction *action,
+ EvPreviewerWindow *window)
+{
+ ev_document_model_set_sizing_mode (window->model,
+ gtk_toggle_action_get_active (action) ?
+ EV_SIZING_BEST_FIT : EV_SIZING_FREE);
+}
+
+static void
+ev_previewer_window_zoom_page_width (GtkToggleAction *action,
+ EvPreviewerWindow *window)
+{
+ ev_document_model_set_sizing_mode (window->model,
+ gtk_toggle_action_get_active (action) ?
+ EV_SIZING_FIT_WIDTH : EV_SIZING_FREE);
+}
+
+static void
+ev_previewer_window_action_page_activated (GtkAction *action,
+ EvLink *link,
+ EvPreviewerWindow *window)
+{
+ ev_view_handle_link (window->view, link);
+ gtk_widget_grab_focus (GTK_WIDGET (window->view));
+}
+
+static void
+ev_previewer_window_focus_page_selector (GtkAction *action,
+ EvPreviewerWindow *window)
+{
+ GtkAction *page_action;
+
+ page_action = gtk_action_group_get_action (window->action_group,
+ "PageSelector");
+ ev_page_action_grab_focus (EV_PAGE_ACTION (page_action));
+}
+
+static void
+ev_previewer_window_scroll_forward (GtkAction *action,
+ EvPreviewerWindow *window)
+{
+ ev_view_scroll (window->view, GTK_SCROLL_PAGE_FORWARD, FALSE);
+}
+
+static void
+ev_previewer_window_scroll_backward (GtkAction *action,
+ EvPreviewerWindow *window)
+{
+ ev_view_scroll (window->view, GTK_SCROLL_PAGE_BACKWARD, FALSE);
+}
+
+#if GTKUNIXPRINT_ENABLED
+static void
+ev_previewer_window_print_finished (GtkPrintJob *print_job,
+ EvPreviewerWindow *window,
+ GError *error)
+{
+ if (error) {
+ ev_previewer_window_error_dialog_run (window, error);
+ }
+
+ g_object_unref (print_job);
+ gtk_widget_destroy (GTK_WIDGET (window));
+}
+
+static void
+ev_previewer_window_do_print (EvPreviewerWindow *window)
+{
+ GtkPrintJob *job;
+ GError *error = NULL;
+
+ job = gtk_print_job_new (window->print_job_title ?
+ window->print_job_title :
+ window->source_file,
+ window->printer,
+ window->print_settings,
+ window->print_page_setup);
+ if (gtk_print_job_set_source_file (job, window->source_file, &error)) {
+ gtk_print_job_send (job,
+ (GtkPrintJobCompleteFunc)ev_previewer_window_print_finished,
+ window, NULL);
+ } else {
+ ev_previewer_window_error_dialog_run (window, error);
+ g_error_free (error);
+ }
+
+ gtk_widget_hide (GTK_WIDGET (window));
+}
+
+static void
+ev_previewer_window_enumerate_finished (EvPreviewerWindow *window)
+{
+ if (window->printer) {
+ ev_previewer_window_do_print (window);
+ } else {
+ GError *error = NULL;
+
+ g_set_error (&error,
+ GTK_PRINT_ERROR,
+ GTK_PRINT_ERROR_GENERAL,
+ _("The selected printer '%s' could not be found"),
+ gtk_print_settings_get_printer (window->print_settings));
+
+ ev_previewer_window_error_dialog_run (window, error);
+ g_error_free (error);
+ }
+}
+
+static gboolean
+ev_previewer_window_enumerate_printers (GtkPrinter *printer,
+ EvPreviewerWindow *window)
+{
+ const gchar *printer_name;
+
+ printer_name = gtk_print_settings_get_printer (window->print_settings);
+ if ((printer_name
+ && strcmp (printer_name, gtk_printer_get_name (printer)) == 0) ||
+ (!printer_name && gtk_printer_is_default (printer))) {
+ if (window->printer)
+ g_object_unref (window->printer);
+ window->printer = g_object_ref (printer);
+
+ return TRUE; /* we're done */
+ }
+
+ return FALSE; /* continue the enumeration */
+}
+
+static void
+ev_previewer_window_print (GtkAction *action,
+ EvPreviewerWindow *window)
+{
+ if (!window->print_settings)
+ window->print_settings = gtk_print_settings_new ();
+ if (!window->print_page_setup)
+ window->print_page_setup = gtk_page_setup_new ();
+ gtk_enumerate_printers ((GtkPrinterFunc)ev_previewer_window_enumerate_printers,
+ window,
+ (GDestroyNotify)ev_previewer_window_enumerate_finished,
+ FALSE);
+}
+#endif
+
+static const GtkActionEntry action_entries[] = {
+ { "FileCloseWindow", GTK_STOCK_CLOSE, NULL, "<control>W",
+ NULL,
+ G_CALLBACK (ev_previewer_window_close) },
+ { "GoPreviousPage", GTK_STOCK_GO_UP, N_("_Previous Page"), "<control>Page_Up",
+ N_("Go to the previous page"),
+ G_CALLBACK (ev_previewer_window_previous_page) },
+ { "GoNextPage", GTK_STOCK_GO_DOWN, N_("_Next Page"), "<control>Page_Down",
+ N_("Go to the next page"),
+ G_CALLBACK (ev_previewer_window_next_page) },
+ { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus",
+ N_("Enlarge the document"),
+ G_CALLBACK (ev_previewer_window_zoom_in) },
+ { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus",
+ N_("Shrink the document"),
+ G_CALLBACK (ev_previewer_window_zoom_out) },
+#if GTKUNIXPRINT_ENABLED
+ { "PreviewPrint", GTK_STOCK_PRINT, N_("Print"), NULL,
+ N_("Print this document"),
+ G_CALLBACK (ev_previewer_window_print) }
+#endif
+};
+
+static const GtkActionEntry accel_entries[] = {
+ { "Space", NULL, "", "space", NULL,
+ G_CALLBACK (ev_previewer_window_scroll_forward) },
+ { "ShiftSpace", NULL, "", "<shift>space", NULL,
+ G_CALLBACK (ev_previewer_window_scroll_backward) },
+ { "BackSpace", NULL, "", "BackSpace", NULL,
+ G_CALLBACK (ev_previewer_window_scroll_backward) },
+ { "ShiftBackSpace", NULL, "", "<shift>BackSpace", NULL,
+ G_CALLBACK (ev_previewer_window_scroll_forward) },
+ { "Return", NULL, "", "Return", NULL,
+ G_CALLBACK (ev_previewer_window_scroll_forward) },
+ { "ShiftReturn", NULL, "", "<shift>Return", NULL,
+ G_CALLBACK (ev_previewer_window_scroll_backward) },
+ { "p", GTK_STOCK_GO_UP, "", "p", NULL,
+ G_CALLBACK (ev_previewer_window_previous_page) },
+ { "n", GTK_STOCK_GO_DOWN, "", "n", NULL,
+ G_CALLBACK (ev_previewer_window_next_page) },
+ { "Plus", GTK_STOCK_ZOOM_IN, NULL, "plus", NULL,
+ G_CALLBACK (ev_previewer_window_zoom_in) },
+ { "CtrlEqual", GTK_STOCK_ZOOM_IN, NULL, "<control>equal", NULL,
+ G_CALLBACK (ev_previewer_window_zoom_in) },
+ { "Equal", GTK_STOCK_ZOOM_IN, NULL, "equal", NULL,
+ G_CALLBACK (ev_previewer_window_zoom_in) },
+ { "Minus", GTK_STOCK_ZOOM_OUT, NULL, "minus", NULL,
+ G_CALLBACK (ev_previewer_window_zoom_out) },
+ { "KpPlus", GTK_STOCK_ZOOM_IN, NULL, "KP_Add", NULL,
+ G_CALLBACK (ev_previewer_window_zoom_in) },
+ { "KpMinus", GTK_STOCK_ZOOM_OUT, NULL, "KP_Subtract", NULL,
+ G_CALLBACK (ev_previewer_window_zoom_out) },
+ { "CtrlKpPlus", GTK_STOCK_ZOOM_IN, NULL, "<control>KP_Add", NULL,
+ G_CALLBACK (ev_previewer_window_zoom_in) },
+ { "CtrlKpMinus", GTK_STOCK_ZOOM_OUT, NULL, "<control>KP_Subtract", NULL,
+ G_CALLBACK (ev_previewer_window_zoom_out) },
+ { "FocusPageSelector", NULL, "", "<control>l", NULL,
+ G_CALLBACK (ev_previewer_window_focus_page_selector) }
+
+};
+
+static const GtkToggleActionEntry toggle_action_entries[] = {
+ { "ViewBestFit", EV_STOCK_ZOOM_PAGE, N_("_Best Fit"), NULL,
+ N_("Make the current document fill the window"),
+ G_CALLBACK (ev_previewer_window_zoom_best_fit) },
+ { "ViewPageWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit Page _Width"), NULL,
+ N_("Make the current document fill the window width"),
+ G_CALLBACK (ev_previewer_window_zoom_page_width) }
+};
+
+static gboolean
+view_focus_changed (GtkWidget *widget,
+ GdkEventFocus *event,
+ EvPreviewerWindow *window)
+{
+ if (window->accels_group)
+ gtk_action_group_set_sensitive (window->accels_group, event->in);
+
+ return FALSE;
+}
+
+static void
+view_sizing_mode_changed (EvDocumentModel *model,
+ GParamSpec *pspec,
+ EvPreviewerWindow *window)
+{
+ EvSizingMode sizing_mode = ev_document_model_get_sizing_mode (model);
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (window->action_group, "ViewBestFit");
+ g_signal_handlers_block_by_func (action,
+ G_CALLBACK (ev_previewer_window_zoom_best_fit),
+ window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+ sizing_mode == EV_SIZING_BEST_FIT);
+ g_signal_handlers_unblock_by_func (action,
+ G_CALLBACK (ev_previewer_window_zoom_best_fit),
+ window);
+
+ action = gtk_action_group_get_action (window->action_group, "ViewPageWidth");
+ g_signal_handlers_block_by_func (action,
+ G_CALLBACK (ev_previewer_window_zoom_page_width),
+ window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+ sizing_mode == EV_SIZING_FIT_WIDTH);
+ g_signal_handlers_unblock_by_func (action,
+ G_CALLBACK (ev_previewer_window_zoom_page_width),
+ window);
+}
+
+static void
+ev_previewer_window_set_document (EvPreviewerWindow *window,
+ GParamSpec *pspec,
+ EvDocumentModel *model)
+{
+ EvDocument *document = ev_document_model_get_document (model);
+
+ window->document = g_object_ref (document);
+
+ g_signal_connect (model, "notify::sizing-mode",
+ G_CALLBACK (view_sizing_mode_changed),
+ window);
+ ev_view_set_loading (window->view, FALSE);
+ gtk_action_group_set_sensitive (window->action_group, TRUE);
+ gtk_action_group_set_sensitive (window->accels_group, TRUE);
+}
+
+static void
+ev_previewer_window_connect_action_accelerators (EvPreviewerWindow *window)
+{
+ GList *actions;
+
+ gtk_ui_manager_ensure_update (window->ui_manager);
+
+ actions = gtk_action_group_list_actions (window->action_group);
+ g_list_foreach (actions, (GFunc)gtk_action_connect_accelerator, NULL);
+ g_list_free (actions);
+}
+
+static void
+ev_previewer_window_dispose (GObject *object)
+{
+ EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
+
+ if (window->model) {
+ g_object_unref (window->model);
+ window->model = NULL;
+ }
+
+ if (window->document) {
+ g_object_unref (window->document);
+ window->document = NULL;
+ }
+
+ if (window->action_group) {
+ g_object_unref (window->action_group);
+ window->action_group = NULL;
+ }
+
+ if (window->accels_group) {
+ g_object_unref (window->accels_group);
+ window->accels_group = NULL;
+ }
+
+ if (window->ui_manager) {
+ g_object_unref (window->ui_manager);
+ window->ui_manager = NULL;
+ }
+
+ if (window->print_settings) {
+ g_object_unref (window->print_settings);
+ window->print_settings = NULL;
+ }
+
+ if (window->print_page_setup) {
+ g_object_unref (window->print_page_setup);
+ window->print_page_setup = NULL;
+ }
+
+#if GTKUNIXPRINT_ENABLED
+ if (window->printer) {
+ g_object_unref (window->printer);
+ window->printer = NULL;
+ }
+#endif
+
+ if (window->print_job_title) {
+ g_free (window->print_job_title);
+ window->print_job_title = NULL;
+ }
+
+ if (window->source_file) {
+ g_free (window->source_file);
+ window->source_file = NULL;
+ }
+
+ G_OBJECT_CLASS (ev_previewer_window_parent_class)->dispose (object);
+}
+
+static gchar*
+data_dir (void)
+{
+ gchar *datadir;
+#ifdef G_OS_WIN32
+ gchar *dir;
+
+ dir = g_win32_get_package_installation_directory_of_module (NULL);
+ datadir = g_build_filename (dir, "share", "evince", NULL);
+ g_free (dir);
+#else
+ datadir = g_strdup (DATADIR);
+#endif
+
+ return datadir;
+}
+
+static void
+ev_previewer_window_init (EvPreviewerWindow *window)
+{
+ gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
+}
+
+static void
+ev_previewer_window_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
+
+ switch (prop_id) {
+ case PROP_MODEL:
+ window->model = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static GObject *
+ev_previewer_window_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ EvPreviewerWindow *window;
+ GtkWidget *vbox;
+ GtkWidget *toolbar;
+ GtkAction *action;
+ GError *error = NULL;
+ gchar *datadir, *ui_path;
+ gdouble dpi;
+
+ object = G_OBJECT_CLASS (ev_previewer_window_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_params);
+ window = EV_PREVIEWER_WINDOW (object);
+
+ dpi = get_screen_dpi (window);
+ ev_document_model_set_min_scale (window->model, MIN_SCALE * dpi / 72.0);
+ ev_document_model_set_max_scale (window->model, MAX_SCALE * dpi / 72.0);
+ ev_document_model_set_sizing_mode (window->model, EV_SIZING_FIT_WIDTH);
+ g_signal_connect_swapped (window->model, "notify::document",
+ G_CALLBACK (ev_previewer_window_set_document),
+ window);
+
+ window->action_group = gtk_action_group_new ("PreviewerActions");
+ gtk_action_group_set_translation_domain (window->action_group, NULL);
+ gtk_action_group_add_actions (window->action_group, action_entries,
+ G_N_ELEMENTS (action_entries),
+ window);
+ gtk_action_group_add_toggle_actions (window->action_group, toggle_action_entries,
+ G_N_ELEMENTS (toggle_action_entries),
+ window);
+ gtk_action_group_set_sensitive (window->action_group, FALSE);
+
+ action = g_object_new (EV_TYPE_PAGE_ACTION,
+ "name", "PageSelector",
+ "label", _("Page"),
+ "tooltip", _("Select Page"),
+ "icon_name", "text-x-generic",
+ "visible_overflown", FALSE,
+ NULL);
+ ev_page_action_set_model (EV_PAGE_ACTION (action), window->model);
+ g_signal_connect (action, "activate_link",
+ G_CALLBACK (ev_previewer_window_action_page_activated),
+ window);
+ gtk_action_group_add_action (window->action_group, action);
+ g_object_unref (action);
+
+ window->accels_group = gtk_action_group_new ("PreviewerAccelerators");
+ gtk_action_group_add_actions (window->accels_group, accel_entries,
+ G_N_ELEMENTS (accel_entries),
+ window);
+ gtk_action_group_set_sensitive (window->accels_group, FALSE);
+
+ window->ui_manager = gtk_ui_manager_new ();
+ gtk_ui_manager_insert_action_group (window->ui_manager,
+ window->action_group, 0);
+ gtk_ui_manager_insert_action_group (window->ui_manager,
+ window->accels_group, 1);
+ gtk_window_add_accel_group (GTK_WINDOW (window),
+ gtk_ui_manager_get_accel_group (window->ui_manager));
+ datadir = data_dir ();
+ ui_path = g_build_filename (datadir, "evince-previewer-ui.xml", NULL);
+ if (!gtk_ui_manager_add_ui_from_file (window->ui_manager, ui_path, &error)) {
+ g_warning ("Failed to load ui from evince-previewer-ui.xml: %s", error->message);
+ g_error_free (error);
+ }
+ g_free (ui_path);
+ g_free (datadir);
+
+ /* GTKUIManager connects actions accels only for menu items,
+ * but not for tool items. See bug #612972.
+ */
+ ev_previewer_window_connect_action_accelerators (window);
+
+ view_sizing_mode_changed (window->model, NULL, window);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+
+ toolbar = gtk_ui_manager_get_widget (window->ui_manager, "/PreviewToolbar");
+ gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
+ gtk_widget_show (toolbar);
+
+ window->swindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window->swindow),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ window->view = EV_VIEW (ev_view_new ());
+ g_signal_connect_object (window->view, "focus_in_event",
+ G_CALLBACK (view_focus_changed),
+ window, 0);
+ g_signal_connect_object (window->view, "focus_out_event",
+ G_CALLBACK (view_focus_changed),
+ window, 0);
+ ev_view_set_model (window->view, window->model);
+ ev_document_model_set_continuous (window->model, FALSE);
+ ev_view_set_loading (window->view, TRUE);
+
+ gtk_container_add (GTK_CONTAINER (window->swindow), GTK_WIDGET (window->view));
+ gtk_widget_show (GTK_WIDGET (window->view));
+
+ gtk_box_pack_start (GTK_BOX (vbox), window->swindow, TRUE, TRUE, 0);
+ gtk_widget_show (window->swindow);
+
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+ gtk_widget_show (vbox);
+
+ return object;
+}
+
+
+static void
+ev_previewer_window_class_init (EvPreviewerWindowClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->constructor = ev_previewer_window_constructor;
+ gobject_class->set_property = ev_previewer_window_set_property;
+ gobject_class->dispose = ev_previewer_window_dispose;
+
+ g_object_class_install_property (gobject_class,
+ PROP_MODEL,
+ g_param_spec_object ("model",
+ "Model",
+ "The document model",
+ EV_TYPE_DOCUMENT_MODEL,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+/* Public methods */
+GtkWidget *
+ev_previewer_window_new (EvDocumentModel *model)
+{
+ return GTK_WIDGET (g_object_new (EV_TYPE_PREVIEWER_WINDOW, "model", model, NULL));
+}
+
+void
+ev_previewer_window_set_print_settings (EvPreviewerWindow *window,
+ const gchar *print_settings)
+{
+ if (window->print_settings)
+ g_object_unref (window->print_settings);
+ if (window->print_page_setup)
+ g_object_unref (window->print_page_setup);
+ if (window->print_job_title)
+ g_free (window->print_job_title);
+
+ if (print_settings && g_file_test (print_settings, G_FILE_TEST_IS_REGULAR)) {
+ GKeyFile *key_file;
+ GError *error = NULL;
+
+ key_file = g_key_file_new ();
+ g_key_file_load_from_file (key_file,
+ print_settings,
+ G_KEY_FILE_KEEP_COMMENTS |
+ G_KEY_FILE_KEEP_TRANSLATIONS,
+ &error);
+ if (!error) {
+ GtkPrintSettings *psettings;
+ GtkPageSetup *psetup;
+ gchar *job_name;
+
+ psettings = gtk_print_settings_new_from_key_file (key_file,
+ "Print Settings",
+ NULL);
+ window->print_settings = psettings ? psettings : gtk_print_settings_new ();
+
+ psetup = gtk_page_setup_new_from_key_file (key_file,
+ "Page Setup",
+ NULL);
+ window->print_page_setup = psetup ? psetup : gtk_page_setup_new ();
+
+ job_name = g_key_file_get_string (key_file,
+ "Print Job", "title",
+ NULL);
+ if (job_name) {
+ window->print_job_title = job_name;
+ gtk_window_set_title (GTK_WINDOW (window), job_name);
+ }
+ } else {
+ window->print_settings = gtk_print_settings_new ();
+ window->print_page_setup = gtk_page_setup_new ();
+ g_error_free (error);
+ }
+
+ g_key_file_free (key_file);
+ } else {
+ window->print_settings = gtk_print_settings_new ();
+ window->print_page_setup = gtk_page_setup_new ();
+ }
+}
+
+void
+ev_previewer_window_set_source_file (EvPreviewerWindow *window,
+ const gchar *source_file)
+{
+ if (window->source_file)
+ g_free (window->source_file);
+ window->source_file = g_strdup (source_file);
+}
diff --git a/previewer/ev-previewer-window.h b/previewer/ev-previewer-window.h
new file mode 100644
index 0000000..698b13f
--- /dev/null
+++ b/previewer/ev-previewer-window.h
@@ -0,0 +1,51 @@
+/* ev-previewer-window.h:
+ * this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EV_PREVIEWER_WINDOW_H
+#define EV_PREVIEWER_WINDOW_H
+
+#include <gtk/gtk.h>
+
+#include <evince-document.h>
+#include <evince-view.h>
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_PREVIEWER_WINDOW (ev_previewer_window_get_type())
+#define EV_PREVIEWER_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_PREVIEWER_WINDOW, EvPreviewerWindow))
+#define EV_PREVIEWER_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_PREVIEWER_WINDOW, EvPreviewerWindowClass))
+#define EV_IS_PREVIEWER_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_PREVIEWER_WINDOW))
+#define EV_IS_PREVIEWER_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_PREVIEWER_WINDOW))
+#define EV_PREVIEWER_WINDOW_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_PREVIEWER_WINDOW, EvPreviewerWindowClass))
+
+typedef struct _EvPreviewerWindow EvPreviewerWindow;
+typedef struct _EvPreviewerWindowClass EvPreviewerWindowClass;
+
+GType ev_previewer_window_get_type (void) G_GNUC_CONST;
+GtkWidget *ev_previewer_window_new (EvDocumentModel *model);
+
+void ev_previewer_window_set_print_settings (EvPreviewerWindow *window,
+ const gchar *print_settings);
+void ev_previewer_window_set_source_file (EvPreviewerWindow *window,
+ const gchar *source_file);
+
+G_END_DECLS
+
+#endif /* EV_PREVIEWER_WINDOW_H */
diff --git a/previewer/ev-previewer.c b/previewer/ev-previewer.c
new file mode 100644
index 0000000..990a003
--- /dev/null
+++ b/previewer/ev-previewer.c
@@ -0,0 +1,208 @@
+/* ev-previewer.c:
+ * this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <evince-document.h>
+#include <evince-view.h>
+
+#include "ev-previewer-window.h"
+
+#ifdef G_OS_WIN32
+#ifdef DATADIR
+#undef DATADIR
+#endif
+#include <io.h>
+#include <conio.h>
+#if !(_WIN32_WINNT >= 0x0500)
+#error "_WIN32_WINNT must be defined >= 0x0500"
+#endif
+#include <windows.h>
+#endif
+
+static gboolean unlink_temp_file = FALSE;
+static const gchar *print_settings;
+static const gchar **filenames;
+
+static const GOptionEntry goption_options[] = {
+ { "unlink-tempfile", 'u', 0, G_OPTION_ARG_NONE, &unlink_temp_file, N_("Delete the temporary file"), NULL },
+ { "print-settings", 'p', 0, G_OPTION_ARG_FILENAME, &print_settings, N_("Print settings file"), N_("FILE") },
+ { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE") },
+ { NULL }
+};
+
+static void
+ev_previewer_unlink_tempfile (const gchar *filename)
+{
+ GFile *file, *tempdir;
+
+ file = g_file_new_for_path (filename);
+ tempdir = g_file_new_for_path (g_get_tmp_dir ());
+
+ if (g_file_has_prefix (file, tempdir)) {
+ g_file_delete (file, NULL, NULL);
+ }
+
+ g_object_unref (file);
+ g_object_unref (tempdir);
+}
+
+static void
+ev_previewer_load_job_finished (EvJob *job,
+ EvDocumentModel *model)
+{
+ if (ev_job_is_failed (job)) {
+ g_warning ("%s", job->error->message);
+ g_object_unref (job);
+
+ return;
+ }
+ ev_document_model_set_document (model, job->document);
+ g_object_unref (job);
+}
+
+static void
+ev_previewer_load_document (const gchar *filename,
+ EvDocumentModel *model)
+{
+ EvJob *job;
+ gchar *uri;
+ GFile *file;
+
+ file = g_file_new_for_commandline_arg (filename);
+ uri = g_file_get_uri (file);
+ g_object_unref (file);
+
+ job = ev_job_load_new (uri);
+ g_signal_connect (job, "finished",
+ G_CALLBACK (ev_previewer_load_job_finished),
+ model);
+ ev_job_scheduler_push_job (job, EV_JOB_PRIORITY_NONE);
+ g_free (uri);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+ GtkWidget *window;
+ GOptionContext *context;
+ const gchar *filename;
+ EvDocumentModel *model;
+ GError *error = NULL;
+
+#ifdef G_OS_WIN32
+ if (fileno (stdout) != -1 &&
+ _get_osfhandle (fileno (stdout)) != -1)
+ {
+ /* stdout is fine, presumably redirected to a file or pipe */
+ }
+ else
+ {
+ typedef BOOL (* WINAPI AttachConsole_t) (DWORD);
+
+ AttachConsole_t p_AttachConsole =
+ (AttachConsole_t) GetProcAddress (GetModuleHandle ("kernel32.dll"), "AttachConsole");
+
+ if (p_AttachConsole != NULL && p_AttachConsole (ATTACH_PARENT_PROCESS))
+ {
+ freopen ("CONOUT$", "w", stdout);
+ dup2 (fileno (stdout), 1);
+ freopen ("CONOUT$", "w", stderr);
+ dup2 (fileno (stderr), 2);
+
+ }
+ }
+#endif
+
+ /* Init glib threads asap */
+ if (!g_thread_supported ())
+ g_thread_init (NULL);
+
+#ifdef ENABLE_NLS
+ /* Initialize the i18n stuff */
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+#endif
+
+ context = g_option_context_new (_("GNOME Document Previewer"));
+ g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
+ g_option_context_add_main_entries (context, goption_options, GETTEXT_PACKAGE);
+
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_warning ("Error parsing command line arguments: %s", error->message);
+ g_error_free (error);
+ g_option_context_free (context);
+
+ return 1;
+ }
+ g_option_context_free (context);
+
+ if (!filenames) {
+ g_warning ("File argument is required");
+
+ return 1;
+ }
+
+ filename = filenames[0];
+
+ if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
+ g_warning ("Filename \"%s\" does not exist or is not a regular file", filename);
+
+ return 1;
+ }
+
+ if (!ev_init ())
+ return 1;
+
+ ev_stock_icons_init ();
+
+ g_set_application_name (_("GNOME Document Previewer"));
+ gtk_window_set_default_icon_name ("evince");
+
+ model = ev_document_model_new ();
+ window = ev_previewer_window_new (model);
+ ev_previewer_window_set_source_file (EV_PREVIEWER_WINDOW (window), filename);
+ ev_previewer_window_set_print_settings (EV_PREVIEWER_WINDOW (window), print_settings);
+ g_signal_connect (window, "delete-event",
+ G_CALLBACK (gtk_main_quit), NULL);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gtk_main_quit), NULL);
+ gtk_widget_show (window);
+
+ ev_previewer_load_document (filename, model);
+
+ gtk_main ();
+
+ if (unlink_temp_file)
+ ev_previewer_unlink_tempfile (filename);
+ if (print_settings)
+ ev_previewer_unlink_tempfile (print_settings);
+
+ ev_shutdown ();
+ ev_stock_icons_shutdown ();
+ g_object_unref (model);
+
+ return 0;
+}