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