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