xref: /plan9/sys/src/cmd/gs/src/gdevwpr2.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevwpr2.c,v 1.18 2004/08/05 17:02:36 stefan Exp $ */
18 /*
19  * Microsoft Windows 3.n printer driver for Ghostscript.
20  * Original version by Russell Lang and
21  * L. Peter Deutsch, Aladdin Enterprises.
22  * Modified by rjl 1995-03-29 to use BMP printer code
23  * Modified by Pierre Arnaud 1999-02-18 (see description below)
24  * Modified by lpd 1999-04-03 for compatibility with Borland C++ 4.5.
25  * Modified by Pierre Arnaud 1999-10-03 (accept b&w printing on color printers).
26  * Modified by Pierre Arnaud 1999-11-20 (accept lower resolution)
27  * Bug fixed by Pierre Arnaud 2000-03-09 (win_pr2_put_params error when is_open)
28  * Bug fixed by Pierre Arnaud 2000-03-20 (win_pr2_set_bpp did not set anti_alias)
29  * Bug fixed by Pierre Arnaud 2000-03-22 (win_pr2_set_bpp depth was wrong)
30  * Modified by Pierre Arnaud 2000-12-12 (mainly added support for Tumble)
31  * Bug fixed by Pierre Arnaud 2000-12-18 (-dQueryUser now works from cmd line)
32  */
33 
34 /* This driver uses the printer default size and resolution and
35  * ignores page size and resolution set using -gWIDTHxHEIGHT and
36  * -rXxY.  You must still set the correct PageSize to get the
37  * correct clipping path.
38  * The code in win_pr2_getdc() does try to set the printer page
39  * size from the PostScript PageSize, but it isn't working
40  * reliably at the moment.
41  *
42  * This driver doesn't work with some Windows printer drivers.
43  * The reason is unknown.  All printers to which I have access
44  * work.
45  *
46  * rjl 1997-11-20
47  */
48 
49 /* Additions by Pierre Arnaud (Pierre.Arnaud@opac.ch)
50  *
51  * The driver has been extended in order to provide some run-time
52  * feed-back about the default Windows printer and to give the user
53  * the opportunity to select the printer's properties before the
54  * device gets opened (and any spooling starts).
55  *
56  * The driver returns an additional property named "UserSettings".
57  * This is a dictionary which contens are valid only after setting
58  * the QueryUser property (see below). The UserSettings dict contains
59  * the following keys:
60  *
61  *  DocumentRange  [begin end]		(int array, can be set)
62  *	Defines the range of pages in the document; [1 10] would
63  *	describe a document starting at page 1 and ending at page 10.
64  *
65  *  SelectedRange  [begin end]		(int array, can be set)
66  *	Defines the pages the user wants to print.
67  *
68  *  MediaSize	   [width height]	(float array, read only)
69  *	Current printer's media size.
70  *
71  *  Copies	   n			(integer, can be set)
72  *	User selected number of copies.
73  *
74  *  PrintCopies    n			(integer, read only)
75  *	Number of copies which must be printed by Ghostscript itself.
76  *	This is still experimental.
77  *
78  *  DocumentName   name			(string, can be set)
79  *	Name to be associated with the print job.
80  *
81  *  UserChangedSettings			(bool, read only)
82  *	Set to 'true' if the last QueryUser operation succeeded.
83  *
84  *  Paper	   n			(integer, can be set)
85  *	Windows paper selection (0 = automatic).
86  *
87  *  Orient	   n			(integer, can be set)
88  *	Windows paper orientation (0 = automatic).
89  *
90  *  Color	   n			(integer, can be set)
91  *	Windows color (0 = automatic, 1 = monochrome, 2 = color).
92  *
93  *  MaxResolution  n			(integer, can be set)
94  *	Maximum resolution in pixels pet inch (0 = no maximum). If
95  *	the printer has a higher resolution than the maximum, trim
96  *	the used resolution to the best one (dpi_chosen <= dpi_max,
97  *	with dpi_chosen = dpi_printer / ratio).
98  */
99 
100 /* Supported printer parameters are :
101  *
102  *  -dBitsPerPixel=n
103  *     Override what the Window printer driver returns.
104  *
105  *  -dNoCancel
106  *     Don't display cancel dialog box.  Useful for unattended or
107  *     console EXE operation.
108  *
109  *  -dQueryUser=n
110  *     Query user interactively for the destination printer, before
111  *     the device gets opened. This fills in the UserSettings dict
112  *     and the OutputFile name properties. The following values are
113  *     supported for n:
114  *     1 => show standard Print dialog
115  *     2 => show Print Setup dialog instead
116  *     3 => select default printer
117  *     other, does nothing
118  *
119  * The /Duplex & /Tumble keys of the setpagedevice dict are supported
120  * if the Windows printer supports duplex printing.
121  */
122 
123 #include "gdevprn.h"
124 #include "gdevpccm.h"
125 
126 #include "windows_.h"
127 #include <shellapi.h>
128 #include "gp_mswin.h"
129 
130 #include "gp.h"
131 #include "gpcheck.h"
132 #include "commdlg.h"
133 
134 
135 /* Make sure we cast to the correct structure type. */
136 typedef struct gx_device_win_pr2_s gx_device_win_pr2;
137 
138 #undef wdev
139 #define wdev ((gx_device_win_pr2 *)dev)
140 
141 /* Device procedures */
142 
143 /* See gxdevice.h for the definitions of the procedures. */
144 private dev_proc_open_device(win_pr2_open);
145 private dev_proc_close_device(win_pr2_close);
146 private dev_proc_print_page(win_pr2_print_page);
147 private dev_proc_map_rgb_color(win_pr2_map_rgb_color);
148 private dev_proc_map_color_rgb(win_pr2_map_color_rgb);
149 private dev_proc_get_params(win_pr2_get_params);
150 private dev_proc_put_params(win_pr2_put_params);
151 
152 private void win_pr2_set_bpp(gx_device * dev, int depth);
153 
154 private const gx_device_procs win_pr2_procs =
155 prn_color_params_procs(win_pr2_open, gdev_prn_output_page, win_pr2_close,
156 		       win_pr2_map_rgb_color, win_pr2_map_color_rgb,
157 		       win_pr2_get_params, win_pr2_put_params);
158 
159 #define PARENT_WINDOW  HWND_DESKTOP
160 BOOL CALLBACK CancelDlgProc(HWND, UINT, WPARAM, LPARAM);
161 BOOL CALLBACK AbortProc2(HDC, int);
162 
163 
164 /* The device descriptor */
165 typedef struct gx_device_win_pr2_s gx_device_win_pr2;
166 struct gx_device_win_pr2_s {
167     gx_device_common;
168     gx_prn_device_common;
169     HDC hdcprn;
170     bool nocancel;
171 
172     int doc_page_begin;		/* first page number in document */
173     int doc_page_end;		/* last page number in document */
174     int user_page_begin;	/* user's choice: first page to print */
175     int user_page_end;		/* user's choice: last page to print */
176     int user_copies;		/* user's choice: number of copies */
177     int print_copies;		/* number of times GS should print each page */
178     float user_media_size[2];	/* width/height of media selected by user */
179     char doc_name[200];		/* name of document for the spooler */
180     char paper_name[64];	/* name of selected paper format */
181     bool user_changed_settings;	/* true if user validated dialog */
182     int user_paper;		/* user's choice: paper format */
183     int user_orient;		/* user's choice: paper orientation */
184     int user_color;		/* user's choice: color format */
185     int max_dpi;		/* maximum resolution in DPI */
186     int ratio;			/* stretch ratio when printing */
187     int selected_bpp;		/* selected bpp, memorised by win_pr2_set_bpp */
188     bool tumble;		/* tumble setting (with duplex) */
189     int query_user;		/* query user (-dQueryUser) */
190 
191     HANDLE win32_hdevmode;	/* handle to device mode information */
192     HANDLE win32_hdevnames;	/* handle to device names information */
193 
194     DLGPROC lpfnAbortProc;
195     DLGPROC lpfnCancelProc;
196     HWND hDlgModeless;
197 
198     bool use_old_spool_name;	/* user prefers old \\spool\ name */
199     gx_device_win_pr2* original_device;	/* used to detect copies */
200 };
201 
202 gx_device_win_pr2 far_data gs_mswinpr2_device =
203 {
204     prn_device_std_body(gx_device_win_pr2, win_pr2_procs, "mswinpr2",
205 		      DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72.0, 72.0,
206 			0, 0, 0, 0,
207 			0, win_pr2_print_page),		/* depth = 0 */
208     0,				/* hdcprn */
209     0,				/* nocancel */
210     0,				/* doc_page_begin */
211     0,				/* doc_page_end */
212     0,				/* user_page_begin */
213     0,				/* user_page_end */
214     1,				/* user_copies */
215     1,				/* print_copies */
216     { 0.0, 0.0 },		/* user_media_size */
217     { 0 },			/* doc_name */
218     { 0 },			/* paper_name */
219     0,				/* user_changed_settings */
220     0,				/* user_paper */
221     0,				/* user_orient */
222     0,				/* user_color */
223     0,				/* max_dpi */
224     0,				/* ratio */
225     0,				/* selected_bpp */
226     false,			/* tumble */
227     -1,				/* query_user */
228     NULL,			/* win32_hdevmode */
229     NULL,			/* win32_hdevnames */
230     NULL,			/* lpfnAbortProc */
231     NULL,			/* lpfnCancelProc */
232     NULL,			/* hDlgModeless */
233     false,			/* use_old_spool_name */
234     NULL			/* original_device */
235 };
236 
237 /********************************************************************************/
238 
239 private int win_pr2_getdc(gx_device_win_pr2 * dev);
240 private int win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
241 private int win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
242 private int win_pr2_print_setup_interaction(gx_device_win_pr2 * dev, int mode);
243 private int win_pr2_write_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
244 private int win_pr2_read_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
245 private void win_pr2_copy_check(gx_device_win_pr2 * dev);
246 
247 /********************************************************************************/
248 
249 /* Open the win_pr2 driver */
250 private int
win_pr2_open(gx_device * dev)251 win_pr2_open(gx_device * dev)
252 {
253     int code;
254     int depth;
255     PRINTDLG pd;
256     POINT offset;
257     POINT size;
258     float m[4];
259     FILE *pfile;
260     DOCINFO docinfo;
261     float ratio = 1.0;
262 
263     win_pr2_copy_check(wdev);
264 
265     /* get a HDC for the printer */
266     if ((wdev->win32_hdevmode) &&
267 	(wdev->win32_hdevnames)) {
268 	/* The user has already had the opportunity to choose the output */
269 	/* file interactively. Just use the specified parameters. */
270 
271 	LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
272 	LPDEVNAMES devnames = (LPDEVNAMES) GlobalLock(wdev->win32_hdevnames);
273 
274 	const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
275 	const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
276 	const char* output = (char*)(devnames)+(devnames->wOutputOffset);
277 
278 	wdev->hdcprn = CreateDC(driver, device, output, devmode);
279 
280 	GlobalUnlock(wdev->win32_hdevmode);
281 	GlobalUnlock(wdev->win32_hdevnames);
282 
283 	if (wdev->hdcprn == NULL) {
284 	    return gs_error_Fatal;
285 	}
286 
287     } else if (!win_pr2_getdc(wdev)) {
288 	/* couldn't get a printer from -sOutputFile= */
289 	/* Prompt with dialog box */
290 
291 	LPDEVMODE devmode = NULL;
292 	memset(&pd, 0, sizeof(pd));
293 
294 	pd.lStructSize = sizeof(pd);
295 	pd.hwndOwner = PARENT_WINDOW;
296 	pd.Flags = PD_RETURNDC;
297 	pd.nMinPage = wdev->doc_page_begin;
298 	pd.nMaxPage = wdev->doc_page_end;
299 	pd.nFromPage = wdev->user_page_begin;
300 	pd.nToPage = wdev->user_page_end;
301 	pd.nCopies = wdev->user_copies;
302 
303 	if (!PrintDlg(&pd)) {
304 	    /* device not opened - exit ghostscript */
305 	    return gs_error_Fatal;	/* exit Ghostscript cleanly */
306 	}
307 
308 	devmode = GlobalLock(pd.hDevMode);
309 	win_pr2_update_dev(wdev,devmode);
310 	GlobalUnlock(pd.hDevMode);
311 
312 	if (wdev->win32_hdevmode)
313 	    GlobalFree(wdev->win32_hdevmode);
314 	if (wdev->win32_hdevnames)
315 	    GlobalFree(wdev->win32_hdevnames);
316 
317 	wdev->hdcprn = pd.hDC;
318 	wdev->win32_hdevmode = pd.hDevMode;
319 	wdev->win32_hdevnames = pd.hDevNames;
320 
321 	pd.hDevMode = NULL;
322 	pd.hDevNames = NULL;
323     }
324     if (!(GetDeviceCaps(wdev->hdcprn, RASTERCAPS) != RC_DIBTODEV)) {
325 	errprintf( "Windows printer does not have RC_DIBTODEV\n");
326 	DeleteDC(wdev->hdcprn);
327 	return gs_error_limitcheck;
328     }
329     /* initialise printer, install abort proc */
330     wdev->lpfnAbortProc = (DLGPROC) AbortProc2;
331     SetAbortProc(wdev->hdcprn, (ABORTPROC) wdev->lpfnAbortProc);
332 
333     /*
334      * Some versions of the Windows headers include lpszDatatype and fwType,
335      * and some don't.  Since we want to set these fields to zero anyway,
336      * we just start by zeroing the whole structure.
337      */
338     memset(&docinfo, 0, sizeof(docinfo));
339     docinfo.cbSize = sizeof(docinfo);
340     docinfo.lpszDocName = wdev->doc_name;
341     /*docinfo.lpszOutput = NULL;*/
342     /*docinfo.lpszDatatype = NULL;*/
343     /*docinfo.fwType = 0;*/
344 
345     if (docinfo.lpszDocName[0] == 0) {
346 	docinfo.lpszDocName = "Ghostscript output";
347     }
348 
349     if (StartDoc(wdev->hdcprn, &docinfo) <= 0) {
350 	errprintf("Printer StartDoc failed (error %08x)\n", GetLastError());
351 	DeleteDC(wdev->hdcprn);
352 	return gs_error_limitcheck;
353     }
354 
355     dev->x_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSX);
356     dev->y_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSY);
357 
358     wdev->ratio = 1;
359 
360     if (wdev->max_dpi > 50) {
361 
362 	float dpi_x = dev->x_pixels_per_inch;
363 	float dpi_y = dev->y_pixels_per_inch;
364 
365 	while ((dev->x_pixels_per_inch > wdev->max_dpi)
366 	    || (dev->y_pixels_per_inch > wdev->max_dpi)) {
367 	    ratio += 1.0;
368 	    wdev->ratio ++;
369 	    dev->x_pixels_per_inch = dpi_x / ratio;
370 	    dev->y_pixels_per_inch = dpi_y / ratio;
371 	}
372     }
373 
374     size.x = GetDeviceCaps(wdev->hdcprn, PHYSICALWIDTH);
375     size.y = GetDeviceCaps(wdev->hdcprn, PHYSICALHEIGHT);
376     gx_device_set_width_height(dev, (int)(size.x / ratio), (int)(size.y / ratio));
377     offset.x = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETX);
378     offset.y = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETY);
379 
380     /* m[] gives margins in inches */
381     m[0] /*left   */ = offset.x / dev->x_pixels_per_inch / ratio;
382     m[3] /*top    */ = offset.y / dev->y_pixels_per_inch / ratio;
383     m[2] /*right  */ = (size.x - offset.x - GetDeviceCaps(wdev->hdcprn, HORZRES)) / dev->x_pixels_per_inch / ratio;
384     m[1] /*bottom */ = (size.y - offset.y - GetDeviceCaps(wdev->hdcprn, VERTRES)) / dev->y_pixels_per_inch / ratio;
385     gx_device_set_margins(dev, m, true);
386 
387     depth = dev->color_info.depth;
388     if (depth == 0) {
389 	/* Set parameters that were unknown before opening device */
390 	/* Find out if the device supports color */
391 	/* We recognize 1, 4 (but use only 3), 8 and 24 bit color devices */
392 	depth = GetDeviceCaps(wdev->hdcprn, PLANES) * GetDeviceCaps(wdev->hdcprn, BITSPIXEL);
393     }
394     win_pr2_set_bpp(dev, depth);
395 
396     /* gdev_prn_open opens a temporary file which we don't want */
397     /* so we specify the name now so we can delete it later */
398     pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
399 				 wdev->fname, "wb");
400     fclose(pfile);
401     code = gdev_prn_open(dev);
402     /* delete unwanted temporary file */
403     unlink(wdev->fname);
404 
405     if (!wdev->nocancel) {
406 	/* inform user of progress with dialog box and allow cancel */
407 	wdev->lpfnCancelProc = (DLGPROC) CancelDlgProc;
408 	wdev->hDlgModeless = CreateDialog(phInstance, "CancelDlgBox",
409 				    PARENT_WINDOW, wdev->lpfnCancelProc);
410 	ShowWindow(wdev->hDlgModeless, SW_HIDE);
411     }
412     return code;
413 };
414 
415 /* Close the win_pr2 driver */
416 private int
win_pr2_close(gx_device * dev)417 win_pr2_close(gx_device * dev)
418 {
419     int code;
420     int aborted = FALSE;
421 
422     win_pr2_copy_check(wdev);
423 
424     /* Free resources */
425 
426     if (!wdev->nocancel) {
427 	if (!wdev->hDlgModeless)
428 	    aborted = TRUE;
429 	else
430 	    DestroyWindow(wdev->hDlgModeless);
431 	wdev->hDlgModeless = 0;
432     }
433     if (aborted)
434 	AbortDoc(wdev->hdcprn);
435     else
436 	EndDoc(wdev->hdcprn);
437 
438     DeleteDC(wdev->hdcprn);
439 
440     if (wdev->win32_hdevmode != NULL) {
441 	GlobalFree(wdev->win32_hdevmode);
442 	wdev->win32_hdevmode = NULL;
443     }
444     if (wdev->win32_hdevnames != NULL) {
445 	GlobalFree(wdev->win32_hdevnames);
446 	wdev->win32_hdevnames = NULL;
447     }
448 
449     code = gdev_prn_close(dev);
450     return code;
451 }
452 
453 
454 /* ------ Internal routines ------ */
455 
456 #undef wdev
457 #define wdev ((gx_device_win_pr2 *)pdev)
458 
459 /********************************************************************************/
460 
461 /* ------ Private definitions ------ */
462 
463 
464 /* new win_pr2_print_page routine */
465 
466 /* Write BMP header to memory, then send bitmap to printer */
467 /* one scan line at a time */
468 private int
win_pr2_print_page(gx_device_printer * pdev,FILE * file)469 win_pr2_print_page(gx_device_printer * pdev, FILE * file)
470 {
471     int raster = gdev_prn_raster(pdev);
472 
473     /* BMP scan lines are padded to 32 bits. */
474     ulong bmp_raster = raster + (-raster & 3);
475     ulong bmp_raster_multi;
476     int scan_lines, yslice, lines, i;
477     int width;
478     int depth = pdev->color_info.depth;
479     byte *row;
480     int y;
481     int code = 0;		/* return code */
482     MSG msg;
483     char dlgtext[32];
484     HGLOBAL hrow;
485     int ratio = ((gx_device_win_pr2 *)pdev)->ratio;
486 
487     struct bmi_s {
488 	BITMAPINFOHEADER h;
489 	RGBQUAD pal[256];
490     } bmi;
491 
492     scan_lines = dev_print_scan_lines(pdev);
493     width = (int)(pdev->width - ((dev_l_margin(pdev) + dev_r_margin(pdev) -
494 				  dev_x_offset(pdev)) * pdev->x_pixels_per_inch));
495 
496     yslice = 65535 / bmp_raster;	/* max lines in 64k */
497     bmp_raster_multi = bmp_raster * yslice;
498     hrow = GlobalAlloc(0, bmp_raster_multi);
499     row = GlobalLock(hrow);
500     if (row == 0)		/* can't allocate row buffer */
501 	return_error(gs_error_VMerror);
502 
503     /* Write the info header. */
504 
505     bmi.h.biSize = sizeof(bmi.h);
506     bmi.h.biWidth = pdev->width;	/* wdev->mdev.width; */
507     bmi.h.biHeight = yslice;
508     bmi.h.biPlanes = 1;
509     bmi.h.biBitCount = pdev->color_info.depth;
510     bmi.h.biCompression = 0;
511     bmi.h.biSizeImage = 0;	/* default */
512     bmi.h.biXPelsPerMeter = 0;	/* default */
513     bmi.h.biYPelsPerMeter = 0;	/* default */
514 
515     StartPage(wdev->hdcprn);
516 
517     /* Write the palette. */
518 
519     if (depth <= 8) {
520 	int i;
521 	gx_color_value rgb[3];
522 	LPRGBQUAD pq;
523 
524 	bmi.h.biClrUsed = 1 << depth;
525 	bmi.h.biClrImportant = 1 << depth;
526 	for (i = 0; i != 1 << depth; i++) {
527 	    (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
528 					      (gx_color_index) i, rgb);
529 	    pq = &bmi.pal[i];
530 	    pq->rgbRed = gx_color_value_to_byte(rgb[0]);
531 	    pq->rgbGreen = gx_color_value_to_byte(rgb[1]);
532 	    pq->rgbBlue = gx_color_value_to_byte(rgb[2]);
533 	    pq->rgbReserved = 0;
534 	}
535     } else {
536 	bmi.h.biClrUsed = 0;
537 	bmi.h.biClrImportant = 0;
538     }
539 
540     if (!wdev->nocancel) {
541 	sprintf(dlgtext, "Printing page %d", (int)(pdev->PageCount) + 1);
542 	SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PRINTING), dlgtext);
543 	ShowWindow(wdev->hDlgModeless, SW_SHOW);
544     }
545     for (y = 0; y < scan_lines;) {
546 	/* copy slice to row buffer */
547 	if (y > scan_lines - yslice)
548 	    lines = scan_lines - y;
549 	else
550 	    lines = yslice;
551 	for (i = 0; i < lines; i++)
552 	    gdev_prn_copy_scan_lines(pdev, y + i,
553 			      row + (bmp_raster * (lines - 1 - i)), raster);
554 
555 	if (ratio > 1) {
556 	    StretchDIBits(wdev->hdcprn, 0, y*ratio, pdev->width*ratio, lines*ratio,
557 			  0, 0, pdev->width, lines,
558 			  row,
559 			  (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS, SRCCOPY);
560 	} else {
561 	    SetDIBitsToDevice(wdev->hdcprn, 0, y, pdev->width, lines,
562 			      0, 0, 0, lines,
563 			      row,
564 			      (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS);
565 	}
566 	y += lines;
567 
568 	if (!wdev->nocancel) {
569 	    /* inform user of progress */
570 	    sprintf(dlgtext, "%d%% done", (int)(y * 100L / scan_lines));
571 	    SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE), dlgtext);
572 	}
573 	/* process message loop */
574 	while (PeekMessage(&msg, wdev->hDlgModeless, 0, 0, PM_REMOVE)) {
575 	    if ((wdev->hDlgModeless == 0) || !IsDialogMessage(wdev->hDlgModeless, &msg)) {
576 		TranslateMessage(&msg);
577 		DispatchMessage(&msg);
578 	    }
579 	}
580 	if ((!wdev->nocancel) && (wdev->hDlgModeless == 0)) {
581 	    /* user pressed cancel button */
582 	    break;
583 	}
584     }
585 
586     if ((!wdev->nocancel) && (wdev->hDlgModeless == 0))
587 	code = gs_error_Fatal;	/* exit Ghostscript cleanly */
588     else {
589 	/* push out the page */
590 	if (!wdev->nocancel)
591 	    SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE),
592 			  "Ejecting page...");
593 	EndPage(wdev->hdcprn);
594 	if (!wdev->nocancel)
595 	    ShowWindow(wdev->hDlgModeless, SW_HIDE);
596     }
597 
598     GlobalUnlock(hrow);
599     GlobalFree(hrow);
600 
601     return code;
602 }
603 
604 /* combined color mappers */
605 
606 /* 24-bit color mappers (taken from gdevmem2.c). */
607 /* Note that Windows expects RGB values in the order B,G,R. */
608 
609 /* Map a r-g-b color to a color index. */
610 private gx_color_index
win_pr2_map_rgb_color(gx_device * dev,const gx_color_value cv[])611 win_pr2_map_rgb_color(gx_device * dev, const gx_color_value cv[])
612 {
613     gx_color_value r = cv[0];
614     gx_color_value g = cv[1];
615     gx_color_value b = cv[2];
616     switch (dev->color_info.depth) {
617 	case 1:
618 	    return gdev_prn_map_rgb_color(dev, cv);
619 	case 4:
620 	    /* use only 8 colors */
621 	    return (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
622 		(g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
623 		(b > (gx_max_color_value / 2 + 1) ? 1 : 0);
624 	case 8:
625 	    return pc_8bit_map_rgb_color(dev, cv);
626 	case 24:
627 	    return gx_color_value_to_byte(r) +
628 		((uint) gx_color_value_to_byte(g) << 8) +
629 		((ulong) gx_color_value_to_byte(b) << 16);
630     }
631     return 0;			/* error */
632 }
633 
634 /* Map a color index to a r-g-b color. */
635 private int
win_pr2_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])636 win_pr2_map_color_rgb(gx_device * dev, gx_color_index color,
637 		      gx_color_value prgb[3])
638 {
639     switch (dev->color_info.depth) {
640 	case 1:
641 	    gdev_prn_map_color_rgb(dev, color, prgb);
642 	    break;
643 	case 4:
644 	    /* use only 8 colors */
645 	    prgb[0] = (color & 4) ? gx_max_color_value : 0;
646 	    prgb[1] = (color & 2) ? gx_max_color_value : 0;
647 	    prgb[2] = (color & 1) ? gx_max_color_value : 0;
648 	    break;
649 	case 8:
650 	    pc_8bit_map_color_rgb(dev, color, prgb);
651 	    break;
652 	case 24:
653 	    prgb[2] = gx_color_value_from_byte(color >> 16);
654 	    prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
655 	    prgb[0] = gx_color_value_from_byte(color & 0xff);
656 	    break;
657     }
658     return 0;
659 }
660 
661 void
win_pr2_set_bpp(gx_device * dev,int depth)662 win_pr2_set_bpp(gx_device * dev, int depth)
663 {
664     if (depth > 8) {
665 	static const gx_device_color_info win_pr2_24color = dci_std_color(24);
666 
667 	dev->color_info = win_pr2_24color;
668 	depth = 24;
669     } else if (depth >= 8) {
670 	/* 8-bit (SuperVGA-style) color. */
671 	/* (Uses a fixed palette of 3,3,2 bits.) */
672 	static const gx_device_color_info win_pr2_8color = dci_pc_8bit;
673 
674 	dev->color_info = win_pr2_8color;
675 	depth = 8;
676     } else if (depth >= 3) {
677 	/* 3 plane printer */
678 	/* suitable for impact dot matrix CMYK printers */
679 	/* create 4-bit bitmap, but only use 8 colors */
680 	static const gx_device_color_info win_pr2_4color = dci_values(3, 4, 1, 1, 2, 2);
681 
682 	dev->color_info = win_pr2_4color;
683 	depth = 4;
684     } else {			/* default is black_and_white */
685 	static const gx_device_color_info win_pr2_1color = dci_std_color(1);
686 
687 	dev->color_info = win_pr2_1color;
688 	depth = 1;
689     }
690 
691     ((gx_device_win_pr2 *)dev)->selected_bpp = depth;
692 
693     /* copy encode/decode procedures */
694     dev->procs.encode_color = dev->procs.map_rgb_color;
695     dev->procs.decode_color = dev->procs.map_color_rgb;
696     if (depth == 1) {
697 	dev->procs.get_color_mapping_procs =
698 	    gx_default_DevGray_get_color_mapping_procs;
699 	dev->procs.get_color_comp_index =
700 	    gx_default_DevGray_get_color_comp_index;
701     }
702     else {
703 	dev->procs.get_color_mapping_procs =
704 	    gx_default_DevRGB_get_color_mapping_procs;
705 	dev->procs.get_color_comp_index =
706 	    gx_default_DevRGB_get_color_comp_index;
707     }
708 }
709 
710 /********************************************************************************/
711 
712 /* Get device parameters */
713 int
win_pr2_get_params(gx_device * pdev,gs_param_list * plist)714 win_pr2_get_params(gx_device * pdev, gs_param_list * plist)
715 {
716     int code = gdev_prn_get_params(pdev, plist);
717 
718     win_pr2_copy_check(wdev);
719 
720     if (code >= 0)
721 	code = param_write_bool(plist, "NoCancel",
722 				&(wdev->nocancel));
723     if (code >= 0)
724 	code = param_write_int(plist, "QueryUser",
725 				&(wdev->query_user));
726     if (code >= 0)
727 	code = win_pr2_write_user_settings(wdev, plist);
728 
729     if ((code >= 0) && (wdev->Duplex_set > 0))
730 	code = param_write_bool(plist, "Tumble",
731 				&(wdev->tumble));
732 
733     return code;
734 }
735 
736 
737 /* We implement this ourselves so that we can change BitsPerPixel */
738 /* before the device is opened */
739 int
win_pr2_put_params(gx_device * pdev,gs_param_list * plist)740 win_pr2_put_params(gx_device * pdev, gs_param_list * plist)
741 {
742     int ecode = 0, code;
743     int old_bpp = pdev->color_info.depth;
744     int bpp = old_bpp;
745     bool tumble   = wdev->tumble;
746     bool nocancel = wdev->nocancel;
747     int queryuser = 0;
748     bool old_duplex = wdev->Duplex;
749     bool old_tumble = wdev->tumble;
750     int  old_orient = wdev->user_orient;
751     int  old_color  = wdev->user_color;
752     int  old_paper  = wdev->user_paper;
753     int  old_mx_dpi = wdev->max_dpi;
754 
755     if (wdev->Duplex_set < 0) {
756 	wdev->Duplex_set = 0;
757 	wdev->Duplex = false;
758 	wdev->tumble = false;
759     }
760 
761     win_pr2_copy_check(wdev);
762 
763     code = win_pr2_read_user_settings(wdev, plist);
764 
765     switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
766 	case 0:
767 	    if (pdev->is_open) {
768 		if (wdev->selected_bpp == bpp) {
769 		    break;
770 		}
771 		ecode = gs_error_rangecheck;
772 	    } else {		/* change dev->color_info is valid before device is opened */
773 		win_pr2_set_bpp(pdev, bpp);
774 		break;
775 	    }
776 	    goto bppe;
777 	default:
778 	    ecode = code;
779 	  bppe:param_signal_error(plist, "BitsPerPixel", ecode);
780 	case 1:
781 	    break;
782     }
783 
784     switch (code = param_read_bool(plist, "NoCancel", &nocancel)) {
785 	case 0:
786 	    if (pdev->is_open) {
787 		if (wdev->nocancel == nocancel) {
788 		    break;
789 		}
790 		ecode = gs_error_rangecheck;
791 	    } else {
792 		wdev->nocancel = nocancel;
793 		break;
794 	    }
795 	    goto nocancele;
796 	default:
797 	    ecode = code;
798 	  nocancele:param_signal_error(plist, "NoCancel", ecode);
799 	case 1:
800 	    break;
801     }
802 
803     switch (code = param_read_bool(plist, "Tumble", &tumble)) {
804 	case 0:
805 	    wdev->tumble = tumble;
806 	    break;
807 	default:
808 	    ecode = code;
809 	    param_signal_error(plist, "Tumble", ecode);
810 	case 1:
811 	    break;
812     }
813 
814     switch (code = param_read_int(plist, "QueryUser", &queryuser)) {
815 	case 0:
816 	    if ((queryuser > 0) &&
817 		(queryuser < 4)) {
818 		win_pr2_print_setup_interaction(wdev, queryuser);
819 	    }
820 	    break;
821 	default:
822 	    ecode = code;
823 	    param_signal_error(plist, "QueryUser", ecode);
824 	case 1:
825 	    break;
826     }
827 
828     if (ecode >= 0)
829 	ecode = gdev_prn_put_params(pdev, plist);
830 
831     if (wdev->win32_hdevmode && wdev->hdcprn) {
832 	if ( (old_duplex != wdev->Duplex)
833 	  || (old_tumble != wdev->tumble)
834 	  || (old_orient != wdev->user_orient)
835 	  || (old_color  != wdev->user_color)
836 	  || (old_paper  != wdev->user_paper)
837 	  || (old_mx_dpi != wdev->max_dpi) ) {
838 
839 	    LPDEVMODE pdevmode = GlobalLock(wdev->win32_hdevmode);
840 
841 	    if (pdevmode) {
842 		win_pr2_update_win(wdev, pdevmode);
843 		ResetDC(wdev->hdcprn, pdevmode);
844 		GlobalUnlock(pdevmode);
845 	    }
846 	}
847     }
848 
849     return ecode;
850 }
851 
852 #undef wdev
853 
854 /********************************************************************************/
855 
856 
857 /* Get Device Context for printer */
858 private int
win_pr2_getdc(gx_device_win_pr2 * wdev)859 win_pr2_getdc(gx_device_win_pr2 * wdev)
860 {
861     char *device;
862     char *devices;
863     char *p;
864     char driverbuf[512];
865     char *driver;
866     char *output;
867     char *devcap;
868     int devcapsize;
869     int size;
870 
871     int i, n;
872     POINT *pp;
873     int paperindex;
874     int paperwidth, paperheight;
875     int orientation;
876     int papersize;
877     char papername[64];
878     char drvname[32];
879     HINSTANCE hlib;
880     LPFNDEVMODE pfnExtDeviceMode;
881     LPFNDEVCAPS pfnDeviceCapabilities;
882     LPDEVMODE podevmode, pidevmode;
883 
884     HANDLE hprinter;
885 
886     /* first try to derive the printer name from -sOutputFile= */
887     /* is printer if name prefixed by \\spool\ or by %printer% */
888     if (is_spool(wdev->fname)) {
889 	device = wdev->fname + 8;	/* skip over \\spool\ */
890 	wdev->use_old_spool_name = true;
891     } else if (strncmp("%printer%",wdev->fname,9) == 0) {
892 	device = wdev->fname + 9;	/* skip over %printer% */
893 	wdev->use_old_spool_name = false;
894     } else {
895 	return FALSE;
896     }
897 
898     /* now try to match the printer name against the [Devices] section */
899     if ((devices = gs_malloc(wdev->memory, 4096, 1, "win_pr2_getdc")) == (char *)NULL)
900 	return FALSE;
901     GetProfileString("Devices", NULL, "", devices, 4096);
902     p = devices;
903     while (*p) {
904 	if (stricmp(p, device) == 0)
905 	    break;
906 	p += strlen(p) + 1;
907     }
908     if (*p == '\0')
909 	p = NULL;
910     gs_free(wdev->memory, devices, 4096, 1, "win_pr2_getdc");
911     if (p == NULL)
912 	return FALSE;		/* doesn't match an available printer */
913 
914     /* the printer exists, get the remaining information from win.ini */
915     GetProfileString("Devices", device, "", driverbuf, sizeof(driverbuf));
916     driver = strtok(driverbuf, ",");
917     output = strtok(NULL, ",");
918     if (is_win32s)
919     {
920 	strcpy(drvname, driver);
921 	strcat(drvname, ".drv");
922 	driver = drvname;
923     }
924 
925     if (!is_win32s) {		/* Win32 */
926 	if (!OpenPrinter(device, &hprinter, NULL))
927 	    return FALSE;
928 	size = DocumentProperties(NULL, hprinter, device, NULL, NULL, 0);
929 	if ((podevmode = gs_malloc(wdev->memory, size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
930 	    ClosePrinter(hprinter);
931 	    return FALSE;
932 	}
933 	if ((pidevmode = gs_malloc(wdev->memory, size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
934 	    gs_free(wdev->memory, podevmode, size, 1, "win_pr2_getdc");
935 	    ClosePrinter(hprinter);
936 	    return FALSE;
937 	}
938 	DocumentProperties(NULL, hprinter, device, podevmode, NULL, DM_OUT_BUFFER);
939 	pfnDeviceCapabilities = (LPFNDEVCAPS) DeviceCapabilities;
940     } else
941     {				/* Win16 and Win32s */
942 	/* now load the printer driver */
943 	hlib = LoadLibrary(driver);
944 	if (hlib < (HINSTANCE) HINSTANCE_ERROR)
945 	    return FALSE;
946 
947 	/* call ExtDeviceMode() to get default parameters */
948 	pfnExtDeviceMode = (LPFNDEVMODE) GetProcAddress(hlib, "ExtDeviceMode");
949 	if (pfnExtDeviceMode == (LPFNDEVMODE) NULL) {
950 	    FreeLibrary(hlib);
951 	    return FALSE;
952 	}
953 	pfnDeviceCapabilities = (LPFNDEVCAPS) GetProcAddress(hlib, "DeviceCapabilities");
954 	if (pfnDeviceCapabilities == (LPFNDEVCAPS) NULL) {
955 	    FreeLibrary(hlib);
956 	    return FALSE;
957 	}
958 	size = pfnExtDeviceMode(NULL, hlib, NULL, device, output, NULL, NULL, 0);
959 	if ((podevmode = gs_malloc(wdev->memory, size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
960 	    FreeLibrary(hlib);
961 	    return FALSE;
962 	}
963 	if ((pidevmode = gs_malloc(wdev->memory, size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
964 	    gs_free(wdev->memory, podevmode, size, 1, "win_pr2_getdc");
965 	    FreeLibrary(hlib);
966 	    return FALSE;
967 	}
968 	pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
969 			 NULL, NULL, DM_OUT_BUFFER);
970     }
971 
972     /* now find out what paper sizes are available */
973     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, NULL, NULL);
974     devcapsize *= sizeof(POINT);
975     if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
976 	return FALSE;
977     n = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, devcap, NULL);
978     paperwidth = (int)(wdev->MediaSize[0] * 254 / 72);
979     paperheight = (int)(wdev->MediaSize[1] * 254 / 72);
980     papername[0] = '\0';
981     papersize = 0;
982     paperindex = -1;
983     orientation = 0;
984     pp = (POINT *) devcap;
985     for (i = 0; i < n; i++, pp++) {
986 	if ((pp->x < paperwidth + 20) && (pp->x > paperwidth - 20) &&
987 	    (pp->y < paperheight + 20) && (pp->y > paperheight - 20)) {
988 	    paperindex = i;
989 	    paperwidth = pp->x;
990 	    paperheight = pp->y;
991 	    orientation = DMORIENT_PORTRAIT;
992 	    break;
993 	}
994     }
995     if (paperindex < 0) {
996 	/* try again in landscape */
997 	pp = (POINT *) devcap;
998 	for (i = 0; i < n; i++, pp++) {
999 	    if ((pp->x < paperheight + 20) && (pp->x > paperheight - 20) &&
1000 		(pp->y < paperwidth + 20) && (pp->y > paperwidth - 20)) {
1001 		paperindex = i;
1002 		paperwidth = pp->x;
1003 		paperheight = pp->y;
1004 		orientation = DMORIENT_LANDSCAPE;
1005 		break;
1006 	    }
1007 	}
1008     }
1009     gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
1010 
1011     /* get the dmPaperSize */
1012     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERS, NULL, NULL);
1013     devcapsize *= sizeof(WORD);
1014     if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
1015 	return FALSE;
1016     n = pfnDeviceCapabilities(device, output, DC_PAPERS, devcap, NULL);
1017     if ((paperindex >= 0) && (paperindex < n))
1018 	papersize = ((WORD *) devcap)[paperindex];
1019     gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
1020 
1021     /* get the paper name */
1022     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, NULL, NULL);
1023     devcapsize *= 64;
1024     if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
1025 	return FALSE;
1026     n = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, devcap, NULL);
1027     if ((paperindex >= 0) && (paperindex < n))
1028 	strcpy(papername, devcap + paperindex * 64);
1029     gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
1030 
1031     memcpy(pidevmode, podevmode, size);
1032 
1033     pidevmode->dmFields = 0;
1034 
1035     wdev->paper_name[0] = 0;
1036 
1037     if ( (wdev->user_paper)
1038       && (wdev->user_paper != papersize) ) {
1039 	papersize = wdev->user_paper;
1040 	paperheight = 0;
1041 	paperwidth = 0;
1042 	papername[0] = 0;
1043     }
1044     if (wdev->user_orient) {
1045 	orientation = wdev->user_orient;
1046     }
1047 
1048     pidevmode->dmFields &= ~(DM_PAPERSIZE | DM_ORIENTATION | DM_COLOR | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_DUPLEX);
1049     pidevmode->dmFields |= DM_DEFAULTSOURCE;
1050     pidevmode->dmDefaultSource = 0;
1051 
1052     if (orientation) {
1053 	wdev->user_orient = orientation;
1054     }
1055     if (papersize) {
1056 	wdev->user_paper = papersize;
1057 	strcpy (wdev->paper_name, papername);
1058     }
1059 
1060     if (paperheight && paperwidth) {
1061 	pidevmode->dmFields |= (DM_PAPERLENGTH | DM_PAPERWIDTH);
1062 	pidevmode->dmPaperWidth = paperwidth;
1063 	pidevmode->dmPaperLength = paperheight;
1064         wdev->user_media_size[0] = paperwidth / 254.0 * 72.0;
1065 	wdev->user_media_size[1] = paperheight / 254.0 * 72.0;
1066     }
1067 
1068     if (DeviceCapabilities(device, output, DC_DUPLEX, NULL, NULL)) {
1069 	wdev->Duplex_set = 1;
1070     }
1071 
1072     win_pr2_update_win(wdev, pidevmode);
1073 
1074     if (!is_win32s) {
1075 
1076 	/* merge the entries */
1077 	DocumentProperties(NULL, hprinter, device, podevmode, pidevmode, DM_IN_BUFFER | DM_OUT_BUFFER);
1078 	ClosePrinter(hprinter);
1079 
1080 	/* now get a DC */
1081 	wdev->hdcprn = CreateDC(driver, device, NULL, podevmode);
1082     } else
1083     {				/* Win16 and Win32s */
1084 	pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
1085 			 pidevmode, NULL, DM_IN_BUFFER | DM_OUT_BUFFER);
1086 	/* release the printer driver */
1087 	FreeLibrary(hlib);
1088 	/* now get a DC */
1089 	if (is_win32s)
1090 	    strtok(driver, ".");	/* remove .drv */
1091 	wdev->hdcprn = CreateDC(driver, device, output, podevmode);
1092     }
1093 
1094     if (wdev->win32_hdevmode == NULL) {
1095 	wdev->win32_hdevmode = GlobalAlloc(0, sizeof(DEVMODE));
1096     }
1097 
1098     if (wdev->win32_hdevmode) {
1099 	LPDEVMODE pdevmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
1100 	if (pdevmode) {
1101 	    memcpy(pdevmode, podevmode, sizeof(DEVMODE));
1102 	    GlobalUnlock(wdev->win32_hdevmode);
1103 	}
1104     }
1105 
1106     gs_free(wdev->memory, pidevmode, size, 1, "win_pr2_getdc");
1107     gs_free(wdev->memory, podevmode, size, 1, "win_pr2_getdc");
1108 
1109     if (wdev->hdcprn != (HDC) NULL)
1110 	return TRUE;		/* success */
1111 
1112     /* fall back to prompting user */
1113     return FALSE;
1114 }
1115 
1116 
1117 /*
1118  *  Minimalist update of the wdev parameters (mainly for the
1119  *  UserSettings parameters).
1120  */
1121 
1122 private int
win_pr2_update_dev(gx_device_win_pr2 * dev,LPDEVMODE pdevmode)1123 win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
1124 {
1125     if (pdevmode == 0)
1126 	return FALSE;
1127 
1128     if (pdevmode->dmFields & DM_COLOR) {
1129 	dev->user_color = pdevmode->dmColor;
1130     }
1131     if (pdevmode->dmFields & DM_ORIENTATION) {
1132 	dev->user_orient = pdevmode->dmOrientation;
1133     }
1134     if (pdevmode->dmFields & DM_PAPERSIZE) {
1135 	dev->user_paper = pdevmode->dmPaperSize;
1136         dev->user_media_size[0] = pdevmode->dmPaperWidth / 254.0 * 72.0;
1137 	dev->user_media_size[1] = pdevmode->dmPaperLength / 254.0 * 72.0;
1138 	dev->paper_name[0] = 0;	    /* unknown paper size */
1139     }
1140     if (pdevmode->dmFields & DM_DUPLEX) {
1141 	dev->Duplex_set = 1;
1142 	dev->Duplex = pdevmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
1143 	dev->tumble = pdevmode->dmDuplex == DMDUP_HORIZONTAL ? true : false;
1144     }
1145 
1146     return TRUE;
1147 }
1148 
1149 private int
win_pr2_update_win(gx_device_win_pr2 * dev,LPDEVMODE pdevmode)1150 win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
1151 {
1152     if (dev->Duplex_set > 0) {
1153 	pdevmode->dmFields |= DM_DUPLEX;
1154 	pdevmode->dmDuplex = DMDUP_SIMPLEX;
1155 	if (dev->Duplex) {
1156 	    if (dev->tumble == false) {
1157 		pdevmode->dmDuplex = DMDUP_VERTICAL;
1158 	    } else {
1159 		pdevmode->dmDuplex = DMDUP_HORIZONTAL;
1160 	    }
1161 	}
1162     }
1163 
1164     if (dev->user_color) {
1165 	pdevmode->dmColor = dev->user_color;
1166 	pdevmode->dmFields |= DM_COLOR;
1167     }
1168 
1169     if (dev->user_orient) {
1170 	pdevmode->dmFields |= DM_ORIENTATION;
1171 	pdevmode->dmOrientation = dev->user_orient;
1172     }
1173 
1174     if (dev->user_paper) {
1175 	pdevmode->dmFields |= DM_PAPERSIZE;
1176 	pdevmode->dmPaperSize = dev->user_paper;
1177     }
1178     return 0;
1179 }
1180 
1181 /********************************************************************************/
1182 
1183 #define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
1184   switch ( code = pread(dict.list, (param_name = pname), &(pa)) )\
1185   {\
1186   case 0:\
1187 	if ( (pa).size != psize )\
1188 	  ecode = gs_note_error(gs_error_rangecheck);\
1189 	else {
1190 /* The body of the processing code goes here. */
1191 /* If it succeeds, it should do a 'break'; */
1192 /* if it fails, it should set ecode and fall through. */
1193 #define END_ARRAY_PARAM(pa, e)\
1194 	}\
1195 	goto e;\
1196   default:\
1197 	ecode = code;\
1198 e:	param_signal_error(dict.list, param_name, ecode);\
1199   case 1:\
1200 	(pa).data = 0;		/* mark as not filled */\
1201   }
1202 
1203 
1204 /* Put the user params from UserSettings into our */
1205 /* internal variables. */
1206 private int
win_pr2_read_user_settings(gx_device_win_pr2 * wdev,gs_param_list * plist)1207 win_pr2_read_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
1208 {
1209     gs_param_dict dict;
1210     gs_param_string docn = { 0 };
1211     const char* dict_name = "UserSettings";
1212     const char* param_name = "";
1213     int code = 0;
1214     int ecode = 0;
1215 
1216     switch (code = param_begin_read_dict(plist, dict_name, &dict, false)) {
1217 	default:
1218 	    param_signal_error(plist, dict_name, code);
1219 	    return code;
1220 	case 1:
1221 	    break;
1222 	case 0:
1223 	    {
1224 		gs_param_int_array ia;
1225 
1226 		BEGIN_ARRAY_PARAM(param_read_int_array, "DocumentRange", ia, 2, ia)
1227 		if ((ia.data[0] < 0) ||
1228 		    (ia.data[1] < 0) ||
1229 		    (ia.data[0] > ia.data[1]))
1230 		    ecode = gs_note_error(gs_error_rangecheck);
1231 		wdev->doc_page_begin = ia.data[0];
1232 		wdev->doc_page_end = ia.data[1];
1233 		END_ARRAY_PARAM(ia, doc_range_error)
1234 
1235 		BEGIN_ARRAY_PARAM(param_read_int_array, "SelectedRange", ia, 2, ia)
1236 		if ((ia.data[0] < 0) ||
1237 		    (ia.data[1] < 0) ||
1238 		    (ia.data[0] > ia.data[1]))
1239 		    ecode = gs_note_error(gs_error_rangecheck);
1240 		wdev->user_page_begin = ia.data[0];
1241 		wdev->user_page_end = ia.data[1];
1242 		END_ARRAY_PARAM(ia, sel_range_error)
1243 
1244 		param_read_int(dict.list, "Copies", &wdev->user_copies);
1245 		param_read_int(dict.list, "Paper", &wdev->user_paper);
1246 		param_read_int(dict.list, "Orientation", &wdev->user_orient);
1247 		param_read_int(dict.list, "Color", &wdev->user_color);
1248 		param_read_int(dict.list, "MaxResolution", &wdev->max_dpi);
1249 
1250 		switch (code = param_read_string(dict.list, (param_name = "DocumentName"), &docn)) {
1251 		    case 0:
1252 			if (docn.size < sizeof(wdev->doc_name))
1253 			    break;
1254 			code = gs_error_rangecheck;
1255 			/* fall through */
1256 		    default:
1257 			ecode = code;
1258 			param_signal_error(plist, param_name, ecode);
1259 			/* fall through */
1260 		    case 1:
1261 			docn.data = 0;
1262 			break;
1263 		}
1264 
1265 		param_end_read_dict(plist, dict_name, &dict);
1266 
1267 		if (docn.data) {
1268 		    memcpy(wdev->doc_name, docn.data, docn.size);
1269 		    wdev->doc_name[docn.size] = 0;
1270 		}
1271 
1272 		wdev->print_copies = 1;
1273 
1274 		if (wdev->win32_hdevmode) {
1275 		    LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
1276 		    if (devmode) {
1277 			devmode->dmCopies = wdev->user_copies;
1278 			devmode->dmPaperSize = wdev->user_paper;
1279 			devmode->dmOrientation = wdev->user_orient;
1280 			devmode->dmColor = wdev->user_color;
1281 			GlobalUnlock(wdev->win32_hdevmode);
1282 		    }
1283 		}
1284 	    }
1285 	    break;
1286     }
1287 
1288     return code;
1289 }
1290 
1291 
1292 private int
win_pr2_write_user_settings(gx_device_win_pr2 * wdev,gs_param_list * plist)1293 win_pr2_write_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
1294 {
1295     gs_param_dict dict;
1296     gs_param_int_array range;
1297     gs_param_float_array box;
1298     gs_param_string docn;
1299     gs_param_string papn;
1300     int array[2];
1301     const char* pname = "UserSettings";
1302     int code;
1303 
1304     dict.size = 12;
1305     code = param_begin_write_dict(plist, pname, &dict, false);
1306     if (code < 0) return code;
1307 
1308     array[0] = wdev->doc_page_begin;
1309     array[1] = wdev->doc_page_end;
1310     range.data = array;
1311     range.size = 2;
1312     range.persistent = false;
1313     code = param_write_int_array(dict.list, "DocumentRange", &range);
1314     if (code < 0) goto error;
1315 
1316     array[0] = wdev->user_page_begin;
1317     array[1] = wdev->user_page_end;
1318     range.data = array;
1319     range.size = 2;
1320     range.persistent = false;
1321     code = param_write_int_array(dict.list, "SelectedRange", &range);
1322     if (code < 0) goto error;
1323 
1324     box.data = wdev->user_media_size;
1325     box.size = 2;
1326     box.persistent = false;
1327     code = param_write_float_array(dict.list, "MediaSize", &box);
1328     if (code < 0) goto error;
1329 
1330     code = param_write_int(dict.list, "Copies", &wdev->user_copies);
1331     if (code < 0) goto error;
1332 
1333     code = param_write_int(dict.list, "Paper", &wdev->user_paper);
1334     if (code < 0) goto error;
1335 
1336     code = param_write_int(dict.list, "Orientation", &wdev->user_orient);
1337     if (code < 0) goto error;
1338 
1339     code = param_write_int(dict.list, "Color", &wdev->user_color);
1340     if (code < 0) goto error;
1341 
1342     code = param_write_int(dict.list, "MaxResolution", &wdev->max_dpi);
1343     if (code < 0) goto error;
1344 
1345     code = param_write_int(dict.list, "PrintCopies", &wdev->print_copies);
1346     if (code < 0) goto error;
1347 
1348     docn.data = (const byte*)wdev->doc_name;
1349     docn.size = strlen(wdev->doc_name);
1350     docn.persistent = false;
1351 
1352     code = param_write_string(dict.list, "DocumentName", &docn);
1353     if (code < 0) goto error;
1354 
1355     papn.data = (const byte*)wdev->paper_name;
1356     papn.size = strlen(wdev->paper_name);
1357     papn.persistent = false;
1358 
1359     code = param_write_string(dict.list, "PaperName", &papn);
1360     if (code < 0) goto error;
1361 
1362     code = param_write_bool(dict.list, "UserChangedSettings", &wdev->user_changed_settings);
1363 
1364 error:
1365     param_end_write_dict(plist, pname, &dict);
1366     return code;
1367 }
1368 
1369 /********************************************************************************/
1370 
1371 /*  Show up a dialog for the user to choose a printer and a paper size.
1372  *  If mode == 3, then automatically select the default Windows printer
1373  *  instead of asking the user.
1374  */
1375 
1376 private int
win_pr2_print_setup_interaction(gx_device_win_pr2 * wdev,int mode)1377 win_pr2_print_setup_interaction(gx_device_win_pr2 * wdev, int mode)
1378 {
1379     PRINTDLG pd;
1380     LPDEVMODE  devmode;
1381     LPDEVNAMES devnames;
1382 
1383     wdev->user_changed_settings = FALSE;
1384     wdev->query_user = mode;
1385 
1386     memset(&pd, 0, sizeof(pd));
1387     pd.lStructSize = sizeof(pd);
1388     pd.hwndOwner = PARENT_WINDOW;
1389 
1390     switch (mode) {
1391 	case 2:	pd.Flags = PD_PRINTSETUP; break;
1392 	case 3:	pd.Flags = PD_RETURNDEFAULT; break;
1393 	default: pd.Flags = 0; break;
1394     }
1395 
1396     pd.Flags |= PD_USEDEVMODECOPIES;
1397 
1398     pd.nMinPage = wdev->doc_page_begin;
1399     pd.nMaxPage = wdev->doc_page_end;
1400     pd.nFromPage = wdev->user_page_begin;
1401     pd.nToPage = wdev->user_page_end;
1402     pd.nCopies = wdev->user_copies;
1403 
1404     /* Show the Print Setup dialog and let the user choose a printer
1405      * and a paper size/orientation.
1406      */
1407 
1408     if (!PrintDlg(&pd)) return FALSE;
1409 
1410     devmode = (LPDEVMODE) GlobalLock(pd.hDevMode);
1411     devnames = (LPDEVNAMES) GlobalLock(pd.hDevNames);
1412 
1413     wdev->user_changed_settings = TRUE;
1414     if (wdev->use_old_spool_name) {
1415 	sprintf(wdev->fname, "\\\\spool\\%s", (char*)(devnames)+(devnames->wDeviceOffset));
1416     } else {
1417 	sprintf(wdev->fname, "%%printer%%%s", (char*)(devnames)+(devnames->wDeviceOffset));
1418     }
1419 
1420     if (mode == 3) {
1421 	devmode->dmCopies = wdev->user_copies * wdev->print_copies;
1422 	pd.nCopies = 1;
1423     }
1424 
1425     wdev->user_page_begin = pd.nFromPage;
1426     wdev->user_page_end = pd.nToPage;
1427     wdev->user_copies = devmode->dmCopies;
1428     wdev->print_copies = pd.nCopies;
1429     wdev->user_media_size[0] = devmode->dmPaperWidth / 254.0 * 72.0;
1430     wdev->user_media_size[1] = devmode->dmPaperLength / 254.0 * 72.0;
1431     wdev->user_paper = devmode->dmPaperSize;
1432     wdev->user_orient = devmode->dmOrientation;
1433     wdev->user_color = devmode->dmColor;
1434 
1435     if (devmode->dmFields & DM_DUPLEX) {
1436 	wdev->Duplex_set = 1;
1437 	wdev->Duplex = devmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
1438 	wdev->tumble = devmode->dmDuplex == DMDUP_HORIZONTAL ? true : false;
1439     }
1440 
1441     {
1442 	float xppinch = 0;
1443 	float yppinch = 0;
1444 	const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
1445 	const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
1446 	const char* output = (char*)(devnames)+(devnames->wOutputOffset);
1447 
1448 	HDC hic = CreateIC(driver, device, output, devmode);
1449 
1450 	if (hic) {
1451 	    xppinch = (float)GetDeviceCaps(hic, LOGPIXELSX);
1452 	    yppinch = (float)GetDeviceCaps(hic, LOGPIXELSY);
1453 	    wdev->user_media_size[0] = GetDeviceCaps(hic, PHYSICALWIDTH) * 72.0 / xppinch;
1454 	    wdev->user_media_size[1] = GetDeviceCaps(hic, PHYSICALHEIGHT) * 72.0 / yppinch;
1455 	    DeleteDC(hic);
1456 	}
1457     }
1458 
1459     devmode = NULL;
1460     devnames = NULL;
1461 
1462     GlobalUnlock(pd.hDevMode);
1463     GlobalUnlock(pd.hDevNames);
1464 
1465     if (wdev->win32_hdevmode != NULL) {
1466 	GlobalFree(wdev->win32_hdevmode);
1467     }
1468     if (wdev->win32_hdevnames != NULL) {
1469 	GlobalFree(wdev->win32_hdevnames);
1470     }
1471 
1472     wdev->win32_hdevmode = pd.hDevMode;
1473     wdev->win32_hdevnames = pd.hDevNames;
1474 
1475     return TRUE;
1476 }
1477 
1478 /*  Check that we are dealing with an original device. If this
1479  *  happens to be a copy made by "copydevice", we will have to
1480  *  copy the original's handles to the associated Win32 params.
1481  */
1482 
1483 private void
win_pr2_copy_check(gx_device_win_pr2 * wdev)1484 win_pr2_copy_check(gx_device_win_pr2 * wdev)
1485 {
1486     HGLOBAL hdevmode = wdev->win32_hdevmode;
1487     HGLOBAL hdevnames = wdev->win32_hdevnames;
1488     DWORD devmode_len = (hdevmode) ? GlobalSize(hdevmode) : 0;
1489     DWORD devnames_len = (hdevnames) ? GlobalSize(hdevnames) : 0;
1490 
1491     if (wdev->original_device == wdev)
1492 	return;
1493 
1494     wdev->hdcprn = NULL;
1495     wdev->win32_hdevmode = NULL;
1496     wdev->win32_hdevnames = NULL;
1497 
1498     wdev->original_device = wdev;
1499 
1500     if (devmode_len) {
1501 	wdev->win32_hdevmode = GlobalAlloc(0, devmode_len);
1502 	if (wdev->win32_hdevmode) {
1503 	    memcpy(GlobalLock(wdev->win32_hdevmode), GlobalLock(hdevmode), devmode_len);
1504 	    GlobalUnlock(wdev->win32_hdevmode);
1505 	    GlobalUnlock(hdevmode);
1506 	}
1507     }
1508 
1509     if (devnames_len) {
1510 	wdev->win32_hdevnames = GlobalAlloc(0, devnames_len);
1511 	if (wdev->win32_hdevnames) {
1512 	    memcpy(GlobalLock(wdev->win32_hdevnames), GlobalLock(hdevnames), devnames_len);
1513 	    GlobalUnlock(wdev->win32_hdevnames);
1514 	    GlobalUnlock(hdevnames);
1515 	}
1516     }
1517 }
1518 
1519 
1520 /* Modeless dialog box - Cancel printing */
1521 BOOL CALLBACK
CancelDlgProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)1522 CancelDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1523 {
1524     switch (message) {
1525 	case WM_INITDIALOG:
1526 	    SetWindowText(hDlg, szAppName);
1527 	    return TRUE;
1528 	case WM_COMMAND:
1529 	    switch (LOWORD(wParam)) {
1530 		case IDCANCEL:
1531 		    DestroyWindow(hDlg);
1532 		    EndDialog(hDlg, 0);
1533 		    return TRUE;
1534 	    }
1535     }
1536     return FALSE;
1537 }
1538 
1539 
1540 BOOL CALLBACK
AbortProc2(HDC hdcPrn,int code)1541 AbortProc2(HDC hdcPrn, int code)
1542 {
1543     process_interrupts(NULL);
1544     if (code == SP_OUTOFDISK)
1545 	return (FALSE);		/* cancel job */
1546     return (TRUE);
1547 }
1548 
1549