filters

XPDFApp.cc

00001 //========================================================================
00002 //
00003 // XPDFApp.cc
00004 //
00005 // Copyright 2002 Glyph & Cog, LLC
00006 //
00007 //========================================================================
00008 
00009 #include <aconf.h>
00010 
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014 
00015 #include "GString.h"
00016 #include "GList.h"
00017 #include "Error.h"
00018 #include "XPDFViewer.h"
00019 #include "XPDFApp.h"
00020 #include "config.h"
00021 
00022 // these macro defns conflict with xpdf's Object class
00023 #ifdef LESSTIF_VERSION
00024 #undef XtDisplay
00025 #undef XtScreen
00026 #undef XtWindow
00027 #undef XtParent
00028 #undef XtIsRealized
00029 #endif
00030 
00031 //------------------------------------------------------------------------
00032 
00033 #define remoteCmdSize 512
00034 
00035 //------------------------------------------------------------------------
00036 
00037 static String fallbackResources[] = {
00038   "*XmTextField.fontList: -*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1",
00039   "*.fontList: -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1",
00040   "*XmTextField.translations: #override\\n"
00041   "  Ctrl<Key>a:beginning-of-line()\\n"
00042   "  Ctrl<Key>b:backward-character()\\n"
00043   "  Ctrl<Key>d:delete-next-character()\\n"
00044   "  Ctrl<Key>e:end-of-line()\\n"
00045   "  Ctrl<Key>f:forward-character()\\n"
00046   "  Ctrl<Key>u:beginning-of-line()delete-to-end-of-line()\\n"
00047   "  Ctrl<Key>k:delete-to-end-of-line()\\n",
00048   NULL
00049 };
00050 
00051 static XrmOptionDescRec xOpts[] = {
00052   {"-display",       ".display",         XrmoptionSepArg,  NULL},
00053   {"-foreground",    "*Foreground",      XrmoptionSepArg,  NULL},
00054   {"-fg",            "*Foreground",      XrmoptionSepArg,  NULL},
00055   {"-background",    "*Background",      XrmoptionSepArg,  NULL},
00056   {"-bg",            "*Background",      XrmoptionSepArg,  NULL},
00057   {"-geometry",      ".geometry",        XrmoptionSepArg,  NULL},
00058   {"-g",             ".geometry",        XrmoptionSepArg,  NULL},
00059   {"-font",          "*.fontList",       XrmoptionSepArg,  NULL},
00060   {"-fn",            "*.fontList",       XrmoptionSepArg,  NULL},
00061   {"-title",         ".title",           XrmoptionSepArg,  NULL},
00062   {"-cmap",          ".installCmap",     XrmoptionNoArg,   (XPointer)"on"},
00063   {"-rgb",           ".rgbCubeSize",     XrmoptionSepArg,  NULL},
00064   {"-rv",            ".reverseVideo",    XrmoptionNoArg,   (XPointer)"true"},
00065   {"-papercolor",    ".paperColor",      XrmoptionSepArg,  NULL},
00066   {"-z",             ".initialZoom",     XrmoptionSepArg,  NULL}
00067 };
00068 
00069 #define nXOpts (sizeof(xOpts) / sizeof(XrmOptionDescRec))
00070 
00071 struct XPDFAppResources {
00072   String geometry;
00073   String title;
00074   Bool installCmap;
00075   int rgbCubeSize;
00076   Bool reverseVideo;
00077   String paperColor;
00078   String initialZoom;
00079   Bool viKeys;
00080 };
00081 
00082 static Bool defInstallCmap = False;
00083 static int defRGBCubeSize = defaultRGBCube;
00084 static Bool defReverseVideo = False;
00085 static Bool defViKeys = False;
00086 
00087 static XtResource xResources[] = {
00088   { "geometry",     "Geometry",     XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, geometry),     XtRString, (XtPointer)NULL             },
00089   { "title",        "Title",        XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, title),        XtRString, (XtPointer)NULL             },
00090   { "installCmap",  "InstallCmap",  XtRBool,   sizeof(Bool),   XtOffsetOf(XPDFAppResources, installCmap),  XtRBool,   (XtPointer)&defInstallCmap  },
00091   { "rgbCubeSize",  "RgbCubeSize",  XtRInt,    sizeof(int),    XtOffsetOf(XPDFAppResources, rgbCubeSize),  XtRInt,    (XtPointer)&defRGBCubeSize  },
00092   { "reverseVideo", "ReverseVideo", XtRBool,   sizeof(Bool),   XtOffsetOf(XPDFAppResources, reverseVideo), XtRBool,   (XtPointer)&defReverseVideo },
00093   { "paperColor",   "PaperColor",   XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, paperColor),   XtRString, (XtPointer)NULL             },
00094   { "initialZoom",  "InitialZoom",  XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, initialZoom),  XtRString, (XtPointer)NULL             },
00095   { "viKeys",       "ViKeys",       XtRBool,   sizeof(Bool),   XtOffsetOf(XPDFAppResources, viKeys),       XtRBool,   (XtPointer)&defViKeys       }
00096 };
00097 
00098 #define nXResources (sizeof(xResources) / sizeof(XtResource))
00099 
00100 //------------------------------------------------------------------------
00101 // XPDFApp
00102 //------------------------------------------------------------------------
00103 
00104 #if 0 //~ for debugging
00105 static int xErrorHandler(Display *display, XErrorEvent *ev) {
00106   printf("X error:\n");
00107   printf("  resource ID = %08lx\n", ev->resourceid);
00108   printf("  serial = %lu\n", ev->serial);
00109   printf("  error_code = %d\n", ev->error_code);
00110   printf("  request_code = %d\n", ev->request_code);
00111   printf("  minor_code = %d\n", ev->minor_code);
00112   fflush(stdout);
00113   abort();
00114 }
00115 #endif
00116 
00117 XPDFApp::XPDFApp(int *argc, char *argv[]) {
00118   appShell = XtAppInitialize(&appContext, xpdfAppName, xOpts, nXOpts,
00119                  argc, argv, fallbackResources, NULL, 0);
00120   display = XtDisplay(appShell);
00121   screenNum = XScreenNumberOfScreen(XtScreen(appShell));
00122 #if XmVERSION > 1
00123   XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
00124         XmNenableButtonTab, True, NULL);
00125 #endif
00126 #if XmVERSION > 1
00127   // Drag-and-drop appears to be buggy -- I'm seeing weird crashes
00128   // deep in the Motif code when I destroy widgets in the XpdfForms
00129   // code.  Xpdf doesn't use it, so just turn it off.
00130   XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
00131         XmNdragInitiatorProtocolStyle, XmDRAG_NONE,
00132         XmNdragReceiverProtocolStyle, XmDRAG_NONE,
00133         NULL);
00134 #endif
00135 
00136 #if 0 //~ for debugging
00137   XSynchronize(display, True);
00138   XSetErrorHandler(&xErrorHandler);
00139 #endif
00140 
00141   fullScreen = gFalse;
00142   remoteAtom = None;
00143   remoteViewer = NULL;
00144   remoteWin = None;
00145 
00146   getResources();
00147 
00148   viewers = new GList();
00149 
00150 }
00151 
00152 void XPDFApp::getResources() {
00153   XPDFAppResources resources;
00154   XColor xcol, xcol2;
00155   Colormap colormap;
00156   
00157   XtGetApplicationResources(appShell, &resources, xResources, nXResources,
00158                 NULL, 0);
00159   geometry = resources.geometry ? new GString(resources.geometry)
00160                                 : (GString *)NULL;
00161   title = resources.title ? new GString(resources.title) : (GString *)NULL;
00162   installCmap = (GBool)resources.installCmap;
00163   rgbCubeSize = resources.rgbCubeSize;
00164   reverseVideo = (GBool)resources.reverseVideo;
00165   paperColor = reverseVideo ? BlackPixel(display, screenNum) :
00166                               WhitePixel(display, screenNum);
00167   if (resources.paperColor) {
00168     XtVaGetValues(appShell, XmNcolormap, &colormap, NULL);
00169     if (XAllocNamedColor(display, colormap, resources.paperColor,
00170              &xcol, &xcol2)) {
00171       paperColor = xcol.pixel;
00172     } else {
00173       error(-1, "Couldn't allocate color '%s'", resources.paperColor);
00174     }
00175   }
00176   initialZoom = resources.initialZoom ? new GString(resources.initialZoom)
00177                                       : (GString *)NULL;
00178   viKeys = (GBool)resources.viKeys;
00179 }
00180 
00181 XPDFApp::~XPDFApp() {
00182   deleteGList(viewers, XPDFViewer);
00183   if (geometry) {
00184     delete geometry;
00185   }
00186   if (title) {
00187     delete title;
00188   }
00189   if (initialZoom) {
00190     delete initialZoom;
00191   }
00192 }
00193 
00194 XPDFViewer *XPDFApp::open(GString *fileName, int page,
00195               GString *ownerPassword, GString *userPassword) {
00196   XPDFViewer *viewer;
00197 
00198   viewer = new XPDFViewer(this, fileName, page, NULL,
00199               ownerPassword, userPassword);
00200   if (!viewer->isOk()) {
00201     delete viewer;
00202     return NULL;
00203   }
00204   if (remoteAtom != None) {
00205     remoteViewer = viewer;
00206     remoteWin = viewer->getWindow();
00207     XtAddEventHandler(remoteWin, PropertyChangeMask, False,
00208               &remoteMsgCbk, this);
00209     XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
00210   }
00211   viewers->append(viewer);
00212   return viewer;
00213 }
00214 
00215 XPDFViewer *XPDFApp::openAtDest(GString *fileName, GString *dest,
00216                 GString *ownerPassword,
00217                 GString *userPassword) {
00218   XPDFViewer *viewer;
00219 
00220   viewer = new XPDFViewer(this, fileName, 1, dest,
00221               ownerPassword, userPassword);
00222   if (!viewer->isOk()) {
00223     delete viewer;
00224     return NULL;
00225   }
00226   if (remoteAtom != None) {
00227     remoteViewer = viewer;
00228     remoteWin = viewer->getWindow();
00229     XtAddEventHandler(remoteWin, PropertyChangeMask, False,
00230               &remoteMsgCbk, this);
00231     XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
00232   }
00233   viewers->append(viewer);
00234   return viewer;
00235 }
00236 
00237 void XPDFApp::close(XPDFViewer *viewer, GBool closeLast) {
00238   int i;
00239 
00240   if (viewers->getLength() == 1) {
00241     if (viewer != (XPDFViewer *)viewers->get(0)) {
00242       return;
00243     }
00244     if (closeLast) {
00245       quit();
00246     } else {
00247       viewer->clear();
00248     }
00249   } else {
00250     for (i = 0; i < viewers->getLength(); ++i) {
00251       if (((XPDFViewer *)viewers->get(i)) == viewer) {
00252     viewers->del(i);
00253     if (remoteAtom != None && remoteViewer == viewer) {
00254       remoteViewer = (XPDFViewer *)viewers->get(viewers->getLength() - 1);
00255       remoteWin = remoteViewer->getWindow();
00256       XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin),
00257                  CurrentTime);
00258     }
00259     delete viewer;
00260     return;
00261       }
00262     }
00263   }
00264 }
00265 
00266 void XPDFApp::quit() {
00267   if (remoteAtom != None) {
00268     XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
00269   }
00270   while (viewers->getLength() > 0) {
00271     delete (XPDFViewer *)viewers->del(0);
00272   }
00273   XtAppSetExitFlag(appContext);
00274 }
00275 
00276 void XPDFApp::run() {
00277   XtAppMainLoop(appContext);
00278 }
00279 
00280 void XPDFApp::setRemoteName(char *remoteName) {
00281   remoteAtom = XInternAtom(display, remoteName, False);
00282   remoteXWin = XGetSelectionOwner(display, remoteAtom);
00283 }
00284 
00285 GBool XPDFApp::remoteServerRunning() {
00286   return remoteXWin != None;
00287 }
00288 
00289 void XPDFApp::remoteOpen(GString *fileName, int page, GBool raise) {
00290   char cmd[remoteCmdSize];
00291 
00292   sprintf(cmd, "%c %d %.200s",
00293       raise ? 'D' : 'd', page, fileName->getCString());
00294   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
00295           PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
00296   XFlush(display);
00297 }
00298 
00299 void XPDFApp::remoteOpenAtDest(GString *fileName, GString *dest, GBool raise) {
00300   char cmd[remoteCmdSize];
00301 
00302   sprintf(cmd, "%c +%.256s %.200s",
00303       raise ? 'D' : 'd', dest->getCString(), fileName->getCString());
00304   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
00305           PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
00306   XFlush(display);
00307 }
00308 
00309 void XPDFApp::remoteRaise() {
00310   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
00311           PropModeReplace, (Guchar *)"r", 2);
00312   XFlush(display);
00313 }
00314 
00315 void XPDFApp::remoteQuit() {
00316   XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
00317           PropModeReplace, (Guchar *)"q", 2);
00318   XFlush(display);
00319 }
00320 
00321 void XPDFApp::remoteMsgCbk(Widget widget, XtPointer ptr,
00322                XEvent *event, Boolean *cont) {
00323   XPDFApp *app = (XPDFApp *)ptr;
00324   char *cmd;
00325   Atom type;
00326   int format;
00327   Gulong size, remain;
00328   char *p, *q;
00329   GString *fileName;
00330   int page;
00331   GString *destName;
00332 
00333   if (event->xproperty.atom != app->remoteAtom) {
00334     *cont = True;
00335     return;
00336   }
00337   *cont = False;
00338 
00339   // get command
00340   if (XGetWindowProperty(app->display, XtWindow(app->remoteWin),
00341              app->remoteAtom, 0, remoteCmdSize/4,
00342              True, app->remoteAtom,
00343              &type, &format, &size, &remain,
00344              (Guchar **)&cmd) != Success) {
00345     return;
00346   }
00347   if (size == 0) {
00348     return;
00349   }
00350 
00351   // raise window
00352   if (cmd[0] == 'D' || cmd[0] == 'r'){
00353     XMapRaised(app->display, XtWindow(app->remoteWin));
00354     XFlush(app->display);
00355   }
00356 
00357   // display file / page
00358   if (cmd[0] == 'd' || cmd[0] == 'D') {
00359     p = cmd + 2;
00360     q = strchr(p, ' ');
00361     if (!q) {
00362       return;
00363     }
00364     *q++ = '\0';
00365     page = 1;
00366     destName = NULL;
00367     if (*p == '+') {
00368       destName = new GString(p + 1);
00369     } else {
00370       page = atoi(p);
00371     }
00372     if (q) {
00373       fileName = new GString(q);
00374       app->remoteViewer->open(fileName, page, destName);
00375       delete fileName;
00376     }
00377     XFree((XPointer)cmd);
00378     if (destName) {
00379       delete destName;
00380     }
00381 
00382   // quit
00383   } else if (cmd[0] == 'q') {
00384     app->quit();
00385   }
00386 }
KDE Home | KDE Accessibility Home | Description of Access Keys