X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=pdf%2Fxpdf%2Fxpdf.cc;h=ff5455031535202237a758ff383dab047c40cfa6;hb=d912e30b579ee21466148f6ff4450442fc3a4064;hp=edd1c758e29caad1f432d05c47eb61f2758a6bec;hpb=d9f9a6449f377b4c933b75d57541b19c6d088994;p=evince.git diff --git a/pdf/xpdf/xpdf.cc b/pdf/xpdf/xpdf.cc index edd1c758..ff545503 100644 --- a/pdf/xpdf/xpdf.cc +++ b/pdf/xpdf/xpdf.cc @@ -2,14 +2,16 @@ // // xpdf.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== +#include #include #include #include #include +#include #include #include #include @@ -18,6 +20,7 @@ #include "parseargs.h" #include "gfile.h" #include "gmem.h" +#include "GlobalParams.h" #include "LTKAll.h" #include "Object.h" #include "Stream.h" @@ -32,7 +35,6 @@ #include "LTKOutputDev.h" #include "PSOutputDev.h" #include "TextOutputDev.h" -#include "Params.h" #include "Error.h" #include "config.h" @@ -51,18 +53,58 @@ typedef char *XPointer; #ifndef XK_Page_Down #define XK_Page_Down 0xFF56 #endif +#ifndef XK_KP_Home +#define XK_KP_Home 0xFF95 +#endif +#ifndef XK_KP_Left +#define XK_KP_Left 0xFF96 +#endif +#ifndef XK_KP_Up +#define XK_KP_Up 0xFF97 +#endif +#ifndef XK_KP_Right +#define XK_KP_Right 0xFF98 +#endif +#ifndef XK_KP_Down +#define XK_KP_Down 0xFF99 +#endif +#ifndef XK_KP_Prior +#define XK_KP_Prior 0xFF9A +#endif +#ifndef XK_KP_Page_Up +#define XK_KP_Page_Up 0xFF9A +#endif +#ifndef XK_KP_Next +#define XK_KP_Next 0xFF9B +#endif +#ifndef XK_KP_Page_Down +#define XK_KP_Page_Down 0xFF9B +#endif +#ifndef XK_KP_End +#define XK_KP_End 0xFF9C +#endif +#ifndef XK_KP_Begin +#define XK_KP_Begin 0xFF9D +#endif +#ifndef XK_KP_Insert +#define XK_KP_Insert 0xFF9E +#endif +#ifndef XK_KP_Delete +#define XK_KP_Delete 0xFF9F +#endif //------------------------------------------------------------------------ // misc constants / enums //------------------------------------------------------------------------ -#define remoteCmdLength 256 +#define remoteCmdLength 512 enum XpdfMenuItem { menuOpen, + menuReload, menuSavePDF, - menuRotateLeft, - menuRotateRight, + menuRotateCCW, + menuRotateCW, menuQuit }; @@ -72,7 +114,9 @@ enum XpdfMenuItem { // loadFile / displayPage static GBool loadFile(GString *fileName); -static void displayPage(int page1, int zoom1, int rotate1); +static void displayPage(int page1, int zoomA, int rotateA, GBool addToHist); +static void displayDest(LinkDest *dest, int zoomA, int rotateA, + GBool addToHist); // key press and menu callbacks static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers, @@ -92,11 +136,14 @@ static void mouseDragCbk(LTKWidget *widget, int widgetNum, // button callbacks static void nextPageCbk(LTKWidget *button, int n, GBool on); static void nextTenPageCbk(LTKWidget *button, int n, GBool on); +static void gotoNextPage(int inc, GBool top); static void prevPageCbk(LTKWidget *button, int n, GBool on); static void prevTenPageCbk(LTKWidget *button, int n, GBool on); +static void gotoPrevPage(int dec, GBool top, GBool bottom); +static void backCbk(LTKWidget *button, int n, GBool on); +static void forwardCbk(LTKWidget *button, int n, GBool on); static void pageNumCbk(LTKWidget *textIn, int n, GString *text); -static void zoomInCbk(LTKWidget *button, int n, GBool on); -static void zoomOutCbk(LTKWidget *button, int n, GBool on); +static void zoomMenuCbk(LTKMenuItem *item); static void postScriptCbk(LTKWidget *button, int n, GBool on); static void aboutCbk(LTKWidget *button, int n, GBool on); static void quitCbk(LTKWidget *button, int n, GBool on); @@ -107,6 +154,7 @@ static void scrollHorizCbk(LTKWidget *scrollbar, int n, int val); // misc callbacks static void layoutCbk(LTKWindow *win1); +static void updateScrollbars(); static void propChangeCbk(LTKWindow *win1, Atom atom); // selection @@ -117,6 +165,9 @@ static void mapOpenDialog(); static void openButtonCbk(LTKWidget *button, int n, GBool on); static void openSelectCbk(LTKWidget *widget, int n, GString *name); +// "Reload" +static void reloadCbk(); + // "Save PDF" dialog static void mapSaveDialog(); static void saveButtonCbk(LTKWidget *button, int n, GBool on); @@ -129,6 +180,9 @@ static void psButtonCbk(LTKWidget *button, int n, GBool on); // "About" window static void mapAboutWin(); static void closeAboutCbk(LTKWidget *button, int n, GBool on); +static void aboutLayoutCbk(LTKWindow *winA); +static void aboutScrollVertCbk(LTKWidget *scrollbar, int n, int val); +static void aboutScrollHorizCbk(LTKWidget *scrollbar, int n, int val); // "Find" window static void findCbk(LTKWidget *button, int n, GBool on); @@ -140,87 +194,172 @@ static void doFind(char *s); static void killCbk(LTKWindow *win1); //------------------------------------------------------------------------ -// GUI includes +// "About" window text //------------------------------------------------------------------------ -#include "xpdfIcon.xpm" -#include "leftArrow.xbm" -#include "dblLeftArrow.xbm" -#include "rightArrow.xbm" -#include "dblRightArrow.xbm" -#include "zoomIn.xbm" -#include "zoomOut.xbm" -#include "find.xbm" -#include "postscript.xbm" -#include "about.xbm" -#include "xpdf-ltk.h" +static char *aboutWinText[] = { + "X X d fff", + " X X d f f", + " X X d f", + " X pppp dddd ffff", + " X X p p d d f", + " X X p p d d f", + "X X pppp dddd f Version " xpdfVersion, + " p", + " p", + " p", + "", + xpdfCopyright, + "", + "http://www.foolabs.com/xpdf/", + "derekn@foolabs.com", + "", + "Licensed under the GNU General Public License (GPL).", + "See the 'COPYING' file for details.", + "", + "Supports PDF version " supportedPDFVersionStr ".", + "", + "The PDF data structures, operators, and specification", + "are copyright 1985-2001 Adobe Systems Inc.", + "", + "Mouse bindings:", + " button 1: select text / follow link", + " button 2: pan window", + " button 3: menu", + "", + "Key bindings:", + " o = open file", + " r = reload", + " f = find text", + " n = = next page", + " p = = previous page", + " = scroll down", + " = = scroll up", + " v = forward (history path)", + " b = backward (history path)", + " 0 / + / - = zoom zero / in / out", + " z / w = zoom page / page width", + " ctrl-L = redraw", + " q = quit", + " / = top / bottom of page", + " = scroll", + "", + "For more information, please read the xpdf(1) man page.", + NULL +}; //------------------------------------------------------------------------ // command line options //------------------------------------------------------------------------ -static XrmOptionDescRec opts[] = { - {"-display", ".display", XrmoptionSepArg, NULL}, - {"-foreground", ".foreground", XrmoptionSepArg, NULL}, - {"-fg", ".foreground", XrmoptionSepArg, NULL}, - {"-background", ".background", XrmoptionSepArg, NULL}, - {"-bg", ".background", XrmoptionSepArg, NULL}, - {"-geometry", ".geometry", XrmoptionSepArg, NULL}, - {"-g", ".geometry", XrmoptionSepArg, NULL}, - {"-font", ".font", XrmoptionSepArg, NULL}, - {"-fn", ".font", XrmoptionSepArg, NULL}, - {"-cmap", ".installCmap", XrmoptionNoArg, (XPointer)"on"}, - {"-rgb", ".rgbCubeSize", XrmoptionSepArg, NULL}, - {"-papercolor", ".paperColor", XrmoptionSepArg, NULL}, - {"-z", ".initialZoom", XrmoptionSepArg, NULL}, - {"-ps", ".psFile", XrmoptionSepArg, NULL}, - {"-paperw", ".psPaperWidth", XrmoptionSepArg, NULL}, - {"-paperh", ".psPaperHeight", XrmoptionSepArg, NULL}, - {"-level1", ".psLevel1", XrmoptionNoArg, (XPointer)"false"}, - {NULL} -}; - -GBool printCommands = gFalse; -static GBool printHelp = gFalse; +static char initialZoomStr[32] = ""; +static char t1libControlStr[16] = ""; +static char freetypeControlStr[16] = ""; +static char psFileArg[256]; +static char paperSize[15] = ""; +static int paperWidth = 0; +static int paperHeight = 0; +static GBool level1 = gFalse; +static char textEncName[128] = ""; +static char textEOL[16] = ""; +static char ownerPassword[33] = ""; +static char userPassword[33] = ""; +static GBool fullScreen = gFalse; static char remoteName[100] = "xpdf_"; static GBool doRemoteRaise = gFalse; static GBool doRemoteQuit = gFalse; +static GBool printCommands = gFalse; +static GBool quiet = gFalse; +static char cfgFileName[256] = ""; +static GBool printVersion = gFalse; +static GBool printHelp = gFalse; +static GBool viKeys = gFalse; static ArgDesc argDesc[] = { - {"-err", argFlag, &errorsToTTY, 0, - "send error messages to /dev/tty instead of stderr"}, - {"-z", argIntDummy, NULL, 0, - "initial zoom level (-5..5)"}, {"-g", argStringDummy, NULL, 0, "initial window geometry"}, {"-geometry", argStringDummy, NULL, 0, "initial window geometry"}, - {"-remote", argString, remoteName + 5, sizeof(remoteName) - 5, - "start/contact xpdf remote server with specified name"}, - {"-raise", argFlag, &doRemoteRaise, 0, - "raise xpdf remote server window (with -remote only)"}, - {"-quit", argFlag, &doRemoteQuit, 0, - "kill xpdf remote server (with -remote only)"}, + {"-title", argStringDummy, NULL, 0, + "window title"}, {"-cmap", argFlagDummy, NULL, 0, "install a private colormap"}, {"-rgb", argIntDummy, NULL, 0, "biggest RGB cube to allocate (default is 5)"}, + {"-rv", argFlagDummy, NULL, 0, + "reverse video"}, {"-papercolor", argStringDummy, NULL, 0, "color of paper background"}, - {"-ps", argStringDummy, NULL, 0, - "default PostScript file/command name"}, - {"-paperw", argIntDummy, NULL, 0, + {"-z", argString, initialZoomStr, sizeof(initialZoomStr), + "initial zoom level (-5..5, page, width)"}, +#if HAVE_T1LIB_H + {"-t1lib", argString, t1libControlStr, sizeof(t1libControlStr), + "t1lib font rasterizer control: none, plain, low, high"}, +#endif +#if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H + {"-freetype", argString, freetypeControlStr, sizeof(freetypeControlStr), + "FreeType font rasterizer control: none, plain, low, high"}, +#endif + {"-ps", argString, psFileArg, sizeof(psFileArg), + "default PostScript file name or command"}, + {"-paper", argString, paperSize, sizeof(paperSize), + "paper size (letter, legal, A4, A3)"}, + {"-paperw", argInt, &paperWidth, 0, "paper width, in points"}, - {"-paperh", argIntDummy, NULL, 0, + {"-paperh", argInt, &paperHeight, 0, "paper height, in points"}, - {"-level1", argFlagDummy, NULL, 0, + {"-level1", argFlag, &level1, 0, "generate Level 1 PostScript"}, + {"-enc", argString, textEncName, sizeof(textEncName), + "output text encoding name"}, + {"-eol", argString, textEOL, sizeof(textEOL), + "output end-of-line convention (unix, dos, or mac)"}, + {"-opw", argString, ownerPassword, sizeof(ownerPassword), + "owner password (for encrypted files)"}, + {"-upw", argString, userPassword, sizeof(userPassword), + "user password (for encrypted files)"}, + {"-fullscreen", argFlag, &fullScreen, 0, + "run in full-screen (presentation) mode"}, + {"-remote", argString, remoteName + 5, sizeof(remoteName) - 5, + "start/contact xpdf remote server with specified name"}, + {"-raise", argFlag, &doRemoteRaise, 0, + "raise xpdf remote server window (with -remote only)"}, + {"-quit", argFlag, &doRemoteQuit, 0, + "kill xpdf remote server (with -remote only)"}, {"-cmd", argFlag, &printCommands, 0, "print commands as they're executed"}, + {"-q", argFlag, &quiet, 0, + "don't print any messages or errors"}, + {"-cfg", argString, cfgFileName, sizeof(cfgFileName), + "configuration file to use in place of .xpdfrc"}, + {"-v", argFlag, &printVersion, 0, + "print copyright and version info"}, {"-h", argFlag, &printHelp, 0, "print usage information"}, {"-help", argFlag, &printHelp, 0, "print usage information"}, + {"--help", argFlag, &printHelp, 0, + "print usage information"}, + {"-?", argFlag, &printHelp, 0, + "print usage information"}, + {NULL} +}; + +static XrmOptionDescRec opts[] = { + {"-display", ".display", XrmoptionSepArg, NULL}, + {"-foreground", ".foreground", XrmoptionSepArg, NULL}, + {"-fg", ".foreground", XrmoptionSepArg, NULL}, + {"-background", ".background", XrmoptionSepArg, NULL}, + {"-bg", ".background", XrmoptionSepArg, NULL}, + {"-geometry", ".geometry", XrmoptionSepArg, NULL}, + {"-g", ".geometry", XrmoptionSepArg, NULL}, + {"-font", ".font", XrmoptionSepArg, NULL}, + {"-fn", ".font", XrmoptionSepArg, NULL}, + {"-title", ".title", XrmoptionSepArg, NULL}, + {"-cmap", ".installCmap", XrmoptionNoArg, (XPointer)"on"}, + {"-rgb", ".rgbCubeSize", XrmoptionSepArg, NULL}, + {"-rv", ".reverseVideo", XrmoptionNoArg, (XPointer)"true"}, + {"-papercolor", ".paperColor", XrmoptionSepArg, NULL}, {NULL} }; @@ -229,14 +368,16 @@ static ArgDesc argDesc[] = { //------------------------------------------------------------------------ // zoom factor is 1.2 (similar to DVI magsteps) -#define minZoom -5 -#define maxZoom 5 +#define minZoom -5 +#define maxZoom 5 +#define zoomPage 100 +#define zoomWidth 101 +#define defZoom 1 static int zoomDPI[maxZoom - minZoom + 1] = { 29, 35, 42, 50, 60, 72, 86, 104, 124, 149, 179 }; -#define defZoom 1 static PDFDoc *doc; @@ -247,6 +388,8 @@ static int zoom; static int rotate; static GBool quit; +static time_t modTime; // last modification time of PDF file + static LinkAction *linkAction; // mouse pointer is over this link static int // coordinates of current selection: selectXMin, selectYMin, // (xMin==xMax || yMin==yMax) means there @@ -255,7 +398,19 @@ static GBool lastDragLeft; // last dragged selection edge was left/right static GBool lastDragTop; // last dragged selection edge was top/bottom static int panMX, panMY; // last mouse position for pan -static GString *defPSFileName; +struct History { + GString *fileName; + int page; +}; +#define historySize 50 +static History // page history queue + history[historySize]; +static int historyCur; // currently displayed page +static int historyBLen; // number of valid entries backward from + // current entry +static int historyFLen; // number of valid entries forward from + // current entry + static GString *psFileName; static int psFirstPage, psLastPage; @@ -263,22 +418,45 @@ static GString *fileReqDir; // current directory for file requesters static GString *urlCommand; // command to execute for URI links +static GString *windowTitle; // window title string + static LTKApp *app; static Display *display; static LTKWindow *win; +static LTKMenu *zoomMenu; static LTKScrollingCanvas *canvas; static LTKScrollbar *hScrollbar, *vScrollbar; static LTKTextIn *pageNumText; static LTKLabel *numPagesLabel; static LTKLabel *linkLabel; +static LTKMenuButton *zoomMenuBtn; static LTKWindow *aboutWin; +static LTKList *aboutList; +static LTKScrollbar *aboutHScrollbar, *aboutVScrollbar; static LTKWindow *psDialog; static LTKWindow *openDialog; static LTKWindow *saveDialog; static LTKWindow *findWin; +static LTKTextIn *findTextIn; static Atom remoteAtom; static GC selectGC; +//------------------------------------------------------------------------ +// GUI includes +//------------------------------------------------------------------------ + +#include "xpdfIcon.xpm" +#include "leftArrow.xbm" +#include "dblLeftArrow.xbm" +#include "rightArrow.xbm" +#include "dblRightArrow.xbm" +#include "backArrow.xbm" +#include "forwardArrow.xbm" +#include "find.xbm" +#include "postscript.xbm" +#include "about.xbm" +#include "xpdf-ltk.h" + //------------------------------------------------------------------------ // main program //------------------------------------------------------------------------ @@ -290,12 +468,20 @@ int main(int argc, char *argv[]) { LTKMenu *menu; GString *name; GString *title; + GString *initialZoom; + GBool reverseVideo; unsigned long paperColor; + GBool installCmap; + int rgbCubeSize; int pg; + GString *destName; + LinkDest *dest; int x, y; Guint width, height; + double width1, height1; GBool ok; char s[20]; + int i; int ret; // initialize @@ -304,23 +490,60 @@ int main(int argc, char *argv[]) { out = NULL; remoteAtom = None; doc = NULL; - xref = NULL; psFileName = NULL; fileReqDir = getCurrentDir(); ret = 0; // parse args - paperWidth = paperHeight = -1; ok = parseArgs(argDesc, &argc, argv); - // init error file - errorInit(); - // read config file - initParams(xpdfConfigFile); + globalParams = new GlobalParams(cfgFileName); + if (psFileArg[0]) { + globalParams->setPSFile(psFileArg); + } + if (paperSize[0]) { + if (!globalParams->setPSPaperSize(paperSize)) { + fprintf(stderr, "Invalid paper size\n"); + } + } else { + if (paperWidth) { + globalParams->setPSPaperWidth(paperWidth); + } + if (paperHeight) { + globalParams->setPSPaperHeight(paperHeight); + } + } + if (level1) { + globalParams->setPSLevel(psLevel1); + } + if (textEncName[0]) { + globalParams->setTextEncoding(textEncName); + } + if (textEOL[0]) { + if (!globalParams->setTextEOL(textEOL)) { + fprintf(stderr, "Bad '-eol' value on command line\n"); + } + } + if (initialZoomStr[0]) { + globalParams->setInitialZoom(initialZoomStr); + } + if (t1libControlStr[0]) { + if (!globalParams->setT1libControl(t1libControlStr)) { + fprintf(stderr, "Bad '-t1lib' value on command line\n"); + } + } + if (freetypeControlStr[0]) { + if (!globalParams->setFreeTypeControl(freetypeControlStr)) { + fprintf(stderr, "Bad '-freetype' value on command line\n"); + } + } + if (quiet) { + globalParams->setErrQuiet(quiet); + } // create LTKApp (and parse X-related args) - app = new LTKApp("xpdf", opts, &argc, argv); + app = new LTKApp("xpdf", "Xpdf", opts, &argc, argv); app->setKillCbk(&killCbk); display = app->getDisplay(); @@ -331,21 +554,29 @@ int main(int argc, char *argv[]) { ok = ok && remoteName[5] && argc == 1; else ok = ok && argc >= 1 && argc <= 3; - if (!ok || printHelp) { + if (!ok || printVersion || printHelp) { fprintf(stderr, "xpdf version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); - printUsage("xpdf", "[ []]", argDesc); + if (!printVersion) { + printUsage("xpdf", "[ [ | +]]", argDesc); + } ret = 1; goto done2; } - if (argc >= 2) + if (argc >= 2) { name = new GString(argv[1]); - else + } else { name = NULL; - if (argc == 3) - pg = atoi(argv[2]); - else - pg = 1; + } + pg = 1; + destName = NULL; + if (argc == 3) { + if (argv[2][0] == '+') { + destName = new GString(&argv[2][1]); + } else { + pg = atoi(argv[2]); + } + } // look for already-running remote server if (remoteName[5]) { @@ -353,8 +584,14 @@ int main(int argc, char *argv[]) { xwin = XGetSelectionOwner(display, remoteAtom); if (xwin != None) { if (name) { - sprintf(cmd, "%c %d %.200s", doRemoteRaise ? 'D' : 'd', - pg, name->getCString()); + if (destName) { + sprintf(cmd, "%c +%.256s %.200s", doRemoteRaise ? 'D' : 'd', + destName->getCString(), name->getCString()); + delete destName; + } else { + sprintf(cmd, "%c %d %.200s", doRemoteRaise ? 'D' : 'd', + pg, name->getCString()); + } XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8, PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1); delete name; @@ -367,16 +604,21 @@ int main(int argc, char *argv[]) { } goto done2; } - if (doRemoteQuit) + if (doRemoteQuit) { + if (destName) { + delete destName; + } goto done2; + } } - // print banner - fprintf(errFile, "xpdf version %s\n", xpdfVersion); - fprintf(errFile, "%s\n", xpdfCopyright); + // no history yet + historyCur = historySize - 1; + historyBLen = historyFLen = 0; + for (i = 0; i < historySize; ++i) + history[i].fileName = NULL; // open PDF file - defPSFileName = app->getStringResource("psFile", NULL); if (name) { if (!loadFile(name)) { ret = 1; @@ -387,12 +629,20 @@ int main(int argc, char *argv[]) { } // check for legal page number - if (doc && (pg < 1 || pg > doc->getNumPages())) + if (doc && (pg < 1 || pg > doc->getNumPages())) { pg = 1; + } // create window - win = makeWindow(app); menu = makeMenu(); + if (fullScreen) { + zoomMenu = NULL; + win = makeFullScreenWindow(app); + win->setDecorated(gFalse); + } else { + zoomMenu = makeZoomMenu(); + win = makeWindow(app); + } win->setMenu(menu); canvas = (LTKScrollingCanvas *)win->findWidget("canvas"); hScrollbar = (LTKScrollbar *)win->findWidget("hScrollbar"); @@ -400,58 +650,105 @@ int main(int argc, char *argv[]) { pageNumText = (LTKTextIn *)win->findWidget("pageNum"); numPagesLabel = (LTKLabel *)win->findWidget("numPages"); linkLabel = (LTKLabel *)win->findWidget("link"); + zoomMenuBtn = (LTKMenuButton *)win->findWidget("zoom"); win->setKeyCbk(&keyPressCbk); win->setLayoutCbk(&layoutCbk); canvas->setButtonPressCbk(&buttonPressCbk); canvas->setButtonReleaseCbk(&buttonReleaseCbk); canvas->setMouseMoveCbk(&mouseMoveCbk); canvas->setMouseDragCbk(&mouseDragCbk); - hScrollbar->setRepeatPeriod(0); - vScrollbar->setRepeatPeriod(0); + if (!fullScreen) { + hScrollbar->setRepeatPeriod(0); + vScrollbar->setRepeatPeriod(0); + } + + // get parameters + urlCommand = globalParams->getURLCommand(); // get X resources - paperWidth = app->getIntResource("psPaperWidth", defPaperWidth); - paperHeight = app->getIntResource("psPaperHeight", defPaperHeight); - psOutLevel1 = app->getBoolResource("psLevel1", gFalse); - urlCommand = app->getStringResource("urlCommand", NULL); + windowTitle = app->getStringResource("title", NULL); installCmap = app->getBoolResource("installCmap", gFalse); - if (installCmap) + if (installCmap) { win->setInstallCmap(gTrue); + } rgbCubeSize = app->getIntResource("rgbCubeSize", defaultRGBCube); - paperColor = app->getColorResource("paperColor", "white", - WhitePixel(display, app->getScreenNum()), - NULL); - zoom = app->getIntResource("initialZoom", defZoom); - if (zoom < minZoom) - zoom = minZoom; - else if (zoom > maxZoom) - zoom = maxZoom; + reverseVideo = app->getBoolResource("reverseVideo", gFalse); + paperColor = app->getColorResource( + "paperColor", + reverseVideo ? (char *)"black" : (char *)"white", + reverseVideo ? BlackPixel(display, app->getScreenNum()) + : WhitePixel(display, app->getScreenNum()), + NULL); + if (fullScreen) { + zoom = zoomPage; + } else { + initialZoom = globalParams->getInitialZoom(); + if (!initialZoom->cmp("page")) { + zoom = zoomPage; + i = maxZoom - minZoom + 2; + } else if (!initialZoom->cmp("width")) { + zoom = zoomWidth; + i = maxZoom - minZoom + 3; + } else { + zoom = atoi(initialZoom->getCString()); + if (zoom < minZoom) { + zoom = minZoom; + } else if (zoom > maxZoom) { + zoom = maxZoom; + } + i = zoom - minZoom; + } + zoomMenuBtn->setInitialMenuItem(zoomMenu->getItem(i)); + } + viKeys = app->getBoolResource("viKeys", gFalse); // get geometry - x = -1; - y = -1; - if (!doc) { - width = 612; - height = 792; - } else if (doc->getPageRotate(pg) == 90 || doc->getPageRotate(pg) == 270) { - width = (int)(doc->getPageHeight(pg) + 0.5); - height = (int)(doc->getPageWidth(pg) + 0.5); + if (fullScreen) { + x = y = 0; + width = app->getDisplayWidth(); + height = app->getDisplayHeight(); } else { - width = (int)(doc->getPageWidth(pg) + 0.5); - height = (int)(doc->getPageHeight(pg) + 0.5); + x = y = -1; + width = height = 0; + app->getGeometryResource("geometry", &x, &y, &width, &height); + if (width == 0 || height == 0) { + if (!doc || doc->getNumPages() == 0) { + width1 = 612; + height1 = 792; + } else if (doc->getPageRotate(pg) == 90 || + doc->getPageRotate(pg) == 270) { + width1 = doc->getPageHeight(pg); + height1 = doc->getPageWidth(pg); + } else { + width1 = doc->getPageWidth(pg); + height1 = doc->getPageHeight(pg); + } + if (zoom == zoomPage || zoom == zoomWidth) { + width = (int)((width1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5); + height = (int)((height1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5); + } else { + width = (int)((width1 * zoomDPI[zoom - minZoom]) / 72 + 0.5); + height = (int)((height1 * zoomDPI[zoom - minZoom]) / 72 + 0.5); + } + width += 28; + height += 56; + if (width > (Guint)app->getDisplayWidth() - 100) { + width = app->getDisplayWidth() - 100; + } + if (height > (Guint)app->getDisplayHeight() - 100) { + height = app->getDisplayHeight() - 100; + } + } } - width = (width * zoomDPI[zoom - minZoom]) / 72 + 28; - if (width > (Guint)app->getDisplayWidth() - 100) - width = app->getDisplayWidth() - 100; - height = (height * zoomDPI[zoom - minZoom]) / 72 + 56; - if (height > (Guint)app->getDisplayHeight() - 100) - height = app->getDisplayHeight() - 100; - app->getGeometryResource("geometry", &x, &y, &width, &height); // finish setting up window - sprintf(s, "of %d", doc ? doc->getNumPages() : 0); - numPagesLabel->setText(s); - if (name) { + if (!fullScreen) { + sprintf(s, "of %d", doc ? doc->getNumPages() : 0); + numPagesLabel->setText(s); + } + if (windowTitle) { + title = windowTitle->copy(); + } else if (name) { title = new GString("xpdf: "); title->append(name); } else { @@ -479,10 +776,25 @@ int main(int argc, char *argv[]) { } // create output device - out = new LTKOutputDev(win, paperColor); + out = new LTKOutputDev(win, reverseVideo, paperColor, + installCmap, rgbCubeSize, !fullScreen); + out->startDoc(doc ? doc->getXRef() : (XRef *)NULL); // display first page - displayPage(pg, zoom, 0); + if (destName) { + if (doc) { + if ((dest = doc->findDest(destName))) { + displayDest(dest, zoom, 0, gTrue); + delete dest; + } else { + error(-1, "Unknown named destination '%s'", destName->getCString()); + displayPage(1, zoom, 0, gTrue); + } + } + delete destName; + } else { + displayPage(pg, zoom, 0, gTrue); + } // event loop quit = gFalse; @@ -497,42 +809,55 @@ int main(int argc, char *argv[]) { done2: // free stuff - if (out) + if (out) { delete out; - if (win) + } + if (win) { delete win; - if (aboutWin) + } + if (aboutWin) { delete aboutWin; - if (findWin) + } + if (findWin) { delete findWin; - if (app) + } + if (app) { delete app; - if (doc) + } + if (doc) { delete doc; - if (psFileName) + } + if (psFileName) { delete psFileName; - if (defPSFileName) - delete defPSFileName; - if (fileReqDir) + } + if (fileReqDir) { delete fileReqDir; - if (urlCommand) - delete urlCommand; - freeParams(); + } + if (windowTitle) { + delete windowTitle; + } + for (i = 0; i < historySize; ++i) { + if (history[i].fileName) { + delete history[i].fileName; + } + } + delete globalParams; // check for memory leaks - Object::memCheck(errFile); - gMemReport(errFile); + Object::memCheck(stderr); + gMemReport(stderr); return ret; } //------------------------------------------------------------------------ -// loadFile / displayPage +// loadFile / displayPage / displayDest //------------------------------------------------------------------------ static GBool loadFile(GString *fileName) { GString *title; PDFDoc *newDoc; + GString *ownerPW, *userPW; char s[20]; char *p; @@ -541,7 +866,23 @@ static GBool loadFile(GString *fileName) { win->setBusyCursor(gTrue); // open PDF file - newDoc = new PDFDoc(fileName); + if (ownerPassword[0]) { + ownerPW = new GString(ownerPassword); + } else { + ownerPW = NULL; + } + if (userPassword[0]) { + userPW = new GString(userPassword); + } else { + userPW = NULL; + } + newDoc = new PDFDoc(fileName, ownerPW, userPW, printCommands); + if (userPW) { + delete userPW; + } + if (ownerPW) { + delete ownerPW; + } if (!newDoc->isOk()) { delete newDoc; if (win) @@ -553,15 +894,21 @@ static GBool loadFile(GString *fileName) { if (doc) delete doc; doc = newDoc; + if (out) { + out->startDoc(doc->getXRef()); + } // nothing displayed yet page = -99; + // save the modification time + modTime = getModTime(fileName->getCString()); + // init PostScript output params if (psFileName) delete psFileName; - if (defPSFileName) { - psFileName = defPSFileName->copy(); + if (globalParams->getPSFile()) { + psFileName = globalParams->getPSFile()->copy(); } else { p = fileName->getCString() + fileName->getLength() - 4; if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) @@ -576,11 +923,15 @@ static GBool loadFile(GString *fileName) { // set up title, number-of-pages display; back to normal cursor if (win) { - title = new GString("xpdf: "); - title->append(fileName); - win->setTitle(title); - sprintf(s, "of %d", doc->getNumPages()); - numPagesLabel->setText(s); + if (!windowTitle) { + title = new GString("xpdf: "); + title->append(fileName); + win->setTitle(title); + } + if (!fullScreen) { + sprintf(s, "of %d", doc->getNumPages()); + numPagesLabel->setText(s); + } win->setBusyCursor(gFalse); } @@ -588,42 +939,176 @@ static GBool loadFile(GString *fileName) { return gTrue; } -static void displayPage(int page1, int zoom1, int rotate1) { +static void displayPage(int pageA, int zoomA, int rotateA, GBool addToHist) { + time_t modTime1; + double hDPI, vDPI, dpi; + int rot; char s[20]; + History *h; // check for document - if (!doc) + if (!doc || doc->getNumPages() == 0) return; + // check for changes to the file + modTime1 = getModTime(doc->getFileName()->getCString()); + if (modTime1 != modTime) { + if (loadFile(doc->getFileName()->copy())) { + if (pageA > doc->getNumPages()) { + pageA = doc->getNumPages(); + } + } + modTime = modTime1; + } + // busy cursor if (win) win->setBusyCursor(gTrue); // new page/zoom/rotate values - page = page1; - zoom = zoom1; - rotate = rotate1; + page = pageA; + zoom = zoomA; + rotate = rotateA; // initialize mouse-related stuff linkAction = NULL; win->setDefaultCursor(); - linkLabel->setText(NULL); + if (!fullScreen) { + linkLabel->setText(NULL); + } selectXMin = selectXMax = 0; selectYMin = selectYMax = 0; lastDragLeft = lastDragTop = gTrue; // draw the page - doc->displayPage(out, page, zoomDPI[zoom - minZoom], rotate, gTrue); - layoutCbk(win); + rot = rotate + doc->getPageRotate(page); + if (rot >= 360) + rot -= 360; + else if (rotate < 0) + rot += 360; + if (fullScreen) { + if (rot == 90 || rot == 270) { + hDPI = (win->getWidth() / doc->getPageHeight(page)) * 72; + vDPI = (win->getHeight() / doc->getPageWidth(page)) * 72; + } else { + hDPI = (win->getWidth() / doc->getPageWidth(page)) * 72; + vDPI = (win->getHeight() / doc->getPageHeight(page)) * 72; + } + dpi = (hDPI < vDPI) ? hDPI : vDPI; + } else if (zoom == zoomPage) { + if (rot == 90 || rot == 270) { + hDPI = (canvas->getWidth() / doc->getPageHeight(page)) * 72; + vDPI = (canvas->getHeight() / doc->getPageWidth(page)) * 72; + } else { + hDPI = (canvas->getWidth() / doc->getPageWidth(page)) * 72; + vDPI = (canvas->getHeight() / doc->getPageHeight(page)) * 72; + } + dpi = (hDPI < vDPI) ? hDPI : vDPI; + } else if (zoom == zoomWidth) { + if (rot == 90 || rot == 270) { + dpi = (canvas->getWidth() / doc->getPageHeight(page)) * 72; + } else { + dpi = (canvas->getWidth() / doc->getPageWidth(page)) * 72; + } + } else { + dpi = zoomDPI[zoom - minZoom]; + } + doc->displayPage(out, page, dpi, rotate, gTrue); + updateScrollbars(); // update page number display - sprintf(s, "%d", page); - pageNumText->setText(s); + if (!fullScreen) { + sprintf(s, "%d", page); + pageNumText->setText(s); + } + + // add to history + if (addToHist) { + if (++historyCur == historySize) + historyCur = 0; + h = &history[historyCur]; + if (h->fileName) + delete h->fileName; + h->fileName = doc->getFileName()->copy(); + h->page = page; + if (historyBLen < historySize) + ++historyBLen; + historyFLen = 0; + } // back to regular cursor win->setBusyCursor(gFalse); } +static void displayDest(LinkDest *dest, int zoomA, int rotateA, + GBool addToHist) { + Ref pageRef; + int pg; + int dx, dy; + + if (dest->isPageRef()) { + pageRef = dest->getPageRef(); + pg = doc->findPage(pageRef.num, pageRef.gen); + } else { + pg = dest->getPageNum(); + } + if (pg <= 0 || pg > doc->getNumPages()) { + pg = 1; + } + if (pg != page) { + displayPage(pg, zoomA, rotateA, addToHist); + } + + if (fullScreen) { + return; + } + switch (dest->getKind()) { + case destXYZ: + out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); + if (dest->getChangeLeft() || dest->getChangeTop()) { + if (dest->getChangeLeft()) { + hScrollbar->setPos(dx, canvas->getWidth()); + } + if (dest->getChangeTop()) { + vScrollbar->setPos(dy, canvas->getHeight()); + } + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + } + //~ what is the zoom parameter? + break; + case destFit: + case destFitB: + //~ do fit + hScrollbar->setPos(0, canvas->getWidth()); + vScrollbar->setPos(0, canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + break; + case destFitH: + case destFitBH: + //~ do fit + out->cvtUserToDev(0, dest->getTop(), &dx, &dy); + hScrollbar->setPos(0, canvas->getWidth()); + vScrollbar->setPos(dy, canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + break; + case destFitV: + case destFitBV: + //~ do fit + out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy); + hScrollbar->setPos(dx, canvas->getWidth()); + vScrollbar->setPos(0, canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + break; + case destFitR: + //~ do fit + out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); + hScrollbar->setPos(dx, canvas->getWidth()); + vScrollbar->setPos(dy, canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + break; + } +} + //------------------------------------------------------------------------ // key press and menu callbacks //------------------------------------------------------------------------ @@ -636,22 +1121,27 @@ static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers, case 'o': mapOpenDialog(); break; + case 'R': + case 'r': + reloadCbk(); + break; case 'F': case 'f': mapFindWin(); break; case 'N': case 'n': - nextPageCbk(NULL, 0, gTrue); + gotoNextPage(1, !(modifiers & Mod5Mask)); break; case 'P': case 'p': - prevPageCbk(NULL, 0, gTrue); + gotoPrevPage(1, !(modifiers & Mod5Mask), gFalse); break; case ' ': - if (vScrollbar->getPos() >= - canvas->getRealHeight() - canvas->getHeight()) { - nextPageCbk(NULL, 0, gTrue); + if (fullScreen || + vScrollbar->getPos() >= + canvas->getRealHeight() - canvas->getHeight()) { + gotoNextPage(1, gTrue); } else { vScrollbar->setPos(vScrollbar->getPos() + canvas->getHeight(), canvas->getHeight()); @@ -660,17 +1150,104 @@ static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers, break; case '\b': // bs case '\177': // del - if (vScrollbar->getPos() == 0) { - prevPageCbk(NULL, 0, gTrue); + if (fullScreen) { + gotoPrevPage(1, gTrue, gFalse); + } else if (vScrollbar->getPos() == 0) { + gotoPrevPage(1, gFalse, gTrue); } else { vScrollbar->setPos(vScrollbar->getPos() - canvas->getHeight(), canvas->getHeight()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); } break; + case 'v': + forwardCbk(NULL, 0, gTrue); + break; + case 'b': + backCbk(NULL, 0, gTrue); + break; + case 'g': + if (fullScreen) { + break; + } + pageNumText->selectAll(); + pageNumText->activate(gTrue); + break; + case 'h': // vi-style left + if (fullScreen) { + break; + } + if (viKeys) { + hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + } + break; + case 'l': // vi-style right + if (fullScreen) { + break; + } + if (viKeys) { + hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + } + break; + case 'k': // vi-style up + if (fullScreen) { + break; + } + if (viKeys) { + vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + } + break; + case 'j': // vi-style down + if (fullScreen) { + break; + } + if (viKeys) { + vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + } + break; + case '0': + if (fullScreen) { + break; + } + if (zoom != defZoom) { + zoomMenuBtn->setMenuItem(zoomMenu->getItem(defZoom - minZoom)); + } + break; + case '+': + if (fullScreen) { + break; + } + if (zoom >= minZoom && zoom < maxZoom) { + zoomMenuBtn->setMenuItem(zoomMenu->getItem(zoom + 1 - minZoom)); + } + break; + case '-': + if (fullScreen) { + break; + } + if (zoom > minZoom && zoom <= maxZoom) { + zoomMenuBtn->setMenuItem(zoomMenu->getItem(zoom - 1 - minZoom)); + } + break; + case 'z': + if (fullScreen) { + break; + } + zoomMenuBtn->setMenuItem(zoomMenu->getItem(maxZoom - minZoom + 2)); + break; + case 'w': + if (fullScreen) { + break; + } + zoomMenuBtn->setMenuItem(zoomMenu->getItem(maxZoom - minZoom + 3)); + break; case '\014': // ^L win->redraw(); - displayPage(page, zoom, rotate); + displayPage(page, zoom, rotate, gFalse); break; case 'Q': case 'q': @@ -680,11 +1257,19 @@ static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers, } else { switch (key) { case XK_Home: + case XK_KP_Home: + if (fullScreen) { + break; + } hScrollbar->setPos(0, canvas->getWidth()); vScrollbar->setPos(0, canvas->getHeight()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; case XK_End: + case XK_KP_End: + if (fullScreen) { + break; + } hScrollbar->setPos(canvas->getRealWidth() - canvas->getWidth(), canvas->getWidth()); vScrollbar->setPos(canvas->getRealHeight() - canvas->getHeight(), @@ -692,8 +1277,11 @@ static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers, canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; case XK_Page_Up: - if (vScrollbar->getPos() == 0) { - prevPageCbk(NULL, 0, gTrue); + case XK_KP_Page_Up: + if (fullScreen) { + gotoPrevPage(1, gTrue, gFalse); + } else if (vScrollbar->getPos() == 0) { + gotoPrevPage(1, gFalse, gTrue); } else { vScrollbar->setPos(vScrollbar->getPos() - canvas->getHeight(), canvas->getHeight()); @@ -701,9 +1289,11 @@ static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers, } break; case XK_Page_Down: - if (vScrollbar->getPos() >= - canvas->getRealHeight() - canvas->getHeight()) { - nextPageCbk(NULL, 0, gTrue); + case XK_KP_Page_Down: + if (fullScreen || + vScrollbar->getPos() >= + canvas->getRealHeight() - canvas->getHeight()) { + gotoNextPage(1, gTrue); } else { vScrollbar->setPos(vScrollbar->getPos() + canvas->getHeight(), canvas->getHeight()); @@ -711,18 +1301,34 @@ static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers, } break; case XK_Left: + case XK_KP_Left: + if (fullScreen) { + break; + } hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; case XK_Right: + case XK_KP_Right: + if (fullScreen) { + break; + } hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; case XK_Up: + case XK_KP_Up: + if (fullScreen) { + break; + } vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; case XK_Down: + case XK_KP_Down: + if (fullScreen) { + break; + } vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; @@ -737,20 +1343,23 @@ static void menuCbk(LTKMenuItem *item) { case menuOpen: mapOpenDialog(); break; + case menuReload: + reloadCbk(); + break; case menuSavePDF: if (doc) mapSaveDialog(); break; - case menuRotateLeft: + case menuRotateCCW: if (doc) { r = (rotate == 0) ? 270 : rotate - 90; - displayPage(page, zoom, r); + displayPage(page, zoom, r, gFalse); } break; - case menuRotateRight: + case menuRotateCW: if (doc) { r = (rotate == 270) ? 0 : rotate + 90; - displayPage(page, zoom, r); + displayPage(page, zoom, r, gFalse); } break; case menuQuit: @@ -765,13 +1374,53 @@ static void menuCbk(LTKMenuItem *item) { static void buttonPressCbk(LTKWidget *canvas1, int n, int mx, int my, int button, GBool dblClick) { - if (!doc) + if (!doc || doc->getNumPages() == 0) { return; - if (button == 1) { + } + switch (button) { + case 1: setSelection(mx, my, mx, my); - } else if (button == 2) { - panMX = mx - hScrollbar->getPos(); - panMY = my - vScrollbar->getPos(); + break; + case 2: + if (!fullScreen) { + panMX = mx - hScrollbar->getPos(); + panMY = my - vScrollbar->getPos(); + } + break; + case 4: // mouse wheel up + if (fullScreen) { + gotoPrevPage(1, gTrue, gFalse); + } else if (vScrollbar->getPos() == 0) { + gotoPrevPage(1, gFalse, gTrue); + } else { + vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + } + break; + case 5: // mouse wheel down + if (fullScreen || + vScrollbar->getPos() >= + canvas->getRealHeight() - canvas->getHeight()) { + gotoNextPage(1, gTrue); + } else { + vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + } + break; + case 6: // second mouse wheel right + if (fullScreen) { + return; + } + hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + break; + case 7: // second mouse wheel left + if (fullScreen) { + return; + } + hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + break; } } @@ -779,7 +1428,7 @@ static void buttonReleaseCbk(LTKWidget *canvas1, int n, int mx, int my, int button, GBool click) { GString *s; - if (!doc) + if (!doc || doc->getNumPages() == 0) return; if (button == 1) { @@ -789,6 +1438,8 @@ static void buttonReleaseCbk(LTKWidget *canvas1, int n, if (doc->okToCopy()) { s = out->getText(selectXMin, selectYMin, selectXMax, selectYMax); win->setSelection(NULL, s); + } else { + error(-1, "Copying of text from this document is not allowed."); } #endif @@ -807,11 +1458,10 @@ static void doLink(int mx, int my) { GString *namedDest; char *s; GString *fileName; - Ref pageRef; - int pg; + GString *actionName; double x, y; - int dx, dy; LTKButtonDialog *dialog; + int i; // look for a link out->cvtDevToUser(mx, my, &x, &y); @@ -854,64 +1504,13 @@ static void doLink(int mx, int my) { dest = doc->findDest(namedDest); delete namedDest; } - if (!dest) { - if (kind == actionGoToR) - displayPage(1, zoom, 0); + if (dest) { + displayDest(dest, zoom, rotate, gTrue); + delete dest; } else { - if (dest->isPageRef()) { - pageRef = dest->getPageRef(); - pg = doc->findPage(pageRef.num, pageRef.gen); - } else { - pg = dest->getPageNum(); + if (kind == actionGoToR) { + displayPage(1, zoom, 0, gTrue); } - if (pg > 0 && pg != page) - displayPage(pg, zoom, rotate); - else if (pg <= 0) - displayPage(1, zoom, rotate); - switch (dest->getKind()) { - case destXYZ: - out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); - if (dest->getChangeLeft() || dest->getChangeTop()) { - if (dest->getChangeLeft()) - hScrollbar->setPos(dx, canvas->getWidth()); - if (dest->getChangeTop()) - vScrollbar->setPos(dy, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - //~ what is the zoom parameter? - break; - case destFit: - case destFitB: - //~ do fit - hScrollbar->setPos(0, canvas->getWidth()); - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case destFitH: - case destFitBH: - //~ do fit - out->cvtUserToDev(0, dest->getTop(), &dx, &dy); - hScrollbar->setPos(0, canvas->getWidth()); - vScrollbar->setPos(dy, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case destFitV: - case destFitBV: - //~ do fit - out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy); - hScrollbar->setPos(dx, canvas->getWidth()); - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case destFitR: - //~ do fit - out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); - hScrollbar->setPos(dx, canvas->getWidth()); - vScrollbar->setPos(dy, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - } - delete dest; } break; @@ -929,7 +1528,7 @@ static void doLink(int mx, int my) { grabPath(doc->getFileName()->getCString()), s); if (!loadFile(fileName)) return; - displayPage(1, zoom, rotate); + displayPage(1, zoom, rotate, gTrue); } else { fileName = fileName->copy(); if (((LinkLaunch *)action)->getParams()) { @@ -958,13 +1557,30 @@ static void doLink(int mx, int my) { case actionURI: if (urlCommand) { for (s = urlCommand->getCString(); *s; ++s) { - if (s[0] == '%' && s[1] == 's') + if (s[0] == '%' && s[1] == 's') { break; + } } if (s) { - fileName = new GString(urlCommand->getCString(), - s - urlCommand->getCString()); - fileName->append(((LinkURI *)action)->getURI()); + fileName = ((LinkURI *)action)->getURI()->copy(); + // filter out any quote marks (' or ") to avoid a potential + // security hole + i = 0; + while (i < fileName->getLength()) { + if (fileName->getChar(i) == '"') { + fileName->del(i); + fileName->insert(i, "%22"); + i += 3; + } else if (fileName->getChar(i) == '\'') { + fileName->del(i); + fileName->insert(i, "%27"); + i += 3; + } else { + ++i; + } + } + fileName->insert(0, urlCommand->getCString(), + s - urlCommand->getCString()); fileName->append(s+2); } else { fileName = urlCommand->copy(); @@ -979,8 +1595,33 @@ static void doLink(int mx, int my) { system(fileName->getCString()); delete fileName; } else { - fprintf(errFile, "URI: %s\n", - ((LinkURI *)action)->getURI()->getCString()); + printf("URI: %s\n", ((LinkURI *)action)->getURI()->getCString()); + } + break; + + // Named action + case actionNamed: + actionName = ((LinkNamed *)action)->getName(); + if (!actionName->cmp("NextPage")) { + gotoNextPage(1, gTrue); + } else if (!actionName->cmp("PrevPage")) { + gotoPrevPage(1, gTrue, gFalse); + } else if (!actionName->cmp("FirstPage")) { + if (page != 1) { + displayPage(1, zoom, rotate, gTrue); + } + } else if (!actionName->cmp("LastPage")) { + if (page != doc->getNumPages()) { + displayPage(doc->getNumPages(), zoom, rotate, gTrue); + } + } else if (!actionName->cmp("GoBack")) { + backCbk(NULL, 0, gTrue); + } else if (!actionName->cmp("GoForward")) { + forwardCbk(NULL, 0, gTrue); + } else if (!actionName->cmp("Quit")) { + quitCbk(NULL, 0, gTrue); + } else { + error(-1, "Unknown named action: '%s'", actionName->getCString()); } break; @@ -998,39 +1639,47 @@ static void mouseMoveCbk(LTKWidget *widget, int widgetNum, int mx, int my) { LinkAction *action; char *s; - if (!doc) + if (!doc || doc->getNumPages() == 0) return; out->cvtDevToUser(mx, my, &x, &y); if ((action = doc->findLink(x, y))) { if (action != linkAction) { - if (!linkAction) + if (!linkAction) { win->setCursor(XC_hand2); + } linkAction = action; - s = NULL; - switch (linkAction->getKind()) { - case actionGoTo: - s = "[internal link]"; - break; - case actionGoToR: - s = ((LinkGoToR *)linkAction)->getFileName()->getCString(); - break; - case actionLaunch: - s = ((LinkLaunch *)linkAction)->getFileName()->getCString(); - break; - case actionURI: - s = ((LinkURI *)action)->getURI()->getCString(); - break; - case actionUnknown: - s = "[unknown link]"; - break; + if (!fullScreen) { + s = NULL; + switch (linkAction->getKind()) { + case actionGoTo: + s = "[internal link]"; + break; + case actionGoToR: + s = ((LinkGoToR *)linkAction)->getFileName()->getCString(); + break; + case actionLaunch: + s = ((LinkLaunch *)linkAction)->getFileName()->getCString(); + break; + case actionURI: + s = ((LinkURI *)action)->getURI()->getCString(); + break; + case actionNamed: + s = ((LinkNamed *)linkAction)->getName()->getCString(); + break; + case actionUnknown: + s = "[unknown link]"; + break; + } + linkLabel->setText(s); } - linkLabel->setText(s); } } else { if (linkAction) { linkAction = NULL; win->setDefaultCursor(); - linkLabel->setText(NULL); + if (!fullScreen) { + linkLabel->setText(NULL); + } } } } @@ -1099,7 +1748,7 @@ static void mouseDragCbk(LTKWidget *widget, int widgetNum, setSelection(xMin, yMin, xMax, yMax); // button 2: pan - } else if (button == 2) { + } else if (!fullScreen && button == 2) { mx -= hScrollbar->getPos(); my -= vScrollbar->getPos(); hScrollbar->setPos(hScrollbar->getPos() - (mx - panMX), @@ -1117,71 +1766,111 @@ static void mouseDragCbk(LTKWidget *widget, int widgetNum, //------------------------------------------------------------------------ static void nextPageCbk(LTKWidget *button, int n, GBool on) { - if (!doc) - return; - if (page < doc->getNumPages()) { - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - displayPage(page + 1, zoom, rotate); - } else { - XBell(display, 0); - } + gotoNextPage(1, gTrue); } static void nextTenPageCbk(LTKWidget *button, int n, GBool on) { + gotoNextPage(10, gTrue); +} + +static void gotoNextPage(int inc, GBool top) { int pg; - if (!doc) + if (!doc || doc->getNumPages() == 0) { return; + } if (page < doc->getNumPages()) { - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - if ((pg = page + 10) > doc->getNumPages()) + if (top && !fullScreen) { + vScrollbar->setPos(0, canvas->getHeight()); + canvas->setScrollPos(hScrollbar->getPos(), vScrollbar->getPos()); + } + if ((pg = page + inc) > doc->getNumPages()) { pg = doc->getNumPages(); - displayPage(pg, zoom, rotate); + } + displayPage(pg, zoom, rotate, gTrue); } else { XBell(display, 0); } } static void prevPageCbk(LTKWidget *button, int n, GBool on) { - if (!doc) - return; - if (page > 1) { - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - displayPage(page - 1, zoom, rotate); - } else { - XBell(display, 0); - } + gotoPrevPage(1, gTrue, gFalse); } static void prevTenPageCbk(LTKWidget *button, int n, GBool on) { + gotoPrevPage(10, gTrue, gFalse); +} + +static void gotoPrevPage(int dec, GBool top, GBool bottom) { int pg; - if (!doc) + if (!doc || doc->getNumPages() == 0) { return; + } if (page > 1) { - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - if ((pg = page - 10) < 1) + if (top && !fullScreen) { + vScrollbar->setPos(0, canvas->getHeight()); + canvas->setScrollPos(hScrollbar->getPos(), vScrollbar->getPos()); + } else if (bottom && !fullScreen) { + vScrollbar->setPos(canvas->getRealHeight() - canvas->getHeight(), + canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + } + if ((pg = page - dec) < 1) { pg = 1; - displayPage(pg, zoom, rotate); + } + displayPage(pg, zoom, rotate, gTrue); } else { XBell(display, 0); } } +static void backCbk(LTKWidget *button, int n, GBool on) { + if (historyBLen <= 1) { + XBell(display, 0); + return; + } + if (--historyCur < 0) + historyCur = historySize - 1; + --historyBLen; + ++historyFLen; + if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) { + if (!loadFile(history[historyCur].fileName->copy())) { + XBell(display, 0); + return; + } + } + displayPage(history[historyCur].page, zoom, rotate, gFalse); +} + +static void forwardCbk(LTKWidget *button, int n, GBool on) { + if (historyFLen == 0) { + XBell(display, 0); + return; + } + if (++historyCur == historySize) + historyCur = 0; + --historyFLen; + ++historyBLen; + if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) { + if (!loadFile(history[historyCur].fileName->copy())) { + XBell(display, 0); + return; + } + } + displayPage(history[historyCur].page, zoom, rotate, gFalse); +} + static void pageNumCbk(LTKWidget *textIn, int n, GString *text) { int page1; char s[20]; - if (!doc) + if (!doc || doc->getNumPages() == 0) return; page1 = atoi(text->getCString()); if (page1 >= 1 && page1 <= doc->getNumPages()) { if (page1 != page) - displayPage(page1, zoom, rotate); + displayPage(page1, zoom, rotate, gTrue); } else { XBell(display, 0); sprintf(s, "%d", page); @@ -1189,22 +1878,16 @@ static void pageNumCbk(LTKWidget *textIn, int n, GString *text) { } } -static void zoomInCbk(LTKWidget *button, int n, GBool on) { - if (!doc) - return; - if (zoom < maxZoom) - displayPage(page, zoom + 1, rotate); - else - XBell(display, 0); -} +static void zoomMenuCbk(LTKMenuItem *item) { + int z; -static void zoomOutCbk(LTKWidget *button, int n, GBool on) { - if (!doc) + if (!doc || doc->getNumPages() == 0) { return; - if (zoom > minZoom) - displayPage(page, zoom - 1, rotate); - else - XBell(display, 0); + } + z = item->getItemNum(); + if (z != zoom) { + displayPage(page, z, rotate, gFalse); + } } static void postScriptCbk(LTKWidget *button, int n, GBool on) { @@ -1240,6 +1923,17 @@ static void scrollHorizCbk(LTKWidget *scrollbar, int n, int val) { //------------------------------------------------------------------------ static void layoutCbk(LTKWindow *win1) { + if (page >= 0 && (zoom == zoomPage || zoom == zoomWidth)) { + displayPage(page, zoom, rotate, gFalse); + } else { + updateScrollbars(); + } +} + +static void updateScrollbars() { + if (fullScreen) { + return; + } hScrollbar->setLimits(0, canvas->getRealWidth() - 1); hScrollbar->setPos(hScrollbar->getPos(), canvas->getWidth()); hScrollbar->setScrollDelta(16); @@ -1255,19 +1949,23 @@ static void propChangeCbk(LTKWindow *win1, Atom atom) { Atom type; int format; Gulong size, remain; - char *p; + char *p, *q; GString *newFileName; int newPage; + GString *destName; + LinkDest *dest; // get command xwin = win1->getXWindow(); if (XGetWindowProperty(display, xwin, remoteAtom, 0, remoteCmdLength/4, True, remoteAtom, &type, &format, &size, &remain, - (Guchar **)&cmd) != Success) + (Guchar **)&cmd) != Success) { return; - if (size == 0) + } + if (size == 0) { return; + } // raise window if (cmd[0] == 'D' || cmd[0] == 'r'){ @@ -1278,10 +1976,22 @@ static void propChangeCbk(LTKWindow *win1, Atom atom) { // display file / page if (cmd[0] == 'd' || cmd[0] == 'D') { p = cmd + 2; - newPage = atoi(p); - if (!(p = strchr(p, ' '))) + q = strchr(p, ' '); + if (!q) { return; - newFileName = new GString(p + 1); + } + *q++ = '\0'; + newPage = 1; + destName = NULL; + if (*p == '+') { + destName = new GString(p + 1); + } else { + newPage = atoi(p); + } + if (!q) { + return; + } + newFileName = new GString(q); XFree((XPointer)cmd); if (!doc || newFileName->cmp(doc->getFileName())) { if (!loadFile(newFileName)) @@ -1289,8 +1999,16 @@ static void propChangeCbk(LTKWindow *win1, Atom atom) { } else { delete newFileName; } - if (newPage != page && newPage >= 1 && newPage <= doc->getNumPages()) - displayPage(newPage, zoom, rotate); + if (destName) { + if ((dest = doc->findDest(destName))) { + displayDest(dest, zoom, rotate, gTrue); + delete dest; + } + delete destName; + } else if (newPage != page && + newPage >= 1 && newPage <= doc->getNumPages()) { + displayPage(newPage, zoom, rotate, gTrue); + } // quit } else if (cmd[0] == 'q') { @@ -1365,6 +2083,9 @@ static void setSelection(int newXMin, int newYMin, int newXMax, int newYMax) { selectYMax = newYMax; // scroll canvas if necessary + if (fullScreen) { + return; + } needScroll = gFalse; w = canvas->getWidth(); h = canvas->getHeight(); @@ -1421,10 +2142,10 @@ static void openButtonCbk(LTKWidget *button, int n, GBool on) { sel = NULL; if (n == 1) { fileReq = (LTKFileReq *)openDialog->findWidget("fileReq"); - if ((sel = fileReq->getSelection())) - openSelectCbk(fileReq, 0, sel); - else - XBell(display, 0); + if (!(sel = fileReq->getSelection())) { + return; + } + openSelectCbk(fileReq, 0, sel); } if (openDialog) { if (sel) { @@ -1446,8 +2167,32 @@ static void openSelectCbk(LTKWidget *widget, int n, GString *name) { delete openDialog; openDialog = NULL; } - if (loadFile(name1)) - displayPage(1, zoom, rotate); + if (loadFile(name1)) { + if (!fullScreen) { + vScrollbar->setPos(0, canvas->getHeight()); + canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); + } + displayPage(1, zoom, rotate, gTrue); + } +} + +//------------------------------------------------------------------------ +// "Reload" +//------------------------------------------------------------------------ + +static void reloadCbk() { + int pg; + + if (!doc) { + return; + } + pg = page; + if (loadFile(doc->getFileName()->copy())) { + if (pg > doc->getNumPages()) { + pg = doc->getNumPages(); + } + displayPage(pg, zoom, rotate, gFalse); + } } //------------------------------------------------------------------------ @@ -1470,10 +2215,10 @@ static void saveButtonCbk(LTKWidget *button, int n, GBool on) { sel = NULL; if (n == 1) { fileReq = (LTKFileReq *)saveDialog->findWidget("fileReq"); - if ((sel = fileReq->getSelection())) - saveSelectCbk(fileReq, 0, sel); - else - XBell(display, 0); + if (!(sel = fileReq->getSelection())) { + return; + } + saveSelectCbk(fileReq, 0, sel); } if (saveDialog) { if (sel) { @@ -1554,13 +2299,15 @@ static void psButtonCbk(LTKWidget *button, int n, GBool on) { psDialog->setBusyCursor(gTrue); win->setBusyCursor(gTrue); if (doc->okToPrint()) { - psOut = new PSOutputDev(psFileName->getCString(), doc->getCatalog(), - psFirstPage, psLastPage, gTrue, gFalse); + psOut = new PSOutputDev(psFileName->getCString(), doc->getXRef(), + doc->getCatalog(), psFirstPage, psLastPage, + psModePS); if (psOut->isOk()) { - doc->displayPages(psOut, psFirstPage, psLastPage, - zoomDPI[zoom - minZoom], rotate); + doc->displayPages(psOut, psFirstPage, psLastPage, 72, 0, gFalse); } delete psOut; + } else { + error(-1, "Printing this document is not allowed."); } delete psDialog; @@ -1577,10 +2324,19 @@ static void psButtonCbk(LTKWidget *button, int n, GBool on) { //------------------------------------------------------------------------ static void mapAboutWin() { + int i; + if (aboutWin) { aboutWin->raise(); } else { aboutWin = makeAboutWindow(app); + aboutWin->setLayoutCbk(&aboutLayoutCbk); + aboutList = (LTKList *)aboutWin->findWidget("list"); + aboutHScrollbar = (LTKScrollbar *)aboutWin->findWidget("hScrollbar"); + aboutVScrollbar = (LTKScrollbar *)aboutWin->findWidget("vScrollbar"); + for (i = 0; aboutWinText[i]; ++i) { + aboutList->addLine(aboutWinText[i]); + } aboutWin->layout(-1, -1, -1, -1); aboutWin->map(); } @@ -1591,12 +2347,30 @@ static void closeAboutCbk(LTKWidget *button, int n, GBool on) { aboutWin = NULL; } +static void aboutLayoutCbk(LTKWindow *winA) { + aboutHScrollbar->setLimits(0, aboutList->getMaxWidth() - 1); + aboutHScrollbar->setPos(aboutHScrollbar->getPos(), aboutList->getWidth()); + aboutVScrollbar->setLimits(0, aboutList->getNumLines() - 1); + aboutVScrollbar->setPos(aboutVScrollbar->getPos(), + aboutList->getDisplayedLines()); +} + +static void aboutScrollVertCbk(LTKWidget *scrollbar, int n, int val) { + aboutList->scrollTo(val, aboutHScrollbar->getPos()); + XSync(display, False); +} + +static void aboutScrollHorizCbk(LTKWidget *scrollbar, int n, int val) { + aboutList->scrollTo(aboutVScrollbar->getPos(), val); + XSync(display, False); +} + //------------------------------------------------------------------------ // "Find" window //------------------------------------------------------------------------ static void findCbk(LTKWidget *button, int n, GBool on) { - if (!doc) + if (!doc || doc->getNumPages() == 0) return; mapFindWin(); } @@ -1608,17 +2382,16 @@ static void mapFindWin() { findWin = makeFindWindow(app); findWin->layout(-1, -1, -1, -1); findWin->map(); + findTextIn = (LTKTextIn *)findWin->findWidget("text"); } + findTextIn->activate(gTrue); } static void findButtonCbk(LTKWidget *button, int n, GBool on) { - LTKTextIn *textIn; - - if (!doc) + if (!doc || doc->getNumPages() == 0) return; if (n == 1) { - textIn = (LTKTextIn *)findWin->findWidget("text"); - doFind(textIn->getText()->getCString()); + doFind(findTextIn->getText()->getCString()); } else { delete findWin; findWin = NULL; @@ -1626,12 +2399,14 @@ static void findButtonCbk(LTKWidget *button, int n, GBool on) { } static void doFind(char *s) { + Unicode *u; TextOutputDev *textOut; int xMin, yMin, xMax, yMax; double xMin1, yMin1, xMax1, yMax1; int pg; GBool top; GString *s1; + int len, i; // check for zero-length string if (!s[0]) { @@ -1643,6 +2418,15 @@ static void doFind(char *s) { win->setBusyCursor(gTrue); findWin->setBusyCursor(gTrue); + // convert to Unicode +#if 1 //~ should do something more intelligent here + len = strlen(s); + u = (Unicode *)gmalloc(len * sizeof(Unicode)); + for (i = 0; i < len; ++i) { + u[i] = (Unicode)(s[i] & 0xff); + } +#endif + // search current page starting at current selection or top of page xMin = yMin = xMax = yMax = 0; if (selectXMin < selectXMax && selectYMin < selectYMax) { @@ -1652,26 +2436,31 @@ static void doFind(char *s) { } else { top = gTrue; } - if (out->findText(s, top, gTrue, &xMin, &yMin, &xMax, &yMax)) + if (out->findText(u, len, top, gTrue, &xMin, &yMin, &xMax, &yMax)) { goto found; + } // search following pages - textOut = new TextOutputDev(NULL, gFalse); + textOut = new TextOutputDev(NULL, gFalse, gFalse); if (!textOut->isOk()) { delete textOut; goto done; } for (pg = page+1; pg <= doc->getNumPages(); ++pg) { doc->displayPage(textOut, pg, 72, 0, gFalse); - if (textOut->findText(s, gTrue, gTrue, &xMin1, &yMin1, &xMax1, &yMax1)) + if (textOut->findText(u, len, gTrue, gTrue, + &xMin1, &yMin1, &xMax1, &yMax1)) { goto foundPage; + } } // search previous pages for (pg = 1; pg < page; ++pg) { doc->displayPage(textOut, pg, 72, 0, gFalse); - if (textOut->findText(s, gTrue, gTrue, &xMin1, &yMin1, &xMax1, &yMax1)) + if (textOut->findText(u, len, gTrue, gTrue, + &xMin1, &yMin1, &xMax1, &yMax1)) { goto foundPage; + } } delete textOut; @@ -1679,8 +2468,9 @@ static void doFind(char *s) { if (selectXMin < selectXMax && selectYMin < selectYMax) { xMax = selectXMin; yMax = (selectYMin + selectYMax) / 2; - if (out->findText(s, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) + if (out->findText(u, len, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) { goto found; + } } // not found @@ -1690,9 +2480,11 @@ static void doFind(char *s) { // found on a different page foundPage: delete textOut; - displayPage(pg, zoom, rotate); - if (!out->findText(s, gTrue, gTrue, &xMin, &yMin, &xMax, &yMax)) - goto done; // this can happen if coalescing is bad + displayPage(pg, zoom, rotate, gTrue); + if (!out->findText(u, len, gTrue, gTrue, &xMin, &yMin, &xMax, &yMax)) { + // this can happen if coalescing is bad + goto done; + } // found: change the selection found: @@ -1705,6 +2497,8 @@ static void doFind(char *s) { #endif done: + gfree(u); + // reset cursors to normal win->setBusyCursor(gFalse); findWin->setBusyCursor(gFalse);