]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/XPDFApp.cc
Import of xpdf code from gpdf.
[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 "xpdfconfig.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   if (reverseVideo) {
167     paperRGB = splashMakeRGB8(0x00, 0x00, 0x00);
168     paperColor = BlackPixel(display, screenNum);
169   } else {
170     paperRGB = splashMakeRGB8(0xff, 0xff, 0xff);
171     paperColor = WhitePixel(display, screenNum);
172   }
173   if (resources.paperColor) {
174     XtVaGetValues(appShell, XmNcolormap, &colormap, NULL);
175     if (XAllocNamedColor(display, colormap, resources.paperColor,
176                          &xcol, &xcol2)) {
177       paperRGB = splashMakeRGB8(xcol.red >> 8,
178                                 xcol.green >> 8,
179                                 xcol.blue >> 8);
180       paperColor = xcol.pixel;
181     } else {
182       error(-1, "Couldn't allocate color '%s'", resources.paperColor);
183     }
184   }
185   initialZoom = resources.initialZoom ? new GString(resources.initialZoom)
186                                       : (GString *)NULL;
187   viKeys = (GBool)resources.viKeys;
188 }
189
190 XPDFApp::~XPDFApp() {
191   deleteGList(viewers, XPDFViewer);
192   if (geometry) {
193     delete geometry;
194   }
195   if (title) {
196     delete title;
197   }
198   if (initialZoom) {
199     delete initialZoom;
200   }
201 }
202
203 XPDFViewer *XPDFApp::open(GString *fileName, int page,
204                           GString *ownerPassword, GString *userPassword) {
205   XPDFViewer *viewer;
206
207   viewer = new XPDFViewer(this, fileName, page, NULL,
208                           ownerPassword, userPassword);
209   if (!viewer->isOk()) {
210     delete viewer;
211     return NULL;
212   }
213   if (remoteAtom != None) {
214     remoteViewer = viewer;
215     remoteWin = viewer->getWindow();
216     XtAddEventHandler(remoteWin, PropertyChangeMask, False,
217                       &remoteMsgCbk, this);
218     XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
219   }
220   viewers->append(viewer);
221   return viewer;
222 }
223
224 XPDFViewer *XPDFApp::openAtDest(GString *fileName, GString *dest,
225                                 GString *ownerPassword,
226                                 GString *userPassword) {
227   XPDFViewer *viewer;
228
229   viewer = new XPDFViewer(this, fileName, 1, dest,
230                           ownerPassword, userPassword);
231   if (!viewer->isOk()) {
232     delete viewer;
233     return NULL;
234   }
235   if (remoteAtom != None) {
236     remoteViewer = viewer;
237     remoteWin = viewer->getWindow();
238     XtAddEventHandler(remoteWin, PropertyChangeMask, False,
239                       &remoteMsgCbk, this);
240     XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
241   }
242   viewers->append(viewer);
243   return viewer;
244 }
245
246 void XPDFApp::close(XPDFViewer *viewer, GBool closeLast) {
247   int i;
248
249   if (viewers->getLength() == 1) {
250     if (viewer != (XPDFViewer *)viewers->get(0)) {
251       return;
252     }
253     if (closeLast) {
254       quit();
255     } else {
256       viewer->clear();
257     }
258   } else {
259     for (i = 0; i < viewers->getLength(); ++i) {
260       if (((XPDFViewer *)viewers->get(i)) == viewer) {
261         viewers->del(i);
262         if (remoteAtom != None && remoteViewer == viewer) {
263           remoteViewer = (XPDFViewer *)viewers->get(viewers->getLength() - 1);
264           remoteWin = remoteViewer->getWindow();
265           XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin),
266                              CurrentTime);
267         }
268         delete viewer;
269         return;
270       }
271     }
272   }
273 }
274
275 void XPDFApp::quit() {
276   if (remoteAtom != None) {
277     XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
278   }
279   while (viewers->getLength() > 0) {
280     delete (XPDFViewer *)viewers->del(0);
281   }
282 #if HAVE_XTAPPSETEXITFLAG
283   XtAppSetExitFlag(appContext);
284 #else
285   exit(0);
286 #endif
287 }
288
289 void XPDFApp::run() {
290   XtAppMainLoop(appContext);
291 }
292
293 void XPDFApp::setRemoteName(char *remoteName) {
294   remoteAtom = XInternAtom(display, remoteName, False);
295   remoteXWin = XGetSelectionOwner(display, remoteAtom);
296 }
297
298 GBool XPDFApp::remoteServerRunning() {
299   return remoteXWin != None;
300 }
301
302 void XPDFApp::remoteOpen(GString *fileName, int page, GBool raise) {
303   char cmd[remoteCmdSize];
304
305   sprintf(cmd, "%c %d %.200s",
306           raise ? 'D' : 'd', page, fileName->getCString());
307   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
308                   PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
309   XFlush(display);
310 }
311
312 void XPDFApp::remoteOpenAtDest(GString *fileName, GString *dest, GBool raise) {
313   char cmd[remoteCmdSize];
314
315   sprintf(cmd, "%c +%.256s %.200s",
316           raise ? 'D' : 'd', dest->getCString(), fileName->getCString());
317   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
318                   PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
319   XFlush(display);
320 }
321
322 void XPDFApp::remoteReload(GBool raise) {
323   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
324                   PropModeReplace, raise ? (Guchar *)"L" : (Guchar *)"l", 2);
325   XFlush(display);
326 }
327
328 void XPDFApp::remoteRaise() {
329   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
330                   PropModeReplace, (Guchar *)"r", 2);
331   XFlush(display);
332 }
333
334 void XPDFApp::remoteQuit() {
335   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
336                   PropModeReplace, (Guchar *)"q", 2);
337   XFlush(display);
338 }
339
340 void XPDFApp::remoteMsgCbk(Widget widget, XtPointer ptr,
341                            XEvent *event, Boolean *cont) {
342   XPDFApp *app = (XPDFApp *)ptr;
343   char *cmd;
344   Atom type;
345   int format;
346   Gulong size, remain;
347   char *p, *q;
348   GString *fileName;
349   int page;
350   GString *destName;
351
352   if (event->xproperty.atom != app->remoteAtom) {
353     *cont = True;
354     return;
355   }
356   *cont = False;
357
358   // get command
359   if (XGetWindowProperty(app->display, XtWindow(app->remoteWin),
360                          app->remoteAtom, 0, remoteCmdSize/4,
361                          True, app->remoteAtom,
362                          &type, &format, &size, &remain,
363                          (Guchar **)&cmd) != Success) {
364     return;
365   }
366   if (size == 0) {
367     return;
368   }
369
370   // display file / page
371   if (cmd[0] == 'd' || cmd[0] == 'D') {
372     p = cmd + 2;
373     q = strchr(p, ' ');
374     if (!q) {
375       return;
376     }
377     *q++ = '\0';
378     page = 1;
379     destName = NULL;
380     if (*p == '+') {
381       destName = new GString(p + 1);
382     } else {
383       page = atoi(p);
384     }
385     if (q) {
386       fileName = new GString(q);
387       app->remoteViewer->open(fileName, page, destName);
388       delete fileName;
389     }
390     if (destName) {
391       delete destName;
392     }
393
394   // reload
395   } else if (cmd[0] == 'l' || cmd[0] == 'L') {
396     app->remoteViewer->reloadFile();
397
398   // quit
399   } else if (cmd[0] == 'q') {
400     app->quit();
401   }
402
403   // raise window
404   if (cmd[0] == 'D' || cmd[0] == 'L' || cmd[0] == 'r'){
405     XMapRaised(app->display, XtWindow(app->remoteWin));
406     XFlush(app->display);
407   }
408
409   XFree((XPointer)cmd);
410 }