]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkprintoperation-win32.c
Replace a lot of idle and timeout calls by the new gdk_threads api.
[~andy/gtk] / gtk / gtkprintoperation-win32.c
index 97e1aaa605785f09023393b1d3df2965adeb66bc..5df99a9ee99e36e1aae8b817fe31eac0f90f4350 100644 (file)
 #define COBJMACROS
 #include "config.h"
 #include <math.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <io.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <cairo-win32.h>
 #include <glib.h>
@@ -35,9 +40,9 @@
 #include "gtkinvisible.h"
 #include "gtkplug.h"
 #include "gtkstock.h"
-#include "gtkalias.h"
 #include "gtk.h"
 #include "gtkwin32embedwidget.h"
+#include "gtkalias.h"
 
 #define MAX_PAGE_RANGES 20
 #define STATUS_POLLING_TIME 2000
@@ -58,6 +63,7 @@ typedef struct {
   int job_id;
   guint timeout_id;
 
+  cairo_surface_t *surface;
   GtkWidget *embed_widget;
 } GtkPrintOperationWin32;
 
@@ -65,6 +71,7 @@ static void win32_poll_status (GtkPrintOperation *op);
 
 static const GUID myIID_IPrintDialogCallback  = {0x5852a2c3,0x6530,0x11d1,{0xb6,0xa3,0x0,0x0,0xf8,0x75,0x7b,0xf9}};
 
+#ifndef _MSC_VER
 #undef INTERFACE
 #define INTERFACE IPrintDialogCallback
 DECLARE_INTERFACE_ (IPrintDialogCallback, IUnknown)
@@ -76,6 +83,7 @@ DECLARE_INTERFACE_ (IPrintDialogCallback, IUnknown)
     STDMETHOD (SelectionChange)(THIS) PURE;
     STDMETHOD (HandleMessage)(THIS_ HWND,UINT,WPARAM,LPARAM,LRESULT*) PURE;
 }; 
+#endif
 
 static UINT got_gdk_events_message;
 
@@ -461,7 +469,7 @@ win32_poll_status_timeout (GtkPrintOperation *op)
   win32_poll_status (op);
 
   if (!gtk_print_operation_is_finished (op))
-    op_win32->timeout_id = g_timeout_add (STATUS_POLLING_TIME,
+    op_win32->timeout_id = gdk_threads_add_timeout (STATUS_POLLING_TIME,
                                          (GSourceFunc)win32_poll_status_timeout,
                                          op);
   g_object_unref (op);
@@ -492,8 +500,9 @@ win32_end_run (GtkPrintOperation *op,
   GlobalFree(op_win32->devmode);
   GlobalFree(op_win32->devnames);
 
-  cairo_surface_destroy (op->priv->surface);
-  op->priv->surface = NULL;
+  cairo_surface_finish (op_win32->surface);
+  cairo_surface_destroy (op_win32->surface);
+  op_win32->surface = NULL;
 
   DeleteDC(op_win32->hdc);
   
@@ -501,7 +510,7 @@ win32_end_run (GtkPrintOperation *op,
     {
       op_win32->printerHandle = printerHandle;
       win32_poll_status (op);
-      op_win32->timeout_id = g_timeout_add (STATUS_POLLING_TIME,
+      op_win32->timeout_id = gdk_threads_add_timeout (STATUS_POLLING_TIME,
                                            (GSourceFunc)win32_poll_status_timeout,
                                            op);
     }
@@ -530,8 +539,9 @@ win32_poll_status (GtkPrintOperation *op)
   status_str = NULL;
   if (ret)
     {
+      DWORD win32_status;
       job_info = (JOB_INFO_1W *)data;
-      DWORD win32_status = job_info->Status;
+      win32_status = job_info->Status;
 
       if (job_info->pStatus)
        status_str = g_utf16_to_utf8 (job_info->pStatus, 
@@ -667,8 +677,7 @@ devmode_to_settings (GtkPrintSettings *settings,
     }
   
   if (devmode->dmFields & DM_SCALE)
-    gtk_print_settings_set_scale (settings,
-                                 devmode->dmScale / 100.0);
+    gtk_print_settings_set_scale (settings, devmode->dmScale);
   
   if (devmode->dmFields & DM_COPIES)
     gtk_print_settings_set_n_copies (settings,
@@ -949,7 +958,7 @@ devmode_from_settings (GtkPrintSettings *settings,
   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_SCALE))
     {
       devmode->dmFields |= DM_SCALE;
-      devmode->dmScale = gtk_print_settings_get_scale (settings) * 100;
+      devmode->dmScale = gtk_print_settings_get_scale (settings);
     }
   
   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_N_COPIES))
@@ -1393,11 +1402,46 @@ create_application_page (GtkPrintOperation *op)
   return hpage;
 }
 
+static GtkPageSetup *
+create_page_setup (GtkPrintOperation *op)
+{
+  GtkPrintOperationPrivate *priv = op->priv;
+  GtkPageSetup *page_setup;
+  GtkPrintSettings *settings;
+  
+  if (priv->default_page_setup)
+    page_setup = gtk_page_setup_copy (priv->default_page_setup);
+  else
+    page_setup = gtk_page_setup_new ();
+
+  settings = priv->print_settings;
+  if (settings)
+    {
+      GtkPaperSize *paper_size;
+      
+      if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION))
+       gtk_page_setup_set_orientation (page_setup,
+                                       gtk_print_settings_get_orientation (settings));
+
+
+      paper_size = gtk_print_settings_get_paper_size (settings);
+      if (paper_size)
+       {
+         gtk_page_setup_set_paper_size (page_setup, paper_size);
+         gtk_paper_size_free (paper_size);
+       }
+
+      /* TODO: Margins? */
+    }
+  
+  return page_setup;
+}
+
 GtkPrintOperationResult
 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
+                                                 gboolean show_dialog,
                                                  GtkWindow *parent,
-                                                 gboolean *do_print,
-                                                 GError **error)
+                                                 gboolean *do_print)
 {
   HRESULT hResult;
   LPPRINTDLGEXW printdlgex = NULL;
@@ -1406,14 +1450,17 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
   GtkWidget *invisible = NULL;
   GtkPrintOperationResult result;
   GtkPrintOperationWin32 *op_win32;
+  GtkPrintOperationPrivate *priv;
   IPrintDialogCallback *callback;
   HPROPSHEETPAGE prop_page;
   
   *do_print = FALSE;
 
+  priv = op->priv;
+  
   op_win32 = g_new0 (GtkPrintOperationWin32, 1);
-  op->priv->platform_data = op_win32;
-  op->priv->free_platform_data = (GDestroyNotify) op_win32_free;
+  priv->platform_data = op_win32;
+  priv->free_platform_data = (GDestroyNotify) op_win32_free;
   
   if (parent == NULL)
     {
@@ -1427,7 +1474,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
   if (!printdlgex)
     {
       result = GTK_PRINT_OPERATION_RESULT_ERROR;
-      g_set_error (error,
+      g_set_error (&priv->error,
                   GTK_PRINT_ERROR,
                   GTK_PRINT_ERROR_NOMEM,
                   _("Not enough free memory"));
@@ -1450,7 +1497,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
   if (!page_ranges) 
     {
       result = GTK_PRINT_OPERATION_RESULT_ERROR;
-      g_set_error (error,
+      g_set_error (&priv->error,
                   GTK_PRINT_ERROR,
                   GTK_PRINT_ERROR_NOMEM,
                   _("Not enough free memory"));
@@ -1498,27 +1545,27 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
     {
       result = GTK_PRINT_OPERATION_RESULT_ERROR;
       if (hResult == E_OUTOFMEMORY)
-       g_set_error (error,
+       g_set_error (&priv->error,
                     GTK_PRINT_ERROR,
                     GTK_PRINT_ERROR_NOMEM,
                     _("Not enough free memory"));
       else if (hResult == E_INVALIDARG)
-       g_set_error (error,
+       g_set_error (&priv->error,
                     GTK_PRINT_ERROR,
                     GTK_PRINT_ERROR_INTERNAL_ERROR,
                     _("Invalid argument to PrintDlgEx"));
       else if (hResult == E_POINTER)
-       g_set_error (error,
+       g_set_error (&priv->error,
                     GTK_PRINT_ERROR,
                     GTK_PRINT_ERROR_INTERNAL_ERROR,
                     _("Invalid pointer to PrintDlgEx"));
       else if (hResult == E_HANDLE)
-       g_set_error (error,
+       g_set_error (&priv->error,
                     GTK_PRINT_ERROR,
                     GTK_PRINT_ERROR_INTERNAL_ERROR,
                     _("Invalid handle to PrintDlgEx"));
       else /* E_FAIL */
-       g_set_error (error,
+       g_set_error (&priv->error,
                     GTK_PRINT_ERROR,
                     GTK_PRINT_ERROR_GENERAL,
                     _("Unspecified error"));
@@ -1538,13 +1585,25 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
     {
       DOCINFOW docinfo;
       int job_id;
-
+      double dpi_x, dpi_y;
+      cairo_t *cr;
+      GtkPageSetup *page_setup;
+
+      priv->print_context = _gtk_print_context_new (op);
+      page_setup = create_page_setup (op);
+      _gtk_print_context_set_page_setup (priv->print_context, page_setup);
+      g_object_unref (page_setup);
+      
       *do_print = TRUE;
 
-      op->priv->surface = cairo_win32_surface_create (printdlgex->hDC);
-      op->priv->dpi_x = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSX);
-      op->priv->dpi_y = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSY);
+      op_win32->surface = cairo_win32_surface_create (printdlgex->hDC);
+      dpi_x = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSX);
+      dpi_y = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSY);
 
+      cr = cairo_create (op_win32->surface);
+      gtk_print_context_set_cairo_context (priv->print_context, cr, dpi_x, dpi_y);
+      cairo_destroy (cr);
+      
       memset( &docinfo, 0, sizeof (DOCINFOW));
       docinfo.cbSize = sizeof (DOCINFOW); 
       docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL); 
@@ -1557,13 +1616,13 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
       if (job_id <= 0) 
        { 
          result = GTK_PRINT_OPERATION_RESULT_ERROR;
-         g_set_error (error,
+         g_set_error (&priv->error,
                       GTK_PRINT_ERROR,
                       GTK_PRINT_ERROR_GENERAL,
                     _("Error from StartDoc"));
          *do_print = FALSE;
-         cairo_surface_destroy (op->priv->surface);
-         op->priv->surface = NULL;
+         cairo_surface_destroy (op_win32->surface);
+         op_win32->surface = NULL;
          goto out; 
        } 
       
@@ -1608,18 +1667,101 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
   return result;
 }
 
-void 
-_gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
-                                                        GtkWindow                  *parent,
-                                                       GtkPrintOperationPrintFunc  print_cb)
+void
+_gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
+                                                     cairo_surface_t   *surface,
+                                                     GtkWindow         *parent,
+                                                     const gchar       *filename)
 {
-  gboolean do_print;
+  HDC dc;
+  HENHMETAFILE metafile;
+  
+  dc = cairo_win32_surface_get_dc (surface);
+  cairo_surface_destroy (surface);
+  metafile = CloseEnhMetaFile (dc);
+  DeleteEnhMetaFile (metafile);
+  
+  ShellExecuteW (NULL, L"open", (gunichar2 *)filename, NULL, NULL, SW_SHOW);
+}
 
-  _gtk_print_operation_platform_backend_run_dialog (op, parent, &do_print, NULL);
-  if (do_print)
-    print_cb (op, parent, FALSE);
-  else
-    _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
+void
+_gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op,
+                                                         cairo_surface_t *surface,
+                                                         cairo_t *cr)
+{
+  HDC dc = cairo_win32_surface_get_dc (surface);
+  StartPage (dc);
+}
+
+void
+_gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op,
+                                                       cairo_surface_t *surface,
+                                                       cairo_t *cr)
+{
+  /* TODO: This doesn't actually seem to work.
+   * Do enhanced metafiles really support multiple pages?
+   */
+  HDC dc = cairo_win32_surface_get_dc (surface);
+  EndPage (dc);
+}
+
+cairo_surface_t *
+_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
+                                                             GtkPageSetup      *page_setup,
+                                                             gdouble           *dpi_x,
+                                                             gdouble           *dpi_y,
+                                                             gchar            **target)
+{
+  GtkPaperSize *paper_size;
+  double w, h;
+  HDC metafile_dc;
+  RECT rect;
+  char *template;
+  char *filename;
+  gunichar2 *filename_utf16;
+  int fd;
+
+  template = g_build_filename (g_get_tmp_dir (), "prXXXXXX", NULL);
+  fd = g_mkstemp (template);
+  close(fd);
+
+  filename = g_strconcat (template, ".emf", NULL);
+  g_free (template);
+  
+  filename_utf16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+  g_free (filename);
+
+  paper_size = gtk_page_setup_get_paper_size (page_setup);
+  w = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM);
+  h = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM);
+  
+  rect.left = 0;
+  rect.right = w*100;
+  rect.top = 0;
+  rect.bottom = h*100;
+  
+  metafile_dc = CreateEnhMetaFileW (NULL, filename_utf16,
+                                   &rect, L"Gtk+\0Print Preview\0\0");
+  if (metafile_dc == NULL)
+    {
+      g_warning ("Can't create metafile");
+      return NULL;
+    }
+
+  *target = (char *)filename_utf16;
+  
+  *dpi_x = (double)GetDeviceCaps (metafile_dc, LOGPIXELSX);
+  *dpi_y = (double)GetDeviceCaps (metafile_dc, LOGPIXELSY);
+
+  return cairo_win32_surface_create (metafile_dc);
+}
+
+void
+_gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op,
+                                                             GtkPageSetup      *page_setup,
+                                                             cairo_surface_t   *surface)
+{
+  /* TODO: Implement */
 }
 
 GtkPageSetup *
@@ -1767,3 +1909,6 @@ gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
   done_cb (new_page_setup, data);
   g_object_unref (new_page_setup);
 }
+
+#define __GTK_PRINT_OPERATION_WIN32_C__
+#include "gtkaliasdef.c"