]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintoperation-win32.c
Fix 32-bit Windows build using mingw-w64 toolchain
[~andy/gtk] / gtk / gtkprintoperation-win32.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintoperation-win32.c: Print Operation Details for Win32
3  * Copyright (C) 2006, Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifndef _MSC_VER
22 #define _WIN32_WINNT 0x0500
23 #define WINVER _WIN32_WINNT
24 #endif
25
26 #define COBJMACROS
27 #include "config.h"
28 #include <math.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #include <io.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <windows.h>
36 #include <cairo-win32.h>
37 #include <glib.h>
38 #include "gtkprintoperation-private.h"
39 #include "gtkprint-win32.h"
40 #include "gtkintl.h"
41 #include "gtkinvisible.h"
42 #include "gtkplug.h"
43 #include "gtkstock.h"
44 #include "gtk.h"
45 #include "gtkwin32embedwidget.h"
46
47 #define MAX_PAGE_RANGES 20
48 #define STATUS_POLLING_TIME 2000
49
50 #ifndef JOB_STATUS_RESTART
51 #define JOB_STATUS_RESTART 0x800
52 #endif
53
54 #ifndef JOB_STATUS_COMPLETE
55 #define JOB_STATUS_COMPLETE 0x1000
56 #endif
57
58 typedef struct {
59   HDC hdc;
60   HGLOBAL devmode;
61   HGLOBAL devnames;
62   HANDLE printerHandle;
63   int job_id;
64   guint timeout_id;
65
66   cairo_surface_t *surface;
67   GtkWidget *embed_widget;
68 } GtkPrintOperationWin32;
69
70 static void win32_poll_status (GtkPrintOperation *op);
71
72 static const GUID myIID_IPrintDialogCallback  = {0x5852a2c3,0x6530,0x11d1,{0xb6,0xa3,0x0,0x0,0xf8,0x75,0x7b,0xf9}};
73
74 #if !defined (_MSC_VER) && !defined (__MINGW64_VERSION_MAJOR)
75 #undef INTERFACE
76 #define INTERFACE IPrintDialogCallback
77 DECLARE_INTERFACE_ (IPrintDialogCallback, IUnknown)
78 {
79     STDMETHOD (QueryInterface)(THIS_ REFIID,LPVOID*) PURE;
80     STDMETHOD_ (ULONG, AddRef)(THIS) PURE;
81     STDMETHOD_ (ULONG, Release)(THIS) PURE;
82     STDMETHOD (InitDone)(THIS) PURE;
83     STDMETHOD (SelectionChange)(THIS) PURE;
84     STDMETHOD (HandleMessage)(THIS_ HWND,UINT,WPARAM,LPARAM,LRESULT*) PURE;
85 }; 
86 #endif
87
88 static UINT got_gdk_events_message;
89
90 UINT_PTR CALLBACK
91 run_mainloop_hook (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
92 {
93   if (uiMsg == WM_INITDIALOG)
94     {
95       gdk_win32_set_modal_dialog_libgtk_only (hdlg);
96       while (gtk_events_pending ())
97         gtk_main_iteration ();
98     }
99   else if (uiMsg == got_gdk_events_message)
100     {
101       while (gtk_events_pending ())
102         gtk_main_iteration ();
103       return 1;
104     }
105   return 0;
106 }
107
108 static GtkPageOrientation
109 orientation_from_win32 (short orientation)
110 {
111   if (orientation == DMORIENT_LANDSCAPE)
112     return GTK_PAGE_ORIENTATION_LANDSCAPE;
113   return GTK_PAGE_ORIENTATION_PORTRAIT;
114 }
115
116 static short
117 orientation_to_win32 (GtkPageOrientation orientation)
118 {
119   if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE ||
120       orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE)
121     return DMORIENT_LANDSCAPE;
122   return DMORIENT_PORTRAIT;
123 }
124
125 static GtkPaperSize *
126 paper_size_from_win32 (short size)
127 {
128   const char *name;
129   
130   switch (size)
131     {
132     case DMPAPER_LETTER_TRANSVERSE:
133     case DMPAPER_LETTER:
134     case DMPAPER_LETTERSMALL:
135       name = "na_letter";
136       break;
137     case DMPAPER_TABLOID:
138     case DMPAPER_LEDGER:
139       name = "na_ledger";
140       break;
141     case DMPAPER_LEGAL:
142       name = "na_legal";
143       break;
144     case DMPAPER_STATEMENT:
145       name = "na_invoice";
146       break;
147     case DMPAPER_EXECUTIVE:
148       name = "na_executive";
149       break;
150     case DMPAPER_A3:
151     case DMPAPER_A3_TRANSVERSE:
152       name = "iso_a3";
153       break;
154     case DMPAPER_A4:
155     case DMPAPER_A4SMALL:
156     case DMPAPER_A4_TRANSVERSE:
157       name = "iso_a4";
158       break;
159     case DMPAPER_A5:
160     case DMPAPER_A5_TRANSVERSE:
161       name = "iso_a5";
162       break;
163     case DMPAPER_B4:
164       name = "jis_b4";
165       break;
166     case DMPAPER_B5:
167     case DMPAPER_B5_TRANSVERSE:
168       name = "jis_b5";
169       break;
170     case DMPAPER_QUARTO:
171       name = "na_quarto";
172       break;
173     case DMPAPER_10X14:
174       name = "na_10x14";
175       break;
176     case DMPAPER_11X17:
177       name = "na_ledger";
178       break;
179     case DMPAPER_NOTE:
180       name = "na_letter";
181       break;
182     case DMPAPER_ENV_9:
183       name = "na_number-9";
184       break;
185     case DMPAPER_ENV_10:
186       name = "na_number-10";
187       break;
188     case DMPAPER_ENV_11:
189       name = "na_number-11";
190       break;
191     case DMPAPER_ENV_12:
192       name = "na_number-12";
193       break;
194     case DMPAPER_ENV_14:
195       name = "na_number-14";
196       break;
197     case DMPAPER_CSHEET:
198       name = "na_c";
199       break;
200     case DMPAPER_DSHEET:
201       name = "na_d";
202       break;
203     case DMPAPER_ESHEET:
204       name = "na_e";
205       break;
206     case DMPAPER_ENV_DL:
207       name = "iso_dl";
208       break;
209     case DMPAPER_ENV_C5:
210       name = "iso_c5";
211       break;
212     case DMPAPER_ENV_C3:
213       name = "iso_c3";
214       break;
215     case DMPAPER_ENV_C4:
216       name = "iso_c4";
217       break;
218     case DMPAPER_ENV_C6:
219       name = "iso_c6";
220       break;
221     case DMPAPER_ENV_C65:
222       name = "iso_c6c5";
223       break;
224     case DMPAPER_ENV_B4:
225       name = "iso_b4";
226       break;
227     case DMPAPER_ENV_B5:
228       name = "iso_b5";
229       break;
230     case DMPAPER_ENV_B6:
231       name = "iso_b6";
232       break;
233     case DMPAPER_ENV_ITALY:
234       name = "om_italian";
235       break;
236     case DMPAPER_ENV_MONARCH:
237       name = "na_monarch";
238       break;
239     case DMPAPER_ENV_PERSONAL:
240       name = "na_personal";
241       break;
242     case DMPAPER_FANFOLD_US:
243       name = "na_fanfold-us";
244       break;
245     case DMPAPER_FANFOLD_STD_GERMAN:
246       name = "na_fanfold-eur";
247       break;
248     case DMPAPER_FANFOLD_LGL_GERMAN:
249       name = "na_foolscap";
250       break;
251     case DMPAPER_ISO_B4:
252       name = "iso_b4";
253       break;
254     case DMPAPER_JAPANESE_POSTCARD:
255       name = "jpn_hagaki";
256       break;
257     case DMPAPER_9X11:
258       name = "na_9x11";
259       break;
260     case DMPAPER_10X11:
261       name = "na_10x11";
262       break;
263     case DMPAPER_ENV_INVITE:
264       name = "om_invite";
265        break;
266     case DMPAPER_LETTER_EXTRA:
267     case DMPAPER_LETTER_EXTRA_TRANSVERSE:
268       name = "na_letter-extra";
269       break;
270     case DMPAPER_LEGAL_EXTRA:
271       name = "na_legal-extra";
272       break;
273     case DMPAPER_TABLOID_EXTRA:
274       name = "na_arch";
275       break;
276     case DMPAPER_A4_EXTRA:
277       name = "iso_a4-extra";
278       break;
279     case DMPAPER_B_PLUS:
280       name = "na_b-plus";
281       break;
282     case DMPAPER_LETTER_PLUS:
283       name = "na_letter-plus";
284       break;
285     case DMPAPER_A3_EXTRA:
286     case DMPAPER_A3_EXTRA_TRANSVERSE:
287       name = "iso_a3-extra";
288       break;
289     case DMPAPER_A5_EXTRA:
290       name = "iso_a5-extra";
291       break;
292     case DMPAPER_B5_EXTRA:
293       name = "iso_b5-extra";
294       break;
295     case DMPAPER_A2:
296       name = "iso_a2";
297       break;
298       
299     default:
300       name = NULL;
301       break;
302     }
303
304   if (name)
305     return gtk_paper_size_new (name);
306   else 
307     return NULL;
308 }
309
310 static short
311 paper_size_to_win32 (GtkPaperSize *paper_size)
312 {
313   const char *format;
314
315   if (gtk_paper_size_is_custom (paper_size))
316     return 0;
317   
318   format = gtk_paper_size_get_name (paper_size);
319
320   if (strcmp (format, "na_letter") == 0)
321     return DMPAPER_LETTER;
322   if (strcmp (format, "na_ledger") == 0)
323     return DMPAPER_LEDGER;
324   if (strcmp (format, "na_legal") == 0)
325     return DMPAPER_LEGAL;
326   if (strcmp (format, "na_invoice") == 0)
327     return DMPAPER_STATEMENT;
328   if (strcmp (format, "na_executive") == 0)
329     return DMPAPER_EXECUTIVE;
330   if (strcmp (format, "iso_a2") == 0)
331     return DMPAPER_A2;
332   if (strcmp (format, "iso_a3") == 0)
333     return DMPAPER_A3;
334   if (strcmp (format, "iso_a4") == 0)
335     return DMPAPER_A4;
336   if (strcmp (format, "iso_a5") == 0)
337     return DMPAPER_A5;
338   if (strcmp (format, "iso_b4") == 0)
339     return DMPAPER_B4;
340   if (strcmp (format, "iso_b5") == 0)
341     return DMPAPER_B5;
342   if (strcmp (format, "na_quarto") == 0)
343     return DMPAPER_QUARTO;
344   if (strcmp (format, "na_10x14") == 0)
345     return DMPAPER_10X14;
346   if (strcmp (format, "na_number-9") == 0)
347     return DMPAPER_ENV_9;
348   if (strcmp (format, "na_number-10") == 0)
349     return DMPAPER_ENV_10;
350   if (strcmp (format, "na_number-11") == 0)
351     return DMPAPER_ENV_11;
352   if (strcmp (format, "na_number-12") == 0)
353     return DMPAPER_ENV_12;
354   if (strcmp (format, "na_number-14") == 0)
355     return DMPAPER_ENV_14;
356   if (strcmp (format, "na_c") == 0)
357     return DMPAPER_CSHEET;
358   if (strcmp (format, "na_d") == 0)
359     return DMPAPER_DSHEET;
360   if (strcmp (format, "na_e") == 0)
361     return DMPAPER_ESHEET;
362   if (strcmp (format, "iso_dl") == 0)
363     return DMPAPER_ENV_DL;
364   if (strcmp (format, "iso_c3") == 0)
365     return DMPAPER_ENV_C3;
366   if (strcmp (format, "iso_c4") == 0)
367     return DMPAPER_ENV_C4;
368   if (strcmp (format, "iso_c5") == 0)
369     return DMPAPER_ENV_C5;
370   if (strcmp (format, "iso_c6") == 0)
371     return DMPAPER_ENV_C6;
372   if (strcmp (format, "iso_c5c6") == 0)
373     return DMPAPER_ENV_C65;
374   if (strcmp (format, "iso_b6") == 0)
375     return DMPAPER_ENV_B6;
376   if (strcmp (format, "om_italian") == 0)
377     return DMPAPER_ENV_ITALY;
378   if (strcmp (format, "na_monarch") == 0)
379     return DMPAPER_ENV_MONARCH;
380   if (strcmp (format, "na_personal") == 0)
381     return DMPAPER_ENV_PERSONAL;
382   if (strcmp (format, "na_fanfold-us") == 0)
383     return DMPAPER_FANFOLD_US;
384   if (strcmp (format, "na_fanfold-eur") == 0)
385     return DMPAPER_FANFOLD_STD_GERMAN;
386   if (strcmp (format, "na_foolscap") == 0)
387     return DMPAPER_FANFOLD_LGL_GERMAN;
388   if (strcmp (format, "jpn_hagaki") == 0)
389     return DMPAPER_JAPANESE_POSTCARD;
390   if (strcmp (format, "na_9x11") == 0)
391     return DMPAPER_9X11;
392   if (strcmp (format, "na_10x11") == 0)
393     return DMPAPER_10X11;
394   if (strcmp (format, "om_invite") == 0)
395     return DMPAPER_ENV_INVITE;
396   if (strcmp (format, "na_letter-extra") == 0)
397     return DMPAPER_LETTER_EXTRA;
398   if (strcmp (format, "na_legal-extra") == 0)
399     return DMPAPER_LEGAL_EXTRA;
400   if (strcmp (format, "na_arch") == 0)
401     return DMPAPER_TABLOID_EXTRA;
402   if (strcmp (format, "iso_a3-extra") == 0)
403     return DMPAPER_A3_EXTRA;
404   if (strcmp (format, "iso_a4-extra") == 0)
405     return DMPAPER_A4_EXTRA;
406   if (strcmp (format, "iso_a5-extra") == 0)
407     return DMPAPER_A5_EXTRA;
408   if (strcmp (format, "iso_b5-extra") == 0)
409     return DMPAPER_B5_EXTRA;
410   if (strcmp (format, "na_b-plus") == 0)
411     return DMPAPER_B_PLUS;
412   if (strcmp (format, "na_letter-plus") == 0)
413     return DMPAPER_LETTER_PLUS;
414
415   return 0;
416 }
417
418 static gchar*
419 get_default_printer (void)
420 {
421   wchar_t *win32_printer_name = NULL;
422   gchar *printer_name = NULL;
423   DWORD needed;
424
425   GetDefaultPrinterW (NULL, &needed);
426   win32_printer_name = g_malloc ((gsize) needed * sizeof (wchar_t));
427   if (!GetDefaultPrinterW (win32_printer_name, &needed))
428     {
429       g_free (win32_printer_name);
430       return NULL;
431     }
432   printer_name = g_utf16_to_utf8 (win32_printer_name, -1, NULL, NULL, NULL);
433   g_free (win32_printer_name);
434
435   return printer_name;
436 }
437
438 static void
439 set_hard_margins (GtkPrintOperation *op)
440 {
441   double top, bottom, left, right;
442   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
443
444   top = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETY);
445   bottom = GetDeviceCaps (op_win32->hdc, PHYSICALHEIGHT)
446       - GetDeviceCaps (op_win32->hdc, VERTRES) - top;
447   left = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETX);
448   right = GetDeviceCaps (op_win32->hdc, PHYSICALWIDTH)
449       - GetDeviceCaps (op_win32->hdc, HORZRES) - left;
450
451   _gtk_print_context_set_hard_margins (op->priv->print_context, top, bottom, left, right);
452 }
453
454 void
455 win32_start_page (GtkPrintOperation *op,
456                   GtkPrintContext *print_context,
457                   GtkPageSetup *page_setup)
458 {
459   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
460   LPDEVMODEW devmode;
461   GtkPaperSize *paper_size;
462   double x_off, y_off;
463
464   devmode = GlobalLock (op_win32->devmode);
465   
466   devmode->dmFields |= DM_ORIENTATION;
467   devmode->dmOrientation =
468     orientation_to_win32 (gtk_page_setup_get_orientation (page_setup));
469   
470   paper_size = gtk_page_setup_get_paper_size (page_setup);
471   devmode->dmFields |= DM_PAPERSIZE;
472   devmode->dmFields &= ~(DM_PAPERWIDTH | DM_PAPERLENGTH);
473   devmode->dmPaperSize = paper_size_to_win32 (paper_size);
474   if (devmode->dmPaperSize == 0)
475     {
476       devmode->dmPaperSize = DMPAPER_USER;
477       devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
478
479       /* Lengths in DEVMODE are in tenths of a millimeter */
480       devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) * 10.0;
481       devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) * 10.0;
482     }
483   
484   ResetDCW (op_win32->hdc, devmode);
485   
486   GlobalUnlock (op_win32->devmode);
487
488   set_hard_margins (op);
489   x_off = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETX);
490   y_off = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETY);
491   cairo_surface_set_device_offset (op_win32->surface, -x_off, -y_off);
492   
493   StartPage (op_win32->hdc);
494 }
495
496 static void
497 win32_end_page (GtkPrintOperation *op,
498                 GtkPrintContext *print_context)
499 {
500   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
501
502   cairo_surface_show_page (op_win32->surface);
503
504   EndPage (op_win32->hdc);
505 }
506
507 static gboolean
508 win32_poll_status_timeout (GtkPrintOperation *op)
509 {
510   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
511   
512   op_win32->timeout_id = 0;
513   /* We need to ref this, as setting the status to finished
514      might unref the object */
515   g_object_ref (op);
516   win32_poll_status (op);
517
518   if (!gtk_print_operation_is_finished (op))
519     op_win32->timeout_id = gdk_threads_add_timeout (STATUS_POLLING_TIME,
520                                           (GSourceFunc)win32_poll_status_timeout,
521                                           op);
522   g_object_unref (op);
523   return FALSE;
524 }
525
526
527 static void
528 win32_end_run (GtkPrintOperation *op,
529                gboolean           wait,
530                gboolean           cancelled)
531 {
532   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
533   LPDEVNAMES devnames;
534   HANDLE printerHandle = 0;
535
536   cairo_surface_finish (op_win32->surface);
537   
538   EndDoc (op_win32->hdc);
539
540   if (op->priv->track_print_status)
541     {
542       devnames = GlobalLock (op_win32->devnames);
543       if (!OpenPrinterW (((gunichar2 *)devnames) + devnames->wDeviceOffset,
544                          &printerHandle, NULL))
545         printerHandle = 0;
546       GlobalUnlock (op_win32->devnames);
547     }
548   
549   GlobalFree (op_win32->devmode);
550   GlobalFree (op_win32->devnames);
551
552   cairo_surface_destroy (op_win32->surface);
553   op_win32->surface = NULL;
554
555   DeleteDC (op_win32->hdc);
556   
557   if (printerHandle != 0)
558     {
559       op_win32->printerHandle = printerHandle;
560       win32_poll_status (op);
561       op_win32->timeout_id = gdk_threads_add_timeout (STATUS_POLLING_TIME,
562                                             (GSourceFunc)win32_poll_status_timeout,
563                                             op);
564     }
565   else
566     /* Dunno what happened, pretend its finished */
567     _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED, NULL);
568 }
569
570 static void
571 win32_poll_status (GtkPrintOperation *op)
572 {
573   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
574   guchar *data;
575   DWORD needed;
576   JOB_INFO_1W *job_info;
577   GtkPrintStatus status;
578   char *status_str;
579   BOOL ret;
580
581   GetJobW (op_win32->printerHandle, op_win32->job_id,
582            1,(LPBYTE)NULL, 0, &needed);
583   data = g_malloc (needed);
584   ret = GetJobW (op_win32->printerHandle, op_win32->job_id,
585                  1, (LPBYTE)data, needed, &needed);
586
587   status_str = NULL;
588   if (ret)
589     {
590       DWORD win32_status;
591       job_info = (JOB_INFO_1W *)data;
592       win32_status = job_info->Status;
593
594       if (job_info->pStatus)
595         status_str = g_utf16_to_utf8 (job_info->pStatus, 
596                                       -1, NULL, NULL, NULL);
597      
598       if (win32_status &
599           (JOB_STATUS_COMPLETE | JOB_STATUS_PRINTED))
600         status = GTK_PRINT_STATUS_FINISHED;
601       else if (win32_status &
602                (JOB_STATUS_OFFLINE |
603                 JOB_STATUS_PAPEROUT |
604                 JOB_STATUS_PAUSED |
605                 JOB_STATUS_USER_INTERVENTION))
606         {
607           status = GTK_PRINT_STATUS_PENDING_ISSUE;
608           if (status_str == NULL)
609             {
610               if (win32_status & JOB_STATUS_OFFLINE)
611                 status_str = g_strdup (_("Printer offline"));
612               else if (win32_status & JOB_STATUS_PAPEROUT)
613                 status_str = g_strdup (_("Out of paper"));
614               else if (win32_status & JOB_STATUS_PAUSED)
615                 status_str = g_strdup (_("Paused"));
616               else if (win32_status & JOB_STATUS_USER_INTERVENTION)
617                 status_str = g_strdup (_("Need user intervention"));
618             }
619         }
620       else if (win32_status &
621                (JOB_STATUS_BLOCKED_DEVQ |
622                 JOB_STATUS_DELETED |
623                 JOB_STATUS_ERROR))
624         status = GTK_PRINT_STATUS_FINISHED_ABORTED;
625       else if (win32_status &
626                (JOB_STATUS_SPOOLING |
627                 JOB_STATUS_DELETING))
628         status = GTK_PRINT_STATUS_PENDING;
629       else if (win32_status & JOB_STATUS_PRINTING)
630         status = GTK_PRINT_STATUS_PRINTING;
631       else
632         status = GTK_PRINT_STATUS_FINISHED;
633     }
634   else
635     status = GTK_PRINT_STATUS_FINISHED;
636
637   g_free (data);
638
639   _gtk_print_operation_set_status (op, status, status_str);
640  
641   g_free (status_str);
642 }
643
644 static void
645 op_win32_free (GtkPrintOperationWin32 *op_win32)
646 {
647   if (op_win32->printerHandle)
648     ClosePrinter (op_win32->printerHandle);
649   if (op_win32->timeout_id != 0)
650     g_source_remove (op_win32->timeout_id);
651   g_free (op_win32);
652 }
653
654 static HWND
655 get_parent_hwnd (GtkWidget *widget)
656 {
657   gtk_widget_realize (widget);
658   return gdk_win32_drawable_get_handle (widget->window);
659 }
660
661 static void
662 devnames_to_settings (GtkPrintSettings *settings,
663                       HANDLE hDevNames)
664 {
665   GtkPrintWin32Devnames *devnames = gtk_print_win32_devnames_from_win32 (hDevNames);
666   gtk_print_settings_set_printer (settings, devnames->device);
667   gtk_print_win32_devnames_free (devnames);
668 }
669
670 static void
671 devmode_to_settings (GtkPrintSettings *settings,
672                      HANDLE hDevMode)
673 {
674   LPDEVMODEW devmode;
675
676   devmode = GlobalLock (hDevMode);
677   
678   gtk_print_settings_set_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION,
679                               devmode->dmDriverVersion);
680   if (devmode->dmDriverExtra != 0)
681     {
682       char *extra = g_base64_encode (((char *)devmode) + sizeof (DEVMODEW),
683                                      devmode->dmDriverExtra);
684       gtk_print_settings_set (settings,
685                               GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA,
686                               extra);
687       g_free (extra);
688     }
689   
690   if (devmode->dmFields & DM_ORIENTATION)
691     gtk_print_settings_set_orientation (settings,
692                                         orientation_from_win32 (devmode->dmOrientation));
693   
694   
695   if (devmode->dmFields & DM_PAPERSIZE &&
696       devmode->dmPaperSize != 0)
697     {
698       GtkPaperSize *paper_size = paper_size_from_win32 (devmode->dmPaperSize);
699       if (paper_size)
700         {
701           gtk_print_settings_set_paper_size (settings, paper_size);
702           gtk_paper_size_free (paper_size);
703         }
704       gtk_print_settings_set_int (settings, "win32-paper-size", (int)devmode->dmPaperSize);
705     }
706   else if ((devmode->dmFields & DM_PAPERSIZE &&
707             devmode->dmPaperSize == 0) ||
708            ((devmode->dmFields & DM_PAPERWIDTH) &&
709             (devmode->dmFields & DM_PAPERLENGTH)))
710     {
711       GtkPaperSize *paper_size;
712       char *form_name = NULL;
713       if (devmode->dmFields & DM_FORMNAME)
714         form_name = g_utf16_to_utf8 (devmode->dmFormName, 
715                                      -1, NULL, NULL, NULL);
716       if (form_name == NULL || form_name[0] == 0)
717         form_name = g_strdup (_("Custom size"));
718
719       /* Lengths in DEVMODE are in tenths of a millimeter */
720       paper_size = gtk_paper_size_new_custom (form_name,
721                                               form_name,
722                                               devmode->dmPaperWidth / 10.0,
723                                               devmode->dmPaperLength / 10.0,
724                                               GTK_UNIT_MM);
725       gtk_print_settings_set_paper_size (settings, paper_size);
726       gtk_paper_size_free (paper_size);
727     }
728   
729   if (devmode->dmFields & DM_SCALE)
730     gtk_print_settings_set_scale (settings, devmode->dmScale);
731   
732   if (devmode->dmFields & DM_COPIES)
733     gtk_print_settings_set_n_copies (settings,
734                                      devmode->dmCopies);
735   
736   if (devmode->dmFields & DM_DEFAULTSOURCE)
737     {
738       char *source;
739       switch (devmode->dmDefaultSource)
740         {
741         default:
742         case DMBIN_AUTO:
743           source = "auto";
744           break;
745         case DMBIN_CASSETTE:
746           source = "cassette";
747           break;
748         case DMBIN_ENVELOPE:
749           source = "envelope";
750           break;
751         case DMBIN_ENVMANUAL:
752           source = "envelope-manual";
753           break;
754         case DMBIN_LOWER:
755           source = "lower";
756           break;
757         case DMBIN_MANUAL:
758           source = "manual";
759           break;
760         case DMBIN_MIDDLE:
761           source = "middle";
762           break;
763         case DMBIN_ONLYONE:
764           source = "only-one";
765           break;
766         case DMBIN_FORMSOURCE:
767           source = "form-source";
768           break;
769         case DMBIN_LARGECAPACITY:
770           source = "large-capacity";
771           break;
772         case DMBIN_LARGEFMT:
773           source = "large-format";
774           break;
775         case DMBIN_TRACTOR:
776           source = "tractor";
777           break;
778         case DMBIN_SMALLFMT:
779           source = "small-format";
780           break;
781         }
782       gtk_print_settings_set_default_source (settings, source);
783       gtk_print_settings_set_int (settings, "win32-default-source", devmode->dmDefaultSource);
784     }
785   
786   if (devmode->dmFields & DM_PRINTQUALITY)
787     {
788       GtkPrintQuality quality;
789       switch (devmode->dmPrintQuality)
790         {
791         case DMRES_LOW:
792           quality = GTK_PRINT_QUALITY_LOW;
793           break;
794         case DMRES_MEDIUM:
795           quality = GTK_PRINT_QUALITY_NORMAL;
796           break;
797         default:
798         case DMRES_HIGH:
799           quality = GTK_PRINT_QUALITY_HIGH;
800           break;
801         case DMRES_DRAFT:
802           quality = GTK_PRINT_QUALITY_DRAFT;
803           break;
804         }
805       gtk_print_settings_set_quality (settings, quality);
806       gtk_print_settings_set_int (settings, "win32-print-quality", devmode->dmPrintQuality);
807     }
808   
809   if (devmode->dmFields & DM_COLOR)
810     gtk_print_settings_set_use_color (settings, devmode->dmColor == DMCOLOR_COLOR);
811   
812   if (devmode->dmFields & DM_DUPLEX)
813     {
814       GtkPrintDuplex duplex;
815       switch (devmode->dmDuplex)
816         {
817         default:
818         case DMDUP_SIMPLEX:
819           duplex = GTK_PRINT_DUPLEX_SIMPLEX;
820           break;
821         case DMDUP_HORIZONTAL:
822           duplex = GTK_PRINT_DUPLEX_HORIZONTAL;
823           break;
824         case DMDUP_VERTICAL:
825           duplex = GTK_PRINT_DUPLEX_VERTICAL;
826           break;
827         }
828       
829       gtk_print_settings_set_duplex (settings, duplex);
830     }
831   
832   if (devmode->dmFields & DM_COLLATE)
833     gtk_print_settings_set_collate (settings,
834                                     devmode->dmCollate == DMCOLLATE_TRUE);
835   
836   if (devmode->dmFields & DM_MEDIATYPE)
837     {
838       char *media_type;
839       switch (devmode->dmMediaType)
840         {
841         default:
842         case DMMEDIA_STANDARD:
843           media_type = "stationery";
844           break;
845         case DMMEDIA_TRANSPARENCY:
846           media_type = "transparency";
847           break;
848         case DMMEDIA_GLOSSY:
849           media_type = "photographic-glossy";
850           break;
851         }
852       gtk_print_settings_set_media_type (settings, media_type);
853       gtk_print_settings_set_int (settings, "win32-media-type", devmode->dmMediaType);
854     }
855   
856   if (devmode->dmFields & DM_DITHERTYPE)
857     {
858       char *dither;
859       switch (devmode->dmDitherType)
860         {
861         default:
862         case DMDITHER_FINE:
863           dither = "fine";
864           break;
865         case DMDITHER_NONE:
866           dither = "none";
867           break;
868         case DMDITHER_COARSE:
869           dither = "coarse";
870           break;
871         case DMDITHER_LINEART:
872           dither = "lineart";
873           break;
874         case DMDITHER_GRAYSCALE:
875           dither = "grayscale";
876           break;
877         case DMDITHER_ERRORDIFFUSION:
878           dither = "error-diffusion";
879           break;
880         }
881       gtk_print_settings_set_dither (settings, dither);
882       gtk_print_settings_set_int (settings, "win32-dither-type", devmode->dmDitherType);
883     }
884   
885   GlobalUnlock (hDevMode);
886 }
887
888 static void
889 dialog_to_print_settings (GtkPrintOperation *op,
890                           LPPRINTDLGEXW printdlgex)
891 {
892   guint i;
893   GtkPrintSettings *settings;
894
895   settings = gtk_print_settings_new ();
896
897   gtk_print_settings_set_print_pages (settings,
898                                       GTK_PRINT_PAGES_ALL);
899   if (printdlgex->Flags & PD_CURRENTPAGE)
900     gtk_print_settings_set_print_pages (settings,
901                                         GTK_PRINT_PAGES_CURRENT);
902   else if (printdlgex->Flags & PD_PAGENUMS)
903     gtk_print_settings_set_print_pages (settings,
904                                         GTK_PRINT_PAGES_RANGES);
905
906   if (printdlgex->nPageRanges > 0)
907     {
908       GtkPageRange *ranges;
909       ranges = g_new (GtkPageRange, printdlgex->nPageRanges);
910
911       for (i = 0; i < printdlgex->nPageRanges; i++)
912         {
913           ranges[i].start = printdlgex->lpPageRanges[i].nFromPage - 1;
914           ranges[i].end = printdlgex->lpPageRanges[i].nToPage - 1;
915         }
916
917       gtk_print_settings_set_page_ranges (settings, ranges,
918                                           printdlgex->nPageRanges);
919       g_free (ranges);
920     }
921   
922   if (printdlgex->hDevNames != NULL)
923     devnames_to_settings (settings, printdlgex->hDevNames);
924
925   if (printdlgex->hDevMode != NULL)
926     devmode_to_settings (settings, printdlgex->hDevMode);
927   
928   gtk_print_operation_set_print_settings (op, settings);
929 }
930
931 static HANDLE
932 devmode_from_settings (GtkPrintSettings *settings,
933                        GtkPageSetup *page_setup)
934 {
935   HANDLE hDevMode;
936   LPDEVMODEW devmode;
937   char *extras;
938   GtkPaperSize *paper_size;
939   const char *extras_base64;
940   int extras_len;
941   const char *val;
942
943   extras = NULL;
944   extras_len = 0;
945   extras_base64 = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA);
946   if (extras_base64)
947     extras = g_base64_decode (extras_base64, &extras_len);
948   
949   hDevMode = GlobalAlloc (GMEM_MOVEABLE, 
950                           sizeof (DEVMODEW) + extras_len);
951
952   devmode = GlobalLock (hDevMode);
953
954   memset (devmode, 0, sizeof (DEVMODEW));
955   
956   devmode->dmSpecVersion = DM_SPECVERSION;
957   devmode->dmSize = sizeof (DEVMODEW);
958   
959   devmode->dmDriverExtra = 0;
960   if (extras && extras_len > 0)
961     {
962       devmode->dmDriverExtra = extras_len;
963       memcpy (((char *)devmode) + sizeof (DEVMODEW), extras, extras_len);
964     }
965   g_free (extras);
966   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION))
967     devmode->dmDriverVersion = gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION);
968   
969   if (page_setup ||
970       gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION))
971     {
972       GtkPageOrientation orientation = gtk_print_settings_get_orientation (settings);
973       if (page_setup)
974         orientation = gtk_page_setup_get_orientation (page_setup);
975       devmode->dmFields |= DM_ORIENTATION;
976       devmode->dmOrientation = orientation_to_win32 (orientation);
977     }
978
979   if (page_setup)
980     paper_size = gtk_paper_size_copy (gtk_page_setup_get_paper_size (page_setup));
981   else
982     {
983       int size;
984       if (gtk_print_settings_has_key (settings, "win32-paper-size") &&
985           (size = gtk_print_settings_get_int (settings, "win32-paper-size")) != 0)
986         {
987           devmode->dmFields |= DM_PAPERSIZE;
988           devmode->dmPaperSize = size;
989           paper_size = NULL;
990         }
991       else
992         paper_size = gtk_print_settings_get_paper_size (settings);
993     }
994   if (paper_size)
995     {
996       devmode->dmFields |= DM_PAPERSIZE;
997       devmode->dmPaperSize = paper_size_to_win32 (paper_size);
998       if (devmode->dmPaperSize == 0)
999         {
1000           devmode->dmPaperSize = DMPAPER_USER;
1001           devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
1002
1003           /* Lengths in DEVMODE are in tenths of a millimeter */
1004           devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) * 10.0;
1005           devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) * 10.0;
1006         }
1007       gtk_paper_size_free (paper_size);
1008     }
1009
1010   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_SCALE))
1011     {
1012       devmode->dmFields |= DM_SCALE;
1013       devmode->dmScale = gtk_print_settings_get_scale (settings);
1014     }
1015   
1016   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_N_COPIES))
1017     {
1018       devmode->dmFields |= DM_COPIES;
1019       devmode->dmCopies = gtk_print_settings_get_n_copies (settings);
1020     }
1021
1022   if (gtk_print_settings_has_key (settings, "win32-default-source"))
1023     {
1024       devmode->dmFields |= DM_DEFAULTSOURCE;
1025       devmode->dmDefaultSource = gtk_print_settings_get_int (settings, "win32-default-source");
1026     }
1027   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE))
1028     {
1029       devmode->dmFields |= DM_DEFAULTSOURCE;
1030       devmode->dmDefaultSource = DMBIN_AUTO;
1031
1032       val = gtk_print_settings_get_default_source (settings);
1033       if (strcmp (val, "auto") == 0)
1034         devmode->dmDefaultSource = DMBIN_AUTO;
1035       if (strcmp (val, "cassette") == 0)
1036         devmode->dmDefaultSource = DMBIN_CASSETTE;
1037       if (strcmp (val, "envelope") == 0)
1038         devmode->dmDefaultSource = DMBIN_ENVELOPE;
1039       if (strcmp (val, "envelope-manual") == 0)
1040         devmode->dmDefaultSource = DMBIN_ENVMANUAL;
1041       if (strcmp (val, "lower") == 0)
1042         devmode->dmDefaultSource = DMBIN_LOWER;
1043       if (strcmp (val, "manual") == 0)
1044         devmode->dmDefaultSource = DMBIN_MANUAL;
1045       if (strcmp (val, "middle") == 0)
1046         devmode->dmDefaultSource = DMBIN_MIDDLE;
1047       if (strcmp (val, "only-one") == 0)
1048         devmode->dmDefaultSource = DMBIN_ONLYONE;
1049       if (strcmp (val, "form-source") == 0)
1050         devmode->dmDefaultSource = DMBIN_FORMSOURCE;
1051       if (strcmp (val, "large-capacity") == 0)
1052         devmode->dmDefaultSource = DMBIN_LARGECAPACITY;
1053       if (strcmp (val, "large-format") == 0)
1054         devmode->dmDefaultSource = DMBIN_LARGEFMT;
1055       if (strcmp (val, "tractor") == 0)
1056         devmode->dmDefaultSource = DMBIN_TRACTOR;
1057       if (strcmp (val, "small-format") == 0)
1058         devmode->dmDefaultSource = DMBIN_SMALLFMT;
1059     }
1060
1061   if (gtk_print_settings_has_key (settings, "win32-print-quality"))
1062     {
1063       devmode->dmFields |= DM_PRINTQUALITY;
1064       devmode->dmPrintQuality = gtk_print_settings_get_int (settings, "win32-print-quality");
1065     }
1066   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_RESOLUTION))
1067     {
1068       devmode->dmFields |= DM_PRINTQUALITY;
1069       devmode->dmPrintQuality = gtk_print_settings_get_resolution (settings);
1070     } 
1071   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_QUALITY))
1072     {
1073       devmode->dmFields |= DM_PRINTQUALITY;
1074       switch (gtk_print_settings_get_quality (settings))
1075         {
1076         case GTK_PRINT_QUALITY_LOW:
1077           devmode->dmPrintQuality = DMRES_LOW;
1078           break;
1079         case GTK_PRINT_QUALITY_DRAFT:
1080           devmode->dmPrintQuality = DMRES_DRAFT;
1081           break;
1082         default:
1083         case GTK_PRINT_QUALITY_NORMAL:
1084           devmode->dmPrintQuality = DMRES_MEDIUM;
1085           break;
1086         case GTK_PRINT_QUALITY_HIGH:
1087           devmode->dmPrintQuality = DMRES_HIGH;
1088           break;
1089         }
1090     }
1091
1092   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_USE_COLOR))
1093     {
1094       devmode->dmFields |= DM_COLOR;
1095       if (gtk_print_settings_get_use_color (settings))
1096         devmode->dmColor = DMCOLOR_COLOR;
1097       else
1098         devmode->dmColor = DMCOLOR_MONOCHROME;
1099     }
1100
1101   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DUPLEX))
1102     {
1103       devmode->dmFields |= DM_DUPLEX;
1104       switch (gtk_print_settings_get_duplex (settings))
1105         {
1106         default:
1107         case GTK_PRINT_DUPLEX_SIMPLEX:
1108           devmode->dmDuplex = DMDUP_SIMPLEX;
1109           break;
1110         case GTK_PRINT_DUPLEX_HORIZONTAL:
1111           devmode->dmDuplex = DMDUP_HORIZONTAL;
1112           break;
1113         case GTK_PRINT_DUPLEX_VERTICAL:
1114           devmode->dmDuplex = DMDUP_VERTICAL;
1115           break;
1116         }
1117     }
1118
1119   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_COLLATE))
1120     {
1121       devmode->dmFields |= DM_COLLATE;
1122       if (gtk_print_settings_get_collate (settings))
1123         devmode->dmCollate = DMCOLLATE_TRUE;
1124       else
1125         devmode->dmCollate = DMCOLLATE_FALSE;
1126     }
1127
1128   if (gtk_print_settings_has_key (settings, "win32-media-type"))
1129     {
1130       devmode->dmFields |= DM_MEDIATYPE;
1131       devmode->dmMediaType = gtk_print_settings_get_int (settings, "win32-media-type");
1132     }
1133   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_MEDIA_TYPE))
1134     {
1135       devmode->dmFields |= DM_MEDIATYPE;
1136       devmode->dmMediaType = DMMEDIA_STANDARD;
1137       
1138       val = gtk_print_settings_get_media_type (settings);
1139       if (strcmp (val, "transparency") == 0)
1140         devmode->dmMediaType = DMMEDIA_TRANSPARENCY;
1141       if (strcmp (val, "photographic-glossy") == 0)
1142         devmode->dmMediaType = DMMEDIA_GLOSSY;
1143     }
1144  
1145   if (gtk_print_settings_has_key (settings, "win32-dither-type"))
1146     {
1147       devmode->dmFields |= DM_DITHERTYPE;
1148       devmode->dmDitherType = gtk_print_settings_get_int (settings, "win32-dither-type");
1149     }
1150   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DITHER))
1151     {
1152       devmode->dmFields |= DM_DITHERTYPE;
1153       devmode->dmDitherType = DMDITHER_FINE;
1154       
1155       val = gtk_print_settings_get_dither (settings);
1156       if (strcmp (val, "none") == 0)
1157         devmode->dmDitherType = DMDITHER_NONE;
1158       if (strcmp (val, "coarse") == 0)
1159         devmode->dmDitherType = DMDITHER_COARSE;
1160       if (strcmp (val, "fine") == 0)
1161         devmode->dmDitherType = DMDITHER_FINE;
1162       if (strcmp (val, "lineart") == 0)
1163         devmode->dmDitherType = DMDITHER_LINEART;
1164       if (strcmp (val, "grayscale") == 0)
1165         devmode->dmDitherType = DMDITHER_GRAYSCALE;
1166       if (strcmp (val, "error-diffusion") == 0)
1167         devmode->dmDitherType = DMDITHER_ERRORDIFFUSION;
1168     }
1169   
1170   GlobalUnlock (hDevMode);
1171
1172   return hDevMode;
1173 }
1174
1175 static void
1176 dialog_from_print_settings (GtkPrintOperation *op,
1177                             LPPRINTDLGEXW printdlgex)
1178 {
1179   GtkPrintSettings *settings = op->priv->print_settings;
1180   const char *printer;
1181
1182   if (settings == NULL)
1183     return;
1184
1185   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PRINT_PAGES))
1186     {
1187       GtkPrintPages print_pages = gtk_print_settings_get_print_pages (settings);
1188
1189       switch (print_pages)
1190         {
1191         default:
1192         case GTK_PRINT_PAGES_ALL:
1193           printdlgex->Flags |= PD_ALLPAGES;
1194           break;
1195         case GTK_PRINT_PAGES_CURRENT:
1196           printdlgex->Flags |= PD_CURRENTPAGE;
1197           break;
1198         case GTK_PRINT_PAGES_RANGES:
1199           printdlgex->Flags |= PD_PAGENUMS;
1200           break;
1201         }
1202     }
1203   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PAGE_RANGES))
1204     {
1205       GtkPageRange *ranges;
1206       int num_ranges, i;
1207
1208       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
1209
1210       if (num_ranges > MAX_PAGE_RANGES)
1211         num_ranges = MAX_PAGE_RANGES;
1212
1213       printdlgex->nPageRanges = num_ranges;
1214       for (i = 0; i < num_ranges; i++)
1215         {
1216           printdlgex->lpPageRanges[i].nFromPage = ranges[i].start + 1;
1217           printdlgex->lpPageRanges[i].nToPage = ranges[i].end + 1;
1218         }
1219     }
1220   
1221   printer = gtk_print_settings_get_printer (settings);
1222   if (printer)
1223     printdlgex->hDevNames = gtk_print_win32_devnames_to_win32_from_printer_name (printer);
1224   
1225   printdlgex->hDevMode = devmode_from_settings (settings,
1226                                                 op->priv->default_page_setup);
1227 }
1228
1229 typedef struct {
1230   IPrintDialogCallback iPrintDialogCallback;
1231   gboolean set_hwnd;
1232   int ref_count;
1233 } PrintDialogCallback;
1234
1235
1236 static ULONG STDMETHODCALLTYPE
1237 iprintdialogcallback_addref (IPrintDialogCallback *This)
1238 {
1239   PrintDialogCallback *callback = (PrintDialogCallback *)This;
1240   return ++callback->ref_count;
1241 }
1242
1243 static ULONG STDMETHODCALLTYPE
1244 iprintdialogcallback_release (IPrintDialogCallback *This)
1245 {
1246   PrintDialogCallback *callback = (PrintDialogCallback *)This;
1247   int ref_count = --callback->ref_count;
1248
1249   if (ref_count == 0)
1250     g_free (This);
1251
1252   return ref_count;
1253 }
1254
1255 static HRESULT STDMETHODCALLTYPE
1256 iprintdialogcallback_queryinterface (IPrintDialogCallback *This,
1257                                      REFIID       riid,
1258                                      LPVOID      *ppvObject)
1259 {
1260    if (IsEqualIID (riid, &IID_IUnknown) ||
1261        IsEqualIID (riid, &myIID_IPrintDialogCallback))
1262      {
1263        *ppvObject = This;
1264        IUnknown_AddRef ((IUnknown *)This);
1265        return NOERROR;
1266      }
1267    else
1268      {
1269        *ppvObject = NULL;
1270        return E_NOINTERFACE;
1271      }
1272 }
1273
1274 static HRESULT STDMETHODCALLTYPE
1275 iprintdialogcallback_initdone (IPrintDialogCallback *This)
1276 {
1277   return S_FALSE;
1278 }
1279
1280 static HRESULT STDMETHODCALLTYPE
1281 iprintdialogcallback_selectionchange (IPrintDialogCallback *This)
1282 {
1283   return S_FALSE;
1284 }
1285
1286 static HRESULT STDMETHODCALLTYPE
1287 iprintdialogcallback_handlemessage (IPrintDialogCallback *This,
1288                                     HWND hDlg,
1289                                     UINT uMsg,
1290                                     WPARAM wParam,
1291                                     LPARAM lParam,
1292                                     LRESULT *pResult)
1293 {
1294   PrintDialogCallback *callback = (PrintDialogCallback *)This;
1295
1296   if (!callback->set_hwnd)
1297     {
1298       gdk_win32_set_modal_dialog_libgtk_only (hDlg);
1299       callback->set_hwnd = TRUE;
1300       while (gtk_events_pending ())
1301         gtk_main_iteration ();
1302     }
1303   else if (uMsg == got_gdk_events_message)
1304     {
1305       while (gtk_events_pending ())
1306         gtk_main_iteration ();
1307       *pResult = TRUE;
1308       return S_OK;
1309     }
1310   
1311   *pResult = 0;
1312   return S_FALSE;
1313 }
1314
1315 static IPrintDialogCallbackVtbl ipdc_vtbl = {
1316   iprintdialogcallback_queryinterface,
1317   iprintdialogcallback_addref,
1318   iprintdialogcallback_release,
1319   iprintdialogcallback_initdone,
1320   iprintdialogcallback_selectionchange,
1321   iprintdialogcallback_handlemessage
1322 };
1323
1324 static IPrintDialogCallback *
1325 print_callback_new  (void)
1326 {
1327   PrintDialogCallback *callback;
1328
1329   callback = g_new0 (PrintDialogCallback, 1);
1330   callback->iPrintDialogCallback.lpVtbl = &ipdc_vtbl;
1331   callback->ref_count = 1;
1332   callback->set_hwnd = FALSE;
1333
1334   return &callback->iPrintDialogCallback;
1335 }
1336
1337 static  void
1338 plug_grab_notify (GtkWidget        *widget,
1339                   gboolean          was_grabbed,
1340                   GtkPrintOperation *op)
1341 {
1342   EnableWindow (GetAncestor (GDK_WINDOW_HWND (widget->window), GA_ROOT),
1343                 was_grabbed);
1344 }
1345
1346
1347 static BOOL CALLBACK
1348 pageDlgProc (HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
1349 {
1350   GtkPrintOperation *op;
1351   GtkPrintOperationWin32 *op_win32;
1352   
1353   if (message == WM_INITDIALOG)
1354     {
1355       PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lparam;
1356       GtkWidget *plug;
1357
1358       op = GTK_PRINT_OPERATION ((gpointer)page->lParam);
1359       op_win32 = op->priv->platform_data;
1360
1361       SetWindowLongPtrW (wnd, GWLP_USERDATA, (LONG_PTR)op);
1362       
1363       plug = _gtk_win32_embed_widget_new ((GdkNativeWindow) wnd);
1364       gtk_window_set_modal (GTK_WINDOW (plug), TRUE);
1365       op_win32->embed_widget = plug;
1366       gtk_container_add (GTK_CONTAINER (plug), op->priv->custom_widget);
1367       gtk_widget_show (op->priv->custom_widget);
1368       gtk_widget_show (plug);
1369       gdk_window_focus (plug->window, GDK_CURRENT_TIME);
1370
1371       /* This dialog is modal, so we grab the embed widget */
1372       gtk_grab_add (plug);
1373
1374       /* When we lose the grab we need to disable the print dialog */
1375       g_signal_connect (plug, "grab-notify", G_CALLBACK (plug_grab_notify), op);
1376       return FALSE;
1377     }
1378   else if (message == WM_DESTROY)
1379     {
1380       op = GTK_PRINT_OPERATION (GetWindowLongPtrW (wnd, GWLP_USERDATA));
1381       op_win32 = op->priv->platform_data;
1382       
1383       g_signal_emit_by_name (op, "custom-widget-apply", op->priv->custom_widget);
1384       gtk_widget_destroy (op_win32->embed_widget);
1385       op_win32->embed_widget = NULL;
1386       op->priv->custom_widget = NULL;
1387     }
1388   else 
1389     {
1390       op = GTK_PRINT_OPERATION (GetWindowLongPtrW (wnd, GWLP_USERDATA));
1391       op_win32 = op->priv->platform_data;
1392
1393       return _gtk_win32_embed_widget_dialog_procedure (GTK_WIN32_EMBED_WIDGET (op_win32->embed_widget),
1394                                                        wnd, message, wparam, lparam);
1395     }
1396   
1397   return FALSE;
1398 }
1399
1400 static HPROPSHEETPAGE
1401 create_application_page (GtkPrintOperation *op)
1402 {
1403   HPROPSHEETPAGE hpage;
1404   PROPSHEETPAGEW page;
1405   DLGTEMPLATE *template;
1406   HGLOBAL htemplate;
1407   LONG base_units;
1408   WORD baseunitX, baseunitY;
1409   WORD *array;
1410   GtkRequisition requisition;
1411   const char *tab_label;
1412
1413   /* Make the template the size of the custom widget size request */
1414   gtk_widget_size_request (op->priv->custom_widget, &requisition);
1415       
1416   base_units = GetDialogBaseUnits ();
1417   baseunitX = LOWORD (base_units);
1418   baseunitY = HIWORD (base_units);
1419   
1420   htemplate = GlobalAlloc (GMEM_MOVEABLE, 
1421                            sizeof (DLGTEMPLATE) + sizeof (WORD) * 3);
1422   template = GlobalLock (htemplate);
1423   template->style = WS_CHILDWINDOW | DS_CONTROL;
1424   template->dwExtendedStyle = WS_EX_CONTROLPARENT;
1425   template->cdit = 0;
1426   template->x = MulDiv (0, 4, baseunitX);
1427   template->y = MulDiv (0, 8, baseunitY);
1428   template->cx = MulDiv (requisition.width, 4, baseunitX);
1429   template->cy = MulDiv (requisition.height, 8, baseunitY);
1430   
1431   array = (WORD *) (template+1);
1432   *array++ = 0; /* menu */
1433   *array++ = 0; /* class */
1434   *array++ = 0; /* title */
1435   
1436   memset (&page, 0, sizeof (page));
1437   page.dwSize = sizeof (page);
1438   page.dwFlags = PSP_DLGINDIRECT | PSP_USETITLE | PSP_PREMATURE;
1439   page.hInstance = GetModuleHandle (NULL);
1440   page.pResource = template;
1441   
1442   tab_label = op->priv->custom_tab_label;
1443   if (tab_label == NULL)
1444     tab_label = g_get_application_name ();
1445   if (tab_label == NULL)
1446     tab_label = _("Application");
1447   page.pszTitle = g_utf8_to_utf16 (tab_label, 
1448                                    -1, NULL, NULL, NULL);
1449   page.pfnDlgProc = pageDlgProc;
1450   page.pfnCallback = NULL;
1451   page.lParam = (LPARAM) op;
1452   hpage = CreatePropertySheetPageW (&page);
1453   
1454   GlobalUnlock (htemplate);
1455   
1456   /* TODO: We're leaking htemplate here... */
1457   
1458   return hpage;
1459 }
1460
1461 static GtkPageSetup *
1462 create_page_setup (GtkPrintOperation *op)
1463 {
1464   GtkPrintOperationPrivate *priv = op->priv;
1465   GtkPageSetup *page_setup;
1466   GtkPrintSettings *settings;
1467   
1468   if (priv->default_page_setup)
1469     page_setup = gtk_page_setup_copy (priv->default_page_setup);
1470   else
1471     page_setup = gtk_page_setup_new ();
1472
1473   settings = priv->print_settings;
1474   if (settings)
1475     {
1476       GtkPaperSize *paper_size;
1477       
1478       if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION))
1479         gtk_page_setup_set_orientation (page_setup,
1480                                         gtk_print_settings_get_orientation (settings));
1481
1482
1483       paper_size = gtk_print_settings_get_paper_size (settings);
1484       if (paper_size)
1485         {
1486           gtk_page_setup_set_paper_size (page_setup, paper_size);
1487           gtk_paper_size_free (paper_size);
1488         }
1489
1490       /* TODO: Margins? */
1491     }
1492   
1493   return page_setup;
1494 }
1495
1496 GtkPrintOperationResult
1497 gtk_print_operation_run_without_dialog (GtkPrintOperation *op,
1498                                         gboolean          *do_print)
1499 {
1500   GtkPrintOperationResult result;
1501   GtkPrintOperationWin32 *op_win32;
1502   GtkPrintOperationPrivate *priv;
1503   GtkPrintSettings *settings;
1504   GtkPageSetup *page_setup;
1505   DOCINFOW docinfo;
1506   HGLOBAL hDevMode = NULL;
1507   HGLOBAL hDevNames = NULL;
1508   HDC hDC = NULL;
1509   const char *printer = NULL;
1510   double dpi_x, dpi_y;
1511   int job_id;
1512   cairo_t *cr;
1513   DEVNAMES *pdn;
1514   DEVMODEW *pdm;
1515
1516   *do_print = FALSE;
1517
1518   priv = op->priv;
1519   settings = priv->print_settings;
1520   
1521   op_win32 = g_new0 (GtkPrintOperationWin32, 1);
1522   priv->platform_data = op_win32;
1523   priv->free_platform_data = (GDestroyNotify) op_win32_free;
1524   printer = gtk_print_settings_get_printer (settings);
1525
1526   if (!printer)
1527     {
1528       /* No printer selected. Get the system default printer and store
1529        * it in settings.
1530        */
1531       gchar *tmp_printer = get_default_printer ();
1532       if (!tmp_printer)
1533         {
1534           result = GTK_PRINT_OPERATION_RESULT_ERROR;
1535           g_set_error_literal (&priv->error,
1536                                GTK_PRINT_ERROR,
1537                                GTK_PRINT_ERROR_INTERNAL_ERROR,
1538                                _("No printer found"));
1539           goto out;
1540         }
1541       gtk_print_settings_set_printer (settings, tmp_printer);
1542       printer = gtk_print_settings_get_printer (settings);
1543       g_free (tmp_printer);
1544     }
1545
1546   hDevNames = gtk_print_win32_devnames_to_win32_from_printer_name (printer);
1547   hDevMode = devmode_from_settings (settings, op->priv->default_page_setup);
1548
1549   /* Create a printer DC for the print settings and page setup provided. */
1550   pdn = GlobalLock (hDevNames);
1551   pdm = GlobalLock (hDevMode);
1552   hDC = CreateDCW ((wchar_t*)pdn + pdn->wDriverOffset,
1553                    (wchar_t*)pdn + pdn->wDeviceOffset,
1554                    (wchar_t*)pdn + pdn->wOutputOffset,
1555                    pdm );
1556   GlobalUnlock (hDevNames);
1557   GlobalUnlock (hDevMode);
1558
1559   if (!hDC)
1560     {
1561       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1562       g_set_error_literal (&priv->error,
1563                            GTK_PRINT_ERROR,
1564                            GTK_PRINT_ERROR_INTERNAL_ERROR,
1565                            _("Invalid argument to CreateDC"));
1566       goto out;
1567     }
1568   
1569   priv->print_context = _gtk_print_context_new (op);
1570   page_setup = create_page_setup (op);
1571   _gtk_print_context_set_page_setup (priv->print_context, page_setup);
1572   g_object_unref (page_setup);
1573
1574   *do_print = TRUE;
1575
1576   op_win32->surface = cairo_win32_printing_surface_create (hDC);
1577   dpi_x = (double) GetDeviceCaps (hDC, LOGPIXELSX);
1578   dpi_y = (double) GetDeviceCaps (hDC, LOGPIXELSY);
1579
1580   cr = cairo_create (op_win32->surface);
1581   gtk_print_context_set_cairo_context (priv->print_context, cr, dpi_x, dpi_y);
1582   cairo_destroy (cr);
1583
1584   set_hard_margins (op);
1585
1586   memset (&docinfo, 0, sizeof (DOCINFOW));
1587   docinfo.cbSize = sizeof (DOCINFOW); 
1588   docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL); 
1589   docinfo.lpszOutput = NULL; 
1590   docinfo.lpszDatatype = NULL; 
1591   docinfo.fwType = 0; 
1592
1593   job_id = StartDocW (hDC, &docinfo); 
1594   g_free ((void *)docinfo.lpszDocName);
1595   if (job_id <= 0)
1596     { 
1597       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1598       g_set_error_literal (&priv->error,
1599                            GTK_PRINT_ERROR,
1600                            GTK_PRINT_ERROR_GENERAL,
1601                            _("Error from StartDoc"));
1602       *do_print = FALSE;
1603       cairo_surface_destroy (op_win32->surface);
1604       op_win32->surface = NULL;
1605       goto out; 
1606     }
1607
1608   result = GTK_PRINT_OPERATION_RESULT_APPLY;
1609   op_win32->hdc = hDC;
1610   op_win32->devmode = hDevMode;
1611   op_win32->devnames = hDevNames;
1612   op_win32->job_id = job_id;
1613   op->priv->print_pages = gtk_print_settings_get_print_pages (op->priv->print_settings);
1614   op->priv->num_page_ranges = 0;
1615   if (op->priv->print_pages == GTK_PRINT_PAGES_RANGES)
1616     op->priv->page_ranges = gtk_print_settings_get_page_ranges (op->priv->print_settings,
1617                                                                 &op->priv->num_page_ranges);
1618   op->priv->manual_num_copies = 1;
1619   op->priv->manual_collation = FALSE;
1620   op->priv->manual_reverse = FALSE;
1621   op->priv->manual_orientation = FALSE;
1622   op->priv->manual_scale = 1.0;
1623   op->priv->manual_page_set = GTK_PAGE_SET_ALL;
1624   op->priv->manual_number_up = 1;
1625   op->priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
1626
1627   op->priv->start_page = win32_start_page;
1628   op->priv->end_page = win32_end_page;
1629   op->priv->end_run = win32_end_run;
1630   
1631  out:
1632   if (!*do_print && hDC != NULL)
1633     DeleteDC (hDC);
1634
1635   if (!*do_print && hDevMode != NULL)
1636     GlobalFree (hDevMode);
1637
1638   if (!*do_print && hDevNames != NULL)
1639     GlobalFree (hDevNames);
1640
1641   return result;
1642 }
1643
1644 GtkPrintOperationResult
1645 gtk_print_operation_run_with_dialog (GtkPrintOperation *op,
1646                                      GtkWindow         *parent,
1647                                      gboolean          *do_print)
1648 {
1649   HRESULT hResult;
1650   LPPRINTDLGEXW printdlgex = NULL;
1651   LPPRINTPAGERANGE page_ranges = NULL;
1652   HWND parentHWnd;
1653   GtkWidget *invisible = NULL;
1654   GtkPrintOperationResult result;
1655   GtkPrintOperationWin32 *op_win32;
1656   GtkPrintOperationPrivate *priv;
1657   IPrintDialogCallback *callback;
1658   HPROPSHEETPAGE prop_page;
1659   
1660   *do_print = FALSE;
1661
1662   priv = op->priv;
1663   
1664   op_win32 = g_new0 (GtkPrintOperationWin32, 1);
1665   priv->platform_data = op_win32;
1666   priv->free_platform_data = (GDestroyNotify) op_win32_free;
1667   
1668   if (parent == NULL)
1669     {
1670       invisible = gtk_invisible_new ();
1671       parentHWnd = get_parent_hwnd (invisible);
1672     }
1673   else 
1674     parentHWnd = get_parent_hwnd (GTK_WIDGET (parent));
1675
1676   printdlgex = (LPPRINTDLGEXW)GlobalAlloc (GPTR, sizeof (PRINTDLGEXW));
1677   if (!printdlgex)
1678     {
1679       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1680       g_set_error_literal (&priv->error,
1681                            GTK_PRINT_ERROR,
1682                            GTK_PRINT_ERROR_NOMEM,
1683                            _("Not enough free memory"));
1684       goto out;
1685     }      
1686
1687   printdlgex->lStructSize = sizeof (PRINTDLGEXW);
1688   printdlgex->hwndOwner = parentHWnd;
1689   printdlgex->hDevMode = NULL;
1690   printdlgex->hDevNames = NULL;
1691   printdlgex->hDC = NULL;
1692   printdlgex->Flags = PD_RETURNDC | PD_NOSELECTION;
1693   if (op->priv->current_page == -1)
1694     printdlgex->Flags |= PD_NOCURRENTPAGE;
1695   printdlgex->Flags2 = 0;
1696   printdlgex->ExclusionFlags = 0;
1697
1698   page_ranges = (LPPRINTPAGERANGE) GlobalAlloc (GPTR, 
1699                                                 MAX_PAGE_RANGES * sizeof (PRINTPAGERANGE));
1700   if (!page_ranges) 
1701     {
1702       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1703       g_set_error_literal (&priv->error,
1704                            GTK_PRINT_ERROR,
1705                            GTK_PRINT_ERROR_NOMEM,
1706                            _("Not enough free memory"));
1707       goto out;
1708     }
1709
1710   printdlgex->nPageRanges = 0;
1711   printdlgex->nMaxPageRanges = MAX_PAGE_RANGES;
1712   printdlgex->lpPageRanges = page_ranges;
1713   printdlgex->nMinPage = 1;
1714   if (op->priv->nr_of_pages != -1)
1715     printdlgex->nMaxPage = op->priv->nr_of_pages;
1716   else
1717     printdlgex->nMaxPage = 10000;
1718   printdlgex->nCopies = 1;
1719   printdlgex->hInstance = 0;
1720   printdlgex->lpPrintTemplateName = NULL;
1721   printdlgex->lpCallback = NULL;
1722
1723   g_signal_emit_by_name (op, "create-custom-widget",
1724                          &op->priv->custom_widget);
1725   if (op->priv->custom_widget) {
1726     prop_page = create_application_page (op);
1727     printdlgex->nPropertyPages = 1;
1728     printdlgex->lphPropertyPages = &prop_page;
1729   } else {
1730     printdlgex->nPropertyPages = 0;
1731     printdlgex->lphPropertyPages = NULL;
1732   }
1733   
1734   printdlgex->nStartPage = START_PAGE_GENERAL;
1735   printdlgex->dwResultAction = 0;
1736
1737   dialog_from_print_settings (op, printdlgex);
1738
1739   callback = print_callback_new ();
1740   printdlgex->lpCallback = (IUnknown *)callback;
1741   got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
1742
1743   hResult = PrintDlgExW (printdlgex);
1744   IUnknown_Release ((IUnknown *)callback);
1745   gdk_win32_set_modal_dialog_libgtk_only (NULL);
1746
1747   if (hResult != S_OK) 
1748     {
1749       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1750       if (hResult == E_OUTOFMEMORY)
1751         g_set_error_literal (&priv->error,
1752                              GTK_PRINT_ERROR,
1753                              GTK_PRINT_ERROR_NOMEM,
1754                              _("Not enough free memory"));
1755       else if (hResult == E_INVALIDARG)
1756         g_set_error_literal (&priv->error,
1757                              GTK_PRINT_ERROR,
1758                              GTK_PRINT_ERROR_INTERNAL_ERROR,
1759                              _("Invalid argument to PrintDlgEx"));
1760       else if (hResult == E_POINTER)
1761         g_set_error_literal (&priv->error,
1762                              GTK_PRINT_ERROR,
1763                              GTK_PRINT_ERROR_INTERNAL_ERROR,
1764                              _("Invalid pointer to PrintDlgEx"));
1765       else if (hResult == E_HANDLE)
1766         g_set_error_literal (&priv->error,
1767                              GTK_PRINT_ERROR,
1768                              GTK_PRINT_ERROR_INTERNAL_ERROR,
1769                              _("Invalid handle to PrintDlgEx"));
1770       else /* E_FAIL */
1771         g_set_error_literal (&priv->error,
1772                              GTK_PRINT_ERROR,
1773                              GTK_PRINT_ERROR_GENERAL,
1774                              _("Unspecified error"));
1775       goto out;
1776     }
1777
1778   if (printdlgex->dwResultAction == PD_RESULT_PRINT ||
1779       printdlgex->dwResultAction == PD_RESULT_APPLY)
1780     {
1781       result = GTK_PRINT_OPERATION_RESULT_APPLY;
1782       dialog_to_print_settings (op, printdlgex);
1783     }
1784   else
1785     result = GTK_PRINT_OPERATION_RESULT_CANCEL;
1786   
1787   if (printdlgex->dwResultAction == PD_RESULT_PRINT)
1788     {
1789       DOCINFOW docinfo;
1790       int job_id;
1791       double dpi_x, dpi_y;
1792       cairo_t *cr;
1793       GtkPageSetup *page_setup;
1794
1795       priv->print_context = _gtk_print_context_new (op);
1796       page_setup = create_page_setup (op);
1797       _gtk_print_context_set_page_setup (priv->print_context, page_setup);
1798       g_object_unref (page_setup);
1799       
1800       *do_print = TRUE;
1801
1802       op_win32->surface = cairo_win32_printing_surface_create (printdlgex->hDC);
1803
1804       dpi_x = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSX);
1805       dpi_y = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSY);
1806
1807       cr = cairo_create (op_win32->surface);
1808       gtk_print_context_set_cairo_context (priv->print_context, cr, dpi_x, dpi_y);
1809       cairo_destroy (cr);
1810
1811       set_hard_margins (op);
1812
1813       memset ( &docinfo, 0, sizeof (DOCINFOW));
1814       docinfo.cbSize = sizeof (DOCINFOW); 
1815       docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL); 
1816       docinfo.lpszOutput = (LPCWSTR) NULL; 
1817       docinfo.lpszDatatype = (LPCWSTR) NULL; 
1818       docinfo.fwType = 0; 
1819
1820       job_id = StartDocW (printdlgex->hDC, &docinfo); 
1821       g_free ((void *)docinfo.lpszDocName);
1822       if (job_id <= 0) 
1823         {
1824           result = GTK_PRINT_OPERATION_RESULT_ERROR;
1825           g_set_error_literal (&priv->error,
1826                                GTK_PRINT_ERROR,
1827                                GTK_PRINT_ERROR_GENERAL,
1828                                _("Error from StartDoc"));
1829           *do_print = FALSE;
1830           cairo_surface_destroy (op_win32->surface);
1831           op_win32->surface = NULL;
1832           goto out; 
1833         } 
1834       
1835       op_win32->hdc = printdlgex->hDC;
1836       op_win32->devmode = printdlgex->hDevMode;
1837       op_win32->devnames = printdlgex->hDevNames;
1838       op_win32->job_id = job_id;
1839       
1840       op->priv->print_pages = gtk_print_settings_get_print_pages (op->priv->print_settings);
1841       op->priv->num_page_ranges = 0;
1842       if (op->priv->print_pages == GTK_PRINT_PAGES_RANGES)
1843         op->priv->page_ranges = gtk_print_settings_get_page_ranges (op->priv->print_settings,
1844                                                                     &op->priv->num_page_ranges);
1845       op->priv->manual_num_copies = printdlgex->nCopies;
1846       op->priv->manual_collation = (printdlgex->Flags & PD_COLLATE) != 0;
1847       op->priv->manual_reverse = FALSE;
1848       op->priv->manual_orientation = FALSE;
1849       op->priv->manual_scale = 1.0;
1850       op->priv->manual_page_set = GTK_PAGE_SET_ALL;
1851       op->priv->manual_number_up = 1;
1852       op->priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
1853     }
1854
1855   op->priv->start_page = win32_start_page;
1856   op->priv->end_page = win32_end_page;
1857   op->priv->end_run = win32_end_run;
1858   
1859   out:
1860   if (!*do_print && printdlgex && printdlgex->hDC != NULL)
1861     DeleteDC (printdlgex->hDC);
1862
1863   if (!*do_print && printdlgex && printdlgex->hDevMode != NULL) 
1864     GlobalFree (printdlgex->hDevMode); 
1865
1866   if (!*do_print && printdlgex && printdlgex->hDevNames != NULL) 
1867     GlobalFree (printdlgex->hDevNames); 
1868
1869   if (page_ranges)
1870     GlobalFree (page_ranges);
1871
1872   if (printdlgex)
1873     GlobalFree (printdlgex);
1874
1875   if (invisible)
1876     gtk_widget_destroy (invisible);
1877
1878   return result;
1879 }
1880
1881 GtkPrintOperationResult
1882 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
1883                                                   gboolean           show_dialog,
1884                                                   GtkWindow         *parent,
1885                                                   gboolean          *do_print)
1886 {
1887   if (show_dialog)
1888     return gtk_print_operation_run_with_dialog (op, parent, do_print);
1889   else
1890     return gtk_print_operation_run_without_dialog (op, do_print);
1891 }
1892
1893 void
1894 _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
1895                                                       cairo_surface_t   *surface,
1896                                                       GtkWindow         *parent,
1897                                                       const gchar       *filename)
1898 {
1899   HDC dc;
1900   HENHMETAFILE metafile;
1901   
1902   dc = cairo_win32_surface_get_dc (surface);
1903   cairo_surface_destroy (surface);
1904   metafile = CloseEnhMetaFile (dc);
1905   DeleteEnhMetaFile (metafile);
1906   
1907   ShellExecuteW (NULL, L"open", (gunichar2 *)filename, NULL, NULL, SW_SHOW);
1908 }
1909
1910 void
1911 _gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op,
1912                                                           cairo_surface_t *surface,
1913                                                           cairo_t *cr)
1914 {
1915   HDC dc = cairo_win32_surface_get_dc (surface);
1916   StartPage (dc);
1917 }
1918
1919 void
1920 _gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op,
1921                                                         cairo_surface_t *surface,
1922                                                         cairo_t *cr)
1923 {
1924   HDC dc;
1925
1926   cairo_surface_show_page (surface);
1927
1928   /* TODO: Enhanced metafiles don't support multiple pages.
1929    */
1930   dc = cairo_win32_surface_get_dc (surface);
1931   EndPage (dc);
1932 }
1933
1934 cairo_surface_t *
1935 _gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
1936                                                               GtkPageSetup      *page_setup,
1937                                                               gdouble           *dpi_x,
1938                                                               gdouble           *dpi_y,
1939                                                               gchar            **target)
1940 {
1941   GtkPaperSize *paper_size;
1942   HDC metafile_dc;
1943   RECT rect;
1944   char *template;
1945   char *filename;
1946   gunichar2 *filename_utf16;
1947   int fd;
1948
1949   template = g_build_filename (g_get_tmp_dir (), "prXXXXXX", NULL);
1950   fd = g_mkstemp (template);
1951   close (fd);
1952
1953   filename = g_strconcat (template, ".emf", NULL);
1954   g_free (template);
1955   
1956   filename_utf16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1957   g_free (filename);
1958
1959   paper_size = gtk_page_setup_get_paper_size (page_setup);
1960
1961   /* The rectangle dimensions are given in hundredths of a millimeter */
1962   rect.left = 0;
1963   rect.right = 100.0 * gtk_paper_size_get_width (paper_size, GTK_UNIT_MM);
1964   rect.top = 0;
1965   rect.bottom = 100.0 * gtk_paper_size_get_height (paper_size, GTK_UNIT_MM);
1966   
1967   metafile_dc = CreateEnhMetaFileW (NULL, filename_utf16,
1968                                     &rect, L"Gtk+\0Print Preview\0\0");
1969   if (metafile_dc == NULL)
1970     {
1971       g_warning ("Can't create metafile");
1972       return NULL;
1973     }
1974
1975   *target = (char *)filename_utf16;
1976   
1977   *dpi_x = (double)GetDeviceCaps (metafile_dc, LOGPIXELSX);
1978   *dpi_y = (double)GetDeviceCaps (metafile_dc, LOGPIXELSY);
1979
1980   return cairo_win32_printing_surface_create (metafile_dc);
1981 }
1982
1983 void
1984 _gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op,
1985                                                               GtkPageSetup      *page_setup,
1986                                                               cairo_surface_t   *surface)
1987 {
1988   /* TODO: Implement */
1989 }
1990
1991 GtkPageSetup *
1992 gtk_print_run_page_setup_dialog (GtkWindow        *parent,
1993                                  GtkPageSetup     *page_setup,
1994                                  GtkPrintSettings *settings)
1995 {
1996   LPPAGESETUPDLGW pagesetupdlg = NULL;
1997   BOOL res;
1998   gboolean free_settings;
1999   const char *printer;
2000   GtkPaperSize *paper_size;
2001   DWORD measure_system;
2002   GtkUnit unit;
2003   double scale;
2004
2005   pagesetupdlg = (LPPAGESETUPDLGW)GlobalAlloc (GPTR, sizeof (PAGESETUPDLGW));
2006   if (!pagesetupdlg)
2007     return NULL;
2008
2009   free_settings = FALSE;
2010   if (settings == NULL)
2011     {
2012       settings = gtk_print_settings_new ();
2013       free_settings = TRUE;
2014     }
2015   
2016   memset (pagesetupdlg, 0, sizeof (PAGESETUPDLGW));
2017
2018   pagesetupdlg->lStructSize = sizeof (PAGESETUPDLGW);
2019
2020   if (parent != NULL)
2021     pagesetupdlg->hwndOwner = get_parent_hwnd (GTK_WIDGET (parent));
2022   else
2023     pagesetupdlg->hwndOwner = NULL;
2024
2025   pagesetupdlg->Flags = PSD_DEFAULTMINMARGINS;
2026   pagesetupdlg->hDevMode = devmode_from_settings (settings, page_setup);
2027   pagesetupdlg->hDevNames = NULL;
2028   printer = gtk_print_settings_get_printer (settings);
2029   if (printer)
2030     pagesetupdlg->hDevNames = gtk_print_win32_devnames_to_win32_from_printer_name (printer);
2031
2032   GetLocaleInfoW (LOCALE_USER_DEFAULT, LOCALE_IMEASURE|LOCALE_RETURN_NUMBER,
2033                   (LPWSTR)&measure_system, sizeof (DWORD));
2034
2035   if (measure_system == 0)
2036     {
2037       pagesetupdlg->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS;
2038       unit = GTK_UNIT_MM;
2039       scale = 100;
2040     }
2041   else
2042     {
2043       pagesetupdlg->Flags |= PSD_INTHOUSANDTHSOFINCHES;
2044       unit = GTK_UNIT_INCH;
2045       scale = 1000;
2046     }
2047
2048   /* This is the object we return, we allocate it here so that
2049    * we can use the default page margins */
2050   if (page_setup)
2051     page_setup = gtk_page_setup_copy (page_setup);
2052   else
2053     page_setup = gtk_page_setup_new ();
2054   
2055   pagesetupdlg->Flags |= PSD_MARGINS;
2056   pagesetupdlg->rtMargin.left =
2057     floor (gtk_page_setup_get_left_margin (page_setup, unit) * scale + 0.5);
2058   pagesetupdlg->rtMargin.right =
2059     floor (gtk_page_setup_get_right_margin (page_setup, unit) * scale + 0.5);
2060   pagesetupdlg->rtMargin.top = 
2061     floor (gtk_page_setup_get_top_margin (page_setup, unit) * scale + 0.5);
2062   pagesetupdlg->rtMargin.bottom =
2063     floor (gtk_page_setup_get_bottom_margin (page_setup, unit) * scale + 0.5);
2064
2065   pagesetupdlg->Flags |= PSD_ENABLEPAGESETUPHOOK;
2066   pagesetupdlg->lpfnPageSetupHook = run_mainloop_hook;
2067   got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
2068   
2069   res = PageSetupDlgW (pagesetupdlg);
2070   gdk_win32_set_modal_dialog_libgtk_only (NULL);
2071
2072   if (res)
2073     {  
2074       if (pagesetupdlg->hDevNames != NULL)
2075         devnames_to_settings (settings, pagesetupdlg->hDevNames);
2076
2077       if (pagesetupdlg->hDevMode != NULL)
2078         devmode_to_settings (settings, pagesetupdlg->hDevMode);
2079     }
2080   
2081   if (res)
2082     {
2083       gtk_page_setup_set_orientation (page_setup, 
2084                                       gtk_print_settings_get_orientation (settings));
2085       paper_size = gtk_print_settings_get_paper_size (settings);
2086       if (paper_size)
2087         {
2088           gtk_page_setup_set_paper_size (page_setup, paper_size);
2089           gtk_paper_size_free (paper_size);
2090         }
2091
2092       if (pagesetupdlg->Flags & PSD_INHUNDREDTHSOFMILLIMETERS)
2093         {
2094           unit = GTK_UNIT_MM;
2095           scale = 100;
2096         }
2097       else
2098         {
2099           unit = GTK_UNIT_INCH;
2100           scale = 1000;
2101         }
2102
2103       gtk_page_setup_set_left_margin (page_setup,
2104                                       pagesetupdlg->rtMargin.left / scale,
2105                                       unit);
2106       gtk_page_setup_set_right_margin (page_setup,
2107                                        pagesetupdlg->rtMargin.right / scale,
2108                                        unit);
2109       gtk_page_setup_set_top_margin (page_setup,
2110                                      pagesetupdlg->rtMargin.top / scale,
2111                                      unit);
2112       gtk_page_setup_set_bottom_margin (page_setup,
2113                                         pagesetupdlg->rtMargin.bottom / scale,
2114                                         unit);
2115     }
2116   
2117   if (free_settings)
2118     g_object_unref (settings);
2119
2120   return page_setup;
2121 }
2122
2123 void
2124 gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
2125                                        GtkPageSetup         *page_setup,
2126                                        GtkPrintSettings     *settings,
2127                                        GtkPageSetupDoneFunc  done_cb,
2128                                        gpointer              data)
2129 {
2130   GtkPageSetup *new_page_setup;
2131
2132   new_page_setup = gtk_print_run_page_setup_dialog (parent, page_setup, settings);
2133   done_cb (new_page_setup, data);
2134   g_object_unref (new_page_setup);
2135 }