[patch] Print Preview



Here is my patch for print preview.  I haven't created the signal yet
but that should be a trivial change.  Right now we just work as if the
user hit print.  The dialog is dismissed and evince (or whatever is
configured as the gtk-print-preview-command settings property) is
launched.  We default to "evince %f".  The dialog dismissal works like
MacOSX works.  I'm not sure if we want to keep the print dialog around
anymore.

Right now we create a directory in /tmp and place a file in there.  This
is because evince needs a .pdf at the end to know it is a pdf and temp
files need to end with the six digit random string.  Using the directory
avoids this by adding the random string to the directory and not the
file.

Things that need to be added:

* enable/disable print preview API
* print preview API so the app can launch a preview without the dialog
* signal so the app can override the print preview and display the pdf
itself
* --preview flag for evince which adds a print button and other print
preview niceties.
* Figure out a way to clean up the temp files and directories.  We could
let evince do this but then we rely on the viewer.  We could also watch
evince and when it exits delete the temp file but we are still left with
the problem of the app exiting before evince is closed.  I'm not sure
what the best thing to do here is.


-- 
John (J5) Palmieri <johnp redhat com>
Index: gtk/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/Makefile.am,v
retrieving revision 1.306
diff -u -r1.306 Makefile.am
--- gtk/Makefile.am	5 May 2006 16:07:49 -0000	1.306
+++ gtk/Makefile.am	12 May 2006 00:51:13 -0000
@@ -4,6 +4,7 @@
 
 if OS_UNIX
 SUBDIRS += xdgmime
+GTK_PRINT_PREVIEW_COMMAND="evince %f"
 endif
 
 DIST_SUBDIRS=theme-bits xdgmime
@@ -25,6 +26,7 @@
 	-DGTK_HOST=\"$(host)\"				\
 	-DGTK_COMPILATION				\
 	-DGTK_PRINT_BACKENDS=\"$(GTK_PRINT_BACKENDS)\"	\
+	-DGTK_PRINT_PREVIEW_COMMAND=\"$(GTK_PRINT_PREVIEW_COMMAND)\"	\
 	-I$(top_builddir)/gtk				\
 	-I$(top_srcdir) -I../gdk			\
 	-I$(top_srcdir)/gdk				\
Index: gtk/gtkprintbackend.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintbackend.c,v
retrieving revision 1.3
diff -u -r1.3 gtkprintbackend.c
--- gtk/gtkprintbackend.c	4 May 2006 13:43:30 -0000	1.3
+++ gtk/gtkprintbackend.c	12 May 2006 00:51:14 -0000
@@ -200,7 +200,6 @@
   GtkPrintBackendModule *pb_module;
   GtkPrintBackend *pb;
 
-  /* TODO: make module loading code work */
   for (l = loaded_backends; l != NULL; l = l->next)
     {
       pb_module = l->data;
@@ -250,6 +249,11 @@
 							  GTK_PRINT_BACKENDS,
 							  GTK_PARAM_READWRITE));
 
+      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;
     }
 }
Index: gtk/gtkprintbackend.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintbackend.h,v
retrieving revision 1.6
diff -u -r1.6 gtkprintbackend.h
--- gtk/gtkprintbackend.h	5 May 2006 16:07:50 -0000	1.6
+++ gtk/gtkprintbackend.h	12 May 2006 00:51:14 -0000
@@ -140,6 +140,9 @@
 void        gtk_print_backend_unref_at_idle        (GtkPrintBackend         *print_backend);
 void        gtk_print_backend_destroy              (GtkPrintBackend         *print_backend);
 
+/* Methods private to gtk */
+GtkPrintBackend * _gtk_print_backend_create        (const char *backend_name);
+
 /* Backend-only functions for GtkPrintBackend */
 
 void        gtk_print_backend_add_printer          (GtkPrintBackend         *print_backend,
Index: gtk/gtkprintoperation-unix.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation-unix.c,v
retrieving revision 1.11
diff -u -r1.11 gtkprintoperation-unix.c
--- gtk/gtkprintoperation-unix.c	5 May 2006 11:03:33 -0000	1.11
+++ gtk/gtkprintoperation-unix.c	12 May 2006 00:51:14 -0000
@@ -44,6 +44,7 @@
   GtkWindow *parent;        /* just in case we need to throw error dialogs */
   GMainLoop *loop;
   gboolean data_sent;
+  gboolean launch_preview;
 } GtkPrintOperationUnix;
 
 typedef struct _PrinterFinder PrinterFinder;
@@ -98,6 +99,84 @@
   g_free (op_unix);
 }
 
+static char *
+shell_command_substitute_file (const gchar *cmd,
+			       const gchar *filename)
+{
+  const char *inptr, *start;
+  char *result;
+  GString *final;
+
+  g_return_val_if_fail (cmd != NULL, NULL);
+  g_return_val_if_fail (filename != NULL, NULL);
+
+  result = NULL;
+  final = g_string_new (NULL);
+
+  start = inptr = cmd;
+
+  while ((inptr = strchr (inptr, '%')) != NULL) 
+    {
+      g_string_append_len (final, start, inptr - start);
+      inptr++;
+      switch (*inptr) 
+        {
+          case 'f':
+            g_string_append (final, filename ? filename : "");
+            break;
+
+          case '%':
+            g_string_append_c (final, '%');
+            break;
+
+          default:
+            g_string_append_c (final, '%');
+            if (*inptr)
+              g_string_append_c (final, *inptr);
+            break;
+        }
+      if (*inptr)
+        inptr++;
+      start = inptr;
+    }
+  g_string_append (final, start);
+
+  result = final->str;
+
+  g_string_free (final, FALSE);
+
+  return result;
+}
+
+static void
+launch_preview (const char *filename, GError **error)
+{
+  int argc;
+  gchar **argv;
+  gchar *cmd;
+  gchar *preview_cmd;
+  GtkSettings *settings;
+  gchar *quoted_filename;
+
+  settings = gtk_settings_get_default ();
+  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);
+  g_shell_parse_argv (cmd, &argc, &argv, error);
+
+  if (error && *error !=NULL)
+    goto out;
+
+  g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, error);
+
+ out:
+  g_free (cmd);
+  g_free (quoted_filename);
+  g_free (preview_cmd);
+  g_strfreev (argv);
+}
+
 static void
 unix_finish_send  (GtkPrintJob *job,
                    void        *user_data, 
@@ -107,6 +186,21 @@
 
   op_unix = (GtkPrintOperationUnix *) user_data;
 
+  if (op_unix->launch_preview && error == NULL)
+    {
+      GtkPrintSettings *settings;
+      const gchar *filename;
+ 
+      settings = gtk_print_job_get_settings (op_unix->job);
+      if (!settings)
+          g_warning ("Settings not preserved for preview");
+      else
+        {
+          filename = gtk_print_settings_get (settings, "pdf-filename");
+          launch_preview (filename, &error);
+        }
+    }
+
   if (error != NULL)
     {
       GtkWidget *edialog;
@@ -125,6 +219,7 @@
     }
 
   op_unix->data_sent = TRUE;
+
   if (op_unix->loop)
     g_main_loop_quit (op_unix->loop);
 }
@@ -233,7 +328,10 @@
 					printer,
 					settings,
 					page_setup);
-  
+ 
+      if (rdata->result == GTK_PRINT_OPERATION_RESULT_PREVIEW)
+        op_unix->launch_preview = TRUE;
+
       rdata->op->priv->surface = gtk_print_job_get_surface (op_unix->job, rdata->error);
       if (op->priv->surface == NULL)
         {
@@ -281,7 +379,7 @@
     rdata->destroy (rdata);
 }
 
-static void
+static void 
 handle_print_response (GtkWidget *dialog,
 		       gint       response,
 		       gpointer   data)
@@ -291,6 +389,7 @@
   GtkPrintSettings *settings = NULL;
   GtkPageSetup *page_setup = NULL;
   GtkPrinter *printer = NULL;
+  GtkPrintBackend *preview_backend = NULL;
 
   if (response == GTK_RESPONSE_OK)
     {
@@ -305,14 +404,53 @@
       settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
       page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd));
     } 
+  else if (response == GTK_RESPONSE_APPLY)
+    {
+      GList *printer_list;
 
+      /* print preview */
+      rdata->result = GTK_PRINT_OPERATION_RESULT_PREVIEW;
+      rdata->do_print = TRUE;
+      
+
+      settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
+
+      gtk_print_settings_set_bool (settings, "print-preview", TRUE);
+
+      page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd));
+    
+      preview_backend = _gtk_print_backend_create ("pdf");
+      if (!preview_backend)
+	{
+	  g_warning ("PDF backend not found for preview mode");
+	  rdata->do_print = FALSE;
+	  goto out;
+	}
+
+      printer_list = gtk_print_backend_get_printer_list (preview_backend);
+      if (printer_list == NULL)
+        {
+	  g_warning ("No printers found for preview");
+          rdata->do_print = FALSE;
+	  g_object_unref (preview_backend);
+	  goto out;
+        }
+
+      printer = GTK_PRINTER (printer_list->data);
+      g_list_free (printer_list);
+    }
+  
  out:  
   finish_print (rdata, printer, page_setup, settings);
 
   if (settings)
     g_object_unref (settings);
-  
+
+  if (preview_backend)
+    g_object_unref (preview_backend);
+
   gtk_widget_destroy (GTK_WIDGET (pd));
+ 
 }
 
 
@@ -419,6 +557,7 @@
   if (op->priv->show_dialog)
     {
       pd = get_print_dialog (op, parent);
+
       response = gtk_dialog_run (GTK_DIALOG (pd));
       handle_print_response (pd, response, &rdata);
     }
Index: gtk/gtkprintoperation.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation.h,v
retrieving revision 1.3
diff -u -r1.3 gtkprintoperation.h
--- gtk/gtkprintoperation.h	24 Apr 2006 20:44:22 -0000	1.3
+++ gtk/gtkprintoperation.h	12 May 2006 00:51:14 -0000
@@ -92,7 +92,8 @@
 typedef enum {
   GTK_PRINT_OPERATION_RESULT_ERROR,
   GTK_PRINT_OPERATION_RESULT_APPLY,
-  GTK_PRINT_OPERATION_RESULT_CANCEL
+  GTK_PRINT_OPERATION_RESULT_CANCEL,
+  GTK_PRINT_OPERATION_RESULT_PREVIEW
 } GtkPrintOperationResult;
 
 #define GTK_PRINT_ERROR gtk_print_error_quark ()
Index: gtk/gtkprintunixdialog.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintunixdialog.c,v
retrieving revision 1.12
diff -u -r1.12 gtkprintunixdialog.c
--- gtk/gtkprintunixdialog.c	8 May 2006 00:08:39 -0000	1.12
+++ gtk/gtkprintunixdialog.c	12 May 2006 00:51:15 -0000
@@ -269,7 +269,8 @@
 		    (GCallback) gtk_print_unix_dialog_destroy, 
 		    NULL);
 
-  gtk_dialog_add_buttons (GTK_DIALOG (dialog), 
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+			  GTK_STOCK_PRINT_PREVIEW, GTK_RESPONSE_APPLY, 
 			  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 			  GTK_STOCK_PRINT, GTK_RESPONSE_OK,
                           NULL);
Index: modules/printbackends/pdf/gtkprintbackendpdf.c
===================================================================
RCS file: /cvs/gnome/gtk+/modules/printbackends/pdf/gtkprintbackendpdf.c,v
retrieving revision 1.4
diff -u -r1.4 gtkprintbackendpdf.c
--- modules/printbackends/pdf/gtkprintbackendpdf.c	5 May 2006 20:22:27 -0000	1.4
+++ modules/printbackends/pdf/gtkprintbackendpdf.c	12 May 2006 00:51:16 -0000
@@ -304,24 +304,49 @@
   GtkPrinter *printer;
   _PrintStreamData *ps;
   GtkPrintSettings *settings;
-  GIOChannel *save_channel;  
-  const char *filename;
+  GIOChannel *save_channel; 
+  const gchar *filename;
+  gchar *preview_filename;
+  gboolean print_preview;
 
   printer = gtk_print_job_get_printer (job);
   settings = gtk_print_job_get_settings (job);
 
   error = NULL;
 
+  print_preview = gtk_print_settings_get_bool (settings, "print-preview");
+  if (print_preview)
+    {
+      char *tmp_dir;
+      char *dir_template = g_strdup_printf ("%s/print-preview-XXXXXX", g_get_tmp_dir ());
+      /* make sure we don't save this setting */
+      gtk_print_settings_set_bool (settings, "print-preview", FALSE);
+
+      /* use temp dirs because apps like evince need to have extentions
+         to determine the mine type */
+      tmp_dir = mkdtemp(dir_template);
+
+      preview_filename = g_strdup_printf ("%s/%s", 
+                                          tmp_dir, 
+                                          "Print Preview.pdf");
+
+      gtk_print_settings_set (settings, "pdf-filename", preview_filename);
+      
+      g_free (dir_template);
+      g_free (preview_filename);
+    }
+  
   filename = gtk_print_settings_get (settings, "pdf-filename");
   if (filename == NULL)
     filename = "output.pdf";
-  
+
   ps = g_new0 (_PrintStreamData, 1);
   ps->callback = callback;
   ps->user_data = user_data;
   ps->job = g_object_ref (job);
 
   ps->target_fd = creat (filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+  
   ps->backend = print_backend;
 
   if (ps->target_fd == -1)


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