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