Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/cmd/gs/src/dpmain.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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 
295
gsdll_stdin(void *instance, char *buf, int len)
296
{
297
    return read(fileno(stdin), buf, len);
298
}
299
 
300
static int 
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 
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 *
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 */
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
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
 
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 */
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
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
}