]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkprintoperation-unix.c
Require cvs glib.
[~andy/gtk] / gtk / gtkprintoperation-unix.c
index d6b486a486e80c0136605caf34a123ad8ee6b3d7..a72866d73ed2a8bef74af8cee59ff7b5a859c0d5 100644 (file)
@@ -1,5 +1,6 @@
 /* GTK - The GIMP Toolkit
- * gtkprintoperation-unix.c: Print Operation Details for Unix and Unix like platforms
+ * gtkprintoperation-unix.c: Print Operation Details for Unix 
+ *                           and Unix-like platforms
  * Copyright (C) 2006, Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
 
 #include <cairo-pdf.h>
 #include <cairo-ps.h>
+#include "gtkprivate.h"
 #include "gtkprintunixdialog.h"
 #include "gtkpagesetupunixdialog.h"
 #include "gtkprintbackend.h"
 #include "gtkprinter.h"
+#include "gtkprinter-private.h"
 #include "gtkprintjob.h"
 #include "gtklabel.h"
 #include "gtkalias.h"
 #include "gtkintl.h"
 
-typedef struct {
+typedef struct 
+{
   GtkWindow *parent;        /* just in case we need to throw error dialogs */
   GMainLoop *loop;
   gboolean data_sent;
 
-  /* Real printing (not preview: */
+  /* Real printing (not preview) */
   GtkPrintJob *job;         /* the job we are sending to the printer */
   cairo_surface_t *surface;
   gulong job_status_changed_tag;
@@ -60,7 +64,7 @@ typedef struct {
 typedef struct _PrinterFinder PrinterFinder;
 
 static void printer_finder_free (PrinterFinder *finder);
-static void find_printer        (const char    *printer,
+static void find_printer        (const gchar   *printer,
                                 GFunc          func,
                                 gpointer       data);
 
@@ -72,7 +76,7 @@ unix_start_page (GtkPrintOperation *op,
   GtkPrintOperationUnix *op_unix;  
   GtkPaperSize *paper_size;
   cairo_surface_type_t type;
-  double w, h;
+  gdouble w, h;
 
   op_unix = op->priv->platform_data;
   
@@ -112,12 +116,12 @@ op_unix_free (GtkPrintOperationUnix *op_unix)
   g_free (op_unix);
 }
 
-static char *
+static gchar *
 shell_command_substitute_file (const gchar *cmd,
                               const gchar *filename)
 {
-  const char *inptr, *start;
-  char *result;
+  const gchar *inptr, *start;
+  gchar *result;
   GString *final;
 
   g_return_val_if_fail (cmd != NULL, NULL);
@@ -161,12 +165,41 @@ shell_command_substitute_file (const gchar *cmd,
   return result;
 }
 
+static void
+gtk_print_operation_unix_initialize (void)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      /**
+       * GtkSettings::gtk-print-preview-command:
+       *
+       * A command to run for displaying the print preview. The command
+       * should contain a %f placeholder, which will get replaced by
+       * the path to the pdf file.
+       *
+       * The preview application is responsible for removing the pdf file
+       * when it is done.
+       *
+       * Since: 2.10
+       */
+      gtk_settings_install_property (g_param_spec_string ("gtk-print-preview-command",
+                                                         P_("Default command to run when displaying a print preview"),
+                                                         P_("Command to run when displaying a print preview"),
+                                                         GTK_PRINT_PREVIEW_COMMAND,
+                                                         GTK_PARAM_READWRITE)); 
+      initialized = TRUE;
+    }
+}
+
 void
 _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
-                                                     GtkWindow *parent,
-                                                     const char *filename)
+                                                     cairo_surface_t   *surface,
+                                                     GtkWindow         *parent,
+                                                     const gchar       *filename)
 {
-  int argc;
+  gint argc;
   gchar **argv;
   gchar *cmd;
   gchar *preview_cmd;
@@ -174,6 +207,10 @@ _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
   gchar *quoted_filename;
   GdkScreen *screen;
   GError *error = NULL;
+
+  gtk_print_operation_unix_initialize ();
+
+  cairo_surface_destroy (surface);
  
   settings = gtk_settings_get_default ();
   g_object_get (settings, "gtk-print-preview-command", &preview_cmd, NULL);
@@ -182,7 +219,7 @@ _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
   cmd = shell_command_substitute_file (preview_cmd, quoted_filename);
   g_shell_parse_argv (cmd, &argc, &argv, &error);
 
-  if (error !=NULL)
+  if (error != NULL)
     goto out;
 
   if (parent)
@@ -220,7 +257,7 @@ _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
 
 static void
 unix_finish_send  (GtkPrintJob *job,
-                   void        *user_data, 
+                   gpointer     user_data, 
                    GError      *error)
 {
   GtkPrintOperationUnix *op_unix;
@@ -308,7 +345,8 @@ get_print_dialog (GtkPrintOperation *op,
                                                 GTK_PRINT_CAPABILITY_COPIES |
                                                 GTK_PRINT_CAPABILITY_COLLATE |
                                                 GTK_PRINT_CAPABILITY_REVERSE |
-                                                GTK_PRINT_CAPABILITY_SCALE);
+                                                GTK_PRINT_CAPABILITY_SCALE |
+                                                 GTK_PRINT_CAPABILITY_GENERATE_PDF);
 
   if (priv->print_settings)
     gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (pd),
@@ -339,16 +377,17 @@ get_print_dialog (GtkPrintOperation *op,
       label = gtk_label_new (custom_tab_label);
       
       gtk_print_unix_dialog_add_custom_tab (GTK_PRINT_UNIX_DIALOG (pd),
-                                           op->priv->custom_widget, label);
+                                           priv->custom_widget, label);
     }
   
   return pd;
 }
   
-typedef struct {
+typedef struct 
+{
   GtkPrintOperation           *op;
   gboolean                     do_print;
-  GError                     **error;
+  gboolean                     do_preview;
   GtkPrintOperationResult      result;
   GtkPrintOperationPrintFunc   print_cb;
   GDestroyNotify               destroy;
@@ -367,15 +406,13 @@ print_response_data_free (gpointer data)
 
 static void
 finish_print (PrintResponseData *rdata,
-             GtkPrinter *printer,
-             GtkPageSetup *page_setup,
-             GtkPrintSettings *settings)
+             GtkPrinter        *printer,
+             GtkPageSetup      *page_setup,
+             GtkPrintSettings  *settings)
 {
   GtkPrintOperation *op = rdata->op;
   GtkPrintOperationPrivate *priv = op->priv;
-  gboolean is_preview;
-
-  is_preview = rdata->result == GTK_PRINT_OPERATION_RESULT_PREVIEW;
+  GtkPrintJob *job;
   
   if (rdata->do_print)
     {
@@ -383,12 +420,12 @@ finish_print (PrintResponseData *rdata,
       priv->print_context = _gtk_print_context_new (op);
       _gtk_print_context_set_page_setup (priv->print_context, page_setup);
 
-      if (!is_preview)
+      if (!rdata->do_preview)
         {
          GtkPrintOperationUnix *op_unix;
          cairo_t *cr;
          
-         op_unix = g_new0 (GtkPrintOperationUnix, 1);     
+         op_unix = g_new0 (GtkPrintOperationUnix, 1);
          priv->platform_data = op_unix;
          priv->free_platform_data = (GDestroyNotify) op_unix_free;
          op_unix->parent = rdata->parent;
@@ -397,49 +434,43 @@ finish_print (PrintResponseData *rdata,
          priv->end_page = unix_end_page;
          priv->end_run = unix_end_run;
          
-         op_unix->job = gtk_print_job_new (priv->job_name,
-                                           printer,
-                                           settings,
-                                           page_setup);
-          gtk_print_job_set_track_print_status (op_unix->job, priv->track_print_status);
+         job = gtk_print_job_new (priv->job_name, printer, settings, page_setup);
+          op_unix->job = job;
+          gtk_print_job_set_track_print_status (job, priv->track_print_status);
          
-         op_unix->surface = gtk_print_job_get_surface (op_unix->job, rdata->error);
-         if (op_unix->surface == NULL) {
-           rdata->do_print = FALSE;
-           goto out;
-         }
+         op_unix->surface = gtk_print_job_get_surface (job, &priv->error);
+         if (op_unix->surface == NULL) 
+            {
+             rdata->result = GTK_PRINT_OPERATION_RESULT_ERROR;
+             rdata->do_print = FALSE;
+             goto out;
+            }
          
          cr = cairo_create (op_unix->surface);
-         gtk_print_context_set_cairo_context (op->priv->print_context,
-                                              cr, 72, 72);
+         gtk_print_context_set_cairo_context (priv->print_context, cr, 72, 72);
          cairo_destroy (cr);
 
-          _gtk_print_operation_set_status (op, gtk_print_job_get_status (op_unix->job), NULL);
+          _gtk_print_operation_set_status (op, gtk_print_job_get_status (job), NULL);
          
           op_unix->job_status_changed_tag =
-           g_signal_connect (op_unix->job, "status-changed",
+           g_signal_connect (job, "status-changed",
                              G_CALLBACK (job_status_changed_cb), op);
          
-          priv->print_pages = op_unix->job->print_pages;
-          priv->page_ranges = op_unix->job->page_ranges;
-          priv->num_page_ranges = op_unix->job->num_page_ranges;
+          priv->print_pages = job->print_pages;
+          priv->page_ranges = job->page_ranges;
+          priv->num_page_ranges = job->num_page_ranges;
          
-          priv->manual_num_copies = op_unix->job->num_copies;
-          priv->manual_collation = op_unix->job->collate;
-          priv->manual_reverse = op_unix->job->reverse;
-          priv->manual_page_set = op_unix->job->page_set;
-          priv->manual_scale = op_unix->job->scale;
-          priv->manual_orientation = op_unix->job->rotate_to_orientation;
+          priv->manual_num_copies = job->num_copies;
+          priv->manual_collation = job->collate;
+          priv->manual_reverse = job->reverse;
+          priv->manual_page_set = job->page_set;
+          priv->manual_scale = job->scale;
+          priv->manual_orientation = job->rotate_to_orientation;
         }
     } 
  out:
   if (rdata->print_cb)
-    {
-      if (rdata->do_print)
-        rdata->print_cb (op, rdata->parent, is_preview); 
-      else
-       _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); 
-    }
+    rdata->print_cb (op, rdata->parent, rdata->do_print, rdata->result); 
 
   if (rdata->destroy)
     rdata->destroy (rdata);
@@ -458,17 +489,21 @@ handle_print_response (GtkWidget *dialog,
 
   if (response == GTK_RESPONSE_OK)
     {
-      rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
-
       printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd));
+
+      rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
+      rdata->do_preview = FALSE;
       if (printer != NULL)
        rdata->do_print = TRUE;
     } 
   else if (response == GTK_RESPONSE_APPLY)
     {
       /* print preview */
-      rdata->result = GTK_PRINT_OPERATION_RESULT_PREVIEW;
+      rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
+      rdata->do_preview = TRUE;
       rdata->do_print = TRUE;
+
+      rdata->op->priv->action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
     }
 
   if (rdata->do_print)
@@ -490,7 +525,7 @@ handle_print_response (GtkWidget *dialog,
 
 
 static void
-found_printer (GtkPrinter *printer,
+found_printer (GtkPrinter        *printer,
               PrintResponseData *rdata)
 {
   GtkPrintOperation *op = rdata->op;
@@ -501,7 +536,8 @@ found_printer (GtkPrinter *printer,
   if (rdata->loop)
     g_main_loop_quit (rdata->loop);
 
-  if (printer != NULL) {
+  if (printer != NULL) 
+    {
       rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
 
       rdata->do_print = TRUE;
@@ -531,24 +567,24 @@ found_printer (GtkPrinter *printer,
 
 void
 _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
+                                                       gboolean                    show_dialog,
                                                         GtkWindow                  *parent,
                                                        GtkPrintOperationPrintFunc  print_cb)
 {
   GtkWidget *pd;
   PrintResponseData *rdata;
-  const char *printer_name;
+  const gchar *printer_name;
 
   rdata = g_new (PrintResponseData, 1);
   rdata->op = g_object_ref (op);
   rdata->do_print = FALSE;
   rdata->result = GTK_PRINT_OPERATION_RESULT_CANCEL;
-  rdata->error = NULL;
   rdata->print_cb = print_cb;
   rdata->parent = parent;
   rdata->loop = NULL;
   rdata->destroy = print_response_data_free;
   
-  if (op->priv->show_dialog)
+  if (show_dialog)
     {
       pd = get_print_dialog (op, parent);
       gtk_window_set_modal (GTK_WINDOW (pd), TRUE);
@@ -564,36 +600,99 @@ _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation
       if (op->priv->print_settings)
        printer_name = gtk_print_settings_get_printer (op->priv->print_settings);
       
-      find_printer (printer_name,
-                   (GFunc) found_printer, rdata);
+      find_printer (printer_name, (GFunc) found_printer, rdata);
+    }
+}
+
+static cairo_status_t
+write_preview (void                *closure,
+               const unsigned char *data,
+               unsigned int         length)
+{
+  gint fd = GPOINTER_TO_INT (closure);
+  gssize written;
+  
+  while (length > 0) 
+    {
+      written = write (fd, data, length);
+
+      if (written == -1)
+       {
+         if (errno == EAGAIN || errno == EINTR)
+           continue;
+         
+         return CAIRO_STATUS_WRITE_ERROR;
+       }    
+
+      data += written;
+      length -= written;
     }
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+close_preview (void *data)
+{
+  gint fd = GPOINTER_TO_INT (data);
+
+  close (fd);
 }
 
 cairo_surface_t *
 _gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
-                                                             GtkPageSetup *page_setup,
-                                                             gdouble *dpi_x,
-                                                             gdouble *dpi_y,
-                                                             const gchar *target)
+                                                             GtkPageSetup      *page_setup,
+                                                             gdouble           *dpi_x,
+                                                             gdouble           *dpi_y,
+                                                             gchar            **target)
 {
+  gchar *filename;
+  gint fd;
   GtkPaperSize *paper_size;
-  double w, h;
+  gdouble w, h;
+  cairo_surface_t *surface;
+  static cairo_user_data_key_t key;
+  
+  filename = g_build_filename (g_get_tmp_dir (), "previewXXXXXX.pdf", NULL);
+  fd = g_mkstemp (filename);
+  *target = filename;
   
+  g_print ("target is %s\n", filename);
+
   paper_size = gtk_page_setup_get_paper_size (page_setup);
   w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
   h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
     
   *dpi_x = *dpi_y = 72;
-  return cairo_pdf_surface_create (target, w, h);
+  surface = cairo_pdf_surface_create_for_stream (write_preview, GINT_TO_POINTER(fd), w, h);
+  cairo_surface_set_user_data (surface, &key, GINT_TO_POINTER (fd), close_preview);
+
+  return surface;
+}
+
+void
+_gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op,
+                                                         cairo_surface_t   *surface,
+                                                         cairo_t           *cr)
+{
+}
+
+void
+_gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op,
+                                                       cairo_surface_t   *surface,
+                                                       cairo_t           *cr)
+{
+  cairo_show_page (cr);
 }
 
 void
 _gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op,
-                                                             GtkPageSetup *page_setup,
-                                                             cairo_surface_t *surface)
+                                                             GtkPageSetup      *page_setup,
+                                                             cairo_surface_t   *surface)
 {
   GtkPaperSize *paper_size;
-  double w, h;
+  gdouble w, h;
   
   paper_size = gtk_page_setup_get_paper_size (page_setup);
   w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
@@ -604,25 +703,24 @@ _gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation
 
 GtkPrintOperationResult
 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
+                                                 gboolean           show_dialog,
                                                  GtkWindow         *parent,
-                                                 gboolean          *do_print,
-                                                 GError           **error)
+                                                 gboolean          *do_print)
  {
   GtkWidget *pd;
   PrintResponseData rdata;
   gint response;  
-  const char *printer_name;
+  const gchar *printer_name;
    
   rdata.op = op;
   rdata.do_print = FALSE;
   rdata.result = GTK_PRINT_OPERATION_RESULT_CANCEL;
-  rdata.error = error;
   rdata.print_cb = NULL;
   rdata.destroy = NULL;
   rdata.parent = parent;
   rdata.loop = NULL;
 
-  if (op->priv->show_dialog)
+  if (show_dialog)
     {
       pd = get_print_dialog (op, parent);
 
@@ -653,7 +751,8 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
 }
 
 
-typedef struct {
+typedef struct 
+{
   GtkPageSetup         *page_setup;
   GtkPageSetupDoneFunc  done_cb;
   gpointer              data;
@@ -665,7 +764,9 @@ page_setup_data_free (gpointer data)
 {
   PageSetupResponseData *rdata = data;
 
-  g_object_unref (rdata->page_setup);
+  if (rdata->page_setup)
+    g_object_unref (rdata->page_setup);
+
   g_free (rdata);
 }
 
@@ -793,11 +894,12 @@ gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
   gtk_window_present (GTK_WINDOW (dialog));
  }
 
-struct _PrinterFinder {
+struct _PrinterFinder 
+{
   gboolean found_printer;
   GFunc func;
   gpointer data;
-  char *printer_name;
+  gchar *printer_name;
   GList *backends;
   guint timeout_tag;
   GtkPrinter *printer;
@@ -832,8 +934,11 @@ printer_added_cb (GtkPrintBackend *backend,
                   GtkPrinter      *printer, 
                  PrinterFinder   *finder)
 {
-  if (gtk_printer_is_virtual (printer) ||
-      finder->found_printer)
+  if (finder->found_printer)
+    return;
+
+  /* FIXME this skips "Print to PDF" - is this intentional ? */
+  if (gtk_printer_is_virtual (printer))
     return;
 
   if (finder->printer_name != NULL &&
@@ -874,7 +979,7 @@ printer_list_done_cb (GtkPrintBackend *backend,
 }
 
 static void
-find_printer_init (PrinterFinder *finder,
+find_printer_init (PrinterFinder   *finder,
                   GtkPrintBackend *backend)
 {
   GList *list;
@@ -902,12 +1007,10 @@ find_printer_init (PrinterFinder *finder,
     }
   else
     {
-      g_signal_connect (backend, 
-                       "printer-added", 
+      g_signal_connect (backend, "printer-added", 
                        (GCallback) printer_added_cb, 
                        finder);
-      g_signal_connect (backend, 
-                       "printer-list-done", 
+      g_signal_connect (backend, "printer-list-done", 
                        (GCallback) printer_list_done_cb, 
                        finder);
     }
@@ -945,9 +1048,9 @@ printer_finder_free (PrinterFinder *finder)
 }
 
 static void 
-find_printer (const char *printer,
-             GFunc func,
-             gpointer data)
+find_printer (const gchar *printer,
+             GFunc        func,
+             gpointer     data)
 {
   GList *node, *next;
   PrinterFinder *finder;