[evince/wip/chpe/load-fd: 841/845] previewer: Allow passing the document and print settings as FDs




commit 61b1a1edadd9be6e5f57b2579719e58eed41c2ca
Author: Christian Persch <chpe src gnome org>
Date:   Thu Nov 18 00:03:14 2021 +0100

    previewer: Allow passing the document and print settings as FDs
    
    This allows passing FDs to the document and print settings files
    which are already unlinked, so don't need --unlink-tempfile. It
    makes sure the files are never left around even if the previewer
    crashes.

 previewer/ev-previewer-window.c | 333 ++++++++++++++++++++++++++--------------
 previewer/ev-previewer-window.h |  22 ++-
 previewer/ev-previewer.c        | 244 +++++++++++++++++++----------
 3 files changed, 397 insertions(+), 202 deletions(-)
---
diff --git a/previewer/ev-previewer-window.c b/previewer/ev-previewer-window.c
index 7d3bd3944..da7c44db1 100644
--- a/previewer/ev-previewer-window.c
+++ b/previewer/ev-previewer-window.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2009 Carlos Garcia Campos <carlosgc gnome org>
  * Copyright (C) 2018 Germán Poo-Caamaño <gpoo gnome org>
+ * Copyright © 2018, 2021 Christian Persch
  *
  * Evince is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by
@@ -21,6 +22,8 @@
 
 #include <config.h>
 
+#include <fcntl.h>
+
 #if GTKUNIXPRINT_ENABLED
 #include <gtk/gtkunixprint.h>
 #endif
@@ -34,6 +37,7 @@
 struct _EvPreviewerWindow {
        GtkApplicationWindow base_instance;
 
+        EvJob            *job;
        EvDocumentModel  *model;
        EvDocument       *document;
 
@@ -48,23 +52,18 @@ struct _EvPreviewerWindow {
 #endif
        gchar            *print_job_title;
        gchar            *source_file;
+        int               source_fd;
 };
 
 struct _EvPreviewerWindowClass {
        GtkApplicationWindowClass 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_APPLICATION_WINDOW)
 
-#if GTKUNIXPRINT_ENABLED
 static void
 ev_previewer_window_error_dialog_run (EvPreviewerWindow *window,
                                      GError            *error)
@@ -82,7 +81,6 @@ ev_previewer_window_error_dialog_run (EvPreviewerWindow *window,
        gtk_dialog_run (GTK_DIALOG (dialog));
        gtk_widget_destroy (dialog);
 }
-#endif
 
 static void
 ev_previewer_window_close (GSimpleAction *action,
@@ -169,6 +167,7 @@ ev_previewer_window_focus_page_selector (GSimpleAction *action,
 }
 
 #if GTKUNIXPRINT_ENABLED
+
 static void
 ev_previewer_window_print_finished (GtkPrintJob       *print_job,
                                    EvPreviewerWindow *window,
@@ -186,15 +185,25 @@ static void
 ev_previewer_window_do_print (EvPreviewerWindow *window)
 {
        GtkPrintJob *job;
+        gboolean     rv = FALSE;
        GError      *error = NULL;
 
        job = gtk_print_job_new (window->print_job_title ?
                                 window->print_job_title :
-                                window->source_file,
+                                (window->source_file ? window->source_file : _("Evince")),
                                 window->printer,
                                 window->print_settings,
                                 window->print_page_setup);
-       if (gtk_print_job_set_source_file (job, window->source_file, &error)) {
+
+        if (window->source_fd != -1)
+                rv = gtk_print_job_set_source_fd (job, window->source_fd, &error);
+        else if (window->source_file != NULL)
+                rv = gtk_print_job_set_source_file (job, window->source_file, &error);
+        else
+                g_set_error_literal (&error, GTK_PRINT_ERROR, GTK_PRINT_ERROR_GENERAL,
+                                     "Neither file nor FD to print.");
+
+        if (rv) {
                gtk_print_job_send (job,
                                    (GtkPrintJobCompleteFunc)ev_previewer_window_print_finished,
                                    window, NULL);
@@ -220,6 +229,7 @@ ev_previewer_window_enumerate_finished (EvPreviewerWindow *window)
                             _("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);
        }
 }
@@ -260,7 +270,8 @@ ev_previewer_window_print (GSimpleAction *action,
                                (GDestroyNotify)ev_previewer_window_enumerate_finished,
                                FALSE);
 }
-#endif
+
+#endif /* GTKUNIXPRINT_ENABLED */
 
 static const GActionEntry actions[] = {
 #if GTKUNIXPRINT_ENABLED
@@ -315,17 +326,28 @@ view_sizing_mode_changed (EvDocumentModel   *model,
 }
 
 static void
-ev_previewer_window_set_document (EvPreviewerWindow *window,
-                                 GParamSpec        *pspec,
-                                 EvDocumentModel   *model)
+load_job_finished_cb (EvJob             *job,
+                      EvPreviewerWindow *window)
 {
-       EvDocument *document = ev_document_model_get_document (model);
+        g_assert (job == window->job);
 
-       window->document = g_object_ref (document);
+        if (ev_job_is_failed (job)) {
+                ev_previewer_window_error_dialog_run (window, job->error);
 
-       g_signal_connect (model, "notify::sizing-mode",
-                         G_CALLBACK (view_sizing_mode_changed),
-                         window);
+                g_object_unref (window->job);
+                window->job = NULL;
+                return;
+        }
+
+        window->document = g_object_ref (job->document);
+
+        g_object_unref (window->job);
+        window->job = NULL;
+
+        ev_document_model_set_document (window->model, window->document);
+        g_signal_connect (window->model, "notify::sizing-mode",
+                          G_CALLBACK (view_sizing_mode_changed),
+                          window);
 }
 
 static void
@@ -333,6 +355,11 @@ ev_previewer_window_dispose (GObject *object)
 {
        EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
 
+        if (window->job) {
+                g_object_unref (window->job);
+                window->job = NULL;
+        }
+
        if (window->model) {
                g_object_unref (window->model);
                window->model = NULL;
@@ -370,34 +397,26 @@ ev_previewer_window_dispose (GObject *object)
                 window->source_file = NULL;
         }
 
+        if (window->source_fd != -1) {
+                close (window->source_fd);
+                window->source_fd = -1;
+        }
+
        G_OBJECT_CLASS (ev_previewer_window_parent_class)->dispose (object);
 }
 
 static void
 ev_previewer_window_init (EvPreviewerWindow *window)
 {
+        window->source_fd = -1;
+
        gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
 
        g_action_map_add_action_entries (G_ACTION_MAP (window),
                                         actions, G_N_ELEMENTS (actions),
                                         window);
-}
-
-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);
-       }
+       gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
 }
 
 static gboolean
@@ -421,31 +440,24 @@ _gtk_css_provider_load_from_resource (GtkCssProvider *provider,
         return retval;
 }
 
-static GObject *
-ev_previewer_window_constructor (GType                  type,
-                                guint                  n_construct_properties,
-                                GObjectConstructParam *construct_params)
+static void
+ev_previewer_window_constructed (GObject *object)
 {
-       GObject           *object;
-       EvPreviewerWindow *window;
+       EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
        GtkWidget         *vbox;
        GtkWidget         *swindow;
        GError            *error = NULL;
        gdouble            dpi;
         GtkCssProvider    *css_provider;
 
-       object = G_OBJECT_CLASS (ev_previewer_window_parent_class)->constructor (type,
-                                                                                n_construct_properties,
-                                                                                construct_params);
-       window = EV_PREVIEWER_WINDOW (object);
+       G_OBJECT_CLASS (ev_previewer_window_parent_class)->constructed (object);
+
+        window->model = ev_document_model_new ();
 
        dpi = ev_document_misc_get_widget_dpi (GTK_WIDGET (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_AUTOMATIC);
-       g_signal_connect_swapped (window->model, "notify::document",
-                                 G_CALLBACK (ev_previewer_window_set_document),
-                                 window);
 
         css_provider = gtk_css_provider_new ();
         _gtk_css_provider_load_from_resource (css_provider,
@@ -491,8 +503,6 @@ ev_previewer_window_constructor (GType                  type,
 
        gtk_container_add (GTK_CONTAINER (window), vbox);
        gtk_widget_show (vbox);
-
-       return object;
 }
 
 
@@ -501,99 +511,188 @@ 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->constructed = ev_previewer_window_constructed;
        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 */
 EvPreviewerWindow *
-ev_previewer_window_new (EvDocumentModel *model)
+ev_previewer_window_new (void)
 {
-       return g_object_new (EV_TYPE_PREVIEWER_WINDOW, 
+       return g_object_new (EV_TYPE_PREVIEWER_WINDOW,
                              "application", g_application_get_default (),
-                             "model", model,
                              NULL);
 }
 
 void
+ev_previewer_window_set_job (EvPreviewerWindow *window,
+                             EvJob             *job)
+{
+        g_return_if_fail (EV_IS_PREVIEWER_WINDOW (window));
+        g_return_if_fail (EV_IS_JOB (job));
+
+        g_clear_object (&window->job);
+        window->job = g_object_ref (job);
+
+        g_signal_connect_object (window->job, "finished",
+                                 G_CALLBACK (load_job_finished_cb),
+                                 window, 0);
+        ev_job_scheduler_push_job (window->job, EV_JOB_PRIORITY_NONE);
+}
+
+static gboolean
+ev_previewer_window_set_print_settings_take_file (EvPreviewerWindow *window,
+                                                  GMappedFile       *file,
+                                                  GError           **error)
+{
+        GBytes           *bytes;
+        GKeyFile         *key_file;
+        GtkPrintSettings *psettings;
+        GtkPageSetup     *psetup;
+        char             *job_name;
+        gboolean          rv;
+
+        g_clear_object (&window->print_settings);
+        g_clear_object (&window->print_page_setup);
+        g_clear_pointer (&window->print_job_title, g_free);
+
+        bytes = g_mapped_file_get_bytes (file);
+        key_file = g_key_file_new ();
+        rv = g_key_file_load_from_bytes (key_file, bytes, G_KEY_FILE_NONE, error);
+        g_bytes_unref (bytes);
+        g_mapped_file_unref (file);
+
+        if (!rv) {
+                window->print_settings = gtk_print_settings_new ();
+                window->print_page_setup = gtk_page_setup_new ();
+                window->print_job_title = g_strdup (_("Evince"));
+                return FALSE;
+        }
+
+        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 && job_name[0]) {
+                window->print_job_title = job_name;
+                gtk_window_set_title (GTK_WINDOW (window), job_name);
+        } else {
+                g_free (job_name);
+                window->print_job_title = g_strdup (_("Evince"));
+        }
+
+        g_key_file_free (key_file);
+
+        return TRUE;
+}
+
+gboolean
 ev_previewer_window_set_print_settings (EvPreviewerWindow *window,
-                                       const gchar       *print_settings)
+                                       const gchar       *print_settings,
+                                        GError           **error)
 {
-       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);
+        GMappedFile *file;
 
-       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 ();
-       }
+        g_return_val_if_fail (EV_IS_PREVIEWER_WINDOW (window), FALSE);
+        g_return_val_if_fail (print_settings != NULL, FALSE);
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+        file = g_mapped_file_new (print_settings, FALSE, error);
+        if (file == NULL)
+                return FALSE;
+
+        return ev_previewer_window_set_print_settings_take_file (window, file, error);
+}
+
+/**
+ * ev_previewer_window_set_print_settings_fd:
+ * @window:
+ * @fd:
+ * @error:
+ *
+ * Sets the print settings from FD.
+ *
+ * Note that this function takes ownership of @fd.
+ */
+gboolean
+ev_previewer_window_set_print_settings_fd (EvPreviewerWindow *window,
+                                           int                fd,
+                                           GError           **error)
+{
+        GMappedFile *file;
+
+        g_return_val_if_fail (EV_IS_PREVIEWER_WINDOW (window), FALSE);
+        g_return_val_if_fail (fd != -1, FALSE);
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+        file = g_mapped_file_new_from_fd (fd, FALSE, error);
+        if (file == NULL)
+                return FALSE;
+
+        return ev_previewer_window_set_print_settings_take_file (window, file, error);
 }
 
 void
 ev_previewer_window_set_source_file (EvPreviewerWindow *window,
                                     const gchar       *source_file)
 {
-       if (window->source_file)
-               g_free (window->source_file);
+        g_return_if_fail (EV_IS_PREVIEWER_WINDOW (window));
+
+        g_free (window->source_file);
        window->source_file = g_strdup (source_file);
 }
 
 EvDocumentModel *
 ev_previewer_window_get_document_model (EvPreviewerWindow *window)
 {
-       g_return_val_if_fail (EV_PREVIEWER_WINDOW (window), NULL);
+        g_return_val_if_fail (EV_IS_PREVIEWER_WINDOW (window), NULL);
+
+        return window->model;
+}
+
+/**
+ * ev_previewer_window_set_source_fd:
+ * @window:
+ * @fd:
+ *
+ * Sets the source document FD.
+ *
+ * Note that this function takes ownership of @fd.
+ *
+ * Returns: %TRUE on success
+ */
+gboolean
+ev_previewer_window_set_source_fd (EvPreviewerWindow *window,
+                                   int                fd,
+                                   GError           **error)
+{
+        int nfd;
+
+        g_return_val_if_fail (EV_IS_PREVIEWER_WINDOW (window), FALSE);
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+        nfd = fcntl (fd, F_DUPFD_CLOEXEC, 3);
+        if (nfd == -1) {
+                int errsv = errno;
+                g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
+                             "Failed to duplicate file descriptor: %s",
+                             g_strerror (errsv));
+                return FALSE;
+        }
+
+        if (window->source_fd != -1)
+                close (window->source_fd);
+
+        window->source_fd = fd;
 
-       return window->model;
+        return TRUE;
 }
diff --git a/previewer/ev-previewer-window.h b/previewer/ev-previewer-window.h
index 7449e8f5c..dfd2a33fc 100644
--- a/previewer/ev-previewer-window.h
+++ b/previewer/ev-previewer-window.h
@@ -38,15 +38,25 @@ G_BEGIN_DECLS
 typedef struct _EvPreviewerWindow      EvPreviewerWindow;
 typedef struct _EvPreviewerWindowClass EvPreviewerWindowClass;
 
-GType              ev_previewer_window_get_type   (void) G_GNUC_CONST;
-EvPreviewerWindow *ev_previewer_window_new        (EvDocumentModel   *model);
+GType              ev_previewer_window_get_type       (void) G_GNUC_CONST;
+
+EvPreviewerWindow *ev_previewer_window_new            (void);
 
 EvDocumentModel   *ev_previewer_window_get_document_model (EvPreviewerWindow *window);
 
-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);
+void       ev_previewer_window_set_job                (EvPreviewerWindow *window,
+                                                       EvJob             *job);
+gboolean   ev_previewer_window_set_print_settings     (EvPreviewerWindow *window,
+                                                       const gchar       *print_settings,
+                                                       GError           **error);
+gboolean   ev_previewer_window_set_print_settings_fd  (EvPreviewerWindow *window,
+                                                       int                fd,
+                                                       GError           **error);
+void       ev_previewer_window_set_source_file        (EvPreviewerWindow *window,
+                                                       const gchar       *source_file);
+gboolean   ev_previewer_window_set_source_fd          (EvPreviewerWindow *window,
+                                                       int                fd,
+                                                      GError           **error);
 
 G_END_DECLS
 
diff --git a/previewer/ev-previewer.c b/previewer/ev-previewer.c
index 06ca7ab2f..378cbdf80 100644
--- a/previewer/ev-previewer.c
+++ b/previewer/ev-previewer.c
@@ -1,8 +1,8 @@
-/* ev-previewer.c: 
+/* ev-previewer.c:
  *  this file is part of evince, a gnome document viewer
  *
  * Copyright (C) 2009 Carlos Garcia Campos <carlosgc gnome org>
- * Copyright © 2012 Christian Persch
+ * Copyright © 2012, 2018 Christian Persch
  *
  * Evince is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by
@@ -21,6 +21,12 @@
 
 #include "config.h"
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 #include <evince-document.h>
@@ -38,12 +44,24 @@
 #endif
 
 static gboolean unlink_temp_file = FALSE;
-static gchar *print_settings = NULL;
+static int input_fd = -1;
+static char *input_file = NULL;
+static char *input_mime_type = NULL;
+static int print_settings_fd = -1;
+static gchar *print_settings_file = NULL;
 static EvPreviewerWindow *window = NULL;
 
 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_("File specifying print 
settings"), N_("FILE") },
+       { "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_file,
+          N_("File specifying print settings"), N_("FILE") },
+       { "fd", 0, 0, G_OPTION_ARG_INT, &input_fd,
+          N_("File descriptor of input file"), N_("FD") },
+        { "mime-type", 0, 0, G_OPTION_ARG_STRING, &input_mime_type,
+          N_("MIME type of input file"), N_("TYPE") },
+       { "print-settings-fd", 0, 0, G_OPTION_ARG_INT, &print_settings_fd,
+          N_("File descriptor of print settings file"), N_("FD") },
        { NULL }
 };
 
@@ -63,35 +81,6 @@ ev_previewer_unlink_tempfile (const gchar *filename)
         g_object_unref (tempdir);
 }
 
-static void
-ev_previewer_load_job_finished (EvJob           *job,
-                               EvDocumentModel *model)
-{
-       if (ev_job_is_failed (job)) {
-               g_object_unref (job);
-               return;
-       }
-       ev_document_model_set_document (model, job->document);
-       g_object_unref (job);
-}
-
-static void
-ev_previewer_load_document (GFile           *file,
-                           EvDocumentModel *model)
-{
-       EvJob *job;
-       gchar *uri;
-
-       uri = g_file_get_uri (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);
-}
-
 static void
 activate_cb (GApplication *application,
              gpointer user_data)
@@ -102,35 +91,147 @@ activate_cb (GApplication *application,
 }
 
 static void
-open_cb (GApplication *application,
-         GFile **files,
-         gint n_files,
-         const gchar *hint,
-         gpointer user_data)
+startup_cb (GApplication *application,
+            gpointer      data)
 {
-        EvDocumentModel *model;
-        GFile           *file;
-        char            *path;
+       EvJob *job;
+        GError *error = NULL;
+        gboolean ps_ok = TRUE;
 
-        if (n_files != 1) {
-                g_application_quit (application);
-                return;
+        g_assert (input_fd != -1 || input_file != NULL);
+
+        window = ev_previewer_window_new ();
+
+        if (print_settings_fd != -1) {
+                ps_ok = ev_previewer_window_set_print_settings_fd (EV_PREVIEWER_WINDOW (window), 
print_settings_fd, &error);
+                print_settings_fd = -1;
+        } else if (print_settings_file != NULL) {
+                ps_ok = ev_previewer_window_set_print_settings (EV_PREVIEWER_WINDOW (window), 
print_settings_file, &error);
+                g_free (print_settings_file);
+                print_settings_file = NULL;
         }
+        if (!ps_ok) {
+                g_printerr ("Failed to load print settings: %s\n", error->message);
+                g_clear_error (&error);
+        }
+
+        if (input_fd != -1) {
+                if (!ev_previewer_window_set_source_fd (EV_PREVIEWER_WINDOW (window), input_fd, &error)) {
+                        g_printerr ("Failed to set source FD: %s\n", error->message);
+                        g_clear_error (&error);
 
-        file = files[0];
+                        g_application_quit (application);
+                        return;
+                }
 
-        model = ev_document_model_new ();
-        ev_previewer_load_document (file, model);
+                job = ev_job_load_fd_new_take (input_fd, input_mime_type,
+                                               EV_DOCUMENT_LOAD_FLAG_NO_CACHE);
 
-        window = ev_previewer_window_new (model);
-        g_object_unref (model);
+                input_fd = -1;
+        } else {
+                GFile *file;
+                char *uri;
+                char *path;
 
-        ev_previewer_window_set_print_settings (EV_PREVIEWER_WINDOW (window), print_settings);
-        path = g_file_get_path (file);
-        ev_previewer_window_set_source_file (EV_PREVIEWER_WINDOW (window), path);
-        g_free (path);
+                file = g_file_new_for_commandline_arg (input_file);
+                uri = g_file_get_uri (file);
+                path = g_file_get_path (file);
 
-        gtk_window_present (GTK_WINDOW (window));
+                ev_previewer_window_set_source_file (EV_PREVIEWER_WINDOW (window), path);
+                job = ev_job_load_new (uri);
+
+                g_free (uri);
+                g_free (path);
+                g_object_unref (file);
+
+                g_free (input_file);
+                input_file = NULL;
+        }
+
+        ev_previewer_window_set_job (window, job);
+        g_object_unref (job);
+
+        /* Window will be presented by 'activate' signal */
+}
+
+static gboolean
+check_arguments (int argc,
+                 char** argv,
+                 GError **error)
+{
+        if (input_fd != -1) {
+                struct stat statbuf;
+                int flags;
+
+                if (fstat (input_fd, &statbuf) == -1 ||
+                    (flags = fcntl (input_fd, F_GETFL, &flags)) == -1) {
+                        int errsv = errno;
+                        g_set_error_literal (error, G_FILE_ERROR,
+                                             g_file_error_from_errno(errsv),
+                                             g_strerror(errsv));
+                        return FALSE;
+                }
+
+                if (!S_ISREG (statbuf.st_mode)) {
+                        g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_BADF,
+                                             "Not a regular file.");
+                        return FALSE;
+                }
+
+                switch (flags & O_ACCMODE) {
+                case O_RDONLY:
+                case O_RDWR:
+                        break;
+                case O_WRONLY:
+                default:
+                        g_set_error_literal(error, G_FILE_ERROR, G_FILE_ERROR_BADF,
+                                            "Not a readable file descriptor.");
+                        return FALSE;
+                }
+
+                if (argc > 1) {
+                        g_set_error_literal (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                                             "Too many arguments");
+                        return FALSE;
+                }
+                if (input_mime_type == NULL) {
+                        g_set_error_literal (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                                             "Must specify --mime-type");
+                        return FALSE;
+                }
+                if (unlink_temp_file) {
+                        g_set_error_literal (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                                             "Must not specify --unlink-tempfile");
+                        return FALSE;
+                }
+
+       } else {
+                char *path;
+
+                if (argc != 2) {
+                        g_set_error_literal (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                                             "Need exactly one argument");
+                        return FALSE;
+                }
+                if (input_mime_type != NULL) {
+                        g_set_error_literal (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                                             "Must not specify --mime-type");
+                        return FALSE;
+                }
+
+                path = g_filename_from_uri (argv[1], NULL, NULL);
+                if (!g_file_test (argv[1], G_FILE_TEST_IS_REGULAR) && !g_file_test (path, 
G_FILE_TEST_IS_REGULAR)) {
+                        g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
+                                     "File \"%s\" does not exist or is not a regular file\n", argv[1]);
+                        g_free (path);
+                        return FALSE;
+                }
+                g_free (path);
+
+                input_file = g_strdup (argv[1]);
+        }
+
+        return TRUE;
 }
 
 gint
@@ -139,7 +240,6 @@ main (gint argc, gchar **argv)
         GtkApplication  *application;
        GOptionContext  *context;
        GError          *error = NULL;
-       gchar           *path;
         int              status = 1;
 
        const gchar *action_accels[] = {
@@ -185,13 +285,16 @@ main (gint argc, gchar **argv)
        textdomain (GETTEXT_PACKAGE);
 #endif
 
+        g_set_prgname ("evince-previewer");
+
        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)) {
+       if (!g_option_context_parse (context, &argc, &argv, &error) ||
+            !check_arguments (argc, argv, &error)) {
                g_printerr ("Error parsing command line arguments: %s\n", error->message);
                g_error_free (error);
                g_option_context_free (context);
@@ -199,21 +302,6 @@ main (gint argc, gchar **argv)
        }
        g_option_context_free (context);
 
-       if (argc < 2) {
-               g_printerr ("File argument is required\n");
-                return 1;
-       } else if (argc > 2) {
-                g_printerr ("Too many files\n");
-                return 1;
-        }
-
-       path = g_filename_from_uri (argv[1], NULL, NULL);
-       if (!g_file_test (argv[1], G_FILE_TEST_IS_REGULAR) && !g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
-               g_printerr ("Filename \"%s\" does not exist or is not a regular file\n", argv[1]);
-                return 1;
-       }
-        g_free (path);
-
        if (!ev_init ())
                 return 1;
 
@@ -222,21 +310,19 @@ main (gint argc, gchar **argv)
        g_set_application_name (_("GNOME Document Previewer"));
        gtk_window_set_default_icon_name (PACKAGE_ICON_NAME);
 
-        application = gtk_application_new (NULL,
-                                           G_APPLICATION_NON_UNIQUE |
-                                           G_APPLICATION_HANDLES_OPEN);
+        application = gtk_application_new (NULL, G_APPLICATION_NON_UNIQUE);
+        g_signal_connect (application, "startup", G_CALLBACK (startup_cb), NULL);
         g_signal_connect (application, "activate", G_CALLBACK (activate_cb), NULL);
-        g_signal_connect (application, "open", G_CALLBACK (open_cb), NULL);
 
         for (it = action_accels; it[0]; it += g_strv_length ((gchar **)it) + 1)
                 gtk_application_set_accels_for_action (GTK_APPLICATION (application), it[0], &it[1]);
 
-        status = g_application_run (G_APPLICATION (application), argc, argv);
+        status = g_application_run (G_APPLICATION (application), 0, NULL);
 
         if (unlink_temp_file)
                 ev_previewer_unlink_tempfile (argv[1]);
-        if (print_settings)
-                ev_previewer_unlink_tempfile (print_settings);
+        if (print_settings_file)
+                ev_previewer_unlink_tempfile (print_settings_file);
 
        ev_shutdown ();
        ev_stock_icons_shutdown ();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]