You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
447 lines
14 KiB
447 lines
14 KiB
//========================================================================
|
|
//
|
|
// XPDFApp.cc
|
|
//
|
|
// Copyright 2002-2003 Glyph & Cog, LLC
|
|
//
|
|
//========================================================================
|
|
|
|
#include <aconf.h>
|
|
|
|
#ifdef USE_GCC_PRAGMAS
|
|
#pragma implementation
|
|
#endif
|
|
|
|
#include "GString.h"
|
|
#include "GList.h"
|
|
#include "Error.h"
|
|
#include "XPDFViewer.h"
|
|
#include "XPDFApp.h"
|
|
#include "config.h"
|
|
|
|
// these macro defns conflict with xpdf's Object class
|
|
#ifdef LESSTIF_VERSION
|
|
#undef XtDisplay
|
|
#undef XtScreen
|
|
#undef XtWindow
|
|
#undef XtParent
|
|
#undef XtIsRealized
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
#define remoteCmdSize 512
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
static String fallbackResources[] = {
|
|
"*.zoomComboBox*fontList: -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1",
|
|
"*XmTextField.fontList: -*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1",
|
|
"*.fontList: -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1",
|
|
"*XmTextField.translations: #override\\n"
|
|
" Ctrl<Key>a:beginning-of-line()\\n"
|
|
" Ctrl<Key>b:backward-character()\\n"
|
|
" Ctrl<Key>d:delete-next-character()\\n"
|
|
" Ctrl<Key>e:end-of-line()\\n"
|
|
" Ctrl<Key>f:forward-character()\\n"
|
|
" Ctrl<Key>u:beginning-of-line()delete-to-end-of-line()\\n"
|
|
" Ctrl<Key>k:delete-to-end-of-line()\\n",
|
|
"*.toolTipEnable: True",
|
|
"*.toolTipPostDelay: 1500",
|
|
"*.toolTipPostDuration: 0",
|
|
"*.TipLabel.foreground: black",
|
|
"*.TipLabel.background: LightYellow",
|
|
"*.TipShell.borderWidth: 1",
|
|
"*.TipShell.borderColor: black",
|
|
NULL
|
|
};
|
|
|
|
static XrmOptionDescRec xOpts[] = {
|
|
{"-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", "*.fontList", XrmoptionSepArg, NULL},
|
|
{"-fn", "*.fontList", XrmoptionSepArg, NULL},
|
|
{"-title", ".title", XrmoptionSepArg, NULL},
|
|
{"-cmap", ".installCmap", XrmoptionNoArg, (XPointer)"on"},
|
|
{"-rgb", ".rgbCubeSize", XrmoptionSepArg, NULL},
|
|
{"-rv", ".reverseVideo", XrmoptionNoArg, (XPointer)"true"},
|
|
{"-papercolor", ".paperColor", XrmoptionSepArg, NULL},
|
|
{"-mattecolor", ".matteColor", XrmoptionSepArg, NULL},
|
|
{"-z", ".initialZoom", XrmoptionSepArg, NULL}
|
|
};
|
|
|
|
#define nXOpts (sizeof(xOpts) / sizeof(XrmOptionDescRec))
|
|
|
|
struct XPDFAppResources {
|
|
String geometry;
|
|
String title;
|
|
Bool installCmap;
|
|
int rgbCubeSize;
|
|
Bool reverseVideo;
|
|
String paperColor;
|
|
String matteColor;
|
|
String fullScreenMatteColor;
|
|
String initialZoom;
|
|
};
|
|
|
|
static Bool defInstallCmap = False;
|
|
static int defRGBCubeSize = defaultRGBCube;
|
|
static Bool defReverseVideo = False;
|
|
|
|
static XtResource xResources[] = {
|
|
{ "geometry", "Geometry", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, geometry), XtRString, (XtPointer)NULL },
|
|
{ "title", "Title", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, title), XtRString, (XtPointer)NULL },
|
|
{ "installCmap", "InstallCmap", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, installCmap), XtRBool, (XtPointer)&defInstallCmap },
|
|
{ "rgbCubeSize", "RgbCubeSize", XtRInt, sizeof(int), XtOffsetOf(XPDFAppResources, rgbCubeSize), XtRInt, (XtPointer)&defRGBCubeSize },
|
|
{ "reverseVideo", "ReverseVideo", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, reverseVideo), XtRBool, (XtPointer)&defReverseVideo },
|
|
{ "paperColor", "PaperColor", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, paperColor), XtRString, (XtPointer)NULL },
|
|
{ "matteColor", "MatteColor", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, matteColor), XtRString, (XtPointer)"gray50" },
|
|
{ "fullScreenMatteColor", "FullScreenMatteColor", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, fullScreenMatteColor), XtRString, (XtPointer)"black" },
|
|
{ "initialZoom", "InitialZoom", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, initialZoom), XtRString, (XtPointer)NULL }
|
|
};
|
|
|
|
#define nXResources (sizeof(xResources) / sizeof(XtResource))
|
|
|
|
//------------------------------------------------------------------------
|
|
// XPDFApp
|
|
//------------------------------------------------------------------------
|
|
|
|
#if 0 //~ for debugging
|
|
static int xErrorHandler(Display *display, XErrorEvent *ev) {
|
|
printf("X error:\n");
|
|
printf(" resource ID = %08lx\n", ev->resourceid);
|
|
printf(" serial = %lu\n", ev->serial);
|
|
printf(" error_code = %d\n", ev->error_code);
|
|
printf(" request_code = %d\n", ev->request_code);
|
|
printf(" minor_code = %d\n", ev->minor_code);
|
|
fflush(stdout);
|
|
abort();
|
|
}
|
|
#endif
|
|
|
|
XPDFApp::XPDFApp(int *argc, char *argv[]) {
|
|
appShell = XtAppInitialize(&appContext, xpdfAppName, xOpts, nXOpts,
|
|
argc, argv, fallbackResources, NULL, 0);
|
|
display = XtDisplay(appShell);
|
|
screenNum = XScreenNumberOfScreen(XtScreen(appShell));
|
|
#if XmVERSION > 1
|
|
XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
|
|
XmNenableButtonTab, True, NULL);
|
|
#endif
|
|
#if XmVERSION > 1
|
|
// Drag-and-drop appears to be buggy -- I'm seeing weird crashes
|
|
// deep in the Motif code when I destroy widgets in the XpdfForms
|
|
// code. Xpdf doesn't use it, so just turn it off.
|
|
XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
|
|
XmNdragInitiatorProtocolStyle, XmDRAG_NONE,
|
|
XmNdragReceiverProtocolStyle, XmDRAG_NONE,
|
|
NULL);
|
|
#endif
|
|
|
|
#if 0 //~ for debugging
|
|
XSynchronize(display, True);
|
|
XSetErrorHandler(&xErrorHandler);
|
|
#endif
|
|
|
|
fullScreen = gFalse;
|
|
remoteAtom = None;
|
|
remoteViewer = NULL;
|
|
remoteWin = None;
|
|
|
|
getResources();
|
|
|
|
viewers = new GList();
|
|
|
|
}
|
|
|
|
void XPDFApp::getResources() {
|
|
XPDFAppResources resources;
|
|
XColor xcol, xcol2;
|
|
Colormap colormap;
|
|
|
|
XtGetApplicationResources(appShell, &resources, xResources, nXResources,
|
|
NULL, 0);
|
|
geometry = resources.geometry ? new GString(resources.geometry)
|
|
: (GString *)NULL;
|
|
title = resources.title ? new GString(resources.title) : (GString *)NULL;
|
|
installCmap = (GBool)resources.installCmap;
|
|
rgbCubeSize = resources.rgbCubeSize;
|
|
reverseVideo = (GBool)resources.reverseVideo;
|
|
if (reverseVideo) {
|
|
paperRGB[0] = paperRGB[1] = paperRGB[2] = 0;
|
|
paperPixel = BlackPixel(display, screenNum);
|
|
} else {
|
|
paperRGB[0] = paperRGB[1] = paperRGB[2] = 0xff;
|
|
paperPixel = WhitePixel(display, screenNum);
|
|
}
|
|
XtVaGetValues(appShell, XmNcolormap, &colormap, NULL);
|
|
if (resources.paperColor) {
|
|
if (XAllocNamedColor(display, colormap, resources.paperColor,
|
|
&xcol, &xcol2)) {
|
|
paperRGB[0] = xcol.red >> 8;
|
|
paperRGB[1] = xcol.green >> 8;
|
|
paperRGB[2] = xcol.blue >> 8;
|
|
paperPixel = xcol.pixel;
|
|
} else {
|
|
error(-1, "Couldn't allocate color '%s'", resources.paperColor);
|
|
}
|
|
}
|
|
if (XAllocNamedColor(display, colormap, resources.matteColor,
|
|
&xcol, &xcol2)) {
|
|
mattePixel = xcol.pixel;
|
|
} else {
|
|
mattePixel = paperPixel;
|
|
}
|
|
if (XAllocNamedColor(display, colormap, resources.fullScreenMatteColor,
|
|
&xcol, &xcol2)) {
|
|
fullScreenMattePixel = xcol.pixel;
|
|
} else {
|
|
fullScreenMattePixel = paperPixel;
|
|
}
|
|
initialZoom = resources.initialZoom ? new GString(resources.initialZoom)
|
|
: (GString *)NULL;
|
|
}
|
|
|
|
XPDFApp::~XPDFApp() {
|
|
deleteGList(viewers, XPDFViewer);
|
|
if (geometry) {
|
|
delete geometry;
|
|
}
|
|
if (title) {
|
|
delete title;
|
|
}
|
|
if (initialZoom) {
|
|
delete initialZoom;
|
|
}
|
|
}
|
|
|
|
XPDFViewer *XPDFApp::open(GString *fileName, int page,
|
|
GString *ownerPassword, GString *userPassword) {
|
|
XPDFViewer *viewer;
|
|
|
|
viewer = new XPDFViewer(this, fileName, page, NULL, fullScreen,
|
|
ownerPassword, userPassword);
|
|
if (!viewer->isOk()) {
|
|
delete viewer;
|
|
return NULL;
|
|
}
|
|
if (remoteAtom != None) {
|
|
remoteViewer = viewer;
|
|
remoteWin = viewer->getWindow();
|
|
XtAddEventHandler(remoteWin, PropertyChangeMask, False,
|
|
&remoteMsgCbk, this);
|
|
XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
|
|
}
|
|
viewers->append(viewer);
|
|
return viewer;
|
|
}
|
|
|
|
XPDFViewer *XPDFApp::openAtDest(GString *fileName, GString *dest,
|
|
GString *ownerPassword,
|
|
GString *userPassword) {
|
|
XPDFViewer *viewer;
|
|
|
|
viewer = new XPDFViewer(this, fileName, 1, dest, fullScreen,
|
|
ownerPassword, userPassword);
|
|
if (!viewer->isOk()) {
|
|
delete viewer;
|
|
return NULL;
|
|
}
|
|
if (remoteAtom != None) {
|
|
remoteViewer = viewer;
|
|
remoteWin = viewer->getWindow();
|
|
XtAddEventHandler(remoteWin, PropertyChangeMask, False,
|
|
&remoteMsgCbk, this);
|
|
XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
|
|
}
|
|
viewers->append(viewer);
|
|
return viewer;
|
|
}
|
|
|
|
XPDFViewer *XPDFApp::reopen(XPDFViewer *viewer, PDFDoc *doc, int page,
|
|
GBool fullScreenA) {
|
|
int i;
|
|
|
|
for (i = 0; i < viewers->getLength(); ++i) {
|
|
if (((XPDFViewer *)viewers->get(i)) == viewer) {
|
|
viewers->del(i);
|
|
delete viewer;
|
|
}
|
|
}
|
|
viewer = new XPDFViewer(this, doc, page, NULL, fullScreenA);
|
|
if (!viewer->isOk()) {
|
|
delete viewer;
|
|
return NULL;
|
|
}
|
|
if (remoteAtom != None) {
|
|
remoteViewer = viewer;
|
|
remoteWin = viewer->getWindow();
|
|
XtAddEventHandler(remoteWin, PropertyChangeMask, False,
|
|
&remoteMsgCbk, this);
|
|
XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
|
|
}
|
|
viewers->append(viewer);
|
|
return viewer;
|
|
}
|
|
|
|
void XPDFApp::close(XPDFViewer *viewer, GBool closeLast) {
|
|
int i;
|
|
|
|
if (viewers->getLength() == 1) {
|
|
if (viewer != (XPDFViewer *)viewers->get(0)) {
|
|
return;
|
|
}
|
|
if (closeLast) {
|
|
quit();
|
|
} else {
|
|
viewer->clear();
|
|
}
|
|
} else {
|
|
for (i = 0; i < viewers->getLength(); ++i) {
|
|
if (((XPDFViewer *)viewers->get(i)) == viewer) {
|
|
viewers->del(i);
|
|
if (remoteAtom != None && remoteViewer == viewer) {
|
|
remoteViewer = (XPDFViewer *)viewers->get(viewers->getLength() - 1);
|
|
remoteWin = remoteViewer->getWindow();
|
|
XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin),
|
|
CurrentTime);
|
|
}
|
|
delete viewer;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void XPDFApp::quit() {
|
|
if (remoteAtom != None) {
|
|
XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
|
|
}
|
|
while (viewers->getLength() > 0) {
|
|
delete (XPDFViewer *)viewers->del(0);
|
|
}
|
|
#if HAVE_XTAPPSETEXITFLAG
|
|
XtAppSetExitFlag(appContext);
|
|
#else
|
|
exit(0);
|
|
#endif
|
|
}
|
|
|
|
void XPDFApp::run() {
|
|
XtAppMainLoop(appContext);
|
|
}
|
|
|
|
void XPDFApp::setRemoteName(char *remoteName) {
|
|
remoteAtom = XInternAtom(display, remoteName, False);
|
|
remoteXWin = XGetSelectionOwner(display, remoteAtom);
|
|
}
|
|
|
|
GBool XPDFApp::remoteServerRunning() {
|
|
return remoteXWin != None;
|
|
}
|
|
|
|
void XPDFApp::remoteExec(char *cmd) {
|
|
char cmd2[remoteCmdSize];
|
|
int n;
|
|
|
|
n = strlen(cmd);
|
|
if (n > remoteCmdSize - 2) {
|
|
n = remoteCmdSize - 2;
|
|
}
|
|
memcpy(cmd2, cmd, n);
|
|
cmd2[n] = '\n';
|
|
cmd2[n+1] = '\0';
|
|
XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
|
|
PropModeReplace, (Guchar *)cmd2, n + 2);
|
|
XFlush(display);
|
|
}
|
|
|
|
void XPDFApp::remoteOpen(GString *fileName, int page, GBool raise) {
|
|
char cmd[remoteCmdSize];
|
|
|
|
sprintf(cmd, "openFileAtPage(%.200s,%d)\n",
|
|
fileName->getCString(), page);
|
|
if (raise) {
|
|
strcat(cmd, "raise\n");
|
|
}
|
|
XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
|
|
PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
|
|
XFlush(display);
|
|
}
|
|
|
|
void XPDFApp::remoteOpenAtDest(GString *fileName, GString *dest, GBool raise) {
|
|
char cmd[remoteCmdSize];
|
|
|
|
sprintf(cmd, "openFileAtDest(%.200s,%.256s)\n",
|
|
fileName->getCString(), dest->getCString());
|
|
if (raise) {
|
|
strcat(cmd, "raise\n");
|
|
}
|
|
XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
|
|
PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
|
|
XFlush(display);
|
|
}
|
|
|
|
void XPDFApp::remoteReload(GBool raise) {
|
|
char cmd[remoteCmdSize];
|
|
|
|
strcpy(cmd, "reload\n");
|
|
if (raise) {
|
|
strcat(cmd, "raise\n");
|
|
}
|
|
XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
|
|
PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
|
|
XFlush(display);
|
|
}
|
|
|
|
void XPDFApp::remoteRaise() {
|
|
XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
|
|
PropModeReplace, (Guchar *)"raise\n", 7);
|
|
XFlush(display);
|
|
}
|
|
|
|
void XPDFApp::remoteQuit() {
|
|
XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
|
|
PropModeReplace, (Guchar *)"quit\n", 6);
|
|
XFlush(display);
|
|
}
|
|
|
|
void XPDFApp::remoteMsgCbk(Widget widget, XtPointer ptr,
|
|
XEvent *event, Boolean *cont) {
|
|
XPDFApp *app = (XPDFApp *)ptr;
|
|
char *cmd, *p0, *p1;
|
|
Atom type;
|
|
int format;
|
|
Gulong size, remain;
|
|
GString *cmdStr;
|
|
|
|
if (event->xproperty.atom != app->remoteAtom) {
|
|
*cont = True;
|
|
return;
|
|
}
|
|
*cont = False;
|
|
|
|
if (XGetWindowProperty(app->display, XtWindow(app->remoteWin),
|
|
app->remoteAtom, 0, remoteCmdSize/4,
|
|
True, app->remoteAtom,
|
|
&type, &format, &size, &remain,
|
|
(Guchar **)&cmd) != Success) {
|
|
return;
|
|
}
|
|
if (!cmd) {
|
|
return;
|
|
}
|
|
p0 = cmd;
|
|
while (*p0 && (p1 = strchr(p0, '\n'))) {
|
|
cmdStr = new GString(p0, p1 - p0);
|
|
app->remoteViewer->execCmd(cmdStr, NULL);
|
|
delete cmdStr;
|
|
p0 = p1 + 1;
|
|
}
|
|
XFree((XPointer)cmd);
|
|
}
|
|
|