1 /* Copyright (C) 1996-2004 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: dwmainc.c,v 1.24 2004/09/15 19:41:01 ray Exp $ */
18 /* dwmainc.c */
19
20 #include "windows_.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <io.h>
24 #include <fcntl.h>
25 #include <process.h>
26 #include "ierrors.h"
27 #include "iapi.h"
28 #include "vdtrace.h"
29 #include "gdevdsp.h"
30 #include "dwdll.h"
31 #include "dwimg.h"
32 #include "dwtrace.h"
33
34 /* Patch by Rod Webster (rodw) */
35 /* Added conditional below to allow Borland Compilation (Tested on 5.5) */
36 /* It would be better to place this code in an include file but no dwmainc.h exists */
37 #ifdef __BORLANDC__
38 #define _isatty isatty
39 #define _setmode setmode
40 #endif
41
42 GSDLL gsdll;
43 void *instance;
44 BOOL quitnow = FALSE;
45 HANDLE hthread;
46 DWORD thread_id;
47 HWND hwndtext = NULL; /* for dwimg.c, but not used */
48 HWND hwndforeground; /* our best guess for our console window handle */
49
50 char start_string[] = "systemdict /start get exec\n";
51
52 /*********************************************************************/
53 /* stdio functions */
54
55 static int GSDLLCALL
gsdll_stdin(void * instance,char * buf,int len)56 gsdll_stdin(void *instance, char *buf, int len)
57 {
58 return _read(fileno(stdin), buf, len);
59 }
60
61 static int GSDLLCALL
gsdll_stdout(void * instance,const char * str,int len)62 gsdll_stdout(void *instance, const char *str, int len)
63 {
64 fwrite(str, 1, len, stdout);
65 fflush(stdout);
66 return len;
67 }
68
69 static int GSDLLCALL
gsdll_stderr(void * instance,const char * str,int len)70 gsdll_stderr(void *instance, const char *str, int len)
71 {
72 fwrite(str, 1, len, stderr);
73 fflush(stderr);
74 return len;
75 }
76
77 /*********************************************************************/
78 /* dll device */
79
80 /* We must run windows from another thread, since main thread */
81 /* is running Ghostscript and blocks on stdin. */
82
83 /* We notify second thread of events using PostThreadMessage()
84 * with the following messages. Apparently Japanese Windows sends
85 * WM_USER+1 with lParam == 0 and crashes. So we use WM_USER+101.
86 * Fix from Akira Kakuto
87 */
88 #define DISPLAY_OPEN WM_USER+101
89 #define DISPLAY_CLOSE WM_USER+102
90 #define DISPLAY_SIZE WM_USER+103
91 #define DISPLAY_SYNC WM_USER+104
92 #define DISPLAY_PAGE WM_USER+105
93 #define DISPLAY_UPDATE WM_USER+106
94
95 /*
96 #define DISPLAY_DEBUG
97 */
98
99 /* The second thread is the message loop */
winthread(void * arg)100 static void winthread(void *arg)
101 {
102 MSG msg;
103 thread_id = GetCurrentThreadId();
104 hthread = GetCurrentThread();
105
106 while (!quitnow && GetMessage(&msg, (HWND)NULL, 0, 0)) {
107 switch (msg.message) {
108 case DISPLAY_OPEN:
109 image_open((IMAGE *)msg.lParam);
110 break;
111 case DISPLAY_CLOSE:
112 {
113 IMAGE *img = (IMAGE *)msg.lParam;
114 HANDLE hmutex = img->hmutex;
115 image_close(img);
116 CloseHandle(hmutex);
117 }
118 break;
119 case DISPLAY_SIZE:
120 image_updatesize((IMAGE *)msg.lParam);
121 break;
122 case DISPLAY_SYNC:
123 image_sync((IMAGE *)msg.lParam);
124 break;
125 case DISPLAY_PAGE:
126 image_page((IMAGE *)msg.lParam);
127 break;
128 case DISPLAY_UPDATE:
129 image_poll((IMAGE *)msg.lParam);
130 break;
131 default:
132 TranslateMessage(&msg);
133 DispatchMessage(&msg);
134 }
135 }
136 }
137
138
139 /* New device has been opened */
140 /* Tell user to use another device */
display_open(void * handle,void * device)141 int display_open(void *handle, void *device)
142 {
143 IMAGE *img;
144 #ifdef DISPLAY_DEBUG
145 fprintf(stdout, "display_open(0x%x, 0x%x)\n", handle, device);
146 #endif
147 img = image_new(handle, device); /* create and add to list */
148 img->hmutex = CreateMutex(NULL, FALSE, NULL);
149 if (img)
150 PostThreadMessage(thread_id, DISPLAY_OPEN, 0, (LPARAM)img);
151 return 0;
152 }
153
display_preclose(void * handle,void * device)154 int display_preclose(void *handle, void *device)
155 {
156 IMAGE *img;
157 #ifdef DISPLAY_DEBUG
158 fprintf(stdout, "display_preclose(0x%x, 0x%x)\n", handle, device);
159 #endif
160 img = image_find(handle, device);
161 if (img) {
162 /* grab mutex to stop other thread using bitmap */
163 WaitForSingleObject(img->hmutex, 120000);
164 }
165 return 0;
166 }
167
display_close(void * handle,void * device)168 int display_close(void *handle, void *device)
169 {
170 IMAGE *img;
171 #ifdef DISPLAY_DEBUG
172 fprintf(stdout, "display_close(0x%x, 0x%x)\n", handle, device);
173 #endif
174 img = image_find(handle, device);
175 if (img) {
176 /* This is a hack to pass focus from image window to console */
177 if (GetForegroundWindow() == img->hwnd)
178 SetForegroundWindow(hwndforeground);
179
180 image_delete(img); /* remove from list, but don't free */
181 PostThreadMessage(thread_id, DISPLAY_CLOSE, 0, (LPARAM)img);
182 }
183 return 0;
184 }
185
display_presize(void * handle,void * device,int width,int height,int raster,unsigned int format)186 int display_presize(void *handle, void *device, int width, int height,
187 int raster, unsigned int format)
188 {
189 IMAGE *img;
190 #ifdef DISPLAY_DEBUG
191 fprintf(stdout, "display_presize(0x%x 0x%x, %d, %d, %d, %d, %ld)\n",
192 handle, device, width, height, raster, format);
193 #endif
194 img = image_find(handle, device);
195 if (img) {
196 /* grab mutex to stop other thread using bitmap */
197 WaitForSingleObject(img->hmutex, 120000);
198 }
199 return 0;
200 }
201
display_size(void * handle,void * device,int width,int height,int raster,unsigned int format,unsigned char * pimage)202 int display_size(void *handle, void *device, int width, int height,
203 int raster, unsigned int format, unsigned char *pimage)
204 {
205 IMAGE *img;
206 #ifdef DISPLAY_DEBUG
207 fprintf(stdout, "display_size(0x%x 0x%x, %d, %d, %d, %d, %ld, 0x%x)\n",
208 handle, device, width, height, raster, format, pimage);
209 #endif
210 img = image_find(handle, device);
211 if (img) {
212 image_size(img, width, height, raster, format, pimage);
213 /* release mutex to allow other thread to use bitmap */
214 ReleaseMutex(img->hmutex);
215 PostThreadMessage(thread_id, DISPLAY_SIZE, 0, (LPARAM)img);
216 }
217 return 0;
218 }
219
display_sync(void * handle,void * device)220 int display_sync(void *handle, void *device)
221 {
222 IMAGE *img;
223 #ifdef DISPLAY_DEBUG
224 fprintf(stdout, "display_sync(0x%x, 0x%x)\n", handle, device);
225 #endif
226 img = image_find(handle, device);
227 if (img && !img->pending_sync) {
228 img->pending_sync = 1;
229 PostThreadMessage(thread_id, DISPLAY_SYNC, 0, (LPARAM)img);
230 }
231 return 0;
232 }
233
display_page(void * handle,void * device,int copies,int flush)234 int display_page(void *handle, void *device, int copies, int flush)
235 {
236 IMAGE *img;
237 #ifdef DISPLAY_DEBUG
238 fprintf(stdout, "display_page(0x%x, 0x%x, copies=%d, flush=%d)\n",
239 handle, device, copies, flush);
240 #endif
241 img = image_find(handle, device);
242 if (img)
243 PostThreadMessage(thread_id, DISPLAY_PAGE, 0, (LPARAM)img);
244 return 0;
245 }
246
display_update(void * handle,void * device,int x,int y,int w,int h)247 int display_update(void *handle, void *device,
248 int x, int y, int w, int h)
249 {
250 IMAGE *img;
251 img = image_find(handle, device);
252 if (img && !img->pending_update && !img->pending_sync) {
253 img->pending_update = 1;
254 PostThreadMessage(thread_id, DISPLAY_UPDATE, 0, (LPARAM)img);
255 }
256 return 0;
257 }
258
259 /*
260 #define DISPLAY_DEBUG_USE_ALLOC
261 */
262 #ifdef DISPLAY_DEBUG_USE_ALLOC
263 /* This code isn't used, but shows how to use this function */
display_memalloc(void * handle,void * device,unsigned long size)264 void *display_memalloc(void *handle, void *device, unsigned long size)
265 {
266 void *mem;
267 #ifdef DISPLAY_DEBUG
268 fprintf(stdout, "display_memalloc(0x%x 0x%x %d)\n",
269 handle, device, size);
270 #endif
271 mem = malloc(size);
272 #ifdef DISPLAY_DEBUG
273 fprintf(stdout, " returning 0x%x\n", (int)mem);
274 #endif
275 return mem;
276 }
277
display_memfree(void * handle,void * device,void * mem)278 int display_memfree(void *handle, void *device, void *mem)
279 {
280 #ifdef DISPLAY_DEBUG
281 fprintf(stdout, "display_memfree(0x%x, 0x%x, 0x%x)\n",
282 handle, device, mem);
283 #endif
284 free(mem);
285 return 0;
286 }
287 #endif
288
display_separation(void * handle,void * device,int comp_num,const char * name,unsigned short c,unsigned short m,unsigned short y,unsigned short k)289 int display_separation(void *handle, void *device,
290 int comp_num, const char *name,
291 unsigned short c, unsigned short m,
292 unsigned short y, unsigned short k)
293 {
294 IMAGE *img;
295 #ifdef DISPLAY_DEBUG
296 fprintf(stdout, "display_separation(0x%x, 0x%x, %d '%s' %d,%d,%d,%d)\n",
297 handle, device, comp_num, name, (int)c, (int)m, (int)y, (int)k);
298 #endif
299 img = image_find(handle, device);
300 if (img)
301 image_separation(img, comp_num, name, c, m, y, k);
302 return 0;
303 }
304
305
306 display_callback display = {
307 sizeof(display_callback),
308 DISPLAY_VERSION_MAJOR,
309 DISPLAY_VERSION_MINOR,
310 display_open,
311 display_preclose,
312 display_close,
313 display_presize,
314 display_size,
315 display_sync,
316 display_page,
317 display_update,
318 #ifdef DISPLAY_DEBUG_USE_ALLOC
319 display_memalloc, /* memalloc */
320 display_memfree, /* memfree */
321 #else
322 NULL, /* memalloc */
323 NULL, /* memfree */
324 #endif
325 display_separation
326 };
327
328
329 /*********************************************************************/
330
main(int argc,char * argv[])331 int main(int argc, char *argv[])
332 {
333 int code, code1;
334 int exit_code;
335 int exit_status;
336 int nargc;
337 char **nargv;
338 char buf[256];
339 char dformat[64];
340 char ddpi[64];
341
342 if (!_isatty(fileno(stdin)))
343 _setmode(fileno(stdin), _O_BINARY);
344 _setmode(fileno(stdout), _O_BINARY);
345 _setmode(fileno(stderr), _O_BINARY);
346
347 hwndforeground = GetForegroundWindow(); /* assume this is ours */
348 memset(buf, 0, sizeof(buf));
349 if (load_dll(&gsdll, buf, sizeof(buf))) {
350 fprintf(stderr, "Can't load Ghostscript DLL\n");
351 fprintf(stderr, "%s\n", buf);
352 return 1;
353 }
354
355 if (gsdll.new_instance(&instance, NULL) < 0) {
356 fprintf(stderr, "Can't create Ghostscript instance\n");
357 return 1;
358 }
359
360 #ifdef DEBUG
361 visual_tracer_init();
362 gsdll.set_visual_tracer(&visual_tracer);
363 #endif
364
365 if (_beginthread(winthread, 65535, NULL) == -1) {
366 fprintf(stderr, "GUI thread creation failed\n");
367 }
368 else {
369 int n = 30;
370 /* wait for thread to start */
371 Sleep(0);
372 while (n && (hthread == INVALID_HANDLE_VALUE)) {
373 n--;
374 Sleep(100);
375 }
376 while (n && (PostThreadMessage(thread_id, WM_USER, 0, 0) == 0)) {
377 n--;
378 Sleep(100);
379 }
380 if (n == 0)
381 fprintf(stderr, "Can't post message to GUI thread\n");
382 }
383
384 gsdll.set_stdio(instance, gsdll_stdin, gsdll_stdout, gsdll_stderr);
385 gsdll.set_display_callback(instance, &display);
386
387 { int format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
388 DISPLAY_DEPTH_1 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
389 HDC hdc = GetDC(NULL); /* get hdc for desktop */
390 int depth = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
391 sprintf(ddpi, "-dDisplayResolution=%d", GetDeviceCaps(hdc, LOGPIXELSY));
392 ReleaseDC(NULL, hdc);
393 if (depth == 32)
394 format = DISPLAY_COLORS_RGB | DISPLAY_UNUSED_LAST |
395 DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
396 else if (depth == 16)
397 format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
398 DISPLAY_DEPTH_16 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST |
399 DISPLAY_NATIVE_555;
400 else if (depth > 8)
401 format = DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE |
402 DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
403 else if (depth >= 8)
404 format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
405 DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
406 else if (depth >= 4)
407 format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
408 DISPLAY_DEPTH_4 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
409 sprintf(dformat, "-dDisplayFormat=%d", format);
410 }
411 nargc = argc + 2;
412 nargv = (char **)malloc((nargc + 1) * sizeof(char *));
413 nargv[0] = argv[0];
414 nargv[1] = dformat;
415 nargv[2] = ddpi;
416 memcpy(&nargv[3], &argv[1], argc * sizeof(char *));
417
418 #if defined(_MSC_VER) || defined(__BORLANDC__)
419 __try {
420 #endif
421 code = gsdll.init_with_args(instance, nargc, nargv);
422 if (code == 0)
423 code = gsdll.run_string(instance, start_string, 0, &exit_code);
424 code1 = gsdll.exit(instance);
425 if (code == 0 || (code == e_Quit && code1 != 0))
426 code = code1;
427 #if defined(_MSC_VER) || defined(__BORLANDC__)
428 } __except(exception_code() == EXCEPTION_STACK_OVERFLOW) {
429 code = e_Fatal;
430 fprintf(stderr, "*** C stack overflow. Quiting...\n");
431 }
432 #endif
433
434 gsdll.delete_instance(instance);
435
436 #ifdef DEBUG
437 visual_tracer_close();
438 #endif
439
440 unload_dll(&gsdll);
441
442 free(nargv);
443
444 /* close other thread */
445 quitnow = TRUE;
446 PostThreadMessage(thread_id, WM_QUIT, 0, (LPARAM)0);
447 Sleep(0);
448
449 exit_status = 0;
450 switch (code) {
451 case 0:
452 case e_Info:
453 case e_Quit:
454 break;
455 case e_Fatal:
456 exit_status = 1;
457 break;
458 default:
459 exit_status = 255;
460 }
461
462
463 return exit_status;
464 }
465
466