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