1 //========================================================================
5 // Copyright 1996-2002 Glyph & Cog, LLC
7 //========================================================================
16 #include <X11/cursorfont.h>
17 #include <X11/keysym.h>
20 #include "parseargs.h"
23 #include "GlobalParams.h"
34 #include "XOutputDev.h"
35 #include "LTKOutputDev.h"
36 #include "PSOutputDev.h"
37 #include "TextOutputDev.h"
41 #ifdef XlibSpecificationRelease
42 #if XlibSpecificationRelease < 5
43 typedef char *XPointer;
46 typedef char *XPointer;
49 // hack around old X includes which are missing these symbols
51 #define XK_Page_Up 0xFF55
54 #define XK_Page_Down 0xFF56
57 #define XK_KP_Home 0xFF95
60 #define XK_KP_Left 0xFF96
63 #define XK_KP_Up 0xFF97
66 #define XK_KP_Right 0xFF98
69 #define XK_KP_Down 0xFF99
72 #define XK_KP_Prior 0xFF9A
75 #define XK_KP_Page_Up 0xFF9A
78 #define XK_KP_Next 0xFF9B
80 #ifndef XK_KP_Page_Down
81 #define XK_KP_Page_Down 0xFF9B
84 #define XK_KP_End 0xFF9C
87 #define XK_KP_Begin 0xFF9D
90 #define XK_KP_Insert 0xFF9E
93 #define XK_KP_Delete 0xFF9F
96 //------------------------------------------------------------------------
97 // misc constants / enums
98 //------------------------------------------------------------------------
100 #define remoteCmdLength 512
111 //------------------------------------------------------------------------
113 //------------------------------------------------------------------------
115 // loadFile / displayPage
116 static GBool loadFile(GString *fileName);
117 static void displayPage(int page1, int zoomA, int rotateA, GBool addToHist);
118 static void displayDest(LinkDest *dest, int zoomA, int rotateA,
121 // key press and menu callbacks
122 static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers,
124 static void menuCbk(LTKMenuItem *item);
127 static void buttonPressCbk(LTKWidget *canvas1, int n,
128 int mx, int my, int button, GBool dblClick);
129 static void buttonReleaseCbk(LTKWidget *canvas1, int n,
130 int mx, int my, int button, GBool click);
131 static void doLink(int mx, int my);
132 static void mouseMoveCbk(LTKWidget *widget, int widgetNum, int mx, int my);
133 static void mouseDragCbk(LTKWidget *widget, int widgetNum,
134 int mx, int my, int button);
137 static void nextPageCbk(LTKWidget *button, int n, GBool on);
138 static void nextTenPageCbk(LTKWidget *button, int n, GBool on);
139 static void gotoNextPage(int inc, GBool top);
140 static void prevPageCbk(LTKWidget *button, int n, GBool on);
141 static void prevTenPageCbk(LTKWidget *button, int n, GBool on);
142 static void gotoPrevPage(int dec, GBool top, GBool bottom);
143 static void backCbk(LTKWidget *button, int n, GBool on);
144 static void forwardCbk(LTKWidget *button, int n, GBool on);
145 static void pageNumCbk(LTKWidget *textIn, int n, GString *text);
146 static void zoomMenuCbk(LTKMenuItem *item);
147 static void postScriptCbk(LTKWidget *button, int n, GBool on);
148 static void aboutCbk(LTKWidget *button, int n, GBool on);
149 static void quitCbk(LTKWidget *button, int n, GBool on);
151 // scrollbar callbacks
152 static void scrollVertCbk(LTKWidget *scrollbar, int n, int val);
153 static void scrollHorizCbk(LTKWidget *scrollbar, int n, int val);
156 static void layoutCbk(LTKWindow *win1);
157 static void updateScrollbars();
158 static void propChangeCbk(LTKWindow *win1, Atom atom);
161 static void setSelection(int newXMin, int newYMin, int newXMax, int newYMax);
164 static void mapOpenDialog();
165 static void openButtonCbk(LTKWidget *button, int n, GBool on);
166 static void openSelectCbk(LTKWidget *widget, int n, GString *name);
169 static void reloadCbk();
172 static void mapSaveDialog();
173 static void saveButtonCbk(LTKWidget *button, int n, GBool on);
174 static void saveSelectCbk(LTKWidget *widget, int n, GString *name);
176 // "PostScript" dialog
177 static void mapPSDialog();
178 static void psButtonCbk(LTKWidget *button, int n, GBool on);
181 static void mapAboutWin();
182 static void closeAboutCbk(LTKWidget *button, int n, GBool on);
183 static void aboutLayoutCbk(LTKWindow *winA);
184 static void aboutScrollVertCbk(LTKWidget *scrollbar, int n, int val);
185 static void aboutScrollHorizCbk(LTKWidget *scrollbar, int n, int val);
188 static void findCbk(LTKWidget *button, int n, GBool on);
189 static void mapFindWin();
190 static void findButtonCbk(LTKWidget *button, int n, GBool on);
191 static void doFind(char *s);
194 static void killCbk(LTKWindow *win1);
196 //------------------------------------------------------------------------
197 // "About" window text
198 //------------------------------------------------------------------------
200 static char *aboutWinText[] = {
207 "X X pppp dddd f Version " xpdfVersion,
214 "http://www.foolabs.com/xpdf/",
215 "derekn@foolabs.com",
217 "Licensed under the GNU General Public License (GPL).",
218 "See the 'COPYING' file for details.",
220 "Supports PDF version " supportedPDFVersionStr ".",
222 "The PDF data structures, operators, and specification",
223 "are copyright 1985-2001 Adobe Systems Inc.",
226 " button 1: select text / follow link",
227 " button 2: pan window",
234 " n = <PgDn> = next page",
235 " p = <PgUp> = previous page",
236 " <space> = scroll down",
237 " <backspace> = <delete> = scroll up",
238 " v = forward (history path)",
239 " b = backward (history path)",
240 " 0 / + / - = zoom zero / in / out",
241 " z / w = zoom page / page width",
244 " <home> / <end> = top / bottom of page",
245 " <arrows> = scroll",
247 "For more information, please read the xpdf(1) man page.",
251 //------------------------------------------------------------------------
252 // command line options
253 //------------------------------------------------------------------------
255 static char initialZoomStr[32] = "";
256 static char t1libControlStr[16] = "";
257 static char freetypeControlStr[16] = "";
258 static char psFileArg[256];
259 static char paperSize[15] = "";
260 static int paperWidth = 0;
261 static int paperHeight = 0;
262 static GBool level1 = gFalse;
263 static char textEncName[128] = "";
264 static char textEOL[16] = "";
265 static char ownerPassword[33] = "";
266 static char userPassword[33] = "";
267 static GBool fullScreen = gFalse;
268 static char remoteName[100] = "xpdf_";
269 static GBool doRemoteRaise = gFalse;
270 static GBool doRemoteQuit = gFalse;
271 static GBool printCommands = gFalse;
272 static GBool quiet = gFalse;
273 static char cfgFileName[256] = "";
274 static GBool printVersion = gFalse;
275 static GBool printHelp = gFalse;
276 static GBool viKeys = gFalse;
278 static ArgDesc argDesc[] = {
279 {"-g", argStringDummy, NULL, 0,
280 "initial window geometry"},
281 {"-geometry", argStringDummy, NULL, 0,
282 "initial window geometry"},
283 {"-title", argStringDummy, NULL, 0,
285 {"-cmap", argFlagDummy, NULL, 0,
286 "install a private colormap"},
287 {"-rgb", argIntDummy, NULL, 0,
288 "biggest RGB cube to allocate (default is 5)"},
289 {"-rv", argFlagDummy, NULL, 0,
291 {"-papercolor", argStringDummy, NULL, 0,
292 "color of paper background"},
293 {"-z", argString, initialZoomStr, sizeof(initialZoomStr),
294 "initial zoom level (-5..5, page, width)"},
296 {"-t1lib", argString, t1libControlStr, sizeof(t1libControlStr),
297 "t1lib font rasterizer control: none, plain, low, high"},
299 #if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H
300 {"-freetype", argString, freetypeControlStr, sizeof(freetypeControlStr),
301 "FreeType font rasterizer control: none, plain, low, high"},
303 {"-ps", argString, psFileArg, sizeof(psFileArg),
304 "default PostScript file name or command"},
305 {"-paper", argString, paperSize, sizeof(paperSize),
306 "paper size (letter, legal, A4, A3)"},
307 {"-paperw", argInt, &paperWidth, 0,
308 "paper width, in points"},
309 {"-paperh", argInt, &paperHeight, 0,
310 "paper height, in points"},
311 {"-level1", argFlag, &level1, 0,
312 "generate Level 1 PostScript"},
313 {"-enc", argString, textEncName, sizeof(textEncName),
314 "output text encoding name"},
315 {"-eol", argString, textEOL, sizeof(textEOL),
316 "output end-of-line convention (unix, dos, or mac)"},
317 {"-opw", argString, ownerPassword, sizeof(ownerPassword),
318 "owner password (for encrypted files)"},
319 {"-upw", argString, userPassword, sizeof(userPassword),
320 "user password (for encrypted files)"},
321 {"-fullscreen", argFlag, &fullScreen, 0,
322 "run in full-screen (presentation) mode"},
323 {"-remote", argString, remoteName + 5, sizeof(remoteName) - 5,
324 "start/contact xpdf remote server with specified name"},
325 {"-raise", argFlag, &doRemoteRaise, 0,
326 "raise xpdf remote server window (with -remote only)"},
327 {"-quit", argFlag, &doRemoteQuit, 0,
328 "kill xpdf remote server (with -remote only)"},
329 {"-cmd", argFlag, &printCommands, 0,
330 "print commands as they're executed"},
331 {"-q", argFlag, &quiet, 0,
332 "don't print any messages or errors"},
333 {"-cfg", argString, cfgFileName, sizeof(cfgFileName),
334 "configuration file to use in place of .xpdfrc"},
335 {"-v", argFlag, &printVersion, 0,
336 "print copyright and version info"},
337 {"-h", argFlag, &printHelp, 0,
338 "print usage information"},
339 {"-help", argFlag, &printHelp, 0,
340 "print usage information"},
341 {"--help", argFlag, &printHelp, 0,
342 "print usage information"},
343 {"-?", argFlag, &printHelp, 0,
344 "print usage information"},
348 static XrmOptionDescRec opts[] = {
349 {"-display", ".display", XrmoptionSepArg, NULL},
350 {"-foreground", ".foreground", XrmoptionSepArg, NULL},
351 {"-fg", ".foreground", XrmoptionSepArg, NULL},
352 {"-background", ".background", XrmoptionSepArg, NULL},
353 {"-bg", ".background", XrmoptionSepArg, NULL},
354 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
355 {"-g", ".geometry", XrmoptionSepArg, NULL},
356 {"-font", ".font", XrmoptionSepArg, NULL},
357 {"-fn", ".font", XrmoptionSepArg, NULL},
358 {"-title", ".title", XrmoptionSepArg, NULL},
359 {"-cmap", ".installCmap", XrmoptionNoArg, (XPointer)"on"},
360 {"-rgb", ".rgbCubeSize", XrmoptionSepArg, NULL},
361 {"-rv", ".reverseVideo", XrmoptionNoArg, (XPointer)"true"},
362 {"-papercolor", ".paperColor", XrmoptionSepArg, NULL},
366 //------------------------------------------------------------------------
368 //------------------------------------------------------------------------
370 // zoom factor is 1.2 (similar to DVI magsteps)
374 #define zoomWidth 101
376 static int zoomDPI[maxZoom - minZoom + 1] = {
379 86, 104, 124, 149, 179
384 static LTKOutputDev *out;
391 static time_t modTime; // last modification time of PDF file
393 static LinkAction *linkAction; // mouse pointer is over this link
394 static int // coordinates of current selection:
395 selectXMin, selectYMin, // (xMin==xMax || yMin==yMax) means there
396 selectXMax, selectYMax; // is no selection
397 static GBool lastDragLeft; // last dragged selection edge was left/right
398 static GBool lastDragTop; // last dragged selection edge was top/bottom
399 static int panMX, panMY; // last mouse position for pan
405 #define historySize 50
406 static History // page history queue
407 history[historySize];
408 static int historyCur; // currently displayed page
409 static int historyBLen; // number of valid entries backward from
411 static int historyFLen; // number of valid entries forward from
414 static GString *psFileName;
415 static int psFirstPage, psLastPage;
417 static GString *fileReqDir; // current directory for file requesters
419 static GString *urlCommand; // command to execute for URI links
421 static GString *windowTitle; // window title string
424 static Display *display;
425 static LTKWindow *win;
426 static LTKMenu *zoomMenu;
427 static LTKScrollingCanvas *canvas;
428 static LTKScrollbar *hScrollbar, *vScrollbar;
429 static LTKTextIn *pageNumText;
430 static LTKLabel *numPagesLabel;
431 static LTKLabel *linkLabel;
432 static LTKMenuButton *zoomMenuBtn;
433 static LTKWindow *aboutWin;
434 static LTKList *aboutList;
435 static LTKScrollbar *aboutHScrollbar, *aboutVScrollbar;
436 static LTKWindow *psDialog;
437 static LTKWindow *openDialog;
438 static LTKWindow *saveDialog;
439 static LTKWindow *findWin;
440 static LTKTextIn *findTextIn;
441 static Atom remoteAtom;
444 //------------------------------------------------------------------------
446 //------------------------------------------------------------------------
448 #include "xpdfIcon.xpm"
449 #include "leftArrow.xbm"
450 #include "dblLeftArrow.xbm"
451 #include "rightArrow.xbm"
452 #include "dblRightArrow.xbm"
453 #include "backArrow.xbm"
454 #include "forwardArrow.xbm"
456 #include "postscript.xbm"
458 #include "xpdf-ltk.h"
460 //------------------------------------------------------------------------
462 //------------------------------------------------------------------------
464 int main(int argc, char *argv[]) {
467 char cmd[remoteCmdLength];
471 GString *initialZoom;
473 unsigned long paperColor;
481 double width1, height1;
494 fileReqDir = getCurrentDir();
498 ok = parseArgs(argDesc, &argc, argv);
501 globalParams = new GlobalParams(cfgFileName);
503 globalParams->setPSFile(psFileArg);
506 if (!globalParams->setPSPaperSize(paperSize)) {
507 fprintf(stderr, "Invalid paper size\n");
511 globalParams->setPSPaperWidth(paperWidth);
514 globalParams->setPSPaperHeight(paperHeight);
518 globalParams->setPSLevel(psLevel1);
520 if (textEncName[0]) {
521 globalParams->setTextEncoding(textEncName);
524 if (!globalParams->setTextEOL(textEOL)) {
525 fprintf(stderr, "Bad '-eol' value on command line\n");
528 if (initialZoomStr[0]) {
529 globalParams->setInitialZoom(initialZoomStr);
531 if (t1libControlStr[0]) {
532 if (!globalParams->setT1libControl(t1libControlStr)) {
533 fprintf(stderr, "Bad '-t1lib' value on command line\n");
536 if (freetypeControlStr[0]) {
537 if (!globalParams->setFreeTypeControl(freetypeControlStr)) {
538 fprintf(stderr, "Bad '-freetype' value on command line\n");
542 globalParams->setErrQuiet(quiet);
545 // create LTKApp (and parse X-related args)
546 app = new LTKApp("xpdf", "Xpdf", opts, &argc, argv);
547 app->setKillCbk(&killCbk);
548 display = app->getDisplay();
550 // check command line
552 ok = ok && remoteName[5] && !doRemoteQuit && argc >= 1 && argc <= 3;
553 else if (doRemoteQuit)
554 ok = ok && remoteName[5] && argc == 1;
556 ok = ok && argc >= 1 && argc <= 3;
557 if (!ok || printVersion || printHelp) {
558 fprintf(stderr, "xpdf version %s\n", xpdfVersion);
559 fprintf(stderr, "%s\n", xpdfCopyright);
561 printUsage("xpdf", "[<PDF-file> [<page> | +<dest>]]", argDesc);
567 name = new GString(argv[1]);
574 if (argv[2][0] == '+') {
575 destName = new GString(&argv[2][1]);
581 // look for already-running remote server
583 remoteAtom = XInternAtom(display, remoteName, False);
584 xwin = XGetSelectionOwner(display, remoteAtom);
588 sprintf(cmd, "%c +%.256s %.200s", doRemoteRaise ? 'D' : 'd',
589 destName->getCString(), name->getCString());
592 sprintf(cmd, "%c %d %.200s", doRemoteRaise ? 'D' : 'd',
593 pg, name->getCString());
595 XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8,
596 PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
598 } else if (doRemoteRaise) {
599 XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8,
600 PropModeReplace, (Guchar *)"r", 2);
601 } else if (doRemoteQuit) {
602 XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8,
603 PropModeReplace, (Guchar *)"q", 2);
616 historyCur = historySize - 1;
617 historyBLen = historyFLen = 0;
618 for (i = 0; i < historySize; ++i)
619 history[i].fileName = NULL;
623 if (!loadFile(name)) {
628 fileReqDir = makePathAbsolute(grabPath(name->getCString()));
631 // check for legal page number
632 if (doc && (pg < 1 || pg > doc->getNumPages())) {
640 win = makeFullScreenWindow(app);
641 win->setDecorated(gFalse);
643 zoomMenu = makeZoomMenu();
644 win = makeWindow(app);
647 canvas = (LTKScrollingCanvas *)win->findWidget("canvas");
648 hScrollbar = (LTKScrollbar *)win->findWidget("hScrollbar");
649 vScrollbar = (LTKScrollbar *)win->findWidget("vScrollbar");
650 pageNumText = (LTKTextIn *)win->findWidget("pageNum");
651 numPagesLabel = (LTKLabel *)win->findWidget("numPages");
652 linkLabel = (LTKLabel *)win->findWidget("link");
653 zoomMenuBtn = (LTKMenuButton *)win->findWidget("zoom");
654 win->setKeyCbk(&keyPressCbk);
655 win->setLayoutCbk(&layoutCbk);
656 canvas->setButtonPressCbk(&buttonPressCbk);
657 canvas->setButtonReleaseCbk(&buttonReleaseCbk);
658 canvas->setMouseMoveCbk(&mouseMoveCbk);
659 canvas->setMouseDragCbk(&mouseDragCbk);
661 hScrollbar->setRepeatPeriod(0);
662 vScrollbar->setRepeatPeriod(0);
666 urlCommand = globalParams->getURLCommand();
669 windowTitle = app->getStringResource("title", NULL);
670 installCmap = app->getBoolResource("installCmap", gFalse);
672 win->setInstallCmap(gTrue);
674 rgbCubeSize = app->getIntResource("rgbCubeSize", defaultRGBCube);
675 reverseVideo = app->getBoolResource("reverseVideo", gFalse);
676 paperColor = app->getColorResource(
678 reverseVideo ? (char *)"black" : (char *)"white",
679 reverseVideo ? BlackPixel(display, app->getScreenNum())
680 : WhitePixel(display, app->getScreenNum()),
685 initialZoom = globalParams->getInitialZoom();
686 if (!initialZoom->cmp("page")) {
688 i = maxZoom - minZoom + 2;
689 } else if (!initialZoom->cmp("width")) {
691 i = maxZoom - minZoom + 3;
693 zoom = atoi(initialZoom->getCString());
694 if (zoom < minZoom) {
696 } else if (zoom > maxZoom) {
701 zoomMenuBtn->setInitialMenuItem(zoomMenu->getItem(i));
703 viKeys = app->getBoolResource("viKeys", gFalse);
708 width = app->getDisplayWidth();
709 height = app->getDisplayHeight();
713 app->getGeometryResource("geometry", &x, &y, &width, &height);
714 if (width == 0 || height == 0) {
715 if (!doc || doc->getNumPages() == 0) {
718 } else if (doc->getPageRotate(pg) == 90 ||
719 doc->getPageRotate(pg) == 270) {
720 width1 = doc->getPageHeight(pg);
721 height1 = doc->getPageWidth(pg);
723 width1 = doc->getPageWidth(pg);
724 height1 = doc->getPageHeight(pg);
726 if (zoom == zoomPage || zoom == zoomWidth) {
727 width = (int)((width1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5);
728 height = (int)((height1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5);
730 width = (int)((width1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
731 height = (int)((height1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
735 if (width > (Guint)app->getDisplayWidth() - 100) {
736 width = app->getDisplayWidth() - 100;
738 if (height > (Guint)app->getDisplayHeight() - 100) {
739 height = app->getDisplayHeight() - 100;
744 // finish setting up window
746 sprintf(s, "of %d", doc ? doc->getNumPages() : 0);
747 numPagesLabel->setText(s);
750 title = windowTitle->copy();
752 title = new GString("xpdf: ");
755 title = new GString("xpdf");
757 win->setTitle(title);
758 win->layout(x, y, width, height);
765 gcValues.foreground = BlackPixel(display, win->getScreenNum()) ^
766 WhitePixel(display, win->getScreenNum());
767 gcValues.function = GXxor;
768 selectGC = XCreateGC(display, win->getXWindow(),
769 GCForeground | GCFunction, &gcValues);
771 // set up remote server
772 if (remoteAtom != None) {
773 win->setPropChangeCbk(&propChangeCbk);
774 xwin = win->getXWindow();
775 XSetSelectionOwner(display, remoteAtom, xwin, CurrentTime);
778 // create output device
779 out = new LTKOutputDev(win, reverseVideo, paperColor,
780 installCmap, rgbCubeSize, !fullScreen);
781 out->startDoc(doc ? doc->getXRef() : (XRef *)NULL);
783 // display first page
786 if ((dest = doc->findDest(destName))) {
787 displayDest(dest, zoom, 0, gTrue);
790 error(-1, "Unknown named destination '%s'", destName->getCString());
791 displayPage(1, zoom, 0, gTrue);
796 displayPage(pg, zoom, 0, gTrue);
806 // release remote control atom
807 if (remoteAtom != None)
808 XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
839 for (i = 0; i < historySize; ++i) {
840 if (history[i].fileName) {
841 delete history[i].fileName;
846 // check for memory leaks
847 Object::memCheck(stderr);
853 //------------------------------------------------------------------------
854 // loadFile / displayPage / displayDest
855 //------------------------------------------------------------------------
857 static GBool loadFile(GString *fileName) {
860 GString *ownerPW, *userPW;
866 win->setBusyCursor(gTrue);
869 if (ownerPassword[0]) {
870 ownerPW = new GString(ownerPassword);
874 if (userPassword[0]) {
875 userPW = new GString(userPassword);
879 newDoc = new PDFDoc(fileName, ownerPW, userPW, printCommands);
886 if (!newDoc->isOk()) {
889 win->setBusyCursor(gFalse);
893 // replace old document
898 out->startDoc(doc->getXRef());
901 // nothing displayed yet
904 // save the modification time
905 modTime = getModTime(fileName->getCString());
907 // init PostScript output params
910 if (globalParams->getPSFile()) {
911 psFileName = globalParams->getPSFile()->copy();
913 p = fileName->getCString() + fileName->getLength() - 4;
914 if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF"))
915 psFileName = new GString(fileName->getCString(),
916 fileName->getLength() - 4);
918 psFileName = fileName->copy();
919 psFileName->append(".ps");
922 psLastPage = doc->getNumPages();
924 // set up title, number-of-pages display; back to normal cursor
927 title = new GString("xpdf: ");
928 title->append(fileName);
929 win->setTitle(title);
932 sprintf(s, "of %d", doc->getNumPages());
933 numPagesLabel->setText(s);
935 win->setBusyCursor(gFalse);
942 static void displayPage(int pageA, int zoomA, int rotateA, GBool addToHist) {
944 double hDPI, vDPI, dpi;
949 // check for document
950 if (!doc || doc->getNumPages() == 0)
953 // check for changes to the file
954 modTime1 = getModTime(doc->getFileName()->getCString());
955 if (modTime1 != modTime) {
956 if (loadFile(doc->getFileName()->copy())) {
957 if (pageA > doc->getNumPages()) {
958 pageA = doc->getNumPages();
966 win->setBusyCursor(gTrue);
968 // new page/zoom/rotate values
973 // initialize mouse-related stuff
975 win->setDefaultCursor();
977 linkLabel->setText(NULL);
979 selectXMin = selectXMax = 0;
980 selectYMin = selectYMax = 0;
981 lastDragLeft = lastDragTop = gTrue;
984 rot = rotate + doc->getPageRotate(page);
990 if (rot == 90 || rot == 270) {
991 hDPI = (win->getWidth() / doc->getPageHeight(page)) * 72;
992 vDPI = (win->getHeight() / doc->getPageWidth(page)) * 72;
994 hDPI = (win->getWidth() / doc->getPageWidth(page)) * 72;
995 vDPI = (win->getHeight() / doc->getPageHeight(page)) * 72;
997 dpi = (hDPI < vDPI) ? hDPI : vDPI;
998 } else if (zoom == zoomPage) {
999 if (rot == 90 || rot == 270) {
1000 hDPI = (canvas->getWidth() / doc->getPageHeight(page)) * 72;
1001 vDPI = (canvas->getHeight() / doc->getPageWidth(page)) * 72;
1003 hDPI = (canvas->getWidth() / doc->getPageWidth(page)) * 72;
1004 vDPI = (canvas->getHeight() / doc->getPageHeight(page)) * 72;
1006 dpi = (hDPI < vDPI) ? hDPI : vDPI;
1007 } else if (zoom == zoomWidth) {
1008 if (rot == 90 || rot == 270) {
1009 dpi = (canvas->getWidth() / doc->getPageHeight(page)) * 72;
1011 dpi = (canvas->getWidth() / doc->getPageWidth(page)) * 72;
1014 dpi = zoomDPI[zoom - minZoom];
1016 doc->displayPage(out, page, dpi, rotate, gTrue);
1019 // update page number display
1021 sprintf(s, "%d", page);
1022 pageNumText->setText(s);
1027 if (++historyCur == historySize)
1029 h = &history[historyCur];
1032 h->fileName = doc->getFileName()->copy();
1034 if (historyBLen < historySize)
1039 // back to regular cursor
1040 win->setBusyCursor(gFalse);
1043 static void displayDest(LinkDest *dest, int zoomA, int rotateA,
1049 if (dest->isPageRef()) {
1050 pageRef = dest->getPageRef();
1051 pg = doc->findPage(pageRef.num, pageRef.gen);
1053 pg = dest->getPageNum();
1055 if (pg <= 0 || pg > doc->getNumPages()) {
1059 displayPage(pg, zoomA, rotateA, addToHist);
1065 switch (dest->getKind()) {
1067 out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
1068 if (dest->getChangeLeft() || dest->getChangeTop()) {
1069 if (dest->getChangeLeft()) {
1070 hScrollbar->setPos(dx, canvas->getWidth());
1072 if (dest->getChangeTop()) {
1073 vScrollbar->setPos(dy, canvas->getHeight());
1075 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1077 //~ what is the zoom parameter?
1082 hScrollbar->setPos(0, canvas->getWidth());
1083 vScrollbar->setPos(0, canvas->getHeight());
1084 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1089 out->cvtUserToDev(0, dest->getTop(), &dx, &dy);
1090 hScrollbar->setPos(0, canvas->getWidth());
1091 vScrollbar->setPos(dy, canvas->getHeight());
1092 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1097 out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy);
1098 hScrollbar->setPos(dx, canvas->getWidth());
1099 vScrollbar->setPos(0, canvas->getHeight());
1100 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1104 out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
1105 hScrollbar->setPos(dx, canvas->getWidth());
1106 vScrollbar->setPos(dy, canvas->getHeight());
1107 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1112 //------------------------------------------------------------------------
1113 // key press and menu callbacks
1114 //------------------------------------------------------------------------
1116 static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers,
1134 gotoNextPage(1, !(modifiers & Mod5Mask));
1138 gotoPrevPage(1, !(modifiers & Mod5Mask), gFalse);
1142 vScrollbar->getPos() >=
1143 canvas->getRealHeight() - canvas->getHeight()) {
1144 gotoNextPage(1, gTrue);
1146 vScrollbar->setPos(vScrollbar->getPos() + canvas->getHeight(),
1147 canvas->getHeight());
1148 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1154 gotoPrevPage(1, gTrue, gFalse);
1155 } else if (vScrollbar->getPos() == 0) {
1156 gotoPrevPage(1, gFalse, gTrue);
1158 vScrollbar->setPos(vScrollbar->getPos() - canvas->getHeight(),
1159 canvas->getHeight());
1160 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1164 forwardCbk(NULL, 0, gTrue);
1167 backCbk(NULL, 0, gTrue);
1173 pageNumText->selectAll();
1174 pageNumText->activate(gTrue);
1176 case 'h': // vi-style left
1181 hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth());
1182 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1185 case 'l': // vi-style right
1190 hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth());
1191 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1194 case 'k': // vi-style up
1199 vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight());
1200 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1203 case 'j': // vi-style down
1208 vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight());
1209 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1216 if (zoom != defZoom) {
1217 zoomMenuBtn->setMenuItem(zoomMenu->getItem(defZoom - minZoom));
1224 if (zoom >= minZoom && zoom < maxZoom) {
1225 zoomMenuBtn->setMenuItem(zoomMenu->getItem(zoom + 1 - minZoom));
1232 if (zoom > minZoom && zoom <= maxZoom) {
1233 zoomMenuBtn->setMenuItem(zoomMenu->getItem(zoom - 1 - minZoom));
1240 zoomMenuBtn->setMenuItem(zoomMenu->getItem(maxZoom - minZoom + 2));
1246 zoomMenuBtn->setMenuItem(zoomMenu->getItem(maxZoom - minZoom + 3));
1250 displayPage(page, zoom, rotate, gFalse);
1254 quitCbk(NULL, 0, gTrue);
1264 hScrollbar->setPos(0, canvas->getWidth());
1265 vScrollbar->setPos(0, canvas->getHeight());
1266 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1273 hScrollbar->setPos(canvas->getRealWidth() - canvas->getWidth(),
1274 canvas->getWidth());
1275 vScrollbar->setPos(canvas->getRealHeight() - canvas->getHeight(),
1276 canvas->getHeight());
1277 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1282 gotoPrevPage(1, gTrue, gFalse);
1283 } else if (vScrollbar->getPos() == 0) {
1284 gotoPrevPage(1, gFalse, gTrue);
1286 vScrollbar->setPos(vScrollbar->getPos() - canvas->getHeight(),
1287 canvas->getHeight());
1288 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1292 case XK_KP_Page_Down:
1294 vScrollbar->getPos() >=
1295 canvas->getRealHeight() - canvas->getHeight()) {
1296 gotoNextPage(1, gTrue);
1298 vScrollbar->setPos(vScrollbar->getPos() + canvas->getHeight(),
1299 canvas->getHeight());
1300 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1308 hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth());
1309 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1316 hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth());
1317 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1324 vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight());
1325 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1332 vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight());
1333 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1339 static void menuCbk(LTKMenuItem *item) {
1342 switch (item->getItemNum()) {
1355 r = (rotate == 0) ? 270 : rotate - 90;
1356 displayPage(page, zoom, r, gFalse);
1361 r = (rotate == 270) ? 0 : rotate + 90;
1362 displayPage(page, zoom, r, gFalse);
1371 //------------------------------------------------------------------------
1373 //------------------------------------------------------------------------
1375 static void buttonPressCbk(LTKWidget *canvas1, int n,
1376 int mx, int my, int button, GBool dblClick) {
1377 if (!doc || doc->getNumPages() == 0) {
1382 setSelection(mx, my, mx, my);
1386 panMX = mx - hScrollbar->getPos();
1387 panMY = my - vScrollbar->getPos();
1390 case 4: // mouse wheel up
1392 gotoPrevPage(1, gTrue, gFalse);
1393 } else if (vScrollbar->getPos() == 0) {
1394 gotoPrevPage(1, gFalse, gTrue);
1396 vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight());
1397 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1400 case 5: // mouse wheel down
1402 vScrollbar->getPos() >=
1403 canvas->getRealHeight() - canvas->getHeight()) {
1404 gotoNextPage(1, gTrue);
1406 vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight());
1407 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1410 case 6: // second mouse wheel right
1414 hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth());
1415 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1417 case 7: // second mouse wheel left
1421 hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth());
1422 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1427 static void buttonReleaseCbk(LTKWidget *canvas1, int n,
1428 int mx, int my, int button, GBool click) {
1431 if (!doc || doc->getNumPages() == 0)
1436 if (selectXMin < selectXMax && selectYMin < selectYMax) {
1437 #ifndef NO_TEXT_SELECT
1438 if (doc->okToCopy()) {
1439 s = out->getText(selectXMin, selectYMin, selectXMax, selectYMax);
1440 win->setSelection(NULL, s);
1442 error(-1, "Copying of text from this document is not allowed.");
1448 setSelection(mx, my, mx, my);
1454 static void doLink(int mx, int my) {
1455 LinkActionKind kind;
1456 LinkAction *action = NULL;
1461 GString *actionName;
1463 LTKButtonDialog *dialog;
1467 out->cvtDevToUser(mx, my, &x, &y);
1468 if ((action = doc->findLink(x, y))) {
1469 switch (kind = action->getKind()) {
1471 // GoTo / GoToR action
1474 if (kind == actionGoTo) {
1477 if ((dest = ((LinkGoTo *)action)->getDest()))
1478 dest = dest->copy();
1479 else if ((namedDest = ((LinkGoTo *)action)->getNamedDest()))
1480 namedDest = namedDest->copy();
1484 if ((dest = ((LinkGoToR *)action)->getDest()))
1485 dest = dest->copy();
1486 else if ((namedDest = ((LinkGoToR *)action)->getNamedDest()))
1487 namedDest = namedDest->copy();
1488 s = ((LinkGoToR *)action)->getFileName()->getCString();
1489 //~ translate path name for VMS (deal with '/')
1490 if (isAbsolutePath(s))
1491 fileName = new GString(s);
1493 fileName = appendToPath(
1494 grabPath(doc->getFileName()->getCString()), s);
1495 if (!loadFile(fileName)) {
1504 dest = doc->findDest(namedDest);
1508 displayDest(dest, zoom, rotate, gTrue);
1511 if (kind == actionGoToR) {
1512 displayPage(1, zoom, 0, gTrue);
1519 fileName = ((LinkLaunch *)action)->getFileName();
1520 s = fileName->getCString();
1521 if (!strcmp(s + fileName->getLength() - 4, ".pdf") ||
1522 !strcmp(s + fileName->getLength() - 4, ".PDF")) {
1523 //~ translate path name for VMS (deal with '/')
1524 if (isAbsolutePath(s))
1525 fileName = fileName->copy();
1527 fileName = appendToPath(
1528 grabPath(doc->getFileName()->getCString()), s);
1529 if (!loadFile(fileName))
1531 displayPage(1, zoom, rotate, gTrue);
1533 fileName = fileName->copy();
1534 if (((LinkLaunch *)action)->getParams()) {
1535 fileName->append(' ');
1536 fileName->append(((LinkLaunch *)action)->getParams());
1539 fileName->insert(0, "spawn/nowait ");
1540 #elif defined(__EMX__)
1541 fileName->insert(0, "start /min /n ");
1543 fileName->append(" &");
1545 dialog = new LTKButtonDialog(win, "xpdf: Launch",
1546 "Execute the command:",
1547 fileName->getCString(),
1548 NULL, "Ok", "Cancel");
1550 system(fileName->getCString());
1559 for (s = urlCommand->getCString(); *s; ++s) {
1560 if (s[0] == '%' && s[1] == 's') {
1565 fileName = ((LinkURI *)action)->getURI()->copy();
1566 // filter out any quote marks (' or ") to avoid a potential
1569 while (i < fileName->getLength()) {
1570 if (fileName->getChar(i) == '"') {
1572 fileName->insert(i, "%22");
1574 } else if (fileName->getChar(i) == '\'') {
1576 fileName->insert(i, "%27");
1582 fileName->insert(0, urlCommand->getCString(),
1583 s - urlCommand->getCString());
1584 fileName->append(s+2);
1586 fileName = urlCommand->copy();
1589 fileName->insert(0, "spawn/nowait ");
1590 #elif defined(__EMX__)
1591 fileName->insert(0, "start /min /n ");
1593 fileName->append(" &");
1595 system(fileName->getCString());
1598 printf("URI: %s\n", ((LinkURI *)action)->getURI()->getCString());
1604 actionName = ((LinkNamed *)action)->getName();
1605 if (!actionName->cmp("NextPage")) {
1606 gotoNextPage(1, gTrue);
1607 } else if (!actionName->cmp("PrevPage")) {
1608 gotoPrevPage(1, gTrue, gFalse);
1609 } else if (!actionName->cmp("FirstPage")) {
1611 displayPage(1, zoom, rotate, gTrue);
1613 } else if (!actionName->cmp("LastPage")) {
1614 if (page != doc->getNumPages()) {
1615 displayPage(doc->getNumPages(), zoom, rotate, gTrue);
1617 } else if (!actionName->cmp("GoBack")) {
1618 backCbk(NULL, 0, gTrue);
1619 } else if (!actionName->cmp("GoForward")) {
1620 forwardCbk(NULL, 0, gTrue);
1621 } else if (!actionName->cmp("Quit")) {
1622 quitCbk(NULL, 0, gTrue);
1624 error(-1, "Unknown named action: '%s'", actionName->getCString());
1628 // unknown action type
1630 error(-1, "Unknown link action type: '%s'",
1631 ((LinkUnknown *)action)->getAction()->getCString());
1637 static void mouseMoveCbk(LTKWidget *widget, int widgetNum, int mx, int my) {
1642 if (!doc || doc->getNumPages() == 0)
1644 out->cvtDevToUser(mx, my, &x, &y);
1645 if ((action = doc->findLink(x, y))) {
1646 if (action != linkAction) {
1648 win->setCursor(XC_hand2);
1650 linkAction = action;
1653 switch (linkAction->getKind()) {
1655 s = "[internal link]";
1658 s = ((LinkGoToR *)linkAction)->getFileName()->getCString();
1661 s = ((LinkLaunch *)linkAction)->getFileName()->getCString();
1664 s = ((LinkURI *)action)->getURI()->getCString();
1667 s = ((LinkNamed *)linkAction)->getName()->getCString();
1670 s = "[unknown link]";
1673 linkLabel->setText(s);
1679 win->setDefaultCursor();
1681 linkLabel->setText(NULL);
1687 static void mouseDragCbk(LTKWidget *widget, int widgetNum,
1688 int mx, int my, int button) {
1690 int xMin, yMin, xMax, yMax;
1695 // clip mouse coords
1699 else if (x >= canvas->getRealWidth())
1700 x = canvas->getRealWidth() - 1;
1704 else if (y >= canvas->getRealHeight())
1705 y = canvas->getRealHeight() - 1;
1707 // move appropriate edges of selection
1709 if (x < selectXMax) {
1715 lastDragLeft = gFalse;
1718 if (x > selectXMin) {
1724 lastDragLeft = gTrue;
1728 if (y < selectYMax) {
1734 lastDragTop = gFalse;
1737 if (y > selectYMin) {
1743 lastDragTop = gTrue;
1747 // redraw the selection
1748 setSelection(xMin, yMin, xMax, yMax);
1751 } else if (!fullScreen && button == 2) {
1752 mx -= hScrollbar->getPos();
1753 my -= vScrollbar->getPos();
1754 hScrollbar->setPos(hScrollbar->getPos() - (mx - panMX),
1755 canvas->getWidth());
1756 vScrollbar->setPos(vScrollbar->getPos() - (my - panMY),
1757 canvas->getHeight());
1758 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1764 //------------------------------------------------------------------------
1766 //------------------------------------------------------------------------
1768 static void nextPageCbk(LTKWidget *button, int n, GBool on) {
1769 gotoNextPage(1, gTrue);
1772 static void nextTenPageCbk(LTKWidget *button, int n, GBool on) {
1773 gotoNextPage(10, gTrue);
1776 static void gotoNextPage(int inc, GBool top) {
1779 if (!doc || doc->getNumPages() == 0) {
1782 if (page < doc->getNumPages()) {
1783 if (top && !fullScreen) {
1784 vScrollbar->setPos(0, canvas->getHeight());
1785 canvas->setScrollPos(hScrollbar->getPos(), vScrollbar->getPos());
1787 if ((pg = page + inc) > doc->getNumPages()) {
1788 pg = doc->getNumPages();
1790 displayPage(pg, zoom, rotate, gTrue);
1796 static void prevPageCbk(LTKWidget *button, int n, GBool on) {
1797 gotoPrevPage(1, gTrue, gFalse);
1800 static void prevTenPageCbk(LTKWidget *button, int n, GBool on) {
1801 gotoPrevPage(10, gTrue, gFalse);
1804 static void gotoPrevPage(int dec, GBool top, GBool bottom) {
1807 if (!doc || doc->getNumPages() == 0) {
1811 if (top && !fullScreen) {
1812 vScrollbar->setPos(0, canvas->getHeight());
1813 canvas->setScrollPos(hScrollbar->getPos(), vScrollbar->getPos());
1814 } else if (bottom && !fullScreen) {
1815 vScrollbar->setPos(canvas->getRealHeight() - canvas->getHeight(),
1816 canvas->getHeight());
1817 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1819 if ((pg = page - dec) < 1) {
1822 displayPage(pg, zoom, rotate, gTrue);
1828 static void backCbk(LTKWidget *button, int n, GBool on) {
1829 if (historyBLen <= 1) {
1833 if (--historyCur < 0)
1834 historyCur = historySize - 1;
1837 if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
1838 if (!loadFile(history[historyCur].fileName->copy())) {
1843 displayPage(history[historyCur].page, zoom, rotate, gFalse);
1846 static void forwardCbk(LTKWidget *button, int n, GBool on) {
1847 if (historyFLen == 0) {
1851 if (++historyCur == historySize)
1855 if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
1856 if (!loadFile(history[historyCur].fileName->copy())) {
1861 displayPage(history[historyCur].page, zoom, rotate, gFalse);
1864 static void pageNumCbk(LTKWidget *textIn, int n, GString *text) {
1868 if (!doc || doc->getNumPages() == 0)
1870 page1 = atoi(text->getCString());
1871 if (page1 >= 1 && page1 <= doc->getNumPages()) {
1873 displayPage(page1, zoom, rotate, gTrue);
1876 sprintf(s, "%d", page);
1877 pageNumText->setText(s);
1881 static void zoomMenuCbk(LTKMenuItem *item) {
1884 if (!doc || doc->getNumPages() == 0) {
1887 z = item->getItemNum();
1889 displayPage(page, z, rotate, gFalse);
1893 static void postScriptCbk(LTKWidget *button, int n, GBool on) {
1899 static void aboutCbk(LTKWidget *button, int n, GBool on) {
1903 static void quitCbk(LTKWidget *button, int n, GBool on) {
1907 //------------------------------------------------------------------------
1908 // scrollbar callbacks
1909 //------------------------------------------------------------------------
1911 static void scrollVertCbk(LTKWidget *scrollbar, int n, int val) {
1912 canvas->scroll(hScrollbar->getPos(), val);
1913 XSync(display, False);
1916 static void scrollHorizCbk(LTKWidget *scrollbar, int n, int val) {
1917 canvas->scroll(val, vScrollbar->getPos());
1918 XSync(display, False);
1921 //------------------------------------------------------------------------
1923 //------------------------------------------------------------------------
1925 static void layoutCbk(LTKWindow *win1) {
1926 if (page >= 0 && (zoom == zoomPage || zoom == zoomWidth)) {
1927 displayPage(page, zoom, rotate, gFalse);
1933 static void updateScrollbars() {
1937 hScrollbar->setLimits(0, canvas->getRealWidth() - 1);
1938 hScrollbar->setPos(hScrollbar->getPos(), canvas->getWidth());
1939 hScrollbar->setScrollDelta(16);
1940 vScrollbar->setLimits(0, canvas->getRealHeight() - 1);
1941 vScrollbar->setPos(vScrollbar->getPos(), canvas->getHeight());
1942 vScrollbar->setScrollDelta(16);
1943 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
1946 static void propChangeCbk(LTKWindow *win1, Atom atom) {
1951 Gulong size, remain;
1953 GString *newFileName;
1959 xwin = win1->getXWindow();
1960 if (XGetWindowProperty(display, xwin, remoteAtom,
1961 0, remoteCmdLength/4, True, remoteAtom,
1962 &type, &format, &size, &remain,
1963 (Guchar **)&cmd) != Success) {
1971 if (cmd[0] == 'D' || cmd[0] == 'r'){
1976 // display file / page
1977 if (cmd[0] == 'd' || cmd[0] == 'D') {
1987 destName = new GString(p + 1);
1994 newFileName = new GString(q);
1995 XFree((XPointer)cmd);
1996 if (!doc || newFileName->cmp(doc->getFileName())) {
1997 if (!loadFile(newFileName))
2003 if ((dest = doc->findDest(destName))) {
2004 displayDest(dest, zoom, rotate, gTrue);
2008 } else if (newPage != page &&
2009 newPage >= 1 && newPage <= doc->getNumPages()) {
2010 displayPage(newPage, zoom, rotate, gTrue);
2014 } else if (cmd[0] == 'q') {
2019 //------------------------------------------------------------------------
2021 //------------------------------------------------------------------------
2023 static void setSelection(int newXMin, int newYMin, int newXMax, int newYMax) {
2025 GBool needRedraw, needScroll;
2026 GBool moveLeft, moveRight, moveTop, moveBottom;
2028 // erase old selection on canvas pixmap
2029 needRedraw = gFalse;
2030 if (selectXMin < selectXMax && selectYMin < selectYMax) {
2031 XFillRectangle(canvas->getDisplay(), canvas->getPixmap(),
2032 selectGC, selectXMin, selectYMin,
2033 selectXMax - selectXMin, selectYMax - selectYMin);
2037 // draw new selection on canvas pixmap
2038 if (newXMin < newXMax && newYMin < newYMax) {
2039 XFillRectangle(canvas->getDisplay(), canvas->getPixmap(),
2040 selectGC, newXMin, newYMin,
2041 newXMax - newXMin, newYMax - newYMin);
2045 // check which edges moved
2046 moveLeft = newXMin != selectXMin;
2047 moveTop = newYMin != selectYMin;
2048 moveRight = newXMax != selectXMax;
2049 moveBottom = newYMax != selectYMax;
2051 // redraw currently visible part of canvas
2054 canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin,
2055 (newYMin < selectYMin) ? newYMin : selectYMin,
2056 (newXMin > selectXMin) ? newXMin : selectXMin,
2057 (newYMax > selectYMax) ? newYMax : selectYMax);
2060 canvas->redrawRect((newXMax < selectXMax) ? newXMax : selectXMax,
2061 (newYMin < selectYMin) ? newYMin : selectYMin,
2062 (newXMax > selectXMax) ? newXMax : selectXMax,
2063 (newYMax > selectYMax) ? newYMax : selectYMax);
2066 canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin,
2067 (newYMin < selectYMin) ? newYMin : selectYMin,
2068 (newXMax > selectXMax) ? newXMax : selectXMax,
2069 (newYMin > selectYMin) ? newYMin : selectYMin);
2072 canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin,
2073 (newYMax < selectYMax) ? newYMax : selectYMax,
2074 (newXMax > selectXMax) ? newXMax : selectXMax,
2075 (newYMax > selectYMax) ? newYMax : selectYMax);
2079 // switch to new selection coords
2080 selectXMin = newXMin;
2081 selectXMax = newXMax;
2082 selectYMin = newYMin;
2083 selectYMax = newYMax;
2085 // scroll canvas if necessary
2089 needScroll = gFalse;
2090 w = canvas->getWidth();
2091 h = canvas->getHeight();
2092 x = hScrollbar->getPos();
2093 y = vScrollbar->getPos();
2094 if (moveLeft && selectXMin < x) {
2097 } else if (moveRight && selectXMax >= x + w) {
2100 } else if (moveLeft && selectXMin >= x + w) {
2103 } else if (moveRight && selectXMax < x) {
2107 if (moveTop && selectYMin < y) {
2110 } else if (moveBottom && selectYMax >= y + h) {
2113 } else if (moveTop && selectYMin >= y + h) {
2116 } else if (moveBottom && selectYMax < y) {
2121 hScrollbar->setPos(x, w);
2122 vScrollbar->setPos(y, h);
2123 canvas->scroll(x, y);
2127 //------------------------------------------------------------------------
2129 //------------------------------------------------------------------------
2131 static void mapOpenDialog() {
2132 openDialog = makeOpenDialog(app);
2133 ((LTKFileReq *)openDialog->findWidget("fileReq"))->setDir(fileReqDir);
2134 openDialog->layoutDialog(win, -1, -1);
2138 static void openButtonCbk(LTKWidget *button, int n, GBool on) {
2139 LTKFileReq *fileReq;
2144 fileReq = (LTKFileReq *)openDialog->findWidget("fileReq");
2145 if (!(sel = fileReq->getSelection())) {
2148 openSelectCbk(fileReq, 0, sel);
2153 fileReqDir = ((LTKFileReq *)openDialog->findWidget("fileReq"))->getDir();
2160 static void openSelectCbk(LTKWidget *widget, int n, GString *name) {
2163 name1 = name->copy();
2166 fileReqDir = ((LTKFileReq *)openDialog->findWidget("fileReq"))->getDir();
2170 if (loadFile(name1)) {
2172 vScrollbar->setPos(0, canvas->getHeight());
2173 canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
2175 displayPage(1, zoom, rotate, gTrue);
2179 //------------------------------------------------------------------------
2181 //------------------------------------------------------------------------
2183 static void reloadCbk() {
2190 if (loadFile(doc->getFileName()->copy())) {
2191 if (pg > doc->getNumPages()) {
2192 pg = doc->getNumPages();
2194 displayPage(pg, zoom, rotate, gFalse);
2198 //------------------------------------------------------------------------
2199 // "Save PDF" dialog
2200 //------------------------------------------------------------------------
2202 static void mapSaveDialog() {
2203 saveDialog = makeSaveDialog(app);
2204 ((LTKFileReq *)saveDialog->findWidget("fileReq"))->setDir(fileReqDir);
2205 saveDialog->layoutDialog(win, -1, -1);
2209 static void saveButtonCbk(LTKWidget *button, int n, GBool on) {
2210 LTKFileReq *fileReq;
2217 fileReq = (LTKFileReq *)saveDialog->findWidget("fileReq");
2218 if (!(sel = fileReq->getSelection())) {
2221 saveSelectCbk(fileReq, 0, sel);
2226 fileReqDir = ((LTKFileReq *)saveDialog->findWidget("fileReq"))->getDir();
2233 static void saveSelectCbk(LTKWidget *widget, int n, GString *name) {
2236 name1 = name->copy();
2239 fileReqDir = ((LTKFileReq *)saveDialog->findWidget("fileReq"))->getDir();
2243 win->setBusyCursor(gTrue);
2246 win->setBusyCursor(gFalse);
2249 //------------------------------------------------------------------------
2250 // "PostScript" dialog
2251 //------------------------------------------------------------------------
2253 static void mapPSDialog() {
2257 psDialog = makePostScriptDialog(app);
2258 sprintf(s, "%d", psFirstPage);
2259 widget = (LTKTextIn *)psDialog->findWidget("firstPage");
2261 sprintf(s, "%d", psLastPage);
2262 widget = (LTKTextIn *)psDialog->findWidget("lastPage");
2264 widget = (LTKTextIn *)psDialog->findWidget("fileName");
2265 widget->setText(psFileName->getCString());
2266 psDialog->layoutDialog(win, -1, -1);
2270 static void psButtonCbk(LTKWidget *button, int n, GBool on) {
2279 // extract params and close the dialog
2280 widget = (LTKTextIn *)psDialog->findWidget("firstPage");
2281 psFirstPage = atoi(widget->getText()->getCString());
2282 if (psFirstPage < 1)
2284 widget = (LTKTextIn *)psDialog->findWidget("lastPage");
2285 psLastPage = atoi(widget->getText()->getCString());
2286 if (psLastPage < psFirstPage)
2287 psLastPage = psFirstPage;
2288 else if (psLastPage > doc->getNumPages())
2289 psLastPage = doc->getNumPages();
2290 widget = (LTKTextIn *)psDialog->findWidget("fileName");
2293 psFileName = widget->getText()->copy();
2294 if (!(psFileName->getChar(0) == '|' ||
2295 psFileName->cmp("-") == 0))
2296 makePathAbsolute(psFileName);
2298 // do the PostScript output
2299 psDialog->setBusyCursor(gTrue);
2300 win->setBusyCursor(gTrue);
2301 if (doc->okToPrint()) {
2302 psOut = new PSOutputDev(psFileName->getCString(), doc->getXRef(),
2303 doc->getCatalog(), psFirstPage, psLastPage,
2305 if (psOut->isOk()) {
2306 doc->displayPages(psOut, psFirstPage, psLastPage, 72, 0, gFalse);
2310 error(-1, "Printing this document is not allowed.");
2314 win->setBusyCursor(gFalse);
2322 //------------------------------------------------------------------------
2324 //------------------------------------------------------------------------
2326 static void mapAboutWin() {
2332 aboutWin = makeAboutWindow(app);
2333 aboutWin->setLayoutCbk(&aboutLayoutCbk);
2334 aboutList = (LTKList *)aboutWin->findWidget("list");
2335 aboutHScrollbar = (LTKScrollbar *)aboutWin->findWidget("hScrollbar");
2336 aboutVScrollbar = (LTKScrollbar *)aboutWin->findWidget("vScrollbar");
2337 for (i = 0; aboutWinText[i]; ++i) {
2338 aboutList->addLine(aboutWinText[i]);
2340 aboutWin->layout(-1, -1, -1, -1);
2345 static void closeAboutCbk(LTKWidget *button, int n, GBool on) {
2350 static void aboutLayoutCbk(LTKWindow *winA) {
2351 aboutHScrollbar->setLimits(0, aboutList->getMaxWidth() - 1);
2352 aboutHScrollbar->setPos(aboutHScrollbar->getPos(), aboutList->getWidth());
2353 aboutVScrollbar->setLimits(0, aboutList->getNumLines() - 1);
2354 aboutVScrollbar->setPos(aboutVScrollbar->getPos(),
2355 aboutList->getDisplayedLines());
2358 static void aboutScrollVertCbk(LTKWidget *scrollbar, int n, int val) {
2359 aboutList->scrollTo(val, aboutHScrollbar->getPos());
2360 XSync(display, False);
2363 static void aboutScrollHorizCbk(LTKWidget *scrollbar, int n, int val) {
2364 aboutList->scrollTo(aboutVScrollbar->getPos(), val);
2365 XSync(display, False);
2368 //------------------------------------------------------------------------
2370 //------------------------------------------------------------------------
2372 static void findCbk(LTKWidget *button, int n, GBool on) {
2373 if (!doc || doc->getNumPages() == 0)
2378 static void mapFindWin() {
2382 findWin = makeFindWindow(app);
2383 findWin->layout(-1, -1, -1, -1);
2385 findTextIn = (LTKTextIn *)findWin->findWidget("text");
2387 findTextIn->activate(gTrue);
2390 static void findButtonCbk(LTKWidget *button, int n, GBool on) {
2391 if (!doc || doc->getNumPages() == 0)
2394 doFind(findTextIn->getText()->getCString());
2401 static void doFind(char *s) {
2403 TextOutputDev *textOut;
2404 int xMin, yMin, xMax, yMax;
2405 double xMin1, yMin1, xMax1, yMax1;
2411 // check for zero-length string
2417 // set cursors to watch
2418 win->setBusyCursor(gTrue);
2419 findWin->setBusyCursor(gTrue);
2421 // convert to Unicode
2422 #if 1 //~ should do something more intelligent here
2424 u = (Unicode *)gmalloc(len * sizeof(Unicode));
2425 for (i = 0; i < len; ++i) {
2426 u[i] = (Unicode)(s[i] & 0xff);
2430 // search current page starting at current selection or top of page
2431 xMin = yMin = xMax = yMax = 0;
2432 if (selectXMin < selectXMax && selectYMin < selectYMax) {
2434 yMin = (selectYMin + selectYMax) / 2;
2439 if (out->findText(u, len, top, gTrue, &xMin, &yMin, &xMax, &yMax)) {
2443 // search following pages
2444 textOut = new TextOutputDev(NULL, gFalse, gFalse);
2445 if (!textOut->isOk()) {
2449 for (pg = page+1; pg <= doc->getNumPages(); ++pg) {
2450 doc->displayPage(textOut, pg, 72, 0, gFalse);
2451 if (textOut->findText(u, len, gTrue, gTrue,
2452 &xMin1, &yMin1, &xMax1, &yMax1)) {
2457 // search previous pages
2458 for (pg = 1; pg < page; ++pg) {
2459 doc->displayPage(textOut, pg, 72, 0, gFalse);
2460 if (textOut->findText(u, len, gTrue, gTrue,
2461 &xMin1, &yMin1, &xMax1, &yMax1)) {
2467 // search current page ending at current selection
2468 if (selectXMin < selectXMax && selectYMin < selectYMax) {
2470 yMax = (selectYMin + selectYMax) / 2;
2471 if (out->findText(u, len, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) {
2480 // found on a different page
2483 displayPage(pg, zoom, rotate, gTrue);
2484 if (!out->findText(u, len, gTrue, gTrue, &xMin, &yMin, &xMax, &yMax)) {
2485 // this can happen if coalescing is bad
2489 // found: change the selection
2491 setSelection(xMin, yMin, xMax, yMax);
2492 #ifndef NO_TEXT_SELECT
2493 if (doc->okToCopy()) {
2494 s1 = out->getText(selectXMin, selectYMin, selectXMax, selectYMax);
2495 win->setSelection(NULL, s1);
2502 // reset cursors to normal
2503 win->setBusyCursor(gFalse);
2504 findWin->setBusyCursor(gFalse);
2507 //------------------------------------------------------------------------
2508 // app kill callback
2509 //------------------------------------------------------------------------
2511 static void killCbk(LTKWindow *win1) {
2514 } else if (win1 == aboutWin) {
2517 } else if (win1 == psDialog) {
2520 } else if (win1 == openDialog) {
2523 } else if (win1 == saveDialog) {
2526 } else if (win1 == findWin) {