1 //========================================================================
5 // Copyright 2002-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
15 #include <X11/keysym.h>
16 #include <X11/cursorfont.h>
22 #include "GlobalParams.h"
24 #include "ErrorCodes.h"
26 #include "PSOutputDev.h"
27 #include "TextOutputDev.h"
28 #include "SplashPattern.h"
29 #include "XSplashOutputDev.h"
32 // these macro defns conflict with xpdf's Object class
33 #ifdef LESSTIF_VERSION
41 // hack around old X includes which are missing these symbols
43 #define XK_Page_Up 0xFF55
46 #define XK_Page_Down 0xFF56
49 #define XK_KP_Home 0xFF95
52 #define XK_KP_Left 0xFF96
55 #define XK_KP_Up 0xFF97
58 #define XK_KP_Right 0xFF98
61 #define XK_KP_Down 0xFF99
64 #define XK_KP_Prior 0xFF9A
67 #define XK_KP_Page_Up 0xFF9A
70 #define XK_KP_Next 0xFF9B
72 #ifndef XK_KP_Page_Down
73 #define XK_KP_Page_Down 0xFF9B
76 #define XK_KP_End 0xFF9C
79 #define XK_KP_Begin 0xFF9D
82 #define XK_KP_Insert 0xFF9E
85 #define XK_KP_Delete 0xFF9F
88 //------------------------------------------------------------------------
90 #define highlightNone 0
91 #define highlightNormal 1
92 #define highlightSelected 2
94 //------------------------------------------------------------------------
96 GString *XPDFCore::currentSelection = NULL;
97 XPDFCore *XPDFCore::currentSelectionOwner = NULL;
98 Atom XPDFCore::targetsAtom;
100 //------------------------------------------------------------------------
102 //------------------------------------------------------------------------
104 XPDFCore::XPDFCore(Widget shellA, Widget parentWidgetA,
105 SplashRGB8 paperColorA, GBool fullScreenA,
106 GBool reverseVideo, GBool installCmap, int rgbCubeSize) {
107 GString *initialZoom;
108 SplashColor paperColor2;
112 parentWidget = parentWidgetA;
113 display = XtDisplay(parentWidget);
114 screenNum = XScreenNumberOfScreen(XtScreen(parentWidget));
115 targetsAtom = XInternAtom(display, "TARGETS", False);
117 paperColor = paperColorA;
118 fullScreen = fullScreenA;
120 // for some reason, querying XmNvisual doesn't work (even if done
121 // after the window is mapped)
122 visual = DefaultVisual(display, screenNum);
123 XtVaGetValues(shell, XmNcolormap, &colormap, NULL);
128 drawAreaFrame = NULL;
136 // get the initial zoom value
137 initialZoom = globalParams->getInitialZoom();
138 if (!initialZoom->cmp("page")) {
140 } else if (!initialZoom->cmp("width")) {
143 zoom = atoi(initialZoom->getCString());
153 selectXMin = selectXMax = 0;
154 selectYMin = selectYMax = 0;
156 lastDragLeft = lastDragTop = gTrue;
165 reqPasswordCbk = NULL;
168 historyCur = xpdfHistorySize - 1;
169 historyBLen = historyFLen = 0;
170 for (i = 0; i < xpdfHistorySize; ++i) {
171 history[i].fileName = NULL;
174 // optional features default to on
175 hyperlinksEnabled = gTrue;
176 selectEnabled = gTrue;
178 // do X-specific initialization and create the widgets
181 // create the OutputDev
182 paperColor2.rgb8 = paperColor;
183 out = new XSplashOutputDev(display, screenNum, visual, colormap,
184 reverseVideo, paperColor2,
185 installCmap, rgbCubeSize, gTrue,
186 &outputDevRedrawCbk, this);
190 XPDFCore::~XPDFCore() {
199 if (currentSelectionOwner == this && currentSelection) {
200 delete currentSelection;
201 currentSelection = NULL;
202 currentSelectionOwner = NULL;
204 for (i = 0; i < xpdfHistorySize; ++i) {
205 if (history[i].fileName) {
206 delete history[i].fileName;
210 XFreeGC(display, drawAreaGC);
213 XtDestroyWidget(scrolledWin);
216 XFreeCursor(display, busyCursor);
219 XFreeCursor(display, linkCursor);
222 XFreeCursor(display, selectCursor);
226 //------------------------------------------------------------------------
227 // loadFile / displayPage / displayDest
228 //------------------------------------------------------------------------
230 int XPDFCore::loadFile(GString *fileName, GString *ownerPassword,
231 GString *userPassword) {
238 setCursor(busyCursor);
241 newDoc = new PDFDoc(fileName->copy(), ownerPassword, userPassword);
242 if (!newDoc->isOk()) {
243 err = newDoc->getErrorCode();
245 if (err != errEncrypted || !reqPasswordCbk) {
250 // try requesting a password
251 again = ownerPassword != NULL || userPassword != NULL;
253 if (!(password = (*reqPasswordCbk)(reqPasswordCbkData, again))) {
257 newDoc = new PDFDoc(fileName->copy(), password, password);
258 if (newDoc->isOk()) {
261 err = newDoc->getErrorCode();
263 if (err != errEncrypted) {
271 // replace old document
277 out->startDoc(doc->getXRef());
280 // nothing displayed yet
283 // save the modification time
284 modTime = getModTime(doc->getFileName()->getCString());
286 // update the parent window
288 (*updateCbk)(updateCbkData, doc->getFileName(), -1,
289 doc->getNumPages(), NULL);
292 // back to regular cursor
298 int XPDFCore::loadFile(BaseStream *stream, GString *ownerPassword,
299 GString *userPassword) {
306 setCursor(busyCursor);
309 newDoc = new PDFDoc(stream, ownerPassword, userPassword);
310 if (!newDoc->isOk()) {
311 err = newDoc->getErrorCode();
313 if (err != errEncrypted || !reqPasswordCbk) {
318 // try requesting a password
319 again = ownerPassword != NULL || userPassword != NULL;
321 if (!(password = (*reqPasswordCbk)(reqPasswordCbkData, again))) {
325 newDoc = new PDFDoc(stream, password, password);
326 if (newDoc->isOk()) {
329 err = newDoc->getErrorCode();
331 if (err != errEncrypted) {
339 // replace old document
345 out->startDoc(doc->getXRef());
348 // nothing displayed yet
351 // save the modification time
352 modTime = getModTime(doc->getFileName()->getCString());
354 // update the parent window
356 (*updateCbk)(updateCbkData, doc->getFileName(), -1,
357 doc->getNumPages(), NULL);
360 // back to regular cursor
366 void XPDFCore::resizeToPage(int pg) {
367 Dimension width, height;
368 double width1, height1;
369 Dimension topW, topH, topBorder, daW, daH;
370 Dimension displayW, displayH;
372 displayW = DisplayWidth(display, screenNum);
373 displayH = DisplayHeight(display, screenNum);
378 if (pg < 0 || pg > doc->getNumPages()) {
381 } else if (doc->getPageRotate(pg) == 90 ||
382 doc->getPageRotate(pg) == 270) {
383 width1 = doc->getPageHeight(pg);
384 height1 = doc->getPageWidth(pg);
386 width1 = doc->getPageWidth(pg);
387 height1 = doc->getPageHeight(pg);
389 if (zoom == zoomPage || zoom == zoomWidth) {
390 width = (Dimension)(width1 * 0.01 * defZoom + 0.5);
391 height = (Dimension)(height1 * 0.01 * defZoom + 0.5);
393 width = (Dimension)(width1 * 0.01 * zoom + 0.5);
394 height = (Dimension)(height1 * 0.01 * zoom + 0.5);
396 if (width > displayW - 100) {
397 width = displayW - 100;
399 if (height > displayH - 150) {
400 height = displayH - 150;
404 if (XtIsRealized(shell)) {
405 XtVaGetValues(shell, XmNwidth, &topW, XmNheight, &topH,
406 XmNborderWidth, &topBorder, NULL);
407 XtVaGetValues(drawArea, XmNwidth, &daW, XmNheight, &daH, NULL);
408 XtVaSetValues(shell, XmNwidth, width + (topW - daW),
409 XmNheight, height + (topH - daH), NULL);
411 XtVaSetValues(drawArea, XmNwidth, width, XmNheight, height, NULL);
415 void XPDFCore::clear() {
429 scrollX = scrollY = 0;
431 redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
434 void XPDFCore::displayPage(int pageA, double zoomA, int rotateA,
435 GBool scrollToTop, GBool addToHist) {
441 int oldScrollX, oldScrollY;
443 // update the zoom and rotate values
444 newZoom = zoomA != zoom;
448 // check for document and valid page number
449 if (!doc || pageA <= 0 || pageA > doc->getNumPages()) {
454 setCursor(busyCursor);
457 // check for changes to the file
458 newModTime = getModTime(doc->getFileName()->getCString());
459 if (newModTime != modTime) {
460 if (loadFile(doc->getFileName()) == errNone) {
461 if (pageA > doc->getNumPages()) {
462 pageA = doc->getNumPages();
465 modTime = newModTime;
476 // if zoom level changed, scroll to the top-left corner
478 scrollX = scrollY = 0;
481 // initialize mouse-related stuff
483 selectXMin = selectXMax = 0;
484 selectYMin = selectYMax = 0;
486 lastDragLeft = lastDragTop = gTrue;
489 rot = rotate + doc->getPageRotate(page);
492 } else if (rotate < 0) {
495 if (zoom == zoomPage) {
496 if (rot == 90 || rot == 270) {
497 hDPI = (drawAreaWidth / doc->getPageHeight(page)) * 72;
498 vDPI = (drawAreaHeight / doc->getPageWidth(page)) * 72;
500 hDPI = (drawAreaWidth / doc->getPageWidth(page)) * 72;
501 vDPI = (drawAreaHeight / doc->getPageHeight(page)) * 72;
503 dpi = (hDPI < vDPI) ? hDPI : vDPI;
504 } else if (zoom == zoomWidth) {
505 if (rot == 90 || rot == 270) {
506 dpi = (drawAreaWidth / doc->getPageHeight(page)) * 72;
508 dpi = (drawAreaWidth / doc->getPageWidth(page)) * 72;
511 dpi = 0.01 * zoom * 72;
513 doc->displayPage(out, page, dpi, dpi, rotate, gTrue, gTrue);
514 oldScrollX = scrollX;
515 oldScrollY = scrollY;
517 if (scrollX != oldScrollX || scrollY != oldScrollY) {
518 redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
524 if (++historyCur == xpdfHistorySize) {
527 h = &history[historyCur];
531 if (doc->getFileName()) {
532 h->fileName = doc->getFileName()->copy();
537 if (historyBLen < xpdfHistorySize) {
543 // update the parent window
545 (*updateCbk)(updateCbkData, NULL, page, -1, "");
548 // back to regular cursor
552 void XPDFCore::displayDest(LinkDest *dest, double zoomA, int rotateA,
558 if (dest->isPageRef()) {
559 pageRef = dest->getPageRef();
560 pg = doc->findPage(pageRef.num, pageRef.gen);
562 pg = dest->getPageNum();
564 if (pg <= 0 || pg > doc->getNumPages()) {
568 displayPage(pg, zoomA, rotateA, gTrue, addToHist);
574 switch (dest->getKind()) {
576 out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
577 if (dest->getChangeLeft() || dest->getChangeTop()) {
578 scrollTo(dest->getChangeLeft() ? dx : scrollX,
579 dest->getChangeTop() ? dy : scrollY);
581 //~ what is the zoom parameter?
591 out->cvtUserToDev(0, dest->getTop(), &dx, &dy);
597 out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy);
602 out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
608 //------------------------------------------------------------------------
609 // page/position changes
610 //------------------------------------------------------------------------
612 void XPDFCore::gotoNextPage(int inc, GBool top) {
615 if (!doc || doc->getNumPages() == 0) {
618 if (page < doc->getNumPages()) {
619 if ((pg = page + inc) > doc->getNumPages()) {
620 pg = doc->getNumPages();
622 displayPage(pg, zoom, rotate, top, gTrue);
628 void XPDFCore::gotoPrevPage(int dec, GBool top, GBool bottom) {
631 if (!doc || doc->getNumPages() == 0) {
635 if (!fullScreen && bottom) {
636 scrollY = out->getBitmapHeight() - drawAreaHeight;
640 // displayPage will call updateScrollBars()
642 if ((pg = page - dec) < 1) {
645 displayPage(pg, zoom, rotate, top, gTrue);
651 void XPDFCore::goForward() {
652 if (historyFLen == 0) {
656 if (++historyCur == xpdfHistorySize) {
661 if (!doc || history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
662 if (loadFile(history[historyCur].fileName) != errNone) {
667 displayPage(history[historyCur].page, zoom, rotate, gFalse, gFalse);
670 void XPDFCore::goBackward() {
671 if (historyBLen <= 1) {
675 if (--historyCur < 0) {
676 historyCur = xpdfHistorySize - 1;
680 if (!doc || history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
681 if (loadFile(history[historyCur].fileName) != errNone) {
686 displayPage(history[historyCur].page, zoom, rotate, gFalse, gFalse);
689 void XPDFCore::scrollLeft(int nCols) {
690 scrollTo(scrollX - nCols * 16, scrollY);
693 void XPDFCore::scrollRight(int nCols) {
694 scrollTo(scrollX + nCols * 16, scrollY);
697 void XPDFCore::scrollUp(int nLines) {
698 scrollTo(scrollX, scrollY - nLines * 16);
701 void XPDFCore::scrollDown(int nLines) {
702 scrollTo(scrollX, scrollY + nLines * 16);
705 void XPDFCore::scrollPageUp() {
707 gotoPrevPage(1, gFalse, gTrue);
709 scrollTo(scrollX, scrollY - drawAreaHeight);
713 void XPDFCore::scrollPageDown() {
714 if (scrollY >= out->getBitmapHeight() - drawAreaHeight) {
715 gotoNextPage(1, gTrue);
717 scrollTo(scrollX, scrollY + drawAreaHeight);
721 void XPDFCore::scrollTo(int x, int y) {
727 maxPos = out ? out->getBitmapWidth() : 1;
728 if (maxPos < drawAreaWidth) {
729 maxPos = drawAreaWidth;
733 } else if (x > maxPos - drawAreaWidth) {
734 pos = maxPos - drawAreaWidth;
738 if (scrollX != pos) {
740 XmScrollBarSetValues(hScrollBar, scrollX, drawAreaWidth, 16,
741 drawAreaWidth, False);
745 maxPos = out ? out->getBitmapHeight() : 1;
746 if (maxPos < drawAreaHeight) {
747 maxPos = drawAreaHeight;
751 } else if (y > maxPos - drawAreaHeight) {
752 pos = maxPos - drawAreaHeight;
756 if (scrollY != pos) {
758 XmScrollBarSetValues(vScrollBar, scrollY, drawAreaHeight, 16,
759 drawAreaHeight, False);
764 redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
768 //------------------------------------------------------------------------
770 //------------------------------------------------------------------------
772 void XPDFCore::setSelection(int newXMin, int newYMin,
773 int newXMax, int newYMax) {
775 GBool needRedraw, needScroll;
776 GBool moveLeft, moveRight, moveTop, moveBottom;
777 SplashColor xorColor;
780 // erase old selection on off-screen bitmap
782 if (selectXMin < selectXMax && selectYMin < selectYMax) {
783 xorColor.rgb8 = splashMakeRGB8(0xff, 0xff, 0xff);
784 out->xorRectangle(selectXMin, selectYMin, selectXMax, selectYMax,
785 new SplashSolidColor(xorColor));
789 // draw new selection on off-screen bitmap
790 if (newXMin < newXMax && newYMin < newYMax) {
791 xorColor.rgb8 = splashMakeRGB8(0xff, 0xff, 0xff);
792 out->xorRectangle(newXMin, newYMin, newXMax, newYMax,
793 new SplashSolidColor(xorColor));
797 // check which edges moved
798 moveLeft = newXMin != selectXMin;
799 moveTop = newYMin != selectYMin;
800 moveRight = newXMax != selectXMax;
801 moveBottom = newYMax != selectYMax;
803 // redraw currently visible part of bitmap
806 redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin,
807 (newYMin < selectYMin) ? newYMin : selectYMin,
808 (newXMin > selectXMin) ? newXMin : selectXMin,
809 (newYMax > selectYMax) ? newYMax : selectYMax);
812 redrawRectangle((newXMax < selectXMax) ? newXMax : selectXMax,
813 (newYMin < selectYMin) ? newYMin : selectYMin,
814 (newXMax > selectXMax) ? newXMax : selectXMax,
815 (newYMax > selectYMax) ? newYMax : selectYMax);
818 redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin,
819 (newYMin < selectYMin) ? newYMin : selectYMin,
820 (newXMax > selectXMax) ? newXMax : selectXMax,
821 (newYMin > selectYMin) ? newYMin : selectYMin);
824 redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin,
825 (newYMax < selectYMax) ? newYMax : selectYMax,
826 (newXMax > selectXMax) ? newXMax : selectXMax,
827 (newYMax > selectYMax) ? newYMax : selectYMax);
831 // switch to new selection coords
832 selectXMin = newXMin;
833 selectXMax = newXMax;
834 selectYMin = newYMin;
835 selectYMax = newYMax;
837 // scroll if necessary
844 if (moveLeft && selectXMin < x) {
847 } else if (moveRight && selectXMax >= x + drawAreaWidth) {
848 x = selectXMax - drawAreaWidth;
850 } else if (moveLeft && selectXMin >= x + drawAreaWidth) {
851 x = selectXMin - drawAreaWidth;
853 } else if (moveRight && selectXMax < x) {
857 if (moveTop && selectYMin < y) {
860 } else if (moveBottom && selectYMax >= y + drawAreaHeight) {
861 y = selectYMax - drawAreaHeight;
863 } else if (moveTop && selectYMin >= y + drawAreaHeight) {
864 y = selectYMin - drawAreaHeight;
866 } else if (moveBottom && selectYMax < y) {
875 void XPDFCore::moveSelection(int mx, int my) {
876 int xMin, yMin, xMax, yMax;
881 } else if (mx >= out->getBitmapWidth()) {
882 mx = out->getBitmapWidth() - 1;
886 } else if (my >= out->getBitmapHeight()) {
887 my = out->getBitmapHeight() - 1;
890 // move appropriate edges of selection
892 if (mx < selectXMax) {
898 lastDragLeft = gFalse;
901 if (mx > selectXMin) {
907 lastDragLeft = gTrue;
911 if (my < selectYMax) {
917 lastDragTop = gFalse;
920 if (my > selectYMin) {
930 // redraw the selection
931 setSelection(xMin, yMin, xMax, yMax);
934 // X's copy-and-paste mechanism is brain damaged. Xt doesn't help
935 // any, but doesn't make it too much worse, either. Motif, on the
936 // other hand, adds significant complexity to the mess. So here we
937 // blow off the Motif junk and stick to plain old Xt. The next two
938 // functions (copySelection and convertSelectionCbk) implement the
939 // magic needed to deal with Xt's mechanism. Note that this requires
940 // global variables (currentSelection and currentSelectionOwner).
942 void XPDFCore::copySelection() {
943 if (!doc->okToCopy()) {
946 if (currentSelection) {
947 delete currentSelection;
949 //~ for multithreading: need a mutex here
950 currentSelection = out->getText(selectXMin, selectYMin,
951 selectXMax, selectYMax);
952 currentSelectionOwner = this;
953 XtOwnSelection(drawArea, XA_PRIMARY, XtLastTimestampProcessed(display),
954 &convertSelectionCbk, NULL, NULL);
957 Boolean XPDFCore::convertSelectionCbk(Widget widget, Atom *selection,
958 Atom *target, Atom *type,
959 XtPointer *value, unsigned long *length,
963 // send back a list of supported conversion targets
964 if (*target == targetsAtom) {
965 if (!(array = (Atom *)XtMalloc(sizeof(Atom)))) {
968 array[0] = XA_STRING;
969 *value = (XtPointer)array;
975 // send the selected text
976 } else if (*target == XA_STRING) {
977 //~ for multithreading: need a mutex here
978 *value = XtNewString(currentSelection->getCString());
979 *length = currentSelection->getLength();
981 *format = 8; // 8-bit elements
988 GBool XPDFCore::getSelection(int *xMin, int *yMin, int *xMax, int *yMax) {
989 if (selectXMin >= selectXMax || selectYMin >= selectYMax) {
999 GString *XPDFCore::extractText(int xMin, int yMin, int xMax, int yMax) {
1000 if (!doc->okToCopy()) {
1003 return out->getText(xMin, yMin, xMax, yMax);
1006 GString *XPDFCore::extractText(int pageNum,
1007 int xMin, int yMin, int xMax, int yMax) {
1008 TextOutputDev *textOut;
1011 if (!doc->okToCopy()) {
1014 textOut = new TextOutputDev(NULL, gTrue, gFalse, gFalse);
1015 if (!textOut->isOk()) {
1019 doc->displayPage(textOut, pageNum, dpi, dpi, rotate, gTrue, gFalse);
1020 s = textOut->getText(xMin, yMin, xMax, yMax);
1025 //------------------------------------------------------------------------
1027 //------------------------------------------------------------------------
1029 GBool XPDFCore::doLink(int mx, int my) {
1034 out->cvtDevToUser(mx, my, &x, &y);
1035 if ((action = doc->findLink(x, y))) {
1042 void XPDFCore::doAction(LinkAction *action) {
1043 LinkActionKind kind;
1047 GString *fileName, *fileName2;
1049 GString *actionName;
1050 Object movieAnnot, obj1, obj2;
1054 switch (kind = action->getKind()) {
1056 // GoTo / GoToR action
1059 if (kind == actionGoTo) {
1062 if ((dest = ((LinkGoTo *)action)->getDest())) {
1063 dest = dest->copy();
1064 } else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) {
1065 namedDest = namedDest->copy();
1070 if ((dest = ((LinkGoToR *)action)->getDest())) {
1071 dest = dest->copy();
1072 } else if ((namedDest = ((LinkGoToR *)action)->getNamedDest())) {
1073 namedDest = namedDest->copy();
1075 s = ((LinkGoToR *)action)->getFileName()->getCString();
1076 //~ translate path name for VMS (deal with '/')
1077 if (isAbsolutePath(s)) {
1078 fileName = new GString(s);
1080 fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s);
1082 if (loadFile(fileName) != errNone) {
1095 dest = doc->findDest(namedDest);
1099 displayDest(dest, zoom, rotate, gTrue);
1102 if (kind == actionGoToR) {
1103 displayPage(1, zoom, 0, gFalse, gTrue);
1110 fileName = ((LinkLaunch *)action)->getFileName();
1111 s = fileName->getCString();
1112 if (!strcmp(s + fileName->getLength() - 4, ".pdf") ||
1113 !strcmp(s + fileName->getLength() - 4, ".PDF")) {
1114 //~ translate path name for VMS (deal with '/')
1115 if (isAbsolutePath(s)) {
1116 fileName = fileName->copy();
1118 fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s);
1120 if (loadFile(fileName) != errNone) {
1125 displayPage(1, zoom, rotate, gFalse, gTrue);
1127 fileName = fileName->copy();
1128 if (((LinkLaunch *)action)->getParams()) {
1129 fileName->append(' ');
1130 fileName->append(((LinkLaunch *)action)->getParams());
1133 fileName->insert(0, "spawn/nowait ");
1134 #elif defined(__EMX__)
1135 fileName->insert(0, "start /min /n ");
1137 fileName->append(" &");
1139 msg = new GString("About to execute the command:\n");
1140 msg->append(fileName);
1141 if (doQuestionDialog("Launching external application", msg)) {
1142 system(fileName->getCString());
1151 if (!(cmd = globalParams->getURLCommand())) {
1152 error(-1, "No urlCommand defined in config file");
1155 runCommand(cmd, ((LinkURI *)action)->getURI());
1160 actionName = ((LinkNamed *)action)->getName();
1161 if (!actionName->cmp("NextPage")) {
1162 gotoNextPage(1, gTrue);
1163 } else if (!actionName->cmp("PrevPage")) {
1164 gotoPrevPage(1, gTrue, gFalse);
1165 } else if (!actionName->cmp("FirstPage")) {
1167 displayPage(1, zoom, rotate, gTrue, gTrue);
1169 } else if (!actionName->cmp("LastPage")) {
1170 if (page != doc->getNumPages()) {
1171 displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue);
1173 } else if (!actionName->cmp("GoBack")) {
1175 } else if (!actionName->cmp("GoForward")) {
1177 } else if (!actionName->cmp("Quit")) {
1179 (*actionCbk)(actionCbkData, "Quit");
1182 error(-1, "Unknown named action: '%s'", actionName->getCString());
1188 if (!(cmd = globalParams->getMovieCommand())) {
1189 error(-1, "No movieCommand defined in config file");
1192 if (((LinkMovie *)action)->hasAnnotRef()) {
1193 doc->getXRef()->fetch(((LinkMovie *)action)->getAnnotRef()->num,
1194 ((LinkMovie *)action)->getAnnotRef()->gen,
1197 doc->getCatalog()->getPage(page)->getAnnots(&obj1);
1198 if (obj1.isArray()) {
1199 for (i = 0; i < obj1.arrayGetLength(); ++i) {
1200 if (obj1.arrayGet(i, &movieAnnot)->isDict()) {
1201 if (movieAnnot.dictLookup("Subtype", &obj2)->isName("Movie")) {
1212 if (movieAnnot.isDict()) {
1213 if (movieAnnot.dictLookup("Movie", &obj1)->isDict()) {
1214 if (obj1.dictLookup("F", &obj2)) {
1215 if ((fileName = LinkAction::getFileSpecName(&obj2))) {
1216 if (!isAbsolutePath(fileName->getCString())) {
1217 fileName2 = appendToPath(
1218 grabPath(doc->getFileName()->getCString()),
1219 fileName->getCString());
1221 fileName = fileName2;
1223 runCommand(cmd, fileName);
1234 // unknown action type
1236 error(-1, "Unknown link action type: '%s'",
1237 ((LinkUnknown *)action)->getAction()->getCString());
1242 // Run a command, given a <cmdFmt> string with one '%s' in it, and an
1243 // <arg> string to insert in place of the '%s'.
1244 void XPDFCore::runCommand(GString *cmdFmt, GString *arg) {
1248 if ((s = strstr(cmdFmt->getCString(), "%s"))) {
1249 cmd = mungeURL(arg);
1250 cmd->insert(0, cmdFmt->getCString(),
1251 s - cmdFmt->getCString());
1254 cmd = cmdFmt->copy();
1257 cmd->insert(0, "spawn/nowait ");
1258 #elif defined(__EMX__)
1259 cmd->insert(0, "start /min /n ");
1263 system(cmd->getCString());
1267 // Escape any characters in a URL which might cause problems when
1268 // calling system().
1269 GString *XPDFCore::mungeURL(GString *url) {
1270 static char *allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1271 "abcdefghijklmnopqrstuvwxyz"
1279 newURL = new GString();
1280 for (i = 0; i < url->getLength(); ++i) {
1281 c = url->getChar(i);
1282 if (strchr(allowed, c)) {
1285 sprintf(buf, "%%%02x", c & 0xff);
1286 newURL->append(buf);
1293 //------------------------------------------------------------------------
1295 //------------------------------------------------------------------------
1297 void XPDFCore::find(char *s, GBool next) {
1299 TextOutputDev *textOut;
1300 int xMin, yMin, xMax, yMax;
1301 double xMin1, yMin1, xMax1, yMax1;
1306 // check for zero-length string
1312 // set cursor to watch
1313 setCursor(busyCursor);
1315 // convert to Unicode
1316 #if 1 //~ should do something more intelligent here
1318 u = (Unicode *)gmalloc(len * sizeof(Unicode));
1319 for (i = 0; i < len; ++i) {
1320 u[i] = (Unicode)(s[i] & 0xff);
1324 // search current page starting at current selection or top of page
1325 startAtTop = !next && !(selectXMin < selectXMax && selectYMin < selectYMax);
1326 xMin = selectXMin + 1;
1327 yMin = selectYMin + 1;
1329 if (out->findText(u, len, startAtTop, gTrue, next, gFalse,
1330 &xMin, &yMin, &xMax, &yMax)) {
1334 // search following pages
1335 textOut = new TextOutputDev(NULL, gTrue, gFalse, gFalse);
1336 if (!textOut->isOk()) {
1340 for (pg = page+1; pg <= doc->getNumPages(); ++pg) {
1341 doc->displayPage(textOut, pg, 72, 72, 0, gTrue, gFalse);
1342 if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse,
1343 &xMin1, &yMin1, &xMax1, &yMax1)) {
1348 // search previous pages
1349 for (pg = 1; pg < page; ++pg) {
1350 doc->displayPage(textOut, pg, 72, 72, 0, gTrue, gFalse);
1351 if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse,
1352 &xMin1, &yMin1, &xMax1, &yMax1)) {
1358 // search current page ending at current selection
1363 if (out->findText(u, len, gTrue, gFalse, gFalse, next,
1364 &xMin, &yMin, &xMax, &yMax)) {
1373 // found on a different page
1376 displayPage(pg, zoom, rotate, gTrue, gTrue);
1377 if (!out->findText(u, len, gTrue, gTrue, gFalse, gFalse,
1378 &xMin, &yMin, &xMax, &yMax)) {
1379 // this can happen if coalescing is bad
1383 // found: change the selection
1385 setSelection(xMin, yMin, xMax, yMax);
1386 #ifndef NO_TEXT_SELECT
1393 // reset cursors to normal
1397 //------------------------------------------------------------------------
1399 //------------------------------------------------------------------------
1401 void XPDFCore::setBusyCursor(GBool busy) {
1402 setCursor(busy ? busyCursor : None);
1405 void XPDFCore::takeFocus() {
1406 XmProcessTraversal(drawArea, XmTRAVERSE_CURRENT);
1409 //------------------------------------------------------------------------
1411 //------------------------------------------------------------------------
1413 void XPDFCore::initWindow() {
1417 // create the cursors
1418 busyCursor = XCreateFontCursor(display, XC_watch);
1419 linkCursor = XCreateFontCursor(display, XC_hand2);
1420 selectCursor = XCreateFontCursor(display, XC_cross);
1423 // create the scrolled window and scrollbars
1425 XtSetArg(args[n], XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++n;
1426 XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n;
1427 scrolledWin = XmCreateScrolledWindow(parentWidget, "scroll", args, n);
1428 XtManageChild(scrolledWin);
1430 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
1431 XtSetArg(args[n], XmNminimum, 0); ++n;
1432 XtSetArg(args[n], XmNmaximum, 1); ++n;
1433 XtSetArg(args[n], XmNsliderSize, 1); ++n;
1434 XtSetArg(args[n], XmNvalue, 0); ++n;
1435 XtSetArg(args[n], XmNincrement, 1); ++n;
1436 XtSetArg(args[n], XmNpageIncrement, 1); ++n;
1437 hScrollBar = XmCreateScrollBar(scrolledWin, "hScrollBar", args, n);
1438 XtManageChild(hScrollBar);
1439 XtAddCallback(hScrollBar, XmNvalueChangedCallback,
1440 &hScrollChangeCbk, (XtPointer)this);
1441 #ifndef DISABLE_SMOOTH_SCROLL
1442 XtAddCallback(hScrollBar, XmNdragCallback,
1443 &hScrollDragCbk, (XtPointer)this);
1446 XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n;
1447 XtSetArg(args[n], XmNminimum, 0); ++n;
1448 XtSetArg(args[n], XmNmaximum, 1); ++n;
1449 XtSetArg(args[n], XmNsliderSize, 1); ++n;
1450 XtSetArg(args[n], XmNvalue, 0); ++n;
1451 XtSetArg(args[n], XmNincrement, 1); ++n;
1452 XtSetArg(args[n], XmNpageIncrement, 1); ++n;
1453 vScrollBar = XmCreateScrollBar(scrolledWin, "vScrollBar", args, n);
1454 XtManageChild(vScrollBar);
1455 XtAddCallback(vScrollBar, XmNvalueChangedCallback,
1456 &vScrollChangeCbk, (XtPointer)this);
1457 #ifndef DISABLE_SMOOTH_SCROLL
1458 XtAddCallback(vScrollBar, XmNdragCallback,
1459 &vScrollDragCbk, (XtPointer)this);
1462 // create the drawing area
1464 XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); ++n;
1465 XtSetArg(args[n], XmNmarginWidth, 0); ++n;
1466 XtSetArg(args[n], XmNmarginHeight, 0); ++n;
1468 XtSetArg(args[n], XmNshadowThickness, 0); ++n;
1470 drawAreaFrame = XmCreateFrame(scrolledWin, "drawAreaFrame", args, n);
1471 XtManageChild(drawAreaFrame);
1473 XtSetArg(args[n], XmNresizePolicy, XmRESIZE_ANY); ++n;
1474 XtSetArg(args[n], XmNwidth, 700); ++n;
1475 XtSetArg(args[n], XmNheight, 500); ++n;
1476 drawArea = XmCreateDrawingArea(drawAreaFrame, "drawArea", args, n);
1477 XtManageChild(drawArea);
1478 XtAddCallback(drawArea, XmNresizeCallback, &resizeCbk, (XtPointer)this);
1479 XtAddCallback(drawArea, XmNexposeCallback, &redrawCbk, (XtPointer)this);
1480 XtAddCallback(drawArea, XmNinputCallback, &inputCbk, (XtPointer)this);
1481 resizeCbk(drawArea, this, NULL);
1483 // set up mouse motion translations
1484 XtOverrideTranslations(drawArea, XtParseTranslationTable(
1485 "<Btn1Down>:DrawingAreaInput()\n"
1486 "<Btn1Up>:DrawingAreaInput()\n"
1487 "<Btn1Motion>:DrawingAreaInput()\n"
1488 "<Motion>:DrawingAreaInput()"));
1490 // can't create a GC until the window gets mapped
1494 void XPDFCore::hScrollChangeCbk(Widget widget, XtPointer ptr,
1495 XtPointer callData) {
1496 XPDFCore *core = (XPDFCore *)ptr;
1497 XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
1499 core->scrollTo(data->value, core->scrollY);
1502 void XPDFCore::hScrollDragCbk(Widget widget, XtPointer ptr,
1503 XtPointer callData) {
1504 XPDFCore *core = (XPDFCore *)ptr;
1505 XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
1507 core->scrollTo(data->value, core->scrollY);
1510 void XPDFCore::vScrollChangeCbk(Widget widget, XtPointer ptr,
1511 XtPointer callData) {
1512 XPDFCore *core = (XPDFCore *)ptr;
1513 XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
1515 core->scrollTo(core->scrollX, data->value);
1518 void XPDFCore::vScrollDragCbk(Widget widget, XtPointer ptr,
1519 XtPointer callData) {
1520 XPDFCore *core = (XPDFCore *)ptr;
1521 XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
1523 core->scrollTo(core->scrollX, data->value);
1526 void XPDFCore::resizeCbk(Widget widget, XtPointer ptr, XtPointer callData) {
1527 XPDFCore *core = (XPDFCore *)ptr;
1531 int oldScrollX, oldScrollY;
1534 XtSetArg(args[n], XmNwidth, &w); ++n;
1535 XtSetArg(args[n], XmNheight, &h); ++n;
1536 XtGetValues(core->drawArea, args, n);
1537 core->drawAreaWidth = (int)w;
1538 core->drawAreaHeight = (int)h;
1539 if (core->page >= 0 &&
1540 (core->zoom == zoomPage || core->zoom == zoomWidth)) {
1541 core->displayPage(core->page, core->zoom, core->rotate,
1544 oldScrollX = core->scrollX;
1545 oldScrollY = core->scrollY;
1546 core->updateScrollBars();
1547 if (core->scrollX != oldScrollX || core->scrollY != oldScrollY) {
1548 core->redrawRectangle(core->scrollX, core->scrollY,
1549 core->drawAreaWidth, core->drawAreaHeight);
1554 void XPDFCore::redrawCbk(Widget widget, XtPointer ptr, XtPointer callData) {
1555 XPDFCore *core = (XPDFCore *)ptr;
1556 XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData;
1559 if (data->reason == XmCR_EXPOSE) {
1560 x = core->scrollX + data->event->xexpose.x;
1561 y = core->scrollY + data->event->xexpose.y;
1562 w = data->event->xexpose.width;
1563 h = data->event->xexpose.height;
1567 w = core->drawAreaWidth;
1568 h = core->drawAreaHeight;
1570 core->redrawRectangle(x, y, w, h);
1573 void XPDFCore::outputDevRedrawCbk(void *data) {
1574 XPDFCore *core = (XPDFCore *)data;
1576 core->redrawRectangle(core->scrollX, core->scrollY,
1577 core->drawAreaWidth, core->drawAreaHeight);
1580 void XPDFCore::inputCbk(Widget widget, XtPointer ptr, XtPointer callData) {
1581 XPDFCore *core = (XPDFCore *)ptr;
1582 XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData;
1591 switch (data->event->type) {
1593 if (data->event->xbutton.button == 1) {
1595 if (core->doc && core->doc->getNumPages() > 0) {
1596 if (core->selectEnabled) {
1597 mx = core->scrollX + data->event->xbutton.x;
1598 my = core->scrollY + data->event->xbutton.y;
1599 core->setSelection(mx, my, mx, my);
1600 core->setCursor(core->selectCursor);
1601 core->dragging = gTrue;
1604 } else if (data->event->xbutton.button == 2) {
1605 if (!core->fullScreen) {
1606 core->panning = gTrue;
1607 core->panMX = data->event->xbutton.x;
1608 core->panMY = data->event->xbutton.y;
1610 } else if (data->event->xbutton.button == 4) { // mouse wheel up
1611 if (core->fullScreen) {
1612 core->gotoPrevPage(1, gTrue, gFalse);
1613 } else if (core->scrollY == 0) {
1614 core->gotoPrevPage(1, gFalse, gTrue);
1618 } else if (data->event->xbutton.button == 5) { // mouse wheel down
1619 if (core->fullScreen ||
1621 core->out->getBitmapHeight() - core->drawAreaHeight) {
1622 core->gotoNextPage(1, gTrue);
1624 core->scrollDown(1);
1626 } else if (data->event->xbutton.button == 6) { // second mouse wheel left
1627 if (!core->fullScreen) {
1628 core->scrollLeft(1);
1630 } else if (data->event->xbutton.button == 7) { // second mouse wheel right
1631 if (!core->fullScreen) {
1632 core->scrollRight(1);
1635 if (*core->mouseCbk) {
1636 (*core->mouseCbk)(core->mouseCbkData, data->event);
1641 if (data->event->xbutton.button == 1) {
1642 if (core->doc && core->doc->getNumPages() > 0) {
1643 mx = core->scrollX + data->event->xbutton.x;
1644 my = core->scrollY + data->event->xbutton.y;
1645 if (core->dragging) {
1646 core->dragging = gFalse;
1647 core->setCursor(None);
1648 core->moveSelection(mx, my);
1649 #ifndef NO_TEXT_SELECT
1650 if (core->selectXMin != core->selectXMax &&
1651 core->selectYMin != core->selectYMax) {
1652 if (core->doc->okToCopy()) {
1653 core->copySelection();
1655 error(-1, "Copying of text from this document is not allowed.");
1660 if (core->hyperlinksEnabled) {
1661 if (core->selectXMin == core->selectXMax ||
1662 core->selectYMin == core->selectYMax) {
1663 core->doLink(mx, my);
1667 } else if (data->event->xbutton.button == 2) {
1668 core->panning = gFalse;
1670 if (*core->mouseCbk) {
1671 (*core->mouseCbk)(core->mouseCbkData, data->event);
1676 if (core->doc && core->doc->getNumPages() > 0) {
1677 mx = core->scrollX + data->event->xbutton.x;
1678 my = core->scrollY + data->event->xbutton.y;
1679 if (core->dragging) {
1680 core->moveSelection(mx, my);
1681 } else if (core->hyperlinksEnabled) {
1682 core->out->cvtDevToUser(mx, my, &x, &y);
1683 if ((action = core->doc->findLink(x, y))) {
1684 core->setCursor(core->linkCursor);
1685 if (action != core->linkAction) {
1686 core->linkAction = action;
1687 if (core->updateCbk) {
1689 switch (action->getKind()) {
1691 s = "[internal link]";
1694 s = ((LinkGoToR *)action)->getFileName()->getCString();
1697 s = ((LinkLaunch *)action)->getFileName()->getCString();
1700 s = ((LinkURI *)action)->getURI()->getCString();
1703 s = ((LinkNamed *)action)->getName()->getCString();
1709 s = "[unknown link]";
1712 (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, s);
1716 core->setCursor(None);
1717 if (core->linkAction) {
1718 core->linkAction = NULL;
1719 if (core->updateCbk) {
1720 (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, "");
1726 if (core->panning) {
1727 core->scrollTo(core->scrollX - (data->event->xbutton.x - core->panMX),
1728 core->scrollY - (data->event->xbutton.y - core->panMY));
1729 core->panMX = data->event->xbutton.x;
1730 core->panMY = data->event->xbutton.y;
1734 n = XLookupString(&data->event->xkey, buf, sizeof(buf) - 1,
1736 core->keyPress(buf, key, data->event->xkey.state);
1741 void XPDFCore::keyPress(char *s, KeySym key, Guint modifiers) {
1745 if (modifiers & ControlMask) {
1746 displayPage(1, zoom, rotate, gTrue, gTrue);
1747 } else if (!fullScreen) {
1753 if (modifiers & ControlMask) {
1754 displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue);
1755 } else if (!fullScreen) {
1756 scrollTo(out->getBitmapWidth() - drawAreaWidth,
1757 out->getBitmapHeight() - drawAreaHeight);
1763 gotoPrevPage(1, gTrue, gFalse);
1769 case XK_KP_Page_Down:
1771 gotoNextPage(1, gTrue);
1803 (*keyPressCbk)(keyPressCbkData, s, key, modifiers);
1807 void XPDFCore::redrawRectangle(int x, int y, int w, int h) {
1816 if (x + w > scrollX + drawAreaWidth) {
1817 w = scrollX + drawAreaWidth - x;
1823 if (y + h > scrollY + drawAreaHeight) {
1824 h = scrollY + drawAreaHeight - y;
1827 // create a GC for the drawing area
1828 drawAreaWin = XtWindow(drawArea);
1830 gcValues.foreground = paperColor;
1831 drawAreaGC = XCreateGC(display, drawAreaWin, GCForeground, &gcValues);
1834 // draw white background past the edges of the document
1835 if (x + w > out->getBitmapWidth()) {
1836 XFillRectangle(display, drawAreaWin, drawAreaGC,
1837 out->getBitmapWidth() - scrollX, y - scrollY,
1838 x + w - out->getBitmapWidth(), h);
1839 w = out->getBitmapWidth() - x;
1841 if (y + h > out->getBitmapHeight()) {
1842 XFillRectangle(display, drawAreaWin, drawAreaGC,
1843 x - scrollX, out->getBitmapHeight() - scrollY,
1844 w, y + h - out->getBitmapHeight());
1845 h = out->getBitmapHeight() - y;
1849 if (w >= 0 && h >= 0) {
1850 out->redraw(x, y, drawAreaWin, drawAreaGC, x - scrollX, y - scrollY, w, h);
1854 void XPDFCore::updateScrollBars() {
1859 maxPos = out ? out->getBitmapWidth() : 1;
1860 if (maxPos < drawAreaWidth) {
1861 maxPos = drawAreaWidth;
1863 if (scrollX > maxPos - drawAreaWidth) {
1864 scrollX = maxPos - drawAreaWidth;
1867 XtSetArg(args[n], XmNvalue, scrollX); ++n;
1868 XtSetArg(args[n], XmNmaximum, maxPos); ++n;
1869 XtSetArg(args[n], XmNsliderSize, drawAreaWidth); ++n;
1870 XtSetArg(args[n], XmNincrement, 16); ++n;
1871 XtSetArg(args[n], XmNpageIncrement, drawAreaWidth); ++n;
1872 XtSetValues(hScrollBar, args, n);
1874 maxPos = out ? out->getBitmapHeight() : 1;
1875 if (maxPos < drawAreaHeight) {
1876 maxPos = drawAreaHeight;
1878 if (scrollY > maxPos - drawAreaHeight) {
1879 scrollY = maxPos - drawAreaHeight;
1882 XtSetArg(args[n], XmNvalue, scrollY); ++n;
1883 XtSetArg(args[n], XmNmaximum, maxPos); ++n;
1884 XtSetArg(args[n], XmNsliderSize, drawAreaHeight); ++n;
1885 XtSetArg(args[n], XmNincrement, 16); ++n;
1886 XtSetArg(args[n], XmNpageIncrement, drawAreaHeight); ++n;
1887 XtSetValues(vScrollBar, args, n);
1890 void XPDFCore::setCursor(Cursor cursor) {
1893 if (cursor == currentCursor) {
1896 if (!(topWin = XtWindow(shell))) {
1899 if (cursor == None) {
1900 XUndefineCursor(display, topWin);
1902 XDefineCursor(display, topWin, cursor);
1905 currentCursor = cursor;
1908 GBool XPDFCore::doQuestionDialog(char *title, GString *msg) {
1909 return doDialog(XmDIALOG_QUESTION, gTrue, title, msg);
1912 void XPDFCore::doInfoDialog(char *title, GString *msg) {
1913 doDialog(XmDIALOG_INFORMATION, gFalse, title, msg);
1916 void XPDFCore::doErrorDialog(char *title, GString *msg) {
1917 doDialog(XmDIALOG_ERROR, gFalse, title, msg);
1920 GBool XPDFCore::doDialog(int type, GBool hasCancel,
1921 char *title, GString *msg) {
1922 Widget dialog, scroll, text;
1923 XtAppContext appContext;
1930 XtSetArg(args[n], XmNdialogType, type); ++n;
1931 XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n;
1932 s1 = XmStringCreateLocalized(title);
1933 XtSetArg(args[n], XmNdialogTitle, s1); ++n;
1934 s2 = NULL; // make gcc happy
1935 if (msg->getLength() <= 80) {
1936 s2 = XmStringCreateLocalized(msg->getCString());
1937 XtSetArg(args[n], XmNmessageString, s2); ++n;
1939 dialog = XmCreateMessageDialog(drawArea, "questionDialog", args, n);
1941 if (msg->getLength() <= 80) {
1945 XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); ++n;
1946 if (drawAreaWidth > 300) {
1947 XtSetArg(args[n], XmNwidth, drawAreaWidth - 100); ++n;
1949 scroll = XmCreateScrolledWindow(dialog, "scroll", args, n);
1950 XtManageChild(scroll);
1952 XtSetArg(args[n], XmNeditable, False); ++n;
1953 XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); ++n;
1954 XtSetArg(args[n], XmNvalue, msg->getCString()); ++n;
1955 XtSetArg(args[n], XmNshadowThickness, 0); ++n;
1956 text = XmCreateText(scroll, "text", args, n);
1957 XtManageChild(text);
1959 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
1960 XtAddCallback(dialog, XmNokCallback,
1961 &dialogOkCbk, (XtPointer)this);
1963 XtAddCallback(dialog, XmNcancelCallback,
1964 &dialogCancelCbk, (XtPointer)this);
1966 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
1969 XtManageChild(dialog);
1971 appContext = XtWidgetToApplicationContext(dialog);
1974 XtAppNextEvent(appContext, &event);
1975 XtDispatchEvent(&event);
1976 } while (!dialogDone);
1978 XtUnmanageChild(dialog);
1979 XtDestroyWidget(dialog);
1981 return dialogDone > 0;
1984 void XPDFCore::dialogOkCbk(Widget widget, XtPointer ptr,
1985 XtPointer callData) {
1986 XPDFCore *core = (XPDFCore *)ptr;
1988 core->dialogDone = 1;
1991 void XPDFCore::dialogCancelCbk(Widget widget, XtPointer ptr,
1992 XtPointer callData) {
1993 XPDFCore *core = (XPDFCore *)ptr;
1995 core->dialogDone = -1;