1 /* Copyright (C) 1996, 2001 Ghostgum Software Pty Ltd. 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
18 /* $Id: dpmain.c,v 1.12 2004/08/19 21:52:20 ghostgum Exp $ */
19 /* Ghostscript DLL loader for OS/2 */
20 /* For WINDOWCOMPAT (console mode) application */
21
22 /* Russell Lang 1996-06-05 */
23
24 /* Updated 2001-03-10 by rjl
25 * New DLL interface, uses display device.
26 * Uses same interface to gspmdrv.c as os2pm device.
27 */
28
29 #define INCL_DOS
30 #define INCL_DOSERRORS
31 #define INCL_WIN /* to get bits/pixel of display */
32 #define INCL_GPI /* to get bits/pixel of display */
33 #include <os2.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <time.h>
37 #include <io.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <sys/select.h>
41 #include "gscdefs.h"
42 #define GS_REVISION gs_revision
43 #include "ierrors.h"
44 #include "iapi.h"
45 #include "gdevdsp.h"
46
47 #define MAXSTR 256
48 #define BITMAPINFO2_SIZE 40
49 const char *szDllName = "GSDLL2.DLL";
50 char start_string[] = "systemdict /start get exec\n";
51 int debug = TRUE /* FALSE */;
52
53
54 #define MIN_COMMIT 4096 /* memory is committed in these size chunks */
55 #define ID_NAME "GSPMDRV_%u_%u"
56 #define SHARED_NAME "\\SHAREMEM\\%s"
57 #define SYNC_NAME "\\SEM32\\SYNC_%s"
58 #define MUTEX_NAME "\\SEM32\\MUTEX_%s"
59
60 LONG display_planes;
61 LONG display_bitcount;
62 LONG display_hasPalMan;
63 ULONG os_version;
64
65 /* main structure with info about the GS DLL */
66 typedef struct tagGSDLL {
67 HMODULE hmodule; /* DLL module handle */
68 PFN_gsapi_revision revision;
69 PFN_gsapi_new_instance new_instance;
70 PFN_gsapi_delete_instance delete_instance;
71 PFN_gsapi_set_stdio set_stdio;
72 PFN_gsapi_set_poll set_poll;
73 PFN_gsapi_set_display_callback set_display_callback;
74 PFN_gsapi_init_with_args init_with_args;
75 PFN_gsapi_run_string run_string;
76 PFN_gsapi_exit exit;
77 } GSDLL;
78
79 GSDLL gsdll;
80 void *instance;
81 TID tid;
82
83 void
gs_addmess(char * str)84 gs_addmess(char *str)
85 {
86 fputs(str, stdout);
87 fflush(stdout);
88 }
89
90 /*********************************************************************/
91 /* load and unload the Ghostscript DLL */
92
93 /* free GS DLL */
94 /* This should only be called when gsdll_execute has returned */
95 /* TRUE means no error */
96 BOOL
gs_free_dll(void)97 gs_free_dll(void)
98 {
99 char buf[MAXSTR];
100 APIRET rc;
101
102 if (gsdll.hmodule == (HMODULE) NULL)
103 return TRUE;
104 rc = DosFreeModule(gsdll.hmodule);
105 if (rc) {
106 sprintf(buf, "DosFreeModule returns %d\n", rc);
107 gs_addmess(buf);
108 sprintf(buf, "Unloaded GSDLL\n\n");
109 gs_addmess(buf);
110 }
111 return !rc;
112 }
113
114 void
gs_load_dll_cleanup(void)115 gs_load_dll_cleanup(void)
116 {
117 char buf[MAXSTR];
118
119 gs_free_dll();
120 }
121
122 /* load GS DLL if not already loaded */
123 /* return TRUE if OK */
124 BOOL
gs_load_dll(void)125 gs_load_dll(void)
126 {
127 char buf[MAXSTR + 40];
128 APIRET rc;
129 char *p;
130 int i;
131 const char *dllname;
132 PTIB pptib;
133 PPIB pppib;
134 char szExePath[MAXSTR];
135 char fullname[1024];
136 const char *shortname;
137 gsapi_revision_t rv;
138
139 if ((rc = DosGetInfoBlocks(&pptib, &pppib)) != 0) {
140 fprintf(stdout, "Couldn't get pid, rc = \n", rc);
141 return FALSE;
142 }
143 /* get path to EXE */
144 if ((rc = DosQueryModuleName(pppib->pib_hmte, sizeof(szExePath),
145 szExePath)) != 0) {
146 fprintf(stdout, "Couldn't get module name, rc = %d\n", rc);
147 return FALSE;
148 }
149 if ((p = strrchr(szExePath, '\\')) != (char *)NULL) {
150 p++;
151 *p = '\0';
152 }
153 dllname = szDllName;
154 #ifdef DEBUG
155 if (debug) {
156 sprintf(buf, "Trying to load %s\n", dllname);
157 gs_addmess(buf);
158 }
159 #endif
160 memset(buf, 0, sizeof(buf));
161 rc = DosLoadModule(buf, sizeof(buf), dllname, &gsdll.hmodule);
162 if (rc) {
163 /* failed */
164 /* try again, with path of EXE */
165 if ((shortname = strrchr((char *)szDllName, '\\'))
166 == (const char *)NULL)
167 shortname = szDllName;
168 strcpy(fullname, szExePath);
169 if ((p = strrchr(fullname, '\\')) != (char *)NULL)
170 p++;
171 else
172 p = fullname;
173 *p = '\0';
174 strcat(fullname, shortname);
175 dllname = fullname;
176 #ifdef DEBUG
177 if (debug) {
178 sprintf(buf, "Trying to load %s\n", dllname);
179 gs_addmess(buf);
180 }
181 #endif
182 rc = DosLoadModule(buf, sizeof(buf), dllname, &gsdll.hmodule);
183 if (rc) {
184 /* failed again */
185 /* try once more, this time on system search path */
186 dllname = shortname;
187 #ifdef DEBUG
188 if (debug) {
189 sprintf(buf, "Trying to load %s\n", dllname);
190 gs_addmess(buf);
191 }
192 #endif
193 rc = DosLoadModule(buf, sizeof(buf), dllname, &gsdll.hmodule);
194 }
195 }
196 if (rc == 0) {
197 #ifdef DEBUG
198 if (debug)
199 gs_addmess("Loaded Ghostscript DLL\n");
200 #endif
201 if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_REVISION",
202 (PFN *) (&gsdll.revision))) != 0) {
203 sprintf(buf, "Can't find GSAPI_REVISION, rc = %d\n", rc);
204 gs_addmess(buf);
205 gs_load_dll_cleanup();
206 return FALSE;
207 }
208 /* check DLL version */
209 if (gsdll.revision(&rv, sizeof(rv)) != 0) {
210 sprintf(buf, "Unable to identify Ghostscript DLL revision - it must be newer than needed.\n");
211 gs_addmess(buf);
212 gs_load_dll_cleanup();
213 return FALSE;
214 }
215
216 if (rv.revision != GS_REVISION) {
217 sprintf(buf, "Wrong version of DLL found.\n Found version %ld\n Need version %ld\n", rv.revision, (long)GS_REVISION);
218 gs_addmess(buf);
219 gs_load_dll_cleanup();
220 return FALSE;
221 }
222
223 if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_NEW_INSTANCE",
224 (PFN *) (&gsdll.new_instance))) != 0) {
225 sprintf(buf, "Can't find GSAPI_NEW_INSTANCE, rc = %d\n", rc);
226 gs_addmess(buf);
227 gs_load_dll_cleanup();
228 return FALSE;
229 }
230 if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_DELETE_INSTANCE",
231 (PFN *) (&gsdll.delete_instance))) != 0) {
232 sprintf(buf, "Can't find GSAPI_DELETE_INSTANCE, rc = %d\n", rc);
233 gs_addmess(buf);
234 gs_load_dll_cleanup();
235 return FALSE;
236 }
237 if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_SET_STDIO",
238 (PFN *) (&gsdll.set_stdio))) != 0) {
239 sprintf(buf, "Can't find GSAPI_SET_STDIO, rc = %d\n", rc);
240 gs_addmess(buf);
241 gs_load_dll_cleanup();
242 return FALSE;
243 }
244 if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_SET_DISPLAY_CALLBACK",
245 (PFN *) (&gsdll.set_display_callback))) != 0) {
246 sprintf(buf, "Can't find GSAPI_SET_DISPLAY_CALLBACK, rc = %d\n", rc);
247 gs_addmess(buf);
248 gs_load_dll_cleanup();
249 return FALSE;
250 }
251 if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_SET_POLL",
252 (PFN *) (&gsdll.set_poll))) != 0) {
253 sprintf(buf, "Can't find GSAPI_SET_POLL, rc = %d\n", rc);
254 gs_addmess(buf);
255 gs_load_dll_cleanup();
256 return FALSE;
257 }
258 if ((rc = DosQueryProcAddr(gsdll.hmodule, 0,
259 "GSAPI_INIT_WITH_ARGS",
260 (PFN *) (&gsdll.init_with_args))) != 0) {
261 sprintf(buf, "Can't find GSAPI_INIT_WITH_ARGS, rc = %d\n", rc);
262 gs_addmess(buf);
263 gs_load_dll_cleanup();
264 return FALSE;
265 }
266 if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_RUN_STRING",
267 (PFN *) (&gsdll.run_string))) != 0) {
268 sprintf(buf, "Can't find GSAPI_RUN_STRING, rc = %d\n", rc);
269 gs_addmess(buf);
270 gs_load_dll_cleanup();
271 return FALSE;
272 }
273 if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_EXIT",
274 (PFN *) (&gsdll.exit))) != 0) {
275 sprintf(buf, "Can't find GSAPI_EXIT, rc = %d\n", rc);
276 gs_addmess(buf);
277 gs_load_dll_cleanup();
278 return FALSE;
279 }
280 } else {
281 sprintf(buf, "Can't load Ghostscript DLL %s \nDosLoadModule rc = %d\n",
282 szDllName, rc);
283 gs_addmess(buf);
284 gs_load_dll_cleanup();
285 return FALSE;
286 }
287 return TRUE;
288 }
289
290
291 /*********************************************************************/
292 /* stdio functions */
293
294 static int
gsdll_stdin(void * instance,char * buf,int len)295 gsdll_stdin(void *instance, char *buf, int len)
296 {
297 return read(fileno(stdin), buf, len);
298 }
299
300 static int
gsdll_stdout(void * instance,const char * str,int len)301 gsdll_stdout(void *instance, const char *str, int len)
302 {
303 fwrite(str, 1, len, stdout);
304 fflush(stdout);
305 return len;
306 }
307
308 static int
gsdll_stderr(void * instance,const char * str,int len)309 gsdll_stderr(void *instance, const char *str, int len)
310 {
311 fwrite(str, 1, len, stderr);
312 fflush(stderr);
313 return len;
314 }
315
316 /*********************************************************************/
317 /* display device */
318
319 /*
320 #define DISPLAY_DEBUG
321 */
322
323 typedef struct IMAGE_S IMAGE;
324 struct IMAGE_S {
325 void *handle;
326 void *device;
327 PID pid; /* PID of our window (CMD.EXE) */
328 HEV sync_event; /* tell gspmdrv to redraw window */
329 HMTX bmp_mutex; /* protects access to bitmap */
330 HQUEUE term_queue; /* notification that gspmdrv has finished */
331 ULONG session_id; /* id of gspmdrv */
332 PID process_id; /* of gspmdrv */
333
334 int width;
335 int height;
336 int raster;
337 int format;
338
339 BOOL format_known;
340
341 unsigned char *bitmap;
342 ULONG committed;
343 IMAGE *next;
344 };
345
346 IMAGE *first_image = NULL;
347 static IMAGE *image_find(void *handle, void *device);
348
349 static IMAGE *
image_find(void * handle,void * device)350 image_find(void *handle, void *device)
351 {
352 IMAGE *img;
353 for (img = first_image; img!=0; img=img->next) {
354 if ((img->handle == handle) && (img->device == device))
355 return img;
356 }
357 return NULL;
358 }
359
360
361 /* start gspmdrv.exe */
run_gspmdrv(IMAGE * img)362 static int run_gspmdrv(IMAGE *img)
363 {
364 int ccode;
365 PCHAR pdrvname = "gspmdrv.exe";
366 CHAR error_message[256];
367 CHAR term_queue_name[128];
368 CHAR id[128];
369 CHAR arg[1024];
370 STARTDATA sdata;
371 APIRET rc;
372 PTIB pptib;
373 PPIB pppib;
374 CHAR progname[256];
375 PCHAR tail;
376
377 #ifdef DEBUG
378 if (debug)
379 fprintf(stdout, "run_gspmdrv: starting\n");
380 #endif
381 sprintf(id, ID_NAME, img->pid, (ULONG)img->device);
382
383 /* Create termination queue - used to find out when gspmdrv terminates */
384 sprintf(term_queue_name, "\\QUEUES\\TERMQ_%s", id);
385 if (DosCreateQueue(&(img->term_queue), QUE_FIFO, term_queue_name)) {
386 fprintf(stdout, "run_gspmdrv: failed to create termination queue\n");
387 return e_limitcheck;
388 }
389 /* get full path to gsos2.exe and hence path to gspmdrv.exe */
390 if ((rc = DosGetInfoBlocks(&pptib, &pppib)) != 0) {
391 fprintf(stdout, "run_gspmdrv: Couldn't get module handle, rc = %d\n",
392 rc);
393 return e_limitcheck;
394 }
395 if ((rc = DosQueryModuleName(pppib->pib_hmte, sizeof(progname) - 1,
396 progname)) != 0) {
397 fprintf(stdout, "run_gspmdrv: Couldn't get module name, rc = %d\n",
398 rc);
399 return e_limitcheck;
400 }
401 if ((tail = strrchr(progname, '\\')) != (PCHAR) NULL) {
402 tail++;
403 *tail = '\0';
404 } else
405 tail = progname;
406 strcat(progname, pdrvname);
407
408 /* Open the PM driver session gspmdrv.exe */
409 /* arguments are: */
410 /* (1) -d (display) option */
411 /* (2) id string */
412 sprintf(arg, "-d %s", id);
413
414 /* because gspmdrv.exe is a different EXE type to gs.exe,
415 * we must use start session not DosExecPgm() */
416 sdata.Length = sizeof(sdata);
417 sdata.Related = SSF_RELATED_CHILD; /* to be a child */
418 sdata.FgBg = SSF_FGBG_BACK; /* start in background */
419 sdata.TraceOpt = 0;
420 sdata.PgmTitle = "Ghostscript PM driver session";
421 sdata.PgmName = progname;
422 sdata.PgmInputs = arg;
423 sdata.TermQ = term_queue_name;
424 sdata.Environment = pppib->pib_pchenv; /* use Parent's environment */
425 sdata.InheritOpt = 0; /* Can't inherit from parent because */
426 /* different sesison type */
427 sdata.SessionType = SSF_TYPE_DEFAULT; /* default is PM */
428 sdata.IconFile = NULL;
429 sdata.PgmHandle = 0;
430 sdata.PgmControl = 0;
431 sdata.InitXPos = 0;
432 sdata.InitYPos = 0;
433 sdata.InitXSize = 0;
434 sdata.InitYSize = 0;
435 sdata.ObjectBuffer = error_message;
436 sdata.ObjectBuffLen = sizeof(error_message);
437
438 rc = DosStartSession(&sdata, &img->session_id, &img->process_id);
439 if (rc == ERROR_FILE_NOT_FOUND) {
440 sdata.PgmName = pdrvname;
441 rc = DosStartSession(&sdata, &img->session_id, &img->process_id);
442 }
443 if (rc) {
444 fprintf(stdout, "run_gspmdrv: failed to run %s, rc = %d\n",
445 sdata.PgmName, rc);
446 fprintf(stdout, "run_gspmdrv: error_message: %s\n", error_message);
447 return e_limitcheck;
448 }
449 #ifdef DEBUG
450 if (debug)
451 fprintf(stdout, "run_gspmdrv: returning\n");
452 #endif
453 return 0;
454 }
455
456 void
image_color(unsigned int format,int index,unsigned char * r,unsigned char * g,unsigned char * b)457 image_color(unsigned int format, int index,
458 unsigned char *r, unsigned char *g, unsigned char *b)
459 {
460 switch (format & DISPLAY_COLORS_MASK) {
461 case DISPLAY_COLORS_NATIVE:
462 switch (format & DISPLAY_DEPTH_MASK) {
463 case DISPLAY_DEPTH_1:
464 *r = *g = *b = (index ? 0 : 255);
465 break;
466 case DISPLAY_DEPTH_4:
467 if (index == 7)
468 *r = *g = *b = 170;
469 else if (index == 8)
470 *r = *g = *b = 85;
471 else {
472 int one = index & 8 ? 255 : 128;
473 *r = (index & 4 ? one : 0);
474 *g = (index & 2 ? one : 0);
475 *b = (index & 1 ? one : 0);
476 }
477 break;
478 case DISPLAY_DEPTH_8:
479 /* palette of 96 colors */
480 /* 0->63 = 00RRGGBB, 64->95 = 010YYYYY */
481 if (index < 64) {
482 int one = 255 / 3;
483 *r = ((index & 0x30) >> 4) * one;
484 *g = ((index & 0x0c) >> 2) * one;
485 *b = (index & 0x03) * one;
486 }
487 else {
488 int val = index & 0x1f;
489 *r = *g = *b = (val << 3) + (val >> 2);
490 }
491 break;
492 }
493 break;
494 case DISPLAY_COLORS_GRAY:
495 switch (format & DISPLAY_DEPTH_MASK) {
496 case DISPLAY_DEPTH_1:
497 *r = *g = *b = (index ? 255 : 0);
498 break;
499 case DISPLAY_DEPTH_4:
500 *r = *g = *b = (unsigned char)((index<<4) + index);
501 break;
502 case DISPLAY_DEPTH_8:
503 *r = *g = *b = (unsigned char)index;
504 break;
505 }
506 break;
507 }
508 }
509
510
image_palette_size(int format)511 static int image_palette_size(int format)
512 {
513 int palsize = 0;
514 switch (format & DISPLAY_COLORS_MASK) {
515 case DISPLAY_COLORS_NATIVE:
516 switch (format & DISPLAY_DEPTH_MASK) {
517 case DISPLAY_DEPTH_1:
518 palsize = 2;
519 break;
520 case DISPLAY_DEPTH_4:
521 palsize = 16;
522 break;
523 case DISPLAY_DEPTH_8:
524 palsize = 96;
525 break;
526 }
527 break;
528 case DISPLAY_COLORS_GRAY:
529 switch (format & DISPLAY_DEPTH_MASK) {
530 case DISPLAY_DEPTH_1:
531 palsize = 2;
532 break;
533 case DISPLAY_DEPTH_4:
534 palsize = 16;
535 break;
536 case DISPLAY_DEPTH_8:
537 palsize = 256;
538 break;
539 }
540 break;
541 }
542 return palsize;
543 }
544
545 /* New device has been opened */
546 /* Tell user to use another device */
display_open(void * handle,void * device)547 int display_open(void *handle, void *device)
548 {
549 APIRET rc;
550 IMAGE *img;
551 PTIB pptib;
552 PPIB pppib;
553 CHAR id[128];
554 CHAR name[128];
555 PBITMAPINFO2 bmi;
556
557 #ifdef DISPLAY_DEBUG
558 if (debug)
559 fputc('o', stdout);
560 fprintf(stdout, "display_open(0x%x, 0x%x)\n", handle, device);
561 #endif
562
563 if (first_image) {
564 /* gsos2.exe is a console application, and displays using
565 * gspmdrv.exe which is a PM application. To start
566 * gspmdrv.exe, DosStartSession is used with SSF_RELATED_CHILD.
567 * A process can have only one child session marked SSF_RELATED_CHILD.
568 * When we call DosStopSession for the second session, it will
569 * close, but it will not write to the termination queue.
570 * When we wait for the session to end by reading the
571 * termination queue, we wait forever.
572 * For this reason, multiple image windows are disabled
573 * for OS/2.
574 * To get around this, we would need to replace the current
575 * method of one gspmdrv.exe session per window, to having
576 * a new PM application which can display multiple windows
577 * within a single session.
578 */
579 return e_limitcheck;
580 }
581
582 img = (IMAGE *)malloc(sizeof(IMAGE));
583 if (img == NULL)
584 return e_limitcheck;
585 memset(img, 0, sizeof(IMAGE));
586
587 /* add to list */
588 img->next = first_image;
589 first_image = img;
590
591 /* remember device and handle */
592 img->handle = handle;
593 img->device = device;
594
595 /* Derive ID from process ID */
596 if (DosGetInfoBlocks(&pptib, &pppib)) {
597 fprintf(stdout, "\ndisplay_open: Couldn't get pid\n");
598 return e_limitcheck;
599 }
600 img->pid = pppib->pib_ulppid; /* use parent (CMD.EXE) pid */
601 sprintf(id, ID_NAME, img->pid, (ULONG) img->device);
602
603 /* Create update event semaphore */
604 sprintf(name, SYNC_NAME, id);
605 if (DosCreateEventSem(name, &(img->sync_event), 0, FALSE)) {
606 fprintf(stdout, "display_open: failed to create event semaphore %s\n", name);
607 return e_limitcheck;
608 }
609 /* Create mutex - used for preventing gspmdrv from accessing */
610 /* bitmap while we are changing the bitmap size. Initially unowned. */
611 sprintf(name, MUTEX_NAME, id);
612 if (DosCreateMutexSem(name, &(img->bmp_mutex), 0, FALSE)) {
613 DosCloseEventSem(img->sync_event);
614 fprintf(stdout, "display_open: failed to create mutex semaphore %s\n", name);
615 return e_limitcheck;
616 }
617
618 /* Shared memory is common to all processes so we don't want to
619 * allocate too much.
620 */
621 sprintf(name, SHARED_NAME, id);
622 if (DosAllocSharedMem((PPVOID) & img->bitmap, name,
623 13 * 1024 * 1024, PAG_READ | PAG_WRITE)) {
624 fprintf(stdout, "display_open: failed allocating shared BMP memory %s\n", name);
625 return e_limitcheck;
626 }
627
628 /* commit one page so there is enough storage for a */
629 /* bitmap header and palette */
630 if (DosSetMem(img->bitmap, MIN_COMMIT, PAG_COMMIT | PAG_DEFAULT)) {
631 DosFreeMem(img->bitmap);
632 fprintf(stdout, "display: failed committing BMP memory\n");
633 return e_limitcheck;
634 }
635 img->committed = MIN_COMMIT;
636
637 /* write a zero pixel BMP */
638 bmi = (PBITMAPINFO2) img->bitmap;
639 bmi->cbFix = BITMAPINFO2_SIZE; /* OS/2 2.0 and Windows 3.0 compatible */
640 bmi->cx = 0;
641 bmi->cy = 0;
642 bmi->cPlanes = 1;
643 bmi->cBitCount = 24;
644 bmi->ulCompression = BCA_UNCOMP;
645 bmi->cbImage = 0;
646 bmi->cxResolution = 0;
647 bmi->cyResolution = 0;
648 bmi->cclrUsed = 0;
649 bmi->cclrImportant = 0;
650
651 /* delay start of gspmdrv until size is known */
652
653 #ifdef DISPLAY_DEBUG
654 if (debug)
655 fputc('O', stdout);
656 #endif
657 return 0;
658 }
659
display_preclose(void * handle,void * device)660 int display_preclose(void *handle, void *device)
661 {
662 IMAGE *img;
663 REQUESTDATA Request;
664 ULONG DataLength;
665 PVOID DataAddress;
666 PULONG QueueEntry;
667 BYTE ElemPriority;
668 #ifdef DISPLAY_DEBUG
669 if (debug)
670 fputc('l', stdout);
671 fprintf(stdout, "display_preclose(0x%x, 0x%x)\n", handle, device);
672 #endif
673 img = image_find(handle, device);
674 if (img) {
675 if (img->session_id) {
676 /* Close gspmdrv driver */
677 DosStopSession(STOP_SESSION_SPECIFIED, img->session_id);
678 Request.pid = img->pid;
679 Request.ulData = 0;
680 /* wait for termination queue, queue is then closed */
681 /* by session manager */
682 DosReadQueue(img->term_queue, &Request, &DataLength,
683 &DataAddress, 0, DCWW_WAIT, &ElemPriority, (HEV) NULL);
684 /* queue needs to be closed by us */
685 DosCloseQueue(img->term_queue);
686 }
687 img->session_id = 0;
688 img->term_queue = 0;
689
690 DosCloseEventSem(img->sync_event);
691 DosCloseMutexSem(img->bmp_mutex);
692 }
693 #ifdef DISPLAY_DEBUG
694 if (debug)
695 fputc('L', stdout);
696 #endif
697 return 0;
698 }
699
display_close(void * handle,void * device)700 int display_close(void *handle, void *device)
701 {
702 IMAGE *img;
703 #ifdef DISPLAY_DEBUG
704 if (debug)
705 fputc('c', stdout);
706 fprintf(stdout, "display_close(0x%x, 0x%x)\n", handle, device);
707 #endif
708 img = image_find(handle, device);
709 if (img) {
710 /* gspmdrv was closed by display_preclose */
711 /* release memory */
712 DosFreeMem(img->bitmap);
713 img->bitmap = (unsigned char *)NULL;
714 img->committed = 0;
715 }
716 #ifdef DISPLAY_DEBUG
717 if (debug)
718 fputc('C', stdout);
719 #endif
720 return 0;
721 }
722
display_presize(void * handle,void * device,int width,int height,int raster,unsigned int format)723 int display_presize(void *handle, void *device, int width, int height,
724 int raster, unsigned int format)
725 {
726 IMAGE *img;
727 #ifdef DISPLAY_DEBUG
728 if (debug)
729 fputc('r', stdout);
730 fprintf(stdout, "display_presize(0x%x 0x%x, %d, %d, %d, %d)\n",
731 handle, device, width, height, raster, format);
732 #endif
733 img = image_find(handle, device);
734 if (img) {
735 int color = format & DISPLAY_COLORS_MASK;
736 int depth = format & DISPLAY_DEPTH_MASK;
737 int alpha = format & DISPLAY_ALPHA_MASK;
738 img->format_known = FALSE;
739 if ( ((color == DISPLAY_COLORS_NATIVE) ||
740 (color == DISPLAY_COLORS_GRAY))
741 &&
742 ((depth == DISPLAY_DEPTH_1) ||
743 (depth == DISPLAY_DEPTH_4) ||
744 (depth == DISPLAY_DEPTH_8)) )
745 img->format_known = TRUE;
746 if ((color == DISPLAY_COLORS_RGB) && (depth == DISPLAY_DEPTH_8) &&
747 (alpha == DISPLAY_ALPHA_NONE))
748 img->format_known = TRUE;
749 if (!img->format_known) {
750 fprintf(stdout, "display_presize: format %d = 0x%x is unsupported\n", format, format);
751 return e_limitcheck;
752 }
753 /* grab mutex to stop other thread using bitmap */
754 DosRequestMutexSem(img->bmp_mutex, 120000);
755 /* remember parameters so we can figure out where to allocate bitmap */
756 img->width = width;
757 img->height = height;
758 img->raster = raster;
759 img->format = format;
760 }
761 #ifdef DISPLAY_DEBUG
762 if (debug)
763 fputc('R', stdout);
764 #endif
765 return 0;
766 }
767
display_size(void * handle,void * device,int width,int height,int raster,unsigned int format,unsigned char * pimage)768 int display_size(void *handle, void *device, int width, int height,
769 int raster, unsigned int format, unsigned char *pimage)
770 {
771 IMAGE *img;
772 PBITMAPINFO2 bmi;
773 int nColors;
774 int i;
775 #ifdef DISPLAY_DEBUG
776 if (debug)
777 fputc('z', stdout);
778 fprintf(stdout, "display_size(0x%x 0x%x, %d, %d, %d, %d, %d, 0x%x)\n",
779 handle, device, width, height, raster, format, pimage);
780 #endif
781 img = image_find(handle, device);
782 if (img) {
783 if (!img->format_known)
784 return e_limitcheck;
785
786 img->width = width;
787 img->height = height;
788 img->raster = raster;
789 img->format = format;
790 /* write BMP header including palette */
791 bmi = (PBITMAPINFO2) img->bitmap;
792 bmi->cbFix = BITMAPINFO2_SIZE;
793 bmi->cx = img->width;
794 bmi->cy = img->height;
795 bmi->cPlanes = 1;
796 bmi->cBitCount = 24;
797 bmi->ulCompression = BCA_UNCOMP;
798 bmi->cbImage = 0;
799 bmi->cxResolution = 0;
800 bmi->cyResolution = 0;
801 bmi->cclrUsed = bmi->cclrImportant = image_palette_size(format);
802
803 switch (img->format & DISPLAY_DEPTH_MASK) {
804 default:
805 case DISPLAY_DEPTH_1:
806 bmi->cBitCount = 1;
807 break;
808 case DISPLAY_DEPTH_4:
809 bmi->cBitCount = 4;
810 break;
811 case DISPLAY_DEPTH_8:
812 if ((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_NATIVE)
813 bmi->cBitCount = 8;
814 else if ((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_GRAY)
815 bmi->cBitCount = 8;
816 else
817 bmi->cBitCount = 24;
818 break;
819 }
820
821 /* add palette if needed */
822 nColors = bmi->cclrUsed;
823 if (nColors) {
824 unsigned char *p;
825 p = img->bitmap + BITMAPINFO2_SIZE;
826 for (i = 0; i < nColors; i++) {
827 image_color(img->format, i, p+2, p+1, p);
828 *(p+3) = 0;
829 p += 4;
830 }
831 }
832
833 /* release mutex to allow other thread to use bitmap */
834 DosReleaseMutexSem(img->bmp_mutex);
835 }
836 #ifdef DISPLAY_DEBUG
837 if (debug) {
838 fprintf(stdout, "\nBMP dump\n");
839 fprintf(stdout, " bitmap=%lx\n", img->bitmap);
840 fprintf(stdout, " committed=%lx\n", img->committed);
841 fprintf(stdout, " cx=%d\n", bmi->cx);
842 fprintf(stdout, " cy=%d\n", bmi->cy);
843 fprintf(stdout, " cPlanes=%d\n", bmi->cPlanes);
844 fprintf(stdout, " cBitCount=%d\n", bmi->cBitCount);
845 fprintf(stdout, " ulCompression=%d\n", bmi->ulCompression);
846 fprintf(stdout, " cbImage=%d\n", bmi->cbImage);
847 fprintf(stdout, " cxResolution=%d\n", bmi->cxResolution);
848 fprintf(stdout, " cyResolution=%d\n", bmi->cyResolution);
849 fprintf(stdout, " cclrUsed=%d\n", bmi->cclrUsed);
850 fprintf(stdout, " cclrImportant=%d\n", bmi->cclrImportant);
851 }
852 if (debug)
853 fputc('Z', stdout);
854 #endif
855 return 0;
856 }
857
display_sync(void * handle,void * device)858 int display_sync(void *handle, void *device)
859 {
860 IMAGE *img;
861 #ifdef DISPLAY_DEBUG
862 if (debug)
863 fputc('s', stdout);
864 fprintf(stdout, "display_sync(0x%x, 0x%x)\n", handle, device);
865 #endif
866 img = image_find(handle, device);
867 if (img) {
868 if (!img->format_known)
869 return e_limitcheck;
870 /* delay starting gspmdrv until display_size has been called */
871 if (!img->session_id && (img->width != 0) && (img->height != 0))
872 run_gspmdrv(img);
873 DosPostEventSem(img->sync_event);
874 }
875 #ifdef DISPLAY_DEBUG
876 if (debug)
877 fputc('S', stdout);
878 #endif
879 return 0;
880 }
881
display_page(void * handle,void * device,int copies,int flush)882 int display_page(void *handle, void *device, int copies, int flush)
883 {
884 #ifdef DISPLAY_DEBUG
885 if (debug)
886 fputc('p', stdout);
887 fprintf(stdout, "display_page(0x%x, 0x%x, copies=%d, flush=%d)\n",
888 handle, device, copies, flush);
889 #endif
890 display_sync(handle, device);
891 #ifdef DISPLAY_DEBUG
892 if (debug)
893 fputc('P', stdout);
894 #endif
895 return 0;
896 }
897
display_memalloc(void * handle,void * device,unsigned long size)898 void *display_memalloc(void *handle, void *device, unsigned long size)
899 {
900 IMAGE *img;
901 unsigned long needed;
902 unsigned long header;
903 APIRET rc;
904 void *mem = NULL;
905
906 #ifdef DISPLAY_DEBUG
907 if (debug)
908 fputc('m', stdout);
909 fprintf(stdout, "display_memalloc(0x%x 0x%x %d)\n",
910 handle, device, size);
911 #endif
912 img = image_find(handle, device);
913 if (img) {
914 /* we don't actually allocate memory here, we only commit
915 * preallocated shared memory.
916 * First work out size of header + palette.
917 * We allocate space for the header and tell Ghostscript
918 * that the memory starts just after the header.
919 * We rely on the Ghostscript memory device placing the
920 * raster at the start of this memory and having a
921 * raster length the same as the length of a BMP row.
922 */
923 header = BITMAPINFO2_SIZE + image_palette_size(img->format) * 4;
924
925 /* Work out if we need to commit more */
926 needed = (size + header + MIN_COMMIT - 1) & (~(MIN_COMMIT - 1));
927 if (needed > img->committed) {
928 /* commit more memory */
929 if (rc = DosSetMem(img->bitmap + img->committed,
930 needed - img->committed,
931 PAG_COMMIT | PAG_DEFAULT)) {
932 fprintf(stdout, "No memory in display_memalloc rc = %d\n", rc);
933 return NULL;
934 }
935 img->committed = needed;
936 }
937 mem = img->bitmap + header;
938 }
939 #ifdef DISPLAY_DEBUG
940 fprintf(stdout, " returning 0x%x\n", (int)mem);
941 if (debug)
942 fputc('M', stdout);
943 #endif
944 return mem;
945 }
946
display_memfree(void * handle,void * device,void * mem)947 int display_memfree(void *handle, void *device, void *mem)
948 {
949 /* we can't uncommit shared memory, so do nothing */
950 /* memory will be released when device is closed */
951 #ifdef DISPLAY_DEBUG
952 fprintf(stdout, "display_memfree(0x%x, 0x%x, 0x%x)\n",
953 handle, device, mem);
954 #endif
955 }
956
display_update(void * handle,void * device,int x,int y,int w,int h)957 int display_update(void *handle, void *device,
958 int x, int y, int w, int h)
959 {
960 /* unneeded - we are running image window in a separate process */
961 return 0;
962 }
963
964
965 display_callback display = {
966 sizeof(display_callback),
967 DISPLAY_VERSION_MAJOR,
968 DISPLAY_VERSION_MINOR,
969 display_open,
970 display_preclose,
971 display_close,
972 display_presize,
973 display_size,
974 display_sync,
975 display_page,
976 display_update,
977 display_memalloc,
978 display_memfree
979 };
980
981
982 /*********************************************************************/
983
984
985 int
main(int argc,char * argv[])986 main(int argc, char *argv[])
987 {
988 int code, code1;
989 int exit_code;
990 int exit_status;
991 int nargc;
992 char **nargv;
993 char dformat[64];
994 ULONG version[3];
995 void *instance;
996
997 if (DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_REVISION,
998 &version, sizeof(version)))
999 os_version = 201000; /* a guess */
1000 else
1001 os_version = version[0] * 10000 + version[1] * 100 + version[2];
1002
1003 if (!gs_load_dll()) {
1004 fprintf(stdout, "Can't load %s\n", szDllName);
1005 return -1;
1006 }
1007
1008 /* insert -dDisplayFormat=XXXXX as first argument */
1009 { int format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
1010 DISPLAY_DEPTH_1 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
1011 int depth;
1012 HPS ps = WinGetPS(HWND_DESKTOP);
1013 HDC hdc = GpiQueryDevice(ps);
1014 DevQueryCaps(hdc, CAPS_COLOR_PLANES, 1, &display_planes);
1015 DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1, &display_bitcount);
1016 DevQueryCaps(hdc, CAPS_ADDITIONAL_GRAPHICS, 1, &display_hasPalMan);
1017 display_hasPalMan &= CAPS_PALETTE_MANAGER;
1018 depth = display_planes * display_bitcount;
1019 if ((depth <= 8) && !display_hasPalMan)
1020 depth = 24; /* disaster: limited colours and no palette */
1021 WinReleasePS(ps);
1022
1023 if (depth > 8)
1024 format = DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE |
1025 DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
1026 else if (depth >= 8)
1027 format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
1028 DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
1029 else if (depth >= 4)
1030 format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
1031 DISPLAY_DEPTH_4 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
1032 sprintf(dformat, "-dDisplayFormat=%d", format);
1033 }
1034 nargc = argc + 1;
1035
1036
1037 #ifdef DEBUG
1038 if (debug)
1039 fprintf(stdout, "%s\n", dformat);
1040 #endif
1041 nargc = argc + 1;
1042 nargv = (char **)malloc((nargc + 1) * sizeof(char *));
1043 nargv[0] = argv[0];
1044 nargv[1] = dformat;
1045 memcpy(&nargv[2], &argv[1], argc * sizeof(char *));
1046
1047 if ( (code = gsdll.new_instance(&instance, NULL)) == 0) {
1048 gsdll.set_stdio(instance, gsdll_stdin, gsdll_stdout, gsdll_stderr);
1049 gsdll.set_display_callback(instance, &display);
1050
1051 code = gsdll.init_with_args(instance, nargc, nargv);
1052 if (code == 0)
1053 code = gsdll.run_string(instance, start_string, 0, &exit_code);
1054 code1 = gsdll.exit(instance);
1055 if (code == 0 || (code == e_Quit && code1 != 0))
1056 code = code1;
1057
1058 gsdll.delete_instance(instance);
1059 }
1060
1061 gs_free_dll();
1062
1063 free(nargv);
1064
1065 exit_status = 0;
1066 switch (code) {
1067 case 0:
1068 case e_Info:
1069 case e_Quit:
1070 break;
1071 case e_Fatal:
1072 exit_status = 1;
1073 break;
1074 default:
1075 exit_status = 255;
1076 }
1077
1078 return exit_status;
1079 }
1080