]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkprintoperation-win32.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkprintoperation-win32.c
index c546ea4c835c9ed9ae061f416336779fed0b43f7..04de8ebbeb178f44d8bd7d2db460199f96162a74 100644 (file)
@@ -13,9 +13,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _MSC_VER
 #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 <windows.h>
 #include <cairo-win32.h>
 #include <glib.h>
 #include "gtkprintoperation-private.h"
@@ -35,7 +39,6 @@
 #include "gtkinvisible.h"
 #include "gtkplug.h"
 #include "gtkstock.h"
-#include "gtkalias.h"
 #include "gtk.h"
 #include "gtkwin32embedwidget.h"
 
@@ -58,6 +61,7 @@ typedef struct {
   int job_id;
   guint timeout_id;
 
+  cairo_surface_t *surface;
   GtkWidget *embed_widget;
 } GtkPrintOperationWin32;
 
@@ -65,6 +69,7 @@ static void win32_poll_status (GtkPrintOperation *op);
 
 static const GUID myIID_IPrintDialogCallback  = {0x5852a2c3,0x6530,0x11d1,{0xb6,0xa3,0x0,0x0,0xf8,0x75,0x7b,0xf9}};
 
+#if !defined (_MSC_VER) && !defined (HAVE_IPRINTDIALOGCALLBACK)
 #undef INTERFACE
 #define INTERFACE IPrintDialogCallback
 DECLARE_INTERFACE_ (IPrintDialogCallback, IUnknown)
@@ -76,6 +81,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;
 
@@ -407,6 +413,42 @@ paper_size_to_win32 (GtkPaperSize *paper_size)
   return 0;
 }
 
+static gchar*
+get_default_printer (void)
+{
+  wchar_t *win32_printer_name = NULL;
+  gchar *printer_name = NULL;
+  DWORD needed;
+
+  GetDefaultPrinterW (NULL, &needed);
+  win32_printer_name = g_malloc ((gsize) needed * sizeof (wchar_t));
+  if (!GetDefaultPrinterW (win32_printer_name, &needed))
+    {
+      g_free (win32_printer_name);
+      return NULL;
+    }
+  printer_name = g_utf16_to_utf8 (win32_printer_name, -1, NULL, NULL, NULL);
+  g_free (win32_printer_name);
+
+  return printer_name;
+}
+
+static void
+set_hard_margins (GtkPrintOperation *op)
+{
+  double top, bottom, left, right;
+  GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
+
+  top = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETY);
+  bottom = GetDeviceCaps (op_win32->hdc, PHYSICALHEIGHT)
+      - GetDeviceCaps (op_win32->hdc, VERTRES) - top;
+  left = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETX);
+  right = GetDeviceCaps (op_win32->hdc, PHYSICALWIDTH)
+      - GetDeviceCaps (op_win32->hdc, HORZRES) - left;
+
+  _gtk_print_context_set_hard_margins (op->priv->print_context, top, bottom, left, right);
+}
+
 void
 win32_start_page (GtkPrintOperation *op,
                  GtkPrintContext *print_context,
@@ -415,6 +457,7 @@ win32_start_page (GtkPrintOperation *op,
   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
   LPDEVMODEW devmode;
   GtkPaperSize *paper_size;
+  double x_off, y_off;
 
   devmode = GlobalLock (op_win32->devmode);
   
@@ -430,6 +473,8 @@ win32_start_page (GtkPrintOperation *op,
     {
       devmode->dmPaperSize = DMPAPER_USER;
       devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
+
+      /* Lengths in DEVMODE are in tenths of a millimeter */
       devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) * 10.0;
       devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) * 10.0;
     }
@@ -437,6 +482,11 @@ win32_start_page (GtkPrintOperation *op,
   ResetDCW (op_win32->hdc, devmode);
   
   GlobalUnlock (op_win32->devmode);
+
+  set_hard_margins (op);
+  x_off = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETX);
+  y_off = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETY);
+  cairo_surface_set_device_offset (op_win32->surface, -x_off, -y_off);
   
   StartPage (op_win32->hdc);
 }
@@ -446,6 +496,9 @@ win32_end_page (GtkPrintOperation *op,
                GtkPrintContext *print_context)
 {
   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
+
+  cairo_surface_show_page (op_win32->surface);
+
   EndPage (op_win32->hdc);
 }
 
@@ -461,7 +514,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);
@@ -477,6 +530,8 @@ win32_end_run (GtkPrintOperation *op,
   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
   LPDEVNAMES devnames;
   HANDLE printerHandle = 0;
+
+  cairo_surface_finish (op_win32->surface);
   
   EndDoc (op_win32->hdc);
 
@@ -489,20 +544,19 @@ win32_end_run (GtkPrintOperation *op,
       GlobalUnlock (op_win32->devnames);
     }
   
-  GlobalFree(op_win32->devmode);
-  GlobalFree(op_win32->devnames);
+  GlobalFree (op_win32->devmode);
+  GlobalFree (op_win32->devnames);
 
-  cairo_surface_finish (op->priv->surface);
-  cairo_surface_destroy (op->priv->surface);
-  op->priv->surface = NULL;
+  cairo_surface_destroy (op_win32->surface);
+  op_win32->surface = NULL;
 
-  DeleteDC(op_win32->hdc);
+  DeleteDC (op_win32->hdc);
   
   if (printerHandle != 0)
     {
       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);
     }
@@ -531,8 +585,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, 
@@ -598,7 +653,7 @@ static HWND
 get_parent_hwnd (GtkWidget *widget)
 {
   gtk_widget_realize (widget);
-  return gdk_win32_drawable_get_handle (widget->window);
+  return gdk_win32_window_get_handle (gtk_widget_get_window (widget));
 }
 
 static void
@@ -658,18 +713,19 @@ devmode_to_settings (GtkPrintSettings *settings,
                                     -1, NULL, NULL, NULL);
       if (form_name == NULL || form_name[0] == 0)
        form_name = g_strdup (_("Custom size"));
+
+      /* Lengths in DEVMODE are in tenths of a millimeter */
       paper_size = gtk_paper_size_new_custom (form_name,
                                              form_name,
-                                             devmode->dmPaperWidth * 10.0,
-                                             devmode->dmPaperLength * 10.0,
+                                             devmode->dmPaperWidth / 10.0,
+                                             devmode->dmPaperLength / 10.0,
                                              GTK_UNIT_MM);
       gtk_print_settings_set_paper_size (settings, paper_size);
       gtk_paper_size_free (paper_size);
     }
   
   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,
@@ -749,7 +805,7 @@ devmode_to_settings (GtkPrintSettings *settings,
     }
   
   if (devmode->dmFields & DM_COLOR)
-    gtk_print_settings_set_use_color (settings, devmode->dmFields == DMCOLOR_COLOR);
+    gtk_print_settings_set_use_color (settings, devmode->dmColor == DMCOLOR_COLOR);
   
   if (devmode->dmFields & DM_DUPLEX)
     {
@@ -831,7 +887,7 @@ static void
 dialog_to_print_settings (GtkPrintOperation *op,
                          LPPRINTDLGEXW printdlgex)
 {
-  int i;
+  guint i;
   GtkPrintSettings *settings;
 
   settings = gtk_print_settings_new ();
@@ -903,8 +959,8 @@ devmode_from_settings (GtkPrintSettings *settings,
     {
       devmode->dmDriverExtra = extras_len;
       memcpy (((char *)devmode) + sizeof (DEVMODEW), extras, extras_len);
-      g_free (extras);
     }
+  g_free (extras);
   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION))
     devmode->dmDriverVersion = gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION);
   
@@ -941,8 +997,10 @@ devmode_from_settings (GtkPrintSettings *settings,
        {
          devmode->dmPaperSize = DMPAPER_USER;
          devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
-         devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) / 10.0;
-         devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) / 10.0;
+
+          /* Lengths in DEVMODE are in tenths of a millimeter */
+         devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) * 10.0;
+         devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) * 10.0;
        }
       gtk_paper_size_free (paper_size);
     }
@@ -950,7 +1008,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))
@@ -1160,7 +1218,7 @@ dialog_from_print_settings (GtkPrintOperation *op,
   
   printer = gtk_print_settings_get_printer (settings);
   if (printer)
-    printdlgex->hDevNames = gtk_print_win32_devnames_from_printer_name (printer);
+    printdlgex->hDevNames = gtk_print_win32_devnames_to_win32_from_printer_name (printer);
   
   printdlgex->hDevMode = devmode_from_settings (settings,
                                                op->priv->default_page_setup);
@@ -1279,8 +1337,8 @@ plug_grab_notify (GtkWidget        *widget,
                  gboolean          was_grabbed,
                  GtkPrintOperation *op)
 {
-  EnableWindow(GetAncestor (GDK_WINDOW_HWND (widget->window), GA_ROOT),
-              was_grabbed);
+  EnableWindow (GetAncestor (GDK_WINDOW_HWND (gtk_widget_get_window (widget)), GA_ROOT),
+               was_grabbed);
 }
 
 
@@ -1298,14 +1356,15 @@ pageDlgProc (HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
       op = GTK_PRINT_OPERATION ((gpointer)page->lParam);
       op_win32 = op->priv->platform_data;
 
-      SetWindowLongPtrW(wnd, GWLP_USERDATA, (LONG_PTR)op);
+      SetWindowLongPtrW (wnd, GWLP_USERDATA, (LONG_PTR)op);
       
-      plug = _gtk_win32_embed_widget_new ((GdkNativeWindow) wnd);
+      plug = _gtk_win32_embed_widget_new (wnd);
+      gtk_window_set_modal (GTK_WINDOW (plug), TRUE);
       op_win32->embed_widget = plug;
       gtk_container_add (GTK_CONTAINER (plug), op->priv->custom_widget);
       gtk_widget_show (op->priv->custom_widget);
       gtk_widget_show (plug);
-      gdk_window_focus (plug->window, GDK_CURRENT_TIME);
+      gdk_window_focus (gtk_widget_get_window (plug), GDK_CURRENT_TIME);
 
       /* This dialog is modal, so we grab the embed widget */
       gtk_grab_add (plug);
@@ -1316,7 +1375,7 @@ pageDlgProc (HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
     }
   else if (message == WM_DESTROY)
     {
-      op = GTK_PRINT_OPERATION (GetWindowLongPtrW(wnd, GWLP_USERDATA));
+      op = GTK_PRINT_OPERATION (GetWindowLongPtrW (wnd, GWLP_USERDATA));
       op_win32 = op->priv->platform_data;
       
       g_signal_emit_by_name (op, "custom-widget-apply", op->priv->custom_widget);
@@ -1326,7 +1385,7 @@ pageDlgProc (HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
     }
   else 
     {
-      op = GTK_PRINT_OPERATION (GetWindowLongPtrW(wnd, GWLP_USERDATA));
+      op = GTK_PRINT_OPERATION (GetWindowLongPtrW (wnd, GWLP_USERDATA));
       op_win32 = op->priv->platform_data;
 
       return _gtk_win32_embed_widget_dialog_procedure (GTK_WIN32_EMBED_WIDGET (op_win32->embed_widget),
@@ -1347,45 +1406,49 @@ create_application_page (GtkPrintOperation *op)
   WORD baseunitX, baseunitY;
   WORD *array;
   GtkRequisition requisition;
-  const char *app_name;
+  const char *tab_label;
 
   /* Make the template the size of the custom widget size request */
-  gtk_widget_size_request (op->priv->custom_widget, &requisition);
-      
-  base_units = GetDialogBaseUnits();
-  baseunitX = LOWORD(base_units);
-  baseunitY = HIWORD(base_units);
+  gtk_widget_get_preferred_size (op->priv->custom_widget,
+                                 &requisition, NULL);
+
+  base_units = GetDialogBaseUnits ();
+  baseunitX = LOWORD (base_units);
+  baseunitY = HIWORD (base_units);
   
   htemplate = GlobalAlloc (GMEM_MOVEABLE, 
-                          sizeof (DLGTEMPLATE) + sizeof(WORD) * 3);
+                          sizeof (DLGTEMPLATE) + sizeof (WORD) * 3);
   template = GlobalLock (htemplate);
   template->style = WS_CHILDWINDOW | DS_CONTROL;
   template->dwExtendedStyle = WS_EX_CONTROLPARENT;
   template->cdit = 0;
-  template->x = MulDiv(0, 4, baseunitX);
-  template->y = MulDiv(0, 8, baseunitY);
-  template->cx = MulDiv(requisition.width, 4, baseunitX);
-  template->cy = MulDiv(requisition.height, 8, baseunitY);
+  template->x = MulDiv (0, 4, baseunitX);
+  template->y = MulDiv (0, 8, baseunitY);
+  template->cx = MulDiv (requisition.width, 4, baseunitX);
+  template->cy = MulDiv (requisition.height, 8, baseunitY);
   
   array = (WORD *) (template+1);
   *array++ = 0; /* menu */
   *array++ = 0; /* class */
   *array++ = 0; /* title */
   
-  memset(&page, 0, sizeof (page));
+  memset (&page, 0, sizeof (page));
   page.dwSize = sizeof (page);
   page.dwFlags = PSP_DLGINDIRECT | PSP_USETITLE | PSP_PREMATURE;
   page.hInstance = GetModuleHandle (NULL);
   page.pResource = template;
-  app_name = g_get_application_name ();
-  if (app_name == NULL)
-    app_name = _("Application");
-  page.pszTitle = g_utf8_to_utf16 (app_name, 
+  
+  tab_label = op->priv->custom_tab_label;
+  if (tab_label == NULL)
+    tab_label = g_get_application_name ();
+  if (tab_label == NULL)
+    tab_label = _("Application");
+  page.pszTitle = g_utf8_to_utf16 (tab_label, 
                                   -1, NULL, NULL, NULL);
   page.pfnDlgProc = pageDlgProc;
   page.pfnCallback = NULL;
   page.lParam = (LPARAM) op;
-  hpage = CreatePropertySheetPageW(&page);
+  hpage = CreatePropertySheetPageW (&page);
   
   GlobalUnlock (htemplate);
   
@@ -1394,11 +1457,193 @@ 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,
-                                                 GtkWindow *parent,
-                                                 gboolean *do_print,
-                                                 GError **error)
+gtk_print_operation_run_without_dialog (GtkPrintOperation *op,
+                                       gboolean          *do_print)
+{
+  GtkPrintOperationResult result;
+  GtkPrintOperationWin32 *op_win32;
+  GtkPrintOperationPrivate *priv;
+  GtkPrintSettings *settings;
+  GtkPageSetup *page_setup;
+  DOCINFOW docinfo;
+  HGLOBAL hDevMode = NULL;
+  HGLOBAL hDevNames = NULL;
+  HDC hDC = NULL;
+  const char *printer = NULL;
+  double dpi_x, dpi_y;
+  int job_id;
+  cairo_t *cr;
+  DEVNAMES *pdn;
+  DEVMODEW *pdm;
+
+  *do_print = FALSE;
+
+  priv = op->priv;
+  settings = priv->print_settings;
+  
+  op_win32 = g_new0 (GtkPrintOperationWin32, 1);
+  priv->platform_data = op_win32;
+  priv->free_platform_data = (GDestroyNotify) op_win32_free;
+  printer = gtk_print_settings_get_printer (settings);
+
+  if (!printer)
+    {
+      /* No printer selected. Get the system default printer and store
+       * it in settings.
+       */
+      gchar *tmp_printer = get_default_printer ();
+      if (!tmp_printer)
+       {
+         result = GTK_PRINT_OPERATION_RESULT_ERROR;
+         g_set_error_literal (&priv->error,
+                              GTK_PRINT_ERROR,
+                              GTK_PRINT_ERROR_INTERNAL_ERROR,
+                              _("No printer found"));
+         goto out;
+       }
+      gtk_print_settings_set_printer (settings, tmp_printer);
+      printer = gtk_print_settings_get_printer (settings);
+      g_free (tmp_printer);
+    }
+
+  hDevNames = gtk_print_win32_devnames_to_win32_from_printer_name (printer);
+  hDevMode = devmode_from_settings (settings, op->priv->default_page_setup);
+
+  /* Create a printer DC for the print settings and page setup provided. */
+  pdn = GlobalLock (hDevNames);
+  pdm = GlobalLock (hDevMode);
+  hDC = CreateDCW ((wchar_t*)pdn + pdn->wDriverOffset,
+                  (wchar_t*)pdn + pdn->wDeviceOffset,
+                  (wchar_t*)pdn + pdn->wOutputOffset,
+                  pdm );
+  GlobalUnlock (hDevNames);
+  GlobalUnlock (hDevMode);
+
+  if (!hDC)
+    {
+      result = GTK_PRINT_OPERATION_RESULT_ERROR;
+      g_set_error_literal (&priv->error,
+                          GTK_PRINT_ERROR,
+                          GTK_PRINT_ERROR_INTERNAL_ERROR,
+                          _("Invalid argument to CreateDC"));
+      goto out;
+    }
+  
+  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_win32->surface = cairo_win32_printing_surface_create (hDC);
+  dpi_x = (double) GetDeviceCaps (hDC, LOGPIXELSX);
+  dpi_y = (double) GetDeviceCaps (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);
+
+  set_hard_margins (op);
+
+  memset (&docinfo, 0, sizeof (DOCINFOW));
+  docinfo.cbSize = sizeof (DOCINFOW); 
+  docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL); 
+  docinfo.lpszOutput = NULL; 
+  docinfo.lpszDatatype = NULL; 
+  docinfo.fwType = 0; 
+
+  job_id = StartDocW (hDC, &docinfo); 
+  g_free ((void *)docinfo.lpszDocName);
+  if (job_id <= 0)
+    { 
+      result = GTK_PRINT_OPERATION_RESULT_ERROR;
+      g_set_error_literal (&priv->error,
+                          GTK_PRINT_ERROR,
+                          GTK_PRINT_ERROR_GENERAL,
+                          _("Error from StartDoc"));
+      *do_print = FALSE;
+      cairo_surface_destroy (op_win32->surface);
+      op_win32->surface = NULL;
+      goto out; 
+    }
+
+  result = GTK_PRINT_OPERATION_RESULT_APPLY;
+  op_win32->hdc = hDC;
+  op_win32->devmode = hDevMode;
+  op_win32->devnames = hDevNames;
+  op_win32->job_id = job_id;
+  op->priv->print_pages = gtk_print_settings_get_print_pages (op->priv->print_settings);
+  op->priv->num_page_ranges = 0;
+  if (op->priv->print_pages == GTK_PRINT_PAGES_RANGES)
+    op->priv->page_ranges = gtk_print_settings_get_page_ranges (op->priv->print_settings,
+                                                               &op->priv->num_page_ranges);
+  op->priv->manual_num_copies = 1;
+  op->priv->manual_collation = FALSE;
+  op->priv->manual_reverse = FALSE;
+  op->priv->manual_orientation = FALSE;
+  op->priv->manual_scale = 1.0;
+  op->priv->manual_page_set = GTK_PAGE_SET_ALL;
+  op->priv->manual_number_up = 1;
+  op->priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
+
+  op->priv->start_page = win32_start_page;
+  op->priv->end_page = win32_end_page;
+  op->priv->end_run = win32_end_run;
+  
+ out:
+  if (!*do_print && hDC != NULL)
+    DeleteDC (hDC);
+
+  if (!*do_print && hDevMode != NULL)
+    GlobalFree (hDevMode);
+
+  if (!*do_print && hDevNames != NULL)
+    GlobalFree (hDevNames);
+
+  return result;
+}
+
+GtkPrintOperationResult
+gtk_print_operation_run_with_dialog (GtkPrintOperation *op,
+                                    GtkWindow         *parent,
+                                    gboolean          *do_print)
 {
   HRESULT hResult;
   LPPRINTDLGEXW printdlgex = NULL;
@@ -1407,14 +1652,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)
     {
@@ -1428,14 +1676,14 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
   if (!printdlgex)
     {
       result = GTK_PRINT_OPERATION_RESULT_ERROR;
-      g_set_error (error,
-                  GTK_PRINT_ERROR,
-                  GTK_PRINT_ERROR_NOMEM,
-                  _("Not enough free memory"));
+      g_set_error_literal (&priv->error,
+                           GTK_PRINT_ERROR,
+                           GTK_PRINT_ERROR_NOMEM,
+                           _("Not enough free memory"));
       goto out;
     }      
 
-  printdlgex->lStructSize = sizeof(PRINTDLGEXW);
+  printdlgex->lStructSize = sizeof (PRINTDLGEXW);
   printdlgex->hwndOwner = parentHWnd;
   printdlgex->hDevMode = NULL;
   printdlgex->hDevNames = NULL;
@@ -1451,10 +1699,10 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
   if (!page_ranges) 
     {
       result = GTK_PRINT_OPERATION_RESULT_ERROR;
-      g_set_error (error,
-                  GTK_PRINT_ERROR,
-                  GTK_PRINT_ERROR_NOMEM,
-                  _("Not enough free memory"));
+      g_set_error_literal (&priv->error,
+                           GTK_PRINT_ERROR,
+                           GTK_PRINT_ERROR_NOMEM,
+                           _("Not enough free memory"));
       goto out;
     }
 
@@ -1491,7 +1739,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
   printdlgex->lpCallback = (IUnknown *)callback;
   got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
 
-  hResult = PrintDlgExW(printdlgex);
+  hResult = PrintDlgExW (printdlgex);
   IUnknown_Release ((IUnknown *)callback);
   gdk_win32_set_modal_dialog_libgtk_only (NULL);
 
@@ -1499,30 +1747,30 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
     {
       result = GTK_PRINT_OPERATION_RESULT_ERROR;
       if (hResult == E_OUTOFMEMORY)
-       g_set_error (error,
-                    GTK_PRINT_ERROR,
-                    GTK_PRINT_ERROR_NOMEM,
-                    _("Not enough free memory"));
+       g_set_error_literal (&priv->error,
+                             GTK_PRINT_ERROR,
+                             GTK_PRINT_ERROR_NOMEM,
+                             _("Not enough free memory"));
       else if (hResult == E_INVALIDARG)
-       g_set_error (error,
-                    GTK_PRINT_ERROR,
-                    GTK_PRINT_ERROR_INTERNAL_ERROR,
-                    _("Invalid argument to PrintDlgEx"));
+       g_set_error_literal (&priv->error,
+                             GTK_PRINT_ERROR,
+                             GTK_PRINT_ERROR_INTERNAL_ERROR,
+                             _("Invalid argument to PrintDlgEx"));
       else if (hResult == E_POINTER)
-       g_set_error (error,
-                    GTK_PRINT_ERROR,
-                    GTK_PRINT_ERROR_INTERNAL_ERROR,
-                    _("Invalid pointer to PrintDlgEx"));
+       g_set_error_literal (&priv->error,
+                             GTK_PRINT_ERROR,
+                             GTK_PRINT_ERROR_INTERNAL_ERROR,
+                             _("Invalid pointer to PrintDlgEx"));
       else if (hResult == E_HANDLE)
-       g_set_error (error,
-                    GTK_PRINT_ERROR,
-                    GTK_PRINT_ERROR_INTERNAL_ERROR,
-                    _("Invalid handle to PrintDlgEx"));
+       g_set_error_literal (&priv->error,
+                             GTK_PRINT_ERROR,
+                             GTK_PRINT_ERROR_INTERNAL_ERROR,
+                             _("Invalid handle to PrintDlgEx"));
       else /* E_FAIL */
-       g_set_error (error,
-                    GTK_PRINT_ERROR,
-                    GTK_PRINT_ERROR_GENERAL,
-                    _("Unspecified error"));
+       g_set_error_literal (&priv->error,
+                             GTK_PRINT_ERROR,
+                             GTK_PRINT_ERROR_GENERAL,
+                             _("Unspecified error"));
       goto out;
     }
 
@@ -1539,32 +1787,47 @@ _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_printing_surface_create (printdlgex->hDC);
 
-      memset( &docinfo, 0, sizeof (DOCINFOW));
+      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);
+
+      set_hard_margins (op);
+
+      memset ( &docinfo, 0, sizeof (DOCINFOW));
       docinfo.cbSize = sizeof (DOCINFOW); 
       docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL); 
       docinfo.lpszOutput = (LPCWSTR) NULL; 
       docinfo.lpszDatatype = (LPCWSTR) NULL; 
       docinfo.fwType = 0; 
 
-      job_id = StartDocW(printdlgex->hDC, &docinfo); 
+      job_id = StartDocW (printdlgex->hDC, &docinfo); 
       g_free ((void *)docinfo.lpszDocName);
       if (job_id <= 0) 
-       { 
+       {
          result = GTK_PRINT_OPERATION_RESULT_ERROR;
-         g_set_error (error,
-                      GTK_PRINT_ERROR,
-                      GTK_PRINT_ERROR_GENERAL,
-                    _("Error from StartDoc"));
+         g_set_error_literal (&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; 
        } 
       
@@ -1584,6 +1847,8 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
       op->priv->manual_orientation = FALSE;
       op->priv->manual_scale = 1.0;
       op->priv->manual_page_set = GTK_PAGE_SET_ALL;
+      op->priv->manual_number_up = 1;
+      op->priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
     }
 
   op->priv->start_page = win32_start_page;
@@ -1591,11 +1856,14 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
   op->priv->end_run = win32_end_run;
   
   out:
+  if (!*do_print && printdlgex && printdlgex->hDC != NULL)
+    DeleteDC (printdlgex->hDC);
+
   if (!*do_print && printdlgex && printdlgex->hDevMode != NULL) 
-    GlobalFree(printdlgex->hDevMode); 
+    GlobalFree (printdlgex->hDevMode); 
 
   if (!*do_print && printdlgex && printdlgex->hDevNames != NULL) 
-    GlobalFree(printdlgex->hDevNames); 
+    GlobalFree (printdlgex->hDevNames); 
 
   if (page_ranges)
     GlobalFree (page_ranges);
@@ -1609,18 +1877,114 @@ _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)
+GtkPrintOperationResult
+_gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
+                                                 gboolean           show_dialog,
+                                                 GtkWindow         *parent,
+                                                 gboolean          *do_print)
 {
-  gboolean do_print;
-
-  _gtk_print_operation_platform_backend_run_dialog (op, parent, &do_print, NULL);
-  if (do_print)
-    print_cb (op, parent, FALSE);
+  if (show_dialog)
+    return gtk_print_operation_run_with_dialog (op, parent, do_print);
   else
-    _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
+    return gtk_print_operation_run_without_dialog (op, do_print);
+}
+
+void
+_gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
+                                                     cairo_surface_t   *surface,
+                                                     GtkWindow         *parent,
+                                                     const gchar       *filename)
+{
+  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);
+}
+
+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)
+{
+  HDC dc;
+
+  cairo_surface_show_page (surface);
+
+  /* TODO: Enhanced metafiles don't support multiple pages.
+   */
+  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;
+  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);
+
+  /* The rectangle dimensions are given in hundredths of a millimeter */
+  rect.left = 0;
+  rect.right = 100.0 * gtk_paper_size_get_width (paper_size, GTK_UNIT_MM);
+  rect.top = 0;
+  rect.bottom = 100.0 * gtk_paper_size_get_height (paper_size, GTK_UNIT_MM);
+  
+  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_printing_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 *
@@ -1650,7 +2014,7 @@ gtk_print_run_page_setup_dialog (GtkWindow        *parent,
   
   memset (pagesetupdlg, 0, sizeof (PAGESETUPDLGW));
 
-  pagesetupdlg->lStructSize = sizeof(PAGESETUPDLGW);
+  pagesetupdlg->lStructSize = sizeof (PAGESETUPDLGW);
 
   if (parent != NULL)
     pagesetupdlg->hwndOwner = get_parent_hwnd (GTK_WIDGET (parent));
@@ -1662,10 +2026,10 @@ gtk_print_run_page_setup_dialog (GtkWindow        *parent,
   pagesetupdlg->hDevNames = NULL;
   printer = gtk_print_settings_get_printer (settings);
   if (printer)
-    pagesetupdlg->hDevNames = gtk_print_win32_devnames_from_printer_name (printer);
+    pagesetupdlg->hDevNames = gtk_print_win32_devnames_to_win32_from_printer_name (printer);
 
-  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE|LOCALE_RETURN_NUMBER,
-                (LPWSTR)&measure_system, sizeof (DWORD));
+  GetLocaleInfoW (LOCALE_USER_DEFAULT, LOCALE_IMEASURE|LOCALE_RETURN_NUMBER,
+                 (LPWSTR)&measure_system, sizeof (DWORD));
 
   if (measure_system == 0)
     {
@@ -1713,9 +2077,6 @@ gtk_print_run_page_setup_dialog (GtkWindow        *parent,
        devmode_to_settings (settings, pagesetupdlg->hDevMode);
     }
   
-  if (free_settings)
-    g_object_unref (settings);
-
   if (res)
     {
       gtk_page_setup_set_orientation (page_setup, 
@@ -1752,6 +2113,9 @@ gtk_print_run_page_setup_dialog (GtkWindow        *parent,
                                        unit);
     }
   
+  if (free_settings)
+    g_object_unref (settings);
+
   return page_setup;
 }