Update at Fri Feb 9 12:38:17 EST 2018 by tim
[xcircuit.git] / render.c
blob77ff16640c610a7b2138a3ab7d1be0a6eec0ff71
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 /*----------------------------------------------------------------------*/
7 #undef GS_DEBUG
8 /* #define GS_DEBUG */
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>
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
35 /*------------------------------------------------------------------------*/
36 /* Local includes */
37 /*------------------------------------------------------------------------*/
39 #ifdef TCL_WRAPPER
40 #include <tk.h>
41 #endif
43 #include "colordefs.h"
44 #include "xcircuit.h"
46 /*----------------------------------------------------------------------*/
47 /* Function prototype declarations */
48 /*----------------------------------------------------------------------*/
49 #include "prototypes.h"
51 /*------------------------------------------------------------------------*/
52 /* External Variable definitions */
53 /*------------------------------------------------------------------------*/
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];
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 */
70 #ifndef HAVE_VFORK
71 #define vfork fork
72 #endif
74 gs_state_t gs_state; /* Track state of the renderer */
76 /*------------------------------------------------------*/
77 /* Global variable definitions */
78 /*------------------------------------------------------*/
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 */
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 /*--------------------------------------------------------------*/
100 void ghostinit_local()
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 */
116 gs_state = GS_INIT;
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 /*------------------------------------------------------*/
128 Boolean render_client(XEvent *eventPtr)
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);
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);
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;
152 else {
153 char *atomname;
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);
160 return False;
162 #endif /* HAVE_CAIRO */
163 return True;
166 /*------------------------------------------------------*/
167 /* Tk client handler procedure for the above routine. */
168 /*------------------------------------------------------*/
170 #ifdef TCL_WRAPPER
172 #ifndef HAVE_CAIRO
173 void handle_client(ClientData clientData, XEvent *eventPtr)
175 if (render_client(eventPtr) == False)
176 fprintf(stderr, "Xcircuit: Received unknown client message\n");
178 #endif /* HAVE_CAIRO */
180 #endif
182 /*------------------------------------------------------*/
183 /* Global initialization */
184 /*------------------------------------------------------*/
186 void ghostinit()
188 #ifndef HAVE_CAIRO
189 gv = XInternAtom(dpy, "GHOSTVIEW", False);
190 gvc = XInternAtom(dpy, "GHOSTVIEW_COLORS", False);
191 gvpage = XInternAtom(dpy, "PAGE", False);
192 gvnext = XInternAtom(dpy, "NEXT", False);
193 gvdone = XInternAtom(dpy, "DONE", False);
195 ghostinit_local();
197 #ifdef TCL_WRAPPER
198 Tk_CreateClientMessageHandler((Tk_ClientMessageProc *)handle_client);
199 #endif
200 #endif /* HAVE_CAIRO */
203 /*------------------------------------------------------*/
204 /* Send a ClientMessage event */
205 /*------------------------------------------------------*/
207 #ifndef HAVE_CAIRO
208 void send_client(Atom msg)
210 XEvent event;
212 if (mwin == 0) return; /* Have to wait for gs */
213 /* to give us window # */
215 event.xclient.type = ClientMessage;
216 event.xclient.display = dpy;
217 event.xclient.window = areawin->window;
218 event.xclient.message_type = msg;
219 event.xclient.format = 32;
220 event.xclient.data.l[0] = mwin;
221 event.xclient.data.l[1] = bbuf;
222 XSendEvent(dpy, mwin, False, 0, &event);
223 XFlush(dpy);
225 #endif /* HAVE_CAIRO */
227 /*------------------------------------------------------*/
228 /* Ask ghostscript to produce the next page. */
229 /*------------------------------------------------------*/
231 void ask_for_next()
233 #ifndef HAVE_CAIRO
234 if (gs_state != GS_READY) {
235 /* If we're in the middle of rendering something, halt */
236 /* immediately and start over. */
237 if (gs_state == GS_PENDING)
238 reset_gs();
239 return;
241 XSync(dpy, False);
242 gs_state = GS_PENDING;
243 send_client(gvnext);
244 #ifdef GS_DEBUG
245 fprintf(stdout, "Xcircuit: Sent NEXT message to ghostscript\n");
246 #endif
247 #endif /* HAVE_CAIRO */
250 /*--------------------------------------------------------*/
251 /* Start a ghostscript process and arrange the I/O pipes */
252 /* (Commented lines cause ghostscript to relay its stderr */
253 /* to xcircuit's stderr) */
254 /*--------------------------------------------------------*/
256 #ifndef HAVE_CAIRO
257 void start_gs()
259 int std_out[2], std_err[2], ret;
260 #ifdef XC_WIN32
261 unsigned int pipe_size = 8196;
262 int pipe_mode = _O_BINARY;
263 #endif
264 #ifdef HAVE_PUTENV
265 static char env_str1[128], env_str2[64];
266 #endif
268 #ifdef TCL_WRAPPER
269 if (bbuf != (Pixmap)NULL) Tk_FreePixmap(dpy, bbuf);
270 bbuf = Tk_GetPixmap(dpy, dbuf, areawin->width, areawin->height,
271 Tk_Depth(areawin->area));
272 #else /* !TCL_WRAPPER */
273 if (bbuf != (Pixmap)NULL) XFreePixmap(dpy, bbuf);
274 bbuf = XCreatePixmap(dpy, dbuf, areawin->width, areawin->height,
275 DefaultDepthOfScreen(xcScreen(areawin->area)));
276 #endif /* TCL_WRAPPER */
278 XSync(dpy, False);
280 #ifndef XC_WIN32
281 ret = pipe(fgs);
282 ret = pipe(std_out);
283 #else
284 ret = _pipe(fgs, pipe_size, pipe_mode);
285 ret = _pipe(std_out, pipe_size, pipe_mode);
286 #endif
287 #ifndef GS_DEBUG
288 #ifndef XC_WIN32
289 ret = pipe(std_err);
290 #else
291 ret = _pipe(std_err, pipe_size, pipe_mode);
292 #endif /* XC_WIN32 */
293 #endif
295 /* We need a complicated pipe here, with input going from xcircuit */
296 /* to gs to provide scale/position information, and input going from */
297 /* the background file to gs for rendering. */
298 /* Here is not the place to do it. Set up gs to take stdin as input.*/
300 #ifdef _MSC_VER
301 if (gsproc == INVALID_HANDLE_VALUE) {
302 STARTUPINFO st_info;
303 PROCESS_INFORMATION pr_info;
304 char cmd[4096];
306 #ifdef HAVE_PUTENV
307 sprintf(env_str1, "DISPLAY=%s", XDisplayString(dpy));
308 putenv(env_str1);
309 sprintf(env_str2, "GHOSTVIEW=%ld %ld", (long)areawin->window, (long)bbuf);
310 putenv(env_str2);
311 #else
312 setenv("DISPLAY", XDisplayString(dpy), True);
313 sprintf(_STR, "%ld %ld", (long)areastruct.areawin, (long)bbuf);
314 setenv("GHOSTVIEW", _STR, True);
315 #endif
317 SetHandleInformation((HANDLE)_get_osfhandle(fgs[1]), HANDLE_FLAG_INHERIT, 0);
318 SetHandleInformation((HANDLE)_get_osfhandle(std_out[0]), HANDLE_FLAG_INHERIT, 0);
319 #ifndef GS_DEBUG
320 SetHandleInformation((HANDLE)_get_osfhandle(std_err[0]), HANDLE_FLAG_INHERIT, 0);
321 #endif
323 ZeroMemory(&st_info, sizeof(STARTUPINFO));
324 ZeroMemory(&pr_info, sizeof(PROCESS_INFORMATION));
325 st_info.cb = sizeof(STARTUPINFO);
326 st_info.dwFlags = STARTF_USESTDHANDLES;
327 st_info.hStdOutput = (HANDLE)_get_osfhandle(std_out[1]);
328 st_info.hStdInput = (HANDLE)_get_osfhandle(fgs[0]);
329 #ifndef GS_DEBUG
330 st_info.hStdError = (HANDLE)_get_osfhandle(std_err[1]);
331 #endif
333 snprintf(cmd, 4095, "%s -dNOPAUSE -", GS_EXEC);
334 if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &st_info, &pr_info) == 0) {
335 Wprintf("Error: ghostscript not running");
336 return;
338 CloseHandle(pr_info.hThread);
339 gsproc = pr_info.hProcess;
341 #else
342 if (gsproc < 0) { /* Ghostscript is not running yet */
343 gsproc = vfork();
344 if (gsproc == 0) { /* child process (gs) */
345 #ifdef GS_DEBUG
346 fprintf(stdout, "Calling %s\n", GS_EXEC);
347 #endif
348 close(std_out[0]);
349 #ifndef GS_DEBUG
350 close(std_err[0]);
351 #endif
352 dup2(fgs[0], 0);
353 close(fgs[0]);
354 dup2(std_out[1], 1);
355 close(std_out[1]);
356 #ifndef GS_DEBUG
357 dup2(std_err[1], 2);
358 close(std_err[1]);
359 #endif
361 #ifdef HAVE_PUTENV
362 sprintf(env_str1, "DISPLAY=%s", XDisplayString(dpy));
363 putenv(env_str1);
364 sprintf(env_str2, "GHOSTVIEW=%ld %ld", (long)areawin->window, (long)bbuf);
365 putenv(env_str2);
366 #else
367 setenv("DISPLAY", XDisplayString(dpy), True);
368 sprintf(_STR, "%ld %ld", (long)areawin->window, (long)bbuf);
369 setenv("GHOSTVIEW", _STR, True);
370 #endif
371 Flush(stderr);
372 execlp(GS_EXEC, "gs", "-dNOPAUSE", "-", (char *)NULL);
373 gsproc = -1;
374 fprintf(stderr, "Exec of gs failed\n");
375 return;
377 else if (gsproc < 0) {
378 Wprintf("Error: ghostscript not running");
379 return; /* error condition */
382 #endif
384 #endif /* HAVE_CAIRO */
386 /*--------------------------------------------------------*/
387 /* Parse the background file for Bounding Box information */
388 /*--------------------------------------------------------*/
390 void parse_bg(FILE *fi, FILE *fbg) {
391 char *bbptr;
392 Boolean bflag = False;
393 int llx, lly, urx, ury;
394 char line_in[256];
395 float psscale;
397 psscale = getpsscale(xobjs.pagelist[areawin->page]->outscale, areawin->page);
399 for(;;) {
400 if (fgets(line_in, 255, fi) == NULL) {
401 Wprintf("Error: end of file before end of insert.");
402 return;
404 else if (strstr(line_in, "end_insert") != NULL) break;
406 if (!bflag) {
407 if ((bbptr = strstr(line_in, "BoundingBox:")) != NULL) {
408 if (strstr(line_in, "(atend)") == NULL) {
409 bflag = True;
410 sscanf(bbptr + 12, "%d %d %d %d", &llx, &lly, &urx, &ury);
411 /* compute user coordinate bounds from PostScript bounds */
412 #ifdef GS_DEBUG
413 fprintf(stdout, "BBox %d %d %d %d PostScript coordinates\n",
414 llx, lly, urx, ury);
415 #endif
416 llx = (int)((float)llx / psscale);
417 lly = (int)((float)lly / psscale);
418 urx = (int)((float)urx / psscale);
419 ury = (int)((float)ury / psscale);
420 #ifdef GS_DEBUG
421 fprintf(stdout, "BBox %d %d %d %d XCircuit coordinates\n",
422 llx, lly, urx, ury);
423 #endif
425 xobjs.pagelist[areawin->page]->background.bbox.lowerleft.x = llx;
426 xobjs.pagelist[areawin->page]->background.bbox.lowerleft.y = lly;
427 xobjs.pagelist[areawin->page]->background.bbox.width = (urx - llx);
428 xobjs.pagelist[areawin->page]->background.bbox.height = (ury - lly);
429 if (fbg == (FILE *)NULL) break;
433 if (fbg != (FILE *)NULL) fputs(line_in, fbg);
437 /*-------------------------------------------------------*/
438 /* Get bounding box information from the background file */
439 /*-------------------------------------------------------*/
441 void bg_get_bbox()
443 FILE *fi;
444 char *fname;
446 fname = xobjs.pagelist[areawin->page]->background.name;
447 if ((fi = fopen(fname, "r")) == NULL) {
448 fprintf(stderr, "Failure to open background file to get bounding box info\n");
449 return;
451 parse_bg(fi, (FILE *)NULL);
452 fclose(fi);
455 /*------------------------------------------------------------*/
456 /* Adjust object's bounding box based on the background image */
457 /*------------------------------------------------------------*/
459 void backgroundbbox(int mpage)
461 int llx, lly, urx, ury, tmp;
462 objectptr thisobj = xobjs.pagelist[mpage]->pageinst->thisobject;
463 psbkground *thisbg = &xobjs.pagelist[mpage]->background;
465 llx = thisobj->bbox.lowerleft.x;
466 lly = thisobj->bbox.lowerleft.y;
467 urx = thisobj->bbox.width + llx;
468 ury = thisobj->bbox.height + lly;
470 if (thisbg->bbox.lowerleft.x < llx) llx = thisbg->bbox.lowerleft.x;
471 if (thisbg->bbox.lowerleft.y < lly) lly = thisbg->bbox.lowerleft.y;
472 tmp = thisbg->bbox.width + thisbg->bbox.lowerleft.x;
473 if (tmp > urx) urx = tmp;
474 tmp = thisbg->bbox.height + thisbg->bbox.lowerleft.y;
475 if (tmp > ury) ury = tmp;
477 thisobj->bbox.lowerleft.x = llx;
478 thisobj->bbox.lowerleft.y = lly;
479 thisobj->bbox.width = urx - llx;
480 thisobj->bbox.height = ury - lly;
483 /*------------------------------------------------------*/
484 /* Read a background PostScript image from a file and */
485 /* store in a temporary file, passing that filename to */
486 /* the background property of the page. */
487 /*------------------------------------------------------*/
489 void readbackground(FILE *fi)
491 FILE *fbg = (FILE *)NULL;
492 int tfd;
493 char *file_in = (char *)malloc(9 + strlen(xobjs.tempdir));
495 /* "@" denotes a temporary file */
496 sprintf(file_in, "@%s/XXXXXX", xobjs.tempdir);
498 #ifdef _MSC_VER
499 tfd = mktemp(file_in + 1);
500 #else
501 tfd = mkstemp(file_in + 1);
502 #endif
503 if (tfd == -1) fprintf(stderr, "Error generating temporary filename\n");
504 else {
505 if ((fbg = fdopen(tfd, "w")) == NULL) {
506 fprintf(stderr, "Error opening temporary file \"%s\"\n", file_in + 1);
510 /* Read the file to the restore directive or end_insertion */
511 /* Skip restore directive and end_insertion command */
513 parse_bg(fi, fbg);
515 if (fbg != (FILE *)NULL) {
516 fclose(fbg);
517 register_bg(file_in);
519 free(file_in);
522 /*------------------------------------------------------*/
523 /* Save a background PostScript image to the output */
524 /* file by streaming directly from the background file */
525 /*------------------------------------------------------*/
527 void savebackground(FILE *fo, char *psfilename)
529 FILE *psf;
530 char *fname = psfilename;
531 char line_in[256];
533 if (fname[0] == '@') fname++;
535 if ((psf = fopen(fname, "r")) == NULL) {
536 fprintf(stderr, "Error opening background file \"%s\" for reading.\n", fname);
537 return;
540 for(;;) {
541 if (fgets(line_in, 255, psf) == NULL)
542 break;
543 else
544 fputs(line_in, fo);
546 fclose(psf);
549 /*--------------------------------------------------------------*/
550 /* Set up a page to render a PostScript image when redrawing. */
551 /* This includes starting the ghostscript process if it has */
552 /* not already been started. This routine does not draw the */
553 /* image, which is done on refresh. */
554 /*--------------------------------------------------------------*/
556 void register_bg(char *gsfile)
558 #ifndef HAVE_CAIRO
559 if (gsproc < 0)
560 start_gs();
561 else
562 reset_gs();
563 #endif /* !HAVE_CAIRO */
565 xobjs.pagelist[areawin->page]->background.name =
566 (char *) malloc(strlen(gsfile) + 1);
567 strcpy(xobjs.pagelist[areawin->page]->background.name, gsfile);
570 /*------------------------------------------------------*/
571 /* Load a generic (non-xcircuit) postscript file as the */
572 /* background for the page. This function is called */
573 /* by the file import routine, and so it completes by */
574 /* running zoomview(), which redraws the image and */
575 /* the page. */
576 /*------------------------------------------------------*/
578 void loadbackground()
580 register_bg(_STR2);
581 bg_get_bbox();
582 updatepagebounds(topobject);
583 zoomview(areawin->area, NULL, NULL);
586 /*------------------------------------------------------*/
587 /* Send text to the ghostscript renderer */
588 /*------------------------------------------------------*/
590 #ifndef HAVE_CAIRO
591 void send_to_gs(char *text)
593 #ifndef XC_WIN32
594 write(fgs[1], text, strlen(text));
595 tcflush(fgs[1], TCOFLUSH);
596 #else
597 _write(fgs[1], text, (unsigned int)strlen(text));
598 #endif
599 #ifdef GS_DEBUG
600 fprintf(stdout, "writing: %s", text);
601 #endif
603 #endif /* !HAVE_CAIRO */
605 /*------------------------------------------------------*/
606 /* write scale and position to ghostscript */
607 /* and tell ghostscript to run the requested file */
608 /*------------------------------------------------------*/
610 #ifndef HAVE_CAIRO
611 void write_scale_position_and_run_gs(float norm, float xpos, float ypos,
612 const char *bgfile)
614 send_to_gs("/GSobj save def\n");
615 send_to_gs("/setpagedevice {pop} def\n");
616 send_to_gs("gsave\n");
617 sprintf(_STR, "%3.2f %3.2f translate\n", xpos, ypos);
618 send_to_gs(_STR);
619 sprintf(_STR, "%3.2f %3.2f scale\n", norm, norm);
620 send_to_gs(_STR);
621 sprintf(_STR, "(%s) run\n", bgfile);
622 send_to_gs(_STR);
623 send_to_gs("GSobj restore\n");
624 send_to_gs("grestore\n");
626 Wprintf("Rendering background image.");
627 XDefineCursor(dpy, areawin->window, WAITFOR);
629 #endif /* !HAVE_CAIRO */
631 /*------------------------------------------------------*/
632 /* Call ghostscript to render the background into the */
633 /* pixmap buffer. */
634 /*------------------------------------------------------*/
636 int renderbackground()
638 char *bgfile;
639 float psnorm, psxpos, psypos, defscale;
640 float devres = 0.96; /* = 72.0 / 75.0, ps_units/in : screen_dpi */
642 #ifndef HAVE_CAIRO
643 if (gsproc < 0) return -1;
644 #endif /* !HAVE_CAIRO */
646 defscale = (xobjs.pagelist[areawin->page]->coordstyle == CM) ?
647 CMSCALE : INCHSCALE;
649 psnorm = areawin->vscale * (1.0 / defscale) * devres;
651 psxpos = (float)(-areawin->pcorner.x) * areawin->vscale * devres;
652 psypos = (float)(-areawin->pcorner.y) * areawin->vscale * devres;
653 #ifndef HAVE_CAIRO
654 psypos += areawin->height / 12.;
655 #endif /* !HAVE_CAIRO */
657 /* Conditions for re-rendering: Must have a background specified */
658 /* and must be on the page, not a library or other object. */
660 if (xobjs.pagelist[areawin->page]->background.name == (char *)NULL)
661 return -1;
662 else if (areawin->lastbackground
663 == xobjs.pagelist[areawin->page]->background.name) {
664 return 0;
667 if (is_page(topobject) == -1)
668 return -1;
670 bgfile = xobjs.pagelist[areawin->page]->background.name;
671 if (*bgfile == '@') bgfile++;
673 /* Ask ghostscript to produce the next page */
674 ask_for_next();
676 /* Set the last background name to NULL; this will get the */
677 /* value when the rendering is done. */
679 areawin->lastbackground = NULL;
681 #ifdef GS_DEBUG
682 fprintf(stdout, "Rendering background from file \"%s\"\n", bgfile);
683 #endif
684 Wprintf("Rendering background image.");
686 /* write scale and position to ghostscript */
687 /* and tell ghostscript to run the requested file */
689 write_scale_position_and_run_gs(psnorm, psxpos, psypos, bgfile);
691 /* The page will be refreshed when we receive confirmation */
692 /* from ghostscript that the buffer has been rendered. */
694 return 0;
697 /*------------------------------------------------------*/
698 /* Copy the rendered background pixmap to the window. */
699 /*------------------------------------------------------*/
701 int copybackground()
703 /* Don't copy if the buffer is not ready to use */
704 if (gs_state != GS_READY)
705 return -1;
707 /* Only draw on a top-level page */
708 if (is_page(topobject) == -1)
709 return -1;
711 #ifdef HAVE_CAIRO
712 cairo_set_source_surface(areawin->cr, bbuf, 0., 0.);
713 cairo_paint(areawin->cr);
714 #else
715 XCopyArea(dpy, bbuf, dbuf, areawin->gc, 0, 0,
716 areawin->width, areawin->height, 0, 0);
717 #endif
719 return 0;
722 /*------------------------------------------------------*/
723 /* Exit ghostscript. . . not so gently */
724 /*------------------------------------------------------*/
726 int exit_gs()
728 #ifndef HAVE_CAIRO
729 #ifdef _MSC_VER
730 if (gsproc == INVALID_HANDLE_VALUE) return -1; /* gs not running */
731 #else
732 if (gsproc < 0) return -1; /* gs not running */
733 #endif
735 #ifdef GS_DEBUG
736 fprintf(stdout, "Waiting for gs to exit\n");
737 #endif
738 #ifndef _MSC_VER
739 kill(gsproc, SIGKILL);
740 waitpid(gsproc, NULL, 0);
741 #else
742 TerminateProcess(gsproc, -1);
743 #endif
744 #ifdef GS_DEBUG
745 fprintf(stdout, "gs has exited\n");
746 #endif
748 mwin = 0;
749 #ifdef _MSC_VER
750 gsproc = INVALID_HANDLE_VALUE;
751 #else
752 gsproc = -1;
753 #endif
754 #endif /* !HAVE_CAIRO */
756 gs_state = GS_INIT;
757 return 0;
760 /*------------------------------------------------------*/
761 /* Restart ghostscript */
762 /*------------------------------------------------------*/
764 int reset_gs()
766 #ifndef HAVE_CAIRO
767 #ifdef _MSC_VER
768 if (gsproc == INVALID_HANDLE_VALUE) return -1;
769 #else
770 if (gsproc < 0) return -1;
771 #endif
773 exit_gs();
774 ghostinit_local();
775 start_gs();
777 #endif /* !HAVE_CAIRO */
778 return 0;
781 /*----------------------------------------------------------------------*/