/* * display.c -- Ghostscript display operations for GSVIEW.EXE, * a graphical interface for MS-Windows Ghostscript * Copyright (C) 1993 Russell Lang * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Author: Russell Lang * Internet: rjl@monu1.cc.monash.edu.au */ #define STRICT #include #include #include #include #include #include #include #include #include #include #include #define NeedFunctionPrototypes 1 #include "ps.h" #include "gsview.h" struct ftime dftime; /* time/date of selected file */ long dflength; /* length of selected file */ /* get current media index to papersizes[], or -1 if no match */ int get_papersizes_index() { int i; for (i=0; papersizes[i].name != (char *)NULL; i++) { if (!stricmp(papersizes[i].name, medianame)) return i; } return -1; } /* calculate bitmap size for gswin */ void gswin_size() { int i = get_papersizes_index(); if ( (xdpi == 0.0) || (ydpi == 0.0) ) xdpi = ydpi = DEFAULT_RESOLUTION; epsf_clipped = FALSE; switch (orientation) { case IDM_LANDSCAPE: case IDM_SEASCAPE: if (i < 0) { bitmap_width = user_height; bitmap_height = user_width; } else { bitmap_width = papersizes[i].height; bitmap_height = papersizes[i].width; } break; default: if ((doc != (struct document *)NULL) && doc->epsf && epsf_clip) { epsf_clipped = TRUE; bitmap_width = doc->boundingbox[URX] - doc->boundingbox[LLX]; bitmap_height = doc->boundingbox[URY] - doc->boundingbox[LLY]; } else if (i < 0) { bitmap_width = user_width; bitmap_height = user_height; } else { bitmap_width = papersizes[i].width; bitmap_height = papersizes[i].height; } } bitmap_width = (unsigned int)(bitmap_width / 72.0 * xdpi); bitmap_height = (unsigned int)(bitmap_height / 72.0 * ydpi); } /* change the size of the gswin image if open */ void gswin_resize() { BOOL display = FALSE; BOOL opened_dfile = FALSE; gswin_size(); if (gswin_hinst == (HINSTANCE)NULL) return; if ( (dfile == (FILE *)NULL) && (doc != (struct document *)NULL) ) { dfreopen(); opened_dfile = TRUE; } if (redisplay && page_ready && (doc != (struct document *)NULL)) display = TRUE; /* redisplay page after resize */ gsview_endfile(); if (gswin_hinst != (HINSTANCE)NULL) { fprintf(cfile,"mark /HWSize [%u %u]\r\n",bitmap_width,bitmap_height); fprintf(cfile,"/HWResolution [%g %g]\r\n",xdpi,ydpi); fprintf(cfile,"currentdevice putdeviceprops pop erasepage flushpage\r\n"); pipeflush(); } if (display) { if (gswin_hinst != (HINSTANCE)NULL) gswin_open(); /* we need it open to redisplay */ fix_orientation(cfile); dsc_header(cfile); dsc_getpages(cfile,pagenum,pagenum); pipeflush(); } if (opened_dfile) dfclose(); } void gsview_orientation(int new_orientation) { if (new_orientation == orientation) return; if (new_orientation == IDM_SWAPLANDSCAPE) { swap_landscape = !swap_landscape; if (swap_landscape) CheckMenuItem(hmenu, IDM_SWAPLANDSCAPE, MF_BYCOMMAND | MF_CHECKED); else CheckMenuItem(hmenu, IDM_SWAPLANDSCAPE, MF_BYCOMMAND | MF_UNCHECKED); if ((orientation != IDM_LANDSCAPE) && (orientation != IDM_SEASCAPE)) return; } else { CheckMenuItem(hmenu, orientation, MF_BYCOMMAND | MF_UNCHECKED); orientation = new_orientation; CheckMenuItem(hmenu, orientation, MF_BYCOMMAND | MF_CHECKED); } gswin_resize(); return; } void gsview_media(int new_media) { if ( (new_media == media) && (new_media != IDM_USERSIZE) ) return; CheckMenuItem(hmenu, media, MF_BYCOMMAND | MF_UNCHECKED); media = new_media; CheckMenuItem(hmenu, media, MF_BYCOMMAND | MF_CHECKED); GetMenuString(hmenu, media, medianame, sizeof(medianame), MF_BYCOMMAND); gswin_resize(); return; } /* run Ghostscript for previewing document */ /* return TRUE if ok, FALSE if error */ BOOL gswin_open() { char command[256]; /* return if already open */ if ((gswin_hinst != (HINSTANCE)NULL) && IsWindow(hwndimgchild)) return TRUE; pipeinit(); /* so we wait for first request */ gswin_size(); sprintf(command,"%s %s -r%gx%g -g%ux%u -sGSVIEW=%u -", szGSwin, safer ? "-dSAFER" : "", xdpi, ydpi, bitmap_width, bitmap_height, (unsigned int)hwndimg); if (strlen(command) > 126) { info_wait(FALSE); gserror(IDS_TOOLONG, command, MB_ICONSTOP, SOUND_ERROR); gswin_hinst = (HINSTANCE)NULL; return FALSE; } gswin_hinst = (HINSTANCE)WinExec(command, SW_SHOWMINNOACTIVE); if (gswin_hinst < HINSTANCE_ERROR) { info_wait(FALSE); gserror(IDS_CANNOTRUN, command, MB_ICONSTOP, SOUND_ERROR); gswin_hinst = (HINSTANCE)NULL; return FALSE; } if (hwndtext == (HWND)NULL) { /* we are running an incompatible version of Ghostscript */ hwndtext = FindWindow("BCEasyWin","Ghostscript"); if (hwndtext) { SendMessage(hwndtext, WM_CHAR, 'q', 1L); SendMessage(hwndtext, WM_CHAR, 'u', 1L); SendMessage(hwndtext, WM_CHAR, 'i', 1L); SendMessage(hwndtext, WM_CHAR, 't', 1L); SendMessage(hwndtext, WM_CHAR, '\r', 1L); } hwndtext = (HWND)NULL; hwndimgchild = (HWND)NULL; gswin_hinst = (HINSTANCE)NULL; clear_timer(); info_wait(FALSE); gserror(IDS_WRONGGS, NULL, MB_ICONSTOP, SOUND_ERROR); return FALSE; } saved = FALSE; /* wait for gswin to initialise */ if (set_timer(CLOSE_TIMEOUT)) EnableWindow(hwndimg, FALSE); while (!is_pipe_done()&& !bTimeout) do_message(); /* wait for pipe data request from gswin */ clear_timer(); EnableWindow(hwndimg, TRUE); cfile = pipeopen(); /* open pipe to gswin */ BringWindowToTop(hwndimg); SetFocus(hwndimg); /* kludge: without this desktop gets focus */ return TRUE; } /* close Ghostscript */ BOOL gswin_close() { BOOL force = FALSE; if (gswin_hinst == (HINSTANCE)NULL) return TRUE; if (doc == (struct document*)NULL) { /* we don't know how many pages remain so we must force an exit */ if (!is_pipe_done()) force = TRUE; } else { if (page_ready) next_page(); } if (!force) { /* try to close Ghostscript cleanly */ pipeclose(); if (set_timer(CLOSE_TIMEOUT)) EnableWindow(hwndimg, FALSE); while (GetModuleUsage(gswin_hinst) && !bTimeout) do_message(); /* wait for gswin to close */ clear_timer(); EnableWindow(hwndimg, TRUE); } do_message(); /* if still there try killing it a using a brute force method */ if (IsWindow(hwndtext)) { if (is_win31) { SendMessage(hwndtext, WM_CLOSE, 0, 0L); if (IsWindow(hwndtext)) SendMessage(hwndtext, WM_CLOSE, 0, 0L); } else { /* Windows 3.0 hangs if we use SendMessage */ PostMessage(hwndtext, WM_CLOSE, 0, 0L); do_message(); } } do_message(); gswin_hinst = (HINSTANCE)NULL; hwndimgchild = (HWND)NULL; hwndtext = (HWND)NULL; bitmap_scrollx = bitmap_scrolly = 0; page_ready = FALSE; saved = FALSE; pipeclose(); return TRUE; } /* send a NEXT_PAGE message to Ghostscript */ void next_page() { int i; if (hwndimgchild && IsWindow(hwndimgchild)) { SendMessage(hwndimgchild, WM_GSVIEW, NEXT_PAGE, 0L); page_ready = FALSE; } do_message(); /* wait for Ghostscript to process message */ for (i=0; i<32; i++) { /* Wait a bit for pipe contents after showpage to be read */ do_message(); if (is_pipe_done()) break; } } /* handle messages while we are waiting */ void do_message() { MSG msg; while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } /* end of file - get ready for new file */ void gsview_endfile() { info_wait(TRUE); if (gswin_hinst == (HINSTANCE)NULL) return; if (!quick || ((doc == (struct document *)NULL) && !is_pipe_done())) { gswin_close(); return; } if (page_ready) next_page(); if ((saved) && (doc != (struct document *)NULL) && (doc->pages)) { /* send trailer if needed */ pscopy(dfile, cfile, doc->begintrailer, doc->endtrailer); } if (saved) { /* restore interpreter state */ fputs("gsview_cleanup\r\n",cfile); fputs("gsview_save restore\r\n",cfile); } else fputs("clear cleardictstack\r\n",cfile); pipeflush(); saved = FALSE; } /* open a new document */ void gsview_openfile(char *filename) { int i; pagenum = 1; page_extra = 0; if (dsc_scan(filename)) { /* found DSC comments */ if (doc->orientation == PORTRAIT) gsview_orientation(IDM_PORTRAIT); if (doc->orientation == LANDSCAPE) gsview_orientation(IDM_LANDSCAPE); if (doc->default_page_media) { char thismedia[20]; for (i=IDM_LETTER; idefault_page_media->name)) { gsview_media(i); break; } } if (i == IDM_USERSIZE) { gsview_media(IDM_USERSIZE); user_width = doc->default_page_media->width; user_height = doc->default_page_media->height; } } } } /* get filename then open new file for printing or extract */ void gsview_select() { LoadString(phInstance, IDS_TOPICOPEN, szHelpTopic, sizeof(szHelpTopic)); if (GetOpenFileName(&ofn)) gsview_selectfile(szOFilename); } /* open new file for printing or extract */ void gsview_selectfile(char *filename) { if (gswin_hinst != (HINSTANCE)NULL) gsview_endfile(); while (*filename && *filename==' ') filename++; gsview_openfile(filename); info_wait(FALSE); } /* get filename then open a new document and display it */ void gsview_display() { LoadString(phInstance, IDS_TOPICOPEN, szHelpTopic, sizeof(szHelpTopic)); if (GetOpenFileName(&ofn)) gsview_displayfile(szOFilename); } /* open a new document and display it */ void gsview_displayfile(char *filename) { char *p; gsview_endfile(); info_wait(TRUE); gsview_openfile(filename); if (epsf_clipped || ((doc != (struct document *)NULL) && doc->epsf && epsf_clip)) gswin_resize(); if (!gswin_open()) { return; } fix_orientation(cfile); if (doc != (struct document *)NULL) { /* found DSC comments */ dsc_header(cfile); dsc_getpages(cfile,pagenum,pagenum); } else { /* non conformant file - send unmodified */ fputs("(Displaying ",cfile); for (p=filename; *p; p++) { if (*p != '\\') fputc(*p,cfile); else fputc('/',cfile); } fputs("\\n) print flush\r\n",cfile); fputc('(',cfile); for (p=filename; *p; p++) { if (*p != '\\') fputc(*p,cfile); else fputc('/',cfile); } fputs(") run flushpage\r\n",cfile); } pipeflush(); } void send_prolog(FILE *f, char *resource) { HGLOBAL hglobal; LPSTR prolog; hglobal = LoadResource(phInstance, FindResource(phInstance, resource, RT_RCDATA)); if ( (prolog = (LPSTR)LockResource(hglobal)) != (LPSTR)NULL) { while (*prolog) fputc(*prolog++, f); FreeResource(hglobal); } } /* add Ghostscript code to change orientation */ void fix_orientation(FILE *f) { int real_orientation; /* save interpreter state */ fputs("clear cleardictstack save /gsview_save exch def\r\n",f); saved = TRUE; /* provide epsf offset */ if (epsf_clipped) fprintf(f,"/gsview_offset {%d %d translate} def\r\n", -doc->boundingbox[LLX], -doc->boundingbox[LLY]); else fprintf(f,"/gsview_offset {} def\r\n"); real_orientation = orientation; if (swap_landscape) { if (orientation == IDM_LANDSCAPE) real_orientation = IDM_SEASCAPE; else if (orientation == IDM_SEASCAPE) real_orientation = IDM_LANDSCAPE; } fprintf(f,"/gsview_landscape %s def\r\n", real_orientation == IDM_LANDSCAPE ? "true" : "false"); fprintf(f,"/gsview_upsidedown %s def\r\n", real_orientation == IDM_UPSIDEDOWN ? "true" : "false"); fprintf(f,"/gsview_seascape %s def\r\n", real_orientation == IDM_SEASCAPE ? "true" : "false"); send_prolog(f, "gsview_orientation"); if (epsf_warn) send_prolog(f, "gsview_epswarn"); } /* Create and open a scratch file with a given name prefix. */ /* Write the actual file name at fname. */ FILE * gp_open_scratch_file(const char *prefix, char *fname, const char *mode) { char *temp; if ( (temp = getenv("TEMP")) == NULL ) *fname = 0; else { strcpy(fname, temp); /* Prevent X's in path from being converted by mktemp. */ for ( temp = fname; *temp; temp++ ) *temp = tolower(*temp); if ( strlen(fname) && (fname[strlen(fname)-1] != '\\') ) strcat(fname, "\\"); } strcat(fname, prefix); strcat(fname, "XXXXXX"); mktemp(fname); return fopen(fname, mode); } /* reopen dfile */ /* if dfile time/date or length has changed, kill gswin and rescan the file */ BOOL dfreopen() { struct ftime thisftime; long thisflength; if (doc == (struct document *)NULL) return TRUE; dfclose(); if (dfname[0] == '\0') return TRUE; if ( (dfile = fopen(efname[0] ? efname : dfname, "rb")) == (FILE *)NULL ) { if (debug) MessageBox(hwndimg, "file missing", "dfreopen", MB_OK); dfname[0] = '\0'; return FALSE; } getftime(fileno(dfile), &thisftime); thisflength = filelength(fileno(dfile)); if ( (thisflength != dflength) || memcmp(&thisftime, &dftime, sizeof(thisftime)) ) { if (debug) MessageBox(hwndimg, "file changed", "dfreopen", MB_OK); /* file may have changed beyond recognition so we must kill gswin */ gswin_close(); if (dsc_scan(dfname)) if ( (dfile = fopen(efname[0] ? efname : dfname, "rb")) == (FILE *)NULL ) { dfname[0] = '\0'; return FALSE; } } return TRUE; } void dfclose() { if (dfile != (FILE *)NULL) fclose(dfile); dfile = (FILE *)NULL; } /* scan file for PostScript Document Structuring Conventions */ /* return TRUE if valid DSC comments found */ BOOL dsc_scan(char *filename) { unsigned char eps[4]; strcpy(dfname, filename); dfclose(); if ((efname[0] != '\0') && !debug) unlink(efname); efname[0] = '\0'; if ( (dfile = fopen(dfname, "rb")) == (FILE *)NULL ) { dfname[0] = '\0'; return FALSE; } getftime(fileno(dfile), &dftime); dflength = filelength(fileno(dfile)); if (page_list.select) free(page_list.select); page_list.select = NULL; if (doc) psfree(doc); is_ctrld = FALSE; fread(eps, 1, 4, dfile); if ((eps[0]==0xc5) && (eps[1]==0xd0) && (eps[2]==0xd3) && (eps[3]==0xc6)) extract_eps(); else preview = 0; doc = psscan(dfile); if (doc == (struct document *)NULL) { dfclose(); return FALSE; } if (eps[0] == '\004') is_ctrld = TRUE; if (!preview && doc->beginpreview) preview = IDS_EPSI; page_list.select = (BOOL *)malloc( doc->numpages * sizeof(BOOL) ); return TRUE; } /* Copy specified pages from dfile to file f */ void dsc_getpages(FILE *f, int first, int last) { int i, page; for (i=first-1; ipages) { fprintf(f,"(Page: %s %d\\n) print flush\r\n", doc->pages[page].label ? doc->pages[page].label : " ", page+1); pscopy(dfile, f, doc->pages[page].begin, doc->pages[page].end); } else { fprintf(f,"(Page: %d\\n) print flush\r\n",page); pscopy(dfile, f, doc->endsetup, doc->endtrailer); } } } /* Copy dsc header to file f */ void dsc_header(FILE *f) { char *p; fputs("(Displaying ",f); for (p=dfname; *p; p++) { if (*p != '\\') fputc(*p,f); else fputc('/',f); } fputs("\\n) print flush\r\n",f); pscopy(dfile, f, doc->beginheader, doc->endheader); pscopy(dfile, f, doc->begindefaults, doc->enddefaults); pscopy(dfile, f, doc->beginprolog, doc->endprolog); pscopy(dfile, f, doc->beginsetup, doc->endsetup); } /* Send commands to gswin to display page */ void dsc_dopage(void) { info_wait(TRUE); if (!saved) { fix_orientation(cfile); dsc_header(cfile); } dsc_getpages(cfile,pagenum,pagenum); pipeflush(); } /* skip pages */ void dsc_skip(int skip) { if ( (skip == 0) || ((skip > 0) && (pagenum == doc->numpages)) || ((skip < 0) && (pagenum == 1)) || (doc->numpages == 0) ) { play_sound(SOUND_NOPAGE); info_wait(FALSE); return; } pagenum += skip; if (pagenum > (int)doc->numpages) pagenum = doc->numpages; if (pagenum < 1) pagenum = 1; info_wait(TRUE); if (page_ready) next_page(); if (gswin_open()) dsc_dopage(); } /* reverse zero based page number if needed */ int map_page(int page) { if (doc->pageorder == DESCEND) return (doc->numpages - 1) - page; return page; }