1 //========================================================================
5 // Copyright 2002-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
18 #include "XPDFViewer.h"
22 // these macro defns conflict with xpdf's Object class
23 #ifdef LESSTIF_VERSION
31 //------------------------------------------------------------------------
33 #define remoteCmdSize 512
35 //------------------------------------------------------------------------
37 static String fallbackResources[] = {
38 "*XmTextField.fontList: -*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1",
39 "*.fontList: -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1",
40 "*XmTextField.translations: #override\\n"
41 " Ctrl<Key>a:beginning-of-line()\\n"
42 " Ctrl<Key>b:backward-character()\\n"
43 " Ctrl<Key>d:delete-next-character()\\n"
44 " Ctrl<Key>e:end-of-line()\\n"
45 " Ctrl<Key>f:forward-character()\\n"
46 " Ctrl<Key>u:beginning-of-line()delete-to-end-of-line()\\n"
47 " Ctrl<Key>k:delete-to-end-of-line()\\n",
51 static XrmOptionDescRec xOpts[] = {
52 {"-display", ".display", XrmoptionSepArg, NULL},
53 {"-foreground", "*Foreground", XrmoptionSepArg, NULL},
54 {"-fg", "*Foreground", XrmoptionSepArg, NULL},
55 {"-background", "*Background", XrmoptionSepArg, NULL},
56 {"-bg", "*Background", XrmoptionSepArg, NULL},
57 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
58 {"-g", ".geometry", XrmoptionSepArg, NULL},
59 {"-font", "*.fontList", XrmoptionSepArg, NULL},
60 {"-fn", "*.fontList", XrmoptionSepArg, NULL},
61 {"-title", ".title", XrmoptionSepArg, NULL},
62 {"-cmap", ".installCmap", XrmoptionNoArg, (XPointer)"on"},
63 {"-rgb", ".rgbCubeSize", XrmoptionSepArg, NULL},
64 {"-rv", ".reverseVideo", XrmoptionNoArg, (XPointer)"true"},
65 {"-papercolor", ".paperColor", XrmoptionSepArg, NULL},
66 {"-z", ".initialZoom", XrmoptionSepArg, NULL}
69 #define nXOpts (sizeof(xOpts) / sizeof(XrmOptionDescRec))
71 struct XPDFAppResources {
82 static Bool defInstallCmap = False;
83 static int defRGBCubeSize = defaultRGBCube;
84 static Bool defReverseVideo = False;
85 static Bool defViKeys = False;
87 static XtResource xResources[] = {
88 { "geometry", "Geometry", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, geometry), XtRString, (XtPointer)NULL },
89 { "title", "Title", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, title), XtRString, (XtPointer)NULL },
90 { "installCmap", "InstallCmap", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, installCmap), XtRBool, (XtPointer)&defInstallCmap },
91 { "rgbCubeSize", "RgbCubeSize", XtRInt, sizeof(int), XtOffsetOf(XPDFAppResources, rgbCubeSize), XtRInt, (XtPointer)&defRGBCubeSize },
92 { "reverseVideo", "ReverseVideo", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, reverseVideo), XtRBool, (XtPointer)&defReverseVideo },
93 { "paperColor", "PaperColor", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, paperColor), XtRString, (XtPointer)NULL },
94 { "initialZoom", "InitialZoom", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, initialZoom), XtRString, (XtPointer)NULL },
95 { "viKeys", "ViKeys", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, viKeys), XtRBool, (XtPointer)&defViKeys }
98 #define nXResources (sizeof(xResources) / sizeof(XtResource))
100 //------------------------------------------------------------------------
102 //------------------------------------------------------------------------
104 #if 0 //~ for debugging
105 static int xErrorHandler(Display *display, XErrorEvent *ev) {
106 printf("X error:\n");
107 printf(" resource ID = %08lx\n", ev->resourceid);
108 printf(" serial = %lu\n", ev->serial);
109 printf(" error_code = %d\n", ev->error_code);
110 printf(" request_code = %d\n", ev->request_code);
111 printf(" minor_code = %d\n", ev->minor_code);
117 XPDFApp::XPDFApp(int *argc, char *argv[]) {
118 appShell = XtAppInitialize(&appContext, xpdfAppName, xOpts, nXOpts,
119 argc, argv, fallbackResources, NULL, 0);
120 display = XtDisplay(appShell);
121 screenNum = XScreenNumberOfScreen(XtScreen(appShell));
123 XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
124 XmNenableButtonTab, True, NULL);
127 // Drag-and-drop appears to be buggy -- I'm seeing weird crashes
128 // deep in the Motif code when I destroy widgets in the XpdfForms
129 // code. Xpdf doesn't use it, so just turn it off.
130 XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
131 XmNdragInitiatorProtocolStyle, XmDRAG_NONE,
132 XmNdragReceiverProtocolStyle, XmDRAG_NONE,
136 #if 0 //~ for debugging
137 XSynchronize(display, True);
138 XSetErrorHandler(&xErrorHandler);
148 viewers = new GList();
152 void XPDFApp::getResources() {
153 XPDFAppResources resources;
157 XtGetApplicationResources(appShell, &resources, xResources, nXResources,
159 geometry = resources.geometry ? new GString(resources.geometry)
161 title = resources.title ? new GString(resources.title) : (GString *)NULL;
162 installCmap = (GBool)resources.installCmap;
163 rgbCubeSize = resources.rgbCubeSize;
164 reverseVideo = (GBool)resources.reverseVideo;
165 paperColor = reverseVideo ? BlackPixel(display, screenNum) :
166 WhitePixel(display, screenNum);
167 if (resources.paperColor) {
168 XtVaGetValues(appShell, XmNcolormap, &colormap, NULL);
169 if (XAllocNamedColor(display, colormap, resources.paperColor,
171 paperColor = xcol.pixel;
173 error(-1, "Couldn't allocate color '%s'", resources.paperColor);
176 initialZoom = resources.initialZoom ? new GString(resources.initialZoom)
178 viKeys = (GBool)resources.viKeys;
181 XPDFApp::~XPDFApp() {
182 deleteGList(viewers, XPDFViewer);
194 XPDFViewer *XPDFApp::open(GString *fileName, int page,
195 GString *ownerPassword, GString *userPassword) {
198 viewer = new XPDFViewer(this, fileName, page, NULL,
199 ownerPassword, userPassword);
200 if (!viewer->isOk()) {
204 if (remoteAtom != None) {
205 remoteViewer = viewer;
206 remoteWin = viewer->getWindow();
207 XtAddEventHandler(remoteWin, PropertyChangeMask, False,
208 &remoteMsgCbk, this);
209 XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
211 viewers->append(viewer);
215 XPDFViewer *XPDFApp::openAtDest(GString *fileName, GString *dest,
216 GString *ownerPassword,
217 GString *userPassword) {
220 viewer = new XPDFViewer(this, fileName, 1, dest,
221 ownerPassword, userPassword);
222 if (!viewer->isOk()) {
226 if (remoteAtom != None) {
227 remoteViewer = viewer;
228 remoteWin = viewer->getWindow();
229 XtAddEventHandler(remoteWin, PropertyChangeMask, False,
230 &remoteMsgCbk, this);
231 XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
233 viewers->append(viewer);
237 void XPDFApp::close(XPDFViewer *viewer, GBool closeLast) {
240 if (viewers->getLength() == 1) {
241 if (viewer != (XPDFViewer *)viewers->get(0)) {
250 for (i = 0; i < viewers->getLength(); ++i) {
251 if (((XPDFViewer *)viewers->get(i)) == viewer) {
253 if (remoteAtom != None && remoteViewer == viewer) {
254 remoteViewer = (XPDFViewer *)viewers->get(viewers->getLength() - 1);
255 remoteWin = remoteViewer->getWindow();
256 XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin),
266 void XPDFApp::quit() {
267 if (remoteAtom != None) {
268 XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
270 while (viewers->getLength() > 0) {
271 delete (XPDFViewer *)viewers->del(0);
273 #if HAVE_XTAPPSETEXITFLAG
276 XtAppSetExitFlag(appContext);
280 void XPDFApp::run() {
281 XtAppMainLoop(appContext);
284 void XPDFApp::setRemoteName(char *remoteName) {
285 remoteAtom = XInternAtom(display, remoteName, False);
286 remoteXWin = XGetSelectionOwner(display, remoteAtom);
289 GBool XPDFApp::remoteServerRunning() {
290 return remoteXWin != None;
293 void XPDFApp::remoteOpen(GString *fileName, int page, GBool raise) {
294 char cmd[remoteCmdSize];
296 sprintf(cmd, "%c %d %.200s",
297 raise ? 'D' : 'd', page, fileName->getCString());
298 XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
299 PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
303 void XPDFApp::remoteOpenAtDest(GString *fileName, GString *dest, GBool raise) {
304 char cmd[remoteCmdSize];
306 sprintf(cmd, "%c +%.256s %.200s",
307 raise ? 'D' : 'd', dest->getCString(), fileName->getCString());
308 XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
309 PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
313 void XPDFApp::remoteReload(GBool raise) {
314 XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
315 PropModeReplace, raise ? (Guchar *)"L" : (Guchar *)"l", 2);
319 void XPDFApp::remoteRaise() {
320 XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
321 PropModeReplace, (Guchar *)"r", 2);
325 void XPDFApp::remoteQuit() {
326 XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
327 PropModeReplace, (Guchar *)"q", 2);
331 void XPDFApp::remoteMsgCbk(Widget widget, XtPointer ptr,
332 XEvent *event, Boolean *cont) {
333 XPDFApp *app = (XPDFApp *)ptr;
343 if (event->xproperty.atom != app->remoteAtom) {
350 if (XGetWindowProperty(app->display, XtWindow(app->remoteWin),
351 app->remoteAtom, 0, remoteCmdSize/4,
352 True, app->remoteAtom,
353 &type, &format, &size, &remain,
354 (Guchar **)&cmd) != Success) {
361 // display file / page
362 if (cmd[0] == 'd' || cmd[0] == 'D') {
372 destName = new GString(p + 1);
377 fileName = new GString(q);
378 app->remoteViewer->open(fileName, page, destName);
381 XFree((XPointer)cmd);
387 } else if (cmd[0] == 'l' || cmd[0] == 'L') {
388 app->remoteViewer->reloadFile();
391 } else if (cmd[0] == 'q') {
396 if (cmd[0] == 'D' || cmd[0] == 'L' || cmd[0] == 'r'){
397 XMapRaised(app->display, XtWindow(app->remoteWin));
398 XFlush(app->display);