home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ghostscript-2.6.2-src.tgz / tar.out / fsf / ghostscript / gdevxini.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-28  |  31.5 KB  |  986 lines

  1. /* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gdevxini.c */
  20. /* X Windows driver initialization for Ghostscript library */
  21. #include "gx.h"            /* for gx_bitmap; includes std.h */
  22. #include "memory_.h"
  23. #include "math_.h"
  24. #include "x_.h"
  25. #include "gxdevice.h"
  26. #include "gdevx.h"
  27.  
  28. extern char *getenv(P1(const char *));
  29.  
  30. private XtResource resources[] = {
  31.     {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
  32.      XtOffsetOf(gx_device_X, background),
  33.      XtRString, (XtPointer)"XtDefaultBackground"},
  34.     {XtNborderColor, XtCBorderColor, XtRPixel, sizeof(Pixel),
  35.      XtOffsetOf(gx_device_X, borderColor),
  36.      XtRString, (XtPointer)"XtDefaultForeground"},
  37.     {XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
  38.      XtOffsetOf(gx_device_X, borderWidth),
  39.      XtRImmediate, (XtPointer)1},
  40.     {"dingbatFonts", "DingbatFonts", XtRString, sizeof(String), 
  41.      XtOffsetOf(gx_device_X, dingbatFonts),
  42.      XtRString, "ZapfDingbats: -Adobe-ITC Zapf Dingbats-Medium-R-Normal--"},
  43.     {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  44.      XtOffsetOf(gx_device_X, foreground),
  45.      XtRString, (XtPointer)"XtDefaultForeground"},
  46.     {XtNgeometry, XtCGeometry, XtRString, sizeof(String), 
  47.      XtOffsetOf(gx_device_X, geometry),
  48.      XtRString, NULL},
  49.     {"logExternalFonts", "LogExternalFonts", XtRBoolean, sizeof(Boolean), 
  50.      XtOffsetOf(gx_device_X, logXFonts),
  51.      XtRImmediate, (XtPointer)False},
  52.     {"maxGrayRamp", "MaxGrayRamp", XtRInt, sizeof(int), 
  53.      XtOffsetOf(gx_device_X, maxGrayRamp),
  54.      XtRImmediate, (XtPointer)128},
  55.     {"maxRGBRamp", "MaxRGBRamp", XtRInt, sizeof(int), 
  56.      XtOffsetOf(gx_device_X, maxRGBRamp),
  57.      XtRImmediate, (XtPointer)5},
  58.     {"palette", "Palette", XtRString, sizeof(String), 
  59.      XtOffsetOf(gx_device_X, palette),
  60.      XtRString, "Color"},
  61.  
  62.     /* I had to compress the whitespace out of the default string to
  63.      * satisfy certain balky compilers.
  64.      */
  65.     {"regularFonts", "RegularFonts", XtRString, sizeof(String), 
  66.      XtOffsetOf(gx_device_X, regularFonts),
  67.      XtRString, "\
  68. AvantGarde-Book:-Adobe-ITC Avant Garde Gothic-Book-R-Normal--\n\
  69. AvantGarde-BookOblique:-Adobe-ITC Avant Garde Gothic-Book-O-Normal--\n\
  70. AvantGarde-Demi:-Adobe-ITC Avant Garde Gothic-Demi-R-Normal--\n\
  71. AvantGarde-DemiOblique:-Adobe-ITC Avant Garde Gothic-Demi-O-Normal--\n\
  72. Bookman-Demi:-Adobe-ITC Bookman-Demi-R-Normal--\n\
  73. Bookman-DemiItalic:-Adobe-ITC Bookman-Demi-I-Normal--\n\
  74. Bookman-Light:-Adobe-ITC Bookman-Light-R-Normal--\n\
  75. Bookman-LightItalic:-Adobe-ITC Bookman-Light-I-Normal--\n\
  76. Courier:-Adobe-Courier-Medium-R-Normal--\n\
  77. Courier-Bold:-Adobe-Courier-Bold-R-Normal--\n\
  78. Courier-BoldOblique:-Adobe-Courier-Bold-O-Normal--\n\
  79. Courier-Oblique:-Adobe-Courier-Medium-O-Normal--\n\
  80. Helvetica:-Adobe-Helvetica-Medium-R-Normal--\n\
  81. Helvetica-Bold:-Adobe-Helvetica-Bold-R-Normal--\n\
  82. Helvetica-BoldOblique:-Adobe-Helvetica-Bold-O-Normal--\n\
  83. Helvetica-Narrow:-Adobe-Helvetica-Medium-R-Narrow--\n\
  84. Helvetica-Narrow-Bold:-Adobe-Helvetica-Bold-R-Narrow--\n\
  85. Helvetica-Narrow-BoldOblique:-Adobe-Helvetica-Bold-O-Narrow--\n\
  86. Helvetica-Narrow-Oblique:-Adobe-Helvetica-Medium-O-Narrow--\n\
  87. Helvetica-Oblique:-Adobe-Helvetica-Medium-O-Normal--\n\
  88. NewCenturySchlbk-Bold:-Adobe-New Century Schoolbook-Bold-R-Normal--\n\
  89. NewCenturySchlbk-BoldItalic:-Adobe-New Century Schoolbook-Bold-I-Normal--\n\
  90. NewCenturySchlbk-Italic:-Adobe-New Century Schoolbook-Medium-I-Normal--\n\
  91. NewCenturySchlbk-Roman:-Adobe-New Century Schoolbook-Medium-R-Normal--\n\
  92. Palatino-Bold:-Adobe-Palatino-Bold-R-Normal--\n\
  93. Palatino-BoldItalic:-Adobe-Palatino-Bold-I-Normal--\n\
  94. Palatino-Italic:-Adobe-Palatino-Medium-I-Normal--\n\
  95. Palatino-Roman:-Adobe-Palatino-Medium-R-Normal--\n\
  96. Times-Bold:-Adobe-Times-Bold-R-Normal--\n\
  97. Times-BoldItalic:-Adobe-Times-Bold-I-Normal--\n\
  98. Times-Italic:-Adobe-Times-Medium-I-Normal--\n\
  99. Times-Roman:-Adobe-Times-Medium-R-Normal--\n\
  100. Utopia-Bold:-Adobe-Utopia-Bold-R-Normal--\n\
  101. Utopia-BoldItalic:-Adobe-Utopia-Bold-I-Normal--\n\
  102. Utopia-Italic:-Adobe-Utopia-Regular-I-Normal--\n\
  103. Utopia-Regular:-Adobe-Utopia-Regular-R-Normal--\n\
  104. ZapfChancery-MediumItalic:-Adobe-ITC Zapf Chancery-Medium-I-Normal--"},
  105.     {"symbolFonts", "SymbolFonts", XtRString, sizeof(String), 
  106.      XtOffsetOf(gx_device_X, symbolFonts),
  107.      XtRString, "Symbol: -Adobe-Symbol-Medium-R-Normal--"},
  108.     {"useBackingPixmap", "UseBackingPixmap", XtRBoolean, sizeof(Boolean), 
  109.      XtOffsetOf(gx_device_X, useBackingPixmap),
  110.      XtRImmediate, (XtPointer)True},
  111.     {"useExternalFonts", "UseExternalFonts", XtRBoolean, sizeof(Boolean), 
  112.      XtOffsetOf(gx_device_X, useXFonts),
  113.      XtRImmediate, (XtPointer)True},
  114.     {"useFontExtensions", "UseFontExtensions", XtRBoolean, sizeof(Boolean), 
  115.      XtOffsetOf(gx_device_X, useFontExtensions),
  116.      XtRImmediate, (XtPointer)True},
  117.     {"useScalableFonts", "UseScalableFonts", XtRBoolean, sizeof(Boolean), 
  118.      XtOffsetOf(gx_device_X, useScalableFonts),
  119.      XtRImmediate, (XtPointer)True},
  120.     {"useXPutImage", "UseXPutImage", XtRBoolean, sizeof(Boolean), 
  121.      XtOffsetOf(gx_device_X, useXPutImage),
  122.      XtRImmediate, (XtPointer)True},
  123.     {"useXSetTile", "UseXSetTile", XtRBoolean, sizeof(Boolean), 
  124.      XtOffsetOf(gx_device_X, useXSetTile),
  125.      XtRImmediate, (XtPointer)True},
  126.     {"xResolution", "Resolution", XtRFloat, sizeof(float),
  127.      XtOffsetOf(gx_device_X, xResolution),
  128.      XtRString, (XtPointer)"0.0"},
  129.     {"yResolution", "Resolution", XtRFloat, sizeof(float),
  130.      XtOffsetOf(gx_device_X, yResolution),
  131.      XtRString, (XtPointer)"0.0"},
  132. };
  133.  
  134. private String
  135. fallback_resources[] = {
  136.     "Ghostscript*Background: white",
  137.     "Ghostscript*Foreground: black",
  138.     NULL
  139. };
  140.  
  141. /* Define constants for orientation from ghostview */
  142. /* Number represents clockwise rotation of the paper in degrees */
  143. typedef enum {
  144.   Portrait = 0,        /* Normal portrait orientation */
  145.   Landscape = 90,    /* Normal landscape orientation */
  146.   Upsidedown = 180,    /* Don't think this will be used much */
  147.   Seascape = 270    /* Landscape rotated the wrong way */
  148. } orientation;
  149.  
  150. /* Forward references */
  151. private void gdev_x_setup_colors(P1(gx_device_X *));
  152. private void gdev_x_setup_fontmap(P1(gx_device_X *));
  153.  
  154. /* Catch the alloc error when there is not enough resources for the
  155.  * backing pixmap.  Automatically shut off backing pixmap and let the
  156.  * user know when this happens.
  157.  */
  158. private Boolean alloc_error;
  159. private XErrorHandler orighandler;
  160. private XErrorHandler oldhandler;
  161.  
  162. private int
  163. x_catch_alloc(Display *dpy, XErrorEvent *err)
  164. {
  165.     if (err->error_code == BadAlloc)
  166.     alloc_error = True;
  167.     if (alloc_error)
  168.     return 0;
  169.     return oldhandler(dpy, err);
  170. }
  171.  
  172. int
  173. x_catch_free_colors(Display *dpy, XErrorEvent *err)
  174. {
  175.     if (err->request_code == X_FreeColors) return 0;
  176.     return orighandler(dpy, err);
  177. }
  178.  
  179. /* Open the X device */
  180. int
  181. gdev_x_open(register gx_device_X *xdev)
  182. {
  183.     XSizeHints sizehints;
  184.     char *window_id;
  185.     XEvent event;
  186.     XVisualInfo xvinfo;
  187.     int nitems;
  188.     XtAppContext app_con;
  189.     Widget toplevel;
  190.     Display *dpy;
  191.     XColor xc;
  192.     int zero = 0;
  193.  
  194. #ifdef DEBUG
  195.     if (gs_debug['X']) {
  196.     extern int _Xdebug;
  197.  
  198.     _Xdebug = 1;
  199.     }
  200. #endif
  201.     if (!(xdev->dpy = XOpenDisplay((char *)NULL))) {
  202.     char *dispname = getenv("DISPLAY");
  203.  
  204.     eprintf1("gs: Cannot open X display `%s'.\n",
  205.          (dispname == NULL ? "(null)" : dispname));
  206.     exit(1);
  207.     }
  208.     xdev->dest = 0;
  209.     if ((window_id = getenv("GHOSTVIEW"))) {
  210.     if (!(xdev->ghostview = sscanf(window_id, "%d %d",
  211.                        &(xdev->win), &(xdev->dest)))) {
  212.         eprintf("gs: Cannot get Window ID from ghostview.\n");
  213.         exit(1);
  214.     }
  215.     }
  216.     if (xdev->ghostview) {
  217.     XWindowAttributes attrib;
  218.     Atom type;
  219.     int format;
  220.     unsigned long nitems, bytes_after;
  221.     char *buf;
  222.     Atom ghostview_atom = XInternAtom(xdev->dpy, "GHOSTVIEW", False);
  223.  
  224.     if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
  225.         xdev->scr = attrib.screen;
  226.         xvinfo.visual = attrib.visual;
  227.         xdev->cmap = attrib.colormap;
  228.         xdev->width = attrib.width;
  229.         xdev->height = attrib.height;
  230.     }
  231.     /* Delete property if explicit dest is given */
  232.     if (XGetWindowProperty(xdev->dpy, xdev->win, ghostview_atom, 0,
  233.                    256, (xdev->dest != 0), XA_STRING,
  234.                    &type, &format, &nitems, &bytes_after,
  235.                    (unsigned char **)&buf) == 0 &&
  236.         type == XA_STRING) {
  237.         int llx, lly, urx, ury;
  238.         int left_margin = 0, bottom_margin = 0;
  239.         int right_margin = 0, top_margin = 0;
  240.  
  241.         /* We declare page_orientation as an int so that we can */
  242.         /* use an int * to reference it for sscanf; compilers */
  243.         /* might be tempted to use less space to hold it if */
  244.         /* it were declared as an orientation. */
  245.         int /*orientation*/ page_orientation;
  246.         float xppp, yppp;    /* pixels per point */
  247.         nitems = sscanf(buf,
  248.                 "%d %d %d %d %d %d %f %f %d %d %d %d",
  249.                 &(xdev->bpixmap), &page_orientation,
  250.                 &llx, &lly, &urx, &ury,
  251.                 &(xdev->x_pixels_per_inch),
  252.                 &(xdev->y_pixels_per_inch),
  253.                 &left_margin, &bottom_margin,
  254.                 &right_margin, &top_margin);
  255.         if (!(nitems == 8 || nitems == 12)) {
  256.         eprintf("gs: Cannot get ghostview property.\n");
  257.         exit(1);
  258.         }
  259.         if (xdev->dest && xdev->bpixmap) {
  260.         eprintf("gs: Both destination and backing pixmap specified.\n");
  261.         exit(1);
  262.         }
  263.         if (xdev->dest) {
  264.         Window root;
  265.         int x, y;
  266.         unsigned int width, height;
  267.         unsigned int border_width, depth;
  268.  
  269.         if (XGetGeometry(xdev->dpy, xdev->dest, &root, &x, &y,
  270.                  &width, &height, &border_width, &depth)) {
  271.             xdev->width = width;
  272.             xdev->height = height;
  273.         }
  274.         }
  275.         xppp = xdev->x_pixels_per_inch / 72.0;
  276.         yppp = xdev->y_pixels_per_inch / 72.0;
  277.         switch (page_orientation) {
  278.         case Portrait:
  279.         xdev->initial_matrix.xx = xppp;
  280.         xdev->initial_matrix.xy = 0.0;
  281.         xdev->initial_matrix.yx = 0.0;
  282.         xdev->initial_matrix.yy = -yppp;
  283.         xdev->initial_matrix.tx = -llx * xppp;
  284.         xdev->initial_matrix.ty = ury * yppp;
  285.         break;
  286.         case Landscape:
  287.         xdev->initial_matrix.xx = 0.0;
  288.         xdev->initial_matrix.xy = yppp;
  289.         xdev->initial_matrix.yx = xppp;
  290.         xdev->initial_matrix.yy = 0.0;
  291.         xdev->initial_matrix.tx = -lly * xppp;
  292.         xdev->initial_matrix.ty = -llx * yppp;
  293.         break;
  294.         case Upsidedown:
  295.         xdev->initial_matrix.xx = -xppp;
  296.         xdev->initial_matrix.xy = 0.0;
  297.         xdev->initial_matrix.yx = 0.0;
  298.         xdev->initial_matrix.yy = yppp;
  299.         xdev->initial_matrix.tx = urx * xppp;
  300.         xdev->initial_matrix.ty = -lly * yppp;
  301.         break;
  302.         case Seascape:
  303.         xdev->initial_matrix.xx = 0.0;
  304.         xdev->initial_matrix.xy = -yppp;
  305.         xdev->initial_matrix.yx = -xppp;
  306.         xdev->initial_matrix.yy = 0.0;
  307.         xdev->initial_matrix.tx = ury * xppp;
  308.         xdev->initial_matrix.ty = urx * yppp;
  309.         break;
  310.         }
  311.  
  312.         /* The following sets the imageable area according to the */
  313.         /* bounding box and margins sent by ghostview.            */
  314.         xdev->l_margin = (llx - left_margin) / 72.0;
  315.         xdev->b_margin = (lly - bottom_margin) / 72.0;
  316.         xdev->r_margin = xdev->width / xdev->x_pixels_per_inch -
  317.                  (urx + right_margin) / 72.0;
  318.         xdev->t_margin = xdev->height / xdev->y_pixels_per_inch -
  319.                  (ury + top_margin) / 72.0;
  320.     } else {
  321.         eprintf("gs: Cannot get ghostview property.\n");
  322.         exit(1);
  323.     }
  324.     } else {
  325.     Screen *scr = DefaultScreenOfDisplay(xdev->dpy);
  326.  
  327.     xdev->scr = scr;
  328.     xvinfo.visual = DefaultVisualOfScreen(scr);
  329.     xdev->cmap = DefaultColormapOfScreen(scr);
  330.     }
  331.  
  332.     xvinfo.visualid = XVisualIDFromVisual(xvinfo.visual);
  333.     xdev->vinfo = XGetVisualInfo(xdev->dpy, VisualIDMask, &xvinfo, &nitems);
  334.     if (xdev->vinfo == NULL) {
  335.     eprintf("gs: Cannot get XVisualInfo.\n");
  336.     exit(1);
  337.     }
  338.  
  339.     /* Buggy X servers may cause a Bad Access on XFreeColors. */
  340.     orighandler = XSetErrorHandler(x_catch_free_colors);
  341.  
  342.     /* Get X Resources.  Use the toolkit for this. */
  343.     XtToolkitInitialize();
  344.     app_con = XtCreateApplicationContext();
  345.     XtAppSetFallbackResources(app_con, fallback_resources);
  346.     dpy = XtOpenDisplay(app_con, NULL, "ghostscript", "Ghostscript",
  347.             NULL, 0, &zero, NULL);
  348.     toplevel = XtAppCreateShell(NULL, "Ghostscript",
  349.                 applicationShellWidgetClass, dpy, NULL, 0);
  350.     XtGetApplicationResources(toplevel, (XtPointer) xdev,
  351.                   resources, XtNumber(resources), NULL, 0);
  352.  
  353.     /* Reserve foreground and background colors under the regular connection. */
  354.     xc.pixel = xdev->foreground;
  355.     XQueryColor(xdev->dpy, xdev->cmap, &xc);
  356.     XAllocColor(xdev->dpy, xdev->cmap, &xc);
  357.     xc.pixel = xdev->background;
  358.     XQueryColor(xdev->dpy, xdev->cmap, &xc);
  359.     XAllocColor(xdev->dpy, xdev->cmap, &xc);
  360.  
  361.     /* And close the toolkit connection. */
  362.     XtDestroyWidget(toplevel);
  363.     XtCloseDisplay(dpy);
  364.     XtDestroyApplicationContext(app_con);
  365.  
  366.     gdev_x_setup_colors(xdev);
  367.     gdev_x_setup_fontmap(xdev);
  368.  
  369.     if (!xdev->ghostview) {
  370.     XWMHints wm_hints;
  371.     XSetWindowAttributes xswa;
  372.     gx_device *dev = (gx_device *)xdev;
  373.  
  374.     /* Take care of resolution and paper size. */
  375.     if (xdev->x_pixels_per_inch == FAKE_RES ||
  376.         xdev->y_pixels_per_inch == FAKE_RES) {
  377.         float xsize, ysize;
  378.  
  379.         xsize = (float)xdev->width / xdev->x_pixels_per_inch;
  380.         ysize = (float)xdev->height / xdev->y_pixels_per_inch;
  381.  
  382.         if (xdev->xResolution == 0.0 && xdev->yResolution == 0.0) {
  383.         float dpi, xdpi, ydpi;
  384.  
  385.         xdpi = 25.4 * WidthOfScreen(xdev->scr) /
  386.                WidthMMOfScreen(xdev->scr);
  387.         ydpi = 25.4 * HeightOfScreen(xdev->scr) /
  388.                HeightMMOfScreen(xdev->scr);
  389.         dpi = min(xdpi, ydpi);
  390.  
  391.         while (xsize*dpi > WidthOfScreen(xdev->scr)-32 ||
  392.                ysize*dpi > HeightOfScreen(xdev->scr)-32) {
  393.             dpi *= 0.95;
  394.         }
  395.         xdev->x_pixels_per_inch = dpi;
  396.         xdev->y_pixels_per_inch = dpi;
  397.         } else {
  398.         xdev->x_pixels_per_inch = xdev->xResolution;
  399.         xdev->y_pixels_per_inch = xdev->yResolution;
  400.         }
  401.         if (xdev->width > WidthOfScreen(xdev->scr)) {
  402.         xdev->width = xsize*xdev->x_pixels_per_inch;
  403.         }
  404.         if (xdev->height > HeightOfScreen(xdev->scr)) {
  405.         xdev->height = ysize*xdev->y_pixels_per_inch;
  406.         }
  407.     }
  408.  
  409.     sizehints.x = 0;
  410.     sizehints.y = 0;
  411.     sizehints.width = xdev->width;
  412.     sizehints.height = xdev->height;
  413.     sizehints.flags = 0;
  414.  
  415.     if (xdev->geometry != NULL) {
  416.         /*
  417.          * Note that border_width must be set first.  We can't use
  418.          * scr, because that is a Screen*, and XWMGeometry wants
  419.          * the screen number.
  420.          */
  421.         char gstr[40];
  422.         int bitmask;
  423.  
  424.         sprintf(gstr, "%dx%d+%d+%d", sizehints.width,
  425.             sizehints.height, sizehints.x, sizehints.y);
  426.         bitmask = XWMGeometry(xdev->dpy, DefaultScreen(xdev->dpy),
  427.                   xdev->geometry, gstr, xdev->borderWidth,
  428.                   &sizehints,
  429.                   &sizehints.x, &sizehints.y,
  430.                   &sizehints.width, &sizehints.height,
  431.                   &sizehints.win_gravity);
  432.  
  433.         if (bitmask & (XValue | YValue))
  434.         sizehints.flags |= USPosition;
  435.     }
  436.  
  437.     gx_default_get_initial_matrix(dev, &(xdev->initial_matrix));
  438.  
  439.     xswa.event_mask = ExposureMask;
  440.     xswa.background_pixel = xdev->background;
  441.     xswa.border_pixel = xdev->borderColor;
  442.     xswa.colormap = xdev->cmap;
  443.     xdev->win = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
  444.                   sizehints.x, sizehints.y,    /* upper left */
  445.                   xdev->width, xdev->height,
  446.                   xdev->borderWidth,
  447.                   xdev->vinfo->depth,
  448.                   InputOutput,    /* class */
  449.                   xdev->vinfo->visual,    /* visual */
  450.                   CWEventMask | CWBackPixel |
  451.                   CWBorderPixel | CWColormap,
  452.                   &xswa);
  453.     XStoreName(xdev->dpy, xdev->win, "ghostscript");
  454.     XSetWMNormalHints(xdev->dpy, xdev->win, &sizehints);
  455.     wm_hints.flags = InputHint;
  456.     wm_hints.input = False;
  457.     XSetWMHints(xdev->dpy, xdev->win, &wm_hints); /* avoid input focus */
  458.     }
  459.  
  460.     xdev->ht.pixmap = (Pixmap) 0;
  461.     xdev->ht.id = gx_no_bitmap_id;;
  462.     xdev->fill_style = FillSolid;
  463.     xdev->function = GXcopy;
  464.     xdev->fid = (Font) 0;
  465.  
  466.     /* Set up a graphics context */
  467.     xdev->gc = XCreateGC(xdev->dpy, xdev->win, 0, (XGCValues *) NULL);
  468.     XSetFunction(xdev->dpy, xdev->gc, GXcopy);
  469.     XSetLineAttributes(xdev->dpy, xdev->gc, 0,
  470.                LineSolid, CapButt, JoinMiter);
  471.  
  472.     gdev_x_clear_window(xdev);
  473.  
  474.     if (!xdev->ghostview) {    /* Make the window appear. */
  475.     XMapWindow(xdev->dpy, xdev->win);
  476.  
  477.     /* Before anything else, do a flush and wait for */
  478.     /* an exposure event. */
  479.     XFlush(xdev->dpy);
  480.     XNextEvent(xdev->dpy, &event);
  481.     } else {
  482.     /* Create an unmapped window, that the window manager will ignore.
  483.      * This invisible window will be used to receive "next page"
  484.      * events from ghostview */
  485.     XSetWindowAttributes attributes;
  486.  
  487.     attributes.override_redirect = True;
  488.     xdev->mwin = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
  489.                    0, 0, 1, 1, 0, CopyFromParent,
  490.                    CopyFromParent, CopyFromParent,
  491.                    CWOverrideRedirect, &attributes);
  492.     xdev->next = XInternAtom(xdev->dpy, "NEXT", False);
  493.     xdev->page = XInternAtom(xdev->dpy, "PAGE", False);
  494.     xdev->done = XInternAtom(xdev->dpy, "DONE", False);
  495.     }
  496.  
  497.     xdev->ht.no_pixmap = XCreatePixmap(xdev->dpy, xdev->win, 1, 1,
  498.                        xdev->vinfo->depth);
  499.  
  500.     return 0;
  501. }
  502.  
  503. /* Allocate the backing pixmap, if any, and clear the window. */
  504. void
  505. gdev_x_clear_window(gx_device_X *xdev)
  506. {
  507.     if (!xdev->ghostview) {
  508.     if (xdev->useBackingPixmap) {
  509.         oldhandler = XSetErrorHandler(x_catch_alloc);
  510.         alloc_error = False;
  511.         xdev->bpixmap =
  512.         XCreatePixmap(xdev->dpy, xdev->win,
  513.                   xdev->width, xdev->height,
  514.                   xdev->vinfo->depth);
  515.         XSync(xdev->dpy, False);    /* Force the error */
  516.         if (alloc_error) {
  517.         xdev->useBackingPixmap = False;
  518.         eprintf("Warning: Failed to allocated backing pixmap.\n");
  519.         if (xdev->bpixmap) {
  520.             XFreePixmap(xdev->dpy, xdev->bpixmap);
  521.             xdev->bpixmap = None;
  522.             XSync(xdev->dpy, False);    /* Force the error */
  523.         }
  524.         }
  525.         oldhandler = XSetErrorHandler(oldhandler);
  526.     } else
  527.         xdev->bpixmap = (Pixmap) 0;
  528.     }
  529.     /* Clear the destination pixmap to avoid initializing with garbage. */
  530.     if (xdev->dest != (Pixmap) 0) {
  531.     XSetForeground(xdev->dpy, xdev->gc, xdev->background);
  532.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc,
  533.                0, 0, xdev->width, xdev->height);
  534.     } else {
  535.     xdev->dest = (xdev->bpixmap != (Pixmap) 0 ?
  536.               xdev->bpixmap : (Pixmap) xdev->win);
  537.     }
  538.  
  539.     /* Clear the background pixmap to avoid initializing with garbage. */
  540.     if (xdev->bpixmap != (Pixmap) 0) {
  541.     if (!xdev->ghostview)
  542.         XSetWindowBackgroundPixmap(xdev->dpy, xdev->win, xdev->bpixmap);
  543.     XSetForeground(xdev->dpy, xdev->gc, xdev->background);
  544.     XFillRectangle(xdev->dpy, xdev->bpixmap, xdev->gc,
  545.                0, 0, xdev->width, xdev->height);
  546.     }
  547.     /* Initialize foreground and background colors */
  548.     xdev->back_color = xdev->background;
  549.     XSetBackground(xdev->dpy, xdev->gc, xdev->background);
  550.     xdev->fore_color = xdev->background;
  551.     XSetForeground(xdev->dpy, xdev->gc, xdev->background);
  552.     xdev->colors_or = xdev->colors_and = xdev->background;
  553. }
  554.  
  555. #if HaveStdCMap
  556. /* get Standard colormap if available */
  557. private XStandardColormap *
  558. x_get_std_cmap(gx_device_X *xdev, Atom prop)
  559. {
  560.     int i;
  561.     XStandardColormap *scmap, *sp;
  562.     int nitems;
  563.  
  564.     if (XGetRGBColormaps(xdev->dpy, RootWindowOfScreen(xdev->scr),
  565.              &scmap, &nitems, prop))
  566.     for (i = 0, sp = scmap; i < nitems; i++, sp++)
  567.         if (xdev->cmap == sp->colormap)
  568.         return sp;
  569.  
  570.     return NULL;
  571. }
  572. #endif
  573.  
  574. /* Setup color mapping. */
  575. private void
  576. gdev_x_setup_colors(gx_device_X *xdev)
  577. {
  578.     char palette;
  579.  
  580.     palette = ((xdev->vinfo->class != StaticGray) &&
  581.            (xdev->vinfo->class != GrayScale) ? 'C' :  /* Color */
  582.            (xdev->vinfo->colormap_size > 2) ?  'G' :  /* GrayScale */
  583.                            'M');  /* MonoChrome */
  584.     if (xdev->ghostview) {
  585.     Atom gv_colors = XInternAtom(xdev->dpy, "GHOSTVIEW_COLORS", False);
  586.     Atom type;
  587.     int format;
  588.     unsigned long nitems, bytes_after;
  589.     char *buf;
  590.  
  591.     /* Delete property if explicit dest is given */
  592.     if (XGetWindowProperty(xdev->dpy, xdev->win, gv_colors, 0,
  593.                    256, (xdev->dest != 0), XA_STRING,
  594.                    &type, &format, &nitems, &bytes_after,
  595.                    (unsigned char **)&buf) == 0 &&
  596.         type == XA_STRING) {
  597.         nitems = sscanf(buf, "%*s %d %d", &(xdev->foreground),
  598.                               &(xdev->background));
  599.         if (nitems != 2 || *buf != 'M' && *buf != 'G' && *buf != 'C') {
  600.         eprintf("gs: Malformed ghostview color property.\n");
  601.         exit(1);
  602.         }
  603.         palette = max(palette, *buf);
  604.     }
  605.     } else {
  606.     if      (xdev->palette[0] == 'c') xdev->palette[0] = 'C';
  607.     else if (xdev->palette[0] == 'g') xdev->palette[0] = 'G';
  608.     else if (xdev->palette[0] == 'm') xdev->palette[0] = 'M';
  609.     palette = max(palette, xdev->palette[0]);
  610.     }
  611.  
  612.     /* set up color mappings here */
  613.     xdev->color_mask = 0xffff - (0xffff >> xdev->vinfo->bits_per_rgb);
  614.     xdev->half_dev_color = 1 << (15 - xdev->vinfo->bits_per_rgb);
  615. #define num_rgb (1 << xdev->vinfo->bits_per_rgb)
  616.  
  617. #if HaveStdCMap
  618.     xdev->std_cmap = NULL;
  619. #endif
  620.     xdev->dither_colors = NULL;
  621.     xdev->dynamic_colors = NULL;
  622.     xdev->dynamic_size = 0;
  623.     xdev->dynamic_allocs = 0;
  624.     xdev->color_info.depth = xdev->vinfo->depth;
  625.  
  626.     if (palette == 'C') {
  627.     xdev->color_info.num_components = 3;
  628.     xdev->color_info.max_gray =
  629.         xdev->color_info.max_rgb = num_rgb - 1;
  630. #if HaveStdCMap
  631.     /* Get a standard color map if available */
  632.     if (xdev->vinfo->visual == DefaultVisualOfScreen(xdev->scr)) {
  633.         xdev->std_cmap = x_get_std_cmap(xdev, XA_RGB_DEFAULT_MAP);
  634.     } else {
  635.         xdev->std_cmap = x_get_std_cmap(xdev, XA_RGB_BEST_MAP);
  636.     }
  637.     if (xdev->std_cmap) {
  638.         xdev->color_info.dither_gray =
  639.         xdev->color_info.dither_rgb =
  640.         min(xdev->std_cmap->red_max,
  641.             min(xdev->std_cmap->green_max,
  642.             xdev->std_cmap->blue_max)) + 1;
  643.     } else
  644. #endif
  645.     /* Otherwise set up a rgb cube of our own */
  646.     /* The color cube is limited to about 1/2 of the available */
  647.     /* colormap, the user specified maxRGBRamp (usually 5), */
  648.     /* or the number of representable colors */
  649. #define cube(r) (r*r*r)
  650. #define cbrt(r) pow(r, 1.0/3.0)
  651.     {
  652.         int ramp_size =
  653.             min((int)cbrt((double)xdev->vinfo->colormap_size / 2.0),
  654.                 min(xdev->maxRGBRamp, num_rgb));
  655.  
  656.         while (!xdev->dither_colors && ramp_size >= 2) {
  657.         int max_rgb = ramp_size - 1;
  658.         int r, g, b;
  659.  
  660.         xdev->color_info.dither_gray =
  661.             xdev->color_info.dither_rgb = ramp_size;
  662.         xdev->dither_colors =
  663.             (x_pixel *) gs_malloc(sizeof(x_pixel), cube(ramp_size),
  664.                       "x11_rgb_cube");
  665.         if (xdev->dither_colors == NULL) {
  666.             ramp_size--;
  667.             goto no_cube;
  668.         }
  669.         for (r = 0; r < ramp_size; r++) {
  670.             for (g = 0; g < ramp_size; g++) {
  671.             for (b = 0; b < ramp_size; b++) {
  672.                 if (r == 0 && g == 0 && b == 0) {
  673.                 xdev->dither_colors[0] = xdev->foreground;
  674.                 } else if (r == max_rgb && g == max_rgb &&
  675.                        b == max_rgb) {
  676.                 xdev->dither_colors[cube_index(r, g, b)] =
  677.                     xdev->background;
  678.                 } else {
  679.                 XColor xc;
  680.  
  681.                 xc.red = (0xffff * r / max_rgb) &
  682.                      xdev->color_mask;
  683.                 xc.green = (0xffff * g / max_rgb) &
  684.                      xdev->color_mask;
  685.                 xc.blue = (0xffff * b / max_rgb) &
  686.                      xdev->color_mask;
  687.                 if (XAllocColor(xdev->dpy, xdev->cmap, &xc)) {
  688.                     xdev->dither_colors[cube_index(r, g, b)] =
  689.                     xc.pixel;
  690.                 } else {
  691.                     eprintf3("Warning: failed to allocate %dx%dx%d RGB cube.\n",
  692.                          ramp_size, ramp_size, ramp_size);
  693.                     ramp_size--;
  694.                     if (cube_index(r, g, b) - 1 > 0) {
  695.                     XFreeColors(xdev->dpy, xdev->cmap,
  696.                             xdev->dither_colors + 1,
  697.                             cube_index(r, g, b) - 1, 0);
  698.                     }
  699.                     gs_free((char *)xdev->dither_colors,
  700.                         sizeof(x_pixel), cube(ramp_size),
  701.                         "x11_rgb_cube");
  702.                     xdev->dither_colors = NULL;
  703.                     goto no_cube;
  704.                 }
  705.                 }
  706.             }
  707.             }
  708.         }
  709. no_cube:    ;
  710.         }
  711.  
  712.         if (!xdev->dither_colors) {
  713.         goto grayscale;
  714.         }
  715.     }
  716.  
  717.     /* Allocate space for dynamic colors hash table */
  718.     xdev->dynamic_colors =
  719.           (x11color*(*)[]) gs_malloc(sizeof(x11color *), num_rgb,
  720.                      "x11_dynamic_colors");
  721.     if (xdev->dynamic_colors) {
  722.         int i;
  723.         xdev->dynamic_size = num_rgb;
  724.         for (i = 0; i < num_rgb; i++) {
  725.         (*xdev->dynamic_colors)[i] = NULL;
  726.         }
  727.         xdev->max_dynamic_colors = xdev->vinfo->colormap_size -
  728.                        cube(xdev->color_info.dither_rgb);
  729.     }
  730. #undef cube
  731.     } else if (palette == 'G') {
  732. grayscale:
  733.     xdev->color_info.num_components = 1;
  734.     xdev->color_info.max_gray = num_rgb - 1;
  735. #if HaveStdCMap
  736.     /* Get a standard color map if available */
  737.     if (xdev->std_cmap = x_get_std_cmap(xdev, XA_RGB_GRAY_MAP)) {
  738.         xdev->color_info.dither_gray = xdev->std_cmap->red_max +
  739.         xdev->std_cmap->green_max +
  740.         xdev->std_cmap->blue_max + 1;
  741.     } else
  742. #endif
  743.     /* Otherwise set up a gray ramp of our own */
  744.     /* The gray ramp is limited to about 1/2 of the available */
  745.     /* colormap, the user specified maxGrayRamp (usually 128), */
  746.     /* or the number of representable grays */
  747.     {
  748.         int ramp_size = min(xdev->vinfo->colormap_size / 2,
  749.                 min(xdev->maxGrayRamp, num_rgb));
  750.  
  751.         while (!xdev->dither_colors && ramp_size >= 3) {
  752.         int max_gray = ramp_size - 1;
  753.         int i;
  754.  
  755.         xdev->color_info.dither_gray = ramp_size;
  756.         xdev->dither_colors =
  757.             (x_pixel *) gs_malloc(sizeof(x_pixel), ramp_size,
  758.                       "x11_gray_ramp");
  759.         if (xdev->dither_colors == NULL) {
  760.             ramp_size--;
  761.             goto no_ramp;
  762.         }
  763.         for (i = 0; i < ramp_size; i++) {
  764.             XColor xc;
  765.  
  766.             xc.red = xc.green = xc.blue =
  767.             (0xffff * i / max_gray) & xdev->color_mask;
  768.             if (i == 0) {
  769.             xdev->dither_colors[i] = xdev->foreground;
  770.             } else if (i == max_gray) {
  771.             xdev->dither_colors[i] = xdev->background;
  772.             } else {
  773.             if (XAllocColor(xdev->dpy, xdev->cmap, &xc)) {
  774.                 xdev->dither_colors[i] = xc.pixel;
  775.             } else {
  776.                 eprintf1("Warning: failed to allocate %d level gray ramp.\n",
  777.                      ramp_size);
  778.                 ramp_size /= 2;
  779.                 if (i - 1 > 0) {
  780.                 XFreeColors(xdev->dpy, xdev->cmap,
  781.                         xdev->dither_colors + 1, i - 1, 0);
  782.                 }
  783.                 gs_free((char *)xdev->dither_colors,
  784.                     sizeof(x_pixel), ramp_size,
  785.                     "x11_gray_ramp");
  786.                 xdev->dither_colors = NULL;
  787.                 goto no_ramp;
  788.             }
  789.             }
  790.         }
  791. no_ramp:    ;
  792.         }
  793.         if (!xdev->dither_colors) {
  794.         goto monochrome;
  795.         }
  796.     }
  797.  
  798.     /* Allocate space for dynamic colors hash table */
  799.     xdev->dynamic_colors =
  800.           (x11color*(*)[]) gs_malloc(sizeof(x11color *), num_rgb,
  801.                      "x11_dynamic_colors");
  802.     if (xdev->dynamic_colors) {
  803.         int i;
  804.         xdev->dynamic_size = num_rgb;
  805.         for (i = 0; i < num_rgb; i++) {
  806.         (*xdev->dynamic_colors)[i] = NULL;
  807.         }
  808.         xdev->max_dynamic_colors = xdev->vinfo->colormap_size -
  809.                        xdev->color_info.dither_gray;
  810.     }
  811.     } else if (palette == 'M') {
  812. monochrome:
  813.     xdev->color_info.num_components = 1;
  814.     xdev->color_info.max_gray = 1;
  815.     xdev->color_info.dither_gray = 2;
  816.     } else {
  817.     eprintf1("gs: Unknown palette: %s\n", xdev->palette);
  818.     exit(1);
  819.     }
  820. }
  821.  
  822. /* Setup X11 font mapping. */
  823. private char *
  824. get_ps_name(char **cpp, int *len)
  825. {
  826.     char *ret;
  827.     *len = 0;
  828.     /* skip over whitespace and newlines */
  829.     while (**cpp == ' ' || **cpp == '\t' || **cpp == '\n') {
  830.     (*cpp)++;
  831.     }
  832.     /* return font name up to ":", whitespace, or end of string */
  833.     if (**cpp == ':' || **cpp == '\0') {
  834.     return NULL;
  835.     }
  836.     ret = *cpp;
  837.     while (**cpp != ':' &&
  838.        **cpp != ' ' && **cpp != '\t' && **cpp != '\n' &&
  839.        **cpp != '\0') {
  840.     (*cpp)++;
  841.     (*len)++;
  842.     }
  843.     return ret;
  844. }
  845.  
  846. private char *
  847. get_x11_name(char **cpp, int *len)
  848. {
  849.     char *ret;
  850.     int dashes = 0;
  851.     *len = 0;
  852.     /* skip over whitespace and the colon */
  853.     while (**cpp == ' ' || **cpp == '\t' ||
  854.        **cpp == ':') {
  855.     (*cpp)++;
  856.     }
  857.     /* return font name up to end of line or string */
  858.     if (**cpp == '\0' || **cpp == '\n') {
  859.     return NULL;
  860.     }
  861.     ret = *cpp;
  862.     while (dashes != 7 &&
  863.        **cpp != '\0' && **cpp != '\n') {
  864.     if (**cpp == '-') dashes++;
  865.     (*cpp)++;
  866.     (*len)++;
  867.     }
  868.     while (**cpp != '\0' && **cpp != '\n') {
  869.     (*cpp)++;
  870.     }
  871.     if (dashes != 7) return NULL;
  872.     return ret;
  873. }
  874.  
  875. private void
  876. gdev_x_setup_fontmap(gx_device_X *xdev)
  877. {
  878.     char *ps_name;
  879.     char *x11_name;
  880.     int ps_name_len;
  881.     int x11_name_len;
  882.     x11fontmap *font;
  883.     char *cp;
  884.  
  885.     if (!xdev->useXFonts) return;    /* If no external fonts, don't bother */
  886.  
  887.     cp = xdev->regularFonts;
  888.     while (ps_name = get_ps_name(&cp, &ps_name_len)) {
  889.     if (x11_name = get_x11_name(&cp, &x11_name_len)) {
  890.         font = (x11fontmap *)gs_malloc(sizeof(x11fontmap), 1,
  891.                        "x11_setup_fontmap");
  892.         if (font == NULL) continue;
  893.         font->ps_name = (char *)gs_malloc(sizeof(char), ps_name_len+1,
  894.                           "x11_setup_fontmap");
  895.         if (font->ps_name == NULL) {
  896.         gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
  897.         continue;
  898.         }
  899.         strncpy(font->ps_name, ps_name, ps_name_len);
  900.         font->ps_name[ps_name_len] = '\0';
  901.         font->x11_name = (char *)gs_malloc(sizeof(char), x11_name_len,
  902.                            "x11_setup_fontmap");
  903.         if (font->x11_name == NULL) {
  904.         gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
  905.             "x11_font_psname");
  906.         gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
  907.         continue;
  908.         }
  909.         strncpy(font->x11_name, x11_name, x11_name_len-1);
  910.         font->x11_name[x11_name_len-1] = '\0';
  911.         font->std_names = NULL;
  912.         font->iso_names = NULL;
  913.         font->std_count = -1;
  914.         font->iso_count = -1;
  915.         font->next = xdev->regular_fonts;
  916.         xdev->regular_fonts = font;
  917.     }
  918.     }
  919.  
  920.     cp = xdev->symbolFonts;
  921.     while (ps_name = get_ps_name(&cp, &ps_name_len)) {
  922.     if (x11_name = get_x11_name(&cp, &x11_name_len)) {
  923.         font = (x11fontmap *)gs_malloc(sizeof(x11fontmap), 1,
  924.                        "x11_setup_fontmap");
  925.         if (font == NULL) continue;
  926.         font->ps_name = (char *)gs_malloc(sizeof(char), ps_name_len+1,
  927.                           "x11_setup_fontmap");
  928.         if (font->ps_name == NULL) {
  929.         gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
  930.         continue;
  931.         }
  932.         strncpy(font->ps_name, ps_name, ps_name_len);
  933.         font->ps_name[ps_name_len] = '\0';
  934.         font->x11_name = (char *)gs_malloc(sizeof(char), x11_name_len,
  935.                            "x11_setup_fontmap");
  936.         if (font->x11_name == NULL) {
  937.         gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
  938.             "x11_font_psname");
  939.         gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
  940.         continue;
  941.         }
  942.         strncpy(font->x11_name, x11_name, x11_name_len-1);
  943.         font->x11_name[x11_name_len-1] = '\0';
  944.         font->std_names = NULL;
  945.         font->iso_names = NULL;
  946.         font->std_count = -1;
  947.         font->iso_count = -1;
  948.         font->next = xdev->symbol_fonts;
  949.         xdev->symbol_fonts = font;
  950.     }
  951.     }
  952.  
  953.     cp = xdev->dingbatFonts;
  954.     while (ps_name = get_ps_name(&cp, &ps_name_len)) {
  955.     if (x11_name = get_x11_name(&cp, &x11_name_len)) {
  956.         font = (x11fontmap *)gs_malloc(sizeof(x11fontmap), 1,
  957.                        "x11_setup_fontmap");
  958.         if (font == NULL) continue;
  959.         font->ps_name = (char *)gs_malloc(sizeof(char), ps_name_len+1,
  960.                           "x11_setup_fontmap");
  961.         if (font->ps_name == NULL) {
  962.         gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
  963.         continue;
  964.         }
  965.         strncpy(font->ps_name, ps_name, ps_name_len);
  966.         font->ps_name[ps_name_len] = '\0';
  967.         font->x11_name = (char *)gs_malloc(sizeof(char), x11_name_len,
  968.                            "x11_setup_fontmap");
  969.         if (font->x11_name == NULL) {
  970.         gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
  971.             "x11_font_psname");
  972.         gs_free((char *)font, sizeof(x11fontmap), 1, "x11_fontmap");
  973.         continue;
  974.         }
  975.         strncpy(font->x11_name, x11_name, x11_name_len-1);
  976.         font->x11_name[x11_name_len-1] = '\0';
  977.         font->std_names = NULL;
  978.         font->iso_names = NULL;
  979.         font->std_count = -1;
  980.         font->iso_count = -1;
  981.         font->next = xdev->dingbat_fonts;
  982.         xdev->dingbat_fonts = font;
  983.     }
  984.     }
  985. }
  986.