xref: /plan9-contrib/sys/src/cmd/gs/src/gdevos2p.c (revision 3ff48bf5ed603850fcd251ddf13025d23d693782)
1*3ff48bf5SDavid du Colombier /* Copyright (C) 1995, 2000 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*3ff48bf5SDavid du Colombier   This file is part of AFPL Ghostscript.
47dd7cddfSDavid du Colombier 
5*3ff48bf5SDavid du Colombier   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6*3ff48bf5SDavid du Colombier   distributor accepts any responsibility for the consequences of using it, or
7*3ff48bf5SDavid du Colombier   for whether it serves any particular purpose or works at all, unless he or
8*3ff48bf5SDavid du Colombier   she says so in writing.  Refer to the Aladdin Free Public License (the
9*3ff48bf5SDavid du Colombier   "License") for full details.
107dd7cddfSDavid du Colombier 
11*3ff48bf5SDavid du Colombier   Every copy of AFPL Ghostscript must include a copy of the License, normally
12*3ff48bf5SDavid du Colombier   in a plain ASCII text file named PUBLIC.  The License grants you the right
13*3ff48bf5SDavid du Colombier   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14*3ff48bf5SDavid du Colombier   conditions described in the License.  Among other things, the License
15*3ff48bf5SDavid du Colombier   requires that the copyright notice and this notice be preserved on all
16*3ff48bf5SDavid du Colombier   copies.
177dd7cddfSDavid du Colombier */
187dd7cddfSDavid du Colombier 
19*3ff48bf5SDavid du Colombier /*$Id: gdevos2p.c,v 1.4 2001/03/13 06:51:39 ghostgum Exp $ */
207dd7cddfSDavid du Colombier /*
217dd7cddfSDavid du Colombier  * OS/2 printer device
227dd7cddfSDavid du Colombier  *
237dd7cddfSDavid du Colombier  * By Russell Lang, derived from mswinpr2 device by Russell Lang and
247dd7cddfSDavid du Colombier  * L. Peter Deutsch, Aladdin Enterprises.
25*3ff48bf5SDavid du Colombier  *
26*3ff48bf5SDavid du Colombier  * Bug fixed by Pierre Arnaud 2000-03-20 (os2prn_set_bpp did not set anti_alias)
277dd7cddfSDavid du Colombier  */
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier /* This device works when GS is a DLL loaded by a PM program */
307dd7cddfSDavid du Colombier /* It does not work when GS is a text mode EXE */
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier /* This driver uses the printer default size and resolution and
337dd7cddfSDavid du Colombier  * ignores page size and resolution set using -gWIDTHxHEIGHT and
347dd7cddfSDavid du Colombier  * -rXxY.  You must still set the correct PageSize to get the
357dd7cddfSDavid du Colombier  * correct clipping path.  If you don't specify a value for
367dd7cddfSDavid du Colombier  * -dBitsPerPixel, the depth will be obtained from the printer
377dd7cddfSDavid du Colombier  * device context.
387dd7cddfSDavid du Colombier  */
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier #define INCL_DOS
417dd7cddfSDavid du Colombier #define INCL_DOSERRORS
427dd7cddfSDavid du Colombier #define INCL_DEV
437dd7cddfSDavid du Colombier #define INCL_GPIBITMAPS
447dd7cddfSDavid du Colombier #define INCL_SPL
457dd7cddfSDavid du Colombier #define INCL_SPLDOSPRINT
467dd7cddfSDavid du Colombier #define INCL_SPLERRORS
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier #include <os2.h>
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier #include "gdevprn.h"
517dd7cddfSDavid du Colombier #include "gdevpccm.h"
527dd7cddfSDavid du Colombier #include "gp.h"
537dd7cddfSDavid du Colombier #include "gscdefs.h"		/* for gs_product */
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier extern HWND hwndtext;		/* in gp_os2.h */
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier typedef struct tagOS2QL {
587dd7cddfSDavid du Colombier     PRQINFO3 *prq;		/* queue list */
597dd7cddfSDavid du Colombier     ULONG len;			/* bytes in queue list (for gs_free) */
607dd7cddfSDavid du Colombier     int defqueue;		/* default queue */
617dd7cddfSDavid du Colombier     int nqueues;		/* number of queues */
627dd7cddfSDavid du Colombier } OS2QL;
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier #ifndef NERR_BufTooSmall
657dd7cddfSDavid du Colombier #define NERR_BufTooSmall 2123	/* For SplEnumQueue */
667dd7cddfSDavid du Colombier #endif
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier /* Make sure we cast to the correct structure type. */
697dd7cddfSDavid du Colombier typedef struct gx_device_os2prn_s gx_device_os2prn;
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier #undef opdev
727dd7cddfSDavid du Colombier #define opdev ((gx_device_os2prn *)dev)
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier /* Device procedures */
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier /* See gxdevice.h for the definitions of the procedures. */
777dd7cddfSDavid du Colombier private dev_proc_open_device(os2prn_open);
787dd7cddfSDavid du Colombier private dev_proc_close_device(os2prn_close);
797dd7cddfSDavid du Colombier private dev_proc_print_page(os2prn_print_page);
807dd7cddfSDavid du Colombier private dev_proc_map_rgb_color(os2prn_map_rgb_color);
817dd7cddfSDavid du Colombier private dev_proc_map_color_rgb(os2prn_map_color_rgb);
827dd7cddfSDavid du Colombier private dev_proc_put_params(os2prn_put_params);
837dd7cddfSDavid du Colombier private dev_proc_get_params(os2prn_get_params);
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier private void os2prn_set_bpp(gx_device * dev, int depth);
867dd7cddfSDavid du Colombier private int os2prn_get_queue_list(OS2QL * ql);
877dd7cddfSDavid du Colombier private void os2prn_free_queue_list(OS2QL * ql);
887dd7cddfSDavid du Colombier int os2prn_get_printer(OS2QL * ql);
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier private gx_device_procs os2prn_procs =
917dd7cddfSDavid du Colombier prn_color_params_procs(os2prn_open, gdev_prn_output_page, os2prn_close,
927dd7cddfSDavid du Colombier 		       os2prn_map_rgb_color, os2prn_map_color_rgb,
937dd7cddfSDavid du Colombier 		       os2prn_get_params, os2prn_put_params);
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier /* The device descriptor */
977dd7cddfSDavid du Colombier struct gx_device_os2prn_s {
987dd7cddfSDavid du Colombier     gx_device_common;
997dd7cddfSDavid du Colombier     gx_prn_device_common;
1007dd7cddfSDavid du Colombier     HAB hab;
1017dd7cddfSDavid du Colombier     HDC hdc;
1027dd7cddfSDavid du Colombier     HPS hps;
1037dd7cddfSDavid du Colombier     char queue_name[256];	/* OS/2 printer queue name */
1047dd7cddfSDavid du Colombier     int newframe;		/* false before first page */
1057dd7cddfSDavid du Colombier     OS2QL ql;
1067dd7cddfSDavid du Colombier     int clipbox[4];		/* llx, lly, urx, ury in pixels */
1077dd7cddfSDavid du Colombier     HDC hdcMem;
1087dd7cddfSDavid du Colombier     HPS hpsMem;
1097dd7cddfSDavid du Colombier };
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier gx_device_os2prn far_data gs_os2prn_device =
1127dd7cddfSDavid du Colombier {
1137dd7cddfSDavid du Colombier     prn_device_std_body(gx_device_os2prn, os2prn_procs, "os2prn",
1147dd7cddfSDavid du Colombier 			DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72, 72,
1157dd7cddfSDavid du Colombier 			0, 0, 0, 0,
1167dd7cddfSDavid du Colombier 			0, os2prn_print_page),	/* depth = 0 */
1177dd7cddfSDavid du Colombier     0,				/* hab */
1187dd7cddfSDavid du Colombier     0,				/* hdc */
1197dd7cddfSDavid du Colombier     0,				/* hps */
1207dd7cddfSDavid du Colombier     ""				/* queue_name */
1217dd7cddfSDavid du Colombier };
1227dd7cddfSDavid du Colombier 
1237dd7cddfSDavid du Colombier /* Open the os2prn driver */
1247dd7cddfSDavid du Colombier private int
1257dd7cddfSDavid du Colombier os2prn_open(gx_device * dev)
1267dd7cddfSDavid du Colombier {
1277dd7cddfSDavid du Colombier     int code;
1287dd7cddfSDavid du Colombier     PTIB pptib;
1297dd7cddfSDavid du Colombier     PPIB pppib;
1307dd7cddfSDavid du Colombier     DEVOPENSTRUC dop;
1317dd7cddfSDavid du Colombier     ULONG cbBuf;
1327dd7cddfSDavid du Colombier     ULONG cbNeeded;
1337dd7cddfSDavid du Colombier     APIRET rc;
1347dd7cddfSDavid du Colombier     PBYTE pbuf;
1357dd7cddfSDavid du Colombier     char *p;
1367dd7cddfSDavid du Colombier     SIZEL sizlPage;
1377dd7cddfSDavid du Colombier     LONG caps[2];
1387dd7cddfSDavid du Colombier     HCINFO hcinfo;
1397dd7cddfSDavid du Colombier     LONG nforms;
1407dd7cddfSDavid du Colombier     float m[4];
1417dd7cddfSDavid du Colombier     int depth;
1427dd7cddfSDavid du Colombier     FILE *pfile;
1437dd7cddfSDavid du Colombier     int i;
1447dd7cddfSDavid du Colombier     char *prefix = "\\\\spool\\";	/* 8 characters long */
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier     PRQINFO3 *pprq;
1477dd7cddfSDavid du Colombier     gx_device_os2prn *oprn;
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier     oprn = opdev;
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier     if (DosGetInfoBlocks(&pptib, &pppib)) {
152*3ff48bf5SDavid du Colombier 	errprintf("\nos2prn_open: Couldn't get pid\n");
1537dd7cddfSDavid du Colombier 	return gs_error_limitcheck;
1547dd7cddfSDavid du Colombier     }
1557dd7cddfSDavid du Colombier     if (pppib->pib_ultype != 3) {
1567dd7cddfSDavid du Colombier 	/* if caller is not PM app */
157*3ff48bf5SDavid du Colombier 	errprintf("os2prn device can only be used from a PM application\n");
1587dd7cddfSDavid du Colombier 	return gs_error_limitcheck;
1597dd7cddfSDavid du Colombier     }
1607dd7cddfSDavid du Colombier     opdev->hab = WinQueryAnchorBlock(hwndtext);
1617dd7cddfSDavid du Colombier     opdev->newframe = 0;
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier     if (os2prn_get_queue_list(&opdev->ql))
1647dd7cddfSDavid du Colombier 	return gs_error_limitcheck;
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier     if (opdev->queue_name[0] == '\0') {
1677dd7cddfSDavid du Colombier 	/* obtain printer name from filename */
1687dd7cddfSDavid du Colombier 	p = opdev->fname;
1697dd7cddfSDavid du Colombier 	for (i = 0; i < 8; i++) {
1707dd7cddfSDavid du Colombier 	    if (prefix[i] == '\\') {
1717dd7cddfSDavid du Colombier 		if ((*p != '\\') && (*p != '/'))
1727dd7cddfSDavid du Colombier 		    break;
1737dd7cddfSDavid du Colombier 	    } else if (tolower(*p) != prefix[i])
1747dd7cddfSDavid du Colombier 		break;
1757dd7cddfSDavid du Colombier 	    p++;
1767dd7cddfSDavid du Colombier 	}
1777dd7cddfSDavid du Colombier 	if (i == 8 && (strlen(p) != 0))
1787dd7cddfSDavid du Colombier 	    strcpy(opdev->queue_name, p);
1797dd7cddfSDavid du Colombier     }
1807dd7cddfSDavid du Colombier     pprq = NULL;
1817dd7cddfSDavid du Colombier     if (opdev->queue_name[0] != '\0') {
1827dd7cddfSDavid du Colombier 	for (i = 0; i < opdev->ql.nqueues; i++) {
1837dd7cddfSDavid du Colombier 	    if (strcmp(opdev->ql.prq[i].pszName, opdev->queue_name) == 0) {
1847dd7cddfSDavid du Colombier 		pprq = &(opdev->ql.prq[i]);
1857dd7cddfSDavid du Colombier 		break;
1867dd7cddfSDavid du Colombier 	    }
1877dd7cddfSDavid du Colombier 	}
1887dd7cddfSDavid du Colombier     } else {
1897dd7cddfSDavid du Colombier 	/* use default queue */
1907dd7cddfSDavid du Colombier 	pprq = &(opdev->ql.prq[opdev->ql.defqueue]);
1917dd7cddfSDavid du Colombier     }
1927dd7cddfSDavid du Colombier     if (pprq == (PRQINFO3 *) NULL) {
193*3ff48bf5SDavid du Colombier 	errprintf("Invalid os2prn queue  name -sOS2QUEUE=\042%s\042\n", opdev->queue_name);
194*3ff48bf5SDavid du Colombier 	errprintf("Valid device names are:\n");
1957dd7cddfSDavid du Colombier 	for (i = 0; i < opdev->ql.nqueues; i++) {
196*3ff48bf5SDavid du Colombier 	    errprintf("  -sOS2QUEUE=\042%s\042\n", opdev->ql.prq[i].pszName);
1977dd7cddfSDavid du Colombier 	}
1987dd7cddfSDavid du Colombier 	return gs_error_rangecheck;
1997dd7cddfSDavid du Colombier     }
2007dd7cddfSDavid du Colombier     /* open printer device */
2017dd7cddfSDavid du Colombier     memset(&dop, 0, sizeof(dop));
2027dd7cddfSDavid du Colombier     dop.pszLogAddress = pprq->pszName;	/* queue name */
2037dd7cddfSDavid du Colombier     p = strchr(pprq->pszDriverName, '.');
2047dd7cddfSDavid du Colombier     if (p != (char *)NULL)
2057dd7cddfSDavid du Colombier 	*p = '\0';
2067dd7cddfSDavid du Colombier     dop.pszDriverName = pprq->pszDriverName;
2077dd7cddfSDavid du Colombier     dop.pszDataType = "PM_Q_STD";
2087dd7cddfSDavid du Colombier     dop.pdriv = pprq->pDriverData;
2097dd7cddfSDavid du Colombier     opdev->hdc = DevOpenDC(opdev->hab, OD_QUEUED, "*", 9L, (PDEVOPENDATA) & dop, (HDC) NULL);
2107dd7cddfSDavid du Colombier     if (opdev->hdc == DEV_ERROR) {
2117dd7cddfSDavid du Colombier 	ERRORID eid = WinGetLastError(opdev->hab);
2127dd7cddfSDavid du Colombier 
213*3ff48bf5SDavid du Colombier 	errprintf("DevOpenDC for printer error 0x%x\n", eid);
2147dd7cddfSDavid du Colombier 	return gs_error_limitcheck;
2157dd7cddfSDavid du Colombier     }
2167dd7cddfSDavid du Colombier     os2prn_free_queue_list(&opdev->ql);
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier     /* find out resolution of printer */
2197dd7cddfSDavid du Colombier     /* this is returned in pixels/metre */
2207dd7cddfSDavid du Colombier     DevQueryCaps(opdev->hdc, CAPS_HORIZONTAL_RESOLUTION, 2, caps);
2217dd7cddfSDavid du Colombier     dev->x_pixels_per_inch = (int)(caps[0] * 0.0254 + 0.5);
2227dd7cddfSDavid du Colombier     dev->y_pixels_per_inch = (int)(caps[1] * 0.0254 + 0.5);
2237dd7cddfSDavid du Colombier 
2247dd7cddfSDavid du Colombier     /* find out page size and margins */
2257dd7cddfSDavid du Colombier     /* these are returned in millimetres */
2267dd7cddfSDavid du Colombier     nforms = DevQueryHardcopyCaps(opdev->hdc, 0, 0, &hcinfo);
2277dd7cddfSDavid du Colombier     for (i = 0; i < nforms; i++) {
2287dd7cddfSDavid du Colombier 	DevQueryHardcopyCaps(opdev->hdc, i, 1, &hcinfo);
2297dd7cddfSDavid du Colombier 	if (hcinfo.flAttributes & HCAPS_CURRENT)
2307dd7cddfSDavid du Colombier 	    break;		/* this is the default page size */
2317dd7cddfSDavid du Colombier     }
2327dd7cddfSDavid du Colombier     /* GS size is in pixels */
2337dd7cddfSDavid du Colombier     dev->width = hcinfo.cx * caps[0] / 1000;
2347dd7cddfSDavid du Colombier     dev->height = hcinfo.cy * caps[1] / 1000;
2357dd7cddfSDavid du Colombier     /* GS margins are in inches */
2367dd7cddfSDavid du Colombier     m[0] /*left */  = hcinfo.xLeftClip / 25.4;
2377dd7cddfSDavid du Colombier     m[1] /*bottom */  = hcinfo.yBottomClip / 25.4;
2387dd7cddfSDavid du Colombier     m[2] /*right */  = (hcinfo.cx - hcinfo.xRightClip) / 25.4;
2397dd7cddfSDavid du Colombier     m[3] /*top */  = (hcinfo.cy - hcinfo.yTopClip) / 25.4;
2407dd7cddfSDavid du Colombier     gx_device_set_margins(dev, m, true);
2417dd7cddfSDavid du Colombier     /* set bounding box in pixels for later drawing */
2427dd7cddfSDavid du Colombier     opdev->clipbox[0] = (int)(hcinfo.xLeftClip / 25.4 * dev->x_pixels_per_inch + 1);	/* round inwards */
2437dd7cddfSDavid du Colombier     opdev->clipbox[1] = (int)(hcinfo.yBottomClip / 25.4 * dev->y_pixels_per_inch + 1);
2447dd7cddfSDavid du Colombier     opdev->clipbox[2] = (int)(hcinfo.xRightClip / 25.4 * dev->x_pixels_per_inch);
2457dd7cddfSDavid du Colombier     opdev->clipbox[3] = (int)(hcinfo.yTopClip / 25.4 * dev->y_pixels_per_inch);
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier     /* get presentation space */
2487dd7cddfSDavid du Colombier     sizlPage.cx = dev->width;
2497dd7cddfSDavid du Colombier     sizlPage.cy = dev->height;
2507dd7cddfSDavid du Colombier     opdev->hps = GpiCreatePS(opdev->hab, opdev->hdc, &sizlPage,
2517dd7cddfSDavid du Colombier 			 PU_PELS | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier     depth = dev->color_info.depth;
2547dd7cddfSDavid du Colombier     if (depth == 0) {
2557dd7cddfSDavid du Colombier 	/* Set parameters that were unknown before opening device */
2567dd7cddfSDavid du Colombier 	/* Find out if the device supports color */
2577dd7cddfSDavid du Colombier 	/* We recognize 1, 3, 8 and 24 bit color devices */
2587dd7cddfSDavid du Colombier 	DevQueryCaps(opdev->hdc, CAPS_COLOR_PLANES, 2, caps);
2597dd7cddfSDavid du Colombier 	/* caps[0] is #color planes, caps[1] is #bits per plane */
2607dd7cddfSDavid du Colombier 	depth = caps[0] * caps[1];
2617dd7cddfSDavid du Colombier     }
2627dd7cddfSDavid du Colombier     os2prn_set_bpp(dev, depth);
2637dd7cddfSDavid du Colombier 
2647dd7cddfSDavid du Colombier     /* create a memory DC compatible with printer */
2657dd7cddfSDavid du Colombier     opdev->hdcMem = DevOpenDC(opdev->hab, OD_MEMORY, "*", 0L, NULL, opdev->hdc);
2667dd7cddfSDavid du Colombier     if (opdev->hdcMem == DEV_ERROR) {
2677dd7cddfSDavid du Colombier 	ERRORID eid = WinGetLastError(opdev->hab);
2687dd7cddfSDavid du Colombier 
269*3ff48bf5SDavid du Colombier 	errprintf("DevOpenDC for memory error 0x%x\n", eid);
2707dd7cddfSDavid du Colombier 	return gs_error_limitcheck;
2717dd7cddfSDavid du Colombier     }
2727dd7cddfSDavid du Colombier     sizlPage.cx = dev->width;
2737dd7cddfSDavid du Colombier     sizlPage.cy = dev->height;
2747dd7cddfSDavid du Colombier     opdev->hpsMem = GpiCreatePS(opdev->hab, opdev->hdcMem, &sizlPage,
2757dd7cddfSDavid du Colombier 			 PU_PELS | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
2767dd7cddfSDavid du Colombier     if (opdev->hpsMem == GPI_ERROR) {
2777dd7cddfSDavid du Colombier 	ERRORID eid = WinGetLastError(opdev->hab);
2787dd7cddfSDavid du Colombier 
279*3ff48bf5SDavid du Colombier 	errprintf("GpiCreatePS for memory error 0x%x\n", eid);
2807dd7cddfSDavid du Colombier 	return gs_error_limitcheck;
2817dd7cddfSDavid du Colombier     }
2827dd7cddfSDavid du Colombier     if (DevEscape(opdev->hdc, DEVESC_STARTDOC, (LONG) strlen(gs_product),
2837dd7cddfSDavid du Colombier 		  (char *)gs_product, NULL, NULL) == DEVESC_ERROR) {
2847dd7cddfSDavid du Colombier 	ERRORID eid = WinGetLastError(opdev->hab);
2857dd7cddfSDavid du Colombier 
286*3ff48bf5SDavid du Colombier 	errprintf("DEVESC_STARTDOC error 0x%x\n", eid);
2877dd7cddfSDavid du Colombier 	return gs_error_limitcheck;
2887dd7cddfSDavid du Colombier     }
2897dd7cddfSDavid du Colombier     /* gdev_prn_open opens a temporary file which we don't want */
2907dd7cddfSDavid du Colombier     /* so we specify the name now so we can delete it later */
2917dd7cddfSDavid du Colombier     pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
2927dd7cddfSDavid du Colombier 				 opdev->fname, "wb");
2937dd7cddfSDavid du Colombier     fclose(pfile);
2947dd7cddfSDavid du Colombier     code = gdev_prn_open(dev);
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier     return code;
2977dd7cddfSDavid du Colombier }
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier /* Close the os2prn driver */
3007dd7cddfSDavid du Colombier private int
3017dd7cddfSDavid du Colombier os2prn_close(gx_device * dev)
3027dd7cddfSDavid du Colombier {
3037dd7cddfSDavid du Colombier     int code;
3047dd7cddfSDavid du Colombier     LONG lOut;
3057dd7cddfSDavid du Colombier     USHORT usJobID;
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier     /* tell printer that all is finished */
3087dd7cddfSDavid du Colombier     DevEscape(opdev->hdc, DEVESC_ENDDOC, 0L, NULL, &lOut, (PBYTE) & usJobID);
3097dd7cddfSDavid du Colombier     /* Free resources */
3107dd7cddfSDavid du Colombier     GpiAssociate(opdev->hps, (HDC) NULL);
3117dd7cddfSDavid du Colombier     GpiDestroyPS(opdev->hps);
3127dd7cddfSDavid du Colombier     DevCloseDC(opdev->hdc);
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier     if (opdev->hpsMem != GPI_ERROR)
3157dd7cddfSDavid du Colombier 	GpiDestroyPS(opdev->hpsMem);
3167dd7cddfSDavid du Colombier     if (opdev->hdcMem != DEV_ERROR)
3177dd7cddfSDavid du Colombier 	DevCloseDC(opdev->hdcMem);
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier     code = gdev_prn_close(dev);
3207dd7cddfSDavid du Colombier     /* delete unwanted temporary file */
3217dd7cddfSDavid du Colombier     unlink(opdev->fname);
3227dd7cddfSDavid du Colombier     return code;
3237dd7cddfSDavid du Colombier }
3247dd7cddfSDavid du Colombier 
3257dd7cddfSDavid du Colombier /* Get os2pm parameters */
3267dd7cddfSDavid du Colombier int
3277dd7cddfSDavid du Colombier os2prn_get_params(gx_device * dev, gs_param_list * plist)
3287dd7cddfSDavid du Colombier {
3297dd7cddfSDavid du Colombier     int code = gdev_prn_get_params(dev, plist);
3307dd7cddfSDavid du Colombier     gs_param_string qs;
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier     qs.data = opdev->queue_name, qs.size = strlen(qs.data),
3337dd7cddfSDavid du Colombier 	qs.persistent = false;
3347dd7cddfSDavid du Colombier     code < 0 ||
3357dd7cddfSDavid du Colombier 	(code = param_write_string(plist, "OS2QUEUE", &qs)) < 0;
3367dd7cddfSDavid du Colombier     return code;
3377dd7cddfSDavid du Colombier }
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 
3417dd7cddfSDavid du Colombier /* We implement this ourselves so that we can change BitsPerPixel */
3427dd7cddfSDavid du Colombier /* before the device is opened */
3437dd7cddfSDavid du Colombier int
3447dd7cddfSDavid du Colombier os2prn_put_params(gx_device * dev, gs_param_list * plist)
3457dd7cddfSDavid du Colombier {
3467dd7cddfSDavid du Colombier     int ecode = 0, code;
3477dd7cddfSDavid du Colombier     int old_bpp = dev->color_info.depth;
3487dd7cddfSDavid du Colombier     int bpp = old_bpp;
3497dd7cddfSDavid du Colombier     gs_param_string qs;
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier     /* Handle extra parameters */
3527dd7cddfSDavid du Colombier     switch (code = param_read_string(plist, "OS2QUEUE", &qs)) {
3537dd7cddfSDavid du Colombier 	case 0:
3547dd7cddfSDavid du Colombier 	    if (qs.size == strlen(opdev->queue_name) &&
3557dd7cddfSDavid du Colombier 		!memcmp(opdev->queue_name, qs.data, qs.size)
3567dd7cddfSDavid du Colombier 		) {
3577dd7cddfSDavid du Colombier 		qs.data = 0;
3587dd7cddfSDavid du Colombier 		break;
3597dd7cddfSDavid du Colombier 	    }
3607dd7cddfSDavid du Colombier 	    if (dev->is_open)
3617dd7cddfSDavid du Colombier 		ecode = gs_error_rangecheck;
3627dd7cddfSDavid du Colombier 	    else if (qs.size >= sizeof(opdev->queue_name))
3637dd7cddfSDavid du Colombier 		ecode = gs_error_limitcheck;
3647dd7cddfSDavid du Colombier 	    else
3657dd7cddfSDavid du Colombier 		break;
3667dd7cddfSDavid du Colombier 	    goto qe;
3677dd7cddfSDavid du Colombier 	default:
3687dd7cddfSDavid du Colombier 	    ecode = code;
3697dd7cddfSDavid du Colombier 	  qe:param_signal_error(plist, "OS2QUEUE", ecode);
3707dd7cddfSDavid du Colombier 	case 1:
3717dd7cddfSDavid du Colombier 	    qs.data = 0;
3727dd7cddfSDavid du Colombier 	    break;
3737dd7cddfSDavid du Colombier     }
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier     switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
3767dd7cddfSDavid du Colombier 	case 0:
3777dd7cddfSDavid du Colombier 	    if (dev->is_open)
3787dd7cddfSDavid du Colombier 		ecode = gs_error_rangecheck;
3797dd7cddfSDavid du Colombier 	    else {		/* change dev->color_info is valid before device is opened */
3807dd7cddfSDavid du Colombier 		os2prn_set_bpp(dev, bpp);
3817dd7cddfSDavid du Colombier 		break;
3827dd7cddfSDavid du Colombier 	    }
3837dd7cddfSDavid du Colombier 	    goto bppe;
3847dd7cddfSDavid du Colombier 	default:
3857dd7cddfSDavid du Colombier 	    ecode = code;
3867dd7cddfSDavid du Colombier 	  bppe:param_signal_error(plist, "BitsPerPixel", ecode);
3877dd7cddfSDavid du Colombier 	case 1:
3887dd7cddfSDavid du Colombier 	    break;
3897dd7cddfSDavid du Colombier     }
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier     if (ecode >= 0)
3927dd7cddfSDavid du Colombier 	ecode = gdev_prn_put_params(dev, plist);
3937dd7cddfSDavid du Colombier 
3947dd7cddfSDavid du Colombier     if ((ecode >= 0) && (qs.data != 0)) {
3957dd7cddfSDavid du Colombier 	memcpy(opdev->queue_name, qs.data, qs.size);
3967dd7cddfSDavid du Colombier 	opdev->queue_name[qs.size] = 0;
3977dd7cddfSDavid du Colombier     }
3987dd7cddfSDavid du Colombier     return ecode;
3997dd7cddfSDavid du Colombier }
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 
4027dd7cddfSDavid du Colombier 
4037dd7cddfSDavid du Colombier /* ------ Internal routines ------ */
4047dd7cddfSDavid du Colombier 
4057dd7cddfSDavid du Colombier #undef opdev
4067dd7cddfSDavid du Colombier #define opdev ((gx_device_os2prn *)pdev)
4077dd7cddfSDavid du Colombier 
4087dd7cddfSDavid du Colombier /************************************************/
4097dd7cddfSDavid du Colombier 
4107dd7cddfSDavid du Colombier 
4117dd7cddfSDavid du Colombier /* ------ Private definitions ------ */
4127dd7cddfSDavid du Colombier 
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier /* new os2prn_print_page routine */
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier /* Write BMP header to memory, then send bitmap to printer */
4177dd7cddfSDavid du Colombier /* one scan line at a time */
4187dd7cddfSDavid du Colombier private int
4197dd7cddfSDavid du Colombier os2prn_print_page(gx_device_printer * pdev, FILE * file)
4207dd7cddfSDavid du Colombier {
4217dd7cddfSDavid du Colombier     int raster = gdev_prn_raster(pdev);
4227dd7cddfSDavid du Colombier 
4237dd7cddfSDavid du Colombier     /* BMP scan lines are padded to 32 bits. */
4247dd7cddfSDavid du Colombier     ulong bmp_raster = (raster + 3) & (~3);
4257dd7cddfSDavid du Colombier     ulong bmp_raster_multi;
4267dd7cddfSDavid du Colombier     int height = pdev->height;
4277dd7cddfSDavid du Colombier     int depth = pdev->color_info.depth;
4287dd7cddfSDavid du Colombier     byte *row;
4297dd7cddfSDavid du Colombier     int y;
4307dd7cddfSDavid du Colombier     int code = 0;		/* return code */
4317dd7cddfSDavid du Colombier     POINTL apts[4];
4327dd7cddfSDavid du Colombier     APIRET rc;
4337dd7cddfSDavid du Colombier     POINTL aptsb[4];
4347dd7cddfSDavid du Colombier     HBITMAP hbmp, hbmr;
4357dd7cddfSDavid du Colombier     int i, lines;
4367dd7cddfSDavid du Colombier     int ystart, yend;
4377dd7cddfSDavid du Colombier     int yslice;
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier     struct bmi_s {
4407dd7cddfSDavid du Colombier 	BITMAPINFOHEADER2 h;
4417dd7cddfSDavid du Colombier 	RGB2 pal[256];
4427dd7cddfSDavid du Colombier     } bmi;
4437dd7cddfSDavid du Colombier 
4447dd7cddfSDavid du Colombier     yslice = 65535 / bmp_raster;
4457dd7cddfSDavid du Colombier     bmp_raster_multi = bmp_raster * yslice;
4467dd7cddfSDavid du Colombier     row = (byte *) gs_malloc(bmp_raster_multi, 1, "bmp file buffer");
4477dd7cddfSDavid du Colombier     if (row == 0)		/* can't allocate row buffer */
4487dd7cddfSDavid du Colombier 	return_error(gs_error_VMerror);
4497dd7cddfSDavid du Colombier 
4507dd7cddfSDavid du Colombier     if (opdev->newframe)
4517dd7cddfSDavid du Colombier 	DevEscape(opdev->hdc, DEVESC_NEWFRAME, 0L, NULL, NULL, NULL);
4527dd7cddfSDavid du Colombier     opdev->newframe = 1;
4537dd7cddfSDavid du Colombier 
4547dd7cddfSDavid du Colombier     /* Write the info header. */
4557dd7cddfSDavid du Colombier 
4567dd7cddfSDavid du Colombier     memset(&bmi.h, 0, sizeof(bmi.h));
4577dd7cddfSDavid du Colombier     bmi.h.cbFix = sizeof(bmi.h);
4587dd7cddfSDavid du Colombier     bmi.h.cx = pdev->width;	/* opdev->mdev.width; */
4597dd7cddfSDavid du Colombier     /* bmi.h.cy = height; */
4607dd7cddfSDavid du Colombier     bmi.h.cy = yslice;		/* size for memory PS */
4617dd7cddfSDavid du Colombier     bmi.h.cPlanes = 1;
4627dd7cddfSDavid du Colombier     bmi.h.cBitCount = pdev->color_info.depth;
4637dd7cddfSDavid du Colombier 
4647dd7cddfSDavid du Colombier     /* Write the palette. */
4657dd7cddfSDavid du Colombier 
4667dd7cddfSDavid du Colombier     if (depth <= 8) {
4677dd7cddfSDavid du Colombier 	int i;
4687dd7cddfSDavid du Colombier 	gx_color_value rgb[3];
4697dd7cddfSDavid du Colombier 	PRGB2 pq;
4707dd7cddfSDavid du Colombier 
4717dd7cddfSDavid du Colombier 	bmi.h.cclrUsed = 1 << depth;
4727dd7cddfSDavid du Colombier 	bmi.h.cclrImportant = 1 << depth;
4737dd7cddfSDavid du Colombier 	for (i = 0; i != 1 << depth; i++) {
4747dd7cddfSDavid du Colombier 	    (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
4757dd7cddfSDavid du Colombier 					      (gx_color_index) i, rgb);
4767dd7cddfSDavid du Colombier 	    pq = &bmi.pal[i];
4777dd7cddfSDavid du Colombier 	    pq->bRed = gx_color_value_to_byte(rgb[0]);
4787dd7cddfSDavid du Colombier 	    pq->bGreen = gx_color_value_to_byte(rgb[1]);
4797dd7cddfSDavid du Colombier 	    pq->bBlue = gx_color_value_to_byte(rgb[2]);
4807dd7cddfSDavid du Colombier 	    pq->fcOptions = 0;
4817dd7cddfSDavid du Colombier 	}
4827dd7cddfSDavid du Colombier     } else {
4837dd7cddfSDavid du Colombier 	bmi.h.cclrUsed = 0;
4847dd7cddfSDavid du Colombier 	bmi.h.cclrImportant = 0;
4857dd7cddfSDavid du Colombier     }
4867dd7cddfSDavid du Colombier 
4877dd7cddfSDavid du Colombier     /* for GpiDrawBits */
4887dd7cddfSDavid du Colombier     /* target is inclusive */
4897dd7cddfSDavid du Colombier     apts[0].x = 0;
4907dd7cddfSDavid du Colombier     apts[0].y = 0;		/* filled in later */
4917dd7cddfSDavid du Colombier     apts[1].x = pdev->width - 1;
4927dd7cddfSDavid du Colombier     apts[1].y = 0;		/* filled in later */
4937dd7cddfSDavid du Colombier     /* source is not inclusive of top & right borders */
4947dd7cddfSDavid du Colombier     apts[2].x = 0;
4957dd7cddfSDavid du Colombier     apts[2].y = 0;
4967dd7cddfSDavid du Colombier     apts[3].x = pdev->width;
4977dd7cddfSDavid du Colombier     apts[3].y = 0;		/* filled in later */
4987dd7cddfSDavid du Colombier 
4997dd7cddfSDavid du Colombier     /* for GpiBitBlt */
5007dd7cddfSDavid du Colombier     /* target is not inclusive */
5017dd7cddfSDavid du Colombier     aptsb[0].x = opdev->clipbox[0];
5027dd7cddfSDavid du Colombier     aptsb[0].y = 0;		/* filled in later */
5037dd7cddfSDavid du Colombier     aptsb[1].x = opdev->clipbox[2];
5047dd7cddfSDavid du Colombier     aptsb[1].y = 0;		/* filled in later */
5057dd7cddfSDavid du Colombier     /* source is not inclusive */
5067dd7cddfSDavid du Colombier     aptsb[2].x = opdev->clipbox[0];
5077dd7cddfSDavid du Colombier     aptsb[2].y = 0;
5087dd7cddfSDavid du Colombier     aptsb[3].x = opdev->clipbox[2];
5097dd7cddfSDavid du Colombier     aptsb[3].y = 0;		/* filled in later */
5107dd7cddfSDavid du Colombier 
5117dd7cddfSDavid du Colombier     /* write the bits */
5127dd7cddfSDavid du Colombier     ystart = opdev->clipbox[3];
5137dd7cddfSDavid du Colombier     yend = opdev->clipbox[1];
5147dd7cddfSDavid du Colombier     y = ystart;
5157dd7cddfSDavid du Colombier     while (y > yend) {
5167dd7cddfSDavid du Colombier 	/* create a bitmap for the memory DC */
5177dd7cddfSDavid du Colombier 	hbmp = GpiCreateBitmap(opdev->hpsMem, &bmi.h, 0L, NULL, NULL);
5187dd7cddfSDavid du Colombier 	if (hbmp == GPI_ERROR)
5197dd7cddfSDavid du Colombier 	    goto bmp_done;
5207dd7cddfSDavid du Colombier 	hbmr = GpiSetBitmap(opdev->hpsMem, hbmp);
5217dd7cddfSDavid du Colombier 
5227dd7cddfSDavid du Colombier 	/* copy slice to memory bitmap */
5237dd7cddfSDavid du Colombier 	if (y > yend + yslice)
5247dd7cddfSDavid du Colombier 	    lines = yslice;
5257dd7cddfSDavid du Colombier 	else
5267dd7cddfSDavid du Colombier 	    lines = y - yend;
5277dd7cddfSDavid du Colombier 	y -= lines;
5287dd7cddfSDavid du Colombier 	for (i = lines - 1; i >= 0; i--)
5297dd7cddfSDavid du Colombier 	    gdev_prn_copy_scan_lines(pdev, ystart - 1 - (y + i), row + (bmp_raster * i), raster);
5307dd7cddfSDavid du Colombier 	apts[0].y = 0;		/* target */
5317dd7cddfSDavid du Colombier 	apts[1].y = lines;
5327dd7cddfSDavid du Colombier 	apts[3].y = lines - 1;	/* source */
5337dd7cddfSDavid du Colombier 	/* copy DIB bitmap to memory bitmap */
5347dd7cddfSDavid du Colombier 	rc = GpiDrawBits(opdev->hpsMem, row, (BITMAPINFO2 *) & bmi, 4, apts,
5357dd7cddfSDavid du Colombier 			 (depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
5367dd7cddfSDavid du Colombier 
5377dd7cddfSDavid du Colombier 	/* copy slice to printer */
5387dd7cddfSDavid du Colombier 	aptsb[0].y = y;
5397dd7cddfSDavid du Colombier 	aptsb[1].y = y + lines;
5407dd7cddfSDavid du Colombier 	aptsb[3].y = lines;
5417dd7cddfSDavid du Colombier 	rc = GpiBitBlt(opdev->hps, opdev->hpsMem, 4, aptsb, ROP_SRCCOPY, BBO_IGNORE);
5427dd7cddfSDavid du Colombier 
5437dd7cddfSDavid du Colombier 	/* delete bitmap */
5447dd7cddfSDavid du Colombier 	if (hbmr != HBM_ERROR)
5457dd7cddfSDavid du Colombier 	    GpiSetBitmap(opdev->hpsMem, (ULONG) 0);
5467dd7cddfSDavid du Colombier 	hbmr = HBM_ERROR;
5477dd7cddfSDavid du Colombier 	if (hbmp != GPI_ERROR)
5487dd7cddfSDavid du Colombier 	    GpiDeleteBitmap(hbmp);
5497dd7cddfSDavid du Colombier 	hbmp = GPI_ERROR;
5507dd7cddfSDavid du Colombier     }
5517dd7cddfSDavid du Colombier 
5527dd7cddfSDavid du Colombier   bmp_done:
5537dd7cddfSDavid du Colombier     if (row)
5547dd7cddfSDavid du Colombier 	gs_free((char *)row, bmp_raster_multi, 1, "bmp file buffer");
5557dd7cddfSDavid du Colombier 
5567dd7cddfSDavid du Colombier     return code;
5577dd7cddfSDavid du Colombier }
5587dd7cddfSDavid du Colombier 
5597dd7cddfSDavid du Colombier /* combined color mappers */
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier /* 24-bit color mappers (taken from gdevmem2.c). */
5627dd7cddfSDavid du Colombier /* Note that OS/2 expects RGB values in the order B,G,R. */
5637dd7cddfSDavid du Colombier 
5647dd7cddfSDavid du Colombier /* Map a r-g-b color to a color index. */
5657dd7cddfSDavid du Colombier private gx_color_index
5667dd7cddfSDavid du Colombier os2prn_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
5677dd7cddfSDavid du Colombier 		     gx_color_value b)
5687dd7cddfSDavid du Colombier {
5697dd7cddfSDavid du Colombier     switch (dev->color_info.depth) {
5707dd7cddfSDavid du Colombier 	case 1:
5717dd7cddfSDavid du Colombier 	    return gdev_prn_map_rgb_color(dev, r, g, b);
5727dd7cddfSDavid du Colombier 	case 4:
5737dd7cddfSDavid du Colombier 	    /* use only 8 colors */
5747dd7cddfSDavid du Colombier 	    return (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
5757dd7cddfSDavid du Colombier 		(g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
5767dd7cddfSDavid du Colombier 		(b > (gx_max_color_value / 2 + 1) ? 1 : 0);
5777dd7cddfSDavid du Colombier 	case 8:
5787dd7cddfSDavid du Colombier 	    return pc_8bit_map_rgb_color(dev, r, g, b);
5797dd7cddfSDavid du Colombier 	case 24:
5807dd7cddfSDavid du Colombier 	    return gx_color_value_to_byte(r) +
5817dd7cddfSDavid du Colombier 		((uint) gx_color_value_to_byte(g) << 8) +
5827dd7cddfSDavid du Colombier 		((ulong) gx_color_value_to_byte(b) << 16);
5837dd7cddfSDavid du Colombier     }
5847dd7cddfSDavid du Colombier     return 0;			/* error */
5857dd7cddfSDavid du Colombier }
5867dd7cddfSDavid du Colombier 
5877dd7cddfSDavid du Colombier /* Map a color index to a r-g-b color. */
5887dd7cddfSDavid du Colombier private int
5897dd7cddfSDavid du Colombier os2prn_map_color_rgb(gx_device * dev, gx_color_index color,
5907dd7cddfSDavid du Colombier 		     gx_color_value prgb[3])
5917dd7cddfSDavid du Colombier {
5927dd7cddfSDavid du Colombier     switch (dev->color_info.depth) {
5937dd7cddfSDavid du Colombier 	case 1:
5947dd7cddfSDavid du Colombier 	    gdev_prn_map_color_rgb(dev, color, prgb);
5957dd7cddfSDavid du Colombier 	    break;
5967dd7cddfSDavid du Colombier 	case 4:
5977dd7cddfSDavid du Colombier 	    /* use only 8 colors */
5987dd7cddfSDavid du Colombier 	    prgb[0] = (color & 4) ? gx_max_color_value : 0;
5997dd7cddfSDavid du Colombier 	    prgb[1] = (color & 2) ? gx_max_color_value : 0;
6007dd7cddfSDavid du Colombier 	    prgb[2] = (color & 1) ? gx_max_color_value : 0;
6017dd7cddfSDavid du Colombier 	    break;
6027dd7cddfSDavid du Colombier 	case 8:
6037dd7cddfSDavid du Colombier 	    pc_8bit_map_color_rgb(dev, color, prgb);
6047dd7cddfSDavid du Colombier 	    break;
6057dd7cddfSDavid du Colombier 	case 24:
6067dd7cddfSDavid du Colombier 	    prgb[2] = gx_color_value_from_byte(color >> 16);
6077dd7cddfSDavid du Colombier 	    prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
6087dd7cddfSDavid du Colombier 	    prgb[0] = gx_color_value_from_byte(color & 0xff);
6097dd7cddfSDavid du Colombier 	    break;
6107dd7cddfSDavid du Colombier     }
6117dd7cddfSDavid du Colombier     return 0;
6127dd7cddfSDavid du Colombier }
6137dd7cddfSDavid du Colombier 
6147dd7cddfSDavid du Colombier void
6157dd7cddfSDavid du Colombier os2prn_set_bpp(gx_device * dev, int depth)
6167dd7cddfSDavid du Colombier {
6177dd7cddfSDavid du Colombier     if (depth > 8) {
6187dd7cddfSDavid du Colombier 	static const gx_device_color_info os2prn_24color = dci_std_color(24);
6197dd7cddfSDavid du Colombier 
6207dd7cddfSDavid du Colombier 	dev->color_info = os2prn_24color;
6217dd7cddfSDavid du Colombier     } else if (depth >= 8) {
6227dd7cddfSDavid du Colombier 	/* 8-bit (SuperVGA-style) color. */
6237dd7cddfSDavid du Colombier 	/* (Uses a fixed palette of 3,3,2 bits.) */
6247dd7cddfSDavid du Colombier 	static const gx_device_color_info os2prn_8color = dci_pc_8bit;
6257dd7cddfSDavid du Colombier 
6267dd7cddfSDavid du Colombier 	dev->color_info = os2prn_8color;
6277dd7cddfSDavid du Colombier     } else if (depth >= 3) {
6287dd7cddfSDavid du Colombier 	/* 3 plane printer */
6297dd7cddfSDavid du Colombier 	/* suitable for impact dot matrix CMYK printers */
6307dd7cddfSDavid du Colombier 	/* create 4-bit bitmap, but only use 8 colors */
631*3ff48bf5SDavid du Colombier 	static const gx_device_color_info os2prn_4color = dci_values(3, 4, 1, 1, 2, 2);
6327dd7cddfSDavid du Colombier 
6337dd7cddfSDavid du Colombier 	dev->color_info = os2prn_4color;
6347dd7cddfSDavid du Colombier     } else {			/* default is black_and_white */
6357dd7cddfSDavid du Colombier 	static const gx_device_color_info os2prn_1color = dci_std_color(1);
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier 	dev->color_info = os2prn_1color;
6387dd7cddfSDavid du Colombier     }
6397dd7cddfSDavid du Colombier }
6407dd7cddfSDavid du Colombier 
6417dd7cddfSDavid du Colombier /* Get list of queues from SplEnumQueue */
6427dd7cddfSDavid du Colombier /* returns 0 if OK, non-zero for error */
6437dd7cddfSDavid du Colombier private int
6447dd7cddfSDavid du Colombier os2prn_get_queue_list(OS2QL * ql)
6457dd7cddfSDavid du Colombier {
6467dd7cddfSDavid du Colombier     SPLERR splerr;
6477dd7cddfSDavid du Colombier     USHORT jobCount;
6487dd7cddfSDavid du Colombier     ULONG cbBuf;
6497dd7cddfSDavid du Colombier     ULONG cTotal;
6507dd7cddfSDavid du Colombier     ULONG cReturned;
6517dd7cddfSDavid du Colombier     ULONG cbNeeded;
6527dd7cddfSDavid du Colombier     ULONG ulLevel;
6537dd7cddfSDavid du Colombier     ULONG i;
6547dd7cddfSDavid du Colombier     PSZ pszComputerName;
6557dd7cddfSDavid du Colombier     PBYTE pBuf;
6567dd7cddfSDavid du Colombier     PPRQINFO3 prq;
6577dd7cddfSDavid du Colombier 
6587dd7cddfSDavid du Colombier     ulLevel = 3L;
6597dd7cddfSDavid du Colombier     pszComputerName = (PSZ) NULL;
6607dd7cddfSDavid du Colombier     splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, 0L,	/* cbBuf */
6617dd7cddfSDavid du Colombier 			  &cReturned, &cTotal,
6627dd7cddfSDavid du Colombier 			  &cbNeeded, NULL);
6637dd7cddfSDavid du Colombier     if (splerr == ERROR_MORE_DATA || splerr == NERR_BufTooSmall) {
6647dd7cddfSDavid du Colombier 	pBuf = gs_malloc(cbNeeded, 1, "OS/2 printer device info buffer");
6657dd7cddfSDavid du Colombier 	ql->prq = (PRQINFO3 *) pBuf;
6667dd7cddfSDavid du Colombier 	if (ql->prq != (PRQINFO3 *) NULL) {
6677dd7cddfSDavid du Colombier 	    ql->len = cbNeeded;
6687dd7cddfSDavid du Colombier 	    cbBuf = cbNeeded;
6697dd7cddfSDavid du Colombier 	    splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, cbBuf,
6707dd7cddfSDavid du Colombier 				  &cReturned, &cTotal,
6717dd7cddfSDavid du Colombier 				  &cbNeeded, NULL);
6727dd7cddfSDavid du Colombier 	    if (splerr == NO_ERROR) {
6737dd7cddfSDavid du Colombier 		/* Set pointer to point to the beginning of the buffer.           */
6747dd7cddfSDavid du Colombier 		prq = (PPRQINFO3) pBuf;
6757dd7cddfSDavid du Colombier 		/* cReturned has the count of the number of PRQINFO3 structures.  */
6767dd7cddfSDavid du Colombier 		ql->nqueues = cReturned;
6777dd7cddfSDavid du Colombier 		ql->defqueue = 0;
6787dd7cddfSDavid du Colombier 		for (i = 0; i < cReturned; i++) {
6797dd7cddfSDavid du Colombier 		    if (prq->fsType & PRQ3_TYPE_APPDEFAULT)
6807dd7cddfSDavid du Colombier 			ql->defqueue = i;
6817dd7cddfSDavid du Colombier 		    prq++;
6827dd7cddfSDavid du Colombier 		}		/*endfor cReturned */
6837dd7cddfSDavid du Colombier 	    }
6847dd7cddfSDavid du Colombier 	}
6857dd7cddfSDavid du Colombier     } else {
6867dd7cddfSDavid du Colombier 	/* If we are here we had a bad error code. Print it and some other info. */
687*3ff48bf5SDavid du Colombier 	eprintf4("SplEnumQueue Error=%ld, Total=%ld, Returned=%ld, Needed=%ld\n",
6887dd7cddfSDavid du Colombier 		splerr, cTotal, cReturned, cbNeeded);
6897dd7cddfSDavid du Colombier     }
6907dd7cddfSDavid du Colombier     if (splerr)
6917dd7cddfSDavid du Colombier 	return splerr;
6927dd7cddfSDavid du Colombier     return 0;
6937dd7cddfSDavid du Colombier }
6947dd7cddfSDavid du Colombier 
6957dd7cddfSDavid du Colombier 
6967dd7cddfSDavid du Colombier private void
6977dd7cddfSDavid du Colombier os2prn_free_queue_list(OS2QL * ql)
6987dd7cddfSDavid du Colombier {
6997dd7cddfSDavid du Colombier     gs_free((char *)ql->prq, ql->len, 1, "os2prn queue list");
7007dd7cddfSDavid du Colombier     ql->prq = NULL;
7017dd7cddfSDavid du Colombier     ql->len = 0;
7027dd7cddfSDavid du Colombier     ql->defqueue = 0;
7037dd7cddfSDavid du Colombier     ql->nqueues = 0;
7047dd7cddfSDavid du Colombier }
705