filters

XPDFApp.cpp
1//========================================================================
2//
3// XPDFApp.cpp
4//
5// Copyright 2002 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <aconf.h>
10
11#ifdef USE_GCC_PRAGMAS
12#pragma implementation
13#endif
14
15#include "GString.h"
16#include "GList.h"
17#include "Error.h"
18#include "XPDFViewer.h"
19#include "XPDFApp.h"
20#include "config.h"
21
22// these macro defns conflict with xpdf's Object class
23#ifdef LESSTIF_VERSION
24#undef XtDisplay
25#undef XtScreen
26#undef XtWindow
27#undef XtParent
28#undef XtIsRealized
29#endif
30
31//------------------------------------------------------------------------
32
33#define remoteCmdSize 512
34
35//------------------------------------------------------------------------
36
37static 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",
48 NULL
49};
50
51static 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}
67};
68
69#define nXOpts (sizeof(xOpts) / sizeof(XrmOptionDescRec))
70
71struct XPDFAppResources {
72 String geometry;
73 String title;
74 Bool installCmap;
75 int rgbCubeSize;
76 Bool reverseVideo;
77 String paperColor;
78 String initialZoom;
79 Bool viKeys;
80};
81
82static Bool defInstallCmap = False;
83static int defRGBCubeSize = defaultRGBCube;
84static Bool defReverseVideo = False;
85static Bool defViKeys = False;
86
87static 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 }
96};
97
98#define nXResources (sizeof(xResources) / sizeof(XtResource))
99
100//------------------------------------------------------------------------
101// XPDFApp
102//------------------------------------------------------------------------
103
104#if 0 //~ for debugging
105static 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);
112 fflush(stdout);
113 abort();
114}
115#endif
116
117XPDFApp::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));
122#if XmVERSION > 1
123 XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
124 XmNenableButtonTab, True, NULL);
125#endif
126#if XmVERSION > 1
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,
133 NULL);
134#endif
135
136#if 0 //~ for debugging
137 XSynchronize(display, True);
138 XSetErrorHandler(&xErrorHandler);
139#endif
140
141 fullScreen = gFalse;
142 remoteAtom = None;
143 remoteViewer = NULL;
144 remoteWin = None;
145
146 getResources();
147
148 viewers = new GList();
149
150}
151
152void XPDFApp::getResources() {
153 XPDFAppResources resources;
154 XColor xcol, xcol2;
155 Colormap colormap;
156
157 XtGetApplicationResources(appShell, &resources, xResources, nXResources,
158 NULL, 0);
159 geometry = resources.geometry ? new GString(resources.geometry)
160 : (GString *)NULL;
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,
170 &xcol, &xcol2)) {
171 paperColor = xcol.pixel;
172 } else {
173 error(-1, "Couldn't allocate color '%s'", resources.paperColor);
174 }
175 }
176 initialZoom = resources.initialZoom ? new GString(resources.initialZoom)
177 : (GString *)NULL;
178 viKeys = (GBool)resources.viKeys;
179}
180
181XPDFApp::~XPDFApp() {
182 deleteGList(viewers, XPDFViewer);
183 if (geometry) {
184 delete geometry;
185 }
186 if (title) {
187 delete title;
188 }
189 if (initialZoom) {
190 delete initialZoom;
191 }
192}
193
194XPDFViewer *XPDFApp::open(GString *fileName, int page,
195 GString *ownerPassword, GString *userPassword) {
196 XPDFViewer *viewer;
197
198 viewer = new XPDFViewer(this, fileName, page, NULL,
199 ownerPassword, userPassword);
200 if (!viewer->isOk()) {
201 delete viewer;
202 return NULL;
203 }
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);
210 }
211 viewers->append(viewer);
212 return viewer;
213}
214
215XPDFViewer *XPDFApp::openAtDest(GString *fileName, GString *dest,
216 GString *ownerPassword,
217 GString *userPassword) {
218 XPDFViewer *viewer;
219
220 viewer = new XPDFViewer(this, fileName, 1, dest,
221 ownerPassword, userPassword);
222 if (!viewer->isOk()) {
223 delete viewer;
224 return NULL;
225 }
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);
232 }
233 viewers->append(viewer);
234 return viewer;
235}
236
237void XPDFApp::close(XPDFViewer *viewer, GBool closeLast) {
238 int i;
239
240 if (viewers->getLength() == 1) {
241 if (viewer != (XPDFViewer *)viewers->get(0)) {
242 return;
243 }
244 if (closeLast) {
245 quit();
246 } else {
247 viewer->clear();
248 }
249 } else {
250 for (i = 0; i < viewers->getLength(); ++i) {
251 if (((XPDFViewer *)viewers->get(i)) == viewer) {
252 viewers->del(i);
253 if (remoteAtom != None && remoteViewer == viewer) {
254 remoteViewer = (XPDFViewer *)viewers->get(viewers->getLength() - 1);
255 remoteWin = remoteViewer->getWindow();
256 XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin),
257 CurrentTime);
258 }
259 delete viewer;
260 return;
261 }
262 }
263 }
264}
265
266void XPDFApp::quit() {
267 if (remoteAtom != None) {
268 XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
269 }
270 while (viewers->getLength() > 0) {
271 delete (XPDFViewer *)viewers->del(0);
272 }
273 XtAppSetExitFlag(appContext);
274}
275
276void XPDFApp::run() {
277 XtAppMainLoop(appContext);
278}
279
280void XPDFApp::setRemoteName(char *remoteName) {
281 remoteAtom = XInternAtom(display, remoteName, False);
282 remoteXWin = XGetSelectionOwner(display, remoteAtom);
283}
284
285GBool XPDFApp::remoteServerRunning() {
286 return remoteXWin != None;
287}
288
289void XPDFApp::remoteOpen(GString *fileName, int page, GBool raise) {
290 char cmd[remoteCmdSize];
291
292 sprintf(cmd, "%c %d %.200s",
293 raise ? 'D' : 'd', page, fileName->getCString());
294 XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
295 PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
296 XFlush(display);
297}
298
299void XPDFApp::remoteOpenAtDest(GString *fileName, GString *dest, GBool raise) {
300 char cmd[remoteCmdSize];
301
302 sprintf(cmd, "%c +%.256s %.200s",
303 raise ? 'D' : 'd', dest->getCString(), fileName->getCString());
304 XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
305 PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
306 XFlush(display);
307}
308
309void XPDFApp::remoteRaise() {
310 XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
311 PropModeReplace, (Guchar *)"r", 2);
312 XFlush(display);
313}
314
315void XPDFApp::remoteQuit() {
316 XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
317 PropModeReplace, (Guchar *)"q", 2);
318 XFlush(display);
319}
320
321void XPDFApp::remoteMsgCbk(Widget widget, XtPointer ptr,
322 XEvent *event, Boolean *cont) {
323 XPDFApp *app = (XPDFApp *)ptr;
324 char *cmd;
325 Atom type;
326 int format;
327 Gulong size, remain;
328 char *p, *q;
329 GString *fileName;
330 int page;
331 GString *destName;
332
333 if (event->xproperty.atom != app->remoteAtom) {
334 *cont = True;
335 return;
336 }
337 *cont = False;
338
339 // get command
340 if (XGetWindowProperty(app->display, XtWindow(app->remoteWin),
341 app->remoteAtom, 0, remoteCmdSize/4,
342 True, app->remoteAtom,
343 &type, &format, &size, &remain,
344 (Guchar **)&cmd) != Success) {
345 return;
346 }
347 if (size == 0) {
348 return;
349 }
350
351 // raise window
352 if (cmd[0] == 'D' || cmd[0] == 'r'){
353 XMapRaised(app->display, XtWindow(app->remoteWin));
354 XFlush(app->display);
355 }
356
357 // display file / page
358 if (cmd[0] == 'd' || cmd[0] == 'D') {
359 p = cmd + 2;
360 q = strchr(p, ' ');
361 if (!q) {
362 return;
363 }
364 *q++ = '\0';
365 page = 1;
366 destName = NULL;
367 if (*p == '+') {
368 destName = new GString(p + 1);
369 } else {
370 page = atoi(p);
371 }
372 if (q) {
373 fileName = new GString(q);
374 app->remoteViewer->open(fileName, page, destName);
375 delete fileName;
376 }
377 XFree((XPointer)cmd);
378 if (destName) {
379 delete destName;
380 }
381
382 // quit
383 } else if (cmd[0] == 'q') {
384 app->quit();
385 }
386}