1 /*----------------------------------------------------------------------*/
2 /* render.c --- Ghostscript rendering of background PostScript files */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /* These routines work only if ghostscript is on the system. */
5 /*----------------------------------------------------------------------*/
6
7 #undef GS_DEBUG
8 /* #define GS_DEBUG */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #ifndef XC_WIN32
14 #include <termios.h>
15 #include <unistd.h>
16 #endif
17 #include <time.h>
18 #ifndef XC_WIN32
19 #include <sys/wait.h> /* for waitpid() */
20 #endif
21 #include <sys/types.h>
22 #include <signal.h>
23 #include <fcntl.h>
24
25 #ifndef XC_WIN32
26 #include <X11/Intrinsic.h>
27 #include <X11/StringDefs.h>
28 #include <X11/Xatom.h>
29 #else
30 #ifdef TCL_WRAPPER
31 #include <X11/Xatom.h>
32 #endif
33 #endif
34
35 /*------------------------------------------------------------------------*/
36 /* Local includes */
37 /*------------------------------------------------------------------------*/
38
39 #ifdef TCL_WRAPPER
40 #include <tk.h>
41 #endif
42
43 #include "colordefs.h"
44 #include "xcircuit.h"
45
46 /*----------------------------------------------------------------------*/
47 /* Function prototype declarations */
48 /*----------------------------------------------------------------------*/
49 #include "prototypes.h"
50
51 /*------------------------------------------------------------------------*/
52 /* External Variable definitions */
53 /*------------------------------------------------------------------------*/
54
55 extern char _STR2[250], _STR[150];
56 extern Globaldata xobjs;
57 extern XCWindowData *areawin;
58 extern Display *dpy;
59 extern int number_colors;
60 extern colorindex *colorlist;
61 extern Cursor appcursors[NUM_CURSORS];
62
63 #ifdef HAVE_CAIRO
64 cairo_surface_t *bbuf = NULL;
65 #else /* HAVE_CAIRO */
66 Pixmap bbuf = (Pixmap)NULL; /* background buffer */
67 extern Pixmap dbuf;
68 #endif /* HAVE_CAIRO */
69
70 #ifndef HAVE_VFORK
71 #define vfork fork
72 #endif
73
74 gs_state_t gs_state; /* Track state of the renderer */
75
76 /*------------------------------------------------------*/
77 /* Global variable definitions */
78 /*------------------------------------------------------*/
79
80 #ifndef HAVE_CAIRO
81 Atom gv, gvc, gvpage, gvnext, gvdone;
82 #ifndef _MSC_VER
83 pid_t gsproc = -1; /* ghostscript process */
84 #else
85 HANDLE gsproc = INVALID_HANDLE_VALUE;
86 #endif
87 int fgs[2]; /* stdin pipe pair for ghostscript */
88 Window mwin = 0; /* "false" window hack to get gs */
89 /* process to capture ClientMessage */
90 /* events. */
91 #endif /* HAVE_CAIRO */
92
93 /*--------------------------------------------------------------*/
94 /* Preliminary in allowing generic PostScript backgrounds */
95 /* via the ghostscript interpreter: Set the GHOSTVIEW and */
96 /* GHOSTVIEW atoms, and set the GHOSTVIEW environtment */
97 /* variable. */
98 /*--------------------------------------------------------------*/
99
ghostinit_local()100 void ghostinit_local()
101 {
102 #ifndef HAVE_CAIRO
103 sprintf(_STR, "%ld %d %d %d %d %d %g %g %d %d %d %d",
104 0L, 0, 0, 0,
105 areawin->width * 75 / 72,
106 areawin->height * 75 / 72,
107 75.0, 75.0, 0, 0, 0, 0);
108 XChangeProperty(dpy, areawin->window, gv, XA_STRING, 8, PropModeReplace,
109 _STR, strlen(_STR));
110 sprintf(_STR, "%s %d %d", "Color", (int)FOREGROUND, (int)BACKGROUND);
111 XChangeProperty(dpy, areawin->window, gvc, XA_STRING, 8, PropModeReplace,
112 _STR, strlen(_STR));
113 XSync(dpy, False);
114 #endif /* HAVE_CAIRO */
115
116 gs_state = GS_INIT;
117 }
118
119 /*------------------------------------------------------*/
120 /* Client message handler. Called by either the Tk */
121 /* client message handler (see below) or the Xt handler */
122 /* (see xcircuit.c). */
123 /* */
124 /* Returns True if a client message was received from */
125 /* the ghostscript process, False if not. */
126 /*------------------------------------------------------*/
127
render_client(XEvent * eventPtr)128 Boolean render_client(XEvent *eventPtr)
129 {
130 #ifndef HAVE_CAIRO
131 if (eventPtr->xclient.message_type == gvpage) {
132 #ifdef GS_DEBUG
133 fprintf(stdout, "Xcircuit: Received PAGE message from ghostscript\n");
134 #endif
135 mwin = eventPtr->xclient.data.l[0];
136 Wprintf("Background finished.");
137 XDefineCursor(dpy, areawin->window, DEFAULTCURSOR);
138
139 /* Mark this as the most recently rendered background, so we don't */
140 /* have to render more than necessary. */
141 areawin->lastbackground = xobjs.pagelist[areawin->page]->background.name;
142 gs_state = GS_READY;
143 drawarea(areawin->area, NULL, NULL);
144 }
145 else if (eventPtr->xclient.message_type == gvdone) {
146 #ifdef GS_DEBUG
147 fprintf(stdout, "Xcircuit: Received DONE message from ghostscript\n");
148 #endif
149 mwin = 0;
150 gs_state = GS_INIT;
151 }
152 else {
153 char *atomname;
154
155 atomname = XGetAtomName(dpy, eventPtr->xclient.message_type);
156 if (atomname != NULL) {
157 fprintf(stderr, "Received client message using atom \"%s\"\n", atomname);
158 XFree(atomname);
159 }
160 return False;
161 }
162 #endif /* HAVE_CAIRO */
163 return True;
164 }
165
166 /*------------------------------------------------------*/
167 /* Tk client handler procedure for the above routine. */
168 /*------------------------------------------------------*/
169
170 #ifdef TCL_WRAPPER
171
172 #ifndef HAVE_CAIRO
handle_client(ClientData clientData,XEvent * eventPtr)173 void handle_client(ClientData clientData, XEvent *eventPtr)
174 {
175 if (render_client(eventPtr) == False)
176 fprintf(stderr, "Xcircuit: Received unknown client message\n");
177 }
178 #endif /* HAVE_CAIRO */
179
180 #endif
181
182 /*------------------------------------------------------*/
183 /* Global initialization */
184 /*------------------------------------------------------*/
185
ghostinit()186 void ghostinit()
187 {
188 #ifndef HAVE_CAIRO
189 if (areawin->area == NULL) return;
190
191 gv = XInternAtom(dpy, "GHOSTVIEW", False);
192 gvc = XInternAtom(dpy, "GHOSTVIEW_COLORS", False);
193 gvpage = XInternAtom(dpy, "PAGE", False);
194 gvnext = XInternAtom(dpy, "NEXT", False);
195 gvdone = XInternAtom(dpy, "DONE", False);
196
197 ghostinit_local();
198
199 #ifdef TCL_WRAPPER
200 Tk_CreateClientMessageHandler((Tk_ClientMessageProc *)handle_client);
201 #endif
202 #endif /* HAVE_CAIRO */
203 }
204
205 /*------------------------------------------------------*/
206 /* Send a ClientMessage event */
207 /*------------------------------------------------------*/
208
209 #ifndef HAVE_CAIRO
send_client(Atom msg)210 void send_client(Atom msg)
211 {
212 XEvent event;
213
214 if (mwin == 0) return; /* Have to wait for gs */
215 /* to give us window # */
216
217 event.xclient.type = ClientMessage;
218 event.xclient.display = dpy;
219 event.xclient.window = areawin->window;
220 event.xclient.message_type = msg;
221 event.xclient.format = 32;
222 event.xclient.data.l[0] = mwin;
223 event.xclient.data.l[1] = bbuf;
224 XSendEvent(dpy, mwin, False, 0, &event);
225 XFlush(dpy);
226 }
227 #endif /* HAVE_CAIRO */
228
229 /*------------------------------------------------------*/
230 /* Ask ghostscript to produce the next page. */
231 /*------------------------------------------------------*/
232
ask_for_next()233 void ask_for_next()
234 {
235 #ifndef HAVE_CAIRO
236 if (gs_state != GS_READY) {
237 /* If we're in the middle of rendering something, halt */
238 /* immediately and start over. */
239 if (gs_state == GS_PENDING)
240 reset_gs();
241 return;
242 }
243 XSync(dpy, False);
244 gs_state = GS_PENDING;
245 send_client(gvnext);
246 #ifdef GS_DEBUG
247 fprintf(stdout, "Xcircuit: Sent NEXT message to ghostscript\n");
248 #endif
249 #endif /* HAVE_CAIRO */
250 }
251
252 /*--------------------------------------------------------*/
253 /* Start a ghostscript process and arrange the I/O pipes */
254 /* (Commented lines cause ghostscript to relay its stderr */
255 /* to xcircuit's stderr) */
256 /*--------------------------------------------------------*/
257
258 #ifndef HAVE_CAIRO
start_gs()259 void start_gs()
260 {
261 int std_out[2], std_err[2], ret;
262 #ifdef XC_WIN32
263 unsigned int pipe_size = 8196;
264 int pipe_mode = _O_BINARY;
265 #endif
266 #ifdef HAVE_PUTENV
267 static char env_str1[128], env_str2[64];
268 #endif
269
270 #ifdef TCL_WRAPPER
271 if (bbuf != (Pixmap)NULL) Tk_FreePixmap(dpy, bbuf);
272 bbuf = Tk_GetPixmap(dpy, dbuf, areawin->width, areawin->height,
273 Tk_Depth(areawin->area));
274 #else /* !TCL_WRAPPER */
275 if (bbuf != (Pixmap)NULL) XFreePixmap(dpy, bbuf);
276 bbuf = XCreatePixmap(dpy, dbuf, areawin->width, areawin->height,
277 DefaultDepthOfScreen(xcScreen(areawin->area)));
278 #endif /* TCL_WRAPPER */
279
280 XSync(dpy, False);
281
282 #ifndef XC_WIN32
283 ret = pipe(fgs);
284 ret = pipe(std_out);
285 #else
286 ret = _pipe(fgs, pipe_size, pipe_mode);
287 ret = _pipe(std_out, pipe_size, pipe_mode);
288 #endif
289 #ifndef GS_DEBUG
290 #ifndef XC_WIN32
291 ret = pipe(std_err);
292 #else
293 ret = _pipe(std_err, pipe_size, pipe_mode);
294 #endif /* XC_WIN32 */
295 #endif
296
297 /* We need a complicated pipe here, with input going from xcircuit */
298 /* to gs to provide scale/position information, and input going from */
299 /* the background file to gs for rendering. */
300 /* Here is not the place to do it. Set up gs to take stdin as input.*/
301
302 #ifdef _MSC_VER
303 if (gsproc == INVALID_HANDLE_VALUE) {
304 STARTUPINFO st_info;
305 PROCESS_INFORMATION pr_info;
306 char cmd[4096];
307
308 #ifdef HAVE_PUTENV
309 sprintf(env_str1, "DISPLAY=%s", XDisplayString(dpy));
310 putenv(env_str1);
311 sprintf(env_str2, "GHOSTVIEW=%ld %ld", (long)areawin->window, (long)bbuf);
312 putenv(env_str2);
313 #else
314 setenv("DISPLAY", XDisplayString(dpy), True);
315 sprintf(_STR, "%ld %ld", (long)areastruct.areawin, (long)bbuf);
316 setenv("GHOSTVIEW", _STR, True);
317 #endif
318
319 SetHandleInformation((HANDLE)_get_osfhandle(fgs[1]), HANDLE_FLAG_INHERIT, 0);
320 SetHandleInformation((HANDLE)_get_osfhandle(std_out[0]), HANDLE_FLAG_INHERIT, 0);
321 #ifndef GS_DEBUG
322 SetHandleInformation((HANDLE)_get_osfhandle(std_err[0]), HANDLE_FLAG_INHERIT, 0);
323 #endif
324
325 ZeroMemory(&st_info, sizeof(STARTUPINFO));
326 ZeroMemory(&pr_info, sizeof(PROCESS_INFORMATION));
327 st_info.cb = sizeof(STARTUPINFO);
328 st_info.dwFlags = STARTF_USESTDHANDLES;
329 st_info.hStdOutput = (HANDLE)_get_osfhandle(std_out[1]);
330 st_info.hStdInput = (HANDLE)_get_osfhandle(fgs[0]);
331 #ifndef GS_DEBUG
332 st_info.hStdError = (HANDLE)_get_osfhandle(std_err[1]);
333 #endif
334
335 snprintf(cmd, 4095, "%s -dNOPAUSE -", GS_EXEC);
336 if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &st_info, &pr_info) == 0) {
337 Wprintf("Error: ghostscript not running");
338 return;
339 }
340 CloseHandle(pr_info.hThread);
341 gsproc = pr_info.hProcess;
342 }
343 #else
344 if (gsproc < 0) { /* Ghostscript is not running yet */
345 gsproc = vfork();
346 if (gsproc == 0) { /* child process (gs) */
347 #ifdef GS_DEBUG
348 fprintf(stdout, "Calling %s\n", GS_EXEC);
349 #endif
350 close(std_out[0]);
351 #ifndef GS_DEBUG
352 close(std_err[0]);
353 #endif
354 dup2(fgs[0], 0);
355 close(fgs[0]);
356 dup2(std_out[1], 1);
357 close(std_out[1]);
358 #ifndef GS_DEBUG
359 dup2(std_err[1], 2);
360 close(std_err[1]);
361 #endif
362
363 #ifdef HAVE_PUTENV
364 sprintf(env_str1, "DISPLAY=%s", XDisplayString(dpy));
365 putenv(env_str1);
366 sprintf(env_str2, "GHOSTVIEW=%ld %ld", (long)areawin->window, (long)bbuf);
367 putenv(env_str2);
368 #else
369 setenv("DISPLAY", XDisplayString(dpy), True);
370 sprintf(_STR, "%ld %ld", (long)areawin->window, (long)bbuf);
371 setenv("GHOSTVIEW", _STR, True);
372 #endif
373 Flush(stderr);
374 execlp(GS_EXEC, "gs", "-dNOPAUSE", "-", (char *)NULL);
375 gsproc = -1;
376 fprintf(stderr, "Exec of gs failed\n");
377 return;
378 }
379 else if (gsproc < 0) {
380 Wprintf("Error: ghostscript not running");
381 return; /* error condition */
382 }
383 }
384 #endif
385 }
386 #endif /* HAVE_CAIRO */
387
388 /*--------------------------------------------------------*/
389 /* Parse the background file for Bounding Box information */
390 /*--------------------------------------------------------*/
391
parse_bg(FILE * fi,FILE * fbg)392 void parse_bg(FILE *fi, FILE *fbg) {
393 char *bbptr;
394 Boolean bflag = False;
395 int llx, lly, urx, ury;
396 char line_in[256];
397 float psscale;
398
399 psscale = getpsscale(xobjs.pagelist[areawin->page]->outscale, areawin->page);
400
401 for(;;) {
402 if (fgets(line_in, 255, fi) == NULL) {
403 Wprintf("Error: end of file before end of insert.");
404 return;
405 }
406 else if (strstr(line_in, "end_insert") != NULL) break;
407
408 if (!bflag) {
409 if ((bbptr = strstr(line_in, "BoundingBox:")) != NULL) {
410 if (strstr(line_in, "(atend)") == NULL) {
411 bflag = True;
412 sscanf(bbptr + 12, "%d %d %d %d", &llx, &lly, &urx, &ury);
413 /* compute user coordinate bounds from PostScript bounds */
414 #ifdef GS_DEBUG
415 fprintf(stdout, "BBox %d %d %d %d PostScript coordinates\n",
416 llx, lly, urx, ury);
417 #endif
418 llx = (int)((float)llx / psscale);
419 lly = (int)((float)lly / psscale);
420 urx = (int)((float)urx / psscale);
421 ury = (int)((float)ury / psscale);
422 #ifdef GS_DEBUG
423 fprintf(stdout, "BBox %d %d %d %d XCircuit coordinates\n",
424 llx, lly, urx, ury);
425 #endif
426
427 xobjs.pagelist[areawin->page]->background.bbox.lowerleft.x = llx;
428 xobjs.pagelist[areawin->page]->background.bbox.lowerleft.y = lly;
429 xobjs.pagelist[areawin->page]->background.bbox.width = (urx - llx);
430 xobjs.pagelist[areawin->page]->background.bbox.height = (ury - lly);
431 if (fbg == (FILE *)NULL) break;
432 }
433 }
434 }
435 if (fbg != (FILE *)NULL) fputs(line_in, fbg);
436 }
437 }
438
439 /*-------------------------------------------------------*/
440 /* Get bounding box information from the background file */
441 /*-------------------------------------------------------*/
442
bg_get_bbox()443 void bg_get_bbox()
444 {
445 FILE *fi;
446 char *fname;
447
448 fname = xobjs.pagelist[areawin->page]->background.name;
449 if ((fi = fopen(fname, "r")) == NULL) {
450 fprintf(stderr, "Failure to open background file to get bounding box info\n");
451 return;
452 }
453 parse_bg(fi, (FILE *)NULL);
454 fclose(fi);
455 }
456
457 /*------------------------------------------------------------*/
458 /* Adjust object's bounding box based on the background image */
459 /*------------------------------------------------------------*/
460
backgroundbbox(int mpage)461 void backgroundbbox(int mpage)
462 {
463 int llx, lly, urx, ury, tmp;
464 objectptr thisobj = xobjs.pagelist[mpage]->pageinst->thisobject;
465 psbkground *thisbg = &xobjs.pagelist[mpage]->background;
466
467 llx = thisobj->bbox.lowerleft.x;
468 lly = thisobj->bbox.lowerleft.y;
469 urx = thisobj->bbox.width + llx;
470 ury = thisobj->bbox.height + lly;
471
472 if (thisbg->bbox.lowerleft.x < llx) llx = thisbg->bbox.lowerleft.x;
473 if (thisbg->bbox.lowerleft.y < lly) lly = thisbg->bbox.lowerleft.y;
474 tmp = thisbg->bbox.width + thisbg->bbox.lowerleft.x;
475 if (tmp > urx) urx = tmp;
476 tmp = thisbg->bbox.height + thisbg->bbox.lowerleft.y;
477 if (tmp > ury) ury = tmp;
478
479 thisobj->bbox.lowerleft.x = llx;
480 thisobj->bbox.lowerleft.y = lly;
481 thisobj->bbox.width = urx - llx;
482 thisobj->bbox.height = ury - lly;
483 }
484
485 /*------------------------------------------------------*/
486 /* Read a background PostScript image from a file and */
487 /* store in a temporary file, passing that filename to */
488 /* the background property of the page. */
489 /*------------------------------------------------------*/
490
readbackground(FILE * fi)491 void readbackground(FILE *fi)
492 {
493 FILE *fbg = (FILE *)NULL;
494 int tfd;
495 char *file_in = (char *)malloc(9 + strlen(xobjs.tempdir));
496
497 /* "@" denotes a temporary file */
498 sprintf(file_in, "@%s/XXXXXX", xobjs.tempdir);
499
500 #ifdef _MSC_VER
501 tfd = mktemp(file_in + 1);
502 #else
503 tfd = mkstemp(file_in + 1);
504 #endif
505 if (tfd == -1) fprintf(stderr, "Error generating temporary filename\n");
506 else {
507 if ((fbg = fdopen(tfd, "w")) == NULL) {
508 fprintf(stderr, "Error opening temporary file \"%s\"\n", file_in + 1);
509 }
510 }
511
512 /* Read the file to the restore directive or end_insertion */
513 /* Skip restore directive and end_insertion command */
514
515 parse_bg(fi, fbg);
516
517 if (fbg != (FILE *)NULL) {
518 fclose(fbg);
519 register_bg(file_in);
520 }
521 free(file_in);
522 }
523
524 /*------------------------------------------------------*/
525 /* Save a background PostScript image to the output */
526 /* file by streaming directly from the background file */
527 /*------------------------------------------------------*/
528
savebackground(FILE * fo,char * psfilename)529 void savebackground(FILE *fo, char *psfilename)
530 {
531 FILE *psf;
532 char *fname = psfilename;
533 char line_in[256];
534
535 if (fname[0] == '@') fname++;
536
537 if ((psf = fopen(fname, "r")) == NULL) {
538 fprintf(stderr, "Error opening background file \"%s\" for reading.\n", fname);
539 return;
540 }
541
542 for(;;) {
543 if (fgets(line_in, 255, psf) == NULL)
544 break;
545 else
546 fputs(line_in, fo);
547 }
548 fclose(psf);
549 }
550
551 /*--------------------------------------------------------------*/
552 /* Set up a page to render a PostScript image when redrawing. */
553 /* This includes starting the ghostscript process if it has */
554 /* not already been started. This routine does not draw the */
555 /* image, which is done on refresh. */
556 /*--------------------------------------------------------------*/
557
register_bg(char * gsfile)558 void register_bg(char *gsfile)
559 {
560 #ifndef HAVE_CAIRO
561 if (gsproc < 0)
562 start_gs();
563 else
564 reset_gs();
565 #endif /* !HAVE_CAIRO */
566
567 xobjs.pagelist[areawin->page]->background.name =
568 (char *) malloc(strlen(gsfile) + 1);
569 strcpy(xobjs.pagelist[areawin->page]->background.name, gsfile);
570 }
571
572 /*------------------------------------------------------*/
573 /* Load a generic (non-xcircuit) postscript file as the */
574 /* background for the page. This function is called */
575 /* by the file import routine, and so it completes by */
576 /* running zoomview(), which redraws the image and */
577 /* the page. */
578 /*------------------------------------------------------*/
579
loadbackground()580 void loadbackground()
581 {
582 register_bg(_STR2);
583 bg_get_bbox();
584 updatepagebounds(topobject);
585 zoomview(areawin->area, NULL, NULL);
586 }
587
588 /*------------------------------------------------------*/
589 /* Send text to the ghostscript renderer */
590 /*------------------------------------------------------*/
591
592 #ifndef HAVE_CAIRO
send_to_gs(char * text)593 void send_to_gs(char *text)
594 {
595 #ifndef XC_WIN32
596 write(fgs[1], text, strlen(text));
597 tcflush(fgs[1], TCOFLUSH);
598 #else
599 _write(fgs[1], text, (unsigned int)strlen(text));
600 #endif
601 #ifdef GS_DEBUG
602 fprintf(stdout, "writing: %s", text);
603 #endif
604 }
605 #endif /* !HAVE_CAIRO */
606
607 /*------------------------------------------------------*/
608 /* write scale and position to ghostscript */
609 /* and tell ghostscript to run the requested file */
610 /*------------------------------------------------------*/
611
612 #ifndef HAVE_CAIRO
write_scale_position_and_run_gs(float norm,float xpos,float ypos,const char * bgfile)613 void write_scale_position_and_run_gs(float norm, float xpos, float ypos,
614 const char *bgfile)
615 {
616 send_to_gs("/GSobj save def\n");
617 send_to_gs("/setpagedevice {pop} def\n");
618 send_to_gs("gsave\n");
619 sprintf(_STR, "%3.2f %3.2f translate\n", xpos, ypos);
620 send_to_gs(_STR);
621 sprintf(_STR, "%3.2f %3.2f scale\n", norm, norm);
622 send_to_gs(_STR);
623 sprintf(_STR, "(%s) run\n", bgfile);
624 send_to_gs(_STR);
625 send_to_gs("GSobj restore\n");
626 send_to_gs("grestore\n");
627
628 Wprintf("Rendering background image.");
629 XDefineCursor(dpy, areawin->window, WAITFOR);
630 }
631 #endif /* !HAVE_CAIRO */
632
633 /*------------------------------------------------------*/
634 /* Call ghostscript to render the background into the */
635 /* pixmap buffer. */
636 /*------------------------------------------------------*/
637
renderbackground()638 int renderbackground()
639 {
640 char *bgfile;
641 float psnorm, psxpos, psypos, defscale;
642 float devres = 0.96; /* = 72.0 / 75.0, ps_units/in : screen_dpi */
643
644 #ifndef HAVE_CAIRO
645 if (gsproc < 0) return -1;
646 #endif /* !HAVE_CAIRO */
647
648 defscale = (xobjs.pagelist[areawin->page]->coordstyle == CM) ?
649 CMSCALE : INCHSCALE;
650
651 psnorm = areawin->vscale * (1.0 / defscale) * devres;
652
653 psxpos = (float)(-areawin->pcorner.x) * areawin->vscale * devres;
654 psypos = (float)(-areawin->pcorner.y) * areawin->vscale * devres;
655 #ifndef HAVE_CAIRO
656 psypos += areawin->height / 12.;
657 #endif /* !HAVE_CAIRO */
658
659 /* Conditions for re-rendering: Must have a background specified */
660 /* and must be on the page, not a library or other object. */
661
662 if (xobjs.pagelist[areawin->page]->background.name == (char *)NULL)
663 return -1;
664 else if (areawin->lastbackground
665 == xobjs.pagelist[areawin->page]->background.name) {
666 return 0;
667 }
668
669 if (is_page(topobject) == -1)
670 return -1;
671
672 bgfile = xobjs.pagelist[areawin->page]->background.name;
673 if (*bgfile == '@') bgfile++;
674
675 /* Ask ghostscript to produce the next page */
676 ask_for_next();
677
678 /* Set the last background name to NULL; this will get the */
679 /* value when the rendering is done. */
680
681 areawin->lastbackground = NULL;
682
683 #ifdef GS_DEBUG
684 fprintf(stdout, "Rendering background from file \"%s\"\n", bgfile);
685 #endif
686 Wprintf("Rendering background image.");
687
688 /* write scale and position to ghostscript */
689 /* and tell ghostscript to run the requested file */
690
691 write_scale_position_and_run_gs(psnorm, psxpos, psypos, bgfile);
692
693 /* The page will be refreshed when we receive confirmation */
694 /* from ghostscript that the buffer has been rendered. */
695
696 return 0;
697 }
698
699 /*------------------------------------------------------*/
700 /* Copy the rendered background pixmap to the window. */
701 /*------------------------------------------------------*/
702
copybackground()703 int copybackground()
704 {
705 /* Don't copy if the buffer is not ready to use */
706 if (gs_state != GS_READY)
707 return -1;
708
709 /* Only draw on a top-level page */
710 if (is_page(topobject) == -1)
711 return -1;
712
713 #ifdef HAVE_CAIRO
714 cairo_set_source_surface(areawin->cr, bbuf, 0., 0.);
715 cairo_paint(areawin->cr);
716 #else
717 XCopyArea(dpy, bbuf, dbuf, areawin->gc, 0, 0,
718 areawin->width, areawin->height, 0, 0);
719 #endif
720
721 return 0;
722 }
723
724 /*------------------------------------------------------*/
725 /* Exit ghostscript. . . not so gently */
726 /*------------------------------------------------------*/
727
exit_gs()728 int exit_gs()
729 {
730 #ifndef HAVE_CAIRO
731 #ifdef _MSC_VER
732 if (gsproc == INVALID_HANDLE_VALUE) return -1; /* gs not running */
733 #else
734 if (gsproc < 0) return -1; /* gs not running */
735 #endif
736
737 #ifdef GS_DEBUG
738 fprintf(stdout, "Waiting for gs to exit\n");
739 #endif
740 #ifndef _MSC_VER
741 kill(gsproc, SIGKILL);
742 waitpid(gsproc, NULL, 0);
743 #else
744 TerminateProcess(gsproc, -1);
745 #endif
746 #ifdef GS_DEBUG
747 fprintf(stdout, "gs has exited\n");
748 #endif
749
750 mwin = 0;
751 #ifdef _MSC_VER
752 gsproc = INVALID_HANDLE_VALUE;
753 #else
754 gsproc = -1;
755 #endif
756 #endif /* !HAVE_CAIRO */
757
758 gs_state = GS_INIT;
759 return 0;
760 }
761
762 /*------------------------------------------------------*/
763 /* Restart ghostscript */
764 /*------------------------------------------------------*/
765
reset_gs()766 int reset_gs()
767 {
768 #ifndef HAVE_CAIRO
769 #ifdef _MSC_VER
770 if (gsproc == INVALID_HANDLE_VALUE) return -1;
771 #else
772 if (gsproc < 0) return -1;
773 #endif
774
775 exit_gs();
776 ghostinit_local();
777 start_gs();
778
779 #endif /* !HAVE_CAIRO */
780 return 0;
781 }
782
783 /*----------------------------------------------------------------------*/
784