xref: /plan9/sys/src/cmd/gs/src/dwmain.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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 /* $Id: dwmain.c,v 1.21 2004/09/15 19:41:01 ray Exp $ */
18 /* Ghostscript DLL loader for Windows */
19 
20 #include "windows_.h"
21 #include <shellapi.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include "gscdefs.h"
26 #define GSREVISION gs_revision
27 #include "ierrors.h"
28 #include "iapi.h"
29 #include "vdtrace.h"
30 
31 #include "dwmain.h"
32 #include "dwdll.h"
33 #include "dwtext.h"
34 #include "dwimg.h"
35 #include "dwtrace.h"
36 #include "dwreg.h"
37 #include "gdevdsp.h"
38 
39 /* public handles */
40 HINSTANCE ghInstance;
41 
42 /* redirected stdio */
43 TW *tw;
44 
45 static const LPSTR szAppName = "Ghostscript";
46 
47 const LPSTR szIniName = "gswin32.ini";
48 const char *szDllName = "gsdll32.dll";
49 const LPSTR szIniSection = "Text";
50 
51 
52 GSDLL gsdll;
53 void *instance;
54 HWND hwndtext;
55 
56 char start_string[] = "systemdict /start get exec\n";
57 
poll(void)58 static int poll(void)
59 {
60     MSG msg;
61     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
62 	TranslateMessage(&msg);
63 	DispatchMessage(&msg);
64     }
65     /* If text window closing then abort Ghostscript */
66     if (tw->quitnow)
67 	return e_Fatal;
68     return 0;
69 }
70 
71 /*********************************************************************/
72 /* stdio functions */
73 static int GSDLLCALL
gsdll_stdin(void * instance,char * buf,int len)74 gsdll_stdin(void *instance, char *buf, int len)
75 {
76     return text_read_line(tw, buf, len);
77 }
78 
79 static int GSDLLCALL
gsdll_stdout(void * instance,const char * str,int len)80 gsdll_stdout(void *instance, const char *str, int len)
81 {
82     text_write_buf(tw, str, len);
83     return len;
84 }
85 
86 static int GSDLLCALL
gsdll_stderr(void * instance,const char * str,int len)87 gsdll_stderr(void *instance, const char *str, int len)
88 {
89     text_write_buf(tw, str, len);
90     return len;
91 }
92 
93 /* Poll the caller for cooperative multitasking. */
94 /* If this function is NULL, polling is not needed */
gsdll_poll(void * handle)95 static int GSDLLCALL gsdll_poll(void *handle)
96 {
97     return poll();
98 }
99 /*********************************************************************/
100 
101 /* new dll display device */
102 /*
103 #define DISPLAY_DEBUG
104  */
105 
106 /* New device has been opened */
107 /* This is the first event from this device. */
display_open(void * handle,void * device)108 static int display_open(void *handle, void *device)
109 {
110     IMAGE *img;
111 #ifdef DISPLAY_DEBUG
112     char buf[256];
113     sprintf(buf, "display_open(0x%x, 0x%x)\n", handle, device);
114     text_puts(tw, buf);
115 #endif
116     img = image_new(handle, device);	/* create and add to list */
117     if (img)
118         image_open(img);
119     return 0;
120 }
121 
122 /* Device is about to be closed. */
123 /* Device will not be closed until this function returns. */
display_preclose(void * handle,void * device)124 static int display_preclose(void *handle, void *device)
125 {
126 #ifdef DISPLAY_DEBUG
127     char buf[256];
128     sprintf(buf, "display_preclose(0x%x, 0x$x)\n", handle, device);
129     text_puts(tw, buf);
130 #endif
131     /* do nothing - no thread synchonisation needed */
132     return 0;
133 }
134 
135 /* Device has been closed. */
136 /* This is the last event from this device. */
display_close(void * handle,void * device)137 static int display_close(void *handle, void *device)
138 {
139     IMAGE *img;
140 #ifdef DISPLAY_DEBUG
141     char buf[256];
142     sprintf(buf, "display_close(0x%x, 0x$x)\n", handle, device);
143     text_puts(tw, buf);
144 #endif
145     img = image_find(handle, device);
146     if (img) {
147 	image_delete(img);	/* remove from list but don't free */
148 	image_close(img);
149     }
150     return 0;
151 }
152 
153 /* Device is about to be resized. */
154 /* Resize will only occur if this function returns 0. */
display_presize(void * handle,void * device,int width,int height,int raster,unsigned int format)155 static int display_presize(void *handle, void *device, int width, int height,
156 	int raster, unsigned int format)
157 {
158 #ifdef DISPLAY_DEBUG
159     char buf[256];
160     sprintf(buf, "display_presize(0x%x, 0x%x, width=%d height=%d raster=%d\n\
161   format=%d)\n",
162        handle, device, width, height, raster, format);
163     text_puts(tw, buf);
164 #endif
165     return 0;
166 }
167 
168 /* Device has been resized. */
169 /* New pointer to raster returned in pimage */
display_size(void * handle,void * device,int width,int height,int raster,unsigned int format,unsigned char * pimage)170 static int display_size(void *handle, void *device, int width, int height,
171 	int raster, unsigned int format, unsigned char *pimage)
172 {
173     IMAGE *img;
174 #ifdef DISPLAY_DEBUG
175     char buf[256];
176     sprintf(buf, "display_size(0x%x, 0x%x, width=%d height=%d raster=%d\n\
177   format=%d image=0x%x)\n",
178        handle, device, width, height, raster, format, pimage);
179     text_puts(tw, buf);
180 #endif
181     img = image_find(handle, device);
182     image_size(img, width, height, raster, format, pimage);
183     image_updatesize(img);
184     return 0;
185 }
186 
187 /* flushpage */
display_sync(void * handle,void * device)188 static int display_sync(void *handle, void *device)
189 {
190     IMAGE *img;
191 #ifdef DISPLAY_DEBUG
192     char buf[256];
193     sprintf(buf, "display_sync(0x%x, 0x%x)\n", handle, device);
194     text_puts(tw, buf);
195 #endif
196     img = image_find(handle, device);
197     image_sync(img);
198     return 0;
199 }
200 
201 /* showpage */
202 /* If you want to pause on showpage, then don't return immediately */
display_page(void * handle,void * device,int copies,int flush)203 static int display_page(void *handle, void *device, int copies, int flush)
204 {
205     IMAGE *img;
206 #ifdef DISPLAY_DEBUG
207     char buf[256];
208     sprintf(buf, "display_page(0x%x, 0x%x, copies=%d flush=%d)\n",
209 	handle, device, copies, flush);
210     text_puts(tw, buf);
211 #endif
212     img = image_find(handle, device);
213     image_page(img);
214     return 0;
215 }
216 
217 /* Poll the caller for cooperative multitasking. */
218 /* If this function is NULL, polling is not needed */
display_update(void * handle,void * device,int x,int y,int w,int h)219 static int display_update(void *handle, void *device,
220     int x, int y, int w, int h)
221 {
222     IMAGE *img;
223     img = image_find(handle, device);
224     image_poll(img);	/* redraw the window periodically */
225     return poll();
226 }
227 
display_separation(void * handle,void * device,int comp_num,const char * name,unsigned short c,unsigned short m,unsigned short y,unsigned short k)228 int display_separation(void *handle, void *device,
229    int comp_num, const char *name,
230    unsigned short c, unsigned short m,
231    unsigned short y, unsigned short k)
232 {
233     IMAGE *img;
234 #ifdef DISPLAY_DEBUG
235     fprintf(stdout, "display_separation(0x%x, 0x%x, %d '%s' %d,%d,%d,%d)\n",
236 	handle, device, comp_num, name, (int)c, (int)m, (int)y, (int)k);
237 #endif
238     img = image_find(handle, device);
239     if (img)
240         image_separation(img, comp_num, name, c, m, y, k);
241     return 0;
242 }
243 
244 display_callback display = {
245     sizeof(display_callback),
246     DISPLAY_VERSION_MAJOR,
247     DISPLAY_VERSION_MINOR,
248     display_open,
249     display_preclose,
250     display_close,
251     display_presize,
252     display_size,
253     display_sync,
254     display_page,
255     display_update,
256     NULL,	/* memalloc */
257     NULL,	/* memfree */
258     display_separation
259 };
260 
261 
262 /*********************************************************************/
263 
264 /* program really starts at WinMain */
new_main(int argc,char * argv[])265 int new_main(int argc, char *argv[])
266 {
267     int code, code1;
268     int exit_status;
269     int exit_code;
270     int nargc;
271     char **nargv;
272     char dformat[64];
273     char ddpi[64];
274     char buf[256];
275 
276     memset(buf, 0, sizeof(buf));
277     if (load_dll(&gsdll, buf, sizeof(buf))) {
278 	text_puts(tw, "Can't load Ghostscript DLL\n");
279 	text_puts(tw, buf);
280 	text_puts(tw, "\n");
281 	return 1;
282     }
283 
284     if (gsdll.new_instance(&instance, NULL) < 0) {
285 	text_puts(tw, "Can't create Ghostscript instance\n");
286 	return 1;
287     }
288 
289 #ifdef DEBUG
290     visual_tracer_init();
291     gsdll.set_visual_tracer(&visual_tracer);
292 #endif
293 
294     gsdll.set_stdio(instance, gsdll_stdin, gsdll_stdout, gsdll_stderr);
295     gsdll.set_poll(instance, gsdll_poll);
296     gsdll.set_display_callback(instance, &display);
297 
298     /* insert display device defaults as first arguments */
299     {   int format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
300 		DISPLAY_DEPTH_1 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
301 	HDC hdc = GetDC(NULL);	/* get hdc for desktop */
302 	int depth = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
303 	sprintf(ddpi, "-dDisplayResolution=%d", GetDeviceCaps(hdc, LOGPIXELSY));
304         ReleaseDC(NULL, hdc);
305 	if (depth == 32)
306  	    format = DISPLAY_COLORS_RGB | DISPLAY_UNUSED_LAST |
307 		DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
308 	else if (depth == 16)
309  	    format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
310 		DISPLAY_DEPTH_16 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST |
311 		DISPLAY_NATIVE_555;
312 	else if (depth > 8)
313  	    format = DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE |
314 		DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
315 	else if (depth >= 8)
316  	    format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
317 		DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
318 	else if (depth >= 4)
319  	    format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
320 		DISPLAY_DEPTH_4 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
321         sprintf(dformat, "-dDisplayFormat=%d", format);
322     }
323     nargc = argc + 2;
324     nargv = (char **)malloc((nargc + 1) * sizeof(char *));
325     nargv[0] = argv[0];
326     nargv[1] = dformat;
327     nargv[2] = ddpi;
328     memcpy(&nargv[3], &argv[1], argc * sizeof(char *));
329 
330 #if defined(_MSC_VER) || defined(__BORLANDC__)
331     __try {
332 #endif
333     code = gsdll.init_with_args(instance, nargc, nargv);
334     if (code == 0)
335 	code = gsdll.run_string(instance, start_string, 0, &exit_code);
336     code1 = gsdll.exit(instance);
337     if (code == 0 || (code == e_Quit && code1 != 0))
338 	code = code1;
339 #if defined(_MSC_VER) || defined(__BORLANDC__)
340     } __except(exception_code() == EXCEPTION_STACK_OVERFLOW) {
341         code = e_Fatal;
342         text_puts(tw, "*** C stack overflow. Quiting...\n");
343     }
344 #endif
345 
346     gsdll.delete_instance(instance);
347 
348 #ifdef DEBUG
349     visual_tracer_close();
350 #endif
351 
352     unload_dll(&gsdll);
353 
354     free(nargv);
355 
356     exit_status = 0;
357     switch (code) {
358 	case 0:
359 	case e_Quit:
360 	    break;
361 	case e_Fatal:
362 	    exit_status = 1;
363 	    break;
364 	case e_Info:
365 	default:
366 	    exit_status = 255;
367     }
368 
369     return exit_status;
370 }
371 
372 
373 
374 void
set_font(void)375 set_font(void)
376 {
377     int fontsize;
378     char fontname[256];
379     char buf[32];
380 
381     /* read ini file */
382     GetPrivateProfileString(szIniSection, "FontName", "Courier New", fontname, sizeof(fontname), szIniName);
383     fontsize = GetPrivateProfileInt(szIniSection, "FontSize", 10, szIniName);
384 
385     /* set font */
386     text_font(tw, fontname, fontsize);
387 
388     /* write ini file */
389     WritePrivateProfileString(szIniSection, "FontName", fontname, szIniName);
390     sprintf(buf, "%d", fontsize);
391     WritePrivateProfileString(szIniSection, "FontSize", buf, szIniName);
392 }
393 
394 int PASCAL
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int cmdShow)395 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
396 {
397     int dll_exit_status;
398 #define MAXCMDTOKENS 128
399     /* BC++ 4.5 will give us _argc and _argv[], but they will be */
400     /* incorrect if there is a space in the program name. */
401     /* Provide our own parsing code to create argc and argv[]. */
402     int argc;
403     LPSTR argv[MAXCMDTOKENS];
404     LPSTR p;
405     char command[256];
406     char *args;
407     char *d, *e;
408     char winposbuf[256];
409     int len = sizeof(winposbuf);
410     int x, y, cx, cy;
411 
412     /* copy the hInstance into a variable so it can be used */
413     ghInstance = hInstance;
414 
415     if (hPrevInstance) {
416 	MessageBox((HWND)NULL,"Can't run twice", szAppName,
417 		MB_ICONHAND | MB_OK);
418 	return FALSE;
419     }
420 
421     /* If called with "gswin32c.exe arg1 arg2"
422      * lpszCmdLine returns:
423      *    "arg1 arg2" if called with CreateProcess(NULL, command, ...)
424      *    "arg2"      if called with CreateProcess(command, args, ...)
425      * GetCommandLine() returns
426      *    ""gswin32c.exe" arg1 arg2"
427      *          if called with CreateProcess(NULL, command, ...)
428      *    "  arg1 arg2"
429      *          if called with CreateProcess(command, args, ...)
430      * Consequently we must use GetCommandLine()
431      */
432     p = GetCommandLine();
433 
434     argc = 0;
435     args = (char *)malloc(lstrlen(p)+1);
436     if (args == (char *)NULL) {
437 	fprintf(stdout, "Insufficient memory in WinMain()\n");
438 	return 1;
439     }
440 
441     /* Parse command line handling quotes. */
442     d = args;
443     while (*p) {
444 	/* for each argument */
445 
446 	if (argc >= MAXCMDTOKENS - 1)
447 	    break;
448 
449         e = d;
450         while ((*p) && (*p != ' ')) {
451 	    if (*p == '\042') {
452 		/* Remove quotes, skipping over embedded spaces. */
453 		/* Doesn't handle embedded quotes. */
454 		p++;
455 		while ((*p) && (*p != '\042'))
456 		    *d++ =*p++;
457 	    }
458 	    else
459 		*d++ = *p;
460 	    if (*p)
461 		p++;
462         }
463 	*d++ = '\0';
464 	argv[argc++] = e;
465 
466 	while ((*p) && (*p == ' '))
467 	    p++;	/* Skip over trailing spaces */
468     }
469     argv[argc] = NULL;
470 
471     if (strlen(argv[0]) == 0) {
472 	GetModuleFileName(hInstance, command, sizeof(command)-1);
473 	argv[0] = command;
474     }
475 
476 
477     tw = text_new();
478     if (tw == NULL) {
479 	MessageBox((HWND)NULL, "Can't create text window",
480 		szAppName, MB_OK | MB_ICONSTOP);
481  	return 1;
482     }
483 
484     /* start up the text window */
485     if (!hPrevInstance) {
486 	HICON hicon = LoadIcon(hInstance, (LPSTR)MAKEINTRESOURCE(GSTEXT_ICON));
487 	text_register_class(tw, hicon);
488     }
489     set_font();
490     text_size(tw, 80, 80);
491     text_drag(tw, "(", ") run\r");
492     if (win_get_reg_value("Text", winposbuf, &len) == 0) {
493 	if (sscanf(winposbuf, "%d %d %d %d", &x, &y, &cx, &cy) == 4)
494 	    text_setpos(tw, x, y, cx, cy);
495     }
496 
497     /* create the text window */
498     if (text_create(tw, szAppName, cmdShow))
499 	exit(1);
500 
501     hwndtext = text_get_handle(tw);
502 
503     dll_exit_status = new_main(argc, argv);
504 
505     if (dll_exit_status && !tw->quitnow) {
506 	/* display error message in text window */
507 	MSG msg;
508 	text_puts(tw, "\nClose this window with the close button on the title bar or the system menu.\n");
509 	if (IsIconic(text_get_handle(tw)))
510 	    ShowWindow(text_get_handle(tw), SW_SHOWNORMAL);
511 	BringWindowToTop(text_get_handle(tw));  /* make text window visible */
512 	FlashWindow(text_get_handle(tw), TRUE);
513 	/* Wait until error message is read */
514 	while (!tw->quitnow && GetMessage(&msg, (HWND)NULL, 0, 0)) {
515 	    TranslateMessage(&msg);
516 	    DispatchMessage(&msg);
517 	}
518     }
519 
520     /* Save the text window size */
521     if (text_getpos(tw, &x, &y, &cx, &cy) == 0) {
522 	sprintf(winposbuf, "%d %d %d %d", x, y, cx, cy);
523 	win_set_reg_value("Text", winposbuf);
524     }
525 
526     text_destroy(tw);
527     tw = NULL;
528 
529     return dll_exit_status;
530 }
531 
532 
533 
534