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