]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/XPDFViewer.cc
Fix for a number of integer overflow bugs discovered by Chris Evans.
[evince.git] / pdf / xpdf / XPDFViewer.cc
index a8c8f8f0fa68d32cb24d10aaf02f7d2547779ae7..b7e5532c628fb737f36356f93658807d9410730d 100644 (file)
@@ -2,7 +2,7 @@
 //
 // XPDFViewer.cc
 //
-// Copyright 2002 Glyph & Cog, LLC
+// Copyright 2002-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
 #ifdef HAVE_X11_XPM_H
 #include <X11/xpm.h>
 #endif
+#if defined(__sgi) && (XmVERSION <= 1)
+#define Object XtObject
+#include <Sgm/HPanedW.h>
+#undef Object
+#endif
 #include "gmem.h"
 #include "gfile.h"
 #include "GString.h"
@@ -36,7 +41,6 @@
 #endif
 #include "XPDFApp.h"
 #include "XPDFViewer.h"
-#include "XPixmapOutputDev.h"
 #include "PSOutputDev.h"
 #include "config.h"
 
 
 //------------------------------------------------------------------------
 
+struct ZoomMenuInfo {
+  char *label;
+  double zoom;
+};
+
+static ZoomMenuInfo zoomMenuInfo[nZoomMenuItems] = {
+  { "400%",      400 },
+  { "200%",      200 },
+  { "150%",      150 },
+  { "125%",      125 },
+  { "100%",      100 },
+  { "50%",        50 },
+  { "25%",        25 },
+  { "12.5%",      12.5 },
+  { "fit page",  zoomPage },
+  { "fit width", zoomWidth }
+};
+
+#define maxZoomIdx   0
+#define defZoomIdx   3
+#define minZoomIdx   7
+#define zoomPageIdx  8
+#define zoomWidthIdx 9
+
+//------------------------------------------------------------------------
+
 XPDFViewer::XPDFViewer(XPDFApp *appA, GString *fileName,
                       int pageA, GString *destName,
                       GString *ownerPassword, GString *userPassword) {
   LinkDest *dest;
-  int pg, z;
+  int pg;
+  double z;
   GString *dir;
 
   app = appA;
@@ -113,6 +144,13 @@ XPDFViewer::XPDFViewer(XPDFApp *appA, GString *fileName,
   if (fileName) {
     if (loadFile(fileName, ownerPassword, userPassword)) {
       getPageAndDest(pageA, destName, &pg, &dest);
+#ifndef DISABLE_OUTLINE
+      if (!app->getFullScreen() &&
+         core->getDoc()->getOutline()->getItems() &&
+         core->getDoc()->getOutline()->getItems()->getLength() > 0) {
+       XtVaSetValues(outlineScroll, XmNwidth, 175, NULL);
+      }
+#endif
       if (pg > 0) {
        core->resizeToPage(pg);
       }
@@ -159,7 +197,8 @@ XPDFViewer::~XPDFViewer() {
 
 void XPDFViewer::open(GString *fileName, int pageA, GString *destName) {
   LinkDest *dest;
-  int pg, z;
+  int pg;
+  double z;
 
   if (!core->getDoc() || fileName->cmp(core->getDoc()->getFileName())) {
     if (!loadFile(fileName, NULL, NULL)) {
@@ -198,6 +237,11 @@ void XPDFViewer::clear() {
   XtVaSetValues(prevPageBtn, XmNsensitive, False, NULL);
   XtVaSetValues(nextTenPageBtn, XmNsensitive, False, NULL);
   XtVaSetValues(nextPageBtn, XmNsensitive, False, NULL);
+
+  // remove the old outline
+#ifndef DISABLE_OUTLINE
+  setupOutline();
+#endif
 }
 
 //------------------------------------------------------------------------
@@ -223,12 +267,12 @@ void XPDFViewer::reloadFile() {
   displayPage(pg, core->getZoom(), core->getRotate(), gFalse, gFalse);
 }
 
-void XPDFViewer::displayPage(int pageA, int zoomA, int rotateA,
+void XPDFViewer::displayPage(int pageA, double zoomA, int rotateA,
                             GBool scrollToTop, GBool addToHist) {
   core->displayPage(pageA, zoomA, rotateA, scrollToTop, addToHist);
 }
 
-void XPDFViewer::displayDest(LinkDest *dest, int zoomA, int rotateA,
+void XPDFViewer::displayDest(LinkDest *dest, double zoomA, int rotateA,
                             GBool addToHist) {
   core->displayDest(dest, zoomA, rotateA, addToHist);
 }
@@ -308,7 +352,7 @@ void XPDFViewer::keyPressCbk(void *data, char *s, KeySym key,
       break;
     case '\007':               // ctrl-G
       if (viewer->core->getDoc()) {
-       XPDFViewer::findFindCbk(None, viewer, NULL);
+       viewer->doFind(gTrue);
       }
       break;
     case '\020':               // ctrl-P
@@ -377,43 +421,39 @@ void XPDFViewer::keyPressCbk(void *data, char *s, KeySym key,
     case '0':
       if (!viewer->app->getFullScreen() &&
          viewer->core->getZoom() != defZoom) {
-       XtVaSetValues(viewer->zoomMenu,
-                     XmNmenuHistory, viewer->getZoomMenuBtn(defZoom),
-                     NULL);
+       viewer->setZoomIdx(defZoomIdx);
        viewer->displayPage(viewer->core->getPageNum(), defZoom,
                            viewer->core->getRotate(), gTrue, gFalse);
       }
       break;
     case '+':
-      if (!viewer->app->getFullScreen() &&
-         viewer->core->getZoom() >= minZoom &&
-         viewer->core->getZoom() < maxZoom) {
-       z = viewer->core->getZoom() + 1;
-       XtVaSetValues(viewer->zoomMenu,
-                     XmNmenuHistory, viewer->getZoomMenuBtn(z),
-                     NULL);
-       viewer->displayPage(viewer->core->getPageNum(), z,
-                           viewer->core->getRotate(), gTrue, gFalse);
+      if (!viewer->app->getFullScreen()) {
+       z = viewer->getZoomIdx();
+       if (z <= minZoomIdx && z > maxZoomIdx) {
+         --z;
+         viewer->setZoomIdx(z);
+         viewer->displayPage(viewer->core->getPageNum(),
+                             zoomMenuInfo[z].zoom,
+                             viewer->core->getRotate(), gTrue, gFalse);
+       }
       }
       break;
     case '-':
-      if (!viewer->app->getFullScreen() &&
-         viewer->core->getZoom() > minZoom &&
-         viewer->core->getZoom() <= maxZoom) {
-       z = viewer->core->getZoom() - 1;
-       XtVaSetValues(viewer->zoomMenu,
-                     XmNmenuHistory, viewer->getZoomMenuBtn(z),
-                     NULL);
-       viewer->displayPage(viewer->core->getPageNum(), z,
-                           viewer->core->getRotate(), gTrue, gFalse);
+      if (!viewer->app->getFullScreen()) {
+       z = viewer->getZoomIdx();
+       if (z < minZoomIdx && z >= maxZoomIdx) {
+         ++z;
+         viewer->setZoomIdx(z);
+         viewer->displayPage(viewer->core->getPageNum(),
+                             zoomMenuInfo[z].zoom,
+                             viewer->core->getRotate(), gTrue, gFalse);
+       }
       }
       break;
     case 'z':
       if (!viewer->app->getFullScreen() &&
          viewer->core->getZoom() != zoomPage) {
-       XtVaSetValues(viewer->zoomMenu,
-                     XmNmenuHistory, viewer->getZoomMenuBtn(zoomPage),
-                     NULL);
+       viewer->setZoomIdx(zoomPageIdx);
        viewer->displayPage(viewer->core->getPageNum(), zoomPage,
                            viewer->core->getRotate(), gTrue, gFalse);
       }
@@ -421,9 +461,7 @@ void XPDFViewer::keyPressCbk(void *data, char *s, KeySym key,
     case 'w':
       if (!viewer->app->getFullScreen() &&
          viewer->core->getZoom() != zoomWidth) {
-       XtVaSetValues(viewer->zoomMenu,
-                     XmNmenuHistory, viewer->getZoomMenuBtn(zoomWidth),
-                     NULL);
+       viewer->setZoomIdx(zoomWidthIdx);
        viewer->displayPage(viewer->core->getPageNum(), zoomWidth,
                            viewer->core->getRotate(), gTrue, gFalse);
       }
@@ -452,6 +490,11 @@ void XPDFViewer::mouseCbk(void *data, XEvent *event) {
   if (event->type == ButtonPress && event->xbutton.button == 3) {
     XmMenuPosition(viewer->popupMenu, &event->xbutton);
     XtManageChild(viewer->popupMenu);
+
+    // this is magic (taken from DDD) - weird things happen if this
+    // call isn't made (this is done in two different places, in hopes
+    // of squashing this stupid bug)
+    XtUngrabButton(viewer->core->getDrawAreaWidget(), AnyButton, AnyModifier);
   }
 }
 
@@ -460,7 +503,7 @@ void XPDFViewer::mouseCbk(void *data, XEvent *event) {
 //------------------------------------------------------------------------
 
 void XPDFViewer::initWindow() {
-  Widget btn, label, menuPane, lastBtn;
+  Widget btn, label, lastBtn, zoomWidget;
 #ifndef DISABLE_OUTLINE
   Widget clipWin;
 #endif
@@ -470,7 +513,6 @@ void XPDFViewer::initWindow() {
   int n;
   char *title;
   XmString s, s2, emptyString;
-  char buf[16];
   int i;
 
   display = XtDisplay(app->getAppShell());
@@ -643,43 +685,50 @@ void XPDFViewer::initWindow() {
   XmStringFree(s);
 
   // zoom menu
+#if USE_COMBO_BOX
+  XmString st[nZoomMenuItems];
+  n = 0;
+  XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+  XtSetArg(args[n], XmNleftWidget, pageCountLabel); ++n;
+  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+  XtSetArg(args[n], XmNmarginWidth, 0); ++n;
+  XtSetArg(args[n], XmNmarginHeight, 0); ++n;
+  XtSetArg(args[n], XmNcomboBoxType, XmDROP_DOWN_COMBO_BOX); ++n;
+  XtSetArg(args[n], XmNpositionMode, XmONE_BASED); ++n;
+  XtSetArg(args[n], XmNcolumns, 7); ++n;
+  for (i = 0; i < nZoomMenuItems; ++i) {
+    st[i] = XmStringCreateLocalized(zoomMenuInfo[i].label);
+  }
+  XtSetArg(args[n], XmNitems, st); ++n;
+  XtSetArg(args[n], XmNitemCount, nZoomMenuItems); ++n;
+  zoomComboBox = XmCreateComboBox(toolBar, "zoomComboBox", args, n);
+  for (i = 0; i < nZoomMenuItems; ++i) {
+    XmStringFree(st[i]);
+  }
+  XtAddCallback(zoomComboBox, XmNselectionCallback,
+               &zoomComboBoxCbk, (XtPointer)this);
+  XtManageChild(zoomComboBox);
+  zoomWidget = zoomComboBox;
+#else
+  Widget menuPane;
+  char buf[16];
   n = 0;
   menuPane = XmCreatePulldownMenu(toolBar, "zoomMenuPane", args, n);
-  for (i = minZoom; i <= maxZoom; ++i) {
+  for (i = 0; i < nZoomMenuItems; ++i) {
     n = 0;
-    sprintf(buf, "%s%d", i > 0 ? "+" : "", i);
-    s = XmStringCreateLocalized(buf);
+    s = XmStringCreateLocalized(zoomMenuInfo[i].label);
     XtSetArg(args[n], XmNlabelString, s); ++n;
     XtSetArg(args[n], XmNuserData, (XtPointer)i); ++n;
-    sprintf(buf, "zoom%s%d", i < 0 ? "M" : "", i < 0 ? -i : i);
+    sprintf(buf, "zoom%d", i);
     btn = XmCreatePushButton(menuPane, buf, args, n);
     XmStringFree(s);
     XtManageChild(btn);
     XtAddCallback(btn, XmNactivateCallback,
                  &zoomMenuCbk, (XtPointer)this);
-    zoomMenuBtns[i - minZoom] = btn;
+    zoomMenuBtns[i] = btn;
   }
   n = 0;
-  s = XmStringCreateLocalized("fit page");
-  XtSetArg(args[n], XmNlabelString, s); ++n;
-  XtSetArg(args[n], XmNuserData, (XtPointer)zoomPage); ++n;
-  btn = XmCreatePushButton(menuPane, "zoomPage", args, n);
-  XmStringFree(s);
-  XtManageChild(btn);
-  XtAddCallback(btn, XmNactivateCallback,
-               &zoomMenuCbk, (XtPointer)this);
-  zoomMenuBtns[maxZoom - minZoom + 1] = btn;
-  n = 0;
-  s = XmStringCreateLocalized("fit width");
-  XtSetArg(args[n], XmNlabelString, s); ++n;
-  XtSetArg(args[n], XmNuserData, (XtPointer)zoomWidth); ++n;
-  btn = XmCreatePushButton(menuPane, "zoomWidth", args, n);
-  XmStringFree(s);
-  XtManageChild(btn);
-  XtAddCallback(btn, XmNactivateCallback,
-               &zoomMenuCbk, (XtPointer)this);
-  zoomMenuBtns[maxZoom - minZoom + 2] = btn;
-  n = 0;
   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
   XtSetArg(args[n], XmNleftWidget, pageCountLabel); ++n;
   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
@@ -689,11 +738,13 @@ void XPDFViewer::initWindow() {
   XtSetArg(args[n], XmNsubMenuId, menuPane); ++n;
   zoomMenu = XmCreateOptionMenu(toolBar, "zoomMenu", args, n);
   XtManageChild(zoomMenu);
+  zoomWidget = zoomMenu;
+#endif
 
   // find/print/about buttons
   n = 0;
   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
-  XtSetArg(args[n], XmNleftWidget, zoomMenu); ++n;
+  XtSetArg(args[n], XmNleftWidget, zoomWidget); ++n;
   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
   XtSetArg(args[n], XmNmarginWidth, 6); ++n;
@@ -744,8 +795,8 @@ void XPDFViewer::initWindow() {
   n = 0;
   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
   XtSetArg(args[n], XmNleftWidget, lastBtn); ++n;
-  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
-  XtSetArg(args[n], XmNrightWidget, btn); ++n;
+  XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); ++n;
+  XtSetArg(args[n], XmNrightWidget, quitBtn); ++n;
   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
   s = XmStringCreateLocalized("");
@@ -761,7 +812,7 @@ void XPDFViewer::initWindow() {
 #endif
 
     // core
-    core = new XPDFCore(win, form, app->getPaperColor(),
+    core = new XPDFCore(win, form, app->getPaperRGB(),
                        app->getFullScreen(), app->getReverseVideo(),
                        app->getInstallCmap(), app->getRGBCubeSize());
     core->setUpdateCbk(&updateCbk, this);
@@ -788,7 +839,11 @@ void XPDFViewer::initWindow() {
     XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
     XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
     XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
+#if defined(__sgi) && (XmVERSION <= 1)
+    panedWin = SgCreateHorzPanedWindow(form, "panedWin", args, n);
+#else
     panedWin = XmCreatePanedWindow(form, "panedWin", args, n);
+#endif
     XtManageChild(panedWin);
 
     // scrolled window for outline container
@@ -797,7 +852,9 @@ void XPDFViewer::initWindow() {
     XtSetArg(args[n], XmNallowResize, True); ++n;
     XtSetArg(args[n], XmNpaneMinimum, 1); ++n;
     XtSetArg(args[n], XmNpaneMaximum, 10000); ++n;
+#if !(defined(__sgi) && (XmVERSION <= 1))
     XtSetArg(args[n], XmNwidth, 1); ++n;
+#endif
     XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); ++n;
     outlineScroll = XmCreateScrolledWindow(panedWin, "outlineScroll", args, n);
     XtManageChild(outlineScroll);
@@ -813,7 +870,7 @@ void XPDFViewer::initWindow() {
                  (XtPointer)this);
 
     // core
-    core = new XPDFCore(win, panedWin, app->getPaperColor(),
+    core = new XPDFCore(win, panedWin, app->getPaperRGB(),
                        app->getFullScreen(), app->getReverseVideo(),
                        app->getInstallCmap(), app->getRGBCubeSize());
     core->setUpdateCbk(&updateCbk, this);
@@ -831,8 +888,7 @@ void XPDFViewer::initWindow() {
 #endif
 
   // set the zoom menu to match the initial zoom setting
-  XtVaSetValues(zoomMenu, XmNmenuHistory,
-               getZoomMenuBtn(core->getZoom()), NULL);
+  setZoomVal(core->getZoom());
 
   // set traversal order
   XtVaSetValues(core->getDrawAreaWidget(),
@@ -851,7 +907,7 @@ void XPDFViewer::initWindow() {
                NULL);
   XtVaSetValues(pageNumText, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
                NULL);
-  XtVaSetValues(zoomMenu, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+  XtVaSetValues(zoomWidget, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
                NULL);
   XtVaSetValues(findBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
                NULL);
@@ -864,7 +920,12 @@ void XPDFViewer::initWindow() {
 
   // popup menu
   n = 0;
+#if XmVersion < 1002
+  // older versions of Motif need this, newer ones choke on it,
+  // sometimes not displaying the menu at all, maybe depending on the
+  // state of the NumLock key (taken from DDD)
   XtSetArg(args[n], XmNmenuPost, "<Btn3Down>"); ++n;
+#endif
   popupMenu = XmCreatePopupMenu(core->getDrawAreaWidget(), "popupMenu",
                                args, n);
   n = 0;
@@ -950,6 +1011,10 @@ void XPDFViewer::initWindow() {
   XtAddCallback(btn, XmNactivateCallback,
                &quitCbk, (XtPointer)this);
 
+  // this is magic (taken from DDD) - weird things happen if this
+  // call isn't made
+  XtUngrabButton(core->getDrawAreaWidget(), AnyButton, AnyModifier);
+
   XmStringFree(emptyString);
 }
 
@@ -958,7 +1023,7 @@ void XPDFViewer::mapWindow() {
   Pixmap iconPixmap;
 #endif
   int depth;
-  Pixel bg, arm;
+  Pixel fg, bg, arm;
 
   // show the window
   XtPopup(win, XtGrabNone);
@@ -974,29 +1039,27 @@ void XPDFViewer::mapWindow() {
 
   // set button bitmaps (must be done after the window is mapped)
   XtVaGetValues(backBtn, XmNdepth, &depth,
-               XmNbackground, &bg, XmNarmColor, &arm, NULL);
+               XmNforeground, &fg, XmNbackground, &bg,
+               XmNarmColor, &arm, NULL);
   XtVaSetValues(backBtn, XmNlabelType, XmPIXMAP,
                XmNlabelPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)backArrow_bits,
                                            backArrow_width,
                                            backArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                XmNarmPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)backArrow_bits,
                                            backArrow_width,
                                            backArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           arm, depth),
+                                           fg, arm, depth),
                XmNlabelInsensitivePixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)backArrowDis_bits,
                                            backArrowDis_width,
                                            backArrowDis_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                NULL);
   XtVaSetValues(prevTenPageBtn, XmNlabelType, XmPIXMAP,
                XmNlabelPixmap,
@@ -1004,22 +1067,19 @@ void XPDFViewer::mapWindow() {
                                            (char *)dblLeftArrow_bits,
                                            dblLeftArrow_width,
                                            dblLeftArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                XmNarmPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)dblLeftArrow_bits,
                                            dblLeftArrow_width,
                                            dblLeftArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           arm, depth),
+                                           fg, arm, depth),
                XmNlabelInsensitivePixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)dblLeftArrowDis_bits,
                                            dblLeftArrowDis_width,
                                            dblLeftArrowDis_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                NULL);
   XtVaSetValues(prevPageBtn, XmNlabelType, XmPIXMAP,
                XmNlabelPixmap,
@@ -1027,22 +1087,19 @@ void XPDFViewer::mapWindow() {
                                            (char *)leftArrow_bits,
                                            leftArrow_width,
                                            leftArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                XmNarmPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)leftArrow_bits,
                                            leftArrow_width,
                                            leftArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           arm, depth),
+                                           fg, arm, depth),
                XmNlabelInsensitivePixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)leftArrowDis_bits,
                                            leftArrowDis_width,
                                            leftArrowDis_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                NULL);
   XtVaSetValues(nextPageBtn, XmNlabelType, XmPIXMAP,
                XmNlabelPixmap,
@@ -1050,22 +1107,19 @@ void XPDFViewer::mapWindow() {
                                            (char *)rightArrow_bits,
                                            rightArrow_width,
                                            rightArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                XmNarmPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)rightArrow_bits,
                                            rightArrow_width,
                                            rightArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           arm, depth),
+                                           fg, arm, depth),
                XmNlabelInsensitivePixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)rightArrowDis_bits,
                                            rightArrowDis_width,
                                            rightArrowDis_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                NULL);
   XtVaSetValues(nextTenPageBtn, XmNlabelType, XmPIXMAP,
                XmNlabelPixmap,
@@ -1073,22 +1127,19 @@ void XPDFViewer::mapWindow() {
                                            (char *)dblRightArrow_bits,
                                            dblRightArrow_width,
                                            dblRightArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                XmNarmPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)dblRightArrow_bits,
                                            dblRightArrow_width,
                                            dblRightArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           arm, depth),
+                                           fg, arm, depth),
                XmNlabelInsensitivePixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)dblRightArrowDis_bits,
                                            dblRightArrowDis_width,
                                            dblRightArrowDis_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                NULL);
   XtVaSetValues(forwardBtn, XmNlabelType, XmPIXMAP,
                XmNlabelPixmap,
@@ -1096,22 +1147,19 @@ void XPDFViewer::mapWindow() {
                                            (char *)forwardArrow_bits,
                                            forwardArrow_width,
                                            forwardArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                XmNarmPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)forwardArrow_bits,
                                            forwardArrow_width,
                                            forwardArrow_height,
-                                           BlackPixel(display, screenNum),
-                                           arm, depth),
+                                           fg, arm, depth),
                XmNlabelInsensitivePixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)forwardArrowDis_bits,
                                            forwardArrowDis_width,
                                            forwardArrowDis_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                NULL);
   XtVaSetValues(findBtn, XmNlabelType, XmPIXMAP,
                XmNlabelPixmap,
@@ -1119,22 +1167,19 @@ void XPDFViewer::mapWindow() {
                                            (char *)find_bits,
                                            find_width,
                                            find_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                XmNarmPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)find_bits,
                                            find_width,
                                            find_height,
-                                           BlackPixel(display, screenNum),
-                                           arm, depth),
+                                           fg, arm, depth),
                XmNlabelInsensitivePixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)findDis_bits,
                                            findDis_width,
                                            findDis_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                NULL);
   XtVaSetValues(printBtn, XmNlabelType, XmPIXMAP,
                XmNlabelPixmap,
@@ -1142,22 +1187,19 @@ void XPDFViewer::mapWindow() {
                                            (char *)print_bits,
                                            print_width,
                                            print_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                XmNarmPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)print_bits,
                                            print_width,
                                            print_height,
-                                           BlackPixel(display, screenNum),
-                                           arm, depth),
+                                           fg, arm, depth),
                XmNlabelInsensitivePixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)printDis_bits,
                                            printDis_width,
                                            printDis_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                NULL);
   XtVaSetValues(aboutBtn, XmNlabelType, XmPIXMAP,
                XmNlabelPixmap,
@@ -1165,15 +1207,13 @@ void XPDFViewer::mapWindow() {
                                            (char *)about_bits,
                                            about_width,
                                            about_height,
-                                           BlackPixel(display, screenNum),
-                                           bg, depth),
+                                           fg, bg, depth),
                XmNarmPixmap,
                XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
                                            (char *)about_bits,
                                            about_width,
                                            about_height,
-                                           BlackPixel(display, screenNum),
-                                           arm, depth),
+                                           fg, arm, depth),
                NULL);
 }
 
@@ -1182,17 +1222,67 @@ void XPDFViewer::closeWindow() {
   XtDestroyWidget(win);
 }
 
-Widget XPDFViewer::getZoomMenuBtn(int z) {
-  if (z >= minZoom && z <= maxZoom) {
-    return zoomMenuBtns[z - minZoom];
+int XPDFViewer::getZoomIdx() {
+#if USE_COMBO_BOX
+  int z;
+
+  XtVaGetValues(zoomComboBox, XmNselectedPosition, &z, NULL);
+  return z - 1;
+#else
+  Widget w;
+  int i;
+
+  XtVaGetValues(zoomMenu, XmNmenuHistory, &w, NULL);
+  for (i = 0; i < nZoomMenuItems; ++i) {
+    if (w == zoomMenuBtns[i]) {
+      return i;
+    }
   }
-  if (z == zoomPage) {
-    return zoomMenuBtns[maxZoom - minZoom + 1];
+  // this should never happen
+  return 0;
+#endif
+}
+
+void XPDFViewer::setZoomIdx(int idx) {
+#if USE_COMBO_BOX
+  XtVaSetValues(zoomComboBox, XmNselectedPosition, idx + 1, NULL);
+#else
+  XtVaSetValues(zoomMenu, XmNmenuHistory, zoomMenuBtns[idx], NULL);
+#endif
+}
+
+void XPDFViewer::setZoomVal(double z) {
+#if USE_COMBO_BOX
+  char buf[32];
+  XmString s;
+  int i;
+
+  for (i = 0; i < nZoomMenuItems; ++i) {
+    if (z == zoomMenuInfo[i].zoom) {
+      XtVaSetValues(zoomComboBox, XmNselectedPosition, i + 1, NULL);
+      return;
+    }
   }
-  if (z == zoomWidth) {
-    return zoomMenuBtns[maxZoom - minZoom + 2];
+  sprintf(buf, "%d", (int)z);
+  s = XmStringCreateLocalized(buf);
+  XtVaSetValues(zoomComboBox, XmNselectedItem, s, NULL);
+  XmStringFree(s);
+#else
+  int i;
+
+  for (i = 0; i < nZoomMenuItems; ++i) {
+    if (z == zoomMenuInfo[i].zoom) {
+      XtVaSetValues(zoomMenu, XmNmenuHistory, zoomMenuBtns[i], NULL);
+      return;
+    }
   }
-  return zoomMenuBtns[0];
+  for (i = maxZoomIdx; i < minZoomIdx; ++i) {
+    if (z > zoomMenuInfo[i].zoom) {
+      break;
+    }
+  }
+  XtVaSetValues(zoomMenu, XmNmenuHistory, zoomMenuBtns[i], NULL);
+#endif
 }
 
 void XPDFViewer::prevPageCbk(Widget widget, XtPointer ptr,
@@ -1243,19 +1333,65 @@ void XPDFViewer::forwardCbk(Widget widget, XtPointer ptr,
   viewer->core->takeFocus();
 }
 
+#if USE_COMBO_BOX
+
+void XPDFViewer::zoomComboBoxCbk(Widget widget, XtPointer ptr,
+                                XtPointer callData) {
+  XPDFViewer *viewer = (XPDFViewer *)ptr;
+  XmComboBoxCallbackStruct *data = (XmComboBoxCallbackStruct *)callData;
+  double z;
+  char *s;
+  XmStringContext context;
+  XmStringCharSet charSet;
+  XmStringDirection dir;
+  Boolean sep;
+
+  z = viewer->core->getZoom();
+  if (data->item_position == 0) {
+    XmStringInitContext(&context, data->item_or_text);
+    if (XmStringGetNextSegment(context, &s, &charSet, &dir, &sep)) {
+      z = atof(s);
+      if (z <= 1) {
+       z = defZoom;
+      }
+      XtFree(charSet);
+      XtFree(s);
+    }
+    XmStringFreeContext(context);
+  } else {
+    z = zoomMenuInfo[data->item_position - 1].zoom;
+  }
+  // only redraw if this was triggered by an event; otherwise
+  // the caller is responsible for doing the redraw
+  if (z != viewer->core->getZoom() && data->event) {
+    viewer->displayPage(viewer->core->getPageNum(), z,
+                       viewer->core->getRotate(), gTrue, gFalse);
+  }
+  viewer->core->takeFocus();
+}
+
+#else // USE_COMBO_BOX
+
 void XPDFViewer::zoomMenuCbk(Widget widget, XtPointer ptr,
                             XtPointer callData) {
   XPDFViewer *viewer = (XPDFViewer *)ptr;
+  XmPushButtonCallbackStruct *data = (XmPushButtonCallbackStruct *)callData;
   XtPointer userData;
+  double z;
 
   XtVaGetValues(widget, XmNuserData, &userData, NULL);
-  if ((int)userData != viewer->core->getZoom()) {
-    viewer->displayPage(viewer->core->getPageNum(), (int)userData,
+  z = zoomMenuInfo[(int)userData].zoom;
+  // only redraw if this was triggered by an event; otherwise
+  // the caller is responsible for doing the redraw
+  if (z != viewer->core->getZoom() && data->event) {
+    viewer->displayPage(viewer->core->getPageNum(), z,
                        viewer->core->getRotate(), gTrue, gFalse);
   }
   viewer->core->takeFocus();
 }
 
+#endif // USE_COMBO_BOX
+
 void XPDFViewer::findCbk(Widget widget, XtPointer ptr,
                         XtPointer callData) {
   XPDFViewer *viewer = (XPDFViewer *)ptr;
@@ -1389,7 +1525,7 @@ void XPDFViewer::pageNumCbk(Widget widget, XtPointer ptr,
 }
 
 void XPDFViewer::updateCbk(void *data, GString *fileName,
-                          int pageNum, int numPages, char *linkLabel) {
+                          int pageNum, int numPages, char *linkString) {
   XPDFViewer *viewer = (XPDFViewer *)data;
   GString *title;
   char buf[20];
@@ -1439,8 +1575,8 @@ void XPDFViewer::updateCbk(void *data, GString *fileName,
     XmStringFree(s);
   }
 
-  if (linkLabel) {
-    s = XmStringCreateLocalized(linkLabel);
+  if (linkString) {
+    s = XmStringCreateLocalized(linkString);
     XtVaSetValues(viewer->linkLabel, XmNlabelString, s, NULL);
     XmStringFree(s);
   }
@@ -1470,18 +1606,21 @@ void XPDFViewer::setupOutline() {
     outlineLabelsLength = outlineLabelsSize = 0;
   }
 
-  // create the new labels
-  items = core->getDoc()->getOutline()->getItems();
-  if (items && items->getLength() > 0) {
-    enc = new GString("Latin1");
-    uMap = globalParams->getUnicodeMap(enc);
-    delete enc;
-    setupOutlineItems(items, NULL, uMap);
-    uMap->decRefCnt();
-  }
+  if (core->getDoc()) {
 
-  // manage the new labels
-  XtManageChildren(outlineLabels, outlineLabelsLength);
+    // create the new labels
+    items = core->getDoc()->getOutline()->getItems();
+    if (items && items->getLength() > 0) {
+      enc = new GString("Latin1");
+      uMap = globalParams->getUnicodeMap(enc);
+      delete enc;
+      setupOutlineItems(items, NULL, uMap);
+      uMap->decRefCnt();
+    }
+
+    // manage the new labels
+    XtManageChildren(outlineLabels, outlineLabelsLength);
+  }
 }
 
 void XPDFViewer::setupOutlineItems(GList *items, Widget parent,
@@ -1600,18 +1739,12 @@ void XPDFViewer::initAboutDialog() {
   XtManageChild(col);
 
   //----- fonts
-  aboutBigFont = XmFontListAppendEntry(NULL,
-      XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT,
-         XLoadQueryFont(display,
-             "-*-times-bold-i-normal--20-*-*-*-*-*-iso8859-1")));
-  aboutVersionFont = XmFontListAppendEntry(NULL,
-      XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT,
-         XLoadQueryFont(display,
-             "-*-times-medium-r-normal--16-*-*-*-*-*-iso8859-1")));
-  aboutFixedFont = XmFontListAppendEntry(NULL,
-      XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT,
-         XLoadQueryFont(display,
-             "-*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1")));
+  aboutBigFont =
+    createFontList("-*-times-bold-i-normal--20-*-*-*-*-*-iso8859-1");
+  aboutVersionFont =
+    createFontList("-*-times-medium-r-normal--16-*-*-*-*-*-iso8859-1");
+  aboutFixedFont =
+    createFontList("-*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1");
 
   //----- heading
   n = 0;
@@ -1745,7 +1878,7 @@ void XPDFViewer::openOkCbk(Widget widget, XtPointer ptr,
 //------------------------------------------------------------------------
 
 void XPDFViewer::initFindDialog() {
-  Widget row1, label, okBtn, closeBtn;
+  Widget form1, label, okBtn, closeBtn;
   Arg args[20];
   int n;
   XmString s;
@@ -1759,31 +1892,8 @@ void XPDFViewer::initFindDialog() {
   findDialog = XmCreateFormDialog(win, "findDialog", args, n);
   XmStringFree(s);
 
-  //----- top row: search string entry
-  n = 0;
-  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
-  XtSetArg(args[n], XmNtopOffset, 4); ++n;
-  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
-  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
-  XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
-  XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); ++n;
-  row1 = XmCreateRowColumn(findDialog, "row1", args, n);
-  XtManageChild(row1);
-  n = 0;
-  s = XmStringCreateLocalized("Find text: ");
-  XtSetArg(args[n], XmNlabelString, s); ++n;
-  label = XmCreateLabel(row1, "label", args, n);
-  XmStringFree(s);
-  XtManageChild(label);
-  n = 0;
-  XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n;
-  findText = XmCreateTextField(row1, "text", args, n);
-  XtManageChild(findText);
-
   //----- "find" and "close" buttons
   n = 0;
-  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
-  XtSetArg(args[n], XmNtopWidget, row1); ++n;
   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
   XtSetArg(args[n], XmNleftOffset, 4); ++n;
   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
@@ -1794,8 +1904,6 @@ void XPDFViewer::initFindDialog() {
   XtAddCallback(okBtn, XmNactivateCallback,
                &findFindCbk, (XtPointer)this);
   n = 0;
-  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
-  XtSetArg(args[n], XmNtopWidget, row1); ++n;
   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
   XtSetArg(args[n], XmNrightOffset, 4); ++n;
   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
@@ -1805,10 +1913,48 @@ void XPDFViewer::initFindDialog() {
   XtManageChild(closeBtn);
   XtAddCallback(closeBtn, XmNactivateCallback,
                &findCloseCbk, (XtPointer)this);
+
+  //----- search string entry
+  n = 0;
+  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+  XtSetArg(args[n], XmNtopOffset, 4); ++n;
+  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n;
+  XtSetArg(args[n], XmNbottomWidget, okBtn); ++n;
+  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+  XtSetArg(args[n], XmNleftOffset, 2); ++n;
+  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+  XtSetArg(args[n], XmNrightOffset, 2); ++n;
+  form1 = XmCreateForm(findDialog, "form", args, n);
+  XtManageChild(form1);
+  n = 0;
+  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+  s = XmStringCreateLocalized("Find text: ");
+  XtSetArg(args[n], XmNlabelString, s); ++n;
+  label = XmCreateLabel(form1, "label", args, n);
+  XmStringFree(s);
+  XtManageChild(label);
+  n = 0;
+  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+  XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+  XtSetArg(args[n], XmNleftWidget, label); ++n;
+  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+  findText = XmCreateTextField(form1, "text", args, n);
+  XtManageChild(findText);
+#ifdef LESSTIF_VERSION
+  XtAddCallback(findText, XmNactivateCallback,
+               &findFindCbk, (XtPointer)this);
+#endif
+
+  //----- dialog parameters
   n = 0;
   XtSetArg(args[n], XmNdefaultButton, okBtn); ++n;
   XtSetArg(args[n], XmNcancelButton, closeBtn); ++n;
+#if XmVersion > 1001
   XtSetArg(args[n], XmNinitialFocus, findText); ++n;
+#endif
   XtSetValues(findDialog, args, n);
 }
 
@@ -1816,7 +1962,17 @@ void XPDFViewer::findFindCbk(Widget widget, XtPointer ptr,
                             XtPointer callData) {
   XPDFViewer *viewer = (XPDFViewer *)ptr;
 
-  viewer->core->find(XmTextFieldGetString(viewer->findText));
+  viewer->doFind(gFalse);
+}
+
+void XPDFViewer::doFind(GBool next) {
+  if (XtWindow(findDialog)) {
+    XDefineCursor(display, XtWindow(findDialog), core->getBusyCursor());
+  }
+  core->find(XmTextFieldGetString(findText), next);
+  if (XtWindow(findDialog)) {
+    XUndefineCursor(display, XtWindow(findDialog));
+  }
 }
 
 void XPDFViewer::findCloseCbk(Widget widget, XtPointer ptr,
@@ -1899,6 +2055,7 @@ void XPDFViewer::initPrintDialog() {
   Arg args[20];
   int n;
   XmString s;
+  GString *psFileName;
 
   //----- dialog
   n = 0;
@@ -2047,37 +2204,42 @@ void XPDFViewer::initPrintDialog() {
   XtSetArg(args[n], XmNdefaultButton, okBtn); ++n;
   XtSetArg(args[n], XmNcancelButton, cancelBtn); ++n;
   XtSetValues(printDialog, args, n);
+
+  //----- initial values
+  if ((psFileName = globalParams->getPSFile())) {
+    if (psFileName->getChar(0) == '|') {
+      XmTextFieldSetString(printCmdText,
+                          psFileName->getCString() + 1);
+    } else {
+      XmTextFieldSetString(printFileText, psFileName->getCString());
+    }
+    delete psFileName;
+  }
 }
 
 void XPDFViewer::setupPrintDialog() {
   PDFDoc *doc;
   char buf[20];
-  GString *pdfFileName, *psFileName;
+  GString *pdfFileName, *psFileName, *psFileName2;
   char *p;
 
   doc = core->getDoc();
-
   psFileName = globalParams->getPSFile();
-  if (psFileName && psFileName->getChar(0) != '|') {
-    XmTextFieldSetString(printFileText, psFileName->getCString());
-  } else {
+  if (!psFileName || psFileName->getChar(0) == '|') {
     pdfFileName = doc->getFileName();
     p = pdfFileName->getCString() + pdfFileName->getLength() - 4;
     if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) {
-      psFileName = new GString(pdfFileName->getCString(),
-                              pdfFileName->getLength() - 4);
+      psFileName2 = new GString(pdfFileName->getCString(),
+                               pdfFileName->getLength() - 4);
     } else {
-      psFileName = pdfFileName->copy();
+      psFileName2 = pdfFileName->copy();
     }
-    psFileName->append(".ps");
-    XmTextFieldSetString(printFileText, psFileName->getCString());
-    delete psFileName;
+    psFileName2->append(".ps");
+    XmTextFieldSetString(printFileText, psFileName2->getCString());
+    delete psFileName2;
   }
-
-  psFileName = globalParams->getPSFile();
-  if (psFileName && psFileName->getChar(0) == '|') {
-    XmTextFieldSetString(printCmdText,
-                        psFileName->getCString() + 1);
+  if (psFileName) {
+    delete psFileName;
   }
 
   sprintf(buf, "%d", doc->getNumPages());
@@ -2155,7 +2317,8 @@ void XPDFViewer::printPrintCbk(Widget widget, XtPointer ptr,
                          doc->getCatalog(), firstPage, lastPage,
                          psModePS);
   if (psOut->isOk()) {
-    doc->displayPages(psOut, firstPage, lastPage, 72, 0, gFalse);
+    doc->displayPages(psOut, firstPage, lastPage, 72, 72,
+                     0, globalParams->getPSCrop(), gFalse);
   }
   delete psOut;
   delete psFileName;
@@ -2247,7 +2410,9 @@ void XPDFViewer::initPasswordDialog() {
   n = 0;
   XtSetArg(args[n], XmNdefaultButton, okBtn); ++n;
   XtSetArg(args[n], XmNcancelButton, cancelBtn); ++n;
+#if XmVersion > 1001
   XtSetArg(args[n], XmNinitialFocus, passwordText); ++n;
+#endif
   XtSetValues(passwordDialog, args, n);
 }
 
@@ -2316,3 +2481,43 @@ void XPDFViewer::getPassword(GBool again) {
     password = NULL;
   }
 }
+
+//------------------------------------------------------------------------
+// Motif support
+//------------------------------------------------------------------------
+
+XmFontList XPDFViewer::createFontList(char *xlfd) {
+  XmFontList fontList;
+
+#if XmVersion <= 1001
+
+  XFontStruct *font;
+  String params;
+  Cardinal nParams;
+
+  font = XLoadQueryFont(display, xlfd);
+  if (font) {
+    fontList = XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET);
+  } else {
+    params = (String)xlfd;
+    nParams = 1;
+    XtAppWarningMsg(app->getAppContext(),
+                   "noSuchFont", "CvtStringToXmFontList",
+                   "XtToolkitError", "No such font: %s",
+                   &params, &nParams);
+    fontList = NULL;
+  }
+
+#else
+
+  XmFontListEntry entry;
+
+  entry = XmFontListEntryLoad(display, xlfd,
+                             XmFONT_IS_FONT, XmFONTLIST_DEFAULT_TAG);
+  fontList = XmFontListAppendEntry(NULL, entry);
+  XmFontListEntryFree(&entry);
+
+#endif
+
+  return fontList;
+}