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