]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/xpdf.cc
(redraw): fix pixbuf data offset.
[evince.git] / pdf / xpdf / xpdf.cc
index ff5455031535202237a758ff383dab047c40cfa6..2705cf653582bff0a7578d8bf454cab3ce745ed5 100644 (file)
 //
 // xpdf.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
 #include <aconf.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <time.h>
-#include <X11/X.h>
-#include <X11/cursorfont.h>
-#include <X11/keysym.h>
 #include "gtypes.h"
 #include "GString.h"
 #include "parseargs.h"
 #include "gfile.h"
 #include "gmem.h"
 #include "GlobalParams.h"
-#include "LTKAll.h"
 #include "Object.h"
-#include "Stream.h"
-#include "Array.h"
-#include "Dict.h"
-#include "XRef.h"
-#include "Catalog.h"
-#include "Page.h"
-#include "Link.h"
-#include "PDFDoc.h"
-#include "XOutputDev.h"
-#include "LTKOutputDev.h"
-#include "PSOutputDev.h"
-#include "TextOutputDev.h"
-#include "Error.h"
-#include "config.h"
-
-#ifdef XlibSpecificationRelease
-#if XlibSpecificationRelease < 5
-typedef char *XPointer;
-#endif
-#else
-typedef char *XPointer;
-#endif
-
-// hack around old X includes which are missing these symbols
-#ifndef XK_Page_Up
-#define XK_Page_Up              0xFF55
-#endif
-#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 512
-
-enum XpdfMenuItem {
-  menuOpen,
-  menuReload,
-  menuSavePDF,
-  menuRotateCCW,
-  menuRotateCW,
-  menuQuit
-};
-
-//------------------------------------------------------------------------
-// prototypes
-//------------------------------------------------------------------------
-
-// loadFile / displayPage
-static GBool loadFile(GString *fileName);
-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,
-                       char *s, int n);
-static void menuCbk(LTKMenuItem *item);
-
-// mouse callbacks
-static void buttonPressCbk(LTKWidget *canvas1, int n,
-                          int mx, int my, int button, GBool dblClick);
-static void buttonReleaseCbk(LTKWidget *canvas1, int n,
-                            int mx, int my, int button, GBool click);
-static void doLink(int mx, int my);
-static void mouseMoveCbk(LTKWidget *widget, int widgetNum, int mx, int my);
-static void mouseDragCbk(LTKWidget *widget, int widgetNum,
-                        int mx, int my, int button);
-
-// 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 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);
-
-// scrollbar callbacks
-static void scrollVertCbk(LTKWidget *scrollbar, int n, int val);
-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
-static void setSelection(int newXMin, int newYMin, int newXMax, int newYMax);
-
-// "Open" dialog
-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);
-static void saveSelectCbk(LTKWidget *widget, int n, GString *name);
-
-// "PostScript" dialog
-static void mapPSDialog();
-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);
-static void mapFindWin();
-static void findButtonCbk(LTKWidget *button, int n, GBool on);
-static void doFind(char *s);
-
-// app kill callback
-static void killCbk(LTKWindow *win1);
-
-//------------------------------------------------------------------------
-// "About" window text
-//------------------------------------------------------------------------
-
-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 = <PgDn>     = next page",
-  "  p = <PgUp>     = previous page",
-  "  <space>        = scroll down",
-  "  <backspace>    = <delete> = 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",
-  "  <home> / <end> = top / bottom of page",
-  "  <arrows>       = scroll",
-  "",
-  "For more information, please read the xpdf(1) man page.",
-  NULL
-};
+#include "XPDFApp.h"
+#include "xpdfconfig.h"
 
 //------------------------------------------------------------------------
 // command line options
 //------------------------------------------------------------------------
 
-static char initialZoomStr[32] = "";
-static char t1libControlStr[16] = "";
-static char freetypeControlStr[16] = "";
+static char enableT1libStr[16] = "";
+static char enableFreeTypeStr[16] = "";
+static char antialiasStr[16] = "";
 static char psFileArg[256];
 static char paperSize[15] = "";
 static int paperWidth = 0;
@@ -262,10 +31,11 @@ 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 char ownerPassword[33] = "\001";
+static char userPassword[33] = "\001";
 static GBool fullScreen = gFalse;
 static char remoteName[100] = "xpdf_";
+static GBool doRemoteReload = gFalse;
 static GBool doRemoteRaise = gFalse;
 static GBool doRemoteQuit = gFalse;
 static GBool printCommands = gFalse;
@@ -273,7 +43,6 @@ static GBool quiet = gFalse;
 static char cfgFileName[256] = "";
 static GBool printVersion = gFalse;
 static GBool printHelp = gFalse;
-static GBool viKeys = gFalse;
 
 static ArgDesc argDesc[] = {
   {"-g",          argStringDummy, NULL,           0,
@@ -290,20 +59,22 @@ static ArgDesc argDesc[] = {
    "reverse video"},
   {"-papercolor", argStringDummy, NULL,           0,
    "color of paper background"},
-  {"-z",          argString,      initialZoomStr, sizeof(initialZoomStr),
-   "initial zoom level (-5..5, page, width)"},
+  {"-z",          argStringDummy, NULL,           0,
+   "initial zoom level (percent, 'page', 'width')"},
 #if HAVE_T1LIB_H
-  {"-t1lib",      argString,      t1libControlStr, sizeof(t1libControlStr),
-   "t1lib font rasterizer control: none, plain, low, high"},
+  {"-t1lib",      argString,      enableT1libStr, sizeof(enableT1libStr),
+   "enable t1lib font rasterizer: yes, no"},
 #endif
 #if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H
-  {"-freetype",   argString,      freetypeControlStr, sizeof(freetypeControlStr),
-   "FreeType font rasterizer control: none, plain, low, high"},
+  {"-freetype",   argString,      enableFreeTypeStr, sizeof(enableFreeTypeStr),
+   "enable FreeType font rasterizer: yes, no"},
 #endif
+  {"-aa",         argString,      antialiasStr,   sizeof(antialiasStr),
+   "enable font anti-aliasing: yes, no"},
   {"-ps",         argString,      psFileArg,      sizeof(psFileArg),
    "default PostScript file name or command"},
   {"-paper",      argString,      paperSize,      sizeof(paperSize),
-   "paper size (letter, legal, A4, A3)"},
+   "paper size (letter, legal, A4, A3, match)"},
   {"-paperw",     argInt,         &paperWidth,    0,
    "paper width, in points"},
   {"-paperh",     argInt,         &paperHeight,   0,
@@ -322,6 +93,8 @@ static ArgDesc argDesc[] = {
    "run in full-screen (presentation) mode"},
   {"-remote",     argString,      remoteName + 5, sizeof(remoteName) - 5,
    "start/contact xpdf remote server with specified name"},
+  {"-reload",     argFlag,        &doRemoteReload, 0,
+   "reload xpdf remove server window (with -remote only)"},
   {"-raise",      argFlag,        &doRemoteRaise, 0,
    "raise xpdf remote server window (with -remote only)"},
   {"-quit",       argFlag,        &doRemoteQuit,  0,
@@ -345,160 +118,35 @@ static ArgDesc argDesc[] = {
   {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}
-};
-
-//------------------------------------------------------------------------
-// global variables
-//------------------------------------------------------------------------
-
-// zoom factor is 1.2 (similar to DVI magsteps)
-#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
-};
-
-static PDFDoc *doc;
-
-static LTKOutputDev *out;
-
-static int page;
-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
-  selectXMax, selectYMax;      //   is no selection
-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
-
-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;
-
-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
 //------------------------------------------------------------------------
 
 int main(int argc, char *argv[]) {
-  Window xwin;
-  XGCValues gcValues;
-  char cmd[remoteCmdLength];
-  LTKMenu *menu;
-  GString *name;
-  GString *title;
-  GString *initialZoom;
-  GBool reverseVideo;
-  unsigned long paperColor;
-  GBool installCmap;
-  int rgbCubeSize;
+  XPDFApp *app;
+  GString *fileName;
   int pg;
   GString *destName;
-  LinkDest *dest;
-  int x, y;
-  Guint width, height;
-  double width1, height1;
+  GString *userPasswordStr, *ownerPasswordStr;
   GBool ok;
-  char s[20];
-  int i;
-  int ret;
+  int exitCode;
 
-  // initialize
-  app = NULL;
-  win = NULL;
-  out = NULL;
-  remoteAtom = None;
-  doc = NULL;
-  psFileName = NULL;
-  fileReqDir = getCurrentDir();
-  ret = 0;
+  exitCode = 0;
+  userPasswordStr = ownerPasswordStr = NULL;
 
   // parse args
   ok = parseArgs(argDesc, &argc, argv);
+  if (!ok || printVersion || printHelp) {
+    fprintf(stderr, "xpdf version %s\n", xpdfVersion);
+    fprintf(stderr, "%s\n", xpdfCopyright);
+    if (!printVersion) {
+      printUsage("xpdf", "[<PDF-file> [<page> | +<dest>]]", argDesc);
+    }
+    exitCode = 99;
+    goto done0;
+  }
 
   // read config file
   globalParams = new GlobalParams(cfgFileName);
+  globalParams->setupBaseFonts(NULL);
   if (psFileArg[0]) {
     globalParams->setPSFile(psFileArg);
   }
@@ -525,48 +173,61 @@ int main(int argc, char *argv[]) {
       fprintf(stderr, "Bad '-eol' value on command line\n");
     }
   }
-  if (initialZoomStr[0]) {
-    globalParams->setInitialZoom(initialZoomStr);
-  }
-  if (t1libControlStr[0]) {
-    if (!globalParams->setT1libControl(t1libControlStr)) {
+  if (enableT1libStr[0]) {
+    if (!globalParams->setEnableT1lib(enableT1libStr)) {
       fprintf(stderr, "Bad '-t1lib' value on command line\n");
     }
   }
-  if (freetypeControlStr[0]) {
-    if (!globalParams->setFreeTypeControl(freetypeControlStr)) {
+  if (enableFreeTypeStr[0]) {
+    if (!globalParams->setEnableFreeType(enableFreeTypeStr)) {
       fprintf(stderr, "Bad '-freetype' value on command line\n");
     }
   }
+  if (antialiasStr[0]) {
+    if (!globalParams->setAntialias(antialiasStr)) {
+      fprintf(stderr, "Bad '-aa' value on command line\n");
+    }
+  }
+  if (printCommands) {
+    globalParams->setPrintCommands(printCommands);
+  }
   if (quiet) {
     globalParams->setErrQuiet(quiet);
   }
 
-  // create LTKApp (and parse X-related args)
-  app = new LTKApp("xpdf", "Xpdf", opts, &argc, argv);
-  app->setKillCbk(&killCbk);
-  display = app->getDisplay();
+  // create the XPDFApp object
+  app = new XPDFApp(&argc, argv);
+
+  // the initialZoom parameter can be set in either the config file or
+  // as an X resource (or command line arg)
+  if (app->getInitialZoom()) {
+    globalParams->setInitialZoom(app->getInitialZoom()->getCString());
+  }
 
   // check command line
-  if (doRemoteRaise)
-    ok = ok && remoteName[5] && !doRemoteQuit && argc >= 1 && argc <= 3;
-  else if (doRemoteQuit)
+  ok = ok && argc >= 1 && argc <= 3;
+  if (doRemoteReload) {
+    ok = ok && remoteName[5] && !doRemoteQuit && argc == 1;
+  }
+  if (doRemoteRaise) {
+    ok = ok && remoteName[5] && !doRemoteQuit;
+  }
+  if (doRemoteQuit) {
     ok = ok && remoteName[5] && argc == 1;
-  else
-    ok = ok && argc >= 1 && argc <= 3;
+  }
   if (!ok || printVersion || printHelp) {
     fprintf(stderr, "xpdf version %s\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("xpdf", "[<PDF-file> [<page> | +<dest>]]", argDesc);
     }
-    ret = 1;
-    goto done2;
+    exitCode = 99;
+    goto done1;
   }
   if (argc >= 2) {
-    name = new GString(argv[1]);
+    fileName = new GString(argv[1]);
   } else {
-    name = NULL;
+    fileName = NULL;
   }
   pg = 1;
   destName = NULL;
@@ -578,1953 +239,78 @@ int main(int argc, char *argv[]) {
     }
   }
 
-  // look for already-running remote server
+  // handle remote server stuff
   if (remoteName[5]) {
-    remoteAtom = XInternAtom(display, remoteName, False);
-    xwin = XGetSelectionOwner(display, remoteAtom);
-    if (xwin != None) {
-      if (name) {
+    app->setRemoteName(remoteName);
+    if (app->remoteServerRunning()) {
+      if (fileName) {
        if (destName) {
-         sprintf(cmd, "%c +%.256s %.200s", doRemoteRaise ? 'D' : 'd',
-                 destName->getCString(), name->getCString());
-         delete destName;
+         app->remoteOpenAtDest(fileName, destName, doRemoteRaise);
        } else {
-         sprintf(cmd, "%c %d %.200s", doRemoteRaise ? 'D' : 'd',
-                 pg, name->getCString());
+         app->remoteOpen(fileName, pg, doRemoteRaise);
        }
-       XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8,
-                       PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
-       delete name;
+      } else if (doRemoteReload) {
+       app->remoteReload(doRemoteRaise);
       } else if (doRemoteRaise) {
-       XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8,
-                       PropModeReplace, (Guchar *)"r", 2);
+       app->remoteRaise();
       } else if (doRemoteQuit) {
-       XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8,
-                       PropModeReplace, (Guchar *)"q", 2);
+       app->remoteQuit();
       }
       goto done2;
     }
     if (doRemoteQuit) {
-      if (destName) {
-       delete destName;
-      }
       goto done2;
     }
   }
 
-  // no history yet
-  historyCur = historySize - 1;
-  historyBLen = historyFLen = 0;
-  for (i = 0; i < historySize; ++i)
-    history[i].fileName = NULL;
-
-  // open PDF file
-  if (name) {
-    if (!loadFile(name)) {
-      ret = 1;
-      goto done1;
-    }
-    delete fileReqDir;
-    fileReqDir = makePathAbsolute(grabPath(name->getCString()));
-  }
-
-  // check for legal page number
-  if (doc && (pg < 1 || pg > doc->getNumPages())) {
-    pg = 1;
-  }
-
-  // create window
-  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");
-  vScrollbar = (LTKScrollbar *)win->findWidget("vScrollbar");
-  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);
-  if (!fullScreen) {
-    hScrollbar->setRepeatPeriod(0);
-    vScrollbar->setRepeatPeriod(0);
-  }
-
-  // get parameters
-  urlCommand = globalParams->getURLCommand();
-
-  // get X resources
-  windowTitle = app->getStringResource("title", NULL);
-  installCmap = app->getBoolResource("installCmap", gFalse);
-  if (installCmap) {
-    win->setInstallCmap(gTrue);
-  }
-  rgbCubeSize = app->getIntResource("rgbCubeSize", defaultRGBCube);
-  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
-  if (fullScreen) {
-    x = y = 0;
-    width = app->getDisplayWidth();
-    height = app->getDisplayHeight();
-  } else {
-    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;
-      }
-    }
-  }
-
-  // finish setting up window
-  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 {
-    title = new GString("xpdf");
-  }
-  win->setTitle(title);
-  win->layout(x, y, width, height);
-  win->map();
-  aboutWin = NULL;
-  psDialog = NULL;
-  openDialog = NULL;
-  saveDialog = NULL;
-  findWin = NULL;
-  gcValues.foreground = BlackPixel(display, win->getScreenNum()) ^
-                        WhitePixel(display, win->getScreenNum());
-  gcValues.function = GXxor;
-  selectGC = XCreateGC(display, win->getXWindow(),
-                      GCForeground | GCFunction, &gcValues);
-
-  // set up remote server
-  if (remoteAtom != None) {
-    win->setPropChangeCbk(&propChangeCbk);
-    xwin = win->getXWindow();
-    XSetSelectionOwner(display, remoteAtom, xwin, CurrentTime);
-  }
+  // set options
+  app->setFullScreen(fullScreen);
 
-  // create output device
-  out = new LTKOutputDev(win, reverseVideo, paperColor,
-                        installCmap, rgbCubeSize, !fullScreen);
-  out->startDoc(doc ? doc->getXRef() : (XRef *)NULL);
+  // check for password string(s)
+  ownerPasswordStr = ownerPassword[0] != '\001' ? new GString(ownerPassword)
+                                                : (GString *)NULL;
+  userPasswordStr = userPassword[0] != '\001' ? new GString(userPassword)
+                                              : (GString *)NULL;
 
-  // display first page
+  // open the file and run the main loop
   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);
-      }
+    if (!app->openAtDest(fileName, destName,
+                        ownerPasswordStr, userPasswordStr)) {
+      exitCode = 1;
+      goto done2;
     }
-    delete destName;
   } else {
-    displayPage(pg, zoom, 0, gTrue);
+    if (!app->open(fileName, pg, ownerPasswordStr, userPasswordStr)) {
+      exitCode = 1;
+      goto done2;
+    }
   }
+  app->run();
 
-  // event loop
-  quit = gFalse;
-  do {
-    app->doEvent(gTrue);
-  } while (!quit);
-
- done1:
-  // release remote control atom
-  if (remoteAtom != None)
-    XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
+  exitCode = 0;
 
+  // clean up
  done2:
-  // free stuff
-  if (out) {
-    delete out;
-  }
-  if (win) {
-    delete win;
-  }
-  if (aboutWin) {
-    delete aboutWin;
-  }
-  if (findWin) {
-    delete findWin;
+  if (userPasswordStr) {
+    delete userPasswordStr;
   }
-  if (app) {
-    delete app;
+  if (ownerPasswordStr) {
+    delete ownerPasswordStr;
   }
-  if (doc) {
-    delete doc;
-  }
-  if (psFileName) {
-    delete psFileName;
-  }
-  if (fileReqDir) {
-    delete fileReqDir;
-  }
-  if (windowTitle) {
-    delete windowTitle;
+  if (destName) {
+    delete destName;
   }
-  for (i = 0; i < historySize; ++i) {
-    if (history[i].fileName) {
-      delete history[i].fileName;
-    }
+  if (fileName) {
+    delete fileName;
   }
+ done1:
+  delete app;
   delete globalParams;
 
   // check for memory leaks
+ done0:
   Object::memCheck(stderr);
   gMemReport(stderr);
 
-  return ret;
-}
-
-//------------------------------------------------------------------------
-// loadFile / displayPage / displayDest
-//------------------------------------------------------------------------
-
-static GBool loadFile(GString *fileName) {
-  GString *title;
-  PDFDoc *newDoc;
-  GString *ownerPW, *userPW;
-  char s[20];
-  char *p;
-
-  // busy cursor
-  if (win)
-    win->setBusyCursor(gTrue);
-
-  // open PDF file
-  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)
-      win->setBusyCursor(gFalse);
-    return gFalse;
-  }
-
-  // replace old document
-  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 (globalParams->getPSFile()) {
-    psFileName = globalParams->getPSFile()->copy();
-  } else {
-    p = fileName->getCString() + fileName->getLength() - 4;
-    if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF"))
-      psFileName = new GString(fileName->getCString(),
-                              fileName->getLength() - 4);
-    else
-      psFileName = fileName->copy();
-    psFileName->append(".ps");
-  }
-  psFirstPage = 1;
-  psLastPage = doc->getNumPages();
-
-  // set up title, number-of-pages display; back to normal cursor
-  if (win) {
-    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);
-  }
-
-  // done
-  return gTrue;
-}
-
-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 || 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 = pageA;
-  zoom = zoomA;
-  rotate = rotateA;
-
-  // initialize mouse-related stuff
-  linkAction = NULL;
-  win->setDefaultCursor();
-  if (!fullScreen) {
-    linkLabel->setText(NULL);
-  }
-  selectXMin = selectXMax = 0;
-  selectYMin = selectYMax = 0;
-  lastDragLeft = lastDragTop = gTrue;
-
-  // draw the page
-  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
-  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
-//------------------------------------------------------------------------
-
-static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers,
-                       char *s, int n) {
-  if (n > 0) {
-    switch (s[0]) {
-    case 'O':
-    case 'o':
-      mapOpenDialog();
-      break;
-    case 'R':
-    case 'r':
-      reloadCbk();
-      break;
-    case 'F':
-    case 'f':
-      mapFindWin();
-      break;
-    case 'N':
-    case 'n':
-      gotoNextPage(1, !(modifiers & Mod5Mask));
-      break;
-    case 'P':
-    case 'p':
-      gotoPrevPage(1, !(modifiers & Mod5Mask), gFalse);
-      break;
-    case ' ':
-      if (fullScreen ||
-         vScrollbar->getPos() >=
-           canvas->getRealHeight() - canvas->getHeight()) {
-       gotoNextPage(1, gTrue);
-      } else {
-       vScrollbar->setPos(vScrollbar->getPos() + canvas->getHeight(),
-                          canvas->getHeight());
-       canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
-      }
-      break;
-    case '\b':                 // bs
-    case '\177':               // del
-      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, gFalse);
-      break;
-    case 'Q':
-    case 'q':
-      quitCbk(NULL, 0, gTrue);
-      break;
-    }
-  } 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(),
-                        canvas->getHeight());
-      canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
-      break;
-    case XK_Page_Up:
-    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());
-       canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
-      }
-      break;
-    case XK_Page_Down:
-    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());
-       canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
-      }
-      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;
-    }
-  }
-}
-
-static void menuCbk(LTKMenuItem *item) {
-  int r;
-
-  switch (item->getItemNum()) {
-  case menuOpen:
-    mapOpenDialog();
-    break;
-  case menuReload:
-    reloadCbk();
-    break;
-  case menuSavePDF:
-    if (doc)
-      mapSaveDialog();
-    break;
-  case menuRotateCCW:
-    if (doc) {
-      r = (rotate == 0) ? 270 : rotate - 90;
-      displayPage(page, zoom, r, gFalse);
-    }
-    break;
-  case menuRotateCW:
-    if (doc) {
-      r = (rotate == 270) ? 0 : rotate + 90;
-      displayPage(page, zoom, r, gFalse);
-    }
-    break;
-  case menuQuit:
-    quit = gTrue;
-    break;
-  }
-}
-
-//------------------------------------------------------------------------
-// mouse callbacks
-//------------------------------------------------------------------------
-
-static void buttonPressCbk(LTKWidget *canvas1, int n,
-                          int mx, int my, int button, GBool dblClick) {
-  if (!doc || doc->getNumPages() == 0) {
-    return;
-  }
-  switch (button) {
-  case 1:
-    setSelection(mx, my, mx, my);
-    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;
-  }
-}
-
-static void buttonReleaseCbk(LTKWidget *canvas1, int n,
-                            int mx, int my, int button, GBool click) {
-  GString *s;
-
-  if (!doc || doc->getNumPages() == 0)
-    return;
-
-  if (button == 1) {
-    // selection
-    if (selectXMin < selectXMax && selectYMin < selectYMax) {
-#ifndef NO_TEXT_SELECT
-      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
-
-    // link
-    } else {
-      setSelection(mx, my, mx, my);
-      doLink(mx, my);
-    }
-  }
-}
-
-static void doLink(int mx, int my) {
-  LinkActionKind kind;
-  LinkAction *action = NULL;
-  LinkDest *dest;
-  GString *namedDest;
-  char *s;
-  GString *fileName;
-  GString *actionName;
-  double x, y;
-  LTKButtonDialog *dialog;
-  int i;
-
-  // look for a link
-  out->cvtDevToUser(mx, my, &x, &y);
-  if ((action = doc->findLink(x, y))) {
-    switch (kind = action->getKind()) {
-
-    // GoTo / GoToR action
-    case actionGoTo:
-    case actionGoToR:
-      if (kind == actionGoTo) {
-       dest = NULL;
-       namedDest = NULL;
-       if ((dest = ((LinkGoTo *)action)->getDest()))
-         dest = dest->copy();
-       else if ((namedDest = ((LinkGoTo *)action)->getNamedDest()))
-         namedDest = namedDest->copy();
-      } else {
-       dest = NULL;
-       namedDest = NULL;
-       if ((dest = ((LinkGoToR *)action)->getDest()))
-         dest = dest->copy();
-       else if ((namedDest = ((LinkGoToR *)action)->getNamedDest()))
-         namedDest = namedDest->copy();
-       s = ((LinkGoToR *)action)->getFileName()->getCString();
-       //~ translate path name for VMS (deal with '/')
-       if (isAbsolutePath(s))
-         fileName = new GString(s);
-       else
-         fileName = appendToPath(
-                        grabPath(doc->getFileName()->getCString()), s);
-       if (!loadFile(fileName)) {
-         if (dest)
-           delete dest;
-         if (namedDest)
-           delete namedDest;
-         return;
-       }
-      }
-      if (namedDest) {
-       dest = doc->findDest(namedDest);
-       delete namedDest;
-      }
-      if (dest) {
-       displayDest(dest, zoom, rotate, gTrue);
-       delete dest;
-      } else {
-       if (kind == actionGoToR) {
-         displayPage(1, zoom, 0, gTrue);
-       }
-      }
-      break;
-
-    // Launch action
-    case actionLaunch:
-      fileName = ((LinkLaunch *)action)->getFileName();
-      s = fileName->getCString();
-      if (!strcmp(s + fileName->getLength() - 4, ".pdf") ||
-         !strcmp(s + fileName->getLength() - 4, ".PDF")) {
-       //~ translate path name for VMS (deal with '/')
-       if (isAbsolutePath(s))
-         fileName = fileName->copy();
-       else
-         fileName = appendToPath(
-                        grabPath(doc->getFileName()->getCString()), s);
-       if (!loadFile(fileName))
-         return;
-       displayPage(1, zoom, rotate, gTrue);
-      } else {
-       fileName = fileName->copy();
-       if (((LinkLaunch *)action)->getParams()) {
-         fileName->append(' ');
-         fileName->append(((LinkLaunch *)action)->getParams());
-       }
-#ifdef VMS
-       fileName->insert(0, "spawn/nowait ");
-#elif defined(__EMX__)
-       fileName->insert(0, "start /min /n ");
-#else
-       fileName->append(" &");
-#endif
-       dialog = new LTKButtonDialog(win, "xpdf: Launch",
-                                    "Execute the command:",
-                                    fileName->getCString(),
-                                    NULL, "Ok", "Cancel");
-       if (dialog->go())
-         system(fileName->getCString());
-       delete dialog;
-       delete fileName;
-      }
-      break;
-
-    // URI action
-    case actionURI:
-      if (urlCommand) {
-       for (s = urlCommand->getCString(); *s; ++s) {
-         if (s[0] == '%' && s[1] == 's') {
-           break;
-         }
-       }
-       if (s) {
-         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();
-       }
-#ifdef VMS
-       fileName->insert(0, "spawn/nowait ");
-#elif defined(__EMX__)
-       fileName->insert(0, "start /min /n ");
-#else
-       fileName->append(" &");
-#endif
-       system(fileName->getCString());
-       delete fileName;
-      } else {
-       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;
-
-    // unknown action type
-    case actionUnknown:
-      error(-1, "Unknown link action type: '%s'",
-           ((LinkUnknown *)action)->getAction()->getCString());
-      break;
-    }
-  }
-}
-
-static void mouseMoveCbk(LTKWidget *widget, int widgetNum, int mx, int my) {
-  double x, y;
-  LinkAction *action;
-  char *s;
-
-  if (!doc || doc->getNumPages() == 0)
-    return;
-  out->cvtDevToUser(mx, my, &x, &y);
-  if ((action = doc->findLink(x, y))) {
-    if (action != linkAction) {
-      if (!linkAction) {
-       win->setCursor(XC_hand2);
-      }
-      linkAction = action;
-      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);
-      }
-    }
-  } else {
-    if (linkAction) {
-      linkAction = NULL;
-      win->setDefaultCursor();
-      if (!fullScreen) {
-       linkLabel->setText(NULL);
-      }
-    }
-  }
-}
-
-static void mouseDragCbk(LTKWidget *widget, int widgetNum,
-                        int mx, int my, int button) {
-  int x, y;
-  int xMin, yMin, xMax, yMax;
-
-  // button 1: select
-  if (button == 1) {
-
-    // clip mouse coords
-    x = mx;
-    if (x < 0)
-      x = 0;
-    else if (x >= canvas->getRealWidth())
-      x = canvas->getRealWidth() - 1;
-    y = my;
-    if (y < 0)
-      y = 0;
-    else if (y >= canvas->getRealHeight())
-      y = canvas->getRealHeight() - 1;
-
-    // move appropriate edges of selection
-    if (lastDragLeft) {
-      if (x < selectXMax) {
-       xMin = x;
-       xMax = selectXMax;
-      } else {
-       xMin = selectXMax;
-       xMax = x;
-       lastDragLeft = gFalse;
-      }      
-    } else {
-      if (x > selectXMin) {
-       xMin = selectXMin;
-       xMax = x;
-      } else {
-       xMin = x;
-       xMax = selectXMin;
-       lastDragLeft = gTrue;
-      }
-    }
-    if (lastDragTop) {
-      if (y < selectYMax) {
-       yMin = y;
-       yMax = selectYMax;
-      } else {
-       yMin = selectYMax;
-       yMax = y;
-       lastDragTop = gFalse;
-      }
-    } else {
-      if (y > selectYMin) {
-       yMin = selectYMin;
-       yMax = y;
-      } else {
-       yMin = y;
-       yMax = selectYMin;
-       lastDragTop = gTrue;
-      }
-    }
-
-    // redraw the selection
-    setSelection(xMin, yMin, xMax, yMax);
-
-  // button 2: pan
-  } else if (!fullScreen && button == 2) {
-    mx -= hScrollbar->getPos();
-    my -= vScrollbar->getPos();
-    hScrollbar->setPos(hScrollbar->getPos() - (mx - panMX),
-                      canvas->getWidth());
-    vScrollbar->setPos(vScrollbar->getPos() - (my - panMY),
-                      canvas->getHeight());
-    canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
-    panMX = mx;
-    panMY = my;
-  }
-}
-
-//------------------------------------------------------------------------
-// button callbacks
-//------------------------------------------------------------------------
-
-static void nextPageCbk(LTKWidget *button, int n, GBool on) {
-  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 || doc->getNumPages() == 0) {
-    return;
-  }
-  if (page < 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, gTrue);
-  } else {
-    XBell(display, 0);
-  }
-}
-
-static void prevPageCbk(LTKWidget *button, int n, GBool on) {
-  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 || doc->getNumPages() == 0) {
-    return;
-  }
-  if (page > 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, 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 || doc->getNumPages() == 0)
-    return;
-  page1 = atoi(text->getCString());
-  if (page1 >= 1 && page1 <= doc->getNumPages()) {
-    if (page1 != page)
-      displayPage(page1, zoom, rotate, gTrue);
-  } else {
-    XBell(display, 0);
-    sprintf(s, "%d", page);
-    pageNumText->setText(s);
-  }
-}
-
-static void zoomMenuCbk(LTKMenuItem *item) {
-  int z;
-
-  if (!doc || doc->getNumPages() == 0) {
-    return;
-  }
-  z = item->getItemNum();
-  if (z != zoom) {
-    displayPage(page, z, rotate, gFalse);
-  }
-}
-
-static void postScriptCbk(LTKWidget *button, int n, GBool on) {
-  if (!doc)
-    return;
-  mapPSDialog();
-}
-
-static void aboutCbk(LTKWidget *button, int n, GBool on) {
-  mapAboutWin();
-}
-
-static void quitCbk(LTKWidget *button, int n, GBool on) {
-  quit = gTrue;
-}
-
-//------------------------------------------------------------------------
-// scrollbar callbacks
-//------------------------------------------------------------------------
-
-static void scrollVertCbk(LTKWidget *scrollbar, int n, int val) {
-  canvas->scroll(hScrollbar->getPos(), val);
-  XSync(display, False);
-}
-
-static void scrollHorizCbk(LTKWidget *scrollbar, int n, int val) {
-  canvas->scroll(val, vScrollbar->getPos());
-  XSync(display, False);
-}
-
-//------------------------------------------------------------------------
-// misc callbacks
-//------------------------------------------------------------------------
-
-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);
-  vScrollbar->setLimits(0, canvas->getRealHeight() - 1);
-  vScrollbar->setPos(vScrollbar->getPos(), canvas->getHeight());
-  vScrollbar->setScrollDelta(16);
-  canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
-}
-
-static void propChangeCbk(LTKWindow *win1, Atom atom) {
-  Window xwin;
-  char *cmd;
-  Atom type;
-  int format;
-  Gulong size, remain;
-  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) {
-    return;
-  }
-  if (size == 0) {
-    return;
-  }
-
-  // raise window
-  if (cmd[0] == 'D' || cmd[0] == 'r'){
-    win->raise();
-    XFlush(display);
-  }
-
-  // display file / page
-  if (cmd[0] == 'd' || cmd[0] == 'D') {
-    p = cmd + 2;
-    q = strchr(p, ' ');
-    if (!q) {
-      return;
-    }
-    *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))
-       return;
-    } else {
-      delete newFileName;
-    }
-    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') {
-    quit = gTrue;
-  }
-}
-
-//------------------------------------------------------------------------
-// selection
-//------------------------------------------------------------------------
-
-static void setSelection(int newXMin, int newYMin, int newXMax, int newYMax) {
-  int x, y, w, h;
-  GBool needRedraw, needScroll;
-  GBool moveLeft, moveRight, moveTop, moveBottom;
-
-  // erase old selection on canvas pixmap
-  needRedraw = gFalse;
-  if (selectXMin < selectXMax && selectYMin < selectYMax) {
-    XFillRectangle(canvas->getDisplay(), canvas->getPixmap(),
-                  selectGC, selectXMin, selectYMin,
-                  selectXMax - selectXMin, selectYMax - selectYMin);
-    needRedraw = gTrue;
-  }
-
-  // draw new selection on canvas pixmap
-  if (newXMin < newXMax && newYMin < newYMax) {
-    XFillRectangle(canvas->getDisplay(), canvas->getPixmap(),
-                  selectGC, newXMin, newYMin,
-                  newXMax - newXMin, newYMax - newYMin);
-    needRedraw = gTrue;
-  }
-
-  // check which edges moved
-  moveLeft = newXMin != selectXMin;
-  moveTop = newYMin != selectYMin;
-  moveRight = newXMax != selectXMax;
-  moveBottom = newYMax != selectYMax;
-
-  // redraw currently visible part of canvas
-  if (needRedraw) {
-    if (moveLeft) {
-      canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin,
-                        (newYMin < selectYMin) ? newYMin : selectYMin,
-                        (newXMin > selectXMin) ? newXMin : selectXMin,
-                        (newYMax > selectYMax) ? newYMax : selectYMax);
-    }
-    if (moveRight) {
-      canvas->redrawRect((newXMax < selectXMax) ? newXMax : selectXMax,
-                        (newYMin < selectYMin) ? newYMin : selectYMin,
-                        (newXMax > selectXMax) ? newXMax : selectXMax,
-                        (newYMax > selectYMax) ? newYMax : selectYMax);
-    }
-    if (moveTop) {
-      canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin,
-                        (newYMin < selectYMin) ? newYMin : selectYMin,
-                        (newXMax > selectXMax) ? newXMax : selectXMax,
-                        (newYMin > selectYMin) ? newYMin : selectYMin);
-    }
-    if (moveBottom) {
-      canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin,
-                        (newYMax < selectYMax) ? newYMax : selectYMax,
-                        (newXMax > selectXMax) ? newXMax : selectXMax,
-                        (newYMax > selectYMax) ? newYMax : selectYMax);
-    }
-  }
-
-  // switch to new selection coords
-  selectXMin = newXMin;
-  selectXMax = newXMax;
-  selectYMin = newYMin;
-  selectYMax = newYMax;
-
-  // scroll canvas if necessary
-  if (fullScreen) {
-    return;
-  }
-  needScroll = gFalse;
-  w = canvas->getWidth();
-  h = canvas->getHeight();
-  x = hScrollbar->getPos();
-  y = vScrollbar->getPos();
-  if (moveLeft && selectXMin < x) {
-    x = selectXMin;
-    needScroll = gTrue;
-  } else if (moveRight && selectXMax >= x + w) {
-    x = selectXMax - w;
-    needScroll = gTrue;
-  } else if (moveLeft && selectXMin >= x + w) {
-    x = selectXMin - w;
-    needScroll = gTrue;
-  } else if (moveRight && selectXMax < x) {
-    x = selectXMax;
-    needScroll = gTrue;
-  }
-  if (moveTop && selectYMin < y) {
-    y = selectYMin;
-    needScroll = gTrue;
-  } else if (moveBottom && selectYMax >= y + h) {
-    y = selectYMax - h;
-    needScroll = gTrue;
-  } else if (moveTop && selectYMin >= y + h) {
-    y = selectYMin - h;
-    needScroll = gTrue;
-  } else if (moveBottom && selectYMax < y) {
-    y = selectYMax;
-    needScroll = gTrue;
-  }
-  if (needScroll) {
-    hScrollbar->setPos(x, w);
-    vScrollbar->setPos(y, h);
-    canvas->scroll(x, y);
-  }
-}
-
-//------------------------------------------------------------------------
-// "Open" dialog
-//------------------------------------------------------------------------
-
-static void mapOpenDialog() {
-  openDialog = makeOpenDialog(app);
-  ((LTKFileReq *)openDialog->findWidget("fileReq"))->setDir(fileReqDir);
-  openDialog->layoutDialog(win, -1, -1);
-  openDialog->map();
-}
-
-static void openButtonCbk(LTKWidget *button, int n, GBool on) {
-  LTKFileReq *fileReq;
-  GString *sel;
-
-  sel = NULL;
-  if (n == 1) {
-    fileReq = (LTKFileReq *)openDialog->findWidget("fileReq");
-    if (!(sel = fileReq->getSelection())) {
-      return;
-    }
-    openSelectCbk(fileReq, 0, sel);
-  }
-  if (openDialog) {
-    if (sel) {
-      delete fileReqDir;
-      fileReqDir = ((LTKFileReq *)openDialog->findWidget("fileReq"))->getDir();
-    }
-    delete openDialog;
-    openDialog = NULL;
-  }
-}
-
-static void openSelectCbk(LTKWidget *widget, int n, GString *name) {
-  GString *name1;
-
-  name1 = name->copy();
-  if (openDialog) {
-    delete fileReqDir;
-    fileReqDir = ((LTKFileReq *)openDialog->findWidget("fileReq"))->getDir();
-    delete openDialog;
-    openDialog = NULL;
-  }
-  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);
-  }
-}
-
-//------------------------------------------------------------------------
-// "Save PDF" dialog
-//------------------------------------------------------------------------
-
-static void mapSaveDialog() {
-  saveDialog = makeSaveDialog(app);
-  ((LTKFileReq *)saveDialog->findWidget("fileReq"))->setDir(fileReqDir);
-  saveDialog->layoutDialog(win, -1, -1);
-  saveDialog->map();
-}
-
-static void saveButtonCbk(LTKWidget *button, int n, GBool on) {
-  LTKFileReq *fileReq;
-  GString *sel;
-
-  if (!doc)
-    return;
-  sel = NULL;
-  if (n == 1) {
-    fileReq = (LTKFileReq *)saveDialog->findWidget("fileReq");
-    if (!(sel = fileReq->getSelection())) {
-      return;
-    }
-    saveSelectCbk(fileReq, 0, sel);
-  }
-  if (saveDialog) {
-    if (sel) {
-      delete fileReqDir;
-      fileReqDir = ((LTKFileReq *)saveDialog->findWidget("fileReq"))->getDir();
-    }
-    delete saveDialog;
-    saveDialog = NULL;
-  }
-}
-
-static void saveSelectCbk(LTKWidget *widget, int n, GString *name) {
-  GString *name1;
-
-  name1 = name->copy();
-  if (saveDialog) {
-    delete fileReqDir;
-    fileReqDir = ((LTKFileReq *)saveDialog->findWidget("fileReq"))->getDir();
-    delete saveDialog;
-    saveDialog = NULL;
-  }
-  win->setBusyCursor(gTrue);
-  doc->saveAs(name1);
-  delete name1;
-  win->setBusyCursor(gFalse);
-}
-
-//------------------------------------------------------------------------
-// "PostScript" dialog
-//------------------------------------------------------------------------
-
-static void mapPSDialog() {
-  LTKTextIn *widget;
-  char s[20];
-
-  psDialog = makePostScriptDialog(app);
-  sprintf(s, "%d", psFirstPage);
-  widget = (LTKTextIn *)psDialog->findWidget("firstPage");
-  widget->setText(s);
-  sprintf(s, "%d", psLastPage);
-  widget = (LTKTextIn *)psDialog->findWidget("lastPage");
-  widget->setText(s);
-  widget = (LTKTextIn *)psDialog->findWidget("fileName");
-  widget->setText(psFileName->getCString());
-  psDialog->layoutDialog(win, -1, -1);
-  psDialog->map();
-}
-
-static void psButtonCbk(LTKWidget *button, int n, GBool on) {
-  PSOutputDev *psOut;
-  LTKTextIn *widget;
-
-  if (!doc)
-    return;
-
-  // "Ok" button
-  if (n == 1) {
-    // extract params and close the dialog
-    widget = (LTKTextIn *)psDialog->findWidget("firstPage");
-    psFirstPage = atoi(widget->getText()->getCString());
-    if (psFirstPage < 1)
-      psFirstPage = 1;
-    widget = (LTKTextIn *)psDialog->findWidget("lastPage");
-    psLastPage = atoi(widget->getText()->getCString());
-    if (psLastPage < psFirstPage)
-      psLastPage = psFirstPage;
-    else if (psLastPage > doc->getNumPages())
-      psLastPage = doc->getNumPages();
-    widget = (LTKTextIn *)psDialog->findWidget("fileName");
-    if (psFileName)
-      delete psFileName;
-    psFileName = widget->getText()->copy();
-    if (!(psFileName->getChar(0) == '|' ||
-         psFileName->cmp("-") == 0))
-      makePathAbsolute(psFileName);
-
-    // do the PostScript output
-    psDialog->setBusyCursor(gTrue);
-    win->setBusyCursor(gTrue);
-    if (doc->okToPrint()) {
-      psOut = new PSOutputDev(psFileName->getCString(), doc->getXRef(),
-                             doc->getCatalog(), psFirstPage, psLastPage,
-                             psModePS);
-      if (psOut->isOk()) {
-       doc->displayPages(psOut, psFirstPage, psLastPage, 72, 0, gFalse);
-      }
-      delete psOut;
-    } else {
-      error(-1, "Printing this document is not allowed.");
-    }
-
-    delete psDialog;
-    win->setBusyCursor(gFalse);
-
-  // "Cancel" button
-  } else {
-    delete psDialog;
-  }
-}
-
-//------------------------------------------------------------------------
-// "About" window
-//------------------------------------------------------------------------
-
-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();
-  }
-}
-
-static void closeAboutCbk(LTKWidget *button, int n, GBool on) {
-  delete aboutWin;
-  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 || doc->getNumPages() == 0)
-    return;
-  mapFindWin();
-}
-
-static void mapFindWin() {
-  if (findWin) {
-    findWin->raise();
-  } else {
-    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) {
-  if (!doc || doc->getNumPages() == 0)
-    return;
-  if (n == 1) {
-    doFind(findTextIn->getText()->getCString());
-  } else {
-    delete findWin;
-    findWin = NULL;
-  }
-}
-
-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]) {
-    XBell(display, 0);
-    return;
-  }
-
-  // set cursors to watch
-  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) {
-    xMin = selectXMax;
-    yMin = (selectYMin + selectYMax) / 2;
-    top = gFalse;
-  } else {
-    top = gTrue;
-  }
-  if (out->findText(u, len, top, gTrue, &xMin, &yMin, &xMax, &yMax)) {
-    goto found;
-  }
-
-  // search following pages
-  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(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(u, len, gTrue, gTrue,
-                         &xMin1, &yMin1, &xMax1, &yMax1)) {
-      goto foundPage;
-    }
-  }
-  delete textOut;
-
-  // search current page ending at current selection
-  if (selectXMin < selectXMax && selectYMin < selectYMax) {
-    xMax = selectXMin;
-    yMax = (selectYMin + selectYMax) / 2;
-    if (out->findText(u, len, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) {
-      goto found;
-    }
-  }
-
-  // not found
-  XBell(display, 0);
-  goto done;
-
-  // found on a different page
- foundPage:
-  delete textOut;
-  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:
-  setSelection(xMin, yMin, xMax, yMax);
-#ifndef NO_TEXT_SELECT
-  if (doc->okToCopy()) {
-    s1 = out->getText(selectXMin, selectYMin, selectXMax, selectYMax);
-    win->setSelection(NULL, s1);
-  }
-#endif
-
- done:
-  gfree(u);
-
-  // reset cursors to normal
-  win->setBusyCursor(gFalse);
-  findWin->setBusyCursor(gFalse);
-}
-
-//------------------------------------------------------------------------
-// app kill callback
-//------------------------------------------------------------------------
-
-static void killCbk(LTKWindow *win1) {
-  if (win1 == win) {
-    quit = gTrue;
-  } else if (win1 == aboutWin) {
-    delete aboutWin;
-    aboutWin = NULL;
-  } else if (win1 == psDialog) {
-    delete psDialog;
-    psDialog = NULL;
-  } else if (win1 == openDialog) {
-    delete openDialog;
-    openDialog = NULL;
-  } else if (win1 == saveDialog) {
-    delete saveDialog;
-    saveDialog = NULL;
-  } else if (win1 == findWin) {
-    delete findWin;
-    findWin = NULL;
-  }
+  return exitCode;
 }