]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkprintoperation-unix.c
build with GTK_DISABLE_DEPRECATED.
[~andy/gtk] / gtk / gtkprintoperation-unix.c
index e87927a8066480c156722f26c99bed120fa62e88..16c7eb263abc4fa94cb1632a38b2c1b690cbf13f 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 <stdlib.h>       
 #include <fcntl.h>
 
+#include <glib/gstdio.h>
 #include "gtkprintoperation-private.h"
-#include "gtkmarshal.h"
 #include "gtkmessagedialog.h"
 
 #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"
+#include "gtkalias.h"
 
 typedef struct 
 {
@@ -50,7 +53,7 @@ typedef struct
   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;
@@ -115,20 +118,24 @@ op_unix_free (GtkPrintOperationUnix *op_unix)
 
 static gchar *
 shell_command_substitute_file (const gchar *cmd,
-                              const gchar *filename)
+                              const gchar *pdf_filename,
+                              const gchar *settings_filename,
+                               gboolean    *pdf_filename_replaced,
+                               gboolean    *settings_filename_replaced)
 {
   const gchar *inptr, *start;
-  gchar *result;
   GString *final;
 
   g_return_val_if_fail (cmd != NULL, NULL);
-  g_return_val_if_fail (filename != NULL, NULL);
+  g_return_val_if_fail (pdf_filename != NULL, NULL);
+  g_return_val_if_fail (settings_filename != NULL, NULL);
 
-  result = NULL;
   final = g_string_new (NULL);
 
-  start = inptr = cmd;
+  *pdf_filename_replaced = FALSE;
+  *settings_filename_replaced = FALSE;
 
+  start = inptr = cmd;
   while ((inptr = strchr (inptr, '%')) != NULL) 
     {
       g_string_append_len (final, start, inptr - start);
@@ -136,7 +143,13 @@ shell_command_substitute_file (const gchar *cmd,
       switch (*inptr) 
         {
           case 'f':
-            g_string_append (final, filename ? filename : "");
+            g_string_append (final, pdf_filename);
+            *pdf_filename_replaced = TRUE;
+            break;
+
+          case 's':
+            g_string_append (final, settings_filename);
+            *settings_filename_replaced = TRUE;
             break;
 
           case '%':
@@ -155,11 +168,7 @@ shell_command_substitute_file (const gchar *cmd,
     }
   g_string_append (final, start);
 
-  result = final->str;
-
-  g_string_free (final, FALSE);
-
-  return result;
+  return g_string_free (final, FALSE);
 }
 
 void
@@ -173,29 +182,55 @@ _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
   gchar *cmd;
   gchar *preview_cmd;
   GtkSettings *settings;
+  GtkPrintSettings *print_settings;
+  gchar *settings_filename = NULL;
   gchar *quoted_filename;
+  gchar *quoted_settings_filename;
+  gboolean filename_used = FALSE;
+  gboolean settings_used = FALSE;
   GdkScreen *screen;
   GError *error = NULL;
+  gint fd;
+  gboolean retval;
 
   cairo_surface_destroy (surface);
  
-  settings = gtk_settings_get_default ();
+  if (parent)
+    screen = gtk_window_get_screen (parent);
+  else
+    screen = gdk_screen_get_default ();
+
+  fd = g_file_open_tmp ("settingsXXXXXX.ini", &settings_filename, &error);
+  if (fd < 0) 
+    goto out;
+
+  print_settings = gtk_print_operation_get_print_settings (op);
+  retval = gtk_print_settings_to_file (print_settings, settings_filename, &error);
+  close (fd);
+
+  if (!retval)
+    goto out;
+
+  settings = gtk_settings_get_for_screen (screen);
   g_object_get (settings, "gtk-print-preview-command", &preview_cmd, NULL);
 
   quoted_filename = g_shell_quote (filename);
-  cmd = shell_command_substitute_file (preview_cmd, quoted_filename);
+  quoted_settings_filename = g_shell_quote (settings_filename);
+  cmd = shell_command_substitute_file (preview_cmd, quoted_filename, quoted_settings_filename, &filename_used, &settings_used);
   g_shell_parse_argv (cmd, &argc, &argv, &error);
 
+  g_free (preview_cmd);
+  g_free (quoted_filename);
+  g_free (quoted_settings_filename);
+  g_free (cmd);
+
   if (error != NULL)
     goto out;
 
-  if (parent)
-    screen = gtk_window_get_screen (parent);
-  else
-    screen = gdk_screen_get_default ();
-  
   gdk_spawn_on_screen (screen, NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
 
+  g_strfreev (argv);
+
  out:
   if (error != NULL)
     {
@@ -207,19 +242,24 @@ _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
                                         _("Error launching preview") /* FIXME better text */);
       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (edialog),
                                                 "%s", error->message);
-      gtk_window_set_modal (GTK_WINDOW (edialog), TRUE);
       g_signal_connect (edialog, "response",
                         G_CALLBACK (gtk_widget_destroy), NULL);
 
       gtk_window_present (GTK_WINDOW (edialog));
 
-      g_error_free (error); 
+      g_error_free (error);
+
+      filename_used = FALSE; 
+      settings_used = FALSE;
    } 
 
-  g_free (cmd);
-  g_free (quoted_filename);
-  g_free (preview_cmd);
-  g_strfreev (argv);
+  if (!filename_used)
+    g_unlink (filename);
+
+  if (!settings_used)
+    g_unlink (settings_filename);
+
+  g_free (settings_filename);
 }
 
 static void
@@ -227,9 +267,8 @@ unix_finish_send  (GtkPrintJob *job,
                    gpointer     user_data, 
                    GError      *error)
 {
-  GtkPrintOperationUnix *op_unix;
-
-  op_unix = (GtkPrintOperationUnix *) user_data;
+  GtkPrintOperation *op = (GtkPrintOperation *) user_data;
+  GtkPrintOperationUnix *op_unix = op->priv->platform_data;
 
   if (error != NULL)
     {
@@ -252,6 +291,8 @@ unix_finish_send  (GtkPrintJob *job,
 
   if (op_unix->loop)
     g_main_loop_quit (op_unix->loop);
+
+  g_object_unref (op);
 }
 
 static void
@@ -271,13 +312,16 @@ unix_end_run (GtkPrintOperation *op,
   
   /* TODO: Check for error */
   if (op_unix->job != NULL)
-    gtk_print_job_send (op_unix->job,
-                        unix_finish_send, 
-                        op_unix, NULL,
-                       NULL);
+    {
+      g_object_ref (op);
+      gtk_print_job_send (op_unix->job,
+                          unix_finish_send, 
+                          op, NULL);
+    }
 
   if (wait)
     {
+      g_object_ref (op);
       if (!op_unix->data_sent)
        {
          GDK_THREADS_LEAVE ();  
@@ -285,6 +329,8 @@ unix_end_run (GtkPrintOperation *op,
          GDK_THREADS_ENTER ();  
        }
       g_main_loop_unref (op_unix->loop);
+      op_unix->loop = NULL;
+      g_object_unref (op);
     }
 }
 
@@ -302,7 +348,6 @@ get_print_dialog (GtkPrintOperation *op,
 {
   GtkPrintOperationPrivate *priv = op->priv;
   GtkWidget *pd, *label;
-  GtkPageSetup *page_setup;
   const gchar *custom_tab_label;
 
   pd = gtk_print_unix_dialog_new (NULL, parent);
@@ -312,19 +357,15 @@ 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_PREVIEW);
 
   if (priv->print_settings)
     gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (pd),
                                        priv->print_settings);
   if (priv->default_page_setup)
-    page_setup = gtk_page_setup_copy (priv->default_page_setup);
-  else
-    page_setup = gtk_page_setup_new ();
-
-  gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (pd), 
-                                        page_setup);
-  g_object_unref (page_setup);
+    gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (pd), 
+                                          priv->default_page_setup);
 
   g_signal_emit_by_name (op, "create-custom-widget",
                         &priv->custom_widget);
@@ -353,6 +394,7 @@ typedef struct
 {
   GtkPrintOperation           *op;
   gboolean                     do_print;
+  gboolean                     do_preview;
   GtkPrintOperationResult      result;
   GtkPrintOperationPrintFunc   print_cb;
   GDestroyNotify               destroy;
@@ -378,17 +420,18 @@ finish_print (PrintResponseData *rdata,
   GtkPrintOperation *op = rdata->op;
   GtkPrintOperationPrivate *priv = op->priv;
   GtkPrintJob *job;
-  gboolean is_preview;
-
-  is_preview = rdata->result == GTK_PRINT_OPERATION_RESULT_PREVIEW;
   
   if (rdata->do_print)
     {
       gtk_print_operation_set_print_settings (op, settings);
       priv->print_context = _gtk_print_context_new (op);
+
+      if ( (page_setup != NULL) && (gtk_print_operation_get_default_page_setup (op) == NULL))
+        gtk_print_operation_set_default_page_setup (op, page_setup);
+
       _gtk_print_context_set_page_setup (priv->print_context, page_setup);
 
-      if (!is_preview)
+      if (!rdata->do_preview)
         {
          GtkPrintOperationUnix *op_unix;
          cairo_t *cr;
@@ -457,17 +500,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)
@@ -542,6 +589,7 @@ _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation
   rdata = g_new (PrintResponseData, 1);
   rdata->op = g_object_ref (op);
   rdata->do_print = FALSE;
+  rdata->do_preview = FALSE;
   rdata->result = GTK_PRINT_OPERATION_RESULT_CANCEL;
   rdata->print_cb = print_cb;
   rdata->parent = parent;
@@ -568,6 +616,41 @@ _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation
     }
 }
 
+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,
@@ -575,41 +658,40 @@ _gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation
                                                              gdouble           *dpi_y,
                                                              gchar            **target)
 {
-  gchar *tmp_dir, *dir_template, *preview_filename;
+  gchar *filename;
+  gint fd;
   GtkPaperSize *paper_size;
   gdouble w, h;
+  cairo_surface_t *surface;
+  static cairo_user_data_key_t key;
   
-  dir_template = g_build_filename (g_get_tmp_dir (), "print-preview-XXXXXX", NULL);
-
-  /* use temp dirs because apps like evince need to have extensions
-   * to determine the mime type 
-   */
-  tmp_dir = mkdtemp(dir_template);
-  preview_filename = g_build_filename (tmp_dir, 
-                                      "Print Preview.pdf",
-                                      NULL);
-  g_free (dir_template);
-  *target = preview_filename;
+  filename = g_build_filename (g_get_tmp_dir (), "previewXXXXXX.pdf", NULL);
+  fd = g_mkstemp (filename);
+  *target = 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 (preview_filename, 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)
+                                                         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_surface_t   *surface,
+                                                       cairo_t           *cr)
 {
   cairo_show_page (cr);
 }
@@ -642,6 +724,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
    
   rdata.op = op;
   rdata.do_print = FALSE;
+  rdata.do_preview = FALSE;
   rdata.result = GTK_PRINT_OPERATION_RESULT_CANCEL;
   rdata.print_cb = NULL;
   rdata.destroy = NULL;
@@ -692,7 +775,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);
 }