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