00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <aconf.h>
00010
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014
00015 #include <X11/keysym.h>
00016 #include <X11/cursorfont.h>
00017 #include "gmem.h"
00018 #include "GString.h"
00019 #include "GList.h"
00020 #include "Error.h"
00021 #include "GlobalParams.h"
00022 #include "PDFDoc.h"
00023 #include "ErrorCodes.h"
00024 #include "GfxState.h"
00025 #include "PSOutputDev.h"
00026 #include "TextOutputDev.h"
00027 #include "XPixmapOutputDev.h"
00028 #include "XPDFCore.h"
00029
00030
00031 #ifdef LESSTIF_VERSION
00032 #undef XtDisplay
00033 #undef XtScreen
00034 #undef XtWindow
00035 #undef XtParent
00036 #undef XtIsRealized
00037 #endif
00038
00039
00040 #ifndef XK_Page_Up
00041 #define XK_Page_Up 0xFF55
00042 #endif
00043 #ifndef XK_Page_Down
00044 #define XK_Page_Down 0xFF56
00045 #endif
00046 #ifndef XK_KP_Home
00047 #define XK_KP_Home 0xFF95
00048 #endif
00049 #ifndef XK_KP_Left
00050 #define XK_KP_Left 0xFF96
00051 #endif
00052 #ifndef XK_KP_Up
00053 #define XK_KP_Up 0xFF97
00054 #endif
00055 #ifndef XK_KP_Right
00056 #define XK_KP_Right 0xFF98
00057 #endif
00058 #ifndef XK_KP_Down
00059 #define XK_KP_Down 0xFF99
00060 #endif
00061 #ifndef XK_KP_Prior
00062 #define XK_KP_Prior 0xFF9A
00063 #endif
00064 #ifndef XK_KP_Page_Up
00065 #define XK_KP_Page_Up 0xFF9A
00066 #endif
00067 #ifndef XK_KP_Next
00068 #define XK_KP_Next 0xFF9B
00069 #endif
00070 #ifndef XK_KP_Page_Down
00071 #define XK_KP_Page_Down 0xFF9B
00072 #endif
00073 #ifndef XK_KP_End
00074 #define XK_KP_End 0xFF9C
00075 #endif
00076 #ifndef XK_KP_Begin
00077 #define XK_KP_Begin 0xFF9D
00078 #endif
00079 #ifndef XK_KP_Insert
00080 #define XK_KP_Insert 0xFF9E
00081 #endif
00082 #ifndef XK_KP_Delete
00083 #define XK_KP_Delete 0xFF9F
00084 #endif
00085
00086
00087
00088 #define highlightNone 0
00089 #define highlightNormal 1
00090 #define highlightSelected 2
00091
00092
00093
00094 static int zoomDPI[maxZoom - minZoom + 1] = {
00095 29, 35, 42, 50, 60,
00096 72,
00097 86, 104, 124, 149, 179
00098 };
00099
00100
00101
00102 GString *XPDFCore::currentSelection = NULL;
00103 XPDFCore *XPDFCore::currentSelectionOwner = NULL;
00104
00105
00106
00107
00108
00109 XPDFCore::XPDFCore(Widget shellA, Widget parentWidgetA,
00110 Gulong paperColorA, GBool fullScreenA, GBool reverseVideo,
00111 GBool installCmap, int rgbCubeSize) {
00112 GString *initialZoom;
00113 int i;
00114
00115 shell = shellA;
00116 parentWidget = parentWidgetA;
00117 display = XtDisplay(parentWidget);
00118 screenNum = XScreenNumberOfScreen(XtScreen(parentWidget));
00119
00120 paperColor = paperColorA;
00121 fullScreen = fullScreenA;
00122
00123
00124
00125 visual = DefaultVisual(display, screenNum);
00126 XtVaGetValues(shell, XmNcolormap, &colormap, NULL);
00127
00128 scrolledWin = NULL;
00129 hScrollBar = NULL;
00130 vScrollBar = NULL;
00131 drawAreaFrame = NULL;
00132 drawArea = NULL;
00133 out = NULL;
00134
00135 doc = NULL;
00136 page = 0;
00137 rotate = 0;
00138
00139
00140 initialZoom = globalParams->getInitialZoom();
00141 if (!initialZoom->cmp("page")) {
00142 zoom = zoomPage;
00143 } else if (!initialZoom->cmp("width")) {
00144 zoom = zoomWidth;
00145 } else {
00146 zoom = atoi(initialZoom->getCString());
00147 if (zoom < minZoom) {
00148 zoom = minZoom;
00149 } else if (zoom > maxZoom) {
00150 zoom = maxZoom;
00151 }
00152 }
00153
00154 scrollX = 0;
00155 scrollY = 0;
00156 linkAction = NULL;
00157 selectXMin = selectXMax = 0;
00158 selectYMin = selectYMax = 0;
00159 dragging = gFalse;
00160 lastDragLeft = lastDragTop = gTrue;
00161
00162 panning = gFalse;
00163
00164
00165 updateCbk = NULL;
00166 actionCbk = NULL;
00167 keyPressCbk = NULL;
00168 mouseCbk = NULL;
00169 reqPasswordCbk = NULL;
00170
00171
00172 historyCur = xpdfHistorySize - 1;
00173 historyBLen = historyFLen = 0;
00174 for (i = 0; i < xpdfHistorySize; ++i) {
00175 history[i].fileName = NULL;
00176 }
00177
00178
00179 hyperlinksEnabled = gTrue;
00180 selectEnabled = gTrue;
00181
00182
00183 initWindow();
00184
00185
00186 out = new XPixmapOutputDev(display, screenNum, visual, colormap,
00187 reverseVideo, paperColor,
00188 installCmap, rgbCubeSize, gTrue,
00189 &outputDevRedrawCbk, this);
00190 out->startDoc(NULL);
00191 }
00192
00193 XPDFCore::~XPDFCore() {
00194 int i;
00195
00196 if (out) {
00197 delete out;
00198 }
00199 if (doc) {
00200 delete doc;
00201 }
00202 if (currentSelectionOwner == this && currentSelection) {
00203 delete currentSelection;
00204 currentSelection = NULL;
00205 currentSelectionOwner = NULL;
00206 }
00207 for (i = 0; i < xpdfHistorySize; ++i) {
00208 if (history[i].fileName) {
00209 delete history[i].fileName;
00210 }
00211 }
00212 if (selectGC) {
00213 XFreeGC(display, selectGC);
00214 XFreeGC(display, highlightGC);
00215 }
00216 if (drawAreaGC) {
00217 XFreeGC(display, drawAreaGC);
00218 }
00219 if (drawArea) {
00220 XtDestroyWidget(drawArea);
00221 }
00222 if (drawAreaFrame) {
00223 XtDestroyWidget(drawAreaFrame);
00224 }
00225 if (vScrollBar) {
00226 XtDestroyWidget(vScrollBar);
00227 }
00228 if (hScrollBar) {
00229 XtDestroyWidget(hScrollBar);
00230 }
00231 if (scrolledWin) {
00232 XtDestroyWidget(scrolledWin);
00233 }
00234 if (busyCursor) {
00235 XFreeCursor(display, busyCursor);
00236 }
00237 if (linkCursor) {
00238 XFreeCursor(display, linkCursor);
00239 }
00240 if (selectCursor) {
00241 XFreeCursor(display, selectCursor);
00242 }
00243 }
00244
00245
00246
00247
00248
00249 int XPDFCore::loadFile(GString *fileName, GString *ownerPassword,
00250 GString *userPassword) {
00251 PDFDoc *newDoc;
00252 GString *password;
00253 GBool again;
00254 int err;
00255
00256
00257 setCursor(busyCursor);
00258
00259
00260 newDoc = new PDFDoc(fileName->copy(), ownerPassword, userPassword);
00261 if (!newDoc->isOk()) {
00262 err = newDoc->getErrorCode();
00263 delete newDoc;
00264 if (err != errEncrypted || !reqPasswordCbk) {
00265 setCursor(None);
00266 return err;
00267 }
00268
00269
00270 again = ownerPassword != NULL || userPassword != NULL;
00271 while (1) {
00272 if (!(password = (*reqPasswordCbk)(reqPasswordCbkData, again))) {
00273 setCursor(None);
00274 return errEncrypted;
00275 }
00276 newDoc = new PDFDoc(fileName->copy(), password, password);
00277 if (newDoc->isOk()) {
00278 break;
00279 }
00280 err = newDoc->getErrorCode();
00281 delete newDoc;
00282 if (err != errEncrypted) {
00283 setCursor(None);
00284 return err;
00285 }
00286 again = gTrue;
00287 }
00288 }
00289
00290
00291 if (doc) {
00292 delete doc;
00293 }
00294 doc = newDoc;
00295 if (out) {
00296 out->startDoc(doc->getXRef());
00297 }
00298
00299
00300 page = -99;
00301
00302
00303 modTime = getModTime(doc->getFileName()->getCString());
00304
00305
00306 if (updateCbk) {
00307 (*updateCbk)(updateCbkData, doc->getFileName(), -1,
00308 doc->getNumPages(), NULL);
00309 }
00310
00311
00312 setCursor(None);
00313
00314 return errNone;
00315 }
00316
00317 void XPDFCore::resizeToPage(int pg) {
00318 Dimension width, height;
00319 double width1, height1;
00320 Dimension topW, topH, topBorder, daW, daH;
00321 Dimension displayW, displayH;
00322
00323 displayW = DisplayWidth(display, screenNum);
00324 displayH = DisplayHeight(display, screenNum);
00325 if (fullScreen) {
00326 width = displayW;
00327 height = displayH;
00328 } else {
00329 if (pg < 0 || pg > doc->getNumPages()) {
00330 width1 = 612;
00331 height1 = 792;
00332 } else if (doc->getPageRotate(pg) == 90 ||
00333 doc->getPageRotate(pg) == 270) {
00334 width1 = doc->getPageHeight(pg);
00335 height1 = doc->getPageWidth(pg);
00336 } else {
00337 width1 = doc->getPageWidth(pg);
00338 height1 = doc->getPageHeight(pg);
00339 }
00340 if (zoom == zoomPage || zoom == zoomWidth) {
00341 width = (Dimension)((width1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5);
00342 height = (Dimension)((height1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5);
00343 } else {
00344 width = (Dimension)((width1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
00345 height = (Dimension)((height1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
00346 }
00347 if (width > displayW - 100) {
00348 width = displayW - 100;
00349 }
00350 if (height > displayH - 150) {
00351 height = displayH - 150;
00352 }
00353 }
00354
00355 if (XtIsRealized(shell)) {
00356 XtVaGetValues(shell, XmNwidth, &topW, XmNheight, &topH,
00357 XmNborderWidth, &topBorder, NULL);
00358 XtVaGetValues(drawArea, XmNwidth, &daW, XmNheight, &daH, NULL);
00359 XtVaSetValues(shell, XmNwidth, width + (topW - daW),
00360 XmNheight, height + (topH - daH), NULL);
00361 } else {
00362 XtVaSetValues(drawArea, XmNwidth, width, XmNheight, height, NULL);
00363 }
00364 }
00365
00366 void XPDFCore::clear() {
00367 if (!doc) {
00368 return;
00369 }
00370
00371
00372 delete doc;
00373 doc = NULL;
00374 out->clear();
00375
00376
00377 page = -99;
00378
00379
00380 scrollX = scrollY = 0;
00381 updateScrollBars();
00382 redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
00383 }
00384
00385 void XPDFCore::displayPage(int pageA, int zoomA, int rotateA,
00386 GBool scrollToTop, GBool addToHist) {
00387 double hDPI, vDPI;
00388 int rot;
00389 XPDFHistory *h;
00390 GBool newZoom;
00391 XGCValues gcValues;
00392 time_t newModTime;
00393 int oldScrollX, oldScrollY;
00394
00395
00396 newZoom = zoomA != zoom;
00397 zoom = zoomA;
00398 rotate = rotateA;
00399
00400
00401 if (!doc || pageA <= 0 || pageA > doc->getNumPages()) {
00402 return;
00403 }
00404
00405
00406 setCursor(busyCursor);
00407
00408
00409
00410 newModTime = getModTime(doc->getFileName()->getCString());
00411 if (newModTime != modTime) {
00412 if (loadFile(doc->getFileName()) == errNone) {
00413 if (pageA > doc->getNumPages()) {
00414 pageA = doc->getNumPages();
00415 }
00416 }
00417 modTime = newModTime;
00418 }
00419
00420
00421 if (selectGC) {
00422 XFreeGC(display, selectGC);
00423 XFreeGC(display, highlightGC);
00424 }
00425
00426
00427 page = pageA;
00428
00429
00430 if (scrollToTop) {
00431 scrollY = 0;
00432 }
00433
00434
00435 if (newZoom) {
00436 scrollX = scrollY = 0;
00437 }
00438
00439
00440 linkAction = NULL;
00441 selectXMin = selectXMax = 0;
00442 selectYMin = selectYMax = 0;
00443 dragging = gFalse;
00444 lastDragLeft = lastDragTop = gTrue;
00445
00446
00447 rot = rotate + doc->getPageRotate(page);
00448 if (rot >= 360) {
00449 rot -= 360;
00450 } else if (rotate < 0) {
00451 rot += 360;
00452 }
00453 if (zoom == zoomPage) {
00454 if (rot == 90 || rot == 270) {
00455 hDPI = (drawAreaWidth / doc->getPageHeight(page)) * 72;
00456 vDPI = (drawAreaHeight / doc->getPageWidth(page)) * 72;
00457 } else {
00458 hDPI = (drawAreaWidth / doc->getPageWidth(page)) * 72;
00459 vDPI = (drawAreaHeight / doc->getPageHeight(page)) * 72;
00460 }
00461 dpi = (hDPI < vDPI) ? hDPI : vDPI;
00462 } else if (zoom == zoomWidth) {
00463 if (rot == 90 || rot == 270) {
00464 dpi = (drawAreaWidth / doc->getPageHeight(page)) * 72;
00465 } else {
00466 dpi = (drawAreaWidth / doc->getPageWidth(page)) * 72;
00467 }
00468 } else {
00469 dpi = zoomDPI[zoom - minZoom];
00470 }
00471 out->setWindow(XtWindow(drawArea));
00472 doc->displayPage(out, page, dpi, rotate, gTrue);
00473 oldScrollX = scrollX;
00474 oldScrollY = scrollY;
00475 updateScrollBars();
00476 if (scrollX != oldScrollX || scrollY != oldScrollY) {
00477 redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
00478 }
00479
00480
00481
00482 if (addToHist) {
00483 if (++historyCur == xpdfHistorySize) {
00484 historyCur = 0;
00485 }
00486 h = &history[historyCur];
00487 if (h->fileName) {
00488 delete h->fileName;
00489 }
00490 h->fileName = doc->getFileName()->copy();
00491 h->page = page;
00492 if (historyBLen < xpdfHistorySize) {
00493 ++historyBLen;
00494 }
00495 historyFLen = 0;
00496 }
00497
00498
00499 if (updateCbk) {
00500 (*updateCbk)(updateCbkData, NULL, page, -1, "");
00501 }
00502
00503
00504 gcValues.foreground = BlackPixel(display, screenNum) ^
00505 WhitePixel(display, screenNum);
00506 gcValues.function = GXxor;
00507 selectGC = XCreateGC(display, out->getPixmap(),
00508 GCForeground | GCFunction, &gcValues);
00509 highlightGC = XCreateGC(display, out->getPixmap(),
00510 GCForeground | GCFunction, &gcValues);
00511
00512
00513 setCursor(None);
00514 }
00515
00516 void XPDFCore::displayDest(LinkDest *dest, int zoomA, int rotateA,
00517 GBool addToHist) {
00518 Ref pageRef;
00519 int pg;
00520 int dx, dy;
00521
00522 if (dest->isPageRef()) {
00523 pageRef = dest->getPageRef();
00524 pg = doc->findPage(pageRef.num, pageRef.gen);
00525 } else {
00526 pg = dest->getPageNum();
00527 }
00528 if (pg <= 0 || pg > doc->getNumPages()) {
00529 pg = 1;
00530 }
00531 if (pg != page) {
00532 displayPage(pg, zoomA, rotateA, gTrue, addToHist);
00533 }
00534
00535 if (fullScreen) {
00536 return;
00537 }
00538 switch (dest->getKind()) {
00539 case destXYZ:
00540 out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
00541 if (dest->getChangeLeft() || dest->getChangeTop()) {
00542 scrollTo(dest->getChangeLeft() ? dx : scrollX,
00543 dest->getChangeTop() ? dy : scrollY);
00544 }
00545
00546 break;
00547 case destFit:
00548 case destFitB:
00549
00550 scrollTo(0, 0);
00551 break;
00552 case destFitH:
00553 case destFitBH:
00554
00555 out->cvtUserToDev(0, dest->getTop(), &dx, &dy);
00556 scrollTo(0, dy);
00557 break;
00558 case destFitV:
00559 case destFitBV:
00560
00561 out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy);
00562 scrollTo(dx, 0);
00563 break;
00564 case destFitR:
00565
00566 out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
00567 scrollTo(dx, dy);
00568 break;
00569 }
00570 }
00571
00572
00573
00574
00575
00576 void XPDFCore::gotoNextPage(int inc, GBool top) {
00577 int pg;
00578
00579 if (!doc || doc->getNumPages() == 0) {
00580 return;
00581 }
00582 if (page < doc->getNumPages()) {
00583 if ((pg = page + inc) > doc->getNumPages()) {
00584 pg = doc->getNumPages();
00585 }
00586 displayPage(pg, zoom, rotate, top, gTrue);
00587 } else {
00588 XBell(display, 0);
00589 }
00590 }
00591
00592 void XPDFCore::gotoPrevPage(int dec, GBool top, GBool bottom) {
00593 int pg;
00594
00595 if (!doc || doc->getNumPages() == 0) {
00596 return;
00597 }
00598 if (page > 1) {
00599 if (!fullScreen && bottom) {
00600 scrollY = out->getPixmapHeight() - drawAreaHeight;
00601 if (scrollY < 0) {
00602 scrollY = 0;
00603 }
00604
00605 }
00606 if ((pg = page - dec) < 1) {
00607 pg = 1;
00608 }
00609 displayPage(pg, zoom, rotate, top, gTrue);
00610 } else {
00611 XBell(display, 0);
00612 }
00613 }
00614
00615 void XPDFCore::goForward() {
00616 if (historyFLen == 0) {
00617 XBell(display, 0);
00618 return;
00619 }
00620 if (++historyCur == xpdfHistorySize) {
00621 historyCur = 0;
00622 }
00623 --historyFLen;
00624 ++historyBLen;
00625 if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
00626 if (loadFile(history[historyCur].fileName) != errNone) {
00627 XBell(display, 0);
00628 return;
00629 }
00630 }
00631 displayPage(history[historyCur].page, zoom, rotate, gFalse, gFalse);
00632 }
00633
00634 void XPDFCore::goBackward() {
00635 if (historyBLen <= 1) {
00636 XBell(display, 0);
00637 return;
00638 }
00639 if (--historyCur < 0) {
00640 historyCur = xpdfHistorySize - 1;
00641 }
00642 --historyBLen;
00643 ++historyFLen;
00644 if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
00645 if (loadFile(history[historyCur].fileName) != errNone) {
00646 XBell(display, 0);
00647 return;
00648 }
00649 }
00650 displayPage(history[historyCur].page, zoom, rotate, gFalse, gFalse);
00651 }
00652
00653 void XPDFCore::scrollLeft(int nCols) {
00654 scrollTo(scrollX - nCols * 16, scrollY);
00655 }
00656
00657 void XPDFCore::scrollRight(int nCols) {
00658 scrollTo(scrollX + nCols * 16, scrollY);
00659 }
00660
00661 void XPDFCore::scrollUp(int nLines) {
00662 scrollTo(scrollX, scrollY - nLines * 16);
00663 }
00664
00665 void XPDFCore::scrollDown(int nLines) {
00666 scrollTo(scrollX, scrollY + nLines * 16);
00667 }
00668
00669 void XPDFCore::scrollPageUp() {
00670 if (scrollY == 0) {
00671 gotoPrevPage(1, gFalse, gTrue);
00672 } else {
00673 scrollTo(scrollX, scrollY - drawAreaHeight);
00674 }
00675 }
00676
00677 void XPDFCore::scrollPageDown() {
00678 if (scrollY >= out->getPixmapHeight() - drawAreaHeight) {
00679 gotoNextPage(1, gTrue);
00680 } else {
00681 scrollTo(scrollX, scrollY + drawAreaHeight);
00682 }
00683 }
00684
00685 void XPDFCore::scrollTo(int x, int y) {
00686 GBool needRedraw;
00687 int maxPos, pos;
00688
00689 needRedraw = gFalse;
00690
00691 maxPos = out ? out->getPixmapWidth() : 1;
00692 if (maxPos < drawAreaWidth) {
00693 maxPos = drawAreaWidth;
00694 }
00695 if (x < 0) {
00696 pos = 0;
00697 } else if (x > maxPos - drawAreaWidth) {
00698 pos = maxPos - drawAreaWidth;
00699 } else {
00700 pos = x;
00701 }
00702 if (scrollX != pos) {
00703 scrollX = pos;
00704 XmScrollBarSetValues(hScrollBar, scrollX, drawAreaWidth, 16,
00705 drawAreaWidth, False);
00706 needRedraw = gTrue;
00707 }
00708
00709 maxPos = out ? out->getPixmapHeight() : 1;
00710 if (maxPos < drawAreaHeight) {
00711 maxPos = drawAreaHeight;
00712 }
00713 if (y < 0) {
00714 pos = 0;
00715 } else if (y > maxPos - drawAreaHeight) {
00716 pos = maxPos - drawAreaHeight;
00717 } else {
00718 pos = y;
00719 }
00720 if (scrollY != pos) {
00721 scrollY = pos;
00722 XmScrollBarSetValues(vScrollBar, scrollY, drawAreaHeight, 16,
00723 drawAreaHeight, False);
00724 needRedraw = gTrue;
00725 }
00726
00727 if (needRedraw) {
00728 redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
00729 }
00730 }
00731
00732
00733
00734
00735
00736 void XPDFCore::setSelection(int newXMin, int newYMin,
00737 int newXMax, int newYMax) {
00738 Pixmap pixmap;
00739 int x, y;
00740 GBool needRedraw, needScroll;
00741 GBool moveLeft, moveRight, moveTop, moveBottom;
00742
00743 pixmap = out->getPixmap();
00744
00745
00746
00747 needRedraw = gFalse;
00748 if (selectXMin < selectXMax && selectYMin < selectYMax) {
00749 XFillRectangle(display, pixmap,
00750 selectGC, selectXMin, selectYMin,
00751 selectXMax - selectXMin, selectYMax - selectYMin);
00752 needRedraw = gTrue;
00753 }
00754
00755
00756 if (newXMin < newXMax && newYMin < newYMax) {
00757 XFillRectangle(display, pixmap,
00758 selectGC, newXMin, newYMin,
00759 newXMax - newXMin, newYMax - newYMin);
00760 needRedraw = gTrue;
00761 }
00762
00763
00764 moveLeft = newXMin != selectXMin;
00765 moveTop = newYMin != selectYMin;
00766 moveRight = newXMax != selectXMax;
00767 moveBottom = newYMax != selectYMax;
00768
00769
00770 if (needRedraw) {
00771 if (moveLeft) {
00772 redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin,
00773 (newYMin < selectYMin) ? newYMin : selectYMin,
00774 (newXMin > selectXMin) ? newXMin : selectXMin,
00775 (newYMax > selectYMax) ? newYMax : selectYMax);
00776 }
00777 if (moveRight) {
00778 redrawRectangle((newXMax < selectXMax) ? newXMax : selectXMax,
00779 (newYMin < selectYMin) ? newYMin : selectYMin,
00780 (newXMax > selectXMax) ? newXMax : selectXMax,
00781 (newYMax > selectYMax) ? newYMax : selectYMax);
00782 }
00783 if (moveTop) {
00784 redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin,
00785 (newYMin < selectYMin) ? newYMin : selectYMin,
00786 (newXMax > selectXMax) ? newXMax : selectXMax,
00787 (newYMin > selectYMin) ? newYMin : selectYMin);
00788 }
00789 if (moveBottom) {
00790 redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin,
00791 (newYMax < selectYMax) ? newYMax : selectYMax,
00792 (newXMax > selectXMax) ? newXMax : selectXMax,
00793 (newYMax > selectYMax) ? newYMax : selectYMax);
00794 }
00795 }
00796
00797
00798 selectXMin = newXMin;
00799 selectXMax = newXMax;
00800 selectYMin = newYMin;
00801 selectYMax = newYMax;
00802
00803
00804 if (fullScreen) {
00805 return;
00806 }
00807 needScroll = gFalse;
00808 x = scrollX;
00809 y = scrollY;
00810 if (moveLeft && selectXMin < x) {
00811 x = selectXMin;
00812 needScroll = gTrue;
00813 } else if (moveRight && selectXMax >= x + drawAreaWidth) {
00814 x = selectXMax - drawAreaWidth;
00815 needScroll = gTrue;
00816 } else if (moveLeft && selectXMin >= x + drawAreaWidth) {
00817 x = selectXMin - drawAreaWidth;
00818 needScroll = gTrue;
00819 } else if (moveRight && selectXMax < x) {
00820 x = selectXMax;
00821 needScroll = gTrue;
00822 }
00823 if (moveTop && selectYMin < y) {
00824 y = selectYMin;
00825 needScroll = gTrue;
00826 } else if (moveBottom && selectYMax >= y + drawAreaHeight) {
00827 y = selectYMax - drawAreaHeight;
00828 needScroll = gTrue;
00829 } else if (moveTop && selectYMin >= y + drawAreaHeight) {
00830 y = selectYMin - drawAreaHeight;
00831 needScroll = gTrue;
00832 } else if (moveBottom && selectYMax < y) {
00833 y = selectYMax;
00834 needScroll = gTrue;
00835 }
00836 if (needScroll) {
00837 scrollTo(x, y);
00838 }
00839 }
00840
00841 void XPDFCore::moveSelection(int mx, int my) {
00842 int xMin, yMin, xMax, yMax;
00843
00844
00845 if (mx < 0) {
00846 mx = 0;
00847 } else if (mx >= out->getPixmapWidth()) {
00848 mx = out->getPixmapWidth() - 1;
00849 }
00850 if (my < 0) {
00851 my = 0;
00852 } else if (my >= out->getPixmapHeight()) {
00853 my = out->getPixmapHeight() - 1;
00854 }
00855
00856
00857 if (lastDragLeft) {
00858 if (mx < selectXMax) {
00859 xMin = mx;
00860 xMax = selectXMax;
00861 } else {
00862 xMin = selectXMax;
00863 xMax = mx;
00864 lastDragLeft = gFalse;
00865 }
00866 } else {
00867 if (mx > selectXMin) {
00868 xMin = selectXMin;
00869 xMax = mx;
00870 } else {
00871 xMin = mx;
00872 xMax = selectXMin;
00873 lastDragLeft = gTrue;
00874 }
00875 }
00876 if (lastDragTop) {
00877 if (my < selectYMax) {
00878 yMin = my;
00879 yMax = selectYMax;
00880 } else {
00881 yMin = selectYMax;
00882 yMax = my;
00883 lastDragTop = gFalse;
00884 }
00885 } else {
00886 if (my > selectYMin) {
00887 yMin = selectYMin;
00888 yMax = my;
00889 } else {
00890 yMin = my;
00891 yMax = selectYMin;
00892 lastDragTop = gTrue;
00893 }
00894 }
00895
00896
00897 setSelection(xMin, yMin, xMax, yMax);
00898 }
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908 void XPDFCore::copySelection() {
00909 if (!doc->okToCopy()) {
00910 return;
00911 }
00912 if (currentSelection) {
00913 delete currentSelection;
00914 }
00915
00916 currentSelection = out->getText(selectXMin, selectYMin,
00917 selectXMax, selectYMax);
00918 currentSelectionOwner = this;
00919 XtOwnSelection(drawArea, XA_PRIMARY, XtLastTimestampProcessed(display),
00920 &convertSelectionCbk, NULL, NULL);
00921 }
00922
00923 Boolean XPDFCore::convertSelectionCbk(Widget widget, Atom *selection,
00924 Atom *target, Atom *type,
00925 XtPointer *value, unsigned long *length,
00926 int *format) {
00927 if (*target != XA_STRING) {
00928 return False;
00929 }
00930
00931 *value = XtNewString(currentSelection->getCString());
00932 *length = currentSelection->getLength();
00933 *type = XA_STRING;
00934 *format = 8;
00935 return True;
00936 }
00937
00938 GBool XPDFCore::getSelection(int *xMin, int *yMin, int *xMax, int *yMax) {
00939 if (selectXMin >= selectXMax || selectYMin >= selectYMax) {
00940 return gFalse;
00941 }
00942 *xMin = selectXMin;
00943 *yMin = selectYMin;
00944 *xMax = selectXMax;
00945 *yMax = selectYMax;
00946 return gTrue;
00947 }
00948
00949 GString *XPDFCore::extractText(int xMin, int yMin, int xMax, int yMax) {
00950 if (!doc->okToCopy()) {
00951 return NULL;
00952 }
00953 return out->getText(xMin, yMin, xMax, yMax);
00954 }
00955
00956 GString *XPDFCore::extractText(int pageNum,
00957 int xMin, int yMin, int xMax, int yMax) {
00958 TextOutputDev *textOut;
00959 GString *s;
00960
00961 if (!doc->okToCopy()) {
00962 return NULL;
00963 }
00964 textOut = new TextOutputDev(NULL, gFalse, gFalse);
00965 if (!textOut->isOk()) {
00966 delete textOut;
00967 return NULL;
00968 }
00969 doc->displayPage(textOut, pageNum, dpi, rotate, gFalse);
00970 s = textOut->getText(xMin, yMin, xMax, yMax);
00971 delete textOut;
00972 return s;
00973 }
00974
00975
00976
00977
00978
00979 void XPDFCore::doLink(int mx, int my) {
00980 double x, y;
00981 LinkAction *action;
00982
00983
00984 out->cvtDevToUser(mx, my, &x, &y);
00985 if ((action = doc->findLink(x, y))) {
00986 doAction(action);
00987 }
00988 }
00989
00990 void XPDFCore::doAction(LinkAction *action) {
00991 LinkActionKind kind;
00992 LinkDest *dest;
00993 GString *namedDest;
00994 char *s;
00995 GString *fileName, *fileName2;
00996 GString *cmd;
00997 GString *actionName;
00998 Object movieAnnot, obj1, obj2;
00999 GString *msg;
01000 int i;
01001
01002 switch (kind = action->getKind()) {
01003
01004
01005 case actionGoTo:
01006 case actionGoToR:
01007 if (kind == actionGoTo) {
01008 dest = NULL;
01009 namedDest = NULL;
01010 if ((dest = ((LinkGoTo *)action)->getDest())) {
01011 dest = dest->copy();
01012 } else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) {
01013 namedDest = namedDest->copy();
01014 }
01015 } else {
01016 dest = NULL;
01017 namedDest = NULL;
01018 if ((dest = ((LinkGoToR *)action)->getDest())) {
01019 dest = dest->copy();
01020 } else if ((namedDest = ((LinkGoToR *)action)->getNamedDest())) {
01021 namedDest = namedDest->copy();
01022 }
01023 s = ((LinkGoToR *)action)->getFileName()->getCString();
01024
01025 if (isAbsolutePath(s)) {
01026 fileName = new GString(s);
01027 } else {
01028 fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s);
01029 }
01030 if (loadFile(fileName) != errNone) {
01031 if (dest) {
01032 delete dest;
01033 }
01034 if (namedDest) {
01035 delete namedDest;
01036 }
01037 delete fileName;
01038 return;
01039 }
01040 delete fileName;
01041 }
01042 if (namedDest) {
01043 dest = doc->findDest(namedDest);
01044 delete namedDest;
01045 }
01046 if (dest) {
01047 displayDest(dest, zoom, rotate, gTrue);
01048 delete dest;
01049 } else {
01050 if (kind == actionGoToR) {
01051 displayPage(1, zoom, 0, gFalse, gTrue);
01052 }
01053 }
01054 break;
01055
01056
01057 case actionLaunch:
01058 fileName = ((LinkLaunch *)action)->getFileName();
01059 s = fileName->getCString();
01060 if (!strcmp(s + fileName->getLength() - 4, ".pdf") ||
01061 !strcmp(s + fileName->getLength() - 4, ".PDF")) {
01062
01063 if (isAbsolutePath(s)) {
01064 fileName = fileName->copy();
01065 } else {
01066 fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s);
01067 }
01068 if (loadFile(fileName) != errNone) {
01069 delete fileName;
01070 return;
01071 }
01072 delete fileName;
01073 displayPage(1, zoom, rotate, gFalse, gTrue);
01074 } else {
01075 fileName = fileName->copy();
01076 if (((LinkLaunch *)action)->getParams()) {
01077 fileName->append(' ');
01078 fileName->append(((LinkLaunch *)action)->getParams());
01079 }
01080 #ifdef VMS
01081 fileName->insert(0, "spawn/nowait ");
01082 #elif defined(__EMX__)
01083 fileName->insert(0, "start /min /n ");
01084 #else
01085 fileName->append(" &");
01086 #endif
01087 msg = new GString("About to execute the command:\n");
01088 msg->append(fileName);
01089 if (doQuestionDialog("Launching external application", msg)) {
01090 system(fileName->getCString());
01091 }
01092 delete fileName;
01093 delete msg;
01094 }
01095 break;
01096
01097
01098 case actionURI:
01099 if (!(cmd = globalParams->getURLCommand())) {
01100 error(-1, "No urlCommand defined in config file");
01101 break;
01102 }
01103 runCommand(cmd, ((LinkURI *)action)->getURI());
01104 break;
01105
01106
01107 case actionNamed:
01108 actionName = ((LinkNamed *)action)->getName();
01109 if (!actionName->cmp("NextPage")) {
01110 gotoNextPage(1, gTrue);
01111 } else if (!actionName->cmp("PrevPage")) {
01112 gotoPrevPage(1, gTrue, gFalse);
01113 } else if (!actionName->cmp("FirstPage")) {
01114 if (page != 1) {
01115 displayPage(1, zoom, rotate, gTrue, gTrue);
01116 }
01117 } else if (!actionName->cmp("LastPage")) {
01118 if (page != doc->getNumPages()) {
01119 displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue);
01120 }
01121 } else if (!actionName->cmp("GoBack")) {
01122 goBackward();
01123 } else if (!actionName->cmp("GoForward")) {
01124 goForward();
01125 } else if (!actionName->cmp("Quit")) {
01126 if (actionCbk) {
01127 (*actionCbk)(actionCbkData, "Quit");
01128 }
01129 } else {
01130 error(-1, "Unknown named action: '%s'", actionName->getCString());
01131 }
01132 break;
01133
01134
01135 case actionMovie:
01136 if (!(cmd = globalParams->getMovieCommand())) {
01137 error(-1, "No movieCommand defined in config file");
01138 break;
01139 }
01140 if (((LinkMovie *)action)->hasAnnotRef()) {
01141 doc->getXRef()->fetch(((LinkMovie *)action)->getAnnotRef()->num,
01142 ((LinkMovie *)action)->getAnnotRef()->gen,
01143 &movieAnnot);
01144 } else {
01145 doc->getCatalog()->getPage(page)->getAnnots(&obj1);
01146 if (obj1.isArray()) {
01147 for (i = 0; i < obj1.arrayGetLength(); ++i) {
01148 if (obj1.arrayGet(i, &movieAnnot)->isDict()) {
01149 if (movieAnnot.dictLookup("Subtype", &obj2)->isName("Movie")) {
01150 obj2.free();
01151 break;
01152 }
01153 obj2.free();
01154 }
01155 movieAnnot.free();
01156 }
01157 obj1.free();
01158 }
01159 }
01160 if (movieAnnot.isDict()) {
01161 if (movieAnnot.dictLookup("Movie", &obj1)->isDict()) {
01162 if (obj1.dictLookup("F", &obj2)) {
01163 if ((fileName = LinkAction::getFileSpecName(&obj2))) {
01164 if (!isAbsolutePath(fileName->getCString())) {
01165 fileName2 = appendToPath(
01166 grabPath(doc->getFileName()->getCString()),
01167 fileName->getCString());
01168 delete fileName;
01169 fileName = fileName2;
01170 }
01171 runCommand(cmd, fileName);
01172 delete fileName;
01173 }
01174 obj2.free();
01175 }
01176 obj1.free();
01177 }
01178 }
01179 movieAnnot.free();
01180 break;
01181
01182
01183 case actionUnknown:
01184 error(-1, "Unknown link action type: '%s'",
01185 ((LinkUnknown *)action)->getAction()->getCString());
01186 break;
01187 }
01188 }
01189
01190
01191
01192 void XPDFCore::runCommand(GString *cmdFmt, GString *arg) {
01193 GString *cmd;
01194 char *s;
01195 int i;
01196
01197 if ((s = strstr(cmdFmt->getCString(), "%s"))) {
01198 cmd = arg->copy();
01199
01200
01201 i = 0;
01202 while (i < cmd->getLength()) {
01203 if (cmd->getChar(i) == '"') {
01204 cmd->del(i);
01205 cmd->insert(i, "%22");
01206 i += 3;
01207 } else if (cmd->getChar(i) == '\'') {
01208 cmd->del(i);
01209 cmd->insert(i, "%27");
01210 i += 3;
01211 } else {
01212 ++i;
01213 }
01214 }
01215 cmd->insert(0, cmdFmt->getCString(),
01216 s - cmdFmt->getCString());
01217 cmd->append(s + 2);
01218 } else {
01219 cmd = cmdFmt->copy();
01220 }
01221 #ifdef VMS
01222 cmd->insert(0, "spawn/nowait ");
01223 #elif defined(__EMX__)
01224 cmd->insert(0, "start /min /n ");
01225 #else
01226 cmd->append(" &");
01227 #endif
01228 system(cmd->getCString());
01229 delete cmd;
01230 }
01231
01232
01233
01234
01235
01236
01237 void XPDFCore::find(char *s) {
01238 Unicode *u;
01239 TextOutputDev *textOut;
01240 int xMin, yMin, xMax, yMax;
01241 double xMin1, yMin1, xMax1, yMax1;
01242 int pg;
01243 GBool top;
01244 int len, i;
01245
01246
01247 if (!s[0]) {
01248 XBell(display, 0);
01249 return;
01250 }
01251
01252
01253 setCursor(busyCursor);
01254
01255
01256 #if 1 //~ should do something more intelligent here
01257 len = strlen(s);
01258 u = (Unicode *)gmalloc(len * sizeof(Unicode));
01259 for (i = 0; i < len; ++i) {
01260 u[i] = (Unicode)(s[i] & 0xff);
01261 }
01262 #endif
01263
01264
01265 xMin = yMin = xMax = yMax = 0;
01266 if (selectXMin < selectXMax && selectYMin < selectYMax) {
01267 xMin = selectXMax;
01268 yMin = (selectYMin + selectYMax) / 2;
01269 top = gFalse;
01270 } else {
01271 top = gTrue;
01272 }
01273 if (out->findText(u, len, top, gTrue, &xMin, &yMin, &xMax, &yMax)) {
01274 goto found;
01275 }
01276
01277
01278 textOut = new TextOutputDev(NULL, gFalse, gFalse);
01279 if (!textOut->isOk()) {
01280 delete textOut;
01281 goto done;
01282 }
01283 for (pg = page+1; pg <= doc->getNumPages(); ++pg) {
01284 doc->displayPage(textOut, pg, 72, 0, gFalse);
01285 if (textOut->findText(u, len, gTrue, gTrue,
01286 &xMin1, &yMin1, &xMax1, &yMax1)) {
01287 goto foundPage;
01288 }
01289 }
01290
01291
01292 for (pg = 1; pg < page; ++pg) {
01293 doc->displayPage(textOut, pg, 72, 0, gFalse);
01294 if (textOut->findText(u, len, gTrue, gTrue,
01295 &xMin1, &yMin1, &xMax1, &yMax1)) {
01296 goto foundPage;
01297 }
01298 }
01299 delete textOut;
01300
01301
01302 if (selectXMin < selectXMax && selectYMin < selectYMax) {
01303 xMax = selectXMin;
01304 yMax = (selectYMin + selectYMax) / 2;
01305 if (out->findText(u, len, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) {
01306 goto found;
01307 }
01308 }
01309
01310
01311 XBell(display, 0);
01312 goto done;
01313
01314
01315 foundPage:
01316 delete textOut;
01317 displayPage(pg, zoom, rotate, gTrue, gTrue);
01318 if (!out->findText(u, len, gTrue, gTrue, &xMin, &yMin, &xMax, &yMax)) {
01319
01320 goto done;
01321 }
01322
01323
01324 found:
01325 setSelection(xMin, yMin, xMax, yMax);
01326 #ifndef NO_TEXT_SELECT
01327 copySelection();
01328 #endif
01329
01330 done:
01331 gfree(u);
01332
01333
01334 setCursor(None);
01335 }
01336
01337
01338
01339
01340
01341 void XPDFCore::setBusyCursor(GBool busy) {
01342 setCursor(busy ? busyCursor : None);
01343 }
01344
01345 void XPDFCore::takeFocus() {
01346 XmProcessTraversal(drawArea, XmTRAVERSE_CURRENT);
01347 }
01348
01349
01350
01351
01352
01353 void XPDFCore::initWindow() {
01354 Arg args[20];
01355 int n;
01356
01357
01358 busyCursor = XCreateFontCursor(display, XC_watch);
01359 linkCursor = XCreateFontCursor(display, XC_hand2);
01360 selectCursor = XCreateFontCursor(display, XC_cross);
01361 currentCursor = 0;
01362
01363
01364 n = 0;
01365 XtSetArg(args[n], XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++n;
01366 XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n;
01367 scrolledWin = XmCreateScrolledWindow(parentWidget, "scroll", args, n);
01368 XtManageChild(scrolledWin);
01369 n = 0;
01370 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
01371 XtSetArg(args[n], XmNminimum, 0); ++n;
01372 XtSetArg(args[n], XmNmaximum, 1); ++n;
01373 XtSetArg(args[n], XmNsliderSize, 1); ++n;
01374 XtSetArg(args[n], XmNvalue, 0); ++n;
01375 XtSetArg(args[n], XmNincrement, 1); ++n;
01376 XtSetArg(args[n], XmNpageIncrement, 1); ++n;
01377 hScrollBar = XmCreateScrollBar(scrolledWin, "hScrollBar", args, n);
01378 XtManageChild(hScrollBar);
01379 XtAddCallback(hScrollBar, XmNvalueChangedCallback,
01380 &hScrollChangeCbk, (XtPointer)this);
01381 #ifndef DISABLE_SMOOTH_SCROLL
01382 XtAddCallback(hScrollBar, XmNdragCallback,
01383 &hScrollDragCbk, (XtPointer)this);
01384 #endif
01385 n = 0;
01386 XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n;
01387 XtSetArg(args[n], XmNminimum, 0); ++n;
01388 XtSetArg(args[n], XmNmaximum, 1); ++n;
01389 XtSetArg(args[n], XmNsliderSize, 1); ++n;
01390 XtSetArg(args[n], XmNvalue, 0); ++n;
01391 XtSetArg(args[n], XmNincrement, 1); ++n;
01392 XtSetArg(args[n], XmNpageIncrement, 1); ++n;
01393 vScrollBar = XmCreateScrollBar(scrolledWin, "vScrollBar", args, n);
01394 XtManageChild(vScrollBar);
01395 XtAddCallback(vScrollBar, XmNvalueChangedCallback,
01396 &vScrollChangeCbk, (XtPointer)this);
01397 #ifndef DISABLE_SMOOTH_SCROLL
01398 XtAddCallback(vScrollBar, XmNdragCallback,
01399 &vScrollDragCbk, (XtPointer)this);
01400 #endif
01401
01402
01403 n = 0;
01404 XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); ++n;
01405 XtSetArg(args[n], XmNmarginWidth, 0); ++n;
01406 XtSetArg(args[n], XmNmarginHeight, 0); ++n;
01407 if (fullScreen) {
01408 XtSetArg(args[n], XmNshadowThickness, 0); ++n;
01409 }
01410 drawAreaFrame = XmCreateFrame(scrolledWin, "drawAreaFrame", args, n);
01411 XtManageChild(drawAreaFrame);
01412 n = 0;
01413 XtSetArg(args[n], XmNresizePolicy, XmRESIZE_ANY); ++n;
01414 XtSetArg(args[n], XmNbackground, paperColor); ++n;
01415 XtSetArg(args[n], XmNwidth, 700); ++n;
01416 XtSetArg(args[n], XmNheight, 500); ++n;
01417 drawArea = XmCreateDrawingArea(drawAreaFrame, "drawArea", args, n);
01418 XtManageChild(drawArea);
01419 XtAddCallback(drawArea, XmNresizeCallback, &resizeCbk, (XtPointer)this);
01420 XtAddCallback(drawArea, XmNexposeCallback, &redrawCbk, (XtPointer)this);
01421 XtAddCallback(drawArea, XmNinputCallback, &inputCbk, (XtPointer)this);
01422 resizeCbk(drawArea, this, NULL);
01423
01424
01425 XtOverrideTranslations(drawArea, XtParseTranslationTable(
01426 "<Btn1Down>:DrawingAreaInput()\n"
01427 "<Btn1Up>:DrawingAreaInput()\n"
01428 "<Btn1Motion>:DrawingAreaInput()\n"
01429 "<Motion>:DrawingAreaInput()"));
01430
01431
01432 drawAreaGC = NULL;
01433 selectGC = NULL;
01434 highlightGC = NULL;
01435 }
01436
01437 void XPDFCore::hScrollChangeCbk(Widget widget, XtPointer ptr,
01438 XtPointer callData) {
01439 XPDFCore *core = (XPDFCore *)ptr;
01440 XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
01441
01442 core->scrollTo(data->value, core->scrollY);
01443 }
01444
01445 void XPDFCore::hScrollDragCbk(Widget widget, XtPointer ptr,
01446 XtPointer callData) {
01447 XPDFCore *core = (XPDFCore *)ptr;
01448 XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
01449
01450 core->scrollTo(data->value, core->scrollY);
01451 }
01452
01453 void XPDFCore::vScrollChangeCbk(Widget widget, XtPointer ptr,
01454 XtPointer callData) {
01455 XPDFCore *core = (XPDFCore *)ptr;
01456 XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
01457
01458 core->scrollTo(core->scrollX, data->value);
01459 }
01460
01461 void XPDFCore::vScrollDragCbk(Widget widget, XtPointer ptr,
01462 XtPointer callData) {
01463 XPDFCore *core = (XPDFCore *)ptr;
01464 XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
01465
01466 core->scrollTo(core->scrollX, data->value);
01467 }
01468
01469 void XPDFCore::resizeCbk(Widget widget, XtPointer ptr, XtPointer callData) {
01470 XPDFCore *core = (XPDFCore *)ptr;
01471 Arg args[2];
01472 int n;
01473 Dimension w, h;
01474
01475 n = 0;
01476 XtSetArg(args[n], XmNwidth, &w); ++n;
01477 XtSetArg(args[n], XmNheight, &h); ++n;
01478 XtGetValues(core->drawArea, args, n);
01479 core->drawAreaWidth = (int)w;
01480 core->drawAreaHeight = (int)h;
01481 if (core->page >= 0 &&
01482 (core->zoom == zoomPage || core->zoom == zoomWidth)) {
01483 core->displayPage(core->page, core->zoom, core->rotate,
01484 gFalse, gFalse);
01485 } else {
01486 core->updateScrollBars();
01487 }
01488 }
01489
01490 void XPDFCore::redrawCbk(Widget widget, XtPointer ptr, XtPointer callData) {
01491 XPDFCore *core = (XPDFCore *)ptr;
01492 XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData;
01493 int x, y, w, h;
01494
01495 if (data->reason == XmCR_EXPOSE) {
01496 x = core->scrollX + data->event->xexpose.x;
01497 y = core->scrollY + data->event->xexpose.y;
01498 w = data->event->xexpose.width;
01499 h = data->event->xexpose.height;
01500 } else {
01501 x = core->scrollX;
01502 y = core->scrollY;
01503 w = core->drawAreaWidth;
01504 h = core->drawAreaHeight;
01505 }
01506 core->redrawRectangle(x, y, w, h);
01507 }
01508
01509 void XPDFCore::outputDevRedrawCbk(void *data) {
01510 XPDFCore *core = (XPDFCore *)data;
01511
01512 core->redrawRectangle(core->scrollX, core->scrollY,
01513 core->drawAreaWidth, core->drawAreaHeight);
01514 }
01515
01516 void XPDFCore::inputCbk(Widget widget, XtPointer ptr, XtPointer callData) {
01517 XPDFCore *core = (XPDFCore *)ptr;
01518 XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData;
01519 LinkAction *action;
01520 int mx, my;
01521 double x, y;
01522 char *s;
01523 KeySym key;
01524 char buf[20];
01525 int n;
01526
01527 switch (data->event->type) {
01528 case ButtonPress:
01529 if (data->event->xbutton.button == 1) {
01530 core->takeFocus();
01531 if (core->doc && core->doc->getNumPages() > 0) {
01532 if (core->selectEnabled) {
01533 mx = core->scrollX + data->event->xbutton.x;
01534 my = core->scrollY + data->event->xbutton.y;
01535 core->setSelection(mx, my, mx, my);
01536 core->setCursor(core->selectCursor);
01537 core->dragging = gTrue;
01538 }
01539 }
01540 } else if (data->event->xbutton.button == 2) {
01541 if (!core->fullScreen) {
01542 core->panning = gTrue;
01543 core->panMX = data->event->xbutton.x;
01544 core->panMY = data->event->xbutton.y;
01545 }
01546 } else if (data->event->xbutton.button == 4) {
01547 if (core->fullScreen) {
01548 core->gotoPrevPage(1, gTrue, gFalse);
01549 } else if (core->scrollY == 0) {
01550 core->gotoPrevPage(1, gFalse, gTrue);
01551 } else {
01552 core->scrollUp(1);
01553 }
01554 } else if (data->event->xbutton.button == 5) {
01555 if (core->fullScreen ||
01556 core->scrollY >=
01557 core->out->getPixmapHeight() - core->drawAreaHeight) {
01558 core->gotoNextPage(1, gTrue);
01559 } else {
01560 core->scrollDown(1);
01561 }
01562 } else if (data->event->xbutton.button == 6) {
01563 if (!core->fullScreen) {
01564 core->scrollRight(1);
01565 }
01566 } else if (data->event->xbutton.button == 7) {
01567 if (!core->fullScreen) {
01568 core->scrollLeft(1);
01569 }
01570 } else {
01571 if (*core->mouseCbk) {
01572 (*core->mouseCbk)(core->mouseCbkData, data->event);
01573 }
01574 }
01575 break;
01576 case ButtonRelease:
01577 if (data->event->xbutton.button == 1) {
01578 if (core->doc && core->doc->getNumPages() > 0) {
01579 mx = core->scrollX + data->event->xbutton.x;
01580 my = core->scrollY + data->event->xbutton.y;
01581 if (core->dragging) {
01582 core->dragging = gFalse;
01583 core->setCursor(None);
01584 core->moveSelection(mx, my);
01585 #ifndef NO_TEXT_SELECT
01586 if (core->selectXMin != core->selectXMax &&
01587 core->selectYMin != core->selectYMax) {
01588 if (core->doc->okToCopy()) {
01589 core->copySelection();
01590 } else {
01591 error(-1, "Copying of text from this document is not allowed.");
01592 }
01593 }
01594 #endif
01595 }
01596 if (core->hyperlinksEnabled) {
01597 if (core->selectXMin == core->selectXMax ||
01598 core->selectYMin == core->selectYMax) {
01599 core->doLink(mx, my);
01600 }
01601 }
01602 }
01603 } else if (data->event->xbutton.button == 2) {
01604 core->panning = gFalse;
01605 } else {
01606 if (*core->mouseCbk) {
01607 (*core->mouseCbk)(core->mouseCbkData, data->event);
01608 }
01609 }
01610 break;
01611 case MotionNotify:
01612 if (core->doc && core->doc->getNumPages() > 0) {
01613 mx = core->scrollX + data->event->xbutton.x;
01614 my = core->scrollY + data->event->xbutton.y;
01615 if (core->dragging) {
01616 core->moveSelection(mx, my);
01617 } else if (core->hyperlinksEnabled) {
01618 core->out->cvtDevToUser(mx, my, &x, &y);
01619 if ((action = core->doc->findLink(x, y))) {
01620 core->setCursor(core->linkCursor);
01621 if (action != core->linkAction) {
01622 core->linkAction = action;
01623 if (core->updateCbk) {
01624 s = "";
01625 switch (action->getKind()) {
01626 case actionGoTo:
01627 s = "[internal link]";
01628 break;
01629 case actionGoToR:
01630 s = ((LinkGoToR *)action)->getFileName()->getCString();
01631 break;
01632 case actionLaunch:
01633 s = ((LinkLaunch *)action)->getFileName()->getCString();
01634 break;
01635 case actionURI:
01636 s = ((LinkURI *)action)->getURI()->getCString();
01637 break;
01638 case actionNamed:
01639 s = ((LinkNamed *)action)->getName()->getCString();
01640 break;
01641 case actionMovie:
01642 s = "[movie]";
01643 break;
01644 case actionUnknown:
01645 s = "[unknown link]";
01646 break;
01647 }
01648 (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, s);
01649 }
01650 }
01651 } else {
01652 core->setCursor(None);
01653 if (core->linkAction) {
01654 core->linkAction = NULL;
01655 if (core->updateCbk) {
01656 (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, "");
01657 }
01658 }
01659 }
01660 }
01661 }
01662 if (core->panning) {
01663 core->scrollTo(core->scrollX - (data->event->xbutton.x - core->panMX),
01664 core->scrollY - (data->event->xbutton.y - core->panMY));
01665 core->panMX = data->event->xbutton.x;
01666 core->panMY = data->event->xbutton.y;
01667 }
01668 break;
01669 case KeyPress:
01670 n = XLookupString(&data->event->xkey, buf, sizeof(buf) - 1,
01671 &key, NULL);
01672 core->keyPress(buf, key, data->event->xkey.state);
01673 break;
01674 }
01675 }
01676
01677 void XPDFCore::keyPress(char *s, KeySym key, Guint modifiers) {
01678 switch (key) {
01679 case XK_Home:
01680 case XK_KP_Home:
01681 if (modifiers & ControlMask) {
01682 displayPage(1, zoom, rotate, gTrue, gTrue);
01683 } else if (!fullScreen) {
01684 scrollTo(0, 0);
01685 }
01686 return;
01687 case XK_End:
01688 case XK_KP_End:
01689 if (modifiers & ControlMask) {
01690 displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue);
01691 } else if (!fullScreen) {
01692 scrollTo(out->getPixmapWidth() - drawAreaWidth,
01693 out->getPixmapHeight() - drawAreaHeight);
01694 }
01695 return;
01696 case XK_Page_Up:
01697 case XK_KP_Page_Up:
01698 if (fullScreen) {
01699 gotoPrevPage(1, gTrue, gFalse);
01700 } else {
01701 scrollPageUp();
01702 }
01703 return;
01704 case XK_Page_Down:
01705 case XK_KP_Page_Down:
01706 if (fullScreen) {
01707 gotoNextPage(1, gTrue);
01708 } else {
01709 scrollPageDown();
01710 }
01711 return;
01712 case XK_Left:
01713 case XK_KP_Left:
01714 if (!fullScreen) {
01715 scrollLeft();
01716 }
01717 return;
01718 case XK_Right:
01719 case XK_KP_Right:
01720 if (!fullScreen) {
01721 scrollRight();
01722 }
01723 return;
01724 case XK_Up:
01725 case XK_KP_Up:
01726 if (!fullScreen) {
01727 scrollUp();
01728 }
01729 return;
01730 case XK_Down:
01731 case XK_KP_Down:
01732 if (!fullScreen) {
01733 scrollDown();
01734 }
01735 return;
01736 }
01737
01738 if (*keyPressCbk) {
01739 (*keyPressCbk)(keyPressCbkData, s, key, modifiers);
01740 }
01741 }
01742
01743 void XPDFCore::redrawRectangle(int x, int y, int w, int h) {
01744 XGCValues gcValues;
01745 Window drawAreaWin;
01746
01747
01748 if (x < scrollX) {
01749 w -= scrollX - x;
01750 x = scrollX;
01751 }
01752 if (x + w > scrollX + drawAreaWidth) {
01753 w = scrollX + drawAreaWidth - x;
01754 }
01755 if (y < scrollY) {
01756 h -= scrollY - y;
01757 y = scrollY;
01758 }
01759 if (y + h > scrollY + drawAreaHeight) {
01760 h = scrollY + drawAreaHeight - y;
01761 }
01762
01763
01764 drawAreaWin = XtWindow(drawArea);
01765 if (!drawAreaGC) {
01766 gcValues.foreground = paperColor;
01767 drawAreaGC = XCreateGC(display, drawAreaWin, GCForeground, &gcValues);
01768 }
01769
01770
01771 if (x + w > out->getPixmapWidth()) {
01772 XFillRectangle(display, drawAreaWin, drawAreaGC,
01773 out->getPixmapWidth() - scrollX, y - scrollY,
01774 x + w - out->getPixmapWidth(), h);
01775 w = out->getPixmapWidth() - x;
01776 }
01777 if (y + h > out->getPixmapHeight()) {
01778 XFillRectangle(display, drawAreaWin, drawAreaGC,
01779 x - scrollX, out->getPixmapHeight() - scrollY,
01780 w, y + h - out->getPixmapHeight());
01781 h = out->getPixmapHeight() - y;
01782 }
01783
01784
01785 if (out->getPixmapWidth() > 0) {
01786 XCopyArea(display, out->getPixmap(), drawAreaWin, drawAreaGC,
01787 x, y, w, h, x - scrollX, y - scrollY);
01788 }
01789 }
01790
01791 void XPDFCore::updateScrollBars() {
01792 Arg args[20];
01793 int n;
01794 int maxPos;
01795
01796 maxPos = out ? out->getPixmapWidth() : 1;
01797 if (maxPos < drawAreaWidth) {
01798 maxPos = drawAreaWidth;
01799 }
01800 if (scrollX > maxPos - drawAreaWidth) {
01801 scrollX = maxPos - drawAreaWidth;
01802 }
01803 n = 0;
01804 XtSetArg(args[n], XmNvalue, scrollX); ++n;
01805 XtSetArg(args[n], XmNmaximum, maxPos); ++n;
01806 XtSetArg(args[n], XmNsliderSize, drawAreaWidth); ++n;
01807 XtSetArg(args[n], XmNincrement, 16); ++n;
01808 XtSetArg(args[n], XmNpageIncrement, drawAreaWidth); ++n;
01809 XtSetValues(hScrollBar, args, n);
01810
01811 maxPos = out ? out->getPixmapHeight() : 1;
01812 if (maxPos < drawAreaHeight) {
01813 maxPos = drawAreaHeight;
01814 }
01815 if (scrollY > maxPos - drawAreaHeight) {
01816 scrollY = maxPos - drawAreaHeight;
01817 }
01818 n = 0;
01819 XtSetArg(args[n], XmNvalue, scrollY); ++n;
01820 XtSetArg(args[n], XmNmaximum, maxPos); ++n;
01821 XtSetArg(args[n], XmNsliderSize, drawAreaHeight); ++n;
01822 XtSetArg(args[n], XmNincrement, 16); ++n;
01823 XtSetArg(args[n], XmNpageIncrement, drawAreaHeight); ++n;
01824 XtSetValues(vScrollBar, args, n);
01825 }
01826
01827 void XPDFCore::setCursor(Cursor cursor) {
01828 Window topWin;
01829
01830 if (cursor == currentCursor) {
01831 return;
01832 }
01833 if (!(topWin = XtWindow(shell))) {
01834 return;
01835 }
01836 if (cursor == None) {
01837 XUndefineCursor(display, topWin);
01838 } else {
01839 XDefineCursor(display, topWin, cursor);
01840 }
01841 XFlush(display);
01842 currentCursor = cursor;
01843 }
01844
01845 GBool XPDFCore::doQuestionDialog(char *title, GString *msg) {
01846 return doDialog(XmDIALOG_QUESTION, gTrue, title, msg);
01847 }
01848
01849 void XPDFCore::doInfoDialog(char *title, GString *msg) {
01850 doDialog(XmDIALOG_INFORMATION, gFalse, title, msg);
01851 }
01852
01853 void XPDFCore::doErrorDialog(char *title, GString *msg) {
01854 doDialog(XmDIALOG_ERROR, gFalse, title, msg);
01855 }
01856
01857 GBool XPDFCore::doDialog(int type, GBool hasCancel,
01858 char *title, GString *msg) {
01859 Widget dialog;
01860 XtAppContext appContext;
01861 Arg args[20];
01862 int n;
01863 XmString s1, s2;
01864 XEvent event;
01865
01866 n = 0;
01867 XtSetArg(args[n], XmNdialogType, type); ++n;
01868 XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n;
01869 s1 = XmStringCreateLocalized(title);
01870 XtSetArg(args[n], XmNdialogTitle, s1); ++n;
01871 s2 = XmStringCreateLocalized(msg->getCString());
01872 XtSetArg(args[n], XmNmessageString, s2); ++n;
01873 dialog = XmCreateMessageDialog(drawArea, "questionDialog", args, n);
01874 XmStringFree(s1);
01875 XmStringFree(s2);
01876 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
01877 XtAddCallback(dialog, XmNokCallback,
01878 &dialogOkCbk, (XtPointer)this);
01879 if (hasCancel) {
01880 XtAddCallback(dialog, XmNcancelCallback,
01881 &dialogCancelCbk, (XtPointer)this);
01882 } else {
01883 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
01884 }
01885
01886 XtManageChild(dialog);
01887
01888 appContext = XtWidgetToApplicationContext(dialog);
01889 dialogDone = 0;
01890 do {
01891 XtAppNextEvent(appContext, &event);
01892 XtDispatchEvent(&event);
01893 } while (!dialogDone);
01894
01895 XtUnmanageChild(dialog);
01896 XtDestroyWidget(dialog);
01897
01898 return dialogDone > 0;
01899 }
01900
01901 void XPDFCore::dialogOkCbk(Widget widget, XtPointer ptr,
01902 XtPointer callData) {
01903 XPDFCore *core = (XPDFCore *)ptr;
01904
01905 core->dialogDone = 1;
01906 }
01907
01908 void XPDFCore::dialogCancelCbk(Widget widget, XtPointer ptr,
01909 XtPointer callData) {
01910 XPDFCore *core = (XPDFCore *)ptr;
01911
01912 core->dialogDone = -1;
01913 }