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