]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/XPDFApp.cc
Import of Xpdf 2.02 for merge
[evince.git] / pdf / xpdf / XPDFApp.cc
1 //========================================================================
2 //
3 // XPDFApp.cc
4 //
5 // Copyright 2002-2003 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
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",
48   NULL
49 };
50
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}
67 };
68
69 #define nXOpts (sizeof(xOpts) / sizeof(XrmOptionDescRec))
70
71 struct 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
82 static Bool defInstallCmap = False;
83 static int defRGBCubeSize = defaultRGBCube;
84 static Bool defReverseVideo = False;
85 static Bool defViKeys = False;
86
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       }
96 };
97
98 #define nXResources (sizeof(xResources) / sizeof(XtResource))
99
100 //------------------------------------------------------------------------
101 // XPDFApp
102 //------------------------------------------------------------------------
103
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);
112   fflush(stdout);
113   abort();
114 }
115 #endif
116
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));
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
152 void 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
181 XPDFApp::~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
194 XPDFViewer *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
215 XPDFViewer *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
237 void 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
266 void 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 #if HAVE_XTAPPSETEXITFLAG
274   exit(0);
275 #else
276   XtAppSetExitFlag(appContext);
277 #endif
278 }
279
280 void XPDFApp::run() {
281   XtAppMainLoop(appContext);
282 }
283
284 void XPDFApp::setRemoteName(char *remoteName) {
285   remoteAtom = XInternAtom(display, remoteName, False);
286   remoteXWin = XGetSelectionOwner(display, remoteAtom);
287 }
288
289 GBool XPDFApp::remoteServerRunning() {
290   return remoteXWin != None;
291 }
292
293 void XPDFApp::remoteOpen(GString *fileName, int page, GBool raise) {
294   char cmd[remoteCmdSize];
295
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);
300   XFlush(display);
301 }
302
303 void XPDFApp::remoteOpenAtDest(GString *fileName, GString *dest, GBool raise) {
304   char cmd[remoteCmdSize];
305
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);
310   XFlush(display);
311 }
312
313 void XPDFApp::remoteReload(GBool raise) {
314   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
315                   PropModeReplace, raise ? (Guchar *)"L" : (Guchar *)"l", 2);
316   XFlush(display);
317 }
318
319 void XPDFApp::remoteRaise() {
320   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
321                   PropModeReplace, (Guchar *)"r", 2);
322   XFlush(display);
323 }
324
325 void XPDFApp::remoteQuit() {
326   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
327                   PropModeReplace, (Guchar *)"q", 2);
328   XFlush(display);
329 }
330
331 void XPDFApp::remoteMsgCbk(Widget widget, XtPointer ptr,
332                            XEvent *event, Boolean *cont) {
333   XPDFApp *app = (XPDFApp *)ptr;
334   char *cmd;
335   Atom type;
336   int format;
337   Gulong size, remain;
338   char *p, *q;
339   GString *fileName;
340   int page;
341   GString *destName;
342
343   if (event->xproperty.atom != app->remoteAtom) {
344     *cont = True;
345     return;
346   }
347   *cont = False;
348
349   // get command
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) {
355     return;
356   }
357   if (size == 0) {
358     return;
359   }
360
361   // display file / page
362   if (cmd[0] == 'd' || cmd[0] == 'D') {
363     p = cmd + 2;
364     q = strchr(p, ' ');
365     if (!q) {
366       return;
367     }
368     *q++ = '\0';
369     page = 1;
370     destName = NULL;
371     if (*p == '+') {
372       destName = new GString(p + 1);
373     } else {
374       page = atoi(p);
375     }
376     if (q) {
377       fileName = new GString(q);
378       app->remoteViewer->open(fileName, page, destName);
379       delete fileName;
380     }
381     XFree((XPointer)cmd);
382     if (destName) {
383       delete destName;
384     }
385
386   // reload
387   } else if (cmd[0] == 'l' || cmd[0] == 'L') {
388     app->remoteViewer->reloadFile();
389
390   // quit
391   } else if (cmd[0] == 'q') {
392     app->quit();
393   }
394
395   // raise window
396   if (cmd[0] == 'D' || cmd[0] == 'L' || cmd[0] == 'r'){
397     XMapRaised(app->display, XtWindow(app->remoteWin));
398     XFlush(app->display);
399   }
400 }