]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/XPDFApp.cc
Import of Xpdf 2.03
[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   "*.zoomComboBox*fontList: -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1",
39   "*XmTextField.fontList: -*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1",
40   "*.fontList: -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1",
41   "*XmTextField.translations: #override\\n"
42   "  Ctrl<Key>a:beginning-of-line()\\n"
43   "  Ctrl<Key>b:backward-character()\\n"
44   "  Ctrl<Key>d:delete-next-character()\\n"
45   "  Ctrl<Key>e:end-of-line()\\n"
46   "  Ctrl<Key>f:forward-character()\\n"
47   "  Ctrl<Key>u:beginning-of-line()delete-to-end-of-line()\\n"
48   "  Ctrl<Key>k:delete-to-end-of-line()\\n",
49   NULL
50 };
51
52 static XrmOptionDescRec xOpts[] = {
53   {"-display",       ".display",         XrmoptionSepArg,  NULL},
54   {"-foreground",    "*Foreground",      XrmoptionSepArg,  NULL},
55   {"-fg",            "*Foreground",      XrmoptionSepArg,  NULL},
56   {"-background",    "*Background",      XrmoptionSepArg,  NULL},
57   {"-bg",            "*Background",      XrmoptionSepArg,  NULL},
58   {"-geometry",      ".geometry",        XrmoptionSepArg,  NULL},
59   {"-g",             ".geometry",        XrmoptionSepArg,  NULL},
60   {"-font",          "*.fontList",       XrmoptionSepArg,  NULL},
61   {"-fn",            "*.fontList",       XrmoptionSepArg,  NULL},
62   {"-title",         ".title",           XrmoptionSepArg,  NULL},
63   {"-cmap",          ".installCmap",     XrmoptionNoArg,   (XPointer)"on"},
64   {"-rgb",           ".rgbCubeSize",     XrmoptionSepArg,  NULL},
65   {"-rv",            ".reverseVideo",    XrmoptionNoArg,   (XPointer)"true"},
66   {"-papercolor",    ".paperColor",      XrmoptionSepArg,  NULL},
67   {"-z",             ".initialZoom",     XrmoptionSepArg,  NULL}
68 };
69
70 #define nXOpts (sizeof(xOpts) / sizeof(XrmOptionDescRec))
71
72 struct XPDFAppResources {
73   String geometry;
74   String title;
75   Bool installCmap;
76   int rgbCubeSize;
77   Bool reverseVideo;
78   String paperColor;
79   String initialZoom;
80   Bool viKeys;
81 };
82
83 static Bool defInstallCmap = False;
84 static int defRGBCubeSize = defaultRGBCube;
85 static Bool defReverseVideo = False;
86 static Bool defViKeys = False;
87
88 static XtResource xResources[] = {
89   { "geometry",     "Geometry",     XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, geometry),     XtRString, (XtPointer)NULL             },
90   { "title",        "Title",        XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, title),        XtRString, (XtPointer)NULL             },
91   { "installCmap",  "InstallCmap",  XtRBool,   sizeof(Bool),   XtOffsetOf(XPDFAppResources, installCmap),  XtRBool,   (XtPointer)&defInstallCmap  },
92   { "rgbCubeSize",  "RgbCubeSize",  XtRInt,    sizeof(int),    XtOffsetOf(XPDFAppResources, rgbCubeSize),  XtRInt,    (XtPointer)&defRGBCubeSize  },
93   { "reverseVideo", "ReverseVideo", XtRBool,   sizeof(Bool),   XtOffsetOf(XPDFAppResources, reverseVideo), XtRBool,   (XtPointer)&defReverseVideo },
94   { "paperColor",   "PaperColor",   XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, paperColor),   XtRString, (XtPointer)NULL             },
95   { "initialZoom",  "InitialZoom",  XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, initialZoom),  XtRString, (XtPointer)NULL             },
96   { "viKeys",       "ViKeys",       XtRBool,   sizeof(Bool),   XtOffsetOf(XPDFAppResources, viKeys),       XtRBool,   (XtPointer)&defViKeys       }
97 };
98
99 #define nXResources (sizeof(xResources) / sizeof(XtResource))
100
101 //------------------------------------------------------------------------
102 // XPDFApp
103 //------------------------------------------------------------------------
104
105 #if 0 //~ for debugging
106 static int xErrorHandler(Display *display, XErrorEvent *ev) {
107   printf("X error:\n");
108   printf("  resource ID = %08lx\n", ev->resourceid);
109   printf("  serial = %lu\n", ev->serial);
110   printf("  error_code = %d\n", ev->error_code);
111   printf("  request_code = %d\n", ev->request_code);
112   printf("  minor_code = %d\n", ev->minor_code);
113   fflush(stdout);
114   abort();
115 }
116 #endif
117
118 XPDFApp::XPDFApp(int *argc, char *argv[]) {
119   appShell = XtAppInitialize(&appContext, xpdfAppName, xOpts, nXOpts,
120                              argc, argv, fallbackResources, NULL, 0);
121   display = XtDisplay(appShell);
122   screenNum = XScreenNumberOfScreen(XtScreen(appShell));
123 #if XmVERSION > 1
124   XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
125                 XmNenableButtonTab, True, NULL);
126 #endif
127 #if XmVERSION > 1
128   // Drag-and-drop appears to be buggy -- I'm seeing weird crashes
129   // deep in the Motif code when I destroy widgets in the XpdfForms
130   // code.  Xpdf doesn't use it, so just turn it off.
131   XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
132                 XmNdragInitiatorProtocolStyle, XmDRAG_NONE,
133                 XmNdragReceiverProtocolStyle, XmDRAG_NONE,
134                 NULL);
135 #endif
136
137 #if 0 //~ for debugging
138   XSynchronize(display, True);
139   XSetErrorHandler(&xErrorHandler);
140 #endif
141
142   fullScreen = gFalse;
143   remoteAtom = None;
144   remoteViewer = NULL;
145   remoteWin = None;
146
147   getResources();
148
149   viewers = new GList();
150
151 }
152
153 void XPDFApp::getResources() {
154   XPDFAppResources resources;
155   XColor xcol, xcol2;
156   Colormap colormap;
157   
158   XtGetApplicationResources(appShell, &resources, xResources, nXResources,
159                             NULL, 0);
160   geometry = resources.geometry ? new GString(resources.geometry)
161                                 : (GString *)NULL;
162   title = resources.title ? new GString(resources.title) : (GString *)NULL;
163   installCmap = (GBool)resources.installCmap;
164   rgbCubeSize = resources.rgbCubeSize;
165   reverseVideo = (GBool)resources.reverseVideo;
166   paperColor = reverseVideo ? BlackPixel(display, screenNum) :
167                               WhitePixel(display, screenNum);
168   if (resources.paperColor) {
169     XtVaGetValues(appShell, XmNcolormap, &colormap, NULL);
170     if (XAllocNamedColor(display, colormap, resources.paperColor,
171                          &xcol, &xcol2)) {
172       paperColor = xcol.pixel;
173     } else {
174       error(-1, "Couldn't allocate color '%s'", resources.paperColor);
175     }
176   }
177   initialZoom = resources.initialZoom ? new GString(resources.initialZoom)
178                                       : (GString *)NULL;
179   viKeys = (GBool)resources.viKeys;
180 }
181
182 XPDFApp::~XPDFApp() {
183   deleteGList(viewers, XPDFViewer);
184   if (geometry) {
185     delete geometry;
186   }
187   if (title) {
188     delete title;
189   }
190   if (initialZoom) {
191     delete initialZoom;
192   }
193 }
194
195 XPDFViewer *XPDFApp::open(GString *fileName, int page,
196                           GString *ownerPassword, GString *userPassword) {
197   XPDFViewer *viewer;
198
199   viewer = new XPDFViewer(this, fileName, page, NULL,
200                           ownerPassword, userPassword);
201   if (!viewer->isOk()) {
202     delete viewer;
203     return NULL;
204   }
205   if (remoteAtom != None) {
206     remoteViewer = viewer;
207     remoteWin = viewer->getWindow();
208     XtAddEventHandler(remoteWin, PropertyChangeMask, False,
209                       &remoteMsgCbk, this);
210     XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
211   }
212   viewers->append(viewer);
213   return viewer;
214 }
215
216 XPDFViewer *XPDFApp::openAtDest(GString *fileName, GString *dest,
217                                 GString *ownerPassword,
218                                 GString *userPassword) {
219   XPDFViewer *viewer;
220
221   viewer = new XPDFViewer(this, fileName, 1, dest,
222                           ownerPassword, userPassword);
223   if (!viewer->isOk()) {
224     delete viewer;
225     return NULL;
226   }
227   if (remoteAtom != None) {
228     remoteViewer = viewer;
229     remoteWin = viewer->getWindow();
230     XtAddEventHandler(remoteWin, PropertyChangeMask, False,
231                       &remoteMsgCbk, this);
232     XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
233   }
234   viewers->append(viewer);
235   return viewer;
236 }
237
238 void XPDFApp::close(XPDFViewer *viewer, GBool closeLast) {
239   int i;
240
241   if (viewers->getLength() == 1) {
242     if (viewer != (XPDFViewer *)viewers->get(0)) {
243       return;
244     }
245     if (closeLast) {
246       quit();
247     } else {
248       viewer->clear();
249     }
250   } else {
251     for (i = 0; i < viewers->getLength(); ++i) {
252       if (((XPDFViewer *)viewers->get(i)) == viewer) {
253         viewers->del(i);
254         if (remoteAtom != None && remoteViewer == viewer) {
255           remoteViewer = (XPDFViewer *)viewers->get(viewers->getLength() - 1);
256           remoteWin = remoteViewer->getWindow();
257           XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin),
258                              CurrentTime);
259         }
260         delete viewer;
261         return;
262       }
263     }
264   }
265 }
266
267 void XPDFApp::quit() {
268   if (remoteAtom != None) {
269     XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
270   }
271   while (viewers->getLength() > 0) {
272     delete (XPDFViewer *)viewers->del(0);
273   }
274 #if HAVE_XTAPPSETEXITFLAG
275   XtAppSetExitFlag(appContext);
276 #else
277   exit(0);
278 #endif
279 }
280
281 void XPDFApp::run() {
282   XtAppMainLoop(appContext);
283 }
284
285 void XPDFApp::setRemoteName(char *remoteName) {
286   remoteAtom = XInternAtom(display, remoteName, False);
287   remoteXWin = XGetSelectionOwner(display, remoteAtom);
288 }
289
290 GBool XPDFApp::remoteServerRunning() {
291   return remoteXWin != None;
292 }
293
294 void XPDFApp::remoteOpen(GString *fileName, int page, GBool raise) {
295   char cmd[remoteCmdSize];
296
297   sprintf(cmd, "%c %d %.200s",
298           raise ? 'D' : 'd', page, fileName->getCString());
299   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
300                   PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
301   XFlush(display);
302 }
303
304 void XPDFApp::remoteOpenAtDest(GString *fileName, GString *dest, GBool raise) {
305   char cmd[remoteCmdSize];
306
307   sprintf(cmd, "%c +%.256s %.200s",
308           raise ? 'D' : 'd', dest->getCString(), fileName->getCString());
309   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
310                   PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
311   XFlush(display);
312 }
313
314 void XPDFApp::remoteReload(GBool raise) {
315   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
316                   PropModeReplace, raise ? (Guchar *)"L" : (Guchar *)"l", 2);
317   XFlush(display);
318 }
319
320 void XPDFApp::remoteRaise() {
321   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
322                   PropModeReplace, (Guchar *)"r", 2);
323   XFlush(display);
324 }
325
326 void XPDFApp::remoteQuit() {
327   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
328                   PropModeReplace, (Guchar *)"q", 2);
329   XFlush(display);
330 }
331
332 void XPDFApp::remoteMsgCbk(Widget widget, XtPointer ptr,
333                            XEvent *event, Boolean *cont) {
334   XPDFApp *app = (XPDFApp *)ptr;
335   char *cmd;
336   Atom type;
337   int format;
338   Gulong size, remain;
339   char *p, *q;
340   GString *fileName;
341   int page;
342   GString *destName;
343
344   if (event->xproperty.atom != app->remoteAtom) {
345     *cont = True;
346     return;
347   }
348   *cont = False;
349
350   // get command
351   if (XGetWindowProperty(app->display, XtWindow(app->remoteWin),
352                          app->remoteAtom, 0, remoteCmdSize/4,
353                          True, app->remoteAtom,
354                          &type, &format, &size, &remain,
355                          (Guchar **)&cmd) != Success) {
356     return;
357   }
358   if (size == 0) {
359     return;
360   }
361
362   // display file / page
363   if (cmd[0] == 'd' || cmd[0] == 'D') {
364     p = cmd + 2;
365     q = strchr(p, ' ');
366     if (!q) {
367       return;
368     }
369     *q++ = '\0';
370     page = 1;
371     destName = NULL;
372     if (*p == '+') {
373       destName = new GString(p + 1);
374     } else {
375       page = atoi(p);
376     }
377     if (q) {
378       fileName = new GString(q);
379       app->remoteViewer->open(fileName, page, destName);
380       delete fileName;
381     }
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
401   XFree((XPointer)cmd);
402 }