home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / printing / ghostscrip / source / specific / c / gdevx < prev    next >
Encoding:
Text File  |  1991-10-25  |  28.6 KB  |  958 lines

  1. /* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gdevx.c */
  21. /* X Windows driver for Ghostscript library */
  22. /* The X include files include <sys/types.h>, which, on some machines */
  23. /* at least, define uint, ushort, and ulong, which std.h also defines. */
  24. /* We have to shuffle the order of includes to make this all work. */
  25. /* First we arrange things so that std.h defines _uint, _ushort, and _ulong */
  26. /* instead of (our own) uint, ushort, and ulong. */
  27. #  define uint _uint
  28. #  define ushort _ushort
  29. #  define ulong _ulong
  30. #include "gx.h"            /* for gx_bitmap; includes std.h */
  31. #include "memory_.h"
  32. #include "gsmatrix.h"            /* needed for gxdevice.h */
  33. #include "gxbitmap.h"
  34. #include "gxdevice.h"
  35. #  undef uint
  36. #  undef ushort
  37. #  undef ulong
  38. /* Now we can include the X files. */
  39. #include "gdevx.h"
  40.  
  41. typedef unsigned long x_pixel;
  42.  
  43. extern char *getenv(P1(char *));
  44. extern double atof(P1(const char *));
  45.  
  46. /* Flags for patching around bugs in the X library */
  47. #define use_XPutImage 1
  48. #define use_XSetTile 1
  49.  
  50. /* Define whether to use a backing pixmap to handle expose events. */
  51. /* Note that this is a variable rather than a #define. */
  52. /* Note also that it is consulted each time we open an X device. */
  53. private int use_backing = 1;
  54.  
  55. /* Define the maximum size of the temporary pixmap for copy_mono */
  56. /* that we are willing to leave lying around in the server */
  57. /* between uses.  (Assume 32-bit ints here!) */
  58. private int max_temp_pixmap = 20000;
  59.  
  60. /* Forward references */
  61. private int set_tile(P2(gx_device *, gx_bitmap *));
  62. private void free_cp(P1(gx_device *));
  63. /* Screen updating machinery */
  64. #define update_init(dev)\
  65.   ((gx_device_X *)(dev))->up_area = 0,\
  66.   ((gx_device_X *)(dev))->up_count = 0
  67. #define update_flush(dev)\
  68.   if ( ((gx_device_X *)(dev))->up_area != 0 ) update_do_flush(dev)
  69. private void update_do_flush(P1(gx_device *));
  70. private void update_add(P5(gx_device *, int, int, int, int));
  71.  
  72. /* Procedures */
  73.  
  74. dev_proc_open_device(x_open);
  75. dev_proc_sync_output(x_sync);
  76. dev_proc_close_device(x_close);
  77. dev_proc_map_rgb_color(x_map_rgb_color);
  78. dev_proc_map_color_rgb(x_map_color_rgb);
  79. dev_proc_fill_rectangle(x_fill_rectangle);
  80. dev_proc_tile_rectangle(x_tile_rectangle);
  81. dev_proc_copy_mono(x_copy_mono);
  82. dev_proc_copy_color(x_copy_color);
  83. dev_proc_draw_line(x_draw_line);
  84.  
  85. /* The device descriptor */
  86. private gx_device_procs x_procs = {
  87.     x_open,
  88.     gx_default_get_initial_matrix,
  89.     x_sync,
  90.     gx_default_output_page,
  91.     x_close,
  92.     x_map_rgb_color,
  93.     x_map_color_rgb,
  94.     x_fill_rectangle,
  95.     x_tile_rectangle,
  96.     x_copy_mono,
  97.     x_copy_color,
  98.     x_draw_line,
  99.     gx_default_fill_trapezoid,
  100.     gx_default_tile_trapezoid
  101. };
  102.  
  103. /* Define default window parameters */
  104.  
  105. #define PROGRAM_NAME "Ghostscript"
  106.  
  107. #define ARG_BORDER_WIDTH "borderWidth"
  108. #define DEFAULT_BORDER_WIDTH 1
  109.  
  110. #define ARG_BORDER_COLOR "borderColor"
  111. #define DEFAULT_BORDER_COLOR  (xdev->color_black)
  112.  
  113. #define ARG_GEOMETRY "geometry"
  114.  
  115. #define DEFAULT_X_POSITION 0
  116. #define DEFAULT_Y_POSITION 0
  117.  
  118. #define ARG_X_RESOLUTION "xResolution"
  119. #define ARG_Y_RESOLUTION "yResolution"
  120.  
  121. #define DEFAULT_WIDTH_INCHES 8.5
  122. #define DEFAULT_HEIGHT_INCHES 11
  123.  
  124. /* Define a rectangle structure for update bookkeeping */
  125. typedef struct rect_s {
  126.   int xo, yo, xe, ye;
  127. } rect;
  128.  
  129. /* Define the X Windows device */
  130. typedef struct gx_device_X_s {
  131.     gx_device_common;
  132.  
  133.     /* An XImage object for writing bitmap images to the screen */
  134.     XImage image;
  135.  
  136.     /* Global X state */
  137.     Display *dpy;
  138.     Screen *scr;
  139.     int depth;
  140.     Visual *vis;
  141.     Colormap cmap;
  142.     Window win;
  143.     GC gc;
  144.  
  145.     /* A backing pixmap so X will handle exposure automatically */
  146.     Pixmap bpixmap;            /* 0 if use_backing is false, */
  147.                     /* or if it can't be allocated */
  148.     rect update;        /* region needing updating */
  149.     long up_area;        /* total area of update */
  150.                 /* (always 0 if no backing pixmap) */
  151.     int up_count;        /* # of updates since flush */
  152.     Pixmap dest;        /* bpixmap if non-0, else win */
  153.     x_pixel colors_or;    /* 'or' of all device colors used so far */
  154.     x_pixel colors_and;    /* 'and' ditto */
  155.  
  156.     /* An intermediate pixmap for the stencil case of copy_mono */
  157.     struct {
  158.       Pixmap pixmap;
  159.       GC gc;
  160.       int raster, height;
  161.     } cp;
  162.  
  163.     /* Structure for dealing with the halftone tile. */
  164.     /* Later this might become a multi-element cache. */
  165.     struct {
  166.       Pixmap pixmap;
  167.       Pixmap no_pixmap;    /* kludge to get around X bug */
  168.       int width, height, raster;
  169.       byte *bits;
  170.       int bits_size;
  171.       gx_color_index fore_c, back_c;
  172.     } ht;
  173.  
  174.     /* Cache the fill style from the GC */
  175.     int fill_style;
  176.  
  177. #define set_fill_style(style)\
  178.   if ( xdev->fill_style != style )\
  179.     XSetFillStyle(xdev->dpy, xdev->gc, (xdev->fill_style = style))
  180. #define set_function(func)\
  181.   XSetFunction(xdev->dpy, xdev->gc, func) /* don't bother to cache */
  182.  
  183.     /* Map color indices to X pixel values */
  184.     x_pixel colors[8];
  185. #define color_black colors[0]
  186. #define color_white colors[7]
  187.     gx_color_index back_color, fore_color;
  188.  
  189. #define set_back_color(color)\
  190.   if ( xdev->back_color != color )\
  191.    { x_pixel dev_color = xdev->colors[(xdev->back_color = color)];\
  192.      xdev->colors_or |= dev_color;\
  193.      xdev->colors_and &= dev_color;\
  194.      XSetBackground(xdev->dpy, xdev->gc, dev_color);\
  195.    }
  196. #define set_fore_color(color)\
  197.   if ( xdev->fore_color != color )\
  198.    { x_pixel dev_color = xdev->colors[(xdev->fore_color = color)];\
  199.      xdev->colors_or |= dev_color;\
  200.      xdev->colors_and &= dev_color;\
  201.      XSetForeground(xdev->dpy, xdev->gc, dev_color);\
  202.    }
  203.  
  204. } gx_device_X;
  205.  
  206. /* The instance is public. */
  207. gx_device_X gs_x11_device = {
  208.     sizeof(gx_device_X),
  209.     &x_procs,
  210.     "x11",
  211.     0, 0,            /* x and y extent */
  212.     0, 0,            /* x and y density */
  213.     no_margins,
  214.         /* Following parameters are initialized for monochrome */
  215.     0,            /* has color */
  216.     1,            /* max r-g-b value */
  217.     1,            /* bits per color pixel */
  218.         /* End of monochrome/color parameters */
  219.     0,            /* connection not initialized */
  220.     { /* image */
  221.       0, 0,            /* width, height */
  222.       0, XYBitmap, NULL,    /* xoffset, format, data */
  223.       LSBFirst, 8,        /* byte-order, bitmap-unit */
  224.       MSBFirst, 8, 1,    /* bitmap-bit-order, bitmap-pad, depth */
  225.       0, 1,            /* bytes_per_line, bits_per_pixel */
  226.       0, 0, 0,        /* red_mask, green_mask, blue_mask */
  227.       NULL,            /* *obdata */
  228.        { NULL,            /* *(*create_image)() */
  229.          NULL,            /* (*destroy_image)() */
  230.          NULL,            /* (*get_pixel)() */
  231.          NULL,            /* (*put_pixel)() */
  232.          NULL,            /* *(*sub_image)() */
  233.          NULL            /* (*add_pixel)() */
  234.        },
  235.     },
  236.     NULL, NULL, 0, NULL,    /* dpy, scr, depth_all_ones, vis */
  237.                 /* (connection not initialized) */
  238.     (Colormap)None,        /* cmap */
  239.     (Window)None,        /* win */
  240.     NULL,            /* gc */
  241.     (Pixmap)0,        /* bpixmap */
  242.      { 0, 0, 0, 0 }, 0, 0,    /* update, up_area, up_count */
  243.     (Pixmap)0,        /* dest */
  244.     0, 0,            /* colors_or, colors_and */
  245.      { /* cp */
  246.        (Pixmap)0,        /* pixmap */
  247.        NULL,        /* gc */
  248.        -1, -1        /* raster, height */
  249.      },
  250.      { /* ht */
  251.        (Pixmap)None,        /* pixmap */
  252.        (Pixmap)None,        /* no_pixmap */
  253.        0, 0, 0,            /* width, height, raster */
  254.        NULL, 1,             /* bits, bits_size */
  255.        0, 0                /* fore_c, back_c */
  256.      },
  257.     FillSolid,        /* fill_style */
  258.     { 0, 0, 0, 0, 0, 0, 0, 0 }, /* colors[8] */
  259.     0, 0            /* back_color, fore_color */
  260.  
  261. };
  262. /* Macro for casting gx_device argument */
  263. #define xdev ((gx_device_X *)dev)
  264.  
  265. /* Macro to validate and coerce arguments */
  266. #define check_rect_extent()\
  267.     if ( x + w > xdev->width ) w = xdev->width - x;\
  268.     if ( y + h > xdev->height ) h = xdev->height - y;\
  269.     if ( w <= 0 || h <= 0 ) return 0
  270. #define check_rect()\
  271.     if ( x < 0 ) w += x, x = 0;\
  272.     if ( y < 0 ) h += y, y = 0;\
  273.     check_rect_extent()
  274.  
  275. #if !use_XPutImage
  276. /* XPutImage doesn't work, do it ourselves. */
  277. #  undef XPutImage
  278. private void alt_put_image();
  279. #  define XPutImage(dpy,win,gc,im,sx,sy,x,y,w,h)\
  280.     alt_put_image(dev,dpy,win,gc,im,sx,sy,x,y,w,h)
  281. #endif
  282.  
  283.  
  284. /* Open the X device */
  285. int
  286. x_open(register gx_device *dev)
  287. {    Screen *scr;
  288.     XSizeHints sizehints;
  289.     int border_width;
  290.     char *border_width_str, *border_color_str;
  291.     unsigned long border_color;
  292.     char *geometry;
  293.     XColor screen_color, exact_color;
  294.     XSetWindowAttributes xswa;
  295.     XEvent event;
  296. #ifdef DEBUG
  297. if ( gs_debug['X'] )
  298.     { extern int _Xdebug;
  299.       _Xdebug = 1;
  300.     }
  301. #endif
  302.     if ( !(xdev->dpy = XOpenDisplay(NULL)) )
  303.       { char *dispname = getenv("DISPLAY");
  304.         eprintf1("gs: Cannot open X display `%s'.\n",
  305.              (dispname == NULL ? "(null)" : dispname));
  306.         exit(1);
  307.       }
  308.     scr = DefaultScreenOfDisplay(xdev->dpy);
  309.     xdev->scr = scr;
  310.     xdev->depth = DefaultDepthOfScreen(scr);
  311.     xdev->vis = DefaultVisualOfScreen(scr);
  312.     xdev->cmap = DefaultColormapOfScreen(scr);
  313.     xdev->color_black = BlackPixelOfScreen(scr);
  314.     xdev->color_white = WhitePixelOfScreen(scr);
  315.  
  316.     /* Figure out the resolution of our screen; 25.4 is the
  317.      * number of millimeters in an inch.  The only reason for
  318.      * allowing the user to specify the resolution is that
  319.      * X servers commonly lie about it (and about the screen size).
  320.      * We assume that the server is more likely to lie about
  321.      * the resolution than about the pixel size of the screen.
  322.      */
  323.  
  324.     { char *x_res_str = XGetDefault(xdev->dpy, PROGRAM_NAME,
  325.                     ARG_X_RESOLUTION);
  326.       char *y_res_str = XGetDefault(xdev->dpy, PROGRAM_NAME,
  327.                     ARG_Y_RESOLUTION);
  328.       float x_res, y_res;
  329.       if ( x_res_str != NULL && y_res_str != NULL )
  330.         { x_res = atof(x_res_str);
  331.           y_res = atof(y_res_str);
  332.         }
  333.       else
  334.         { int screen_width = WidthOfScreen(scr);
  335.           int screen_height = HeightOfScreen(scr);
  336.           x_res = 25.4 * screen_width / WidthMMOfScreen(scr);
  337.           y_res = 25.4 * screen_height / HeightMMOfScreen(scr);
  338.           if ( x_res * DEFAULT_WIDTH_INCHES > screen_width ||
  339.           y_res * DEFAULT_HEIGHT_INCHES > screen_height
  340.           )
  341.         { /* Force a full page to fit on the screen */
  342.           /* by adjusting the server's claimed resolution. */
  343.           x_res = (screen_width - 32) / (float)DEFAULT_WIDTH_INCHES;
  344.           y_res = (screen_height - 32) / (float)DEFAULT_HEIGHT_INCHES;
  345.           x_res = y_res = min(x_res, y_res);
  346.         }
  347.         }
  348.       xdev->x_pixels_per_inch = x_res;
  349.       xdev->y_pixels_per_inch = y_res;
  350.     }
  351.  
  352.     /* Figure out monochrome vs. color */
  353.     switch ( xdev->vis->class )
  354.       {
  355.       case StaticGray:
  356.       case GrayScale:
  357.         xdev->has_color = 0;
  358.         { int i;
  359.           for ( i = 1; i < 7; i++ )
  360.         xdev->colors[i] = xdev->color_white;
  361.         }
  362.         break;
  363.       default:        /* color */
  364.         xdev->has_color = 1;
  365.         /* Just do primary colors for now */
  366.         { XColor xc;
  367.           int i;
  368.           for ( i = 1; i < 7; i++ )
  369.         { xc.red = (i & 4 ? ~(_ushort)0 : 0);
  370.           xc.green = (i & 2 ? ~(_ushort)0 : 0);
  371.           xc.blue = (i & 1 ? ~(_ushort)0 : 0);
  372.           XAllocColor(xdev->dpy, xdev->cmap, &xc);
  373.           xdev->colors[i] = xc.pixel;
  374.         }
  375.         }
  376.       }
  377.     xdev->ht.pixmap = (Pixmap)0;
  378.     xdev->ht.bits = 0;
  379.     xdev->fill_style = FillSolid;
  380.  
  381.     /* Get defaults from the database. */
  382.     border_width_str = XGetDefault(xdev->dpy, PROGRAM_NAME,
  383.                        ARG_BORDER_WIDTH);
  384.  
  385.     border_width = (border_width_str == NULL ? DEFAULT_BORDER_WIDTH :
  386.             atoi(border_width_str));
  387.  
  388.     border_color_str = XGetDefault(xdev->dpy, PROGRAM_NAME,
  389.                        ARG_BORDER_COLOR);
  390.  
  391.     border_color = (border_color_str == NULL ||
  392.              !XAllocNamedColor(xdev->dpy, xdev->cmap, 
  393.                        border_color_str, 
  394.                        &screen_color, &exact_color) ?
  395.             DEFAULT_BORDER_COLOR :
  396.             screen_color.pixel);
  397.  
  398.     sizehints.x = DEFAULT_X_POSITION;
  399.     sizehints.y = DEFAULT_Y_POSITION;
  400.     sizehints.width = (int)(xdev->x_pixels_per_inch * DEFAULT_WIDTH_INCHES);
  401.     sizehints.height = (int)(xdev->y_pixels_per_inch * DEFAULT_HEIGHT_INCHES);
  402.     sizehints.flags = 0;
  403.  
  404.     geometry = XGetDefault(xdev->dpy, PROGRAM_NAME, ARG_GEOMETRY);
  405.  
  406.     if (geometry != NULL)
  407.        {    /*
  408.          * Note that border_width must be set first.  We can't use
  409.          * scr, because that is a Screen*, and XGeometry wants
  410.          * the screen number.
  411.          */
  412.         char gstr[40];
  413.         int bitmask;
  414.         sprintf(gstr, "%dx%d+%d+%d", sizehints.width,
  415.             sizehints.height, sizehints.x, sizehints.y);
  416.         bitmask = XGeometry(xdev->dpy, DefaultScreen(xdev->dpy),
  417.                     geometry, gstr, border_width,
  418.                     1, 1, /* ``Font'' width and height. */
  419.                     0, 0, /* Interior padding. */
  420.                     &sizehints.x, &sizehints.y,
  421.                     &sizehints.width, &sizehints.height);
  422.  
  423.         if (bitmask & (XValue | YValue))
  424.             sizehints.flags |= USPosition;
  425.  
  426.         if (bitmask & (WidthValue | HeightValue))
  427.             sizehints.flags |= USSize;
  428.        }
  429.  
  430.     xdev->width = sizehints.width;
  431.     xdev->height = sizehints.height;
  432.  
  433.     xswa.event_mask = ExposureMask;
  434.     xswa.background_pixel = xdev->color_black;
  435.     xswa.border_pixel = border_color;
  436.     xdev->win = XCreateWindow(xdev->dpy, RootWindowOfScreen(scr),
  437.                   sizehints.x, sizehints.y, /* upper left */
  438.                   sizehints.width, sizehints.height,
  439.                   border_width,
  440.                   xdev->depth,
  441.                   InputOutput, /* class */
  442.                   xdev->vis, /* visual */
  443.                   CWEventMask | CWBackPixel | CWBorderPixel,
  444.                   &xswa);
  445.     if ( use_backing )
  446.       xdev->bpixmap =
  447.         XCreatePixmap(xdev->dpy, xdev->win,
  448.                   xdev->width, xdev->height,
  449.                   xdev->depth);
  450.     else
  451.       xdev->bpixmap = (Pixmap)0;
  452.     xdev->dest = (xdev->bpixmap != (Pixmap)0 ?
  453.               xdev->bpixmap : (Pixmap)xdev->win);
  454.     xdev->colors_or = 0L;
  455.     xdev->colors_and = ~0L;
  456.     update_init(dev);
  457.  
  458.     XChangeProperty(xdev->dpy, xdev->win, XA_WM_NAME, XA_STRING, 8,
  459.             PropModeReplace, (unsigned char *)PROGRAM_NAME,
  460.             strlen(PROGRAM_NAME));
  461.     XSetNormalHints(xdev->dpy, xdev->win, &sizehints);
  462.  
  463.     /* Set up a graphics context */
  464.     xdev->gc = XCreateGC(xdev->dpy, xdev->win, 0, NULL);
  465.     XSetFunction(xdev->dpy, xdev->gc, GXcopy);
  466.     XSetLineAttributes(xdev->dpy, xdev->gc, 0,
  467.                LineSolid, CapButt, JoinMiter);
  468.  
  469.     /* Clear the background pixmap to avoid initializing with garbage. */
  470.     if ( xdev->bpixmap != (Pixmap)0 )
  471.       { XSetWindowBackgroundPixmap(xdev->dpy, xdev->win, xdev->bpixmap);
  472.         XSetForeground(xdev->dpy, xdev->gc, xdev->color_white);
  473.         XFillRectangle(xdev->dpy, xdev->bpixmap, xdev->gc,
  474.                0, 0, xdev->width, xdev->height);
  475.       }
  476.  
  477.     /* Initialize foreground and background colors */
  478.     xdev->back_color = 7;
  479.     XSetBackground(xdev->dpy, xdev->gc, xdev->color_white);
  480.     xdev->fore_color = 0;
  481.     XSetForeground(xdev->dpy, xdev->gc, xdev->color_black);
  482.  
  483.     /* Make the window appear. */
  484.     XMapWindow(xdev->dpy, xdev->win);
  485.  
  486.     /* Before anything else, do a flush and wait for */
  487.     /* an exposure event. */
  488.     XFlush(xdev->dpy);
  489.     XNextEvent(xdev->dpy, &event);
  490.  
  491.     xdev->ht.no_pixmap = XCreatePixmap(xdev->dpy, xdev->win, 1, 1,
  492.                        xdev->depth);
  493.  
  494.     XSync(xdev->dpy, 0);
  495.     return 0;
  496. }
  497.  
  498. /* Close the device.  NOT SURE WHAT TO DO HERE YET. */
  499. int
  500. x_close(gx_device *dev)
  501. {    return 0;
  502. }
  503.  
  504. /* Map a color.  The "device colors" are just r,g,b packed together. */
  505. gx_color_index
  506. x_map_rgb_color(register gx_device *dev, _ushort r, _ushort g, _ushort b)
  507. {    return (r << 2) + (g << 1) + b;
  508. }
  509.  
  510.  
  511. /* Map a "device color" back to r-g-b. */
  512. int
  513. x_map_color_rgb(register gx_device *dev, gx_color_index color, _ushort prgb[3])
  514. {    prgb[0] = (color >> 2) & 1;
  515.     prgb[1] = (color >> 1) & 1;
  516.     prgb[2] = color & 1;
  517.     return 0;
  518. }
  519.  
  520. /* Synchronize the display with the commands already given */
  521. int
  522. x_sync(register gx_device *dev)
  523. {    update_flush(dev);
  524.     XSync(xdev->dpy, 0);
  525.     return 0;
  526. }
  527.  
  528. /* Fill a rectangle with a color. */
  529. int
  530. x_fill_rectangle(register gx_device *dev,
  531.   int x, int y, int w, int h, gx_color_index color)
  532. {    check_rect();
  533.     set_fill_style(FillSolid);
  534.     set_fore_color(color);
  535.     set_function(GXcopy);
  536.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  537.     if ( xdev->bpixmap != (Pixmap)0 )
  538.      { update_add(dev, x, y, w, h);
  539.      }
  540. #ifdef DEBUG
  541. if ( gs_debug['F'] )
  542.     dprintf5("[F] fill (%d,%d):(%d,%d) %ld\n",
  543.              x, y, w, h, (long)color);
  544. #endif
  545.     return 0;
  546. }
  547.  
  548. /* Tile a rectangle. */
  549. int
  550. x_tile_rectangle(register gx_device *dev, gx_bitmap *tile,
  551.   int x, int y, int w, int h, gx_color_index zero, gx_color_index one,
  552.   int px, int py)
  553. {    check_rect();
  554.  
  555.     /* Check for a colored tile.  We should implement this */
  556.     /* properly someday, since X can handle it. */
  557.  
  558.     if ( one == gx_no_color_index && zero == gx_no_color_index )
  559.         return -1;
  560.  
  561.     /* For the moment, give up if the phase is non-zero. */
  562.     if ( px || py )
  563.         return -1;
  564.  
  565.     /* 
  566.      * Remember, an X tile is already filled with particular
  567.      * pixel values (i.e., colors).  Therefore if we are changing
  568.      * fore/background color, we must invalidate the tile (using
  569.      * the same technique as in set_tile).  This problem only
  570.      * bites when using grayscale -- you may want to change
  571.      * fg/bg but use the same halftone screen.
  572.      */
  573.     if ( (zero != xdev->ht.back_c) || (one != xdev->ht.fore_c) )
  574.       if ( xdev->ht.bits ) *xdev->ht.bits = ~*tile->data;
  575.  
  576.     set_back_color(zero);
  577.     set_fore_color(one);
  578.     set_function(GXcopy);
  579.     if ( !set_tile(dev, tile) )
  580.      { /* Bad news.  Fall back to the default algorithm. */
  581.        set_fill_style(FillSolid);
  582.        return gx_default_tile_rectangle(dev, tile, x, y, w, h, zero, one, px, py);
  583.      }
  584.     else
  585.       { /* Use the tile to fill the rectangle */
  586.         XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  587.         if ( xdev->bpixmap != (Pixmap)0 )
  588.          { update_add(dev, x, y, w, h);
  589.          }
  590.       }
  591. #ifdef DEBUG
  592. if ( gs_debug['F'] )
  593.     dprintf6("[F] tile (%d,%d):(%d,%d) %ld,%ld\n",
  594.              x, y, w, h, (long)zero, (long)one);
  595. #endif
  596.     return 0;
  597. }
  598.  
  599. /* Set up with a specified tile. */
  600. /* Return false if we can't do it for some reason. */
  601. private int
  602. set_tile(register gx_device *dev, register gx_bitmap *tile)
  603. {
  604. #ifdef DEBUG
  605. if ( gs_debug['T'] )
  606.     return 0;
  607. #endif
  608.     /* Set up the tile Pixmap */
  609.     if ( tile->width != xdev->ht.width ||
  610.          tile->height != xdev->ht.height ||
  611.          xdev->ht.pixmap == (Pixmap)0
  612.        )
  613.       { if ( xdev->ht.pixmap != (Pixmap)0 )
  614.           XFreePixmap(xdev->dpy, xdev->ht.pixmap);
  615.         if ( xdev->ht.bits )
  616.           { gs_free((char *)xdev->ht.bits, xdev->ht.height,
  617.             xdev->ht.raster, "gdevx set_tile");
  618.         xdev->ht.bits = 0;
  619.           }
  620.         xdev->ht.pixmap = XCreatePixmap(xdev->dpy, xdev->win,
  621.                         tile->width, tile->height,
  622.                         xdev->depth);
  623.         if ( xdev->ht.pixmap == (Pixmap)0 )
  624.           return 0;
  625.         xdev->ht.bits_size = tile->raster * tile->height;
  626.         xdev->ht.bits = (byte *)gs_malloc(tile->height, tile->raster,
  627.                           "gdevx set_tile");
  628.         if ( xdev->ht.bits == 0 )
  629.           { XFreePixmap(xdev->dpy, xdev->ht.pixmap);
  630.         xdev->ht.pixmap = (Pixmap)0;
  631.         return 0;
  632.           }
  633.         xdev->ht.width = tile->width, xdev->ht.height = tile->height;
  634.         xdev->ht.raster = tile->raster;
  635.         *xdev->ht.bits = ~*tile->data; /* force copying */
  636.       }
  637.     xdev->ht.fore_c = xdev->fore_color;
  638.     xdev->ht.back_c = xdev->back_color;
  639.     /* Copy the tile into the Pixmap if needed */
  640.     if ( memcmp(xdev->ht.bits, tile->data, xdev->ht.bits_size) )
  641.       { memcpy(xdev->ht.bits, tile->data, xdev->ht.bits_size);
  642.         xdev->image.data = (char *)tile->data;
  643.         xdev->image.width = tile->width;
  644.         xdev->image.height = tile->height;
  645.         xdev->image.bytes_per_line = tile->raster;
  646.         xdev->image.format = XYBitmap;
  647.         set_fill_style(FillSolid);
  648. #ifdef DEBUG
  649. if ( gs_debug['H'] )
  650.         { int i;
  651.           dprintf4("[H] 0x%x: width=%d height=%d raster=%d\n",
  652.                tile->data, tile->width, tile->height, tile->raster);
  653.           for ( i = 0; i < tile->raster * tile->height; i++ )
  654.         dprintf1(" %02x", tile->data[i]);
  655.           dputc('\n');
  656.         }
  657. #endif
  658.         XSetTile(xdev->dpy, xdev->gc, xdev->ht.no_pixmap); /* *** X bug *** */
  659.         XPutImage(xdev->dpy, xdev->ht.pixmap, xdev->gc, &xdev->image,
  660.               0, 0, 0, 0, tile->width, tile->height);
  661.         XSetTile(xdev->dpy, xdev->gc, xdev->ht.pixmap);
  662.       }
  663.     set_fill_style(FillTiled);
  664.     return use_XSetTile;
  665. }
  666.  
  667. /* Copy a monochrome bitmap. */
  668. int
  669. x_copy_mono(register gx_device *dev, byte *base, int sourcex, int raster,
  670.   int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
  671. /*
  672.  * X doesn't readily support the simple operation of writing a color
  673.  * through a mask.  The plot is the following: 
  674.  *  If neither color is gx_no_color_index ("transparent"),
  675.  *    use XPutImage with the "copy" function as usual.
  676.  *  If the color is 0 or bitwise-includes every color written to date
  677.  *    (a special optimization for writing black/white on color displays),
  678.  *    use XPutImage with an appropriate Boolean function.
  679.  *  Otherwise, do the following complicated stuff:
  680.  *    Create pixmap of depth 1 if necessary.
  681.  *    If foreground color is "transparent" then
  682.  *      invert the raster data (using GXcopyInverted in XPutImage).
  683.  *    Use XPutImage to copy the raster image to the newly
  684.  *      created Pixmap.
  685.  *    Install the Pixmap as the clip_mask in the X GC and
  686.  *      tweak the clip origin.
  687.  *    Do an XFillRectangle, fill style=solid, specifying a
  688.  *      rectangle the same size as the original raster data.
  689.  *    De-install the clip_mask.
  690.  */
  691. {    int function = GXcopy;
  692.     unsigned long
  693.       bc = xdev->colors[zero],
  694.       fc = xdev->colors[one];
  695.     
  696.     /* We need a different version of check_rect, because */
  697.     /* we have to adjust the source coordinates too. */
  698.     if ( x < 0 ) w += x, sourcex -= x, x = 0;
  699.     if ( y < 0 ) h += y, base -= y * raster, y = 0;
  700.     check_rect_extent();
  701.  
  702.     xdev->image.width = raster << 3;
  703.     xdev->image.height = h;
  704.     xdev->image.data = (char *)base;
  705.     xdev->image.bytes_per_line = raster;
  706.     set_fill_style(FillSolid);
  707.  
  708.     /* Check for null, easy 1-color, hard 1-color, and 2-color cases. */
  709.     if ( zero != gx_no_color_index )
  710.       { if ( one != gx_no_color_index )
  711.           { /* Simply replace existing bits with what's in the image */
  712.           }
  713.         else if ( bc == 0 )
  714.           function = GXand,
  715.           fc = xdev->colors_or;
  716.         else if ( !(~bc & xdev->colors_or) )
  717.           function = GXorInverted,
  718.           fc = bc, bc = 0;
  719.         else
  720.           goto hard;
  721.       }
  722.     else
  723.       { if ( one == gx_no_color_index ) /* no-op */
  724.           return 0;
  725.         else if ( fc == 0 )
  726.           function = GXandInverted,
  727.           bc = 0, fc = xdev->colors_or;
  728.         else if ( !(~fc & xdev->colors_or) )
  729.           function = GXor,
  730.           bc = 0;
  731.         else
  732.           goto hard;
  733.       }
  734.     xdev->image.format = XYBitmap;
  735.     set_function(function);
  736.     XSetBackground(xdev->dpy, xdev->gc, bc);
  737.     XSetForeground(xdev->dpy, xdev->gc, fc);
  738.     xdev->back_color = xdev->fore_color = gx_no_color_index;
  739.     xdev->colors_or |= fc | bc;
  740.     xdev->colors_and &= fc & bc;
  741.     XPutImage(xdev->dpy, xdev->dest, xdev->gc, &xdev->image,
  742.           sourcex, 0, x, y, w, h);
  743.  
  744.     goto out;
  745.  
  746. hard:    /* Handle the hard 1-color case. */
  747.     if ( raster > xdev->cp.raster || h > xdev->cp.height )
  748.       { /* Must allocate a new pixmap and GC. */
  749.         /* Release the old ones first. */
  750.         free_cp(dev);
  751.  
  752.         /* Create the clipping pixmap, depth must be 1. */
  753.         xdev->cp.pixmap =
  754.           XCreatePixmap(xdev->dpy, xdev->win, raster << 3, h, 1);
  755.         if ( xdev->cp.pixmap == (Pixmap)0 )
  756.           {    lprintf("x_copy_mono: can't allocate pixmap\n");
  757.         exit(1);
  758.           }
  759.         xdev->cp.gc = XCreateGC(xdev->dpy, xdev->cp.pixmap, 0, 0);
  760.         if ( xdev->cp.gc == (GC)0 )
  761.           {    lprintf("x_copy_mono: can't allocate GC\n");
  762.         exit(1);
  763.           }
  764.         xdev->cp.raster = raster;
  765.         xdev->cp.height = h;
  766.       }
  767.  
  768.     /* Initialize static mask image params */
  769.     xdev->image.format = ZPixmap;
  770.  
  771.     /* Select polarity based on fg/bg transparency. */
  772.     if ( one == gx_no_color_index )    /* invert */
  773.       { XSetBackground(xdev->dpy, xdev->cp.gc, (unsigned long)1);
  774.         XSetForeground(xdev->dpy, xdev->cp.gc, (unsigned long)0);
  775.         set_fore_color(zero);
  776.       }
  777.     else
  778.       { XSetBackground(xdev->dpy, xdev->cp.gc, (unsigned long)0);
  779.         XSetForeground(xdev->dpy, xdev->cp.gc, (unsigned long)1);
  780.         set_fore_color(one);
  781.       }
  782.     XPutImage(xdev->dpy, xdev->cp.pixmap, xdev->cp.gc,
  783.           &xdev->image, sourcex, 0, 0, 0, w, h);
  784.  
  785.     /* Install as clipmask. */
  786.     XSetClipMask(xdev->dpy, xdev->gc, xdev->cp.pixmap);
  787.     XSetClipOrigin(xdev->dpy, xdev->gc, x, y);
  788.  
  789.     /*
  790.      * Draw a solid rectangle through the raster clip mask.
  791.      * Note fill style is guaranteed to be solid from above.
  792.      */
  793.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  794.  
  795.     /* Tidy up.  Free the pixmap if it's big. */
  796.     XSetClipMask(xdev->dpy, xdev->gc, None);
  797.     if ( raster * h > max_temp_pixmap )
  798.       free_cp(dev);
  799.  
  800. out:    if ( xdev->bpixmap != (Pixmap)0 )
  801.       { /* We wrote to the pixmap, so update the display now. */
  802.         update_add(dev, x, y, w, h);
  803.       }
  804.  
  805.     return 0;
  806. }
  807.  
  808. /* Internal routine to free the GC and pixmap used for copying. */
  809. private void
  810. free_cp(register gx_device *dev)
  811. {    if ( xdev->cp.gc != NULL )
  812.        {    XFreeGC(xdev->dpy, xdev->cp.gc);
  813.         xdev->cp.gc = NULL;
  814.        }
  815.     if ( xdev->cp.pixmap != (Pixmap)0 )
  816.        {    XFreePixmap(xdev->dpy, xdev->cp.pixmap);
  817.         xdev->cp.pixmap = (Pixmap)0;
  818.        }
  819.     xdev->cp.raster = -1;    /* mark as unallocated */
  820. }
  821.  
  822. /* Copy a "color" bitmap.  Since "color" is the same as monochrome, */
  823. /* this just reduces to copying a monochrome bitmap. */
  824. /****** THIS ROUTINE IS COMPLETELY WRONG, SINCE WE DO SUPPORT COLOR. ******/
  825. /* Fortunately, no one uses it at the moment. */
  826. int
  827. x_copy_color(register gx_device *dev, byte *base, int sourcex, int raster,
  828.   int x, int y, int w, int h)
  829. {    return x_copy_mono(dev, base, sourcex, raster, x, y, w, h, (gx_color_index)0, (gx_color_index)7);
  830. }
  831.  
  832. /* Draw a line */
  833. int
  834. x_draw_line(register gx_device *dev,
  835.   int x0, int y0, int x1, int y1, gx_color_index color)
  836. {    set_fore_color(color);
  837.     set_fill_style(FillSolid);
  838.     set_function(GXcopy);
  839.     XDrawLine(xdev->dpy, xdev->dest, xdev->gc, x0, y0, x1, y1);
  840.     if ( xdev->bpixmap != (Pixmap)0 )
  841.      { int x = x0, y = y0, w = x1 - x0, h = y1 - y0;
  842.        if ( w < 0 ) x = x1, w = - w;
  843.        if ( h < 0 ) y = y1, h = - h;
  844.        update_add(dev, x, y, w+1, h+1);
  845.      }
  846.     return 0;
  847. }
  848.  
  849. /* ------ Screen update procedures ------ */
  850.  
  851. /* Flush updates to the screen if needed. */
  852. private void
  853. update_do_flush(register gx_device *dev)
  854. {    int xo = xdev->update.xo, yo = xdev->update.yo;
  855.     set_function(GXcopy);
  856.     XCopyArea(xdev->dpy, xdev->bpixmap, xdev->win, xdev->gc,
  857.           xo, yo, xdev->update.xe - xo, xdev->update.ye - yo,
  858.           xo, yo);
  859.     update_init(dev);
  860. }
  861.  
  862. /* Add a region to be updated. */
  863. /* This is only called if xdev->bpixmap != 0. */
  864. private void
  865. update_add(register gx_device *dev, int xo, int yo, int w, int h)
  866. {    int xe = xo + w, ye = yo + h;
  867.     long new_area = (long)w * h;
  868.     ++xdev->up_count;
  869.     if ( xdev->up_area != 0 )
  870.       { /* See whether adding this rectangle */
  871.         /* would result in too much being copied unnecessarily. */
  872.         long old_area = xdev->up_area;
  873.         long new_up_area;
  874.         rect u;
  875.         u.xo = min(xo, xdev->update.xo);
  876.         u.yo = min(yo, xdev->update.yo);
  877.         u.xe = max(xe, xdev->update.xe);
  878.         u.ye = max(ye, xdev->update.ye);
  879.         new_up_area = (long)(u.xe - u.xo) * (u.ye - u.yo);
  880.         if ( new_up_area > 100 &&
  881.         old_area + new_area < new_up_area * 2 / 3 ||
  882.         xdev->up_count >= 200
  883.         )
  884.           update_do_flush(dev);
  885.         else
  886.           { xdev->update = u;
  887.         xdev->up_area = new_up_area;
  888.         return;
  889.           }
  890.       }
  891.     xdev->update.xo = xo;
  892.     xdev->update.yo = yo;
  893.     xdev->update.xe = xe;
  894.     xdev->update.ye = ye;
  895.     xdev->up_area = new_area;
  896. }
  897.  
  898. /* ------ Internal procedures ------ */
  899.  
  900. /* Substitute for XPutImage using XFillRectangle. */
  901. /* This is a total hack to get around an apparent bug */
  902. /* in the X server.  It only works with the specific */
  903. /* parameters (bit/byte order, padding) used above. */
  904. private void
  905. alt_put_image(gx_device *dev, Display *dpy, Drawable win, GC gc,
  906.   XImage *pi, int sx, int sy, int dx, int dy, unsigned w, unsigned h)
  907. {    int raster = pi->bytes_per_line;
  908.     byte *data = (byte *)pi->data + sy * raster + (sx >> 3);
  909.     int init_mask = 0x80 >> (sx & 7);
  910.     int invert;
  911.     int yi;
  912. #define nrects 40
  913.     XRectangle rects[nrects];
  914.     XRectangle *rp = rects;
  915.     if ( xdev->fore_color != gx_no_color_index )
  916.       { if ( xdev->back_color != gx_no_color_index )
  917.           { XSetForeground(dpy, gc, xdev->colors[xdev->back_color]);
  918.         XFillRectangle(dpy, win, gc, dx, dy, w, h);
  919.           }
  920.         XSetForeground(dpy, gc, xdev->colors[xdev->fore_color]);
  921.         invert = 0;
  922.       }
  923.     else if ( xdev->back_color != gx_no_color_index )
  924.       { XSetForeground(dpy, gc, xdev->colors[xdev->back_color]);
  925.         invert = 0xff;
  926.       }
  927.     else
  928.       return;
  929.     for ( yi = 0; yi < h; yi++, data += raster )
  930.       { register int mask = init_mask;
  931.         register byte *dp = data;
  932.         register int xi = 0;
  933.         while ( xi < w )
  934.           { if ( (*dp ^ invert) & mask )
  935.           { int xleft = xi;
  936.             if ( rp == &rects[nrects] )
  937.               { XFillRectangles(dpy, win, gc, rects, nrects);
  938.             rp = rects;
  939.               }
  940.             /* Scan over a run of 1-bits */
  941.             rp->x = dx + xi, rp->y = dy + yi;
  942.             do
  943.               { if ( !(mask >>= 1) ) mask = 0x80, dp++;
  944.             xi++;
  945.               }
  946.             while ( xi < w && (*dp & mask) );
  947.             rp->width = xi - xleft, rp->height = 1;
  948.             rp++;
  949.           }
  950.         else
  951.           { if ( !(mask >>= 1) ) mask = 0x80, dp++;
  952.             xi++;
  953.           }
  954.           }
  955.       }
  956.     XFillRectangles(dpy, win, gc, rects, rp - rects);
  957. }
  958.