Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 
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 
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