diff options
author | Michele Calgaro <michele.calgaro@yahoo.it> | 2021-05-23 20:48:35 +0900 |
---|---|---|
committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2021-05-29 15:16:28 +0900 |
commit | 8b78a8791bc539bcffe7159f9d9714d577cb3d7d (patch) | |
tree | 1328291f966f19a22d7b13657d3f01a588eb1083 /filters/kword/pdf/xpdf/xpdf/XPDFCore.cpp | |
parent | 95834e2bdc5e01ae1bd21ac0dfa4fa1d2417fae9 (diff) | |
download | koffice-8b78a8791bc539bcffe7159f9d9714d577cb3d7d.tar.gz koffice-8b78a8791bc539bcffe7159f9d9714d577cb3d7d.zip |
Renaming of files in preparation for code style tools.
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'filters/kword/pdf/xpdf/xpdf/XPDFCore.cpp')
-rw-r--r-- | filters/kword/pdf/xpdf/xpdf/XPDFCore.cpp | 1913 |
1 files changed, 1913 insertions, 0 deletions
diff --git a/filters/kword/pdf/xpdf/xpdf/XPDFCore.cpp b/filters/kword/pdf/xpdf/xpdf/XPDFCore.cpp new file mode 100644 index 000000000..517b99700 --- /dev/null +++ b/filters/kword/pdf/xpdf/xpdf/XPDFCore.cpp @@ -0,0 +1,1913 @@ +//======================================================================== +// +// XPDFCore.cpp +// +// Copyright 2002 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <X11/keysym.h> +#include <X11/cursorfont.h> +#include "gmem.h" +#include "GString.h" +#include "GList.h" +#include "Error.h" +#include "GlobalParams.h" +#include "PDFDoc.h" +#include "ErrorCodes.h" +#include "GfxState.h" +#include "PSOutputDev.h" +#include "TextOutputDev.h" +#include "XPixmapOutputDev.h" +#include "XPDFCore.h" + +// these macro defns conflict with xpdf's Object class +#ifdef LESSTIF_VERSION +#undef XtDisplay +#undef XtScreen +#undef XtWindow +#undef XtParent +#undef XtIsRealized +#endif + +// hack around old X includes which are missing these symbols +#ifndef XK_Page_Up +#define XK_Page_Up 0xFF55 +#endif +#ifndef XK_Page_Down +#define XK_Page_Down 0xFF56 +#endif +#ifndef XK_KP_Home +#define XK_KP_Home 0xFF95 +#endif +#ifndef XK_KP_Left +#define XK_KP_Left 0xFF96 +#endif +#ifndef XK_KP_Up +#define XK_KP_Up 0xFF97 +#endif +#ifndef XK_KP_Right +#define XK_KP_Right 0xFF98 +#endif +#ifndef XK_KP_Down +#define XK_KP_Down 0xFF99 +#endif +#ifndef XK_KP_Prior +#define XK_KP_Prior 0xFF9A +#endif +#ifndef XK_KP_Page_Up +#define XK_KP_Page_Up 0xFF9A +#endif +#ifndef XK_KP_Next +#define XK_KP_Next 0xFF9B +#endif +#ifndef XK_KP_Page_Down +#define XK_KP_Page_Down 0xFF9B +#endif +#ifndef XK_KP_End +#define XK_KP_End 0xFF9C +#endif +#ifndef XK_KP_Begin +#define XK_KP_Begin 0xFF9D +#endif +#ifndef XK_KP_Insert +#define XK_KP_Insert 0xFF9E +#endif +#ifndef XK_KP_Delete +#define XK_KP_Delete 0xFF9F +#endif + +//------------------------------------------------------------------------ + +#define highlightNone 0 +#define highlightNormal 1 +#define highlightSelected 2 + +//------------------------------------------------------------------------ + +static int zoomDPI[maxZoom - minZoom + 1] = { + 29, 35, 42, 50, 60, + 72, + 86, 104, 124, 149, 179 +}; + +//------------------------------------------------------------------------ + +GString *XPDFCore::currentSelection = NULL; +XPDFCore *XPDFCore::currentSelectionOwner = NULL; + +//------------------------------------------------------------------------ +// XPDFCore +//------------------------------------------------------------------------ + +XPDFCore::XPDFCore(Widget shellA, Widget parentWidgetA, + Gulong paperColorA, GBool fullScreenA, GBool reverseVideo, + GBool installCmap, int rgbCubeSize) { + GString *initialZoom; + int i; + + shell = shellA; + parentWidget = parentWidgetA; + display = XtDisplay(parentWidget); + screenNum = XScreenNumberOfScreen(XtScreen(parentWidget)); + + paperColor = paperColorA; + fullScreen = fullScreenA; + + // for some reason, querying XmNvisual doesn't work (even if done + // after the window is mapped) + visual = DefaultVisual(display, screenNum); + XtVaGetValues(shell, XmNcolormap, &colormap, NULL); + + scrolledWin = NULL; + hScrollBar = NULL; + vScrollBar = NULL; + drawAreaFrame = NULL; + drawArea = NULL; + out = NULL; + + doc = NULL; + page = 0; + rotate = 0; + + // get the initial zoom value + initialZoom = globalParams->getInitialZoom(); + if (!initialZoom->cmp("page")) { + zoom = zoomPage; + } else if (!initialZoom->cmp("width")) { + zoom = zoomWidth; + } else { + zoom = atoi(initialZoom->getCString()); + if (zoom < minZoom) { + zoom = minZoom; + } else if (zoom > maxZoom) { + zoom = maxZoom; + } + } + + scrollX = 0; + scrollY = 0; + linkAction = NULL; + selectXMin = selectXMax = 0; + selectYMin = selectYMax = 0; + dragging = gFalse; + lastDragLeft = lastDragTop = gTrue; + + panning = gFalse; + + + updateCbk = NULL; + actionCbk = NULL; + keyPressCbk = NULL; + mouseCbk = NULL; + reqPasswordCbk = NULL; + + // no history yet + historyCur = xpdfHistorySize - 1; + historyBLen = historyFLen = 0; + for (i = 0; i < xpdfHistorySize; ++i) { + history[i].fileName = NULL; + } + + // optional features default to on + hyperlinksEnabled = gTrue; + selectEnabled = gTrue; + + // do X-specific initialization and create the widgets + initWindow(); + + // create the OutputDev + out = new XPixmapOutputDev(display, screenNum, visual, colormap, + reverseVideo, paperColor, + installCmap, rgbCubeSize, gTrue, + &outputDevRedrawCbk, this); + out->startDoc(NULL); +} + +XPDFCore::~XPDFCore() { + int i; + + if (out) { + delete out; + } + if (doc) { + delete doc; + } + if (currentSelectionOwner == this && currentSelection) { + delete currentSelection; + currentSelection = NULL; + currentSelectionOwner = NULL; + } + for (i = 0; i < xpdfHistorySize; ++i) { + if (history[i].fileName) { + delete history[i].fileName; + } + } + if (selectGC) { + XFreeGC(display, selectGC); + XFreeGC(display, highlightGC); + } + if (drawAreaGC) { + XFreeGC(display, drawAreaGC); + } + if (drawArea) { + XtDestroyWidget(drawArea); + } + if (drawAreaFrame) { + XtDestroyWidget(drawAreaFrame); + } + if (vScrollBar) { + XtDestroyWidget(vScrollBar); + } + if (hScrollBar) { + XtDestroyWidget(hScrollBar); + } + if (scrolledWin) { + XtDestroyWidget(scrolledWin); + } + if (busyCursor) { + XFreeCursor(display, busyCursor); + } + if (linkCursor) { + XFreeCursor(display, linkCursor); + } + if (selectCursor) { + XFreeCursor(display, selectCursor); + } +} + +//------------------------------------------------------------------------ +// loadFile / displayPage / displayDest +//------------------------------------------------------------------------ + +int XPDFCore::loadFile(GString *fileName, GString *ownerPassword, + GString *userPassword) { + PDFDoc *newDoc; + GString *password; + GBool again; + int err; + + // busy cursor + setCursor(busyCursor); + + // open the PDF file + newDoc = new PDFDoc(fileName->copy(), ownerPassword, userPassword); + if (!newDoc->isOk()) { + err = newDoc->getErrorCode(); + delete newDoc; + if (err != errEncrypted || !reqPasswordCbk) { + setCursor(None); + return err; + } + + // try requesting a password + again = ownerPassword != NULL || userPassword != NULL; + while (1) { + if (!(password = (*reqPasswordCbk)(reqPasswordCbkData, again))) { + setCursor(None); + return errEncrypted; + } + newDoc = new PDFDoc(fileName->copy(), password, password); + if (newDoc->isOk()) { + break; + } + err = newDoc->getErrorCode(); + delete newDoc; + if (err != errEncrypted) { + setCursor(None); + return err; + } + again = gTrue; + } + } + + // replace old document + if (doc) { + delete doc; + } + doc = newDoc; + if (out) { + out->startDoc(doc->getXRef()); + } + + // nothing displayed yet + page = -99; + + // save the modification time + modTime = getModTime(doc->getFileName()->getCString()); + + // update the parent window + if (updateCbk) { + (*updateCbk)(updateCbkData, doc->getFileName(), -1, + doc->getNumPages(), NULL); + } + + // back to regular cursor + setCursor(None); + + return errNone; +} + +void XPDFCore::resizeToPage(int pg) { + Dimension width, height; + double width1, height1; + Dimension topW, topH, topBorder, daW, daH; + Dimension displayW, displayH; + + displayW = DisplayWidth(display, screenNum); + displayH = DisplayHeight(display, screenNum); + if (fullScreen) { + width = displayW; + height = displayH; + } else { + if (pg < 0 || pg > doc->getNumPages()) { + width1 = 612; + height1 = 792; + } else if (doc->getPageRotate(pg) == 90 || + doc->getPageRotate(pg) == 270) { + width1 = doc->getPageHeight(pg); + height1 = doc->getPageWidth(pg); + } else { + width1 = doc->getPageWidth(pg); + height1 = doc->getPageHeight(pg); + } + if (zoom == zoomPage || zoom == zoomWidth) { + width = (Dimension)((width1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5); + height = (Dimension)((height1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5); + } else { + width = (Dimension)((width1 * zoomDPI[zoom - minZoom]) / 72 + 0.5); + height = (Dimension)((height1 * zoomDPI[zoom - minZoom]) / 72 + 0.5); + } + if (width > displayW - 100) { + width = displayW - 100; + } + if (height > displayH - 150) { + height = displayH - 150; + } + } + + if (XtIsRealized(shell)) { + XtVaGetValues(shell, XmNwidth, &topW, XmNheight, &topH, + XmNborderWidth, &topBorder, NULL); + XtVaGetValues(drawArea, XmNwidth, &daW, XmNheight, &daH, NULL); + XtVaSetValues(shell, XmNwidth, width + (topW - daW), + XmNheight, height + (topH - daH), NULL); + } else { + XtVaSetValues(drawArea, XmNwidth, width, XmNheight, height, NULL); + } +} + +void XPDFCore::clear() { + if (!doc) { + return; + } + + // no document + delete doc; + doc = NULL; + out->clear(); + + // no page displayed + page = -99; + + // redraw + scrollX = scrollY = 0; + updateScrollBars(); + redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight); +} + +void XPDFCore::displayPage(int pageA, int zoomA, int rotateA, + GBool scrollToTop, GBool addToHist) { + double hDPI, vDPI; + int rot; + XPDFHistory *h; + GBool newZoom; + XGCValues gcValues; + time_t newModTime; + int oldScrollX, oldScrollY; + + // update the zoom and rotate values + newZoom = zoomA != zoom; + zoom = zoomA; + rotate = rotateA; + + // check for document and valid page number + if (!doc || pageA <= 0 || pageA > doc->getNumPages()) { + return; + } + + // busy cursor + setCursor(busyCursor); + + + // check for changes to the file + newModTime = getModTime(doc->getFileName()->getCString()); + if (newModTime != modTime) { + if (loadFile(doc->getFileName()) == errNone) { + if (pageA > doc->getNumPages()) { + pageA = doc->getNumPages(); + } + } + modTime = newModTime; + } + + // free the old GCs + if (selectGC) { + XFreeGC(display, selectGC); + XFreeGC(display, highlightGC); + } + + // new page number + page = pageA; + + // scroll to top + if (scrollToTop) { + scrollY = 0; + } + + // if zoom level changed, scroll to the top-left corner + if (newZoom) { + scrollX = scrollY = 0; + } + + // initialize mouse-related stuff + linkAction = NULL; + selectXMin = selectXMax = 0; + selectYMin = selectYMax = 0; + dragging = gFalse; + lastDragLeft = lastDragTop = gTrue; + + // draw the page + rot = rotate + doc->getPageRotate(page); + if (rot >= 360) { + rot -= 360; + } else if (rotate < 0) { + rot += 360; + } + if (zoom == zoomPage) { + if (rot == 90 || rot == 270) { + hDPI = (drawAreaWidth / doc->getPageHeight(page)) * 72; + vDPI = (drawAreaHeight / doc->getPageWidth(page)) * 72; + } else { + hDPI = (drawAreaWidth / doc->getPageWidth(page)) * 72; + vDPI = (drawAreaHeight / doc->getPageHeight(page)) * 72; + } + dpi = (hDPI < vDPI) ? hDPI : vDPI; + } else if (zoom == zoomWidth) { + if (rot == 90 || rot == 270) { + dpi = (drawAreaWidth / doc->getPageHeight(page)) * 72; + } else { + dpi = (drawAreaWidth / doc->getPageWidth(page)) * 72; + } + } else { + dpi = zoomDPI[zoom - minZoom]; + } + out->setWindow(XtWindow(drawArea)); + doc->displayPage(out, page, dpi, rotate, gTrue); + oldScrollX = scrollX; + oldScrollY = scrollY; + updateScrollBars(); + if (scrollX != oldScrollX || scrollY != oldScrollY) { + redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight); + } + + + // add to history + if (addToHist) { + if (++historyCur == xpdfHistorySize) { + historyCur = 0; + } + h = &history[historyCur]; + if (h->fileName) { + delete h->fileName; + } + h->fileName = doc->getFileName()->copy(); + h->page = page; + if (historyBLen < xpdfHistorySize) { + ++historyBLen; + } + historyFLen = 0; + } + + // update the parent window + if (updateCbk) { + (*updateCbk)(updateCbkData, NULL, page, -1, ""); + } + + // allocate new GCs + gcValues.foreground = BlackPixel(display, screenNum) ^ + WhitePixel(display, screenNum); + gcValues.function = GXxor; + selectGC = XCreateGC(display, out->getPixmap(), + GCForeground | GCFunction, &gcValues); + highlightGC = XCreateGC(display, out->getPixmap(), + GCForeground | GCFunction, &gcValues); + + // back to regular cursor + setCursor(None); +} + +void XPDFCore::displayDest(LinkDest *dest, int zoomA, int rotateA, + GBool addToHist) { + Ref pageRef; + int pg; + int dx, dy; + + if (dest->isPageRef()) { + pageRef = dest->getPageRef(); + pg = doc->findPage(pageRef.num, pageRef.gen); + } else { + pg = dest->getPageNum(); + } + if (pg <= 0 || pg > doc->getNumPages()) { + pg = 1; + } + if (pg != page) { + displayPage(pg, zoomA, rotateA, gTrue, addToHist); + } + + if (fullScreen) { + return; + } + switch (dest->getKind()) { + case destXYZ: + out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); + if (dest->getChangeLeft() || dest->getChangeTop()) { + scrollTo(dest->getChangeLeft() ? dx : scrollX, + dest->getChangeTop() ? dy : scrollY); + } + //~ what is the zoom parameter? + break; + case destFit: + case destFitB: + //~ do fit + scrollTo(0, 0); + break; + case destFitH: + case destFitBH: + //~ do fit + out->cvtUserToDev(0, dest->getTop(), &dx, &dy); + scrollTo(0, dy); + break; + case destFitV: + case destFitBV: + //~ do fit + out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy); + scrollTo(dx, 0); + break; + case destFitR: + //~ do fit + out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); + scrollTo(dx, dy); + break; + } +} + +//------------------------------------------------------------------------ +// page/position changes +//------------------------------------------------------------------------ + +void XPDFCore::gotoNextPage(int inc, GBool top) { + int pg; + + if (!doc || doc->getNumPages() == 0) { + return; + } + if (page < doc->getNumPages()) { + if ((pg = page + inc) > doc->getNumPages()) { + pg = doc->getNumPages(); + } + displayPage(pg, zoom, rotate, top, gTrue); + } else { + XBell(display, 0); + } +} + +void XPDFCore::gotoPrevPage(int dec, GBool top, GBool bottom) { + int pg; + + if (!doc || doc->getNumPages() == 0) { + return; + } + if (page > 1) { + if (!fullScreen && bottom) { + scrollY = out->getPixmapHeight() - drawAreaHeight; + if (scrollY < 0) { + scrollY = 0; + } + // displayPage will call updateScrollBars() + } + if ((pg = page - dec) < 1) { + pg = 1; + } + displayPage(pg, zoom, rotate, top, gTrue); + } else { + XBell(display, 0); + } +} + +void XPDFCore::goForward() { + if (historyFLen == 0) { + XBell(display, 0); + return; + } + if (++historyCur == xpdfHistorySize) { + historyCur = 0; + } + --historyFLen; + ++historyBLen; + if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) { + if (loadFile(history[historyCur].fileName) != errNone) { + XBell(display, 0); + return; + } + } + displayPage(history[historyCur].page, zoom, rotate, gFalse, gFalse); +} + +void XPDFCore::goBackward() { + if (historyBLen <= 1) { + XBell(display, 0); + return; + } + if (--historyCur < 0) { + historyCur = xpdfHistorySize - 1; + } + --historyBLen; + ++historyFLen; + if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) { + if (loadFile(history[historyCur].fileName) != errNone) { + XBell(display, 0); + return; + } + } + displayPage(history[historyCur].page, zoom, rotate, gFalse, gFalse); +} + +void XPDFCore::scrollLeft(int nCols) { + scrollTo(scrollX - nCols * 16, scrollY); +} + +void XPDFCore::scrollRight(int nCols) { + scrollTo(scrollX + nCols * 16, scrollY); +} + +void XPDFCore::scrollUp(int nLines) { + scrollTo(scrollX, scrollY - nLines * 16); +} + +void XPDFCore::scrollDown(int nLines) { + scrollTo(scrollX, scrollY + nLines * 16); +} + +void XPDFCore::scrollPageUp() { + if (scrollY == 0) { + gotoPrevPage(1, gFalse, gTrue); + } else { + scrollTo(scrollX, scrollY - drawAreaHeight); + } +} + +void XPDFCore::scrollPageDown() { + if (scrollY >= out->getPixmapHeight() - drawAreaHeight) { + gotoNextPage(1, gTrue); + } else { + scrollTo(scrollX, scrollY + drawAreaHeight); + } +} + +void XPDFCore::scrollTo(int x, int y) { + GBool needRedraw; + int maxPos, pos; + + needRedraw = gFalse; + + maxPos = out ? out->getPixmapWidth() : 1; + if (maxPos < drawAreaWidth) { + maxPos = drawAreaWidth; + } + if (x < 0) { + pos = 0; + } else if (x > maxPos - drawAreaWidth) { + pos = maxPos - drawAreaWidth; + } else { + pos = x; + } + if (scrollX != pos) { + scrollX = pos; + XmScrollBarSetValues(hScrollBar, scrollX, drawAreaWidth, 16, + drawAreaWidth, False); + needRedraw = gTrue; + } + + maxPos = out ? out->getPixmapHeight() : 1; + if (maxPos < drawAreaHeight) { + maxPos = drawAreaHeight; + } + if (y < 0) { + pos = 0; + } else if (y > maxPos - drawAreaHeight) { + pos = maxPos - drawAreaHeight; + } else { + pos = y; + } + if (scrollY != pos) { + scrollY = pos; + XmScrollBarSetValues(vScrollBar, scrollY, drawAreaHeight, 16, + drawAreaHeight, False); + needRedraw = gTrue; + } + + if (needRedraw) { + redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight); + } +} + +//------------------------------------------------------------------------ +// selection +//------------------------------------------------------------------------ + +void XPDFCore::setSelection(int newXMin, int newYMin, + int newXMax, int newYMax) { + Pixmap pixmap; + int x, y; + GBool needRedraw, needScroll; + GBool moveLeft, moveRight, moveTop, moveBottom; + + pixmap = out->getPixmap(); + + + // erase old selection on off-screen bitmap + needRedraw = gFalse; + if (selectXMin < selectXMax && selectYMin < selectYMax) { + XFillRectangle(display, pixmap, + selectGC, selectXMin, selectYMin, + selectXMax - selectXMin, selectYMax - selectYMin); + needRedraw = gTrue; + } + + // draw new selection on off-screen bitmap + if (newXMin < newXMax && newYMin < newYMax) { + XFillRectangle(display, pixmap, + selectGC, newXMin, newYMin, + newXMax - newXMin, newYMax - newYMin); + needRedraw = gTrue; + } + + // check which edges moved + moveLeft = newXMin != selectXMin; + moveTop = newYMin != selectYMin; + moveRight = newXMax != selectXMax; + moveBottom = newYMax != selectYMax; + + // redraw currently visible part of bitmap + if (needRedraw) { + if (moveLeft) { + redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin, + (newYMin < selectYMin) ? newYMin : selectYMin, + (newXMin > selectXMin) ? newXMin : selectXMin, + (newYMax > selectYMax) ? newYMax : selectYMax); + } + if (moveRight) { + redrawRectangle((newXMax < selectXMax) ? newXMax : selectXMax, + (newYMin < selectYMin) ? newYMin : selectYMin, + (newXMax > selectXMax) ? newXMax : selectXMax, + (newYMax > selectYMax) ? newYMax : selectYMax); + } + if (moveTop) { + redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin, + (newYMin < selectYMin) ? newYMin : selectYMin, + (newXMax > selectXMax) ? newXMax : selectXMax, + (newYMin > selectYMin) ? newYMin : selectYMin); + } + if (moveBottom) { + redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin, + (newYMax < selectYMax) ? newYMax : selectYMax, + (newXMax > selectXMax) ? newXMax : selectXMax, + (newYMax > selectYMax) ? newYMax : selectYMax); + } + } + + // switch to new selection coords + selectXMin = newXMin; + selectXMax = newXMax; + selectYMin = newYMin; + selectYMax = newYMax; + + // scroll if necessary + if (fullScreen) { + return; + } + needScroll = gFalse; + x = scrollX; + y = scrollY; + if (moveLeft && selectXMin < x) { + x = selectXMin; + needScroll = gTrue; + } else if (moveRight && selectXMax >= x + drawAreaWidth) { + x = selectXMax - drawAreaWidth; + needScroll = gTrue; + } else if (moveLeft && selectXMin >= x + drawAreaWidth) { + x = selectXMin - drawAreaWidth; + needScroll = gTrue; + } else if (moveRight && selectXMax < x) { + x = selectXMax; + needScroll = gTrue; + } + if (moveTop && selectYMin < y) { + y = selectYMin; + needScroll = gTrue; + } else if (moveBottom && selectYMax >= y + drawAreaHeight) { + y = selectYMax - drawAreaHeight; + needScroll = gTrue; + } else if (moveTop && selectYMin >= y + drawAreaHeight) { + y = selectYMin - drawAreaHeight; + needScroll = gTrue; + } else if (moveBottom && selectYMax < y) { + y = selectYMax; + needScroll = gTrue; + } + if (needScroll) { + scrollTo(x, y); + } +} + +void XPDFCore::moveSelection(int mx, int my) { + int xMin, yMin, xMax, yMax; + + // clip mouse coords + if (mx < 0) { + mx = 0; + } else if (mx >= out->getPixmapWidth()) { + mx = out->getPixmapWidth() - 1; + } + if (my < 0) { + my = 0; + } else if (my >= out->getPixmapHeight()) { + my = out->getPixmapHeight() - 1; + } + + // move appropriate edges of selection + if (lastDragLeft) { + if (mx < selectXMax) { + xMin = mx; + xMax = selectXMax; + } else { + xMin = selectXMax; + xMax = mx; + lastDragLeft = gFalse; + } + } else { + if (mx > selectXMin) { + xMin = selectXMin; + xMax = mx; + } else { + xMin = mx; + xMax = selectXMin; + lastDragLeft = gTrue; + } + } + if (lastDragTop) { + if (my < selectYMax) { + yMin = my; + yMax = selectYMax; + } else { + yMin = selectYMax; + yMax = my; + lastDragTop = gFalse; + } + } else { + if (my > selectYMin) { + yMin = selectYMin; + yMax = my; + } else { + yMin = my; + yMax = selectYMin; + lastDragTop = gTrue; + } + } + + // redraw the selection + setSelection(xMin, yMin, xMax, yMax); +} + +// X's copy-and-paste mechanism is brain damaged. Xt doesn't help +// any, but doesn't make it too much worse, either. Motif, on the +// other hand, adds significant complexity to the mess. So here we +// blow off the Motif junk and stick to plain old Xt. The next two +// functions (copySelection and convertSelectionCbk) implement the +// magic needed to deal with Xt's mechanism. Note that this requires +// global variables (currentSelection and currentSelectionOwner). + +void XPDFCore::copySelection() { + if (!doc->okToCopy()) { + return; + } + if (currentSelection) { + delete currentSelection; + } + //~ for multithreading: need a mutex here + currentSelection = out->getText(selectXMin, selectYMin, + selectXMax, selectYMax); + currentSelectionOwner = this; + XtOwnSelection(drawArea, XA_PRIMARY, XtLastTimestampProcessed(display), + &convertSelectionCbk, NULL, NULL); +} + +Boolean XPDFCore::convertSelectionCbk(Widget widget, Atom *selection, + Atom *target, Atom *type, + XtPointer *value, unsigned long *length, + int *format) { + if (*target != XA_STRING) { + return False; + } + //~ for multithreading: need a mutex here + *value = XtNewString(currentSelection->getCString()); + *length = currentSelection->getLength(); + *type = XA_STRING; + *format = 8; // 8-bit elements + return True; +} + +GBool XPDFCore::getSelection(int *xMin, int *yMin, int *xMax, int *yMax) { + if (selectXMin >= selectXMax || selectYMin >= selectYMax) { + return gFalse; + } + *xMin = selectXMin; + *yMin = selectYMin; + *xMax = selectXMax; + *yMax = selectYMax; + return gTrue; +} + +GString *XPDFCore::extractText(int xMin, int yMin, int xMax, int yMax) { + if (!doc->okToCopy()) { + return NULL; + } + return out->getText(xMin, yMin, xMax, yMax); +} + +GString *XPDFCore::extractText(int pageNum, + int xMin, int yMin, int xMax, int yMax) { + TextOutputDev *textOut; + GString *s; + + if (!doc->okToCopy()) { + return NULL; + } + textOut = new TextOutputDev(NULL, gFalse, gFalse); + if (!textOut->isOk()) { + delete textOut; + return NULL; + } + doc->displayPage(textOut, pageNum, dpi, rotate, gFalse); + s = textOut->getText(xMin, yMin, xMax, yMax); + delete textOut; + return s; +} + +//------------------------------------------------------------------------ +// hyperlinks +//------------------------------------------------------------------------ + +void XPDFCore::doLink(int mx, int my) { + double x, y; + LinkAction *action; + + // look for a link + out->cvtDevToUser(mx, my, &x, &y); + if ((action = doc->findLink(x, y))) { + doAction(action); + } +} + +void XPDFCore::doAction(LinkAction *action) { + LinkActionKind kind; + LinkDest *dest; + GString *namedDest; + char *s; + GString *fileName, *fileName2; + GString *cmd; + GString *actionName; + Object movieAnnot, obj1, obj2; + GString *msg; + int i; + + switch (kind = action->getKind()) { + + // GoTo / GoToR action + case actionGoTo: + case actionGoToR: + if (kind == actionGoTo) { + dest = NULL; + namedDest = NULL; + if ((dest = ((LinkGoTo *)action)->getDest())) { + dest = dest->copy(); + } else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) { + namedDest = namedDest->copy(); + } + } else { + dest = NULL; + namedDest = NULL; + if ((dest = ((LinkGoToR *)action)->getDest())) { + dest = dest->copy(); + } else if ((namedDest = ((LinkGoToR *)action)->getNamedDest())) { + namedDest = namedDest->copy(); + } + s = ((LinkGoToR *)action)->getFileName()->getCString(); + //~ translate path name for VMS (deal with '/') + if (isAbsolutePath(s)) { + fileName = new GString(s); + } else { + fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s); + } + if (loadFile(fileName) != errNone) { + if (dest) { + delete dest; + } + if (namedDest) { + delete namedDest; + } + delete fileName; + return; + } + delete fileName; + } + if (namedDest) { + dest = doc->findDest(namedDest); + delete namedDest; + } + if (dest) { + displayDest(dest, zoom, rotate, gTrue); + delete dest; + } else { + if (kind == actionGoToR) { + displayPage(1, zoom, 0, gFalse, gTrue); + } + } + break; + + // Launch action + case actionLaunch: + fileName = ((LinkLaunch *)action)->getFileName(); + s = fileName->getCString(); + if (!strcmp(s + fileName->getLength() - 4, ".pdf") || + !strcmp(s + fileName->getLength() - 4, ".PDF")) { + //~ translate path name for VMS (deal with '/') + if (isAbsolutePath(s)) { + fileName = fileName->copy(); + } else { + fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s); + } + if (loadFile(fileName) != errNone) { + delete fileName; + return; + } + delete fileName; + displayPage(1, zoom, rotate, gFalse, gTrue); + } else { + fileName = fileName->copy(); + if (((LinkLaunch *)action)->getParams()) { + fileName->append(' '); + fileName->append(((LinkLaunch *)action)->getParams()); + } +#ifdef VMS + fileName->insert(0, "spawn/nowait "); +#elif defined(__EMX__) + fileName->insert(0, "start /min /n "); +#else + fileName->append(" &"); +#endif + msg = new GString("About to execute the command:\n"); + msg->append(fileName); + if (doQuestionDialog("Launching external application", msg)) { + system(fileName->getCString()); + } + delete fileName; + delete msg; + } + break; + + // URI action + case actionURI: + if (!(cmd = globalParams->getURLCommand())) { + error(-1, "No urlCommand defined in config file"); + break; + } + runCommand(cmd, ((LinkURI *)action)->getURI()); + break; + + // Named action + case actionNamed: + actionName = ((LinkNamed *)action)->getName(); + if (!actionName->cmp("NextPage")) { + gotoNextPage(1, gTrue); + } else if (!actionName->cmp("PrevPage")) { + gotoPrevPage(1, gTrue, gFalse); + } else if (!actionName->cmp("FirstPage")) { + if (page != 1) { + displayPage(1, zoom, rotate, gTrue, gTrue); + } + } else if (!actionName->cmp("LastPage")) { + if (page != doc->getNumPages()) { + displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue); + } + } else if (!actionName->cmp("GoBack")) { + goBackward(); + } else if (!actionName->cmp("GoForward")) { + goForward(); + } else if (!actionName->cmp("Quit")) { + if (actionCbk) { + (*actionCbk)(actionCbkData, "Quit"); + } + } else { + error(-1, "Unknown named action: '%s'", actionName->getCString()); + } + break; + + // Movie action + case actionMovie: + if (!(cmd = globalParams->getMovieCommand())) { + error(-1, "No movieCommand defined in config file"); + break; + } + if (((LinkMovie *)action)->hasAnnotRef()) { + doc->getXRef()->fetch(((LinkMovie *)action)->getAnnotRef()->num, + ((LinkMovie *)action)->getAnnotRef()->gen, + &movieAnnot); + } else { + doc->getCatalog()->getPage(page)->getAnnots(&obj1); + if (obj1.isArray()) { + for (i = 0; i < obj1.arrayGetLength(); ++i) { + if (obj1.arrayGet(i, &movieAnnot)->isDict()) { + if (movieAnnot.dictLookup("Subtype", &obj2)->isName("Movie")) { + obj2.free(); + break; + } + obj2.free(); + } + movieAnnot.free(); + } + obj1.free(); + } + } + if (movieAnnot.isDict()) { + if (movieAnnot.dictLookup("Movie", &obj1)->isDict()) { + if (obj1.dictLookup("F", &obj2)) { + if ((fileName = LinkAction::getFileSpecName(&obj2))) { + if (!isAbsolutePath(fileName->getCString())) { + fileName2 = appendToPath( + grabPath(doc->getFileName()->getCString()), + fileName->getCString()); + delete fileName; + fileName = fileName2; + } + runCommand(cmd, fileName); + delete fileName; + } + obj2.free(); + } + obj1.free(); + } + } + movieAnnot.free(); + break; + + // unknown action type + case actionUnknown: + error(-1, "Unknown link action type: '%s'", + ((LinkUnknown *)action)->getAction()->getCString()); + break; + } +} + +// Run a command, given a <cmdFmt> string with one '%s' in it, and an +// <arg> string to insert in place of the '%s'. +void XPDFCore::runCommand(GString *cmdFmt, GString *arg) { + GString *cmd; + char *s; + int i; + + if ((s = strstr(cmdFmt->getCString(), "%s"))) { + cmd = arg->copy(); + // filter out any quote marks (' or ") to avoid a potential + // security hole + i = 0; + while (i < cmd->getLength()) { + if (cmd->getChar(i) == '"') { + cmd->del(i); + cmd->insert(i, "%22"); + i += 3; + } else if (cmd->getChar(i) == '\'') { + cmd->del(i); + cmd->insert(i, "%27"); + i += 3; + } else { + ++i; + } + } + cmd->insert(0, cmdFmt->getCString(), + s - cmdFmt->getCString()); + cmd->append(s + 2); + } else { + cmd = cmdFmt->copy(); + } +#ifdef VMS + cmd->insert(0, "spawn/nowait "); +#elif defined(__EMX__) + cmd->insert(0, "start /min /n "); +#else + cmd->append(" &"); +#endif + system(cmd->getCString()); + delete cmd; +} + + +//------------------------------------------------------------------------ +// find +//------------------------------------------------------------------------ + +void XPDFCore::find(char *s) { + Unicode *u; + TextOutputDev *textOut; + int xMin, yMin, xMax, yMax; + double xMin1, yMin1, xMax1, yMax1; + int pg; + GBool top; + int len, i; + + // check for zero-length string + if (!s[0]) { + XBell(display, 0); + return; + } + + // set cursor to watch + setCursor(busyCursor); + + // convert to Unicode +#if 1 //~ should do something more intelligent here + len = strlen(s); + u = (Unicode *)gmalloc(len * sizeof(Unicode)); + for (i = 0; i < len; ++i) { + u[i] = (Unicode)(s[i] & 0xff); + } +#endif + + // search current page starting at current selection or top of page + xMin = yMin = xMax = yMax = 0; + if (selectXMin < selectXMax && selectYMin < selectYMax) { + xMin = selectXMax; + yMin = (selectYMin + selectYMax) / 2; + top = gFalse; + } else { + top = gTrue; + } + if (out->findText(u, len, top, gTrue, &xMin, &yMin, &xMax, &yMax)) { + goto found; + } + + // search following pages + textOut = new TextOutputDev(NULL, gFalse, gFalse); + if (!textOut->isOk()) { + delete textOut; + goto done; + } + for (pg = page+1; pg <= doc->getNumPages(); ++pg) { + doc->displayPage(textOut, pg, 72, 0, gFalse); + if (textOut->findText(u, len, gTrue, gTrue, + &xMin1, &yMin1, &xMax1, &yMax1)) { + goto foundPage; + } + } + + // search previous pages + for (pg = 1; pg < page; ++pg) { + doc->displayPage(textOut, pg, 72, 0, gFalse); + if (textOut->findText(u, len, gTrue, gTrue, + &xMin1, &yMin1, &xMax1, &yMax1)) { + goto foundPage; + } + } + delete textOut; + + // search current page ending at current selection + if (selectXMin < selectXMax && selectYMin < selectYMax) { + xMax = selectXMin; + yMax = (selectYMin + selectYMax) / 2; + if (out->findText(u, len, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) { + goto found; + } + } + + // not found + XBell(display, 0); + goto done; + + // found on a different page + foundPage: + delete textOut; + displayPage(pg, zoom, rotate, gTrue, gTrue); + if (!out->findText(u, len, gTrue, gTrue, &xMin, &yMin, &xMax, &yMax)) { + // this can happen if coalescing is bad + goto done; + } + + // found: change the selection + found: + setSelection(xMin, yMin, xMax, yMax); +#ifndef NO_TEXT_SELECT + copySelection(); +#endif + + done: + gfree(u); + + // reset cursors to normal + setCursor(None); +} + +//------------------------------------------------------------------------ +// misc access +//------------------------------------------------------------------------ + +void XPDFCore::setBusyCursor(GBool busy) { + setCursor(busy ? busyCursor : None); +} + +void XPDFCore::takeFocus() { + XmProcessTraversal(drawArea, XmTRAVERSE_CURRENT); +} + +//------------------------------------------------------------------------ +// GUI code +//------------------------------------------------------------------------ + +void XPDFCore::initWindow() { + Arg args[20]; + int n; + + // create the cursors + busyCursor = XCreateFontCursor(display, XC_watch); + linkCursor = XCreateFontCursor(display, XC_hand2); + selectCursor = XCreateFontCursor(display, XC_cross); + currentCursor = 0; + + // create the scrolled window and scrollbars + n = 0; + XtSetArg(args[n], XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++n; + XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n; + scrolledWin = XmCreateScrolledWindow(parentWidget, "scroll", args, n); + XtManageChild(scrolledWin); + n = 0; + XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; + XtSetArg(args[n], XmNminimum, 0); ++n; + XtSetArg(args[n], XmNmaximum, 1); ++n; + XtSetArg(args[n], XmNsliderSize, 1); ++n; + XtSetArg(args[n], XmNvalue, 0); ++n; + XtSetArg(args[n], XmNincrement, 1); ++n; + XtSetArg(args[n], XmNpageIncrement, 1); ++n; + hScrollBar = XmCreateScrollBar(scrolledWin, "hScrollBar", args, n); + XtManageChild(hScrollBar); + XtAddCallback(hScrollBar, XmNvalueChangedCallback, + &hScrollChangeCbk, (XtPointer)this); +#ifndef DISABLE_SMOOTH_SCROLL + XtAddCallback(hScrollBar, XmNdragCallback, + &hScrollDragCbk, (XtPointer)this); +#endif + n = 0; + XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n; + XtSetArg(args[n], XmNminimum, 0); ++n; + XtSetArg(args[n], XmNmaximum, 1); ++n; + XtSetArg(args[n], XmNsliderSize, 1); ++n; + XtSetArg(args[n], XmNvalue, 0); ++n; + XtSetArg(args[n], XmNincrement, 1); ++n; + XtSetArg(args[n], XmNpageIncrement, 1); ++n; + vScrollBar = XmCreateScrollBar(scrolledWin, "vScrollBar", args, n); + XtManageChild(vScrollBar); + XtAddCallback(vScrollBar, XmNvalueChangedCallback, + &vScrollChangeCbk, (XtPointer)this); +#ifndef DISABLE_SMOOTH_SCROLL + XtAddCallback(vScrollBar, XmNdragCallback, + &vScrollDragCbk, (XtPointer)this); +#endif + + // create the drawing area + n = 0; + XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); ++n; + XtSetArg(args[n], XmNmarginWidth, 0); ++n; + XtSetArg(args[n], XmNmarginHeight, 0); ++n; + if (fullScreen) { + XtSetArg(args[n], XmNshadowThickness, 0); ++n; + } + drawAreaFrame = XmCreateFrame(scrolledWin, "drawAreaFrame", args, n); + XtManageChild(drawAreaFrame); + n = 0; + XtSetArg(args[n], XmNresizePolicy, XmRESIZE_ANY); ++n; + XtSetArg(args[n], XmNbackground, paperColor); ++n; + XtSetArg(args[n], XmNwidth, 700); ++n; + XtSetArg(args[n], XmNheight, 500); ++n; + drawArea = XmCreateDrawingArea(drawAreaFrame, "drawArea", args, n); + XtManageChild(drawArea); + XtAddCallback(drawArea, XmNresizeCallback, &resizeCbk, (XtPointer)this); + XtAddCallback(drawArea, XmNexposeCallback, &redrawCbk, (XtPointer)this); + XtAddCallback(drawArea, XmNinputCallback, &inputCbk, (XtPointer)this); + resizeCbk(drawArea, this, NULL); + + // set up mouse motion translations + XtOverrideTranslations(drawArea, XtParseTranslationTable( + "<Btn1Down>:DrawingAreaInput()\n" + "<Btn1Up>:DrawingAreaInput()\n" + "<Btn1Motion>:DrawingAreaInput()\n" + "<Motion>:DrawingAreaInput()")); + + // can't create a GC until the window gets mapped + drawAreaGC = NULL; + selectGC = NULL; + highlightGC = NULL; +} + +void XPDFCore::hScrollChangeCbk(Widget widget, XtPointer ptr, + XtPointer callData) { + XPDFCore *core = (XPDFCore *)ptr; + XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData; + + core->scrollTo(data->value, core->scrollY); +} + +void XPDFCore::hScrollDragCbk(Widget widget, XtPointer ptr, + XtPointer callData) { + XPDFCore *core = (XPDFCore *)ptr; + XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData; + + core->scrollTo(data->value, core->scrollY); +} + +void XPDFCore::vScrollChangeCbk(Widget widget, XtPointer ptr, + XtPointer callData) { + XPDFCore *core = (XPDFCore *)ptr; + XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData; + + core->scrollTo(core->scrollX, data->value); +} + +void XPDFCore::vScrollDragCbk(Widget widget, XtPointer ptr, + XtPointer callData) { + XPDFCore *core = (XPDFCore *)ptr; + XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData; + + core->scrollTo(core->scrollX, data->value); +} + +void XPDFCore::resizeCbk(Widget widget, XtPointer ptr, XtPointer callData) { + XPDFCore *core = (XPDFCore *)ptr; + Arg args[2]; + int n; + Dimension w, h; + + n = 0; + XtSetArg(args[n], XmNwidth, &w); ++n; + XtSetArg(args[n], XmNheight, &h); ++n; + XtGetValues(core->drawArea, args, n); + core->drawAreaWidth = (int)w; + core->drawAreaHeight = (int)h; + if (core->page >= 0 && + (core->zoom == zoomPage || core->zoom == zoomWidth)) { + core->displayPage(core->page, core->zoom, core->rotate, + gFalse, gFalse); + } else { + core->updateScrollBars(); + } +} + +void XPDFCore::redrawCbk(Widget widget, XtPointer ptr, XtPointer callData) { + XPDFCore *core = (XPDFCore *)ptr; + XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData; + int x, y, w, h; + + if (data->reason == XmCR_EXPOSE) { + x = core->scrollX + data->event->xexpose.x; + y = core->scrollY + data->event->xexpose.y; + w = data->event->xexpose.width; + h = data->event->xexpose.height; + } else { + x = core->scrollX; + y = core->scrollY; + w = core->drawAreaWidth; + h = core->drawAreaHeight; + } + core->redrawRectangle(x, y, w, h); +} + +void XPDFCore::outputDevRedrawCbk(void *data) { + XPDFCore *core = (XPDFCore *)data; + + core->redrawRectangle(core->scrollX, core->scrollY, + core->drawAreaWidth, core->drawAreaHeight); +} + +void XPDFCore::inputCbk(Widget widget, XtPointer ptr, XtPointer callData) { + XPDFCore *core = (XPDFCore *)ptr; + XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData; + LinkAction *action; + int mx, my; + double x, y; + char *s; + KeySym key; + char buf[20]; + int n; + + switch (data->event->type) { + case ButtonPress: + if (data->event->xbutton.button == 1) { + core->takeFocus(); + if (core->doc && core->doc->getNumPages() > 0) { + if (core->selectEnabled) { + mx = core->scrollX + data->event->xbutton.x; + my = core->scrollY + data->event->xbutton.y; + core->setSelection(mx, my, mx, my); + core->setCursor(core->selectCursor); + core->dragging = gTrue; + } + } + } else if (data->event->xbutton.button == 2) { + if (!core->fullScreen) { + core->panning = gTrue; + core->panMX = data->event->xbutton.x; + core->panMY = data->event->xbutton.y; + } + } else if (data->event->xbutton.button == 4) { // mouse wheel up + if (core->fullScreen) { + core->gotoPrevPage(1, gTrue, gFalse); + } else if (core->scrollY == 0) { + core->gotoPrevPage(1, gFalse, gTrue); + } else { + core->scrollUp(1); + } + } else if (data->event->xbutton.button == 5) { // mouse wheel down + if (core->fullScreen || + core->scrollY >= + core->out->getPixmapHeight() - core->drawAreaHeight) { + core->gotoNextPage(1, gTrue); + } else { + core->scrollDown(1); + } + } else if (data->event->xbutton.button == 6) { // second mouse wheel right + if (!core->fullScreen) { + core->scrollRight(1); + } + } else if (data->event->xbutton.button == 7) { // second mouse wheel left + if (!core->fullScreen) { + core->scrollLeft(1); + } + } else { + if (*core->mouseCbk) { + (*core->mouseCbk)(core->mouseCbkData, data->event); + } + } + break; + case ButtonRelease: + if (data->event->xbutton.button == 1) { + if (core->doc && core->doc->getNumPages() > 0) { + mx = core->scrollX + data->event->xbutton.x; + my = core->scrollY + data->event->xbutton.y; + if (core->dragging) { + core->dragging = gFalse; + core->setCursor(None); + core->moveSelection(mx, my); +#ifndef NO_TEXT_SELECT + if (core->selectXMin != core->selectXMax && + core->selectYMin != core->selectYMax) { + if (core->doc->okToCopy()) { + core->copySelection(); + } else { + error(-1, "Copying of text from this document is not allowed."); + } + } +#endif + } + if (core->hyperlinksEnabled) { + if (core->selectXMin == core->selectXMax || + core->selectYMin == core->selectYMax) { + core->doLink(mx, my); + } + } + } + } else if (data->event->xbutton.button == 2) { + core->panning = gFalse; + } else { + if (*core->mouseCbk) { + (*core->mouseCbk)(core->mouseCbkData, data->event); + } + } + break; + case MotionNotify: + if (core->doc && core->doc->getNumPages() > 0) { + mx = core->scrollX + data->event->xbutton.x; + my = core->scrollY + data->event->xbutton.y; + if (core->dragging) { + core->moveSelection(mx, my); + } else if (core->hyperlinksEnabled) { + core->out->cvtDevToUser(mx, my, &x, &y); + if ((action = core->doc->findLink(x, y))) { + core->setCursor(core->linkCursor); + if (action != core->linkAction) { + core->linkAction = action; + if (core->updateCbk) { + s = ""; + switch (action->getKind()) { + case actionGoTo: + s = "[internal link]"; + break; + case actionGoToR: + s = ((LinkGoToR *)action)->getFileName()->getCString(); + break; + case actionLaunch: + s = ((LinkLaunch *)action)->getFileName()->getCString(); + break; + case actionURI: + s = ((LinkURI *)action)->getURI()->getCString(); + break; + case actionNamed: + s = ((LinkNamed *)action)->getName()->getCString(); + break; + case actionMovie: + s = "[movie]"; + break; + case actionUnknown: + s = "[unknown link]"; + break; + } + (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, s); + } + } + } else { + core->setCursor(None); + if (core->linkAction) { + core->linkAction = NULL; + if (core->updateCbk) { + (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, ""); + } + } + } + } + } + if (core->panning) { + core->scrollTo(core->scrollX - (data->event->xbutton.x - core->panMX), + core->scrollY - (data->event->xbutton.y - core->panMY)); + core->panMX = data->event->xbutton.x; + core->panMY = data->event->xbutton.y; + } + break; + case KeyPress: + n = XLookupString(&data->event->xkey, buf, sizeof(buf) - 1, + &key, NULL); + core->keyPress(buf, key, data->event->xkey.state); + break; + } +} + +void XPDFCore::keyPress(char *s, KeySym key, Guint modifiers) { + switch (key) { + case XK_Home: + case XK_KP_Home: + if (modifiers & ControlMask) { + displayPage(1, zoom, rotate, gTrue, gTrue); + } else if (!fullScreen) { + scrollTo(0, 0); + } + return; + case XK_End: + case XK_KP_End: + if (modifiers & ControlMask) { + displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue); + } else if (!fullScreen) { + scrollTo(out->getPixmapWidth() - drawAreaWidth, + out->getPixmapHeight() - drawAreaHeight); + } + return; + case XK_Page_Up: + case XK_KP_Page_Up: + if (fullScreen) { + gotoPrevPage(1, gTrue, gFalse); + } else { + scrollPageUp(); + } + return; + case XK_Page_Down: + case XK_KP_Page_Down: + if (fullScreen) { + gotoNextPage(1, gTrue); + } else { + scrollPageDown(); + } + return; + case XK_Left: + case XK_KP_Left: + if (!fullScreen) { + scrollLeft(); + } + return; + case XK_Right: + case XK_KP_Right: + if (!fullScreen) { + scrollRight(); + } + return; + case XK_Up: + case XK_KP_Up: + if (!fullScreen) { + scrollUp(); + } + return; + case XK_Down: + case XK_KP_Down: + if (!fullScreen) { + scrollDown(); + } + return; + } + + if (*keyPressCbk) { + (*keyPressCbk)(keyPressCbkData, s, key, modifiers); + } +} + +void XPDFCore::redrawRectangle(int x, int y, int w, int h) { + XGCValues gcValues; + Window drawAreaWin; + + // clip to window + if (x < scrollX) { + w -= scrollX - x; + x = scrollX; + } + if (x + w > scrollX + drawAreaWidth) { + w = scrollX + drawAreaWidth - x; + } + if (y < scrollY) { + h -= scrollY - y; + y = scrollY; + } + if (y + h > scrollY + drawAreaHeight) { + h = scrollY + drawAreaHeight - y; + } + + // create a GC for the drawing area + drawAreaWin = XtWindow(drawArea); + if (!drawAreaGC) { + gcValues.foreground = paperColor; + drawAreaGC = XCreateGC(display, drawAreaWin, GCForeground, &gcValues); + } + + // draw white background past the edges of the document + if (x + w > out->getPixmapWidth()) { + XFillRectangle(display, drawAreaWin, drawAreaGC, + out->getPixmapWidth() - scrollX, y - scrollY, + x + w - out->getPixmapWidth(), h); + w = out->getPixmapWidth() - x; + } + if (y + h > out->getPixmapHeight()) { + XFillRectangle(display, drawAreaWin, drawAreaGC, + x - scrollX, out->getPixmapHeight() - scrollY, + w, y + h - out->getPixmapHeight()); + h = out->getPixmapHeight() - y; + } + + // redraw (checking to see if pixmap has been allocated yet) + if (out->getPixmapWidth() > 0) { + XCopyArea(display, out->getPixmap(), drawAreaWin, drawAreaGC, + x, y, w, h, x - scrollX, y - scrollY); + } +} + +void XPDFCore::updateScrollBars() { + Arg args[20]; + int n; + int maxPos; + + maxPos = out ? out->getPixmapWidth() : 1; + if (maxPos < drawAreaWidth) { + maxPos = drawAreaWidth; + } + if (scrollX > maxPos - drawAreaWidth) { + scrollX = maxPos - drawAreaWidth; + } + n = 0; + XtSetArg(args[n], XmNvalue, scrollX); ++n; + XtSetArg(args[n], XmNmaximum, maxPos); ++n; + XtSetArg(args[n], XmNsliderSize, drawAreaWidth); ++n; + XtSetArg(args[n], XmNincrement, 16); ++n; + XtSetArg(args[n], XmNpageIncrement, drawAreaWidth); ++n; + XtSetValues(hScrollBar, args, n); + + maxPos = out ? out->getPixmapHeight() : 1; + if (maxPos < drawAreaHeight) { + maxPos = drawAreaHeight; + } + if (scrollY > maxPos - drawAreaHeight) { + scrollY = maxPos - drawAreaHeight; + } + n = 0; + XtSetArg(args[n], XmNvalue, scrollY); ++n; + XtSetArg(args[n], XmNmaximum, maxPos); ++n; + XtSetArg(args[n], XmNsliderSize, drawAreaHeight); ++n; + XtSetArg(args[n], XmNincrement, 16); ++n; + XtSetArg(args[n], XmNpageIncrement, drawAreaHeight); ++n; + XtSetValues(vScrollBar, args, n); +} + +void XPDFCore::setCursor(Cursor cursor) { + Window topWin; + + if (cursor == currentCursor) { + return; + } + if (!(topWin = XtWindow(shell))) { + return; + } + if (cursor == None) { + XUndefineCursor(display, topWin); + } else { + XDefineCursor(display, topWin, cursor); + } + XFlush(display); + currentCursor = cursor; +} + +GBool XPDFCore::doQuestionDialog(char *title, GString *msg) { + return doDialog(XmDIALOG_QUESTION, gTrue, title, msg); +} + +void XPDFCore::doInfoDialog(char *title, GString *msg) { + doDialog(XmDIALOG_INFORMATION, gFalse, title, msg); +} + +void XPDFCore::doErrorDialog(char *title, GString *msg) { + doDialog(XmDIALOG_ERROR, gFalse, title, msg); +} + +GBool XPDFCore::doDialog(int type, GBool hasCancel, + char *title, GString *msg) { + Widget dialog; + XtAppContext appContext; + Arg args[20]; + int n; + XmString s1, s2; + XEvent event; + + n = 0; + XtSetArg(args[n], XmNdialogType, type); ++n; + XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n; + s1 = XmStringCreateLocalized(title); + XtSetArg(args[n], XmNdialogTitle, s1); ++n; + s2 = XmStringCreateLocalized(msg->getCString()); + XtSetArg(args[n], XmNmessageString, s2); ++n; + dialog = XmCreateMessageDialog(drawArea, "questionDialog", args, n); + XmStringFree(s1); + XmStringFree(s2); + XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON)); + XtAddCallback(dialog, XmNokCallback, + &dialogOkCbk, (XtPointer)this); + if (hasCancel) { + XtAddCallback(dialog, XmNcancelCallback, + &dialogCancelCbk, (XtPointer)this); + } else { + XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON)); + } + + XtManageChild(dialog); + + appContext = XtWidgetToApplicationContext(dialog); + dialogDone = 0; + do { + XtAppNextEvent(appContext, &event); + XtDispatchEvent(&event); + } while (!dialogDone); + + XtUnmanageChild(dialog); + XtDestroyWidget(dialog); + + return dialogDone > 0; +} + +void XPDFCore::dialogOkCbk(Widget widget, XtPointer ptr, + XtPointer callData) { + XPDFCore *core = (XPDFCore *)ptr; + + core->dialogDone = 1; +} + +void XPDFCore::dialogCancelCbk(Widget widget, XtPointer ptr, + XtPointer callData) { + XPDFCore *core = (XPDFCore *)ptr; + + core->dialogDone = -1; +} |