]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintoperation-win32.c
Added gtk_print_job_set/get_track_print_status
[~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 #include <stdlib.h>
30 #include <cairo-win32.h>
31 #include <glib.h>
32 #include "gtkprintoperation-private.h"
33 #include "gtkprint-win32.h"
34 #include "gtkintl.h"
35 #include "gtkinvisible.h"
36 #include "gtkalias.h"
37
38 #define MAX_PAGE_RANGES 20
39 #define STATUS_POLLING_TIME 2000
40
41 #ifndef JOB_STATUS_RESTART
42 #define JOB_STATUS_RESTART 0x800
43 #endif
44
45 #ifndef JOB_STATUS_COMPLETE
46 #define JOB_STATUS_COMPLETE 0x1000
47 #endif
48
49 typedef struct {
50   HDC hdc;
51   HGLOBAL devmode;
52   HGLOBAL devnames;
53   HANDLE printerHandle;
54   int job_id;
55   guint timeout_id;
56 } GtkPrintOperationWin32;
57
58 static void win32_poll_status (GtkPrintOperation *op);
59
60 static const GUID myIID_IPrintDialogCallback  = {0x5852a2c3,0x6530,0x11d1,{0xb6,0xa3,0x0,0x0,0xf8,0x75,0x7b,0xf9}};
61
62 #undef INTERFACE
63 #define INTERFACE IPrintDialogCallback
64 DECLARE_INTERFACE_ (IPrintDialogCallback, IUnknown)
65 {
66     STDMETHOD (QueryInterface)(THIS_ REFIID,LPVOID*) PURE;
67     STDMETHOD_ (ULONG, AddRef)(THIS) PURE;
68     STDMETHOD_ (ULONG, Release)(THIS) PURE;
69     STDMETHOD (InitDone)(THIS) PURE;
70     STDMETHOD (SelectionChange)(THIS) PURE;
71     STDMETHOD (HandleMessage)(THIS_ HWND,UINT,WPARAM,LPARAM,LRESULT*) PURE;
72 }; 
73
74 static UINT got_gdk_events_message;
75
76 UINT_PTR CALLBACK
77 run_mainloop_hook (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
78 {
79   if (uiMsg == WM_INITDIALOG)
80     {
81       gdk_win32_set_modal_dialog_libgtk_only (hdlg);
82       while (gtk_events_pending ())
83         gtk_main_iteration ();
84     }
85   else if (uiMsg == got_gdk_events_message)
86     {
87       while (gtk_events_pending ())
88         gtk_main_iteration ();
89       return 1;
90     }
91   return 0;
92 }
93
94 static GtkPageOrientation
95 orientation_from_win32 (short orientation)
96 {
97   if (orientation == DMORIENT_LANDSCAPE)
98     return GTK_PAGE_ORIENTATION_LANDSCAPE;
99   return GTK_PAGE_ORIENTATION_PORTRAIT;
100 }
101
102 static short
103 orientation_to_win32 (GtkPageOrientation orientation)
104 {
105   if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE ||
106       orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE)
107     return DMORIENT_LANDSCAPE;
108   return DMORIENT_PORTRAIT;
109 }
110
111 static GtkPaperSize *
112 paper_size_from_win32 (short size)
113 {
114   const char *name;
115   
116   switch (size)
117     {
118     case DMPAPER_LETTER_TRANSVERSE:
119     case DMPAPER_LETTER:
120     case DMPAPER_LETTERSMALL:
121       name = "na_letter";
122       break;
123     case DMPAPER_TABLOID:
124     case DMPAPER_LEDGER:
125       name = "na_ledger";
126       break;
127     case DMPAPER_LEGAL:
128       name = "na_legal";
129       break;
130     case DMPAPER_STATEMENT:
131       name = "na_invoice";
132       break;
133     case DMPAPER_EXECUTIVE:
134       name = "na_executive";
135       break;
136     case DMPAPER_A3:
137     case DMPAPER_A3_TRANSVERSE:
138       name = "iso_a3";
139       break;
140     case DMPAPER_A4:
141     case DMPAPER_A4SMALL:
142     case DMPAPER_A4_TRANSVERSE:
143       name = "iso_a4";
144       break;
145     case DMPAPER_A5:
146     case DMPAPER_A5_TRANSVERSE:
147       name = "iso_a5";
148       break;
149     case DMPAPER_B4:
150       name = "jis_b4";
151       break;
152     case DMPAPER_B5:
153     case DMPAPER_B5_TRANSVERSE:
154       name = "jis_b5";
155       break;
156     case DMPAPER_QUARTO:
157       name = "na_quarto";
158       break;
159     case DMPAPER_10X14:
160       name = "na_10x14";
161       break;
162     case DMPAPER_11X17:
163       name = "na_ledger";
164       break;
165     case DMPAPER_NOTE:
166       name = "na_letter";
167       break;
168     case DMPAPER_ENV_9:
169       name = "na_number-9";
170       break;
171     case DMPAPER_ENV_10:
172       name = "na_number-10";
173       break;
174     case DMPAPER_ENV_11:
175       name = "na_number-11";
176       break;
177     case DMPAPER_ENV_12:
178       name = "na_number-12";
179       break;
180     case DMPAPER_ENV_14:
181       name = "na_number-14";
182       break;
183     case DMPAPER_CSHEET:
184       name = "na_c";
185       break;
186     case DMPAPER_DSHEET:
187       name = "na_d";
188       break;
189     case DMPAPER_ESHEET:
190       name = "na_e";
191       break;
192     case DMPAPER_ENV_DL:
193       name = "iso_dl";
194       break;
195     case DMPAPER_ENV_C5:
196       name = "iso_c5";
197       break;
198     case DMPAPER_ENV_C3:
199       name = "iso_c3";
200       break;
201     case DMPAPER_ENV_C4:
202       name = "iso_c4";
203       break;
204     case DMPAPER_ENV_C6:
205       name = "iso_c6";
206       break;
207     case DMPAPER_ENV_C65:
208       name = "iso_c6c5";
209       break;
210     case DMPAPER_ENV_B4:
211       name = "iso_b4";
212       break;
213     case DMPAPER_ENV_B5:
214       name = "iso_b5";
215       break;
216     case DMPAPER_ENV_B6:
217       name = "iso_b6";
218       break;
219     case DMPAPER_ENV_ITALY:
220       name = "om_italian";
221       break;
222     case DMPAPER_ENV_MONARCH:
223       name = "na_monarch";
224       break;
225     case DMPAPER_ENV_PERSONAL:
226       name = "na_personal";
227       break;
228     case DMPAPER_FANFOLD_US:
229       name = "na_fanfold-us";
230       break;
231     case DMPAPER_FANFOLD_STD_GERMAN:
232       name = "na_fanfold-eur";
233       break;
234     case DMPAPER_FANFOLD_LGL_GERMAN:
235       name = "na_foolscap";
236       break;
237     case DMPAPER_ISO_B4:
238       name = "iso_b4";
239       break;
240     case DMPAPER_JAPANESE_POSTCARD:
241       name = "jpn_hagaki";
242       break;
243     case DMPAPER_9X11:
244       name = "na_9x11";
245       break;
246     case DMPAPER_10X11:
247       name = "na_10x11";
248       break;
249     case DMPAPER_ENV_INVITE:
250       name = "om_invite";
251        break;
252     case DMPAPER_LETTER_EXTRA:
253     case DMPAPER_LETTER_EXTRA_TRANSVERSE:
254       name = "na_letter-extra";
255       break;
256     case DMPAPER_LEGAL_EXTRA:
257       name = "na_legal-extra";
258       break;
259     case DMPAPER_TABLOID_EXTRA:
260       name = "na_arch";
261       break;
262     case DMPAPER_A4_EXTRA:
263       name = "iso_a4-extra";
264       break;
265     case DMPAPER_B_PLUS:
266       name = "na_b-plus";
267       break;
268     case DMPAPER_LETTER_PLUS:
269       name = "na_letter-plus";
270       break;
271     case DMPAPER_A3_EXTRA:
272     case DMPAPER_A3_EXTRA_TRANSVERSE:
273       name = "iso_a3-extra";
274       break;
275     case DMPAPER_A5_EXTRA:
276       name = "iso_a5-extra";
277       break;
278     case DMPAPER_B5_EXTRA:
279       name = "iso_b5-extra";
280       break;
281     case DMPAPER_A2:
282       name = "iso_a2";
283       break;
284       
285     default:
286       name = NULL;
287       break;
288     }
289
290   if (name)
291     return gtk_paper_size_new (name);
292   else 
293     return NULL;
294 }
295
296 static short
297 paper_size_to_win32 (GtkPaperSize *paper_size)
298 {
299   const char *format;
300
301   if (gtk_paper_size_is_custom (paper_size))
302     return 0;
303   
304   format = gtk_paper_size_get_name (paper_size);
305
306   if (strcmp (format, "na_letter") == 0)
307     return DMPAPER_LETTER;
308   if (strcmp (format, "na_ledger") == 0)
309     return DMPAPER_LEDGER;
310   if (strcmp (format, "na_legal") == 0)
311     return DMPAPER_LEGAL;
312   if (strcmp (format, "na_invoice") == 0)
313     return DMPAPER_STATEMENT;
314   if (strcmp (format, "na_executive") == 0)
315     return DMPAPER_EXECUTIVE;
316   if (strcmp (format, "iso_a2") == 0)
317     return DMPAPER_A2;
318   if (strcmp (format, "iso_a3") == 0)
319     return DMPAPER_A3;
320   if (strcmp (format, "iso_a4") == 0)
321     return DMPAPER_A4;
322   if (strcmp (format, "iso_a5") == 0)
323     return DMPAPER_A5;
324   if (strcmp (format, "iso_b4") == 0)
325     return DMPAPER_B4;
326   if (strcmp (format, "iso_b5") == 0)
327     return DMPAPER_B5;
328   if (strcmp (format, "na_quarto") == 0)
329     return DMPAPER_QUARTO;
330   if (strcmp (format, "na_10x14") == 0)
331     return DMPAPER_10X14;
332   if (strcmp (format, "na_number-9") == 0)
333     return DMPAPER_ENV_9;
334   if (strcmp (format, "na_number-10") == 0)
335     return DMPAPER_ENV_10;
336   if (strcmp (format, "na_number-11") == 0)
337     return DMPAPER_ENV_11;
338   if (strcmp (format, "na_number-12") == 0)
339     return DMPAPER_ENV_12;
340   if (strcmp (format, "na_number-14") == 0)
341     return DMPAPER_ENV_14;
342   if (strcmp (format, "na_c") == 0)
343     return DMPAPER_CSHEET;
344   if (strcmp (format, "na_d") == 0)
345     return DMPAPER_DSHEET;
346   if (strcmp (format, "na_e") == 0)
347     return DMPAPER_ESHEET;
348   if (strcmp (format, "iso_dl") == 0)
349     return DMPAPER_ENV_DL;
350   if (strcmp (format, "iso_c3") == 0)
351     return DMPAPER_ENV_C3;
352   if (strcmp (format, "iso_c4") == 0)
353     return DMPAPER_ENV_C4;
354   if (strcmp (format, "iso_c5") == 0)
355     return DMPAPER_ENV_C5;
356   if (strcmp (format, "iso_c6") == 0)
357     return DMPAPER_ENV_C6;
358   if (strcmp (format, "iso_c5c6") == 0)
359     return DMPAPER_ENV_C65;
360   if (strcmp (format, "iso_b6") == 0)
361     return DMPAPER_ENV_B6;
362   if (strcmp (format, "om_italian") == 0)
363     return DMPAPER_ENV_ITALY;
364   if (strcmp (format, "na_monarch") == 0)
365     return DMPAPER_ENV_MONARCH;
366   if (strcmp (format, "na_personal") == 0)
367     return DMPAPER_ENV_PERSONAL;
368   if (strcmp (format, "na_fanfold-us") == 0)
369     return DMPAPER_FANFOLD_US;
370   if (strcmp (format, "na_fanfold-eur") == 0)
371     return DMPAPER_FANFOLD_STD_GERMAN;
372   if (strcmp (format, "na_foolscap") == 0)
373     return DMPAPER_FANFOLD_LGL_GERMAN;
374   if (strcmp (format, "jpn_hagaki") == 0)
375     return DMPAPER_JAPANESE_POSTCARD;
376   if (strcmp (format, "na_9x11") == 0)
377     return DMPAPER_9X11;
378   if (strcmp (format, "na_10x11") == 0)
379     return DMPAPER_10X11;
380   if (strcmp (format, "om_invite") == 0)
381     return DMPAPER_ENV_INVITE;
382   if (strcmp (format, "na_letter-extra") == 0)
383     return DMPAPER_LETTER_EXTRA;
384   if (strcmp (format, "na_legal-extra") == 0)
385     return DMPAPER_LEGAL_EXTRA;
386   if (strcmp (format, "na_arch") == 0)
387     return DMPAPER_TABLOID_EXTRA;
388   if (strcmp (format, "iso_a3-extra") == 0)
389     return DMPAPER_A3_EXTRA;
390   if (strcmp (format, "iso_a4-extra") == 0)
391     return DMPAPER_A4_EXTRA;
392   if (strcmp (format, "iso_a5-extra") == 0)
393     return DMPAPER_A5_EXTRA;
394   if (strcmp (format, "iso_b5-extra") == 0)
395     return DMPAPER_B5_EXTRA;
396   if (strcmp (format, "na_b-plus") == 0)
397     return DMPAPER_B_PLUS;
398   if (strcmp (format, "na_letter-plus") == 0)
399     return DMPAPER_LETTER_PLUS;
400
401   return 0;
402 }
403
404 void
405 win32_start_page (GtkPrintOperation *op,
406                   GtkPrintContext *print_context,
407                   GtkPageSetup *page_setup)
408 {
409   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
410   LPDEVMODEW devmode;
411   GtkPaperSize *paper_size;
412
413   devmode = GlobalLock (op_win32->devmode);
414   
415   devmode->dmFields |= DM_ORIENTATION;
416   devmode->dmOrientation =
417     orientation_to_win32 (gtk_page_setup_get_orientation (page_setup));
418   
419   paper_size = gtk_page_setup_get_paper_size (page_setup);
420   devmode->dmFields |= DM_PAPERSIZE;
421   devmode->dmFields &= ~(DM_PAPERWIDTH | DM_PAPERLENGTH);
422   devmode->dmPaperSize = paper_size_to_win32 (paper_size);
423   if (devmode->dmPaperSize == 0)
424     {
425       devmode->dmPaperSize = DMPAPER_USER;
426       devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
427       devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) * 10.0;
428       devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) * 10.0;
429     }
430   
431   ResetDCW (op_win32->hdc, devmode);
432   
433   GlobalUnlock (op_win32->devmode);
434   
435   StartPage (op_win32->hdc);
436 }
437
438 static void
439 win32_end_page (GtkPrintOperation *op,
440                 GtkPrintContext *print_context)
441 {
442   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
443   EndPage (op_win32->hdc);
444 }
445
446 static gboolean
447 win32_poll_status_timeout (GtkPrintOperation *op)
448 {
449   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
450   
451   op_win32->timeout_id = 0;
452   /* We need to ref this, as setting the status to finished
453      might unref the object */
454   g_object_ref (op);
455   win32_poll_status (op);
456
457   if (!gtk_print_operation_is_finished (op))
458     op_win32->timeout_id = g_timeout_add (STATUS_POLLING_TIME,
459                                           (GSourceFunc)win32_poll_status_timeout,
460                                           op);
461   g_object_unref (op);
462   return FALSE;
463 }
464
465
466 static void
467 win32_end_run (GtkPrintOperation *op)
468 {
469   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
470   LPDEVNAMES devnames;
471   HANDLE printerHandle = 0;
472   
473   EndDoc (op_win32->hdc);
474
475   if (op->track_print_status)
476     {
477       devnames = GlobalLock (op_win32->devnames);
478       if (!OpenPrinterW (((gunichar2 *)devnames) + devnames->wDeviceOffset,
479                          &printerHandle, NULL))
480         printerHandle = 0;
481       GlobalUnlock (op_win32->devnames);
482     }
483   
484   GlobalFree(op_win32->devmode);
485   GlobalFree(op_win32->devnames);
486
487   cairo_surface_destroy (op->priv->surface);
488   op->priv->surface = NULL;
489
490   DeleteDC(op_win32->hdc);
491   
492   if (printerHandle != 0)
493     {
494       op_win32->printerHandle = printerHandle;
495       win32_poll_status (op);
496       op_win32->timeout_id = g_timeout_add (STATUS_POLLING_TIME,
497                                             (GSourceFunc)win32_poll_status_timeout,
498                                             op);
499     }
500   else
501     /* Dunno what happened, pretend its finished */
502     _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED, NULL);
503 }
504
505 static void
506 win32_poll_status (GtkPrintOperation *op)
507 {
508   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
509   guchar *data;
510   DWORD needed;
511   JOB_INFO_1W *job_info;
512   GtkPrintStatus status;
513   char *status_str;
514   BOOL ret;
515
516   GetJobW (op_win32->printerHandle, op_win32->job_id,
517            1,(LPBYTE)NULL, 0, &needed);
518   data = g_malloc (needed);
519   ret = GetJobW (op_win32->printerHandle, op_win32->job_id,
520                  1, (LPBYTE)data, needed, &needed);
521
522   status_str = NULL;
523   if (ret)
524     {
525       job_info = (JOB_INFO_1W *)data;
526       DWORD win32_status = job_info->Status;
527
528       if (job_info->pStatus)
529         status_str = g_utf16_to_utf8 (job_info->pStatus, 
530                                       -1, NULL, NULL, NULL);
531      
532       if (win32_status &
533           (JOB_STATUS_COMPLETE | JOB_STATUS_PRINTED))
534         status = GTK_PRINT_STATUS_FINISHED;
535       else if (win32_status &
536                (JOB_STATUS_OFFLINE |
537                 JOB_STATUS_PAPEROUT |
538                 JOB_STATUS_PAUSED |
539                 JOB_STATUS_USER_INTERVENTION))
540         {
541           status = GTK_PRINT_STATUS_PENDING_ISSUE;
542           if (status_str == NULL)
543             {
544               if (win32_status & JOB_STATUS_OFFLINE)
545                 status_str = g_strdup (_("Printer offline"));
546               else if (win32_status & JOB_STATUS_PAPEROUT)
547                 status_str = g_strdup (_("Out of paper"));
548               else if (win32_status & JOB_STATUS_PAUSED)
549                 status_str = g_strdup (_("Paused"));
550               else if (win32_status & JOB_STATUS_USER_INTERVENTION)
551                 status_str = g_strdup (_("Need user intervention"));
552             }
553         }
554       else if (win32_status &
555                (JOB_STATUS_BLOCKED_DEVQ |
556                 JOB_STATUS_DELETED |
557                 JOB_STATUS_ERROR))
558         status = GTK_PRINT_STATUS_FINISHED_ABORTED;
559       else if (win32_status &
560                (JOB_STATUS_SPOOLING |
561                 JOB_STATUS_DELETING))
562         status = GTK_PRINT_STATUS_PENDING;
563       else if (win32_status & JOB_STATUS_PRINTING)
564         status = GTK_PRINT_STATUS_PRINTING;
565       else
566         status = GTK_PRINT_STATUS_FINISHED;
567     }
568   else
569     status = GTK_PRINT_STATUS_FINISHED;
570
571   g_free (data);
572
573   _gtk_print_operation_set_status (op, status, status_str);
574  
575   g_free (status_str);
576 }
577
578 static void
579 op_win32_free (GtkPrintOperationWin32 *op_win32)
580 {
581   if (op_win32->printerHandle)
582     ClosePrinter (op_win32->printerHandle);
583   if (op_win32->timeout_id != 0)
584     g_source_remove (op_win32->timeout_id);
585   g_free (op_win32);
586 }
587
588 static HWND
589 get_parent_hwnd (GtkWidget *widget)
590 {
591   gtk_widget_realize (widget);
592   return gdk_win32_drawable_get_handle (widget->window);
593 }
594
595
596 static void
597 devnames_to_settings (GtkPrintSettings *settings,
598                       HANDLE hDevNames)
599 {
600   GtkPrintWin32Devnames *devnames = gtk_print_win32_devnames_from_win32 (hDevNames);
601   gtk_print_settings_set_printer (settings, devnames->device);
602   gtk_print_win32_devnames_free (devnames);
603 }
604
605 static void
606 devmode_to_settings (GtkPrintSettings *settings,
607                      HANDLE hDevMode)
608 {
609   LPDEVMODEW devmode;
610
611   devmode = GlobalLock (hDevMode);
612   
613   gtk_print_settings_set_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION,
614                               devmode->dmDriverVersion);
615   if (devmode->dmDriverExtra != 0)
616     {
617       char *extra = g_base64_encode (((char *)devmode) + sizeof (DEVMODEW),
618                                      devmode->dmDriverExtra);
619       gtk_print_settings_set (settings,
620                               GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA,
621                               extra);
622       g_free (extra);
623     }
624   
625   if (devmode->dmFields & DM_ORIENTATION)
626     gtk_print_settings_set_orientation (settings,
627                                         orientation_from_win32 (devmode->dmOrientation));
628   
629   
630   if (devmode->dmFields & DM_PAPERSIZE &&
631       devmode->dmPaperSize != 0)
632     {
633       GtkPaperSize *paper_size = paper_size_from_win32 (devmode->dmPaperSize);
634       if (paper_size)
635         {
636           gtk_print_settings_set_paper_size (settings, paper_size);
637           gtk_paper_size_free (paper_size);
638         }
639       gtk_print_settings_set_int (settings, "win32-paper-size", (int)devmode->dmPaperSize);
640     }
641   else if ((devmode->dmFields & DM_PAPERSIZE &&
642             devmode->dmPaperSize == 0) ||
643            ((devmode->dmFields & DM_PAPERWIDTH) &&
644             (devmode->dmFields & DM_PAPERLENGTH)))
645     {
646       GtkPaperSize *paper_size;
647       char *form_name = NULL;
648       if (devmode->dmFields & DM_FORMNAME)
649         form_name = g_utf16_to_utf8 (devmode->dmFormName, 
650                                      -1, NULL, NULL, NULL);
651       if (form_name == NULL || form_name[0] == 0)
652         form_name = g_strdup (_("Custom size"));
653       paper_size = gtk_paper_size_new_custom (form_name,
654                                               form_name,
655                                               devmode->dmPaperWidth * 10.0,
656                                               devmode->dmPaperLength * 10.0,
657                                               GTK_UNIT_MM);
658       gtk_print_settings_set_paper_size (settings, paper_size);
659       gtk_paper_size_free (paper_size);
660     }
661   
662   if (devmode->dmFields & DM_SCALE)
663     gtk_print_settings_set_scale (settings,
664                                   devmode->dmScale / 100.0);
665   
666   if (devmode->dmFields & DM_COPIES)
667     gtk_print_settings_set_n_copies (settings,
668                                      devmode->dmCopies);
669   
670   if (devmode->dmFields & DM_DEFAULTSOURCE)
671     {
672       char *source;
673       switch (devmode->dmDefaultSource)
674         {
675         default:
676         case DMBIN_AUTO:
677           source = "auto";
678           break;
679         case DMBIN_CASSETTE:
680           source = "cassette";
681           break;
682         case DMBIN_ENVELOPE:
683           source = "envelope";
684           break;
685         case DMBIN_ENVMANUAL:
686           source = "envelope-manual";
687           break;
688         case DMBIN_LOWER:
689           source = "lower";
690           break;
691         case DMBIN_MANUAL:
692           source = "manual";
693           break;
694         case DMBIN_MIDDLE:
695           source = "middle";
696           break;
697         case DMBIN_ONLYONE:
698           source = "only-one";
699           break;
700         case DMBIN_FORMSOURCE:
701           source = "form-source";
702           break;
703         case DMBIN_LARGECAPACITY:
704           source = "large-capacity";
705           break;
706         case DMBIN_LARGEFMT:
707           source = "large-format";
708           break;
709         case DMBIN_TRACTOR:
710           source = "tractor";
711           break;
712         case DMBIN_SMALLFMT:
713           source = "small-format";
714           break;
715         }
716       gtk_print_settings_set_default_source (settings, source);
717       gtk_print_settings_set_int (settings, "win32-default-source", devmode->dmDefaultSource);
718     }
719   
720   if (devmode->dmFields & DM_PRINTQUALITY)
721     {
722       GtkPrintQuality quality;
723       switch (devmode->dmPrintQuality)
724         {
725         case DMRES_LOW:
726           quality = GTK_PRINT_QUALITY_LOW;
727           break;
728         case DMRES_MEDIUM:
729           quality = GTK_PRINT_QUALITY_NORMAL;
730           break;
731         default:
732         case DMRES_HIGH:
733           quality = GTK_PRINT_QUALITY_HIGH;
734           break;
735         case DMRES_DRAFT:
736           quality = GTK_PRINT_QUALITY_DRAFT;
737           break;
738         }
739       gtk_print_settings_set_quality (settings, quality);
740       gtk_print_settings_set_int (settings, "win32-print-quality", devmode->dmPrintQuality);
741     }
742   
743   if (devmode->dmFields & DM_COLOR)
744     gtk_print_settings_set_use_color (settings, devmode->dmFields == DMCOLOR_COLOR);
745   
746   if (devmode->dmFields & DM_DUPLEX)
747     {
748       GtkPrintDuplex duplex;
749       switch (devmode->dmDuplex)
750         {
751         default:
752         case DMDUP_SIMPLEX:
753           duplex = GTK_PRINT_DUPLEX_SIMPLEX;
754           break;
755         case DMDUP_HORIZONTAL:
756           duplex = GTK_PRINT_DUPLEX_HORIZONTAL;
757           break;
758         case DMDUP_VERTICAL:
759           duplex = GTK_PRINT_DUPLEX_VERTICAL;
760           break;
761         }
762       
763       gtk_print_settings_set_duplex (settings, duplex);
764     }
765   
766   if (devmode->dmFields & DM_COLLATE)
767     gtk_print_settings_set_collate (settings,
768                                     devmode->dmCollate == DMCOLLATE_TRUE);
769   
770   if (devmode->dmFields & DM_MEDIATYPE)
771     {
772       char *media_type;
773       switch (devmode->dmMediaType)
774         {
775         default:
776         case DMMEDIA_STANDARD:
777           media_type = "stationery";
778           break;
779         case DMMEDIA_TRANSPARENCY:
780           media_type = "transparency";
781           break;
782         case DMMEDIA_GLOSSY:
783           media_type = "photographic-glossy";
784           break;
785         }
786       gtk_print_settings_set_media_type (settings, media_type);
787       gtk_print_settings_set_int (settings, "win32-media-type", devmode->dmMediaType);
788     }
789   
790   if (devmode->dmFields & DM_DITHERTYPE)
791     {
792       char *dither;
793       switch (devmode->dmDitherType)
794         {
795         default:
796         case DMDITHER_FINE:
797           dither = "fine";
798           break;
799         case DMDITHER_NONE:
800           dither = "none";
801           break;
802         case DMDITHER_COARSE:
803           dither = "coarse";
804           break;
805         case DMDITHER_LINEART:
806           dither = "lineart";
807           break;
808         case DMDITHER_GRAYSCALE:
809           dither = "grayscale";
810           break;
811         case DMDITHER_ERRORDIFFUSION:
812           dither = "error-diffusion";
813           break;
814         }
815       gtk_print_settings_set_dither (settings, dither);
816       gtk_print_settings_set_int (settings, "win32-dither-type", devmode->dmDitherType);
817     }
818   
819   GlobalUnlock (hDevMode);
820 }
821
822 static void
823 dialog_to_print_settings (GtkPrintOperation *op,
824                           LPPRINTDLGEXW printdlgex)
825 {
826   int i;
827   GtkPrintSettings *settings;
828
829   settings = gtk_print_settings_new ();
830
831   gtk_print_settings_set_print_pages (settings,
832                                       GTK_PRINT_PAGES_ALL);
833   if (printdlgex->Flags & PD_CURRENTPAGE)
834     gtk_print_settings_set_print_pages (settings,
835                                         GTK_PRINT_PAGES_CURRENT);
836   else if (printdlgex->Flags & PD_PAGENUMS)
837     gtk_print_settings_set_print_pages (settings,
838                                         GTK_PRINT_PAGES_RANGES);
839
840   if (printdlgex->nPageRanges > 0)
841     {
842       GtkPageRange *ranges;
843       ranges = g_new (GtkPageRange, printdlgex->nPageRanges);
844
845       for (i = 0; i < printdlgex->nPageRanges; i++)
846         {
847           ranges[i].start = printdlgex->lpPageRanges[i].nFromPage - 1;
848           ranges[i].end = printdlgex->lpPageRanges[i].nToPage - 1;
849         }
850
851       gtk_print_settings_set_page_ranges (settings, ranges,
852                                           printdlgex->nPageRanges);
853       g_free (ranges);
854     }
855   
856   if (printdlgex->hDevNames != NULL)
857     devnames_to_settings (settings, printdlgex->hDevNames);
858
859   if (printdlgex->hDevMode != NULL)
860     devmode_to_settings (settings, printdlgex->hDevMode);
861   
862   gtk_print_operation_set_print_settings (op, settings);
863 }
864
865 static HANDLE
866 devmode_from_settings (GtkPrintSettings *settings,
867                        GtkPageSetup *page_setup)
868 {
869   HANDLE hDevMode;
870   LPDEVMODEW devmode;
871   char *extras;
872   GtkPaperSize *paper_size;
873   const char *extras_base64;
874   int extras_len;
875   const char *val;
876
877   extras = NULL;
878   extras_len = 0;
879   extras_base64 = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA);
880   if (extras_base64)
881     extras = g_base64_decode (extras_base64, &extras_len);
882   
883   hDevMode = GlobalAlloc (GMEM_MOVEABLE, 
884                           sizeof (DEVMODEW) + extras_len);
885
886   devmode = GlobalLock (hDevMode);
887
888   memset (devmode, 0, sizeof (DEVMODEW));
889   
890   devmode->dmSpecVersion = DM_SPECVERSION;
891   devmode->dmSize = sizeof (DEVMODEW);
892   
893   devmode->dmDriverExtra = 0;
894   if (extras && extras_len > 0)
895     {
896       devmode->dmDriverExtra = extras_len;
897       memcpy (((char *)devmode) + sizeof (DEVMODEW), extras, extras_len);
898       g_free (extras);
899     }
900   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION))
901     devmode->dmDriverVersion = gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION);
902   
903   if (page_setup ||
904       gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION))
905     {
906       GtkPageOrientation orientation = gtk_print_settings_get_orientation (settings);
907       if (page_setup)
908         orientation = gtk_page_setup_get_orientation (page_setup);
909       devmode->dmFields |= DM_ORIENTATION;
910       devmode->dmOrientation = orientation_to_win32 (orientation);
911     }
912
913   if (page_setup)
914     paper_size = gtk_paper_size_copy (gtk_page_setup_get_paper_size (page_setup));
915   else
916     {
917       int size;
918       if (gtk_print_settings_has_key (settings, "win32-paper-size") &&
919           (size = gtk_print_settings_get_int (settings, "win32-paper-size")) != 0)
920         {
921           devmode->dmFields |= DM_PAPERSIZE;
922           devmode->dmPaperSize = size;
923           paper_size = NULL;
924         }
925       else
926         paper_size = gtk_print_settings_get_paper_size (settings);
927     }
928   if (paper_size)
929     {
930       devmode->dmFields |= DM_PAPERSIZE;
931       devmode->dmPaperSize = paper_size_to_win32 (paper_size);
932       if (devmode->dmPaperSize == 0)
933         {
934           devmode->dmPaperSize = DMPAPER_USER;
935           devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
936           devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) / 10.0;
937           devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) / 10.0;
938         }
939       gtk_paper_size_free (paper_size);
940     }
941
942   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_SCALE))
943     {
944       devmode->dmFields |= DM_SCALE;
945       devmode->dmScale = gtk_print_settings_get_scale (settings) * 100;
946     }
947   
948   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_N_COPIES))
949     {
950       devmode->dmFields |= DM_COPIES;
951       devmode->dmCopies = gtk_print_settings_get_n_copies (settings);
952     }
953
954   if (gtk_print_settings_has_key (settings, "win32-default-source"))
955     {
956       devmode->dmFields |= DM_DEFAULTSOURCE;
957       devmode->dmDefaultSource = gtk_print_settings_get_int (settings, "win32-default-source");
958     }
959   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE))
960     {
961       devmode->dmFields |= DM_DEFAULTSOURCE;
962       devmode->dmDefaultSource = DMBIN_AUTO;
963
964       val = gtk_print_settings_get_default_source (settings);
965       if (strcmp (val, "auto") == 0)
966         devmode->dmDefaultSource = DMBIN_AUTO;
967       if (strcmp (val, "cassette") == 0)
968         devmode->dmDefaultSource = DMBIN_CASSETTE;
969       if (strcmp (val, "envelope") == 0)
970         devmode->dmDefaultSource = DMBIN_ENVELOPE;
971       if (strcmp (val, "envelope-manual") == 0)
972         devmode->dmDefaultSource = DMBIN_ENVMANUAL;
973       if (strcmp (val, "lower") == 0)
974         devmode->dmDefaultSource = DMBIN_LOWER;
975       if (strcmp (val, "manual") == 0)
976         devmode->dmDefaultSource = DMBIN_MANUAL;
977       if (strcmp (val, "middle") == 0)
978         devmode->dmDefaultSource = DMBIN_MIDDLE;
979       if (strcmp (val, "only-one") == 0)
980         devmode->dmDefaultSource = DMBIN_ONLYONE;
981       if (strcmp (val, "form-source") == 0)
982         devmode->dmDefaultSource = DMBIN_FORMSOURCE;
983       if (strcmp (val, "large-capacity") == 0)
984         devmode->dmDefaultSource = DMBIN_LARGECAPACITY;
985       if (strcmp (val, "large-format") == 0)
986         devmode->dmDefaultSource = DMBIN_LARGEFMT;
987       if (strcmp (val, "tractor") == 0)
988         devmode->dmDefaultSource = DMBIN_TRACTOR;
989       if (strcmp (val, "small-format") == 0)
990         devmode->dmDefaultSource = DMBIN_SMALLFMT;
991     }
992
993   if (gtk_print_settings_has_key (settings, "win32-print-quality"))
994     {
995       devmode->dmFields |= DM_PRINTQUALITY;
996       devmode->dmPrintQuality = gtk_print_settings_get_int (settings, "win32-print-quality");
997     }
998   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_RESOLUTION))
999     {
1000       devmode->dmFields |= DM_PRINTQUALITY;
1001       devmode->dmPrintQuality = gtk_print_settings_get_resolution (settings);
1002     } 
1003   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_QUALITY))
1004     {
1005       devmode->dmFields |= DM_PRINTQUALITY;
1006       switch (gtk_print_settings_get_quality (settings))
1007         {
1008         case GTK_PRINT_QUALITY_LOW:
1009           devmode->dmPrintQuality = DMRES_LOW;
1010           break;
1011         case GTK_PRINT_QUALITY_DRAFT:
1012           devmode->dmPrintQuality = DMRES_DRAFT;
1013           break;
1014         default:
1015         case GTK_PRINT_QUALITY_NORMAL:
1016           devmode->dmPrintQuality = DMRES_MEDIUM;
1017           break;
1018         case GTK_PRINT_QUALITY_HIGH:
1019           devmode->dmPrintQuality = DMRES_HIGH;
1020           break;
1021         }
1022     }
1023
1024   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_USE_COLOR))
1025     {
1026       devmode->dmFields |= DM_COLOR;
1027       if (gtk_print_settings_get_use_color (settings))
1028         devmode->dmColor = DMCOLOR_COLOR;
1029       else
1030         devmode->dmColor = DMCOLOR_MONOCHROME;
1031     }
1032
1033   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DUPLEX))
1034     {
1035       devmode->dmFields |= DM_DUPLEX;
1036       switch (gtk_print_settings_get_duplex (settings))
1037         {
1038         default:
1039         case GTK_PRINT_DUPLEX_SIMPLEX:
1040           devmode->dmDuplex = DMDUP_SIMPLEX;
1041           break;
1042         case GTK_PRINT_DUPLEX_HORIZONTAL:
1043           devmode->dmDuplex = DMDUP_HORIZONTAL;
1044           break;
1045         case GTK_PRINT_DUPLEX_VERTICAL:
1046           devmode->dmDuplex = DMDUP_VERTICAL;
1047           break;
1048         }
1049     }
1050
1051   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_COLLATE))
1052     {
1053       devmode->dmFields |= DM_COLLATE;
1054       if (gtk_print_settings_get_collate (settings))
1055         devmode->dmCollate = DMCOLLATE_TRUE;
1056       else
1057         devmode->dmCollate = DMCOLLATE_FALSE;
1058     }
1059
1060   if (gtk_print_settings_has_key (settings, "win32-media-type"))
1061     {
1062       devmode->dmFields |= DM_MEDIATYPE;
1063       devmode->dmMediaType = gtk_print_settings_get_int (settings, "win32-media-type");
1064     }
1065   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_MEDIA_TYPE))
1066     {
1067       devmode->dmFields |= DM_MEDIATYPE;
1068       devmode->dmMediaType = DMMEDIA_STANDARD;
1069       
1070       val = gtk_print_settings_get_media_type (settings);
1071       if (strcmp (val, "transparency") == 0)
1072         devmode->dmMediaType = DMMEDIA_TRANSPARENCY;
1073       if (strcmp (val, "photographic-glossy") == 0)
1074         devmode->dmMediaType = DMMEDIA_GLOSSY;
1075     }
1076  
1077   if (gtk_print_settings_has_key (settings, "win32-dither-type"))
1078     {
1079       devmode->dmFields |= DM_DITHERTYPE;
1080       devmode->dmDitherType = gtk_print_settings_get_int (settings, "win32-dither-type");
1081     }
1082   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DITHER))
1083     {
1084       devmode->dmFields |= DM_DITHERTYPE;
1085       devmode->dmDitherType = DMDITHER_FINE;
1086       
1087       val = gtk_print_settings_get_dither (settings);
1088       if (strcmp (val, "none") == 0)
1089         devmode->dmDitherType = DMDITHER_NONE;
1090       if (strcmp (val, "coarse") == 0)
1091         devmode->dmDitherType = DMDITHER_COARSE;
1092       if (strcmp (val, "fine") == 0)
1093         devmode->dmDitherType = DMDITHER_FINE;
1094       if (strcmp (val, "lineart") == 0)
1095         devmode->dmDitherType = DMDITHER_LINEART;
1096       if (strcmp (val, "grayscale") == 0)
1097         devmode->dmDitherType = DMDITHER_GRAYSCALE;
1098       if (strcmp (val, "error-diffusion") == 0)
1099         devmode->dmDitherType = DMDITHER_ERRORDIFFUSION;
1100     }
1101   
1102   GlobalUnlock (hDevMode);
1103
1104   return hDevMode;
1105 }
1106
1107 static void
1108 dialog_from_print_settings (GtkPrintOperation *op,
1109                             LPPRINTDLGEXW printdlgex)
1110 {
1111   GtkPrintSettings *settings = op->priv->print_settings;
1112   const char *printer;
1113
1114   if (settings == NULL)
1115     return;
1116
1117   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PRINT_PAGES))
1118     {
1119       GtkPrintPages print_pages = gtk_print_settings_get_print_pages (settings);
1120
1121       switch (print_pages)
1122         {
1123         default:
1124         case GTK_PRINT_PAGES_ALL:
1125           printdlgex->Flags |= PD_ALLPAGES;
1126           break;
1127         case GTK_PRINT_PAGES_CURRENT:
1128           printdlgex->Flags |= PD_CURRENTPAGE;
1129           break;
1130         case GTK_PRINT_PAGES_RANGES:
1131           printdlgex->Flags |= PD_PAGENUMS;
1132           break;
1133         }
1134     }
1135   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PAGE_RANGES))
1136     {
1137       GtkPageRange *ranges;
1138       int num_ranges, i;
1139
1140       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
1141
1142       if (num_ranges > MAX_PAGE_RANGES)
1143         num_ranges = MAX_PAGE_RANGES;
1144
1145       printdlgex->nPageRanges = num_ranges;
1146       for (i = 0; i < num_ranges; i++)
1147         {
1148           printdlgex->lpPageRanges[i].nFromPage = ranges[i].start + 1;
1149           printdlgex->lpPageRanges[i].nToPage = ranges[i].end + 1;
1150         }
1151     }
1152   
1153   printer = gtk_print_settings_get_printer (settings);
1154   if (printer)
1155     printdlgex->hDevNames = gtk_print_win32_devnames_from_printer_name (printer);
1156   
1157   printdlgex->hDevMode = devmode_from_settings (settings,
1158                                                 op->priv->default_page_setup);
1159 }
1160
1161 typedef struct {
1162   IPrintDialogCallback iPrintDialogCallback;
1163   gboolean set_hwnd;
1164   int ref_count;
1165 } PrintDialogCallback;
1166
1167
1168 static ULONG STDMETHODCALLTYPE
1169 iprintdialogcallback_addref (IPrintDialogCallback *This)
1170 {
1171   PrintDialogCallback *callback = (PrintDialogCallback *)This;
1172   return ++callback->ref_count;
1173 }
1174
1175 static ULONG STDMETHODCALLTYPE
1176 iprintdialogcallback_release (IPrintDialogCallback *This)
1177 {
1178   PrintDialogCallback *callback = (PrintDialogCallback *)This;
1179   int ref_count = --callback->ref_count;
1180
1181   if (ref_count == 0)
1182     g_free (This);
1183
1184   return ref_count;
1185 }
1186
1187 static HRESULT STDMETHODCALLTYPE
1188 iprintdialogcallback_queryinterface (IPrintDialogCallback *This,
1189                                      REFIID       riid,
1190                                      LPVOID      *ppvObject)
1191 {
1192    if (IsEqualIID (riid, &IID_IUnknown) ||
1193        IsEqualIID (riid, &myIID_IPrintDialogCallback))
1194      {
1195        *ppvObject = This;
1196        IUnknown_AddRef ((IUnknown *)This);
1197        return NOERROR;
1198      }
1199    else
1200      {
1201        *ppvObject = NULL;
1202        return E_NOINTERFACE;
1203      }
1204 }
1205
1206 static HRESULT STDMETHODCALLTYPE
1207 iprintdialogcallback_initdone (IPrintDialogCallback *This)
1208 {
1209   return S_FALSE;
1210 }
1211
1212 static HRESULT STDMETHODCALLTYPE
1213 iprintdialogcallback_selectionchange (IPrintDialogCallback *This)
1214 {
1215   return S_FALSE;
1216 }
1217
1218 static HRESULT STDMETHODCALLTYPE
1219 iprintdialogcallback_handlemessage (IPrintDialogCallback *This,
1220                                     HWND hDlg,
1221                                     UINT uMsg,
1222                                     WPARAM wParam,
1223                                     LPARAM lParam,
1224                                     LRESULT *pResult)
1225 {
1226   PrintDialogCallback *callback = (PrintDialogCallback *)This;
1227
1228   if (!callback->set_hwnd)
1229     {
1230       gdk_win32_set_modal_dialog_libgtk_only (hDlg);
1231       callback->set_hwnd = TRUE;
1232       while (gtk_events_pending ())
1233         gtk_main_iteration ();
1234     }
1235   else if (uMsg == got_gdk_events_message)
1236     {
1237       while (gtk_events_pending ())
1238         gtk_main_iteration ();
1239       *pResult = TRUE;
1240       return S_OK;
1241     }
1242   
1243   *pResult = 0;
1244   return S_FALSE;
1245 }
1246
1247 static IPrintDialogCallbackVtbl ipdc_vtbl = {
1248   iprintdialogcallback_queryinterface,
1249   iprintdialogcallback_addref,
1250   iprintdialogcallback_release,
1251   iprintdialogcallback_initdone,
1252   iprintdialogcallback_selectionchange,
1253   iprintdialogcallback_handlemessage
1254 };
1255
1256 static IPrintDialogCallback *
1257 print_callback_new  (void)
1258 {
1259   PrintDialogCallback *callback;
1260
1261   callback = g_new0 (PrintDialogCallback, 1);
1262   callback->iPrintDialogCallback.lpVtbl = &ipdc_vtbl;
1263   callback->ref_count = 1;
1264   callback->set_hwnd = FALSE;
1265
1266   return &callback->iPrintDialogCallback;
1267 }
1268
1269 GtkPrintOperationResult
1270 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
1271                                                   GtkWindow *parent,
1272                                                   gboolean *do_print,
1273                                                   GError **error)
1274 {
1275   HRESULT hResult;
1276   LPPRINTDLGEXW printdlgex = NULL;
1277   LPPRINTPAGERANGE page_ranges = NULL;
1278   HWND parentHWnd;
1279   GtkWidget *invisible = NULL;
1280   GtkPrintOperationResult result;
1281   GtkPrintOperationWin32 *op_win32;
1282   IPrintDialogCallback *callback;
1283   
1284   *do_print = FALSE;
1285
1286   if (parent == NULL)
1287     {
1288       invisible = gtk_invisible_new ();
1289       parentHWnd = get_parent_hwnd (invisible);
1290     }
1291   else 
1292     parentHWnd = get_parent_hwnd (GTK_WIDGET (parent));
1293
1294   printdlgex = (LPPRINTDLGEXW)GlobalAlloc (GPTR, sizeof (PRINTDLGEXW));
1295   if (!printdlgex)
1296     {
1297       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1298       g_set_error (error,
1299                    GTK_PRINT_ERROR,
1300                    GTK_PRINT_ERROR_NOMEM,
1301                    _("Not enough free memory"));
1302       goto out;
1303     }      
1304
1305   printdlgex->lStructSize = sizeof(PRINTDLGEXW);
1306   printdlgex->hwndOwner = parentHWnd;
1307   printdlgex->hDevMode = NULL;
1308   printdlgex->hDevNames = NULL;
1309   printdlgex->hDC = NULL;
1310   printdlgex->Flags = PD_RETURNDC | PD_NOSELECTION;
1311   if (op->priv->current_page == -1)
1312     printdlgex->Flags |= PD_NOCURRENTPAGE;
1313   printdlgex->Flags2 = 0;
1314   printdlgex->ExclusionFlags = 0;
1315
1316   page_ranges = (LPPRINTPAGERANGE) GlobalAlloc (GPTR, 
1317                                                 MAX_PAGE_RANGES * sizeof (PRINTPAGERANGE));
1318   if (!page_ranges) 
1319     {
1320       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1321       g_set_error (error,
1322                    GTK_PRINT_ERROR,
1323                    GTK_PRINT_ERROR_NOMEM,
1324                    _("Not enough free memory"));
1325       goto out;
1326     }
1327
1328   printdlgex->nPageRanges = 0;
1329   printdlgex->nMaxPageRanges = MAX_PAGE_RANGES;
1330   printdlgex->lpPageRanges = page_ranges;
1331   printdlgex->nMinPage = 1;
1332   if (op->priv->nr_of_pages != -1)
1333     printdlgex->nMaxPage = op->priv->nr_of_pages;
1334   else
1335     printdlgex->nMaxPage = 10000;
1336   printdlgex->nCopies = 1;
1337   printdlgex->hInstance = 0;
1338   printdlgex->lpPrintTemplateName = NULL;
1339   printdlgex->lpCallback = NULL;
1340   printdlgex->nPropertyPages = 0;
1341   printdlgex->lphPropertyPages = NULL;
1342   printdlgex->nStartPage = START_PAGE_GENERAL;
1343   printdlgex->dwResultAction = 0;
1344
1345   dialog_from_print_settings (op, printdlgex);
1346
1347   callback = print_callback_new ();
1348   printdlgex->lpCallback = (IUnknown *)callback;
1349   got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
1350   
1351   hResult = PrintDlgExW(printdlgex);
1352   IUnknown_Release ((IUnknown *)callback);
1353   gdk_win32_set_modal_dialog_libgtk_only (NULL);
1354
1355   if (hResult != S_OK) 
1356     {
1357       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1358       if (hResult == E_OUTOFMEMORY)
1359         g_set_error (error,
1360                      GTK_PRINT_ERROR,
1361                      GTK_PRINT_ERROR_NOMEM,
1362                      _("Not enough free memory"));
1363       else if (hResult == E_INVALIDARG)
1364         g_set_error (error,
1365                      GTK_PRINT_ERROR,
1366                      GTK_PRINT_ERROR_INTERNAL_ERROR,
1367                      _("Invalid argument to PrintDlgEx"));
1368       else if (hResult == E_POINTER)
1369         g_set_error (error,
1370                      GTK_PRINT_ERROR,
1371                      GTK_PRINT_ERROR_INTERNAL_ERROR,
1372                      _("Invalid pointer to PrintDlgEx"));
1373       else if (hResult == E_HANDLE)
1374         g_set_error (error,
1375                      GTK_PRINT_ERROR,
1376                      GTK_PRINT_ERROR_INTERNAL_ERROR,
1377                      _("Invalid handle to PrintDlgEx"));
1378       else /* E_FAIL */
1379         g_set_error (error,
1380                      GTK_PRINT_ERROR,
1381                      GTK_PRINT_ERROR_GENERAL,
1382                      _("Unspecified error"));
1383       goto out;
1384     }
1385
1386   if (printdlgex->dwResultAction == PD_RESULT_PRINT ||
1387       printdlgex->dwResultAction == PD_RESULT_APPLY)
1388     {
1389       result = GTK_PRINT_OPERATION_RESULT_APPLY;
1390       dialog_to_print_settings (op, printdlgex);
1391     }
1392   else
1393     result = GTK_PRINT_OPERATION_RESULT_CANCEL;
1394   
1395   if (printdlgex->dwResultAction == PD_RESULT_PRINT)
1396     {
1397       DOCINFOW docinfo;
1398       int job_id;
1399
1400       *do_print = TRUE;
1401
1402       op->priv->surface = cairo_win32_surface_create (printdlgex->hDC);
1403       op->priv->dpi_x = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSX);
1404       op->priv->dpi_y = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSY);
1405
1406       memset( &docinfo, 0, sizeof (DOCINFOW));
1407       docinfo.cbSize = sizeof (DOCINFOW); 
1408       docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL); 
1409       docinfo.lpszOutput = (LPCWSTR) NULL; 
1410       docinfo.lpszDatatype = (LPCWSTR) NULL; 
1411       docinfo.fwType = 0; 
1412
1413       job_id = StartDocW(printdlgex->hDC, &docinfo); 
1414       g_free ((void *)docinfo.lpszDocName);
1415       if (job_id <= 0) 
1416         { 
1417           result = GTK_PRINT_OPERATION_RESULT_ERROR;
1418           g_set_error (error,
1419                        GTK_PRINT_ERROR,
1420                        GTK_PRINT_ERROR_GENERAL,
1421                      _("Error from StartDoc"));
1422           *do_print = FALSE;
1423           cairo_surface_destroy (op->priv->surface);
1424           op->priv->surface = NULL;
1425           goto out; 
1426         } 
1427       
1428       op_win32 = g_new (GtkPrintOperationWin32, 1);
1429       op->priv->platform_data = op_win32;
1430       op->priv->free_platform_data = (GDestroyNotify) op_win32_free;
1431       op_win32->hdc = printdlgex->hDC;
1432       op_win32->devmode = printdlgex->hDevMode;
1433       op_win32->devnames = printdlgex->hDevNames;
1434       op_win32->job_id = job_id;
1435       
1436       op->priv->print_pages = gtk_print_settings_get_print_pages (op->priv->print_settings);
1437       op->priv->num_page_ranges = 0;
1438       if (op->priv->print_pages == GTK_PRINT_PAGES_RANGES)
1439         op->priv->page_ranges = gtk_print_settings_get_page_ranges (op->priv->print_settings,
1440                                                                     &op->priv->num_page_ranges);
1441       op->priv->manual_num_copies = printdlgex->nCopies;
1442       op->priv->manual_collation = (printdlgex->Flags & PD_COLLATE) != 0;
1443       op->priv->manual_reverse = FALSE;
1444       op->priv->manual_orientation = FALSE;
1445       op->priv->manual_scale = 1.0;
1446       op->priv->manual_page_set = GTK_PAGE_SET_ALL;
1447     }
1448
1449   op->priv->start_page = win32_start_page;
1450   op->priv->end_page = win32_end_page;
1451   op->priv->end_run = win32_end_run;
1452   
1453   out:
1454   if (!*do_print && printdlgex && printdlgex->hDevMode != NULL) 
1455     GlobalFree(printdlgex->hDevMode); 
1456
1457   if (!*do_print && printdlgex && printdlgex->hDevNames != NULL) 
1458     GlobalFree(printdlgex->hDevNames); 
1459
1460   if (page_ranges)
1461     GlobalFree (page_ranges);
1462
1463   if (printdlgex)
1464     GlobalFree (printdlgex);
1465
1466   if (invisible)
1467     gtk_widget_destroy (invisible);
1468
1469   return result;
1470 }
1471
1472 void 
1473 _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
1474                                                         GtkWindow                  *parent,
1475                                                         GtkPrintOperationPrintFunc  print_cb)
1476 {
1477   gboolean do_print;
1478
1479   _gtk_print_operation_platform_backend_run_dialog (op, parent, &do_print, NULL);
1480   if (do_print)
1481     print_cb (op);
1482   else
1483     _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
1484 }
1485
1486 GtkPageSetup *
1487 gtk_print_run_page_setup_dialog (GtkWindow        *parent,
1488                                  GtkPageSetup     *page_setup,
1489                                  GtkPrintSettings *settings)
1490 {
1491   LPPAGESETUPDLGW pagesetupdlg = NULL;
1492   BOOL res;
1493   gboolean free_settings;
1494   const char *printer;
1495   GtkPaperSize *paper_size;
1496   DWORD measure_system;
1497   GtkUnit unit;
1498   double scale;
1499
1500   pagesetupdlg = (LPPAGESETUPDLGW)GlobalAlloc (GPTR, sizeof (PAGESETUPDLGW));
1501   if (!pagesetupdlg)
1502     return NULL;
1503
1504   free_settings = FALSE;
1505   if (settings == NULL)
1506     {
1507       settings = gtk_print_settings_new ();
1508       free_settings = TRUE;
1509     }
1510   
1511   memset (pagesetupdlg, 0, sizeof (PAGESETUPDLGW));
1512
1513   pagesetupdlg->lStructSize = sizeof(PAGESETUPDLGW);
1514
1515   if (parent != NULL)
1516     pagesetupdlg->hwndOwner = get_parent_hwnd (GTK_WIDGET (parent));
1517   else
1518     pagesetupdlg->hwndOwner = NULL;
1519
1520   pagesetupdlg->Flags = PSD_DEFAULTMINMARGINS;
1521   pagesetupdlg->hDevMode = devmode_from_settings (settings, page_setup);
1522   pagesetupdlg->hDevNames = NULL;
1523   printer = gtk_print_settings_get_printer (settings);
1524   if (printer)
1525     pagesetupdlg->hDevNames = gtk_print_win32_devnames_from_printer_name (printer);
1526
1527   GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE|LOCALE_RETURN_NUMBER,
1528                  (LPWSTR)&measure_system, sizeof (DWORD));
1529
1530   if (measure_system == 0)
1531     {
1532       pagesetupdlg->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS;
1533       unit = GTK_UNIT_MM;
1534       scale = 100;
1535     }
1536   else
1537     {
1538       pagesetupdlg->Flags |= PSD_INTHOUSANDTHSOFINCHES;
1539       unit = GTK_UNIT_INCH;
1540       scale = 1000;
1541     }
1542
1543   /* This is the object we return, we allocate it here so that
1544    * we can use the default page margins */
1545   if (page_setup)
1546     page_setup = gtk_page_setup_copy (page_setup);
1547   else
1548     page_setup = gtk_page_setup_new ();
1549   
1550   pagesetupdlg->Flags |= PSD_MARGINS;
1551   pagesetupdlg->rtMargin.left =
1552     floor (gtk_page_setup_get_left_margin (page_setup, unit) * scale + 0.5);
1553   pagesetupdlg->rtMargin.right =
1554     floor (gtk_page_setup_get_right_margin (page_setup, unit) * scale + 0.5);
1555   pagesetupdlg->rtMargin.top = 
1556     floor (gtk_page_setup_get_top_margin (page_setup, unit) * scale + 0.5);
1557   pagesetupdlg->rtMargin.bottom =
1558     floor (gtk_page_setup_get_bottom_margin (page_setup, unit) * scale + 0.5);
1559
1560   pagesetupdlg->Flags |= PSD_ENABLEPAGESETUPHOOK;
1561   pagesetupdlg->lpfnPageSetupHook = run_mainloop_hook;
1562   got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
1563   
1564   res = PageSetupDlgW (pagesetupdlg);
1565   gdk_win32_set_modal_dialog_libgtk_only (NULL);
1566
1567   if (res)
1568     {  
1569       if (pagesetupdlg->hDevNames != NULL)
1570         devnames_to_settings (settings, pagesetupdlg->hDevNames);
1571
1572       if (pagesetupdlg->hDevMode != NULL)
1573         devmode_to_settings (settings, pagesetupdlg->hDevMode);
1574     }
1575   
1576   if (free_settings)
1577     g_object_unref (settings);
1578
1579   if (res)
1580     {
1581       gtk_page_setup_set_orientation (page_setup, 
1582                                       gtk_print_settings_get_orientation (settings));
1583       paper_size = gtk_print_settings_get_paper_size (settings);
1584       if (paper_size)
1585         {
1586           gtk_page_setup_set_paper_size (page_setup, paper_size);
1587           gtk_paper_size_free (paper_size);
1588         }
1589
1590       if (pagesetupdlg->Flags & PSD_INHUNDREDTHSOFMILLIMETERS)
1591         {
1592           unit = GTK_UNIT_MM;
1593           scale = 100;
1594         }
1595       else
1596         {
1597           unit = GTK_UNIT_INCH;
1598           scale = 1000;
1599         }
1600
1601       gtk_page_setup_set_left_margin (page_setup,
1602                                       pagesetupdlg->rtMargin.left / scale,
1603                                       unit);
1604       gtk_page_setup_set_right_margin (page_setup,
1605                                        pagesetupdlg->rtMargin.right / scale,
1606                                        unit);
1607       gtk_page_setup_set_top_margin (page_setup,
1608                                      pagesetupdlg->rtMargin.top / scale,
1609                                      unit);
1610       gtk_page_setup_set_bottom_margin (page_setup,
1611                                         pagesetupdlg->rtMargin.bottom / scale,
1612                                         unit);
1613     }
1614   
1615   return page_setup;
1616 }
1617
1618 void
1619 gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
1620                                        GtkPageSetup         *page_setup,
1621                                        GtkPrintSettings     *settings,
1622                                        GtkPageSetupDoneFunc  done_cb,
1623                                        gpointer              data)
1624 {
1625   GtkPageSetup *page_setup;
1626
1627   page_setup = gtk_print_run_page_setup_dialog (parent, page_setup, settings);
1628   done_cb (page_setup, data);
1629   g_object_unref (page_setup);
1630 }