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