1 /* Copyright (C) 1995, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gdevos2p.c,v 1.4.2.1.2.1 2003/01/17 00:49:01 giles Exp $ */
20 /*
21  * OS/2 printer device
22  *
23  * By Russell Lang, derived from mswinpr2 device by Russell Lang and
24  * L. Peter Deutsch, Aladdin Enterprises.
25  *
26  * Bug fixed by Pierre Arnaud 2000-03-20 (os2prn_set_bpp did not set anti_alias)
27  */
28 
29 /* This device works when GS is a DLL loaded by a PM program */
30 /* It does not work when GS is a text mode EXE */
31 
32 /* This driver uses the printer default size and resolution and
33  * ignores page size and resolution set using -gWIDTHxHEIGHT and
34  * -rXxY.  You must still set the correct PageSize to get the
35  * correct clipping path.  If you don't specify a value for
36  * -dBitsPerPixel, the depth will be obtained from the printer
37  * device context.
38  */
39 
40 #define INCL_DOS
41 #define INCL_DOSERRORS
42 #define INCL_DEV
43 #define INCL_GPIBITMAPS
44 #define INCL_SPL
45 #define INCL_SPLDOSPRINT
46 #define INCL_SPLERRORS
47 
48 #include <os2.h>
49 
50 #include "gdevprn.h"
51 #include "gdevpccm.h"
52 #include "gp.h"
53 #include "gscdefs.h"		/* for gs_product */
54 
55 extern HWND hwndtext;		/* in gp_os2.h */
56 
57 typedef struct tagOS2QL {
58     PRQINFO3 *prq;		/* queue list */
59     ULONG len;			/* bytes in queue list (for gs_free) */
60     int defqueue;		/* default queue */
61     int nqueues;		/* number of queues */
62 } OS2QL;
63 
64 #ifndef NERR_BufTooSmall
65 #define NERR_BufTooSmall 2123	/* For SplEnumQueue */
66 #endif
67 
68 /* Make sure we cast to the correct structure type. */
69 typedef struct gx_device_os2prn_s gx_device_os2prn;
70 
71 #undef opdev
72 #define opdev ((gx_device_os2prn *)dev)
73 
74 /* Device procedures */
75 
76 /* See gxdevice.h for the definitions of the procedures. */
77 private dev_proc_open_device(os2prn_open);
78 private dev_proc_close_device(os2prn_close);
79 private dev_proc_print_page(os2prn_print_page);
80 private dev_proc_map_rgb_color(os2prn_map_rgb_color);
81 private dev_proc_map_color_rgb(os2prn_map_color_rgb);
82 private dev_proc_put_params(os2prn_put_params);
83 private dev_proc_get_params(os2prn_get_params);
84 
85 private void os2prn_set_bpp(gx_device * dev, int depth);
86 private int os2prn_get_queue_list(OS2QL * ql);
87 private void os2prn_free_queue_list(OS2QL * ql);
88 int os2prn_get_printer(OS2QL * ql);
89 
90 private gx_device_procs os2prn_procs =
91 prn_color_params_procs(os2prn_open, gdev_prn_output_page, os2prn_close,
92 		       os2prn_map_rgb_color, os2prn_map_color_rgb,
93 		       os2prn_get_params, os2prn_put_params);
94 
95 
96 /* The device descriptor */
97 struct gx_device_os2prn_s {
98     gx_device_common;
99     gx_prn_device_common;
100     HAB hab;
101     HDC hdc;
102     HPS hps;
103     char queue_name[256];	/* OS/2 printer queue name */
104     int newframe;		/* false before first page */
105     OS2QL ql;
106     int clipbox[4];		/* llx, lly, urx, ury in pixels */
107     HDC hdcMem;
108     HPS hpsMem;
109 };
110 
111 gx_device_os2prn far_data gs_os2prn_device =
112 {
113     prn_device_std_body(gx_device_os2prn, os2prn_procs, "os2prn",
114 			DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72, 72,
115 			0, 0, 0, 0,
116 			0, os2prn_print_page),	/* depth = 0 */
117     0,				/* hab */
118     0,				/* hdc */
119     0,				/* hps */
120     ""				/* queue_name */
121 };
122 
123 /* Open the os2prn driver */
124 private int
os2prn_open(gx_device * dev)125 os2prn_open(gx_device * dev)
126 {
127     int code;
128     PTIB pptib;
129     PPIB pppib;
130     DEVOPENSTRUC dop;
131     ULONG cbBuf;
132     ULONG cbNeeded;
133     APIRET rc;
134     PBYTE pbuf;
135     char *p;
136     SIZEL sizlPage;
137     LONG caps[2];
138     HCINFO hcinfo;
139     LONG nforms;
140     float m[4];
141     int depth;
142     FILE *pfile;
143     int i;
144     char *prefix = "\\\\spool\\";	/* 8 characters long */
145 
146     PRQINFO3 *pprq;
147     gx_device_os2prn *oprn;
148 
149     oprn = opdev;
150 
151     if (DosGetInfoBlocks(&pptib, &pppib)) {
152 	errprintf("\nos2prn_open: Couldn't get pid\n");
153 	return gs_error_limitcheck;
154     }
155     if (pppib->pib_ultype != 3) {
156 	/* if caller is not PM app */
157 	errprintf("os2prn device can only be used from a PM application\n");
158 	return gs_error_limitcheck;
159     }
160     opdev->hab = WinQueryAnchorBlock(hwndtext);
161     opdev->newframe = 0;
162 
163     if (os2prn_get_queue_list(&opdev->ql))
164 	return gs_error_limitcheck;
165 
166     if (opdev->queue_name[0] == '\0') {
167 	/* obtain printer name from filename */
168 	p = opdev->fname;
169 	for (i = 0; i < 8; i++) {
170 	    if (prefix[i] == '\\') {
171 		if ((*p != '\\') && (*p != '/'))
172 		    break;
173 	    } else if (tolower(*p) != prefix[i])
174 		break;
175 	    p++;
176 	}
177 	if (i == 8 && (strlen(p) != 0))
178 	    strcpy(opdev->queue_name, p);
179     }
180     pprq = NULL;
181     if (opdev->queue_name[0] != '\0') {
182 	for (i = 0; i < opdev->ql.nqueues; i++) {
183 	    if (strcmp(opdev->ql.prq[i].pszName, opdev->queue_name) == 0) {
184 		pprq = &(opdev->ql.prq[i]);
185 		break;
186 	    }
187 	}
188     } else {
189 	/* use default queue */
190 	pprq = &(opdev->ql.prq[opdev->ql.defqueue]);
191     }
192     if (pprq == (PRQINFO3 *) NULL) {
193 	errprintf("Invalid os2prn queue  name -sOS2QUEUE=\042%s\042\n", opdev->queue_name);
194 	errprintf("Valid device names are:\n");
195 	for (i = 0; i < opdev->ql.nqueues; i++) {
196 	    errprintf("  -sOS2QUEUE=\042%s\042\n", opdev->ql.prq[i].pszName);
197 	}
198 	return gs_error_rangecheck;
199     }
200     /* open printer device */
201     memset(&dop, 0, sizeof(dop));
202     dop.pszLogAddress = pprq->pszName;	/* queue name */
203     p = strchr(pprq->pszDriverName, '.');
204     if (p != (char *)NULL)
205 	*p = '\0';
206     dop.pszDriverName = pprq->pszDriverName;
207     dop.pszDataType = "PM_Q_STD";
208     dop.pdriv = pprq->pDriverData;
209     opdev->hdc = DevOpenDC(opdev->hab, OD_QUEUED, "*", 9L, (PDEVOPENDATA) & dop, (HDC) NULL);
210     if (opdev->hdc == DEV_ERROR) {
211 	ERRORID eid = WinGetLastError(opdev->hab);
212 
213 	errprintf("DevOpenDC for printer error 0x%x\n", eid);
214 	return gs_error_limitcheck;
215     }
216     os2prn_free_queue_list(&opdev->ql);
217 
218     /* find out resolution of printer */
219     /* this is returned in pixels/metre */
220     DevQueryCaps(opdev->hdc, CAPS_HORIZONTAL_RESOLUTION, 2, caps);
221     dev->x_pixels_per_inch = (int)(caps[0] * 0.0254 + 0.5);
222     dev->y_pixels_per_inch = (int)(caps[1] * 0.0254 + 0.5);
223 
224     /* find out page size and margins */
225     /* these are returned in millimetres */
226     nforms = DevQueryHardcopyCaps(opdev->hdc, 0, 0, &hcinfo);
227     for (i = 0; i < nforms; i++) {
228 	DevQueryHardcopyCaps(opdev->hdc, i, 1, &hcinfo);
229 	if (hcinfo.flAttributes & HCAPS_CURRENT)
230 	    break;		/* this is the default page size */
231     }
232     /* GS size is in pixels */
233     dev->width = hcinfo.cx * caps[0] / 1000;
234     dev->height = hcinfo.cy * caps[1] / 1000;
235     /* GS margins are in inches */
236     m[0] /*left */  = hcinfo.xLeftClip / 25.4;
237     m[1] /*bottom */  = hcinfo.yBottomClip / 25.4;
238     m[2] /*right */  = (hcinfo.cx - hcinfo.xRightClip) / 25.4;
239     m[3] /*top */  = (hcinfo.cy - hcinfo.yTopClip) / 25.4;
240     gx_device_set_margins(dev, m, true);
241     /* set bounding box in pixels for later drawing */
242     opdev->clipbox[0] = (int)(hcinfo.xLeftClip / 25.4 * dev->x_pixels_per_inch + 1);	/* round inwards */
243     opdev->clipbox[1] = (int)(hcinfo.yBottomClip / 25.4 * dev->y_pixels_per_inch + 1);
244     opdev->clipbox[2] = (int)(hcinfo.xRightClip / 25.4 * dev->x_pixels_per_inch);
245     opdev->clipbox[3] = (int)(hcinfo.yTopClip / 25.4 * dev->y_pixels_per_inch);
246 
247     /* get presentation space */
248     sizlPage.cx = dev->width;
249     sizlPage.cy = dev->height;
250     opdev->hps = GpiCreatePS(opdev->hab, opdev->hdc, &sizlPage,
251 			 PU_PELS | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
252 
253     depth = dev->color_info.depth;
254     if (depth == 0) {
255 	/* Set parameters that were unknown before opening device */
256 	/* Find out if the device supports color */
257 	/* We recognize 1, 3, 8 and 24 bit color devices */
258 	DevQueryCaps(opdev->hdc, CAPS_COLOR_PLANES, 2, caps);
259 	/* caps[0] is #color planes, caps[1] is #bits per plane */
260 	depth = caps[0] * caps[1];
261     }
262     os2prn_set_bpp(dev, depth);
263 
264     /* create a memory DC compatible with printer */
265     opdev->hdcMem = DevOpenDC(opdev->hab, OD_MEMORY, "*", 0L, NULL, opdev->hdc);
266     if (opdev->hdcMem == DEV_ERROR) {
267 	ERRORID eid = WinGetLastError(opdev->hab);
268 
269 	errprintf("DevOpenDC for memory error 0x%x\n", eid);
270 	return gs_error_limitcheck;
271     }
272     sizlPage.cx = dev->width;
273     sizlPage.cy = dev->height;
274     opdev->hpsMem = GpiCreatePS(opdev->hab, opdev->hdcMem, &sizlPage,
275 			 PU_PELS | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
276     if (opdev->hpsMem == GPI_ERROR) {
277 	ERRORID eid = WinGetLastError(opdev->hab);
278 
279 	errprintf("GpiCreatePS for memory error 0x%x\n", eid);
280 	return gs_error_limitcheck;
281     }
282     if (DevEscape(opdev->hdc, DEVESC_STARTDOC, (LONG) strlen(gs_product),
283 		  (char *)gs_product, NULL, NULL) == DEVESC_ERROR) {
284 	ERRORID eid = WinGetLastError(opdev->hab);
285 
286 	errprintf("DEVESC_STARTDOC error 0x%x\n", eid);
287 	return gs_error_limitcheck;
288     }
289     /* gdev_prn_open opens a temporary file which we don't want */
290     /* so we specify the name now so we can delete it later */
291     pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
292 				 opdev->fname, "wb");
293     fclose(pfile);
294     code = gdev_prn_open(dev);
295 
296     return code;
297 }
298 
299 /* Close the os2prn driver */
300 private int
os2prn_close(gx_device * dev)301 os2prn_close(gx_device * dev)
302 {
303     int code;
304     LONG lOut;
305     USHORT usJobID;
306 
307     /* tell printer that all is finished */
308     DevEscape(opdev->hdc, DEVESC_ENDDOC, 0L, NULL, &lOut, (PBYTE) & usJobID);
309     /* Free resources */
310     GpiAssociate(opdev->hps, (HDC) NULL);
311     GpiDestroyPS(opdev->hps);
312     DevCloseDC(opdev->hdc);
313 
314     if (opdev->hpsMem != GPI_ERROR)
315 	GpiDestroyPS(opdev->hpsMem);
316     if (opdev->hdcMem != DEV_ERROR)
317 	DevCloseDC(opdev->hdcMem);
318 
319     code = gdev_prn_close(dev);
320     /* delete unwanted temporary file */
321     unlink(opdev->fname);
322     return code;
323 }
324 
325 /* Get os2pm parameters */
326 int
os2prn_get_params(gx_device * dev,gs_param_list * plist)327 os2prn_get_params(gx_device * dev, gs_param_list * plist)
328 {
329     int code = gdev_prn_get_params(dev, plist);
330     gs_param_string qs;
331 
332     qs.data = opdev->queue_name, qs.size = strlen(qs.data),
333 	qs.persistent = false;
334     code < 0 ||
335 	(code = param_write_string(plist, "OS2QUEUE", &qs)) < 0;
336     return code;
337 }
338 
339 
340 
341 /* We implement this ourselves so that we can change BitsPerPixel */
342 /* before the device is opened */
343 int
os2prn_put_params(gx_device * dev,gs_param_list * plist)344 os2prn_put_params(gx_device * dev, gs_param_list * plist)
345 {
346     int ecode = 0, code;
347     int old_bpp = dev->color_info.depth;
348     int bpp = old_bpp;
349     gs_param_string qs;
350 
351     /* Handle extra parameters */
352     switch (code = param_read_string(plist, "OS2QUEUE", &qs)) {
353 	case 0:
354 	    if (qs.size == strlen(opdev->queue_name) &&
355 		!memcmp(opdev->queue_name, qs.data, qs.size)
356 		) {
357 		qs.data = 0;
358 		break;
359 	    }
360 	    if (dev->is_open)
361 		ecode = gs_error_rangecheck;
362 	    else if (qs.size >= sizeof(opdev->queue_name))
363 		ecode = gs_error_limitcheck;
364 	    else
365 		break;
366 	    goto qe;
367 	default:
368 	    ecode = code;
369 	  qe:param_signal_error(plist, "OS2QUEUE", ecode);
370 	case 1:
371 	    qs.data = 0;
372 	    break;
373     }
374 
375     switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
376 	case 0:
377 	    if (dev->is_open)
378 		ecode = gs_error_rangecheck;
379 	    else {		/* change dev->color_info is valid before device is opened */
380 		os2prn_set_bpp(dev, bpp);
381 		break;
382 	    }
383 	    goto bppe;
384 	default:
385 	    ecode = code;
386 	  bppe:param_signal_error(plist, "BitsPerPixel", ecode);
387 	case 1:
388 	    break;
389     }
390 
391     if (ecode >= 0)
392 	ecode = gdev_prn_put_params(dev, plist);
393 
394     if ((ecode >= 0) && (qs.data != 0)) {
395 	memcpy(opdev->queue_name, qs.data, qs.size);
396 	opdev->queue_name[qs.size] = 0;
397     }
398     return ecode;
399 }
400 
401 
402 
403 /* ------ Internal routines ------ */
404 
405 #undef opdev
406 #define opdev ((gx_device_os2prn *)pdev)
407 
408 /************************************************/
409 
410 
411 /* ------ Private definitions ------ */
412 
413 
414 /* new os2prn_print_page routine */
415 
416 /* Write BMP header to memory, then send bitmap to printer */
417 /* one scan line at a time */
418 private int
os2prn_print_page(gx_device_printer * pdev,FILE * file)419 os2prn_print_page(gx_device_printer * pdev, FILE * file)
420 {
421     int raster = gdev_prn_raster(pdev);
422 
423     /* BMP scan lines are padded to 32 bits. */
424     ulong bmp_raster = (raster + 3) & (~3);
425     ulong bmp_raster_multi;
426     int height = pdev->height;
427     int depth = pdev->color_info.depth;
428     byte *row;
429     int y;
430     int code = 0;		/* return code */
431     POINTL apts[4];
432     APIRET rc;
433     POINTL aptsb[4];
434     HBITMAP hbmp, hbmr;
435     int i, lines;
436     int ystart, yend;
437     int yslice;
438 
439     struct bmi_s {
440 	BITMAPINFOHEADER2 h;
441 	RGB2 pal[256];
442     } bmi;
443 
444     yslice = 65535 / bmp_raster;
445     bmp_raster_multi = bmp_raster * yslice;
446     row = (byte *) gs_malloc(bmp_raster_multi, 1, "bmp file buffer");
447     if (row == 0)		/* can't allocate row buffer */
448 	return_error(gs_error_VMerror);
449 
450     if (opdev->newframe)
451 	DevEscape(opdev->hdc, DEVESC_NEWFRAME, 0L, NULL, NULL, NULL);
452     opdev->newframe = 1;
453 
454     /* Write the info header. */
455 
456     memset(&bmi.h, 0, sizeof(bmi.h));
457     bmi.h.cbFix = sizeof(bmi.h);
458     bmi.h.cx = pdev->width;	/* opdev->mdev.width; */
459     /* bmi.h.cy = height; */
460     bmi.h.cy = yslice;		/* size for memory PS */
461     bmi.h.cPlanes = 1;
462     bmi.h.cBitCount = pdev->color_info.depth;
463 
464     /* Write the palette. */
465 
466     if (depth <= 8) {
467 	int i;
468 	gx_color_value rgb[3];
469 	PRGB2 pq;
470 
471 	bmi.h.cclrUsed = 1 << depth;
472 	bmi.h.cclrImportant = 1 << depth;
473 	for (i = 0; i != 1 << depth; i++) {
474 	    (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
475 					      (gx_color_index) i, rgb);
476 	    pq = &bmi.pal[i];
477 	    pq->bRed = gx_color_value_to_byte(rgb[0]);
478 	    pq->bGreen = gx_color_value_to_byte(rgb[1]);
479 	    pq->bBlue = gx_color_value_to_byte(rgb[2]);
480 	    pq->fcOptions = 0;
481 	}
482     } else {
483 	bmi.h.cclrUsed = 0;
484 	bmi.h.cclrImportant = 0;
485     }
486 
487     /* for GpiDrawBits */
488     /* target is inclusive */
489     apts[0].x = 0;
490     apts[0].y = 0;		/* filled in later */
491     apts[1].x = pdev->width - 1;
492     apts[1].y = 0;		/* filled in later */
493     /* source is not inclusive of top & right borders */
494     apts[2].x = 0;
495     apts[2].y = 0;
496     apts[3].x = pdev->width;
497     apts[3].y = 0;		/* filled in later */
498 
499     /* for GpiBitBlt */
500     /* target is not inclusive */
501     aptsb[0].x = opdev->clipbox[0];
502     aptsb[0].y = 0;		/* filled in later */
503     aptsb[1].x = opdev->clipbox[2];
504     aptsb[1].y = 0;		/* filled in later */
505     /* source is not inclusive */
506     aptsb[2].x = opdev->clipbox[0];
507     aptsb[2].y = 0;
508     aptsb[3].x = opdev->clipbox[2];
509     aptsb[3].y = 0;		/* filled in later */
510 
511     /* write the bits */
512     ystart = opdev->clipbox[3];
513     yend = opdev->clipbox[1];
514     y = ystart;
515     while (y > yend) {
516 	/* create a bitmap for the memory DC */
517 	hbmp = GpiCreateBitmap(opdev->hpsMem, &bmi.h, 0L, NULL, NULL);
518 	if (hbmp == GPI_ERROR)
519 	    goto bmp_done;
520 	hbmr = GpiSetBitmap(opdev->hpsMem, hbmp);
521 
522 	/* copy slice to memory bitmap */
523 	if (y > yend + yslice)
524 	    lines = yslice;
525 	else
526 	    lines = y - yend;
527 	y -= lines;
528 	for (i = lines - 1; i >= 0; i--)
529 	    gdev_prn_copy_scan_lines(pdev, ystart - 1 - (y + i), row + (bmp_raster * i), raster);
530 	apts[0].y = 0;		/* target */
531 	apts[1].y = lines;
532 	apts[3].y = lines - 1;	/* source */
533 	/* copy DIB bitmap to memory bitmap */
534 	rc = GpiDrawBits(opdev->hpsMem, row, (BITMAPINFO2 *) & bmi, 4, apts,
535 			 (depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
536 
537 	/* copy slice to printer */
538 	aptsb[0].y = y;
539 	aptsb[1].y = y + lines;
540 	aptsb[3].y = lines;
541 	rc = GpiBitBlt(opdev->hps, opdev->hpsMem, 4, aptsb, ROP_SRCCOPY, BBO_IGNORE);
542 
543 	/* delete bitmap */
544 	if (hbmr != HBM_ERROR)
545 	    GpiSetBitmap(opdev->hpsMem, (ULONG) 0);
546 	hbmr = HBM_ERROR;
547 	if (hbmp != GPI_ERROR)
548 	    GpiDeleteBitmap(hbmp);
549 	hbmp = GPI_ERROR;
550     }
551 
552   bmp_done:
553     if (row)
554 	gs_free((char *)row, bmp_raster_multi, 1, "bmp file buffer");
555 
556     return code;
557 }
558 
559 /* combined color mappers */
560 
561 /* 24-bit color mappers (taken from gdevmem2.c). */
562 /* Note that OS/2 expects RGB values in the order B,G,R. */
563 
564 /* Map a r-g-b color to a color index. */
565 private gx_color_index
os2prn_map_rgb_color(gx_device * dev,gx_color_value r,gx_color_value g,gx_color_value b)566 os2prn_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
567 		     gx_color_value b)
568 {
569     switch (dev->color_info.depth) {
570 	case 1:
571 	    return gdev_prn_map_rgb_color(dev, r, g, b);
572 	case 4:
573 	    /* use only 8 colors */
574 	    return (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
575 		(g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
576 		(b > (gx_max_color_value / 2 + 1) ? 1 : 0);
577 	case 8:
578 	    return pc_8bit_map_rgb_color(dev, r, g, b);
579 	case 24:
580 	    return gx_color_value_to_byte(r) +
581 		((uint) gx_color_value_to_byte(g) << 8) +
582 		((ulong) gx_color_value_to_byte(b) << 16);
583     }
584     return 0;			/* error */
585 }
586 
587 /* Map a color index to a r-g-b color. */
588 private int
os2prn_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])589 os2prn_map_color_rgb(gx_device * dev, gx_color_index color,
590 		     gx_color_value prgb[3])
591 {
592     switch (dev->color_info.depth) {
593 	case 1:
594 	    gdev_prn_map_color_rgb(dev, color, prgb);
595 	    break;
596 	case 4:
597 	    /* use only 8 colors */
598 	    prgb[0] = (color & 4) ? gx_max_color_value : 0;
599 	    prgb[1] = (color & 2) ? gx_max_color_value : 0;
600 	    prgb[2] = (color & 1) ? gx_max_color_value : 0;
601 	    break;
602 	case 8:
603 	    pc_8bit_map_color_rgb(dev, color, prgb);
604 	    break;
605 	case 24:
606 	    prgb[2] = gx_color_value_from_byte(color >> 16);
607 	    prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
608 	    prgb[0] = gx_color_value_from_byte(color & 0xff);
609 	    break;
610     }
611     return 0;
612 }
613 
614 void
os2prn_set_bpp(gx_device * dev,int depth)615 os2prn_set_bpp(gx_device * dev, int depth)
616 {
617     if (depth > 8) {
618 	static const gx_device_color_info os2prn_24color = dci_std_color(24);
619 
620 	dev->color_info = os2prn_24color;
621     } else if (depth >= 8) {
622 	/* 8-bit (SuperVGA-style) color. */
623 	/* (Uses a fixed palette of 3,3,2 bits.) */
624 	static const gx_device_color_info os2prn_8color = dci_pc_8bit;
625 
626 	dev->color_info = os2prn_8color;
627     } else if (depth >= 3) {
628 	/* 3 plane printer */
629 	/* suitable for impact dot matrix CMYK printers */
630 	/* create 4-bit bitmap, but only use 8 colors */
631 	static const gx_device_color_info os2prn_4color = dci_values(3, 4, 1, 1, 2, 2);
632 
633 	dev->color_info = os2prn_4color;
634     } else {			/* default is black_and_white */
635 	static const gx_device_color_info os2prn_1color = dci_std_color(1);
636 
637 	dev->color_info = os2prn_1color;
638     }
639 }
640 
641 /* Get list of queues from SplEnumQueue */
642 /* returns 0 if OK, non-zero for error */
643 private int
os2prn_get_queue_list(OS2QL * ql)644 os2prn_get_queue_list(OS2QL * ql)
645 {
646     SPLERR splerr;
647     USHORT jobCount;
648     ULONG cbBuf;
649     ULONG cTotal;
650     ULONG cReturned;
651     ULONG cbNeeded;
652     ULONG ulLevel;
653     ULONG i;
654     PSZ pszComputerName;
655     PBYTE pBuf;
656     PPRQINFO3 prq;
657 
658     ulLevel = 3L;
659     pszComputerName = (PSZ) NULL;
660     splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, 0L,	/* cbBuf */
661 			  &cReturned, &cTotal,
662 			  &cbNeeded, NULL);
663     if (splerr == ERROR_MORE_DATA || splerr == NERR_BufTooSmall) {
664 	pBuf = gs_malloc(cbNeeded, 1, "OS/2 printer device info buffer");
665 	ql->prq = (PRQINFO3 *) pBuf;
666 	if (ql->prq != (PRQINFO3 *) NULL) {
667 	    ql->len = cbNeeded;
668 	    cbBuf = cbNeeded;
669 	    splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, cbBuf,
670 				  &cReturned, &cTotal,
671 				  &cbNeeded, NULL);
672 	    if (splerr == NO_ERROR) {
673 		/* Set pointer to point to the beginning of the buffer.           */
674 		prq = (PPRQINFO3) pBuf;
675 		/* cReturned has the count of the number of PRQINFO3 structures.  */
676 		ql->nqueues = cReturned;
677 		ql->defqueue = 0;
678 		for (i = 0; i < cReturned; i++) {
679 		    if (prq->fsType & PRQ3_TYPE_APPDEFAULT)
680 			ql->defqueue = i;
681 		    prq++;
682 		}		/*endfor cReturned */
683 	    }
684 	}
685     } else {
686 	/* If we are here we had a bad error code. Print it and some other info. */
687 	eprintf4("SplEnumQueue Error=%ld, Total=%ld, Returned=%ld, Needed=%ld\n",
688 		splerr, cTotal, cReturned, cbNeeded);
689     }
690     if (splerr)
691 	return splerr;
692     return 0;
693 }
694 
695 
696 private void
os2prn_free_queue_list(OS2QL * ql)697 os2prn_free_queue_list(OS2QL * ql)
698 {
699     gs_free((char *)ql->prq, ql->len, 1, "os2prn queue list");
700     ql->prq = NULL;
701     ql->len = 0;
702     ql->defqueue = 0;
703     ql->nqueues = 0;
704 }
705