mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-03 06:34:13 +00:00
42c3c82014
svn path=/trunk/kdegraphics/kpdf/; revision=174591
2543 lines
67 KiB
C++
2543 lines
67 KiB
C++
//========================================================================
|
|
//
|
|
// xpdf.cc
|
|
//
|
|
// Copyright 1996-2002 Glyph & Cog, LLC
|
|
//
|
|
//========================================================================
|
|
|
|
#include <aconf.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <X11/X.h>
|
|
#include <X11/cursorfont.h>
|
|
#include <X11/keysym.h>
|
|
#include "gtypes.h"
|
|
#include "GString.h"
|
|
#include "parseargs.h"
|
|
#include "gfile.h"
|
|
#include "gmem.h"
|
|
#include "GlobalParams.h"
|
|
#include "LTKAll.h"
|
|
#include "Object.h"
|
|
#include "Stream.h"
|
|
#include "Array.h"
|
|
#include "Dict.h"
|
|
#include "XRef.h"
|
|
#include "Catalog.h"
|
|
#include "Page.h"
|
|
#include "Link.h"
|
|
#include "PDFDoc.h"
|
|
#include "XOutputDev.h"
|
|
#include "LTKOutputDev.h"
|
|
#include "PSOutputDev.h"
|
|
#include "TextOutputDev.h"
|
|
#include "Error.h"
|
|
#include "config.h"
|
|
|
|
#ifdef XlibSpecificationRelease
|
|
#if XlibSpecificationRelease < 5
|
|
typedef char *XPointer;
|
|
#endif
|
|
#else
|
|
typedef char *XPointer;
|
|
#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
|
|
|
|
//------------------------------------------------------------------------
|
|
// misc constants / enums
|
|
//------------------------------------------------------------------------
|
|
|
|
#define remoteCmdLength 512
|
|
|
|
enum XpdfMenuItem {
|
|
menuOpen,
|
|
menuReload,
|
|
menuSavePDF,
|
|
menuRotateCCW,
|
|
menuRotateCW,
|
|
menuQuit
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
// prototypes
|
|
//------------------------------------------------------------------------
|
|
|
|
// loadFile / displayPage
|
|
static GBool loadFile(GString *fileName);
|
|
static void displayPage(int page1, int zoomA, int rotateA, GBool addToHist);
|
|
static void displayDest(LinkDest *dest, int zoomA, int rotateA,
|
|
GBool addToHist);
|
|
|
|
// key press and menu callbacks
|
|
static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers,
|
|
char *s, int n);
|
|
static void menuCbk(LTKMenuItem *item);
|
|
|
|
// mouse callbacks
|
|
static void buttonPressCbk(LTKWidget *canvas1, int n,
|
|
int mx, int my, int button, GBool dblClick);
|
|
static void buttonReleaseCbk(LTKWidget *canvas1, int n,
|
|
int mx, int my, int button, GBool click);
|
|
static void doLink(int mx, int my);
|
|
static void mouseMoveCbk(LTKWidget *widget, int widgetNum, int mx, int my);
|
|
static void mouseDragCbk(LTKWidget *widget, int widgetNum,
|
|
int mx, int my, int button);
|
|
|
|
// button callbacks
|
|
static void nextPageCbk(LTKWidget *button, int n, GBool on);
|
|
static void nextTenPageCbk(LTKWidget *button, int n, GBool on);
|
|
static void gotoNextPage(int inc, GBool top);
|
|
static void prevPageCbk(LTKWidget *button, int n, GBool on);
|
|
static void prevTenPageCbk(LTKWidget *button, int n, GBool on);
|
|
static void gotoPrevPage(int dec, GBool top, GBool bottom);
|
|
static void backCbk(LTKWidget *button, int n, GBool on);
|
|
static void forwardCbk(LTKWidget *button, int n, GBool on);
|
|
static void pageNumCbk(LTKWidget *textIn, int n, GString *text);
|
|
static void zoomMenuCbk(LTKMenuItem *item);
|
|
static void postScriptCbk(LTKWidget *button, int n, GBool on);
|
|
static void aboutCbk(LTKWidget *button, int n, GBool on);
|
|
static void quitCbk(LTKWidget *button, int n, GBool on);
|
|
|
|
// scrollbar callbacks
|
|
static void scrollVertCbk(LTKWidget *scrollbar, int n, int val);
|
|
static void scrollHorizCbk(LTKWidget *scrollbar, int n, int val);
|
|
|
|
// misc callbacks
|
|
static void layoutCbk(LTKWindow *win1);
|
|
static void updateScrollbars();
|
|
static void propChangeCbk(LTKWindow *win1, Atom atom);
|
|
|
|
// selection
|
|
static void setSelection(int newXMin, int newYMin, int newXMax, int newYMax);
|
|
|
|
// "Open" dialog
|
|
static void mapOpenDialog();
|
|
static void openButtonCbk(LTKWidget *button, int n, GBool on);
|
|
static void openSelectCbk(LTKWidget *widget, int n, GString *name);
|
|
|
|
// "Reload"
|
|
static void reloadCbk();
|
|
|
|
// "Save PDF" dialog
|
|
static void mapSaveDialog();
|
|
static void saveButtonCbk(LTKWidget *button, int n, GBool on);
|
|
static void saveSelectCbk(LTKWidget *widget, int n, GString *name);
|
|
|
|
// "PostScript" dialog
|
|
static void mapPSDialog();
|
|
static void psButtonCbk(LTKWidget *button, int n, GBool on);
|
|
|
|
// "About" window
|
|
static void mapAboutWin();
|
|
static void closeAboutCbk(LTKWidget *button, int n, GBool on);
|
|
static void aboutLayoutCbk(LTKWindow *winA);
|
|
static void aboutScrollVertCbk(LTKWidget *scrollbar, int n, int val);
|
|
static void aboutScrollHorizCbk(LTKWidget *scrollbar, int n, int val);
|
|
|
|
// "Find" window
|
|
static void findCbk(LTKWidget *button, int n, GBool on);
|
|
static void mapFindWin();
|
|
static void findButtonCbk(LTKWidget *button, int n, GBool on);
|
|
static void doFind(char *s);
|
|
|
|
// app kill callback
|
|
static void killCbk(LTKWindow *win1);
|
|
|
|
//------------------------------------------------------------------------
|
|
// "About" window text
|
|
//------------------------------------------------------------------------
|
|
|
|
static char *aboutWinText[] = {
|
|
"X X d fff",
|
|
" X X d f f",
|
|
" X X d f",
|
|
" X pppp dddd ffff",
|
|
" X X p p d d f",
|
|
" X X p p d d f",
|
|
"X X pppp dddd f Version " xpdfVersion,
|
|
" p",
|
|
" p",
|
|
" p",
|
|
"",
|
|
xpdfCopyright,
|
|
"",
|
|
"http://www.foolabs.com/xpdf/",
|
|
"derekn@foolabs.com",
|
|
"",
|
|
"Licensed under the GNU General Public License (GPL).",
|
|
"See the 'COPYING' file for details.",
|
|
"",
|
|
"Supports PDF version " supportedPDFVersionStr ".",
|
|
"",
|
|
"The PDF data structures, operators, and specification",
|
|
"are copyright 1985-2001 Adobe Systems Inc.",
|
|
"",
|
|
"Mouse bindings:",
|
|
" button 1: select text / follow link",
|
|
" button 2: pan window",
|
|
" button 3: menu",
|
|
"",
|
|
"Key bindings:",
|
|
" o = open file",
|
|
" r = reload",
|
|
" f = find text",
|
|
" n = <PgDn> = next page",
|
|
" p = <PgUp> = previous page",
|
|
" <space> = scroll down",
|
|
" <backspace> = <delete> = scroll up",
|
|
" v = forward (history path)",
|
|
" b = backward (history path)",
|
|
" 0 / + / - = zoom zero / in / out",
|
|
" z / w = zoom page / page width",
|
|
" ctrl-L = redraw",
|
|
" q = quit",
|
|
" <home> / <end> = top / bottom of page",
|
|
" <arrows> = scroll",
|
|
"",
|
|
"For more information, please read the xpdf(1) man page.",
|
|
NULL
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
// command line options
|
|
//------------------------------------------------------------------------
|
|
|
|
static char initialZoomStr[32] = "";
|
|
static char t1libControlStr[16] = "";
|
|
static char freetypeControlStr[16] = "";
|
|
static char psFileArg[256];
|
|
static char paperSize[15] = "";
|
|
static int paperWidth = 0;
|
|
static int paperHeight = 0;
|
|
static GBool level1 = gFalse;
|
|
static char textEncName[128] = "";
|
|
static char textEOL[16] = "";
|
|
static char ownerPassword[33] = "";
|
|
static char userPassword[33] = "";
|
|
static GBool fullScreen = gFalse;
|
|
static char remoteName[100] = "xpdf_";
|
|
static GBool doRemoteRaise = gFalse;
|
|
static GBool doRemoteQuit = gFalse;
|
|
static GBool printCommands = gFalse;
|
|
static GBool quiet = gFalse;
|
|
static char cfgFileName[256] = "";
|
|
static GBool printVersion = gFalse;
|
|
static GBool printHelp = gFalse;
|
|
static GBool viKeys = gFalse;
|
|
|
|
static ArgDesc argDesc[] = {
|
|
{"-g", argStringDummy, NULL, 0,
|
|
"initial window geometry"},
|
|
{"-geometry", argStringDummy, NULL, 0,
|
|
"initial window geometry"},
|
|
{"-title", argStringDummy, NULL, 0,
|
|
"window title"},
|
|
{"-cmap", argFlagDummy, NULL, 0,
|
|
"install a private colormap"},
|
|
{"-rgb", argIntDummy, NULL, 0,
|
|
"biggest RGB cube to allocate (default is 5)"},
|
|
{"-rv", argFlagDummy, NULL, 0,
|
|
"reverse video"},
|
|
{"-papercolor", argStringDummy, NULL, 0,
|
|
"color of paper background"},
|
|
{"-z", argString, initialZoomStr, sizeof(initialZoomStr),
|
|
"initial zoom level (-5..5, page, width)"},
|
|
#if HAVE_T1LIB_H
|
|
{"-t1lib", argString, t1libControlStr, sizeof(t1libControlStr),
|
|
"t1lib font rasterizer control: none, plain, low, high"},
|
|
#endif
|
|
#if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H
|
|
{"-freetype", argString, freetypeControlStr, sizeof(freetypeControlStr),
|
|
"FreeType font rasterizer control: none, plain, low, high"},
|
|
#endif
|
|
{"-ps", argString, psFileArg, sizeof(psFileArg),
|
|
"default PostScript file name or command"},
|
|
{"-paper", argString, paperSize, sizeof(paperSize),
|
|
"paper size (letter, legal, A4, A3)"},
|
|
{"-paperw", argInt, &paperWidth, 0,
|
|
"paper width, in points"},
|
|
{"-paperh", argInt, &paperHeight, 0,
|
|
"paper height, in points"},
|
|
{"-level1", argFlag, &level1, 0,
|
|
"generate Level 1 PostScript"},
|
|
{"-enc", argString, textEncName, sizeof(textEncName),
|
|
"output text encoding name"},
|
|
{"-eol", argString, textEOL, sizeof(textEOL),
|
|
"output end-of-line convention (unix, dos, or mac)"},
|
|
{"-opw", argString, ownerPassword, sizeof(ownerPassword),
|
|
"owner password (for encrypted files)"},
|
|
{"-upw", argString, userPassword, sizeof(userPassword),
|
|
"user password (for encrypted files)"},
|
|
{"-fullscreen", argFlag, &fullScreen, 0,
|
|
"run in full-screen (presentation) mode"},
|
|
{"-remote", argString, remoteName + 5, sizeof(remoteName) - 5,
|
|
"start/contact xpdf remote server with specified name"},
|
|
{"-raise", argFlag, &doRemoteRaise, 0,
|
|
"raise xpdf remote server window (with -remote only)"},
|
|
{"-quit", argFlag, &doRemoteQuit, 0,
|
|
"kill xpdf remote server (with -remote only)"},
|
|
{"-cmd", argFlag, &printCommands, 0,
|
|
"print commands as they're executed"},
|
|
{"-q", argFlag, &quiet, 0,
|
|
"don't print any messages or errors"},
|
|
{"-cfg", argString, cfgFileName, sizeof(cfgFileName),
|
|
"configuration file to use in place of .xpdfrc"},
|
|
{"-v", argFlag, &printVersion, 0,
|
|
"print copyright and version info"},
|
|
{"-h", argFlag, &printHelp, 0,
|
|
"print usage information"},
|
|
{"-help", argFlag, &printHelp, 0,
|
|
"print usage information"},
|
|
{"--help", argFlag, &printHelp, 0,
|
|
"print usage information"},
|
|
{"-?", argFlag, &printHelp, 0,
|
|
"print usage information"},
|
|
{NULL}
|
|
};
|
|
|
|
static XrmOptionDescRec opts[] = {
|
|
{"-display", ".display", XrmoptionSepArg, NULL},
|
|
{"-foreground", ".foreground", XrmoptionSepArg, NULL},
|
|
{"-fg", ".foreground", XrmoptionSepArg, NULL},
|
|
{"-background", ".background", XrmoptionSepArg, NULL},
|
|
{"-bg", ".background", XrmoptionSepArg, NULL},
|
|
{"-geometry", ".geometry", XrmoptionSepArg, NULL},
|
|
{"-g", ".geometry", XrmoptionSepArg, NULL},
|
|
{"-font", ".font", XrmoptionSepArg, NULL},
|
|
{"-fn", ".font", XrmoptionSepArg, NULL},
|
|
{"-title", ".title", XrmoptionSepArg, NULL},
|
|
{"-cmap", ".installCmap", XrmoptionNoArg, (XPointer)"on"},
|
|
{"-rgb", ".rgbCubeSize", XrmoptionSepArg, NULL},
|
|
{"-rv", ".reverseVideo", XrmoptionNoArg, (XPointer)"true"},
|
|
{"-papercolor", ".paperColor", XrmoptionSepArg, NULL},
|
|
{NULL}
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
// global variables
|
|
//------------------------------------------------------------------------
|
|
|
|
// zoom factor is 1.2 (similar to DVI magsteps)
|
|
#define minZoom -5
|
|
#define maxZoom 5
|
|
#define zoomPage 100
|
|
#define zoomWidth 101
|
|
#define defZoom 1
|
|
static int zoomDPI[maxZoom - minZoom + 1] = {
|
|
29, 35, 42, 50, 60,
|
|
72,
|
|
86, 104, 124, 149, 179
|
|
};
|
|
|
|
static PDFDoc *doc;
|
|
|
|
static LTKOutputDev *out;
|
|
|
|
static int page;
|
|
static int zoom;
|
|
static int rotate;
|
|
static GBool quit;
|
|
|
|
static time_t modTime; // last modification time of PDF file
|
|
|
|
static LinkAction *linkAction; // mouse pointer is over this link
|
|
static int // coordinates of current selection:
|
|
selectXMin, selectYMin, // (xMin==xMax || yMin==yMax) means there
|
|
selectXMax, selectYMax; // is no selection
|
|
static GBool lastDragLeft; // last dragged selection edge was left/right
|
|
static GBool lastDragTop; // last dragged selection edge was top/bottom
|
|
static int panMX, panMY; // last mouse position for pan
|
|
|
|
struct History {
|
|
GString *fileName;
|
|
int page;
|
|
};
|
|
#define historySize 50
|
|
static History // page history queue
|
|
history[historySize];
|
|
static int historyCur; // currently displayed page
|
|
static int historyBLen; // number of valid entries backward from
|
|
// current entry
|
|
static int historyFLen; // number of valid entries forward from
|
|
// current entry
|
|
|
|
static GString *psFileName;
|
|
static int psFirstPage, psLastPage;
|
|
|
|
static GString *fileReqDir; // current directory for file requesters
|
|
|
|
static GString *urlCommand; // command to execute for URI links
|
|
|
|
static GString *windowTitle; // window title string
|
|
|
|
static LTKApp *app;
|
|
static Display *display;
|
|
static LTKWindow *win;
|
|
static LTKMenu *zoomMenu;
|
|
static LTKScrollingCanvas *canvas;
|
|
static LTKScrollbar *hScrollbar, *vScrollbar;
|
|
static LTKTextIn *pageNumText;
|
|
static LTKLabel *numPagesLabel;
|
|
static LTKLabel *linkLabel;
|
|
static LTKMenuButton *zoomMenuBtn;
|
|
static LTKWindow *aboutWin;
|
|
static LTKList *aboutList;
|
|
static LTKScrollbar *aboutHScrollbar, *aboutVScrollbar;
|
|
static LTKWindow *psDialog;
|
|
static LTKWindow *openDialog;
|
|
static LTKWindow *saveDialog;
|
|
static LTKWindow *findWin;
|
|
static LTKTextIn *findTextIn;
|
|
static Atom remoteAtom;
|
|
static GC selectGC;
|
|
|
|
//------------------------------------------------------------------------
|
|
// GUI includes
|
|
//------------------------------------------------------------------------
|
|
|
|
#include "xpdfIcon.xpm"
|
|
#include "leftArrow.xbm"
|
|
#include "dblLeftArrow.xbm"
|
|
#include "rightArrow.xbm"
|
|
#include "dblRightArrow.xbm"
|
|
#include "backArrow.xbm"
|
|
#include "forwardArrow.xbm"
|
|
#include "find.xbm"
|
|
#include "postscript.xbm"
|
|
#include "about.xbm"
|
|
#include "xpdf-ltk.h"
|
|
|
|
//------------------------------------------------------------------------
|
|
// main program
|
|
//------------------------------------------------------------------------
|
|
|
|
int main(int argc, char *argv[]) {
|
|
Window xwin;
|
|
XGCValues gcValues;
|
|
char cmd[remoteCmdLength];
|
|
LTKMenu *menu;
|
|
GString *name;
|
|
GString *title;
|
|
GString *initialZoom;
|
|
GBool reverseVideo;
|
|
unsigned long paperColor;
|
|
GBool installCmap;
|
|
int rgbCubeSize;
|
|
int pg;
|
|
GString *destName;
|
|
LinkDest *dest;
|
|
int x, y;
|
|
Guint width, height;
|
|
double width1, height1;
|
|
GBool ok;
|
|
char s[20];
|
|
int i;
|
|
int ret;
|
|
|
|
// initialize
|
|
app = NULL;
|
|
win = NULL;
|
|
out = NULL;
|
|
remoteAtom = None;
|
|
doc = NULL;
|
|
psFileName = NULL;
|
|
fileReqDir = getCurrentDir();
|
|
ret = 0;
|
|
|
|
// parse args
|
|
ok = parseArgs(argDesc, &argc, argv);
|
|
|
|
// read config file
|
|
globalParams = new GlobalParams(cfgFileName);
|
|
if (psFileArg[0]) {
|
|
globalParams->setPSFile(psFileArg);
|
|
}
|
|
if (paperSize[0]) {
|
|
if (!globalParams->setPSPaperSize(paperSize)) {
|
|
fprintf(stderr, "Invalid paper size\n");
|
|
}
|
|
} else {
|
|
if (paperWidth) {
|
|
globalParams->setPSPaperWidth(paperWidth);
|
|
}
|
|
if (paperHeight) {
|
|
globalParams->setPSPaperHeight(paperHeight);
|
|
}
|
|
}
|
|
if (level1) {
|
|
globalParams->setPSLevel(psLevel1);
|
|
}
|
|
if (textEncName[0]) {
|
|
globalParams->setTextEncoding(textEncName);
|
|
}
|
|
if (textEOL[0]) {
|
|
if (!globalParams->setTextEOL(textEOL)) {
|
|
fprintf(stderr, "Bad '-eol' value on command line\n");
|
|
}
|
|
}
|
|
if (initialZoomStr[0]) {
|
|
globalParams->setInitialZoom(initialZoomStr);
|
|
}
|
|
if (t1libControlStr[0]) {
|
|
if (!globalParams->setT1libControl(t1libControlStr)) {
|
|
fprintf(stderr, "Bad '-t1lib' value on command line\n");
|
|
}
|
|
}
|
|
if (freetypeControlStr[0]) {
|
|
if (!globalParams->setFreeTypeControl(freetypeControlStr)) {
|
|
fprintf(stderr, "Bad '-freetype' value on command line\n");
|
|
}
|
|
}
|
|
if (quiet) {
|
|
globalParams->setErrQuiet(quiet);
|
|
}
|
|
|
|
// create LTKApp (and parse X-related args)
|
|
app = new LTKApp("xpdf", "Xpdf", opts, &argc, argv);
|
|
app->setKillCbk(&killCbk);
|
|
display = app->getDisplay();
|
|
|
|
// check command line
|
|
if (doRemoteRaise)
|
|
ok = ok && remoteName[5] && !doRemoteQuit && argc >= 1 && argc <= 3;
|
|
else if (doRemoteQuit)
|
|
ok = ok && remoteName[5] && argc == 1;
|
|
else
|
|
ok = ok && argc >= 1 && argc <= 3;
|
|
if (!ok || printVersion || printHelp) {
|
|
fprintf(stderr, "xpdf version %s\n", xpdfVersion);
|
|
fprintf(stderr, "%s\n", xpdfCopyright);
|
|
if (!printVersion) {
|
|
printUsage("xpdf", "[<PDF-file> [<page> | +<dest>]]", argDesc);
|
|
}
|
|
ret = 1;
|
|
goto done2;
|
|
}
|
|
if (argc >= 2) {
|
|
name = new GString(argv[1]);
|
|
} else {
|
|
name = NULL;
|
|
}
|
|
pg = 1;
|
|
destName = NULL;
|
|
if (argc == 3) {
|
|
if (argv[2][0] == '+') {
|
|
destName = new GString(&argv[2][1]);
|
|
} else {
|
|
pg = atoi(argv[2]);
|
|
}
|
|
}
|
|
|
|
// look for already-running remote server
|
|
if (remoteName[5]) {
|
|
remoteAtom = XInternAtom(display, remoteName, False);
|
|
xwin = XGetSelectionOwner(display, remoteAtom);
|
|
if (xwin != None) {
|
|
if (name) {
|
|
if (destName) {
|
|
sprintf(cmd, "%c +%.256s %.200s", doRemoteRaise ? 'D' : 'd',
|
|
destName->getCString(), name->getCString());
|
|
delete destName;
|
|
} else {
|
|
sprintf(cmd, "%c %d %.200s", doRemoteRaise ? 'D' : 'd',
|
|
pg, name->getCString());
|
|
}
|
|
XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8,
|
|
PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
|
|
delete name;
|
|
} else if (doRemoteRaise) {
|
|
XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8,
|
|
PropModeReplace, (Guchar *)"r", 2);
|
|
} else if (doRemoteQuit) {
|
|
XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8,
|
|
PropModeReplace, (Guchar *)"q", 2);
|
|
}
|
|
goto done2;
|
|
}
|
|
if (doRemoteQuit) {
|
|
if (destName) {
|
|
delete destName;
|
|
}
|
|
goto done2;
|
|
}
|
|
}
|
|
|
|
// no history yet
|
|
historyCur = historySize - 1;
|
|
historyBLen = historyFLen = 0;
|
|
for (i = 0; i < historySize; ++i)
|
|
history[i].fileName = NULL;
|
|
|
|
// open PDF file
|
|
if (name) {
|
|
if (!loadFile(name)) {
|
|
ret = 1;
|
|
goto done1;
|
|
}
|
|
delete fileReqDir;
|
|
fileReqDir = makePathAbsolute(grabPath(name->getCString()));
|
|
}
|
|
|
|
// check for legal page number
|
|
if (doc && (pg < 1 || pg > doc->getNumPages())) {
|
|
pg = 1;
|
|
}
|
|
|
|
// create window
|
|
menu = makeMenu();
|
|
if (fullScreen) {
|
|
zoomMenu = NULL;
|
|
win = makeFullScreenWindow(app);
|
|
win->setDecorated(gFalse);
|
|
} else {
|
|
zoomMenu = makeZoomMenu();
|
|
win = makeWindow(app);
|
|
}
|
|
win->setMenu(menu);
|
|
canvas = (LTKScrollingCanvas *)win->findWidget("canvas");
|
|
hScrollbar = (LTKScrollbar *)win->findWidget("hScrollbar");
|
|
vScrollbar = (LTKScrollbar *)win->findWidget("vScrollbar");
|
|
pageNumText = (LTKTextIn *)win->findWidget("pageNum");
|
|
numPagesLabel = (LTKLabel *)win->findWidget("numPages");
|
|
linkLabel = (LTKLabel *)win->findWidget("link");
|
|
zoomMenuBtn = (LTKMenuButton *)win->findWidget("zoom");
|
|
win->setKeyCbk(&keyPressCbk);
|
|
win->setLayoutCbk(&layoutCbk);
|
|
canvas->setButtonPressCbk(&buttonPressCbk);
|
|
canvas->setButtonReleaseCbk(&buttonReleaseCbk);
|
|
canvas->setMouseMoveCbk(&mouseMoveCbk);
|
|
canvas->setMouseDragCbk(&mouseDragCbk);
|
|
if (!fullScreen) {
|
|
hScrollbar->setRepeatPeriod(0);
|
|
vScrollbar->setRepeatPeriod(0);
|
|
}
|
|
|
|
// get parameters
|
|
urlCommand = globalParams->getURLCommand();
|
|
|
|
// get X resources
|
|
windowTitle = app->getStringResource("title", NULL);
|
|
installCmap = app->getBoolResource("installCmap", gFalse);
|
|
if (installCmap) {
|
|
win->setInstallCmap(gTrue);
|
|
}
|
|
rgbCubeSize = app->getIntResource("rgbCubeSize", defaultRGBCube);
|
|
reverseVideo = app->getBoolResource("reverseVideo", gFalse);
|
|
paperColor = app->getColorResource(
|
|
"paperColor",
|
|
reverseVideo ? (char *)"black" : (char *)"white",
|
|
reverseVideo ? BlackPixel(display, app->getScreenNum())
|
|
: WhitePixel(display, app->getScreenNum()),
|
|
NULL);
|
|
if (fullScreen) {
|
|
zoom = zoomPage;
|
|
} else {
|
|
initialZoom = globalParams->getInitialZoom();
|
|
if (!initialZoom->cmp("page")) {
|
|
zoom = zoomPage;
|
|
i = maxZoom - minZoom + 2;
|
|
} else if (!initialZoom->cmp("width")) {
|
|
zoom = zoomWidth;
|
|
i = maxZoom - minZoom + 3;
|
|
} else {
|
|
zoom = atoi(initialZoom->getCString());
|
|
if (zoom < minZoom) {
|
|
zoom = minZoom;
|
|
} else if (zoom > maxZoom) {
|
|
zoom = maxZoom;
|
|
}
|
|
i = zoom - minZoom;
|
|
}
|
|
zoomMenuBtn->setInitialMenuItem(zoomMenu->getItem(i));
|
|
}
|
|
viKeys = app->getBoolResource("viKeys", gFalse);
|
|
|
|
// get geometry
|
|
if (fullScreen) {
|
|
x = y = 0;
|
|
width = app->getDisplayWidth();
|
|
height = app->getDisplayHeight();
|
|
} else {
|
|
x = y = -1;
|
|
width = height = 0;
|
|
app->getGeometryResource("geometry", &x, &y, &width, &height);
|
|
if (width == 0 || height == 0) {
|
|
if (!doc || doc->getNumPages() == 0) {
|
|
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 = (int)((width1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5);
|
|
height = (int)((height1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5);
|
|
} else {
|
|
width = (int)((width1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
|
|
height = (int)((height1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
|
|
}
|
|
width += 28;
|
|
height += 56;
|
|
if (width > (Guint)app->getDisplayWidth() - 100) {
|
|
width = app->getDisplayWidth() - 100;
|
|
}
|
|
if (height > (Guint)app->getDisplayHeight() - 100) {
|
|
height = app->getDisplayHeight() - 100;
|
|
}
|
|
}
|
|
}
|
|
|
|
// finish setting up window
|
|
if (!fullScreen) {
|
|
sprintf(s, "of %d", doc ? doc->getNumPages() : 0);
|
|
numPagesLabel->setText(s);
|
|
}
|
|
if (windowTitle) {
|
|
title = windowTitle->copy();
|
|
} else if (name) {
|
|
title = new GString("xpdf: ");
|
|
title->append(name);
|
|
} else {
|
|
title = new GString("xpdf");
|
|
}
|
|
win->setTitle(title);
|
|
win->layout(x, y, width, height);
|
|
win->map();
|
|
aboutWin = NULL;
|
|
psDialog = NULL;
|
|
openDialog = NULL;
|
|
saveDialog = NULL;
|
|
findWin = NULL;
|
|
gcValues.foreground = BlackPixel(display, win->getScreenNum()) ^
|
|
WhitePixel(display, win->getScreenNum());
|
|
gcValues.function = GXxor;
|
|
selectGC = XCreateGC(display, win->getXWindow(),
|
|
GCForeground | GCFunction, &gcValues);
|
|
|
|
// set up remote server
|
|
if (remoteAtom != None) {
|
|
win->setPropChangeCbk(&propChangeCbk);
|
|
xwin = win->getXWindow();
|
|
XSetSelectionOwner(display, remoteAtom, xwin, CurrentTime);
|
|
}
|
|
|
|
// create output device
|
|
out = new LTKOutputDev(win, reverseVideo, paperColor,
|
|
installCmap, rgbCubeSize, !fullScreen);
|
|
out->startDoc(doc ? doc->getXRef() : (XRef *)NULL);
|
|
|
|
// display first page
|
|
if (destName) {
|
|
if (doc) {
|
|
if ((dest = doc->findDest(destName))) {
|
|
displayDest(dest, zoom, 0, gTrue);
|
|
delete dest;
|
|
} else {
|
|
error(-1, "Unknown named destination '%s'", destName->getCString());
|
|
displayPage(1, zoom, 0, gTrue);
|
|
}
|
|
}
|
|
delete destName;
|
|
} else {
|
|
displayPage(pg, zoom, 0, gTrue);
|
|
}
|
|
|
|
// event loop
|
|
quit = gFalse;
|
|
do {
|
|
app->doEvent(gTrue);
|
|
} while (!quit);
|
|
|
|
done1:
|
|
// release remote control atom
|
|
if (remoteAtom != None)
|
|
XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
|
|
|
|
done2:
|
|
// free stuff
|
|
if (out) {
|
|
delete out;
|
|
}
|
|
if (win) {
|
|
delete win;
|
|
}
|
|
if (aboutWin) {
|
|
delete aboutWin;
|
|
}
|
|
if (findWin) {
|
|
delete findWin;
|
|
}
|
|
if (app) {
|
|
delete app;
|
|
}
|
|
if (doc) {
|
|
delete doc;
|
|
}
|
|
if (psFileName) {
|
|
delete psFileName;
|
|
}
|
|
if (fileReqDir) {
|
|
delete fileReqDir;
|
|
}
|
|
if (windowTitle) {
|
|
delete windowTitle;
|
|
}
|
|
for (i = 0; i < historySize; ++i) {
|
|
if (history[i].fileName) {
|
|
delete history[i].fileName;
|
|
}
|
|
}
|
|
delete globalParams;
|
|
|
|
// check for memory leaks
|
|
Object::memCheck(stderr);
|
|
gMemReport(stderr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// loadFile / displayPage / displayDest
|
|
//------------------------------------------------------------------------
|
|
|
|
static GBool loadFile(GString *fileName) {
|
|
GString *title;
|
|
PDFDoc *newDoc;
|
|
GString *ownerPW, *userPW;
|
|
char s[20];
|
|
char *p;
|
|
|
|
// busy cursor
|
|
if (win)
|
|
win->setBusyCursor(gTrue);
|
|
|
|
// open PDF file
|
|
if (ownerPassword[0]) {
|
|
ownerPW = new GString(ownerPassword);
|
|
} else {
|
|
ownerPW = NULL;
|
|
}
|
|
if (userPassword[0]) {
|
|
userPW = new GString(userPassword);
|
|
} else {
|
|
userPW = NULL;
|
|
}
|
|
newDoc = new PDFDoc(fileName, ownerPW, userPW, printCommands);
|
|
if (userPW) {
|
|
delete userPW;
|
|
}
|
|
if (ownerPW) {
|
|
delete ownerPW;
|
|
}
|
|
if (!newDoc->isOk()) {
|
|
delete newDoc;
|
|
if (win)
|
|
win->setBusyCursor(gFalse);
|
|
return gFalse;
|
|
}
|
|
|
|
// 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(fileName->getCString());
|
|
|
|
// init PostScript output params
|
|
if (psFileName)
|
|
delete psFileName;
|
|
if (globalParams->getPSFile()) {
|
|
psFileName = globalParams->getPSFile()->copy();
|
|
} else {
|
|
p = fileName->getCString() + fileName->getLength() - 4;
|
|
if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF"))
|
|
psFileName = new GString(fileName->getCString(),
|
|
fileName->getLength() - 4);
|
|
else
|
|
psFileName = fileName->copy();
|
|
psFileName->append(".ps");
|
|
}
|
|
psFirstPage = 1;
|
|
psLastPage = doc->getNumPages();
|
|
|
|
// set up title, number-of-pages display; back to normal cursor
|
|
if (win) {
|
|
if (!windowTitle) {
|
|
title = new GString("xpdf: ");
|
|
title->append(fileName);
|
|
win->setTitle(title);
|
|
}
|
|
if (!fullScreen) {
|
|
sprintf(s, "of %d", doc->getNumPages());
|
|
numPagesLabel->setText(s);
|
|
}
|
|
win->setBusyCursor(gFalse);
|
|
}
|
|
|
|
// done
|
|
return gTrue;
|
|
}
|
|
|
|
static void displayPage(int pageA, int zoomA, int rotateA, GBool addToHist) {
|
|
time_t modTime1;
|
|
double hDPI, vDPI, dpi;
|
|
int rot;
|
|
char s[20];
|
|
History *h;
|
|
|
|
// check for document
|
|
if (!doc || doc->getNumPages() == 0)
|
|
return;
|
|
|
|
// check for changes to the file
|
|
modTime1 = getModTime(doc->getFileName()->getCString());
|
|
if (modTime1 != modTime) {
|
|
if (loadFile(doc->getFileName()->copy())) {
|
|
if (pageA > doc->getNumPages()) {
|
|
pageA = doc->getNumPages();
|
|
}
|
|
}
|
|
modTime = modTime1;
|
|
}
|
|
|
|
// busy cursor
|
|
if (win)
|
|
win->setBusyCursor(gTrue);
|
|
|
|
// new page/zoom/rotate values
|
|
page = pageA;
|
|
zoom = zoomA;
|
|
rotate = rotateA;
|
|
|
|
// initialize mouse-related stuff
|
|
linkAction = NULL;
|
|
win->setDefaultCursor();
|
|
if (!fullScreen) {
|
|
linkLabel->setText(NULL);
|
|
}
|
|
selectXMin = selectXMax = 0;
|
|
selectYMin = selectYMax = 0;
|
|
lastDragLeft = lastDragTop = gTrue;
|
|
|
|
// draw the page
|
|
rot = rotate + doc->getPageRotate(page);
|
|
if (rot >= 360)
|
|
rot -= 360;
|
|
else if (rotate < 0)
|
|
rot += 360;
|
|
if (fullScreen) {
|
|
if (rot == 90 || rot == 270) {
|
|
hDPI = (win->getWidth() / doc->getPageHeight(page)) * 72;
|
|
vDPI = (win->getHeight() / doc->getPageWidth(page)) * 72;
|
|
} else {
|
|
hDPI = (win->getWidth() / doc->getPageWidth(page)) * 72;
|
|
vDPI = (win->getHeight() / doc->getPageHeight(page)) * 72;
|
|
}
|
|
dpi = (hDPI < vDPI) ? hDPI : vDPI;
|
|
} else if (zoom == zoomPage) {
|
|
if (rot == 90 || rot == 270) {
|
|
hDPI = (canvas->getWidth() / doc->getPageHeight(page)) * 72;
|
|
vDPI = (canvas->getHeight() / doc->getPageWidth(page)) * 72;
|
|
} else {
|
|
hDPI = (canvas->getWidth() / doc->getPageWidth(page)) * 72;
|
|
vDPI = (canvas->getHeight() / doc->getPageHeight(page)) * 72;
|
|
}
|
|
dpi = (hDPI < vDPI) ? hDPI : vDPI;
|
|
} else if (zoom == zoomWidth) {
|
|
if (rot == 90 || rot == 270) {
|
|
dpi = (canvas->getWidth() / doc->getPageHeight(page)) * 72;
|
|
} else {
|
|
dpi = (canvas->getWidth() / doc->getPageWidth(page)) * 72;
|
|
}
|
|
} else {
|
|
dpi = zoomDPI[zoom - minZoom];
|
|
}
|
|
doc->displayPage(out, page, dpi, rotate, gTrue);
|
|
updateScrollbars();
|
|
|
|
// update page number display
|
|
if (!fullScreen) {
|
|
sprintf(s, "%d", page);
|
|
pageNumText->setText(s);
|
|
}
|
|
|
|
// add to history
|
|
if (addToHist) {
|
|
if (++historyCur == historySize)
|
|
historyCur = 0;
|
|
h = &history[historyCur];
|
|
if (h->fileName)
|
|
delete h->fileName;
|
|
h->fileName = doc->getFileName()->copy();
|
|
h->page = page;
|
|
if (historyBLen < historySize)
|
|
++historyBLen;
|
|
historyFLen = 0;
|
|
}
|
|
|
|
// back to regular cursor
|
|
win->setBusyCursor(gFalse);
|
|
}
|
|
|
|
static void 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, addToHist);
|
|
}
|
|
|
|
if (fullScreen) {
|
|
return;
|
|
}
|
|
switch (dest->getKind()) {
|
|
case destXYZ:
|
|
out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
|
|
if (dest->getChangeLeft() || dest->getChangeTop()) {
|
|
if (dest->getChangeLeft()) {
|
|
hScrollbar->setPos(dx, canvas->getWidth());
|
|
}
|
|
if (dest->getChangeTop()) {
|
|
vScrollbar->setPos(dy, canvas->getHeight());
|
|
}
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
//~ what is the zoom parameter?
|
|
break;
|
|
case destFit:
|
|
case destFitB:
|
|
//~ do fit
|
|
hScrollbar->setPos(0, canvas->getWidth());
|
|
vScrollbar->setPos(0, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
case destFitH:
|
|
case destFitBH:
|
|
//~ do fit
|
|
out->cvtUserToDev(0, dest->getTop(), &dx, &dy);
|
|
hScrollbar->setPos(0, canvas->getWidth());
|
|
vScrollbar->setPos(dy, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
case destFitV:
|
|
case destFitBV:
|
|
//~ do fit
|
|
out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy);
|
|
hScrollbar->setPos(dx, canvas->getWidth());
|
|
vScrollbar->setPos(0, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
case destFitR:
|
|
//~ do fit
|
|
out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
|
|
hScrollbar->setPos(dx, canvas->getWidth());
|
|
vScrollbar->setPos(dy, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// key press and menu callbacks
|
|
//------------------------------------------------------------------------
|
|
|
|
static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers,
|
|
char *s, int n) {
|
|
if (n > 0) {
|
|
switch (s[0]) {
|
|
case 'O':
|
|
case 'o':
|
|
mapOpenDialog();
|
|
break;
|
|
case 'R':
|
|
case 'r':
|
|
reloadCbk();
|
|
break;
|
|
case 'F':
|
|
case 'f':
|
|
mapFindWin();
|
|
break;
|
|
case 'N':
|
|
case 'n':
|
|
gotoNextPage(1, !(modifiers & Mod5Mask));
|
|
break;
|
|
case 'P':
|
|
case 'p':
|
|
gotoPrevPage(1, !(modifiers & Mod5Mask), gFalse);
|
|
break;
|
|
case ' ':
|
|
if (fullScreen ||
|
|
vScrollbar->getPos() >=
|
|
canvas->getRealHeight() - canvas->getHeight()) {
|
|
gotoNextPage(1, gTrue);
|
|
} else {
|
|
vScrollbar->setPos(vScrollbar->getPos() + canvas->getHeight(),
|
|
canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case '\b': // bs
|
|
case '\177': // del
|
|
if (fullScreen) {
|
|
gotoPrevPage(1, gTrue, gFalse);
|
|
} else if (vScrollbar->getPos() == 0) {
|
|
gotoPrevPage(1, gFalse, gTrue);
|
|
} else {
|
|
vScrollbar->setPos(vScrollbar->getPos() - canvas->getHeight(),
|
|
canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case 'v':
|
|
forwardCbk(NULL, 0, gTrue);
|
|
break;
|
|
case 'b':
|
|
backCbk(NULL, 0, gTrue);
|
|
break;
|
|
case 'g':
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
pageNumText->selectAll();
|
|
pageNumText->activate(gTrue);
|
|
break;
|
|
case 'h': // vi-style left
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
if (viKeys) {
|
|
hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case 'l': // vi-style right
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
if (viKeys) {
|
|
hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case 'k': // vi-style up
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
if (viKeys) {
|
|
vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case 'j': // vi-style down
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
if (viKeys) {
|
|
vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case '0':
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
if (zoom != defZoom) {
|
|
zoomMenuBtn->setMenuItem(zoomMenu->getItem(defZoom - minZoom));
|
|
}
|
|
break;
|
|
case '+':
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
if (zoom >= minZoom && zoom < maxZoom) {
|
|
zoomMenuBtn->setMenuItem(zoomMenu->getItem(zoom + 1 - minZoom));
|
|
}
|
|
break;
|
|
case '-':
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
if (zoom > minZoom && zoom <= maxZoom) {
|
|
zoomMenuBtn->setMenuItem(zoomMenu->getItem(zoom - 1 - minZoom));
|
|
}
|
|
break;
|
|
case 'z':
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
zoomMenuBtn->setMenuItem(zoomMenu->getItem(maxZoom - minZoom + 2));
|
|
break;
|
|
case 'w':
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
zoomMenuBtn->setMenuItem(zoomMenu->getItem(maxZoom - minZoom + 3));
|
|
break;
|
|
case '\014': // ^L
|
|
win->redraw();
|
|
displayPage(page, zoom, rotate, gFalse);
|
|
break;
|
|
case 'Q':
|
|
case 'q':
|
|
quitCbk(NULL, 0, gTrue);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (key) {
|
|
case XK_Home:
|
|
case XK_KP_Home:
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
hScrollbar->setPos(0, canvas->getWidth());
|
|
vScrollbar->setPos(0, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
case XK_End:
|
|
case XK_KP_End:
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
hScrollbar->setPos(canvas->getRealWidth() - canvas->getWidth(),
|
|
canvas->getWidth());
|
|
vScrollbar->setPos(canvas->getRealHeight() - canvas->getHeight(),
|
|
canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
case XK_Page_Up:
|
|
case XK_KP_Page_Up:
|
|
if (fullScreen) {
|
|
gotoPrevPage(1, gTrue, gFalse);
|
|
} else if (vScrollbar->getPos() == 0) {
|
|
gotoPrevPage(1, gFalse, gTrue);
|
|
} else {
|
|
vScrollbar->setPos(vScrollbar->getPos() - canvas->getHeight(),
|
|
canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case XK_Page_Down:
|
|
case XK_KP_Page_Down:
|
|
if (fullScreen ||
|
|
vScrollbar->getPos() >=
|
|
canvas->getRealHeight() - canvas->getHeight()) {
|
|
gotoNextPage(1, gTrue);
|
|
} else {
|
|
vScrollbar->setPos(vScrollbar->getPos() + canvas->getHeight(),
|
|
canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case XK_Left:
|
|
case XK_KP_Left:
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
case XK_Right:
|
|
case XK_KP_Right:
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
case XK_Up:
|
|
case XK_KP_Up:
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
case XK_Down:
|
|
case XK_KP_Down:
|
|
if (fullScreen) {
|
|
break;
|
|
}
|
|
vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void menuCbk(LTKMenuItem *item) {
|
|
int r;
|
|
|
|
switch (item->getItemNum()) {
|
|
case menuOpen:
|
|
mapOpenDialog();
|
|
break;
|
|
case menuReload:
|
|
reloadCbk();
|
|
break;
|
|
case menuSavePDF:
|
|
if (doc)
|
|
mapSaveDialog();
|
|
break;
|
|
case menuRotateCCW:
|
|
if (doc) {
|
|
r = (rotate == 0) ? 270 : rotate - 90;
|
|
displayPage(page, zoom, r, gFalse);
|
|
}
|
|
break;
|
|
case menuRotateCW:
|
|
if (doc) {
|
|
r = (rotate == 270) ? 0 : rotate + 90;
|
|
displayPage(page, zoom, r, gFalse);
|
|
}
|
|
break;
|
|
case menuQuit:
|
|
quit = gTrue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// mouse callbacks
|
|
//------------------------------------------------------------------------
|
|
|
|
static void buttonPressCbk(LTKWidget *canvas1, int n,
|
|
int mx, int my, int button, GBool dblClick) {
|
|
if (!doc || doc->getNumPages() == 0) {
|
|
return;
|
|
}
|
|
switch (button) {
|
|
case 1:
|
|
setSelection(mx, my, mx, my);
|
|
break;
|
|
case 2:
|
|
if (!fullScreen) {
|
|
panMX = mx - hScrollbar->getPos();
|
|
panMY = my - vScrollbar->getPos();
|
|
}
|
|
break;
|
|
case 4: // mouse wheel up
|
|
if (fullScreen) {
|
|
gotoPrevPage(1, gTrue, gFalse);
|
|
} else if (vScrollbar->getPos() == 0) {
|
|
gotoPrevPage(1, gFalse, gTrue);
|
|
} else {
|
|
vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case 5: // mouse wheel down
|
|
if (fullScreen ||
|
|
vScrollbar->getPos() >=
|
|
canvas->getRealHeight() - canvas->getHeight()) {
|
|
gotoNextPage(1, gTrue);
|
|
} else {
|
|
vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
break;
|
|
case 6: // second mouse wheel right
|
|
if (fullScreen) {
|
|
return;
|
|
}
|
|
hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
case 7: // second mouse wheel left
|
|
if (fullScreen) {
|
|
return;
|
|
}
|
|
hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void buttonReleaseCbk(LTKWidget *canvas1, int n,
|
|
int mx, int my, int button, GBool click) {
|
|
GString *s;
|
|
|
|
if (!doc || doc->getNumPages() == 0)
|
|
return;
|
|
|
|
if (button == 1) {
|
|
// selection
|
|
if (selectXMin < selectXMax && selectYMin < selectYMax) {
|
|
#ifndef NO_TEXT_SELECT
|
|
#ifdef ENFORCE_PERMISSIONS
|
|
if (doc->okToCopy()) {
|
|
#endif
|
|
s = out->getText(selectXMin, selectYMin, selectXMax, selectYMax);
|
|
win->setSelection(NULL, s);
|
|
#ifdef ENFORCE_PERMISSIONS
|
|
} else {
|
|
error(-1, "Copying of text from this document is not allowed.");
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
// link
|
|
} else {
|
|
setSelection(mx, my, mx, my);
|
|
doLink(mx, my);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void doLink(int mx, int my) {
|
|
LinkActionKind kind;
|
|
LinkAction *action = NULL;
|
|
LinkDest *dest;
|
|
GString *namedDest;
|
|
char *s;
|
|
GString *fileName;
|
|
GString *actionName;
|
|
double x, y;
|
|
LTKButtonDialog *dialog;
|
|
int i;
|
|
|
|
// look for a link
|
|
out->cvtDevToUser(mx, my, &x, &y);
|
|
if ((action = doc->findLink(x, y))) {
|
|
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)) {
|
|
if (dest)
|
|
delete dest;
|
|
if (namedDest)
|
|
delete namedDest;
|
|
return;
|
|
}
|
|
}
|
|
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, 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))
|
|
return;
|
|
displayPage(1, zoom, rotate, 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
|
|
dialog = new LTKButtonDialog(win, "xpdf: Launch",
|
|
"Execute the command:",
|
|
fileName->getCString(),
|
|
NULL, "Ok", "Cancel");
|
|
if (dialog->go())
|
|
system(fileName->getCString());
|
|
delete dialog;
|
|
delete fileName;
|
|
}
|
|
break;
|
|
|
|
// URI action
|
|
case actionURI:
|
|
if (urlCommand) {
|
|
for (s = urlCommand->getCString(); *s; ++s) {
|
|
if (s[0] == '%' && s[1] == 's') {
|
|
break;
|
|
}
|
|
}
|
|
if (s) {
|
|
fileName = ((LinkURI *)action)->getURI()->copy();
|
|
// filter out any quote marks (' or ") to avoid a potential
|
|
// security hole
|
|
i = 0;
|
|
while (i < fileName->getLength()) {
|
|
if (fileName->getChar(i) == '"') {
|
|
fileName->del(i);
|
|
fileName->insert(i, "%22");
|
|
i += 3;
|
|
} else if (fileName->getChar(i) == '\'') {
|
|
fileName->del(i);
|
|
fileName->insert(i, "%27");
|
|
i += 3;
|
|
} else {
|
|
++i;
|
|
}
|
|
}
|
|
fileName->insert(0, urlCommand->getCString(),
|
|
s - urlCommand->getCString());
|
|
fileName->append(s+2);
|
|
} else {
|
|
fileName = urlCommand->copy();
|
|
}
|
|
#ifdef VMS
|
|
fileName->insert(0, "spawn/nowait ");
|
|
#elif defined(__EMX__)
|
|
fileName->insert(0, "start /min /n ");
|
|
#else
|
|
fileName->append(" &");
|
|
#endif
|
|
system(fileName->getCString());
|
|
delete fileName;
|
|
} else {
|
|
printf("URI: %s\n", ((LinkURI *)action)->getURI()->getCString());
|
|
}
|
|
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);
|
|
}
|
|
} else if (!actionName->cmp("LastPage")) {
|
|
if (page != doc->getNumPages()) {
|
|
displayPage(doc->getNumPages(), zoom, rotate, gTrue);
|
|
}
|
|
} else if (!actionName->cmp("GoBack")) {
|
|
backCbk(NULL, 0, gTrue);
|
|
} else if (!actionName->cmp("GoForward")) {
|
|
forwardCbk(NULL, 0, gTrue);
|
|
} else if (!actionName->cmp("Quit")) {
|
|
quitCbk(NULL, 0, gTrue);
|
|
} else {
|
|
error(-1, "Unknown named action: '%s'", actionName->getCString());
|
|
}
|
|
break;
|
|
|
|
// unknown action type
|
|
case actionUnknown:
|
|
error(-1, "Unknown link action type: '%s'",
|
|
((LinkUnknown *)action)->getAction()->getCString());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mouseMoveCbk(LTKWidget *widget, int widgetNum, int mx, int my) {
|
|
double x, y;
|
|
LinkAction *action;
|
|
char *s;
|
|
|
|
if (!doc || doc->getNumPages() == 0)
|
|
return;
|
|
out->cvtDevToUser(mx, my, &x, &y);
|
|
if ((action = doc->findLink(x, y))) {
|
|
if (action != linkAction) {
|
|
if (!linkAction) {
|
|
win->setCursor(XC_hand2);
|
|
}
|
|
linkAction = action;
|
|
if (!fullScreen) {
|
|
s = NULL;
|
|
switch (linkAction->getKind()) {
|
|
case actionGoTo:
|
|
s = "[internal link]";
|
|
break;
|
|
case actionGoToR:
|
|
s = ((LinkGoToR *)linkAction)->getFileName()->getCString();
|
|
break;
|
|
case actionLaunch:
|
|
s = ((LinkLaunch *)linkAction)->getFileName()->getCString();
|
|
break;
|
|
case actionURI:
|
|
s = ((LinkURI *)action)->getURI()->getCString();
|
|
break;
|
|
case actionNamed:
|
|
s = ((LinkNamed *)linkAction)->getName()->getCString();
|
|
break;
|
|
case actionUnknown:
|
|
s = "[unknown link]";
|
|
break;
|
|
}
|
|
linkLabel->setText(s);
|
|
}
|
|
}
|
|
} else {
|
|
if (linkAction) {
|
|
linkAction = NULL;
|
|
win->setDefaultCursor();
|
|
if (!fullScreen) {
|
|
linkLabel->setText(NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mouseDragCbk(LTKWidget *widget, int widgetNum,
|
|
int mx, int my, int button) {
|
|
int x, y;
|
|
int xMin, yMin, xMax, yMax;
|
|
|
|
// button 1: select
|
|
if (button == 1) {
|
|
|
|
// clip mouse coords
|
|
x = mx;
|
|
if (x < 0)
|
|
x = 0;
|
|
else if (x >= canvas->getRealWidth())
|
|
x = canvas->getRealWidth() - 1;
|
|
y = my;
|
|
if (y < 0)
|
|
y = 0;
|
|
else if (y >= canvas->getRealHeight())
|
|
y = canvas->getRealHeight() - 1;
|
|
|
|
// move appropriate edges of selection
|
|
if (lastDragLeft) {
|
|
if (x < selectXMax) {
|
|
xMin = x;
|
|
xMax = selectXMax;
|
|
} else {
|
|
xMin = selectXMax;
|
|
xMax = x;
|
|
lastDragLeft = gFalse;
|
|
}
|
|
} else {
|
|
if (x > selectXMin) {
|
|
xMin = selectXMin;
|
|
xMax = x;
|
|
} else {
|
|
xMin = x;
|
|
xMax = selectXMin;
|
|
lastDragLeft = gTrue;
|
|
}
|
|
}
|
|
if (lastDragTop) {
|
|
if (y < selectYMax) {
|
|
yMin = y;
|
|
yMax = selectYMax;
|
|
} else {
|
|
yMin = selectYMax;
|
|
yMax = y;
|
|
lastDragTop = gFalse;
|
|
}
|
|
} else {
|
|
if (y > selectYMin) {
|
|
yMin = selectYMin;
|
|
yMax = y;
|
|
} else {
|
|
yMin = y;
|
|
yMax = selectYMin;
|
|
lastDragTop = gTrue;
|
|
}
|
|
}
|
|
|
|
// redraw the selection
|
|
setSelection(xMin, yMin, xMax, yMax);
|
|
|
|
// button 2: pan
|
|
} else if (!fullScreen && button == 2) {
|
|
mx -= hScrollbar->getPos();
|
|
my -= vScrollbar->getPos();
|
|
hScrollbar->setPos(hScrollbar->getPos() - (mx - panMX),
|
|
canvas->getWidth());
|
|
vScrollbar->setPos(vScrollbar->getPos() - (my - panMY),
|
|
canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
panMX = mx;
|
|
panMY = my;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// button callbacks
|
|
//------------------------------------------------------------------------
|
|
|
|
static void nextPageCbk(LTKWidget *button, int n, GBool on) {
|
|
gotoNextPage(1, gTrue);
|
|
}
|
|
|
|
static void nextTenPageCbk(LTKWidget *button, int n, GBool on) {
|
|
gotoNextPage(10, gTrue);
|
|
}
|
|
|
|
static void gotoNextPage(int inc, GBool top) {
|
|
int pg;
|
|
|
|
if (!doc || doc->getNumPages() == 0) {
|
|
return;
|
|
}
|
|
if (page < doc->getNumPages()) {
|
|
if (top && !fullScreen) {
|
|
vScrollbar->setPos(0, canvas->getHeight());
|
|
canvas->setScrollPos(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
if ((pg = page + inc) > doc->getNumPages()) {
|
|
pg = doc->getNumPages();
|
|
}
|
|
displayPage(pg, zoom, rotate, gTrue);
|
|
} else {
|
|
XBell(display, 0);
|
|
}
|
|
}
|
|
|
|
static void prevPageCbk(LTKWidget *button, int n, GBool on) {
|
|
gotoPrevPage(1, gTrue, gFalse);
|
|
}
|
|
|
|
static void prevTenPageCbk(LTKWidget *button, int n, GBool on) {
|
|
gotoPrevPage(10, gTrue, gFalse);
|
|
}
|
|
|
|
static void gotoPrevPage(int dec, GBool top, GBool bottom) {
|
|
int pg;
|
|
|
|
if (!doc || doc->getNumPages() == 0) {
|
|
return;
|
|
}
|
|
if (page > 1) {
|
|
if (top && !fullScreen) {
|
|
vScrollbar->setPos(0, canvas->getHeight());
|
|
canvas->setScrollPos(hScrollbar->getPos(), vScrollbar->getPos());
|
|
} else if (bottom && !fullScreen) {
|
|
vScrollbar->setPos(canvas->getRealHeight() - canvas->getHeight(),
|
|
canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
if ((pg = page - dec) < 1) {
|
|
pg = 1;
|
|
}
|
|
displayPage(pg, zoom, rotate, gTrue);
|
|
} else {
|
|
XBell(display, 0);
|
|
}
|
|
}
|
|
|
|
static void backCbk(LTKWidget *button, int n, GBool on) {
|
|
if (historyBLen <= 1) {
|
|
XBell(display, 0);
|
|
return;
|
|
}
|
|
if (--historyCur < 0)
|
|
historyCur = historySize - 1;
|
|
--historyBLen;
|
|
++historyFLen;
|
|
if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
|
|
if (!loadFile(history[historyCur].fileName->copy())) {
|
|
XBell(display, 0);
|
|
return;
|
|
}
|
|
}
|
|
displayPage(history[historyCur].page, zoom, rotate, gFalse);
|
|
}
|
|
|
|
static void forwardCbk(LTKWidget *button, int n, GBool on) {
|
|
if (historyFLen == 0) {
|
|
XBell(display, 0);
|
|
return;
|
|
}
|
|
if (++historyCur == historySize)
|
|
historyCur = 0;
|
|
--historyFLen;
|
|
++historyBLen;
|
|
if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
|
|
if (!loadFile(history[historyCur].fileName->copy())) {
|
|
XBell(display, 0);
|
|
return;
|
|
}
|
|
}
|
|
displayPage(history[historyCur].page, zoom, rotate, gFalse);
|
|
}
|
|
|
|
static void pageNumCbk(LTKWidget *textIn, int n, GString *text) {
|
|
int page1;
|
|
char s[20];
|
|
|
|
if (!doc || doc->getNumPages() == 0)
|
|
return;
|
|
page1 = atoi(text->getCString());
|
|
if (page1 >= 1 && page1 <= doc->getNumPages()) {
|
|
if (page1 != page)
|
|
displayPage(page1, zoom, rotate, gTrue);
|
|
} else {
|
|
XBell(display, 0);
|
|
sprintf(s, "%d", page);
|
|
pageNumText->setText(s);
|
|
}
|
|
}
|
|
|
|
static void zoomMenuCbk(LTKMenuItem *item) {
|
|
int z;
|
|
|
|
if (!doc || doc->getNumPages() == 0) {
|
|
return;
|
|
}
|
|
z = item->getItemNum();
|
|
if (z != zoom) {
|
|
displayPage(page, z, rotate, gFalse);
|
|
}
|
|
}
|
|
|
|
static void postScriptCbk(LTKWidget *button, int n, GBool on) {
|
|
if (!doc)
|
|
return;
|
|
mapPSDialog();
|
|
}
|
|
|
|
static void aboutCbk(LTKWidget *button, int n, GBool on) {
|
|
mapAboutWin();
|
|
}
|
|
|
|
static void quitCbk(LTKWidget *button, int n, GBool on) {
|
|
quit = gTrue;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// scrollbar callbacks
|
|
//------------------------------------------------------------------------
|
|
|
|
static void scrollVertCbk(LTKWidget *scrollbar, int n, int val) {
|
|
canvas->scroll(hScrollbar->getPos(), val);
|
|
XSync(display, False);
|
|
}
|
|
|
|
static void scrollHorizCbk(LTKWidget *scrollbar, int n, int val) {
|
|
canvas->scroll(val, vScrollbar->getPos());
|
|
XSync(display, False);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// misc callbacks
|
|
//------------------------------------------------------------------------
|
|
|
|
static void layoutCbk(LTKWindow *win1) {
|
|
if (page >= 0 && (zoom == zoomPage || zoom == zoomWidth)) {
|
|
displayPage(page, zoom, rotate, gFalse);
|
|
} else {
|
|
updateScrollbars();
|
|
}
|
|
}
|
|
|
|
static void updateScrollbars() {
|
|
if (fullScreen) {
|
|
return;
|
|
}
|
|
hScrollbar->setLimits(0, canvas->getRealWidth() - 1);
|
|
hScrollbar->setPos(hScrollbar->getPos(), canvas->getWidth());
|
|
hScrollbar->setScrollDelta(16);
|
|
vScrollbar->setLimits(0, canvas->getRealHeight() - 1);
|
|
vScrollbar->setPos(vScrollbar->getPos(), canvas->getHeight());
|
|
vScrollbar->setScrollDelta(16);
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
|
|
static void propChangeCbk(LTKWindow *win1, Atom atom) {
|
|
Window xwin;
|
|
char *cmd;
|
|
Atom type;
|
|
int format;
|
|
Gulong size, remain;
|
|
char *p, *q;
|
|
GString *newFileName;
|
|
int newPage;
|
|
GString *destName;
|
|
LinkDest *dest;
|
|
|
|
// get command
|
|
xwin = win1->getXWindow();
|
|
if (XGetWindowProperty(display, xwin, remoteAtom,
|
|
0, remoteCmdLength/4, True, remoteAtom,
|
|
&type, &format, &size, &remain,
|
|
(Guchar **)&cmd) != Success) {
|
|
return;
|
|
}
|
|
if (size == 0) {
|
|
return;
|
|
}
|
|
|
|
// raise window
|
|
if (cmd[0] == 'D' || cmd[0] == 'r'){
|
|
win->raise();
|
|
XFlush(display);
|
|
}
|
|
|
|
// display file / page
|
|
if (cmd[0] == 'd' || cmd[0] == 'D') {
|
|
p = cmd + 2;
|
|
q = strchr(p, ' ');
|
|
if (!q) {
|
|
return;
|
|
}
|
|
*q++ = '\0';
|
|
newPage = 1;
|
|
destName = NULL;
|
|
if (*p == '+') {
|
|
destName = new GString(p + 1);
|
|
} else {
|
|
newPage = atoi(p);
|
|
}
|
|
if (!q) {
|
|
return;
|
|
}
|
|
newFileName = new GString(q);
|
|
XFree((XPointer)cmd);
|
|
if (!doc || newFileName->cmp(doc->getFileName())) {
|
|
if (!loadFile(newFileName))
|
|
return;
|
|
} else {
|
|
delete newFileName;
|
|
}
|
|
if (destName) {
|
|
if ((dest = doc->findDest(destName))) {
|
|
displayDest(dest, zoom, rotate, gTrue);
|
|
delete dest;
|
|
}
|
|
delete destName;
|
|
} else if (newPage != page &&
|
|
newPage >= 1 && newPage <= doc->getNumPages()) {
|
|
displayPage(newPage, zoom, rotate, gTrue);
|
|
}
|
|
|
|
// quit
|
|
} else if (cmd[0] == 'q') {
|
|
quit = gTrue;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// selection
|
|
//------------------------------------------------------------------------
|
|
|
|
static void setSelection(int newXMin, int newYMin, int newXMax, int newYMax) {
|
|
int x, y, w, h;
|
|
GBool needRedraw, needScroll;
|
|
GBool moveLeft, moveRight, moveTop, moveBottom;
|
|
|
|
// erase old selection on canvas pixmap
|
|
needRedraw = gFalse;
|
|
if (selectXMin < selectXMax && selectYMin < selectYMax) {
|
|
XFillRectangle(canvas->getDisplay(), canvas->getPixmap(),
|
|
selectGC, selectXMin, selectYMin,
|
|
selectXMax - selectXMin, selectYMax - selectYMin);
|
|
needRedraw = gTrue;
|
|
}
|
|
|
|
// draw new selection on canvas pixmap
|
|
if (newXMin < newXMax && newYMin < newYMax) {
|
|
XFillRectangle(canvas->getDisplay(), canvas->getPixmap(),
|
|
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 canvas
|
|
if (needRedraw) {
|
|
if (moveLeft) {
|
|
canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin,
|
|
(newYMin < selectYMin) ? newYMin : selectYMin,
|
|
(newXMin > selectXMin) ? newXMin : selectXMin,
|
|
(newYMax > selectYMax) ? newYMax : selectYMax);
|
|
}
|
|
if (moveRight) {
|
|
canvas->redrawRect((newXMax < selectXMax) ? newXMax : selectXMax,
|
|
(newYMin < selectYMin) ? newYMin : selectYMin,
|
|
(newXMax > selectXMax) ? newXMax : selectXMax,
|
|
(newYMax > selectYMax) ? newYMax : selectYMax);
|
|
}
|
|
if (moveTop) {
|
|
canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin,
|
|
(newYMin < selectYMin) ? newYMin : selectYMin,
|
|
(newXMax > selectXMax) ? newXMax : selectXMax,
|
|
(newYMin > selectYMin) ? newYMin : selectYMin);
|
|
}
|
|
if (moveBottom) {
|
|
canvas->redrawRect((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 canvas if necessary
|
|
if (fullScreen) {
|
|
return;
|
|
}
|
|
needScroll = gFalse;
|
|
w = canvas->getWidth();
|
|
h = canvas->getHeight();
|
|
x = hScrollbar->getPos();
|
|
y = vScrollbar->getPos();
|
|
if (moveLeft && selectXMin < x) {
|
|
x = selectXMin;
|
|
needScroll = gTrue;
|
|
} else if (moveRight && selectXMax >= x + w) {
|
|
x = selectXMax - w;
|
|
needScroll = gTrue;
|
|
} else if (moveLeft && selectXMin >= x + w) {
|
|
x = selectXMin - w;
|
|
needScroll = gTrue;
|
|
} else if (moveRight && selectXMax < x) {
|
|
x = selectXMax;
|
|
needScroll = gTrue;
|
|
}
|
|
if (moveTop && selectYMin < y) {
|
|
y = selectYMin;
|
|
needScroll = gTrue;
|
|
} else if (moveBottom && selectYMax >= y + h) {
|
|
y = selectYMax - h;
|
|
needScroll = gTrue;
|
|
} else if (moveTop && selectYMin >= y + h) {
|
|
y = selectYMin - h;
|
|
needScroll = gTrue;
|
|
} else if (moveBottom && selectYMax < y) {
|
|
y = selectYMax;
|
|
needScroll = gTrue;
|
|
}
|
|
if (needScroll) {
|
|
hScrollbar->setPos(x, w);
|
|
vScrollbar->setPos(y, h);
|
|
canvas->scroll(x, y);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// "Open" dialog
|
|
//------------------------------------------------------------------------
|
|
|
|
static void mapOpenDialog() {
|
|
openDialog = makeOpenDialog(app);
|
|
((LTKFileReq *)openDialog->findWidget("fileReq"))->setDir(fileReqDir);
|
|
openDialog->layoutDialog(win, -1, -1);
|
|
openDialog->map();
|
|
}
|
|
|
|
static void openButtonCbk(LTKWidget *button, int n, GBool on) {
|
|
LTKFileReq *fileReq;
|
|
GString *sel;
|
|
|
|
sel = NULL;
|
|
if (n == 1) {
|
|
fileReq = (LTKFileReq *)openDialog->findWidget("fileReq");
|
|
if (!(sel = fileReq->getSelection())) {
|
|
return;
|
|
}
|
|
openSelectCbk(fileReq, 0, sel);
|
|
}
|
|
if (openDialog) {
|
|
if (sel) {
|
|
delete fileReqDir;
|
|
fileReqDir = ((LTKFileReq *)openDialog->findWidget("fileReq"))->getDir();
|
|
}
|
|
delete openDialog;
|
|
openDialog = NULL;
|
|
}
|
|
}
|
|
|
|
static void openSelectCbk(LTKWidget *widget, int n, GString *name) {
|
|
GString *name1;
|
|
|
|
name1 = name->copy();
|
|
if (openDialog) {
|
|
delete fileReqDir;
|
|
fileReqDir = ((LTKFileReq *)openDialog->findWidget("fileReq"))->getDir();
|
|
delete openDialog;
|
|
openDialog = NULL;
|
|
}
|
|
if (loadFile(name1)) {
|
|
if (!fullScreen) {
|
|
vScrollbar->setPos(0, canvas->getHeight());
|
|
canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
|
|
}
|
|
displayPage(1, zoom, rotate, gTrue);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// "Reload"
|
|
//------------------------------------------------------------------------
|
|
|
|
static void reloadCbk() {
|
|
int pg;
|
|
|
|
if (!doc) {
|
|
return;
|
|
}
|
|
pg = page;
|
|
if (loadFile(doc->getFileName()->copy())) {
|
|
if (pg > doc->getNumPages()) {
|
|
pg = doc->getNumPages();
|
|
}
|
|
displayPage(pg, zoom, rotate, gFalse);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// "Save PDF" dialog
|
|
//------------------------------------------------------------------------
|
|
|
|
static void mapSaveDialog() {
|
|
saveDialog = makeSaveDialog(app);
|
|
((LTKFileReq *)saveDialog->findWidget("fileReq"))->setDir(fileReqDir);
|
|
saveDialog->layoutDialog(win, -1, -1);
|
|
saveDialog->map();
|
|
}
|
|
|
|
static void saveButtonCbk(LTKWidget *button, int n, GBool on) {
|
|
LTKFileReq *fileReq;
|
|
GString *sel;
|
|
|
|
if (!doc)
|
|
return;
|
|
sel = NULL;
|
|
if (n == 1) {
|
|
fileReq = (LTKFileReq *)saveDialog->findWidget("fileReq");
|
|
if (!(sel = fileReq->getSelection())) {
|
|
return;
|
|
}
|
|
saveSelectCbk(fileReq, 0, sel);
|
|
}
|
|
if (saveDialog) {
|
|
if (sel) {
|
|
delete fileReqDir;
|
|
fileReqDir = ((LTKFileReq *)saveDialog->findWidget("fileReq"))->getDir();
|
|
}
|
|
delete saveDialog;
|
|
saveDialog = NULL;
|
|
}
|
|
}
|
|
|
|
static void saveSelectCbk(LTKWidget *widget, int n, GString *name) {
|
|
GString *name1;
|
|
|
|
name1 = name->copy();
|
|
if (saveDialog) {
|
|
delete fileReqDir;
|
|
fileReqDir = ((LTKFileReq *)saveDialog->findWidget("fileReq"))->getDir();
|
|
delete saveDialog;
|
|
saveDialog = NULL;
|
|
}
|
|
win->setBusyCursor(gTrue);
|
|
doc->saveAs(name1);
|
|
delete name1;
|
|
win->setBusyCursor(gFalse);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// "PostScript" dialog
|
|
//------------------------------------------------------------------------
|
|
|
|
static void mapPSDialog() {
|
|
LTKTextIn *widget;
|
|
char s[20];
|
|
|
|
psDialog = makePostScriptDialog(app);
|
|
sprintf(s, "%d", psFirstPage);
|
|
widget = (LTKTextIn *)psDialog->findWidget("firstPage");
|
|
widget->setText(s);
|
|
sprintf(s, "%d", psLastPage);
|
|
widget = (LTKTextIn *)psDialog->findWidget("lastPage");
|
|
widget->setText(s);
|
|
widget = (LTKTextIn *)psDialog->findWidget("fileName");
|
|
widget->setText(psFileName->getCString());
|
|
psDialog->layoutDialog(win, -1, -1);
|
|
psDialog->map();
|
|
}
|
|
|
|
static void psButtonCbk(LTKWidget *button, int n, GBool on) {
|
|
PSOutputDev *psOut;
|
|
LTKTextIn *widget;
|
|
|
|
if (!doc)
|
|
return;
|
|
|
|
// "Ok" button
|
|
if (n == 1) {
|
|
// extract params and close the dialog
|
|
widget = (LTKTextIn *)psDialog->findWidget("firstPage");
|
|
psFirstPage = atoi(widget->getText()->getCString());
|
|
if (psFirstPage < 1)
|
|
psFirstPage = 1;
|
|
widget = (LTKTextIn *)psDialog->findWidget("lastPage");
|
|
psLastPage = atoi(widget->getText()->getCString());
|
|
if (psLastPage < psFirstPage)
|
|
psLastPage = psFirstPage;
|
|
else if (psLastPage > doc->getNumPages())
|
|
psLastPage = doc->getNumPages();
|
|
widget = (LTKTextIn *)psDialog->findWidget("fileName");
|
|
if (psFileName)
|
|
delete psFileName;
|
|
psFileName = widget->getText()->copy();
|
|
if (!(psFileName->getChar(0) == '|' ||
|
|
psFileName->cmp("-") == 0))
|
|
makePathAbsolute(psFileName);
|
|
|
|
// do the PostScript output
|
|
psDialog->setBusyCursor(gTrue);
|
|
win->setBusyCursor(gTrue);
|
|
#ifdef ENFORCE_PERMISSIONS
|
|
if (doc->okToPrint()) {
|
|
#endif
|
|
psOut = new PSOutputDev(psFileName->getCString(), doc->getXRef(),
|
|
doc->getCatalog(), psFirstPage, psLastPage,
|
|
psModePS);
|
|
if (psOut->isOk()) {
|
|
doc->displayPages(psOut, psFirstPage, psLastPage, 72, 0, gFalse);
|
|
}
|
|
delete psOut;
|
|
#ifdef ENFORCE_PERMISSIONS
|
|
} else {
|
|
error(-1, "Printing this document is not allowed.");
|
|
}
|
|
#endif
|
|
|
|
delete psDialog;
|
|
win->setBusyCursor(gFalse);
|
|
|
|
// "Cancel" button
|
|
} else {
|
|
delete psDialog;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// "About" window
|
|
//------------------------------------------------------------------------
|
|
|
|
static void mapAboutWin() {
|
|
int i;
|
|
|
|
if (aboutWin) {
|
|
aboutWin->raise();
|
|
} else {
|
|
aboutWin = makeAboutWindow(app);
|
|
aboutWin->setLayoutCbk(&aboutLayoutCbk);
|
|
aboutList = (LTKList *)aboutWin->findWidget("list");
|
|
aboutHScrollbar = (LTKScrollbar *)aboutWin->findWidget("hScrollbar");
|
|
aboutVScrollbar = (LTKScrollbar *)aboutWin->findWidget("vScrollbar");
|
|
for (i = 0; aboutWinText[i]; ++i) {
|
|
aboutList->addLine(aboutWinText[i]);
|
|
}
|
|
aboutWin->layout(-1, -1, -1, -1);
|
|
aboutWin->map();
|
|
}
|
|
}
|
|
|
|
static void closeAboutCbk(LTKWidget *button, int n, GBool on) {
|
|
delete aboutWin;
|
|
aboutWin = NULL;
|
|
}
|
|
|
|
static void aboutLayoutCbk(LTKWindow *winA) {
|
|
aboutHScrollbar->setLimits(0, aboutList->getMaxWidth() - 1);
|
|
aboutHScrollbar->setPos(aboutHScrollbar->getPos(), aboutList->getWidth());
|
|
aboutVScrollbar->setLimits(0, aboutList->getNumLines() - 1);
|
|
aboutVScrollbar->setPos(aboutVScrollbar->getPos(),
|
|
aboutList->getDisplayedLines());
|
|
}
|
|
|
|
static void aboutScrollVertCbk(LTKWidget *scrollbar, int n, int val) {
|
|
aboutList->scrollTo(val, aboutHScrollbar->getPos());
|
|
XSync(display, False);
|
|
}
|
|
|
|
static void aboutScrollHorizCbk(LTKWidget *scrollbar, int n, int val) {
|
|
aboutList->scrollTo(aboutVScrollbar->getPos(), val);
|
|
XSync(display, False);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// "Find" window
|
|
//------------------------------------------------------------------------
|
|
|
|
static void findCbk(LTKWidget *button, int n, GBool on) {
|
|
if (!doc || doc->getNumPages() == 0)
|
|
return;
|
|
mapFindWin();
|
|
}
|
|
|
|
static void mapFindWin() {
|
|
if (findWin) {
|
|
findWin->raise();
|
|
} else {
|
|
findWin = makeFindWindow(app);
|
|
findWin->layout(-1, -1, -1, -1);
|
|
findWin->map();
|
|
findTextIn = (LTKTextIn *)findWin->findWidget("text");
|
|
}
|
|
findTextIn->activate(gTrue);
|
|
}
|
|
|
|
static void findButtonCbk(LTKWidget *button, int n, GBool on) {
|
|
if (!doc || doc->getNumPages() == 0)
|
|
return;
|
|
if (n == 1) {
|
|
doFind(findTextIn->getText()->getCString());
|
|
} else {
|
|
delete findWin;
|
|
findWin = NULL;
|
|
}
|
|
}
|
|
|
|
static void doFind(char *s) {
|
|
Unicode *u;
|
|
TextOutputDev *textOut;
|
|
int xMin, yMin, xMax, yMax;
|
|
double xMin1, yMin1, xMax1, yMax1;
|
|
int pg;
|
|
GBool top;
|
|
GString *s1;
|
|
int len, i;
|
|
|
|
// check for zero-length string
|
|
if (!s[0]) {
|
|
XBell(display, 0);
|
|
return;
|
|
}
|
|
|
|
// set cursors to watch
|
|
win->setBusyCursor(gTrue);
|
|
findWin->setBusyCursor(gTrue);
|
|
|
|
// 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);
|
|
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
|
|
#ifdef ENFORCE_PERMISSIONS
|
|
if (doc->okToCopy()) {
|
|
#endif
|
|
s1 = out->getText(selectXMin, selectYMin, selectXMax, selectYMax);
|
|
win->setSelection(NULL, s1);
|
|
#ifdef ENFORCE_PERMISSIONS
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
done:
|
|
gfree(u);
|
|
|
|
// reset cursors to normal
|
|
win->setBusyCursor(gFalse);
|
|
findWin->setBusyCursor(gFalse);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// app kill callback
|
|
//------------------------------------------------------------------------
|
|
|
|
static void killCbk(LTKWindow *win1) {
|
|
if (win1 == win) {
|
|
quit = gTrue;
|
|
} else if (win1 == aboutWin) {
|
|
delete aboutWin;
|
|
aboutWin = NULL;
|
|
} else if (win1 == psDialog) {
|
|
delete psDialog;
|
|
psDialog = NULL;
|
|
} else if (win1 == openDialog) {
|
|
delete openDialog;
|
|
openDialog = NULL;
|
|
} else if (win1 == saveDialog) {
|
|
delete saveDialog;
|
|
saveDialog = NULL;
|
|
} else if (win1 == findWin) {
|
|
delete findWin;
|
|
findWin = NULL;
|
|
}
|
|
}
|