]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintoperation-win32.c
Refactor the gtk_print_operation_run() code and add an _async version.
[~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   devnames = GlobalLock (op_win32->devnames);
475   if (!OpenPrinterW (((gunichar2 *)devnames) + devnames->wDeviceOffset,
476                      &printerHandle, NULL))
477     printerHandle = 0;
478   GlobalUnlock (op_win32->devnames);
479   
480   GlobalFree(op_win32->devmode);
481   GlobalFree(op_win32->devnames);
482
483   cairo_surface_destroy (op->priv->surface);
484   op->priv->surface = NULL;
485
486   DeleteDC(op_win32->hdc);
487   
488   if (printerHandle != 0)
489     {
490       op_win32->printerHandle = printerHandle;
491       win32_poll_status (op);
492       op_win32->timeout_id = g_timeout_add (STATUS_POLLING_TIME,
493                                             (GSourceFunc)win32_poll_status_timeout,
494                                             op);
495     }
496   else
497     /* Dunno what happened, pretend its finished */
498     _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED, NULL);
499 }
500
501 static void
502 win32_poll_status (GtkPrintOperation *op)
503 {
504   GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
505   guchar *data;
506   DWORD needed;
507   JOB_INFO_1W *job_info;
508   GtkPrintStatus status;
509   char *status_str;
510   BOOL ret;
511
512   GetJobW (op_win32->printerHandle, op_win32->job_id,
513            1,(LPBYTE)NULL, 0, &needed);
514   data = g_malloc (needed);
515   ret = GetJobW (op_win32->printerHandle, op_win32->job_id,
516                  1, (LPBYTE)data, needed, &needed);
517
518   status_str = NULL;
519   if (ret)
520     {
521       job_info = (JOB_INFO_1W *)data;
522       DWORD win32_status = job_info->Status;
523
524       if (job_info->pStatus)
525         status_str = g_utf16_to_utf8 (job_info->pStatus, 
526                                       -1, NULL, NULL, NULL);
527      
528       if (win32_status &
529           (JOB_STATUS_COMPLETE | JOB_STATUS_PRINTED))
530         status = GTK_PRINT_STATUS_FINISHED;
531       else if (win32_status &
532                (JOB_STATUS_OFFLINE |
533                 JOB_STATUS_PAPEROUT |
534                 JOB_STATUS_PAUSED |
535                 JOB_STATUS_USER_INTERVENTION))
536         {
537           status = GTK_PRINT_STATUS_PENDING_ISSUE;
538           if (status_str == NULL)
539             {
540               if (win32_status & JOB_STATUS_OFFLINE)
541                 status_str = g_strdup (_("Printer offline"));
542               else if (win32_status & JOB_STATUS_PAPEROUT)
543                 status_str = g_strdup (_("Out of paper"));
544               else if (win32_status & JOB_STATUS_PAUSED)
545                 status_str = g_strdup (_("Paused"));
546               else if (win32_status & JOB_STATUS_USER_INTERVENTION)
547                 status_str = g_strdup (_("Need user intervention"));
548             }
549         }
550       else if (win32_status &
551                (JOB_STATUS_BLOCKED_DEVQ |
552                 JOB_STATUS_DELETED |
553                 JOB_STATUS_ERROR))
554         status = GTK_PRINT_STATUS_FINISHED_ABORTED;
555       else if (win32_status &
556                (JOB_STATUS_SPOOLING |
557                 JOB_STATUS_DELETING))
558         status = GTK_PRINT_STATUS_PENDING;
559       else if (win32_status & JOB_STATUS_PRINTING)
560         status = GTK_PRINT_STATUS_PRINTING;
561       else
562         status = GTK_PRINT_STATUS_FINISHED;
563     }
564   else
565     status = GTK_PRINT_STATUS_FINISHED;
566
567   g_free (data);
568
569   _gtk_print_operation_set_status (op, status, status_str);
570  
571   g_free (status_str);
572 }
573
574 static void
575 op_win32_free (GtkPrintOperationWin32 *op_win32)
576 {
577   if (op_win32->printerHandle)
578     ClosePrinter (op_win32->printerHandle);
579   if (op_win32->timeout_id != 0)
580     g_source_remove (op_win32->timeout_id);
581   g_free (op_win32);
582 }
583
584 static HWND
585 get_parent_hwnd (GtkWidget *widget)
586 {
587   gtk_widget_realize (widget);
588   return gdk_win32_drawable_get_handle (widget->window);
589 }
590
591
592 static void
593 devnames_to_settings (GtkPrintSettings *settings,
594                       HANDLE hDevNames)
595 {
596   GtkPrintWin32Devnames *devnames = gtk_print_win32_devnames_from_win32 (hDevNames);
597   gtk_print_settings_set_printer (settings, devnames->device);
598   gtk_print_win32_devnames_free (devnames);
599 }
600
601 static void
602 devmode_to_settings (GtkPrintSettings *settings,
603                      HANDLE hDevMode)
604 {
605   LPDEVMODEW devmode;
606
607   devmode = GlobalLock (hDevMode);
608   
609   gtk_print_settings_set_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION,
610                               devmode->dmDriverVersion);
611   if (devmode->dmDriverExtra != 0)
612     {
613       char *extra = g_base64_encode (((char *)devmode) + sizeof (DEVMODEW),
614                                      devmode->dmDriverExtra);
615       gtk_print_settings_set (settings,
616                               GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA,
617                               extra);
618       g_free (extra);
619     }
620   
621   if (devmode->dmFields & DM_ORIENTATION)
622     gtk_print_settings_set_orientation (settings,
623                                         orientation_from_win32 (devmode->dmOrientation));
624   
625   
626   if (devmode->dmFields & DM_PAPERSIZE &&
627       devmode->dmPaperSize != 0)
628     {
629       GtkPaperSize *paper_size = paper_size_from_win32 (devmode->dmPaperSize);
630       if (paper_size)
631         {
632           gtk_print_settings_set_paper_size (settings, paper_size);
633           gtk_paper_size_free (paper_size);
634         }
635       gtk_print_settings_set_int (settings, "win32-paper-size", (int)devmode->dmPaperSize);
636     }
637   else if ((devmode->dmFields & DM_PAPERSIZE &&
638             devmode->dmPaperSize == 0) ||
639            ((devmode->dmFields & DM_PAPERWIDTH) &&
640             (devmode->dmFields & DM_PAPERLENGTH)))
641     {
642       GtkPaperSize *paper_size;
643       char *form_name = NULL;
644       if (devmode->dmFields & DM_FORMNAME)
645         form_name = g_utf16_to_utf8 (devmode->dmFormName, 
646                                      -1, NULL, NULL, NULL);
647       if (form_name == NULL || form_name[0] == 0)
648         form_name = g_strdup (_("Custom size"));
649       paper_size = gtk_paper_size_new_custom (form_name,
650                                               form_name,
651                                               devmode->dmPaperWidth * 10.0,
652                                               devmode->dmPaperLength * 10.0,
653                                               GTK_UNIT_MM);
654       gtk_print_settings_set_paper_size (settings, paper_size);
655       gtk_paper_size_free (paper_size);
656     }
657   
658   if (devmode->dmFields & DM_SCALE)
659     gtk_print_settings_set_scale (settings,
660                                   devmode->dmScale / 100.0);
661   
662   if (devmode->dmFields & DM_COPIES)
663     gtk_print_settings_set_num_copies (settings,
664                                        devmode->dmCopies);
665   
666   if (devmode->dmFields & DM_DEFAULTSOURCE)
667     {
668       char *source;
669       switch (devmode->dmDefaultSource)
670         {
671         default:
672         case DMBIN_AUTO:
673           source = "auto";
674           break;
675         case DMBIN_CASSETTE:
676           source = "cassette";
677           break;
678         case DMBIN_ENVELOPE:
679           source = "envelope";
680           break;
681         case DMBIN_ENVMANUAL:
682           source = "envelope-manual";
683           break;
684         case DMBIN_LOWER:
685           source = "lower";
686           break;
687         case DMBIN_MANUAL:
688           source = "manual";
689           break;
690         case DMBIN_MIDDLE:
691           source = "middle";
692           break;
693         case DMBIN_ONLYONE:
694           source = "only-one";
695           break;
696         case DMBIN_FORMSOURCE:
697           source = "form-source";
698           break;
699         case DMBIN_LARGECAPACITY:
700           source = "large-capacity";
701           break;
702         case DMBIN_LARGEFMT:
703           source = "large-format";
704           break;
705         case DMBIN_TRACTOR:
706           source = "tractor";
707           break;
708         case DMBIN_SMALLFMT:
709           source = "small-format";
710           break;
711         }
712       gtk_print_settings_set_default_source (settings, source);
713       gtk_print_settings_set_int (settings, "win32-default-source", devmode->dmDefaultSource);
714     }
715   
716   if (devmode->dmFields & DM_PRINTQUALITY)
717     {
718       GtkPrintQuality quality;
719       switch (devmode->dmPrintQuality)
720         {
721         case DMRES_LOW:
722           quality = GTK_PRINT_QUALITY_LOW;
723           break;
724         case DMRES_MEDIUM:
725           quality = GTK_PRINT_QUALITY_NORMAL;
726           break;
727         default:
728         case DMRES_HIGH:
729           quality = GTK_PRINT_QUALITY_HIGH;
730           break;
731         case DMRES_DRAFT:
732           quality = GTK_PRINT_QUALITY_DRAFT;
733           break;
734         }
735       gtk_print_settings_set_quality (settings, quality);
736       gtk_print_settings_set_int (settings, "win32-print-quality", devmode->dmPrintQuality);
737     }
738   
739   if (devmode->dmFields & DM_COLOR)
740     gtk_print_settings_set_use_color (settings, devmode->dmFields == DMCOLOR_COLOR);
741   
742   if (devmode->dmFields & DM_DUPLEX)
743     {
744       GtkPrintDuplex duplex;
745       switch (devmode->dmDuplex)
746         {
747         default:
748         case DMDUP_SIMPLEX:
749           duplex = GTK_PRINT_DUPLEX_SIMPLEX;
750           break;
751         case DMDUP_HORIZONTAL:
752           duplex = GTK_PRINT_DUPLEX_HORIZONTAL;
753           break;
754         case DMDUP_VERTICAL:
755           duplex = GTK_PRINT_DUPLEX_VERTICAL;
756           break;
757         }
758       
759       gtk_print_settings_set_duplex (settings, duplex);
760     }
761   
762   if (devmode->dmFields & DM_COLLATE)
763     gtk_print_settings_set_collate (settings,
764                                     devmode->dmCollate == DMCOLLATE_TRUE);
765   
766   if (devmode->dmFields & DM_MEDIATYPE)
767     {
768       char *media_type;
769       switch (devmode->dmMediaType)
770         {
771         default:
772         case DMMEDIA_STANDARD:
773           media_type = "stationery";
774           break;
775         case DMMEDIA_TRANSPARENCY:
776           media_type = "transparency";
777           break;
778         case DMMEDIA_GLOSSY:
779           media_type = "photographic-glossy";
780           break;
781         }
782       gtk_print_settings_set_media_type (settings, media_type);
783       gtk_print_settings_set_int (settings, "win32-media-type", devmode->dmMediaType);
784     }
785   
786   if (devmode->dmFields & DM_DITHERTYPE)
787     {
788       char *dither;
789       switch (devmode->dmDitherType)
790         {
791         default:
792         case DMDITHER_FINE:
793           dither = "fine";
794           break;
795         case DMDITHER_NONE:
796           dither = "none";
797           break;
798         case DMDITHER_COARSE:
799           dither = "coarse";
800           break;
801         case DMDITHER_LINEART:
802           dither = "lineart";
803           break;
804         case DMDITHER_GRAYSCALE:
805           dither = "grayscale";
806           break;
807         case DMDITHER_ERRORDIFFUSION:
808           dither = "error-diffusion";
809           break;
810         }
811       gtk_print_settings_set_dither (settings, dither);
812       gtk_print_settings_set_int (settings, "win32-dither-type", devmode->dmDitherType);
813     }
814   
815   GlobalUnlock (hDevMode);
816 }
817
818 static void
819 dialog_to_print_settings (GtkPrintOperation *op,
820                           LPPRINTDLGEXW printdlgex)
821 {
822   int i;
823   GtkPrintSettings *settings;
824
825   settings = gtk_print_settings_new ();
826
827   gtk_print_settings_set_print_pages (settings,
828                                       GTK_PRINT_PAGES_ALL);
829   if (printdlgex->Flags & PD_CURRENTPAGE)
830     gtk_print_settings_set_print_pages (settings,
831                                         GTK_PRINT_PAGES_CURRENT);
832   else if (printdlgex->Flags & PD_PAGENUMS)
833     gtk_print_settings_set_print_pages (settings,
834                                         GTK_PRINT_PAGES_RANGES);
835
836   if (printdlgex->nPageRanges > 0)
837     {
838       GtkPageRange *ranges;
839       ranges = g_new (GtkPageRange, printdlgex->nPageRanges);
840
841       for (i = 0; i < printdlgex->nPageRanges; i++)
842         {
843           ranges[i].start = printdlgex->lpPageRanges[i].nFromPage - 1;
844           ranges[i].end = printdlgex->lpPageRanges[i].nToPage - 1;
845         }
846
847       gtk_print_settings_set_page_ranges (settings, ranges,
848                                           printdlgex->nPageRanges);
849       g_free (ranges);
850     }
851   
852   if (printdlgex->hDevNames != NULL)
853     devnames_to_settings (settings, printdlgex->hDevNames);
854
855   if (printdlgex->hDevMode != NULL)
856     devmode_to_settings (settings, printdlgex->hDevMode);
857   
858   gtk_print_operation_set_print_settings (op, settings);
859 }
860
861 static HANDLE
862 devmode_from_settings (GtkPrintSettings *settings,
863                        GtkPageSetup *page_setup)
864 {
865   HANDLE hDevMode;
866   LPDEVMODEW devmode;
867   char *extras;
868   GtkPaperSize *paper_size;
869   const char *extras_base64;
870   int extras_len;
871   const char *val;
872
873   extras = NULL;
874   extras_len = 0;
875   extras_base64 = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA);
876   if (extras_base64)
877     extras = g_base64_decode (extras_base64, &extras_len);
878   
879   hDevMode = GlobalAlloc (GMEM_MOVEABLE, 
880                           sizeof (DEVMODEW) + extras_len);
881
882   devmode = GlobalLock (hDevMode);
883
884   memset (devmode, 0, sizeof (DEVMODEW));
885   
886   devmode->dmSpecVersion = DM_SPECVERSION;
887   devmode->dmSize = sizeof (DEVMODEW);
888   
889   devmode->dmDriverExtra = 0;
890   if (extras && extras_len > 0)
891     {
892       devmode->dmDriverExtra = extras_len;
893       memcpy (((char *)devmode) + sizeof (DEVMODEW), extras, extras_len);
894       g_free (extras);
895     }
896   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION))
897     devmode->dmDriverVersion = gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION);
898   
899   if (page_setup ||
900       gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION))
901     {
902       GtkPageOrientation orientation = gtk_print_settings_get_orientation (settings);
903       if (page_setup)
904         orientation = gtk_page_setup_get_orientation (page_setup);
905       devmode->dmFields |= DM_ORIENTATION;
906       devmode->dmOrientation = orientation_to_win32 (orientation);
907     }
908
909   if (page_setup)
910     paper_size = gtk_paper_size_copy (gtk_page_setup_get_paper_size (page_setup));
911   else
912     {
913       int size;
914       if (gtk_print_settings_has_key (settings, "win32-paper-size") &&
915           (size = gtk_print_settings_get_int (settings, "win32-paper-size")) != 0)
916         {
917           devmode->dmFields |= DM_PAPERSIZE;
918           devmode->dmPaperSize = size;
919           paper_size = NULL;
920         }
921       else
922         paper_size = gtk_print_settings_get_paper_size (settings);
923     }
924   if (paper_size)
925     {
926       devmode->dmFields |= DM_PAPERSIZE;
927       devmode->dmPaperSize = paper_size_to_win32 (paper_size);
928       if (devmode->dmPaperSize == 0)
929         {
930           devmode->dmPaperSize = DMPAPER_USER;
931           devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
932           devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) / 10.0;
933           devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) / 10.0;
934         }
935       gtk_paper_size_free (paper_size);
936     }
937
938   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_SCALE))
939     {
940       devmode->dmFields |= DM_SCALE;
941       devmode->dmScale = gtk_print_settings_get_scale (settings) * 100;
942     }
943   
944   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_NUM_COPIES))
945     {
946       devmode->dmFields |= DM_COPIES;
947       devmode->dmCopies = gtk_print_settings_get_num_copies (settings);
948     }
949
950   if (gtk_print_settings_has_key (settings, "win32-default-source"))
951     {
952       devmode->dmFields |= DM_DEFAULTSOURCE;
953       devmode->dmDefaultSource = gtk_print_settings_get_int (settings, "win32-default-source");
954     }
955   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE))
956     {
957       devmode->dmFields |= DM_DEFAULTSOURCE;
958       devmode->dmDefaultSource = DMBIN_AUTO;
959
960       val = gtk_print_settings_get_default_source (settings);
961       if (strcmp (val, "auto") == 0)
962         devmode->dmDefaultSource = DMBIN_AUTO;
963       if (strcmp (val, "cassette") == 0)
964         devmode->dmDefaultSource = DMBIN_CASSETTE;
965       if (strcmp (val, "envelope") == 0)
966         devmode->dmDefaultSource = DMBIN_ENVELOPE;
967       if (strcmp (val, "envelope-manual") == 0)
968         devmode->dmDefaultSource = DMBIN_ENVMANUAL;
969       if (strcmp (val, "lower") == 0)
970         devmode->dmDefaultSource = DMBIN_LOWER;
971       if (strcmp (val, "manual") == 0)
972         devmode->dmDefaultSource = DMBIN_MANUAL;
973       if (strcmp (val, "middle") == 0)
974         devmode->dmDefaultSource = DMBIN_MIDDLE;
975       if (strcmp (val, "only-one") == 0)
976         devmode->dmDefaultSource = DMBIN_ONLYONE;
977       if (strcmp (val, "form-source") == 0)
978         devmode->dmDefaultSource = DMBIN_FORMSOURCE;
979       if (strcmp (val, "large-capacity") == 0)
980         devmode->dmDefaultSource = DMBIN_LARGECAPACITY;
981       if (strcmp (val, "large-format") == 0)
982         devmode->dmDefaultSource = DMBIN_LARGEFMT;
983       if (strcmp (val, "tractor") == 0)
984         devmode->dmDefaultSource = DMBIN_TRACTOR;
985       if (strcmp (val, "small-format") == 0)
986         devmode->dmDefaultSource = DMBIN_SMALLFMT;
987     }
988
989   if (gtk_print_settings_has_key (settings, "win32-print-quality"))
990     {
991       devmode->dmFields |= DM_PRINTQUALITY;
992       devmode->dmPrintQuality = gtk_print_settings_get_int (settings, "win32-print-quality");
993     }
994   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_RESOLUTION))
995     {
996       devmode->dmFields |= DM_PRINTQUALITY;
997       devmode->dmPrintQuality = gtk_print_settings_get_resolution (settings);
998     } 
999   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_QUALITY))
1000     {
1001       devmode->dmFields |= DM_PRINTQUALITY;
1002       switch (gtk_print_settings_get_quality (settings))
1003         {
1004         case GTK_PRINT_QUALITY_LOW:
1005           devmode->dmPrintQuality = DMRES_LOW;
1006           break;
1007         case GTK_PRINT_QUALITY_DRAFT:
1008           devmode->dmPrintQuality = DMRES_DRAFT;
1009           break;
1010         default:
1011         case GTK_PRINT_QUALITY_NORMAL:
1012           devmode->dmPrintQuality = DMRES_MEDIUM;
1013           break;
1014         case GTK_PRINT_QUALITY_HIGH:
1015           devmode->dmPrintQuality = DMRES_HIGH;
1016           break;
1017         }
1018     }
1019
1020   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_USE_COLOR))
1021     {
1022       devmode->dmFields |= DM_COLOR;
1023       if (gtk_print_settings_get_use_color (settings))
1024         devmode->dmColor = DMCOLOR_COLOR;
1025       else
1026         devmode->dmColor = DMCOLOR_MONOCHROME;
1027     }
1028
1029   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DUPLEX))
1030     {
1031       devmode->dmFields |= DM_DUPLEX;
1032       switch (gtk_print_settings_get_duplex (settings))
1033         {
1034         default:
1035         case GTK_PRINT_DUPLEX_SIMPLEX:
1036           devmode->dmDuplex = DMDUP_SIMPLEX;
1037           break;
1038         case GTK_PRINT_DUPLEX_HORIZONTAL:
1039           devmode->dmDuplex = DMDUP_HORIZONTAL;
1040           break;
1041         case GTK_PRINT_DUPLEX_VERTICAL:
1042           devmode->dmDuplex = DMDUP_VERTICAL;
1043           break;
1044         }
1045     }
1046
1047   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_COLLATE))
1048     {
1049       devmode->dmFields |= DM_COLLATE;
1050       if (gtk_print_settings_get_collate (settings))
1051         devmode->dmCollate = DMCOLLATE_TRUE;
1052       else
1053         devmode->dmCollate = DMCOLLATE_FALSE;
1054     }
1055
1056   if (gtk_print_settings_has_key (settings, "win32-media-type"))
1057     {
1058       devmode->dmFields |= DM_MEDIATYPE;
1059       devmode->dmMediaType = gtk_print_settings_get_int (settings, "win32-media-type");
1060     }
1061   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_MEDIA_TYPE))
1062     {
1063       devmode->dmFields |= DM_MEDIATYPE;
1064       devmode->dmMediaType = DMMEDIA_STANDARD;
1065       
1066       val = gtk_print_settings_get_media_type (settings);
1067       if (strcmp (val, "transparency") == 0)
1068         devmode->dmMediaType = DMMEDIA_TRANSPARENCY;
1069       if (strcmp (val, "photographic-glossy") == 0)
1070         devmode->dmMediaType = DMMEDIA_GLOSSY;
1071     }
1072  
1073   if (gtk_print_settings_has_key (settings, "win32-dither-type"))
1074     {
1075       devmode->dmFields |= DM_DITHERTYPE;
1076       devmode->dmDitherType = gtk_print_settings_get_int (settings, "win32-dither-type");
1077     }
1078   else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DITHER))
1079     {
1080       devmode->dmFields |= DM_DITHERTYPE;
1081       devmode->dmDitherType = DMDITHER_FINE;
1082       
1083       val = gtk_print_settings_get_dither (settings);
1084       if (strcmp (val, "none") == 0)
1085         devmode->dmDitherType = DMDITHER_NONE;
1086       if (strcmp (val, "coarse") == 0)
1087         devmode->dmDitherType = DMDITHER_COARSE;
1088       if (strcmp (val, "fine") == 0)
1089         devmode->dmDitherType = DMDITHER_FINE;
1090       if (strcmp (val, "lineart") == 0)
1091         devmode->dmDitherType = DMDITHER_LINEART;
1092       if (strcmp (val, "grayscale") == 0)
1093         devmode->dmDitherType = DMDITHER_GRAYSCALE;
1094       if (strcmp (val, "error-diffusion") == 0)
1095         devmode->dmDitherType = DMDITHER_ERRORDIFFUSION;
1096     }
1097   
1098   GlobalUnlock (hDevMode);
1099
1100   return hDevMode;
1101 }
1102
1103 static void
1104 dialog_from_print_settings (GtkPrintOperation *op,
1105                             LPPRINTDLGEXW printdlgex)
1106 {
1107   GtkPrintSettings *settings = op->priv->print_settings;
1108   const char *printer;
1109
1110   if (settings == NULL)
1111     return;
1112
1113   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PRINT_PAGES))
1114     {
1115       GtkPrintPages print_pages = gtk_print_settings_get_print_pages (settings);
1116
1117       switch (print_pages)
1118         {
1119         default:
1120         case GTK_PRINT_PAGES_ALL:
1121           printdlgex->Flags |= PD_ALLPAGES;
1122           break;
1123         case GTK_PRINT_PAGES_CURRENT:
1124           printdlgex->Flags |= PD_CURRENTPAGE;
1125           break;
1126         case GTK_PRINT_PAGES_RANGES:
1127           printdlgex->Flags |= PD_PAGENUMS;
1128           break;
1129         }
1130     }
1131   if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PAGE_RANGES))
1132     {
1133       GtkPageRange *ranges;
1134       int num_ranges, i;
1135
1136       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
1137
1138       if (num_ranges > MAX_PAGE_RANGES)
1139         num_ranges = MAX_PAGE_RANGES;
1140
1141       printdlgex->nPageRanges = num_ranges;
1142       for (i = 0; i < num_ranges; i++)
1143         {
1144           printdlgex->lpPageRanges[i].nFromPage = ranges[i].start + 1;
1145           printdlgex->lpPageRanges[i].nToPage = ranges[i].end + 1;
1146         }
1147     }
1148   
1149   printer = gtk_print_settings_get_printer (settings);
1150   if (printer)
1151     printdlgex->hDevNames = gtk_print_win32_devnames_from_printer_name (printer);
1152   
1153   printdlgex->hDevMode = devmode_from_settings (settings,
1154                                                 op->priv->default_page_setup);
1155 }
1156
1157 typedef struct {
1158   IPrintDialogCallback iPrintDialogCallback;
1159   gboolean set_hwnd;
1160   int ref_count;
1161 } PrintDialogCallback;
1162
1163
1164 static ULONG STDMETHODCALLTYPE
1165 iprintdialogcallback_addref (IPrintDialogCallback *This)
1166 {
1167   PrintDialogCallback *callback = (PrintDialogCallback *)This;
1168   return ++callback->ref_count;
1169 }
1170
1171 static ULONG STDMETHODCALLTYPE
1172 iprintdialogcallback_release (IPrintDialogCallback *This)
1173 {
1174   PrintDialogCallback *callback = (PrintDialogCallback *)This;
1175   int ref_count = --callback->ref_count;
1176
1177   if (ref_count == 0)
1178     g_free (This);
1179
1180   return ref_count;
1181 }
1182
1183 static HRESULT STDMETHODCALLTYPE
1184 iprintdialogcallback_queryinterface (IPrintDialogCallback *This,
1185                                      REFIID       riid,
1186                                      LPVOID      *ppvObject)
1187 {
1188    if (IsEqualIID (riid, &IID_IUnknown) ||
1189        IsEqualIID (riid, &myIID_IPrintDialogCallback))
1190      {
1191        *ppvObject = This;
1192        IUnknown_AddRef ((IUnknown *)This);
1193        return NOERROR;
1194      }
1195    else
1196      {
1197        *ppvObject = NULL;
1198        return E_NOINTERFACE;
1199      }
1200 }
1201
1202 static HRESULT STDMETHODCALLTYPE
1203 iprintdialogcallback_initdone (IPrintDialogCallback *This)
1204 {
1205   return S_FALSE;
1206 }
1207
1208 static HRESULT STDMETHODCALLTYPE
1209 iprintdialogcallback_selectionchange (IPrintDialogCallback *This)
1210 {
1211   return S_FALSE;
1212 }
1213
1214 static HRESULT STDMETHODCALLTYPE
1215 iprintdialogcallback_handlemessage (IPrintDialogCallback *This,
1216                                     HWND hDlg,
1217                                     UINT uMsg,
1218                                     WPARAM wParam,
1219                                     LPARAM lParam,
1220                                     LRESULT *pResult)
1221 {
1222   PrintDialogCallback *callback = (PrintDialogCallback *)This;
1223
1224   if (!callback->set_hwnd)
1225     {
1226       gdk_win32_set_modal_dialog_libgtk_only (hDlg);
1227       callback->set_hwnd = TRUE;
1228       while (gtk_events_pending ())
1229         gtk_main_iteration ();
1230     }
1231   else if (uMsg == got_gdk_events_message)
1232     {
1233       while (gtk_events_pending ())
1234         gtk_main_iteration ();
1235       *pResult = TRUE;
1236       return S_OK;
1237     }
1238   
1239   *pResult = 0;
1240   return S_FALSE;
1241 }
1242
1243 static IPrintDialogCallbackVtbl ipdc_vtbl = {
1244   iprintdialogcallback_queryinterface,
1245   iprintdialogcallback_addref,
1246   iprintdialogcallback_release,
1247   iprintdialogcallback_initdone,
1248   iprintdialogcallback_selectionchange,
1249   iprintdialogcallback_handlemessage
1250 };
1251
1252 static IPrintDialogCallback *
1253 print_callback_new  (void)
1254 {
1255   PrintDialogCallback *callback;
1256
1257   callback = g_new0 (PrintDialogCallback, 1);
1258   callback->iPrintDialogCallback.lpVtbl = &ipdc_vtbl;
1259   callback->ref_count = 1;
1260   callback->set_hwnd = FALSE;
1261
1262   return &callback->iPrintDialogCallback;
1263 }
1264
1265 GtkPrintOperationResult
1266 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
1267                                                   GtkWindow *parent,
1268                                                   gboolean *do_print,
1269                                                   GError **error)
1270 {
1271   HRESULT hResult;
1272   LPPRINTDLGEXW printdlgex = NULL;
1273   LPPRINTPAGERANGE page_ranges = NULL;
1274   HWND parentHWnd;
1275   GtkWidget *invisible = NULL;
1276   GtkPrintOperationResult result;
1277   GtkPrintOperationWin32 *op_win32;
1278   IPrintDialogCallback *callback;
1279   
1280   *do_print = FALSE;
1281
1282   if (parent == NULL)
1283     {
1284       invisible = gtk_invisible_new ();
1285       parentHWnd = get_parent_hwnd (invisible);
1286     }
1287   else 
1288     parentHWnd = get_parent_hwnd (GTK_WIDGET (parent));
1289
1290   printdlgex = (LPPRINTDLGEXW)GlobalAlloc (GPTR, sizeof (PRINTDLGEXW));
1291   if (!printdlgex)
1292     {
1293       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1294       g_set_error (error,
1295                    GTK_PRINT_ERROR,
1296                    GTK_PRINT_ERROR_NOMEM,
1297                    _("Not enough free memory"));
1298       goto out;
1299     }      
1300
1301   printdlgex->lStructSize = sizeof(PRINTDLGEXW);
1302   printdlgex->hwndOwner = parentHWnd;
1303   printdlgex->hDevMode = NULL;
1304   printdlgex->hDevNames = NULL;
1305   printdlgex->hDC = NULL;
1306   printdlgex->Flags = PD_RETURNDC | PD_NOSELECTION;
1307   if (op->priv->current_page == -1)
1308     printdlgex->Flags |= PD_NOCURRENTPAGE;
1309   printdlgex->Flags2 = 0;
1310   printdlgex->ExclusionFlags = 0;
1311
1312   page_ranges = (LPPRINTPAGERANGE) GlobalAlloc (GPTR, 
1313                                                 MAX_PAGE_RANGES * sizeof (PRINTPAGERANGE));
1314   if (!page_ranges) 
1315     {
1316       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1317       g_set_error (error,
1318                    GTK_PRINT_ERROR,
1319                    GTK_PRINT_ERROR_NOMEM,
1320                    _("Not enough free memory"));
1321       goto out;
1322     }
1323
1324   printdlgex->nPageRanges = 0;
1325   printdlgex->nMaxPageRanges = MAX_PAGE_RANGES;
1326   printdlgex->lpPageRanges = page_ranges;
1327   printdlgex->nMinPage = 1;
1328   if (op->priv->nr_of_pages != -1)
1329     printdlgex->nMaxPage = op->priv->nr_of_pages;
1330   else
1331     printdlgex->nMaxPage = 10000;
1332   printdlgex->nCopies = 1;
1333   printdlgex->hInstance = 0;
1334   printdlgex->lpPrintTemplateName = NULL;
1335   printdlgex->lpCallback = NULL;
1336   printdlgex->nPropertyPages = 0;
1337   printdlgex->lphPropertyPages = NULL;
1338   printdlgex->nStartPage = START_PAGE_GENERAL;
1339   printdlgex->dwResultAction = 0;
1340
1341   dialog_from_print_settings (op, printdlgex);
1342
1343   callback = print_callback_new ();
1344   printdlgex->lpCallback = (IUnknown *)callback;
1345   got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
1346   
1347   hResult = PrintDlgExW(printdlgex);
1348   IUnknown_Release ((IUnknown *)callback);
1349   gdk_win32_set_modal_dialog_libgtk_only (NULL);
1350
1351   if (hResult != S_OK) 
1352     {
1353       result = GTK_PRINT_OPERATION_RESULT_ERROR;
1354       if (hResult == E_OUTOFMEMORY)
1355         g_set_error (error,
1356                      GTK_PRINT_ERROR,
1357                      GTK_PRINT_ERROR_NOMEM,
1358                      _("Not enough free memory"));
1359       else if (hResult == E_INVALIDARG)
1360         g_set_error (error,
1361                      GTK_PRINT_ERROR,
1362                      GTK_PRINT_ERROR_INTERNAL_ERROR,
1363                      _("Invalid argument to PrintDlgEx"));
1364       else if (hResult == E_POINTER)
1365         g_set_error (error,
1366                      GTK_PRINT_ERROR,
1367                      GTK_PRINT_ERROR_INTERNAL_ERROR,
1368                      _("Invalid pointer to PrintDlgEx"));
1369       else if (hResult == E_HANDLE)
1370         g_set_error (error,
1371                      GTK_PRINT_ERROR,
1372                      GTK_PRINT_ERROR_INTERNAL_ERROR,
1373                      _("Invalid handle to PrintDlgEx"));
1374       else /* E_FAIL */
1375         g_set_error (error,
1376                      GTK_PRINT_ERROR,
1377                      GTK_PRINT_ERROR_GENERAL,
1378                      _("Unspecified error"));
1379       goto out;
1380     }
1381
1382   if (printdlgex->dwResultAction == PD_RESULT_PRINT ||
1383       printdlgex->dwResultAction == PD_RESULT_APPLY)
1384     {
1385       result = GTK_PRINT_OPERATION_RESULT_APPLY;
1386       dialog_to_print_settings (op, printdlgex);
1387     }
1388   else
1389     result = GTK_PRINT_OPERATION_RESULT_CANCEL;
1390   
1391   if (printdlgex->dwResultAction == PD_RESULT_PRINT)
1392     {
1393       DOCINFOW docinfo;
1394       int job_id;
1395
1396       *do_print = TRUE;
1397
1398       op->priv->surface = cairo_win32_surface_create (printdlgex->hDC);
1399       op->priv->dpi_x = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSX);
1400       op->priv->dpi_y = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSY);
1401
1402       memset( &docinfo, 0, sizeof (DOCINFOW));
1403       docinfo.cbSize = sizeof (DOCINFOW); 
1404       docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL); 
1405       docinfo.lpszOutput = (LPCWSTR) NULL; 
1406       docinfo.lpszDatatype = (LPCWSTR) NULL; 
1407       docinfo.fwType = 0; 
1408
1409       job_id = StartDocW(printdlgex->hDC, &docinfo); 
1410       g_free ((void *)docinfo.lpszDocName);
1411       if (job_id <= 0) 
1412         { 
1413           result = GTK_PRINT_OPERATION_RESULT_ERROR;
1414           g_set_error (error,
1415                        GTK_PRINT_ERROR,
1416                        GTK_PRINT_ERROR_GENERAL,
1417                      _("Error from StartDoc"));
1418           *do_print = FALSE;
1419           cairo_surface_destroy (op->priv->surface);
1420           op->priv->surface = NULL;
1421           goto out; 
1422         } 
1423       
1424       op_win32 = g_new (GtkPrintOperationWin32, 1);
1425       op->priv->platform_data = op_win32;
1426       op->priv->free_platform_data = (GDestroyNotify) op_win32_free;
1427       op_win32->hdc = printdlgex->hDC;
1428       op_win32->devmode = printdlgex->hDevMode;
1429       op_win32->devnames = printdlgex->hDevNames;
1430       op_win32->job_id = job_id;
1431       
1432       op->priv->print_pages = gtk_print_settings_get_print_pages (op->priv->print_settings);
1433       op->priv->num_page_ranges = 0;
1434       if (op->priv->print_pages == GTK_PRINT_PAGES_RANGES)
1435         op->priv->page_ranges = gtk_print_settings_get_page_ranges (op->priv->print_settings,
1436                                                                     &op->priv->num_page_ranges);
1437       op->priv->manual_num_copies = printdlgex->nCopies;
1438       op->priv->manual_collation = (printdlgex->Flags & PD_COLLATE) != 0;
1439       op->priv->manual_reverse = FALSE;
1440       op->priv->manual_orientation = FALSE;
1441       op->priv->manual_scale = 1.0;
1442       op->priv->manual_page_set = GTK_PAGE_SET_ALL;
1443     }
1444
1445   op->priv->start_page = win32_start_page;
1446   op->priv->end_page = win32_end_page;
1447   op->priv->end_run = win32_end_run;
1448   
1449   out:
1450   if (!*do_print && printdlgex && printdlgex->hDevMode != NULL) 
1451     GlobalFree(printdlgex->hDevMode); 
1452
1453   if (!*do_print && printdlgex && printdlgex->hDevNames != NULL) 
1454     GlobalFree(printdlgex->hDevNames); 
1455
1456   if (page_ranges)
1457     GlobalFree (page_ranges);
1458
1459   if (printdlgex)
1460     GlobalFree (printdlgex);
1461
1462   if (invisible)
1463     gtk_widget_destroy (invisible);
1464
1465   return result;
1466 }
1467
1468 void 
1469 _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
1470                                                         GtkWindow                  *parent,
1471                                                         GtkPrintOperationPrintFunc  print_cb)
1472 {
1473   gboolean do_print;
1474
1475   _gtk_print_operation_platform_backend_run_dialog (op, parent, &do_print, NULL);
1476   if (do_print)
1477     print_cb (op);
1478   else
1479     _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
1480 }
1481
1482 GtkPageSetup *
1483 gtk_print_run_page_setup_dialog (GtkWindow        *parent,
1484                                  GtkPageSetup     *page_setup,
1485                                  GtkPrintSettings *settings)
1486 {
1487   LPPAGESETUPDLGW pagesetupdlg = NULL;
1488   BOOL res;
1489   gboolean free_settings;
1490   const char *printer;
1491   GtkPaperSize *paper_size;
1492   DWORD measure_system;
1493   GtkUnit unit;
1494   double scale;
1495
1496   pagesetupdlg = (LPPAGESETUPDLGW)GlobalAlloc (GPTR, sizeof (PAGESETUPDLGW));
1497   if (!pagesetupdlg)
1498     return NULL;
1499
1500   free_settings = FALSE;
1501   if (settings == NULL)
1502     {
1503       settings = gtk_print_settings_new ();
1504       free_settings = TRUE;
1505     }
1506   
1507   memset (pagesetupdlg, 0, sizeof (PAGESETUPDLGW));
1508
1509   pagesetupdlg->lStructSize = sizeof(PAGESETUPDLGW);
1510
1511   if (parent != NULL)
1512     pagesetupdlg->hwndOwner = get_parent_hwnd (GTK_WIDGET (parent));
1513   else
1514     pagesetupdlg->hwndOwner = NULL;
1515
1516   pagesetupdlg->Flags = PSD_DEFAULTMINMARGINS;
1517   pagesetupdlg->hDevMode = devmode_from_settings (settings, page_setup);
1518   pagesetupdlg->hDevNames = NULL;
1519   printer = gtk_print_settings_get_printer (settings);
1520   if (printer)
1521     pagesetupdlg->hDevNames = gtk_print_win32_devnames_from_printer_name (printer);
1522
1523   GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE|LOCALE_RETURN_NUMBER,
1524                  (LPWSTR)&measure_system, sizeof (DWORD));
1525
1526   if (measure_system == 0)
1527     {
1528       pagesetupdlg->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS;
1529       unit = GTK_UNIT_MM;
1530       scale = 100;
1531     }
1532   else
1533     {
1534       pagesetupdlg->Flags |= PSD_INTHOUSANDTHSOFINCHES;
1535       unit = GTK_UNIT_INCH;
1536       scale = 1000;
1537     }
1538
1539   /* This is the object we return, we allocate it here so that
1540    * we can use the default page margins */
1541   if (page_setup)
1542     page_setup = gtk_page_setup_copy (page_setup);
1543   else
1544     page_setup = gtk_page_setup_new ();
1545   
1546   pagesetupdlg->Flags |= PSD_MARGINS;
1547   pagesetupdlg->rtMargin.left =
1548     floor (gtk_page_setup_get_left_margin (page_setup, unit) * scale + 0.5);
1549   pagesetupdlg->rtMargin.right =
1550     floor (gtk_page_setup_get_right_margin (page_setup, unit) * scale + 0.5);
1551   pagesetupdlg->rtMargin.top = 
1552     floor (gtk_page_setup_get_top_margin (page_setup, unit) * scale + 0.5);
1553   pagesetupdlg->rtMargin.bottom =
1554     floor (gtk_page_setup_get_bottom_margin (page_setup, unit) * scale + 0.5);
1555
1556   pagesetupdlg->Flags |= PSD_ENABLEPAGESETUPHOOK;
1557   pagesetupdlg->lpfnPageSetupHook = run_mainloop_hook;
1558   got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
1559   
1560   res = PageSetupDlgW (pagesetupdlg);
1561   gdk_win32_set_modal_dialog_libgtk_only (NULL);
1562
1563   if (res)
1564     {  
1565       if (pagesetupdlg->hDevNames != NULL)
1566         devnames_to_settings (settings, pagesetupdlg->hDevNames);
1567
1568       if (pagesetupdlg->hDevMode != NULL)
1569         devmode_to_settings (settings, pagesetupdlg->hDevMode);
1570     }
1571   
1572   if (free_settings)
1573     g_object_unref (settings);
1574
1575   if (res)
1576     {
1577       gtk_page_setup_set_orientation (page_setup, 
1578                                       gtk_print_settings_get_orientation (settings));
1579       paper_size = gtk_print_settings_get_paper_size (settings);
1580       if (paper_size)
1581         {
1582           gtk_page_setup_set_paper_size (page_setup, paper_size);
1583           gtk_paper_size_free (paper_size);
1584         }
1585
1586       if (pagesetupdlg->Flags & PSD_INHUNDREDTHSOFMILLIMETERS)
1587         {
1588           unit = GTK_UNIT_MM;
1589           scale = 100;
1590         }
1591       else
1592         {
1593           unit = GTK_UNIT_INCH;
1594           scale = 1000;
1595         }
1596
1597       gtk_page_setup_set_left_margin (page_setup,
1598                                       pagesetupdlg->rtMargin.left / scale,
1599                                       unit);
1600       gtk_page_setup_set_right_margin (page_setup,
1601                                        pagesetupdlg->rtMargin.right / scale,
1602                                        unit);
1603       gtk_page_setup_set_top_margin (page_setup,
1604                                      pagesetupdlg->rtMargin.top / scale,
1605                                      unit);
1606       gtk_page_setup_set_bottom_margin (page_setup,
1607                                         pagesetupdlg->rtMargin.bottom / scale,
1608                                         unit);
1609     }
1610   
1611   return page_setup;
1612 }
1613
1614 void
1615 gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
1616                                        GtkPageSetup         *page_setup,
1617                                        GtkPrintSettings     *settings,
1618                                        GtkPageSetupDoneFunc  done_cb,
1619                                        gpointer              data)
1620 {
1621   GtkPageSetup *page_setup;
1622
1623   page_setup = gtk_print_run_page_setup_dialog (parent, page_setup, settings);
1624   done_cb (page_setup, data);
1625   g_object_unref (page_setup);
1626 }