home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / g / gs252src.zip / GS252 / GDEVX.C < prev    next >
C/C++ Source or Header  |  1992-09-11  |  25KB  |  828 lines

  1. /* Copyright (C) 1989, 1992 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. /* std.h has taken care of this. */
  25. #include "gx.h"            /* for gx_bitmap; includes std.h */
  26. #include "memory_.h"
  27. #include "x_.h"
  28. #include "gserrors.h"
  29. #include "gsprops.h"
  30. #include "gsutil.h"        /* for props_extract */
  31. #include "gxdevice.h"
  32. #include "gdevx.h"
  33.  
  34. /* Flags for patching around bugs in the X library */
  35. private int use_XPutImage = 1;
  36. private int use_XSetTile = 1;
  37.  
  38. /* Define the maximum size of the temporary pixmap for copy_mono */
  39. /* that we are willing to leave lying around in the server */
  40. /* between uses.  (Assume 32-bit ints here!) */
  41. private int max_temp_pixmap = 20000;
  42.  
  43. /* Forward references */
  44. private int set_tile(P2(gx_device *, const gx_bitmap *));
  45. private void free_cp(P1(gx_device *));
  46. /* Screen updating machinery */
  47. #define update_init(dev)\
  48.   ((gx_device_X *)(dev))->up_area = 0,\
  49.   ((gx_device_X *)(dev))->up_count = 0
  50. #define update_flush(dev)\
  51.   if ( ((gx_device_X *)(dev))->up_area != 0 ) update_do_flush(dev)
  52. private void update_do_flush(P1(gx_device *));
  53. private void update_add(P5(gx_device *, int, int, int, int));
  54. private void send_event(P2(gx_device *, Atom));
  55.  
  56. /* Procedures */
  57.  
  58. extern int gdev_x_open(P1(gx_device_X *));
  59. private dev_proc_open_device(x_open);
  60. private dev_proc_get_initial_matrix(x_get_initial_matrix);
  61. private dev_proc_sync_output(x_sync);
  62. private dev_proc_output_page(x_output_page);
  63. private dev_proc_close_device(x_close);
  64. private dev_proc_map_rgb_color(x_map_rgb_color);
  65. private dev_proc_map_color_rgb(x_map_color_rgb);
  66. private dev_proc_fill_rectangle(x_fill_rectangle);
  67. private dev_proc_tile_rectangle(x_tile_rectangle);
  68. private dev_proc_copy_mono(x_copy_mono);
  69. private dev_proc_copy_color(x_copy_color);
  70. private dev_proc_draw_line(x_draw_line);
  71. private dev_proc_put_props(x_put_props);
  72.  
  73. /* The device descriptor */
  74. private gx_device_procs x_procs = {
  75.     x_open,
  76.     x_get_initial_matrix,
  77.     x_sync,
  78.     x_output_page,
  79.     x_close,
  80.     x_map_rgb_color,
  81.     x_map_color_rgb,
  82.     x_fill_rectangle,
  83.     x_tile_rectangle,
  84.     x_copy_mono,
  85.     x_copy_color,
  86.     x_draw_line,
  87.     gx_default_get_bits,
  88.     gx_default_get_props,
  89.     x_put_props
  90. };
  91.  
  92. /* The instance is public. */
  93. gx_device_X gs_x11_device = {
  94.     sizeof(gx_device_X),
  95.     &x_procs,
  96.     "x11",
  97.     (int)(FAKE_RES*DEFAULT_WIDTH_INCHES), (int)(FAKE_RES*DEFAULT_HEIGHT_INCHES),    /* x and y extent (nominal) */
  98.     FAKE_RES, FAKE_RES,    /* x and y density (nominal) */
  99.     no_margins,
  100.     dci_black_and_white,
  101.     0,            /* connection not initialized */
  102.     { /* image */
  103.       0, 0,            /* width, height */
  104.       0, XYBitmap, NULL,    /* xoffset, format, data */
  105.       LSBFirst, 8,        /* byte-order, bitmap-unit */
  106.       MSBFirst, 8, 1,    /* bitmap-bit-order, bitmap-pad, depth */
  107.       0, 1,            /* bytes_per_line, bits_per_pixel */
  108.       0, 0, 0,        /* red_mask, green_mask, blue_mask */
  109.       NULL,            /* *obdata */
  110.        { NULL,            /* *(*create_image)() */
  111.          NULL,            /* (*destroy_image)() */
  112.          NULL,            /* (*get_pixel)() */
  113.          NULL,            /* (*put_pixel)() */
  114.          NULL,            /* *(*sub_image)() */
  115.          NULL            /* (*add_pixel)() */
  116.        },
  117.     },
  118.     NULL, NULL,        /* dpy, scr */
  119.                 /* (connection not initialized) */
  120.     NULL,            /* vinfo */
  121.     (Colormap)None,        /* cmap */
  122.     (Window)None,        /* win */
  123.     NULL,            /* gc */
  124.     (Pixmap)0,        /* bpixmap */
  125.     0,            /* ghostview */
  126.     (Window)None,        /* mwin */
  127. #if HaveStdCMap
  128.     NULL,            /* std_cmap */
  129. #endif
  130.     identity_matrix_body,    /* initial matrix (filled in) */
  131.     (Atom)0, (Atom)0, (Atom)0,    /* Atoms: NEXT, PAGE, DONE */
  132.      { 0, 0, 0, 0 }, 0, 0,    /* update, up_area, up_count */
  133.     (Pixmap)0,        /* dest */
  134.     0L, ~0L,        /* colors_or, colors_and */
  135.      { /* cp */
  136.        (Pixmap)0,        /* pixmap */
  137.        NULL,        /* gc */
  138.        -1, -1        /* raster, height */
  139.      },
  140.      { /* ht */
  141.        (Pixmap)None,        /* pixmap */
  142.        (Pixmap)None,        /* no_pixmap */
  143.        gx_no_bitmap_id,        /* id */
  144.        0, 0, 0,            /* width, height, raster */
  145.        0, 0                /* fore_c, back_c */
  146.      },
  147.     GXcopy,            /* function */
  148.     FillSolid,        /* fill_style */
  149.     0,            /* pixel_fix */
  150.     { 0, 0, 0, 0, 0, 0, 0, 0 }, /* colors[8] */
  151.     0, 0            /* back_color, fore_color */
  152.  
  153. };
  154.  
  155. /* Macro for casting gx_device argument */
  156. #define xdev ((gx_device_X *)dev)
  157.  
  158. /* If XPutImage doesn't work, do it ourselves. */
  159. private void alt_put_image();
  160. #define put_image(dpy,win,gc,im,sx,sy,x,y,w,h)\
  161.   if ( use_XPutImage) XPutImage(dpy,win,gc,im,sx,sy,x,y,w,h);\
  162.   else alt_put_image(dev,dpy,win,gc,im,sx,sy,x,y,w,h)
  163.  
  164.  
  165. /* Open the device.  Most of the code is in gdevxini.c. */
  166. private int
  167. x_open(gx_device *dev)
  168. {    int code = gdev_x_open(xdev);
  169.     if ( code < 0 ) return code;
  170.     update_init(dev);
  171.     return 0;
  172. }
  173.  
  174. /* Close the device.  NOT SURE WHAT TO DO HERE YET. */
  175. private int
  176. x_close(gx_device *dev)
  177. {    if ( xdev->ghostview )
  178.       { send_event(dev, xdev->done);
  179.       }
  180.     XCloseDisplay(xdev->dpy);
  181.     return 0;
  182. }
  183.  
  184. /* Map a color.  The "device colors" are just r,g,b packed together. */
  185. private gx_color_index
  186. x_map_rgb_color(register gx_device *dev,
  187.         gx_color_value r, gx_color_value g, gx_color_value b)
  188. {
  189. #if HaveStdCMap
  190.     if ( xdev->std_cmap )
  191.       { XStandardColormap *cmap = xdev->std_cmap;
  192.         x_pixel color;
  193.         if ( r == 0 && g == 0 && b == 0 )
  194.           return pixel_black;
  195.         if ( r == gx_max_color_value && g == gx_max_color_value &&
  196.          b == gx_max_color_value )
  197.           return pixel_white;
  198. #define cv_denom (gx_max_color_value + 1)
  199.         color =
  200.           (gx_device_has_color(xdev) ?
  201.            (r * (cmap->red_max + 1) / cv_denom * cmap->red_mult) +
  202.            (g * (cmap->green_max + 1) / cv_denom * cmap->green_mult) +
  203.            (b * (cmap->blue_max + 1) / cv_denom * cmap->blue_mult) :
  204.            (r * (xdev->color_info.max_gray + 1) / cv_denom *
  205.         cmap->red_mult)) +
  206.           cmap->base_pixel;
  207. #undef cv_denom
  208.         return pixel_to_color_index(color);
  209.       }
  210.     else
  211. #endif
  212. #define cv_half (gx_max_color_value / 2)
  213.       { return
  214.           pixel_to_color_index(xdev->colors[(r > cv_half ? 4 : 0) +
  215.                         (g > cv_half ? 2 : 0) +
  216.                         (b > cv_half ? 1 : 0)]);
  217.       }
  218. #undef cv_half
  219. }
  220.  
  221.  
  222. /* Map a "device color" back to r-g-b. */
  223. private int
  224. x_map_color_rgb(register gx_device *dev, gx_color_index color,
  225.         gx_color_value prgb[3])
  226. {    x_pixel pixel = color_index_to_pixel(color);
  227.     if ( pixel == pixel_black )
  228.      { prgb[0] = prgb[1] = prgb[2] = 0;
  229.      }
  230.     else if ( pixel == pixel_white )
  231.      { prgb[0] = prgb[1] = prgb[2] = gx_max_color_value;
  232.      }
  233. #if HaveStdCMap
  234.     else if ( xdev->std_cmap )
  235.       { XStandardColormap *cmap = xdev->std_cmap;
  236.         if ( gx_device_has_color(xdev) )
  237.           { prgb[0] =
  238.           ((pixel - cmap->base_pixel) / cmap->red_mult) %
  239.             (cmap->red_max + 1) * gx_max_color_value /
  240.               cmap->red_max;
  241.             prgb[1] =
  242.           ((pixel - cmap->base_pixel) / cmap->green_mult) %
  243.             (cmap->green_max + 1) * gx_max_color_value /
  244.               cmap->green_max;
  245.             prgb[2] =
  246.           ((pixel - cmap->base_pixel) / cmap->blue_mult) %
  247.             (cmap->blue_max + 1) * gx_max_color_value /
  248.               cmap->blue_max;
  249.           }
  250.         else
  251.           { prgb[0] = prgb[1] = prgb[2] =
  252.           (pixel - cmap->base_pixel) / cmap->red_mult *
  253.             gx_max_color_value / xdev->color_info.max_gray;
  254.           }
  255.       }
  256. #endif
  257.     else
  258.      { int i;
  259.        for ( i = 1; i < 7; i++ )
  260.         { if ( pixel == xdev->colors[i] )
  261.            { prgb[0] = (i & 4 ? gx_max_color_value : 0);
  262.          prgb[1] = (i & 2 ? gx_max_color_value : 0);
  263.          prgb[2] = (i & 1 ? gx_max_color_value : 0);
  264.          break;
  265.            }
  266.         }
  267.      }
  268.     return 0;
  269. }
  270.  
  271. /* Get initial matrix for X device */
  272. private void
  273. x_get_initial_matrix(register gx_device *dev, register gs_matrix *pmat)
  274. {    pmat->xx = xdev->initial_matrix.xx;
  275.     pmat->xy = xdev->initial_matrix.xy;
  276.     pmat->yx = xdev->initial_matrix.yx;
  277.     pmat->yy = xdev->initial_matrix.yy;
  278.     pmat->tx = xdev->initial_matrix.tx;
  279.     pmat->ty = xdev->initial_matrix.ty;
  280. }
  281.  
  282. /* Synchronize the display with the commands already given */
  283. private int
  284. x_sync(register gx_device *dev)
  285. {    update_flush(dev);
  286.     XSync(xdev->dpy, 0);
  287.     return 0;
  288. }
  289.  
  290. /* Send event to ghostview process */
  291. private void
  292. send_event(gx_device *dev, Atom msg)
  293. {    XEvent event;
  294.     event.xclient.type = ClientMessage;
  295.     event.xclient.display = xdev->dpy;
  296.     event.xclient.window = xdev->win;
  297.     event.xclient.message_type = msg;
  298.     event.xclient.format = 32;
  299.     event.xclient.data.l[0] = xdev->mwin;
  300.     event.xclient.data.l[1] = xdev->dest;
  301.     XSendEvent(xdev->dpy, xdev->win, False, 0, &event);
  302. }
  303.  
  304. /* Output "page" */
  305. private int
  306. x_output_page(gx_device *dev, int num_copies, int flush)
  307. {    x_sync(dev);
  308.  
  309.     /* Send ghostview a "page" client event */
  310.     /* Wait for a "next" client event */
  311.     if ( xdev->ghostview )
  312.       { XEvent event;
  313.         send_event(dev, xdev->page);
  314.         XNextEvent(xdev->dpy, &event);
  315.         while (event.type != ClientMessage ||
  316.            event.xclient.message_type != xdev->next)
  317.           { XNextEvent(xdev->dpy, &event);
  318.           }
  319.       }
  320.     return 0;
  321. }
  322.  
  323. /* Fill a rectangle with a color. */
  324. private int
  325. x_fill_rectangle(register gx_device *dev,
  326.   int x, int y, int w, int h, gx_color_index color)
  327. {    fit_fill(dev, x, y, w, h);
  328.     set_fill_style(FillSolid);
  329.     set_fore_color(color_index_to_pixel(color));
  330.     set_function(GXcopy);
  331.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  332.     /* If we are filling the entire screen, reset */
  333.     /* colors_or and colors_and.  It's wasteful to do this */
  334.     /* on every operation, but there's no separate driver routine */
  335.     /* for erasepage (yet). */
  336.     if ( x == 0 && y == 0 && w == xdev->width && h == xdev->height )
  337.      { xdev->colors_or = xdev->colors_and = color_index_to_pixel(color);
  338.      }
  339.     if ( xdev->bpixmap != (Pixmap)0 )
  340.      { update_add(dev, x, y, w, h);
  341.      }
  342. #ifdef DEBUG
  343. if ( gs_debug['F'] )
  344.     dprintf5("[F] fill (%d,%d):(%d,%d) %ld\n",
  345.              x, y, w, h, (long)color);
  346. #endif
  347.     return 0;
  348. }
  349.  
  350. /* Tile a rectangle. */
  351. private int
  352. x_tile_rectangle(register gx_device *dev, const gx_bitmap *tile,
  353.   int x, int y, int w, int h, gx_color_index zero, gx_color_index one,
  354.   int px, int py)
  355. {    x_pixel
  356.       p_zero = color_index_to_pixel(zero),
  357.       p_one = color_index_to_pixel(one);
  358.     fit_fill(dev, x, y, w, h);
  359.  
  360.     /* Check for a colored tile.  We should implement this */
  361.     /* properly someday, since X can handle it. */
  362.  
  363.     if ( one == gx_no_color_index && zero == gx_no_color_index )
  364.         return -1;
  365.  
  366.     /* For the moment, give up if the phase is non-zero. */
  367.     if ( px | py )
  368.         return -1;
  369.  
  370.     /* 
  371.      * Remember, an X tile is already filled with particular
  372.      * pixel values (i.e., colors).  Therefore if we are changing
  373.      * fore/background color, we must invalidate the tile (using
  374.      * the same technique as in set_tile).  This problem only
  375.      * bites when using grayscale -- you may want to change
  376.      * fg/bg but use the same halftone screen.
  377.      */
  378.     if ( (p_zero != xdev->ht.back_c) || (p_one != xdev->ht.fore_c) )
  379.       xdev->ht.id = ~tile->id; /* force reload */
  380.  
  381.     set_back_color(p_zero);
  382.     set_fore_color(p_one);
  383.     if ( !set_tile(dev, tile) )
  384.      { /* Bad news.  Fall back to the default algorithm. */
  385.        return gx_default_tile_rectangle(dev, tile, x, y, w, h, zero, one, px, py);
  386.      }
  387.     else
  388.       { /* Use the tile to fill the rectangle */
  389.         set_fill_style(FillTiled);
  390.         set_function(GXcopy);
  391.         XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  392.         if ( xdev->bpixmap != (Pixmap)0 )
  393.          { update_add(dev, x, y, w, h);
  394.          }
  395.       }
  396. #ifdef DEBUG
  397. if ( gs_debug['F'] )
  398.     dprintf6("[F] tile (%d,%d):(%d,%d) %ld,%ld\n",
  399.              x, y, w, h, (long)zero, (long)one);
  400. #endif
  401.     return 0;
  402. }
  403.  
  404. /* Set up with a specified tile. */
  405. /* Return false if we can't do it for some reason. */
  406. private int
  407. set_tile(register gx_device *dev, register const gx_bitmap *tile)
  408. {
  409. #ifdef DEBUG
  410. if ( gs_debug['T'] )
  411.     return 0;
  412. #endif
  413.     if ( tile->id == xdev->ht.id && tile->id != gx_no_bitmap_id )
  414.       return use_XSetTile;
  415.     /* Set up the tile Pixmap */
  416.     if ( tile->size.x != xdev->ht.width ||
  417.          tile->size.y != xdev->ht.height ||
  418.          xdev->ht.pixmap == (Pixmap)0
  419.        )
  420.       { if ( xdev->ht.pixmap != (Pixmap)0 )
  421.           XFreePixmap(xdev->dpy, xdev->ht.pixmap);
  422.         xdev->ht.pixmap = XCreatePixmap(xdev->dpy, xdev->win,
  423.                         tile->size.x, tile->size.y,
  424.                         xdev->vinfo->depth);
  425.         if ( xdev->ht.pixmap == (Pixmap)0 )
  426.           return 0;
  427.         xdev->ht.width = tile->size.x, xdev->ht.height = tile->size.y;
  428.         xdev->ht.raster = tile->raster;
  429.       }
  430.     xdev->ht.fore_c = xdev->fore_color;
  431.     xdev->ht.back_c = xdev->back_color;
  432.     /* Copy the tile into the Pixmap */
  433.     xdev->image.data = (char *)tile->data;
  434.     xdev->image.width = tile->size.x;
  435.     xdev->image.height = tile->size.y;
  436.     xdev->image.bytes_per_line = tile->raster;
  437.     xdev->image.format = XYBitmap;
  438.     set_fill_style(FillSolid);
  439. #ifdef DEBUG
  440. if ( gs_debug['H'] )
  441.      { int i;
  442.        dprintf4("[H] 0x%x: width=%d height=%d raster=%d\n",
  443.             tile->data, tile->size.x, tile->size.y, tile->raster);
  444.        for ( i = 0; i < tile->raster * tile->size.y; i++ )
  445.          dprintf1(" %02x", tile->data[i]);
  446.        dputc('\n');
  447.      }
  448. #endif
  449.     XSetTile(xdev->dpy, xdev->gc, xdev->ht.no_pixmap); /* *** X bug *** */
  450.     set_function(GXcopy);
  451.     put_image(xdev->dpy, xdev->ht.pixmap, xdev->gc, &xdev->image,
  452.           0, 0, 0, 0, tile->size.x, tile->size.y);
  453.     XSetTile(xdev->dpy, xdev->gc, xdev->ht.pixmap);
  454.     xdev->ht.id = tile->id;
  455.     return use_XSetTile;
  456. }
  457.  
  458. /* Copy a monochrome bitmap. */
  459. private int
  460. x_copy_mono(register gx_device *dev,
  461.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  462.   int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
  463. /*
  464.  * X doesn't directly support the simple operation of writing a color
  465.  * through a mask specified by an image.  The plot is the following: 
  466.  *  If neither color is gx_no_color_index ("transparent"),
  467.  *    use XPutImage with the "copy" function as usual.
  468.  *  If the color either bitwise-includes or is bitwise-included-in
  469.  *      every color written to date
  470.  *      (a special optimization for writing black/white on color displays),
  471.  *    use XPutImage with an appropriate Boolean function.
  472.  *  Otherwise, do the following complicated stuff:
  473.  *    Create pixmap of depth 1 if necessary.
  474.  *    If foreground color is "transparent" then
  475.  *      invert the raster data.
  476.  *    Use XPutImage to copy the raster image to the newly
  477.  *      created Pixmap.
  478.  *    Install the Pixmap as the clip_mask in the X GC and
  479.  *      tweak the clip origin.
  480.  *    Do an XFillRectangle, fill style=solid, specifying a
  481.  *      rectangle the same size as the original raster data.
  482.  *    De-install the clip_mask.
  483.  */
  484. {    int function = GXcopy;
  485.     x_pixel
  486.       p_zero = color_index_to_pixel(zero),
  487.       p_one = color_index_to_pixel(one);
  488.     x_pixel
  489.       bc = p_zero,
  490.       fc = p_one;
  491.     
  492.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  493.  
  494.     xdev->image.width = raster << 3;
  495.     xdev->image.height = h;
  496.     xdev->image.data = (char *)base;
  497.     xdev->image.bytes_per_line = raster;
  498.     set_fill_style(FillSolid);
  499.  
  500.     /* Check for null, easy 1-color, hard 1-color, and 2-color cases. */
  501.     if ( zero != gx_no_color_index )
  502.       { if ( one != gx_no_color_index )
  503.           { /* 2-color case. */
  504.         /* Simply replace existing bits with what's in the image. */
  505.           }
  506.         else if ( !(~xdev->colors_and & bc) )
  507.           function = GXand,
  508.           fc = ~(x_pixel)0;
  509.         else if ( !(~bc & xdev->colors_or) )
  510.           function = GXor,
  511.           fc = 0;
  512.         else
  513.           goto hard;
  514.       }
  515.     else
  516.       { if ( one == gx_no_color_index ) /* no-op */
  517.           return 0;
  518.         else if ( !(~xdev->colors_and & fc) )
  519.           function = GXand,
  520.           bc = ~(x_pixel)0;
  521.         else if ( !(~fc & xdev->colors_or) )
  522.           function = GXor,
  523.           bc = 0;
  524.         else
  525.           goto hard;
  526.       }
  527.     xdev->image.format = XYBitmap;
  528.     set_function(function);
  529.     if ( bc != xdev->back_color )
  530.       XSetBackground(xdev->dpy, xdev->gc, (xdev->back_color = bc));
  531.     if ( fc != xdev->fore_color )
  532.       XSetForeground(xdev->dpy, xdev->gc, (xdev->fore_color = fc));
  533.     if ( zero != gx_no_color_index )
  534.       note_color(p_zero);
  535.     if ( one != gx_no_color_index )
  536.       note_color(p_one);
  537.     put_image(xdev->dpy, xdev->dest, xdev->gc, &xdev->image,
  538.           sourcex, 0, x, y, w, h);
  539.  
  540.     goto out;
  541.  
  542. hard:    /* Handle the hard 1-color case. */
  543.     if ( raster > xdev->cp.raster || h > xdev->cp.height )
  544.       { /* Must allocate a new pixmap and GC. */
  545.         /* Release the old ones first. */
  546.         free_cp(dev);
  547.  
  548.         /* Create the clipping pixmap, depth must be 1. */
  549.         xdev->cp.pixmap =
  550.           XCreatePixmap(xdev->dpy, xdev->win, raster << 3, h, 1);
  551.         if ( xdev->cp.pixmap == (Pixmap)0 )
  552.           {    lprintf("x_copy_mono: can't allocate pixmap\n");
  553.         exit(1);
  554.           }
  555.         xdev->cp.gc = XCreateGC(xdev->dpy, xdev->cp.pixmap, 0, 0);
  556.         if ( xdev->cp.gc == (GC)0 )
  557.           {    lprintf("x_copy_mono: can't allocate GC\n");
  558.         exit(1);
  559.           }
  560.         xdev->cp.raster = raster;
  561.         xdev->cp.height = h;
  562.       }
  563.  
  564.     /* Initialize static mask image params */
  565.     xdev->image.format = ZPixmap;
  566.  
  567.     /* Select polarity based on fg/bg transparency. */
  568.     if ( one == gx_no_color_index )    /* invert */
  569.       { XSetBackground(xdev->dpy, xdev->cp.gc, (x_pixel)1);
  570.         XSetForeground(xdev->dpy, xdev->cp.gc, (x_pixel)0);
  571.         set_fore_color(p_zero);
  572.       }
  573.     else
  574.       { XSetBackground(xdev->dpy, xdev->cp.gc, (x_pixel)0);
  575.         XSetForeground(xdev->dpy, xdev->cp.gc, (x_pixel)1);
  576.         set_fore_color(p_one);
  577.       }
  578.     put_image(xdev->dpy, xdev->cp.pixmap, xdev->cp.gc,
  579.           &xdev->image, sourcex, 0, 0, 0, w, h);
  580.  
  581.     /* Install as clipmask. */
  582.     XSetClipMask(xdev->dpy, xdev->gc, xdev->cp.pixmap);
  583.     XSetClipOrigin(xdev->dpy, xdev->gc, x, y);
  584.  
  585.     /*
  586.      * Draw a solid rectangle through the raster clip mask.
  587.      * Note fill style is guaranteed to be solid from above.
  588.      */
  589.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  590.  
  591.     /* Tidy up.  Free the pixmap if it's big. */
  592.     XSetClipMask(xdev->dpy, xdev->gc, None);
  593.     if ( raster * h > max_temp_pixmap )
  594.       free_cp(dev);
  595.  
  596. out:    if ( xdev->bpixmap != (Pixmap)0 )
  597.       { /* We wrote to the pixmap, so update the display now. */
  598.         update_add(dev, x, y, w, h);
  599.       }
  600.  
  601.     return 0;
  602. }
  603.  
  604. /* Internal routine to free the GC and pixmap used for copying. */
  605. private void
  606. free_cp(register gx_device *dev)
  607. {    if ( xdev->cp.gc != NULL )
  608.        {    XFreeGC(xdev->dpy, xdev->cp.gc);
  609.         xdev->cp.gc = NULL;
  610.        }
  611.     if ( xdev->cp.pixmap != (Pixmap)0 )
  612.        {    XFreePixmap(xdev->dpy, xdev->cp.pixmap);
  613.         xdev->cp.pixmap = (Pixmap)0;
  614.        }
  615.     xdev->cp.raster = -1;    /* mark as unallocated */
  616. }
  617.  
  618. /* Copy a "color" bitmap.  Since "color" is the same as monochrome, */
  619. /* this just reduces to copying a monochrome bitmap. */
  620. /****** THIS ROUTINE IS COMPLETELY WRONG, SINCE WE DO SUPPORT COLOR. ******/
  621. /* Fortunately, no one uses it at the moment. */
  622. private int
  623. x_copy_color(register gx_device *dev,
  624.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  625.   int x, int y, int w, int h)
  626. {    return x_copy_mono(dev, base, sourcex, raster, id, x, y, w, h,
  627.                pixel_to_color_index(pixel_black),
  628.                pixel_to_color_index(pixel_white));
  629. }
  630.  
  631. /* Draw a line */
  632. private int
  633. x_draw_line(register gx_device *dev,
  634.   int x0, int y0, int x1, int y1, gx_color_index color)
  635. {    set_fore_color(color_index_to_pixel(color));
  636.     set_fill_style(FillSolid);
  637.     set_function(GXcopy);
  638.     XDrawLine(xdev->dpy, xdev->dest, xdev->gc, x0, y0, x1, y1);
  639.     if ( xdev->bpixmap != (Pixmap)0 )
  640.      { int x = x0, y = y0, w = x1 - x0, h = y1 - y0;
  641.        if ( w < 0 ) x = x1, w = - w;
  642.        if ( h < 0 ) y = y1, h = - h;
  643.        w++; h++;
  644.        fit_fill(dev, x, y, w, h);
  645.        update_add(dev, x, y, w, h);
  646.      }
  647.     return 0;
  648. }
  649.  
  650. /* Set the device properties.  We reimplement this so we can resize */
  651. /* the window and avoid closing and reopening the device. */
  652. private const gs_prop_item x_props[] = {
  653.     prop_def("HWResolution", prt_float_array),
  654.     prop_def("HWSize", prt_int_array),
  655.         /* Slots for arrays */
  656.     prop_float, prop_float,
  657.     prop_int, prop_int,
  658. };
  659. private int
  660. x_put_props(gx_device *dev, gs_prop_item *plist, int count)
  661. {    gs_prop_item *known[2];
  662.     int code = 0;
  663.     gx_device_X temp_dev;
  664.     temp_dev = *xdev;
  665.     props_extract(plist, count, x_props, 2, known, 0);
  666.     if ( known[1] != 0 )
  667.        {    if ( known[1]->value.a.size != 2 )
  668.             known[1]->status = pv_typecheck,
  669.             code = gs_error_typecheck;
  670.         else
  671.            {    gs_prop_item *ap = known[1]->value.a.p.v;
  672.             if ( ap[0].value.i <= 0 || ap[0].value.i > 0x7fff ||
  673.                  ap[1].value.i <= 0 || ap[1].value.i > 0x7fff
  674.                )
  675.                 known[1]->status = pv_rangecheck,
  676.                 code = gs_error_rangecheck;
  677.             else
  678.                {    temp_dev.width = ap[0].value.i;
  679.                 temp_dev.height = ap[1].value.i;
  680.                }
  681.            }
  682.        }
  683.     if ( known[0] != 0 )
  684.        {    if ( known[0]->value.a.size != 2 )
  685.             known[0]->status = pv_typecheck,
  686.             code = gs_error_typecheck;
  687.         else
  688.            {    gs_prop_item *ap = known[0]->value.a.p.v;
  689.             if ( ap[0].value.f <= 0 || ap[1].value.f <= 0 )
  690.                 known[0]->status = pv_rangecheck,
  691.                 code = gs_error_rangecheck;
  692.             else
  693.                {    temp_dev.x_pixels_per_inch = ap[0].value.f;
  694.                 temp_dev.y_pixels_per_inch = ap[1].value.f;
  695.                }
  696.            }
  697.        }
  698.     if ( code < 0 )
  699.         return_error(code);
  700.     dev->x_pixels_per_inch = temp_dev.x_pixels_per_inch;
  701.     dev->y_pixels_per_inch = temp_dev.y_pixels_per_inch;
  702.     dev->width = temp_dev.width;
  703.     dev->height = temp_dev.height;
  704.     /* If the device is open, resize the window. */
  705.     /* Don't do this if Ghostview is active. */
  706.     if ( dev->is_open && (known[0] != 0 || known[1] != 0) && !xdev->ghostview )
  707.       { XResizeWindow(xdev->dpy, xdev->win, dev->width, dev->height);
  708.         if ( xdev->bpixmap != (Pixmap)0 )
  709.           { XFreePixmap(xdev->dpy, xdev->bpixmap);
  710.         xdev->bpixmap = (Pixmap)0;
  711.           }
  712.         xdev->dest = 0;
  713.         gdev_x_clear_window(xdev);
  714.       }
  715.     return gx_default_put_props(dev, plist, count);
  716. }
  717.  
  718.  
  719. /* ------ Screen update procedures ------ */
  720.  
  721. /* Flush updates to the screen if needed. */
  722. private void
  723. update_do_flush(register gx_device *dev)
  724. {    int xo = xdev->update.xo, yo = xdev->update.yo;
  725.     set_function(GXcopy);
  726.     XCopyArea(xdev->dpy, xdev->bpixmap, xdev->win, xdev->gc,
  727.           xo, yo, xdev->update.xe - xo, xdev->update.ye - yo,
  728.           xo, yo);
  729.     update_init(dev);
  730. }
  731.  
  732. /* Add a region to be updated. */
  733. /* This is only called if xdev->bpixmap != 0. */
  734. private void
  735. update_add(register gx_device *dev, int xo, int yo, int w, int h)
  736. {    int xe = xo + w, ye = yo + h;
  737.     long new_area = (long)w * h;
  738.     ++xdev->up_count;
  739.     if ( xdev->up_area != 0 )
  740.       { /* See whether adding this rectangle */
  741.         /* would result in too much being copied unnecessarily. */
  742.         long old_area = xdev->up_area;
  743.         long new_up_area;
  744.         rect u;
  745.         u.xo = min(xo, xdev->update.xo);
  746.         u.yo = min(yo, xdev->update.yo);
  747.         u.xe = max(xe, xdev->update.xe);
  748.         u.ye = max(ye, xdev->update.ye);
  749.         new_up_area = (long)(u.xe - u.xo) * (u.ye - u.yo);
  750.         if ( new_up_area > 100 &&
  751.         old_area + new_area < new_up_area * 2 / 3 ||
  752.         xdev->up_count >= 200
  753.         )
  754.           update_do_flush(dev);
  755.         else
  756.           { xdev->update = u;
  757.         xdev->up_area = new_up_area;
  758.         return;
  759.           }
  760.       }
  761.     xdev->update.xo = xo;
  762.     xdev->update.yo = yo;
  763.     xdev->update.xe = xe;
  764.     xdev->update.ye = ye;
  765.     xdev->up_area = new_area;
  766. }
  767.  
  768. /* ------ Internal procedures ------ */
  769.  
  770. /* Substitute for XPutImage using XFillRectangle. */
  771. /* This is a total hack to get around an apparent bug */
  772. /* in some X servers.  It only works with the specific */
  773. /* parameters (bit/byte order, padding) used above. */
  774. private void
  775. alt_put_image(gx_device *dev, Display *dpy, Drawable win, GC gc,
  776.   XImage *pi, int sx, int sy, int dx, int dy, unsigned w, unsigned h)
  777. {    int raster = pi->bytes_per_line;
  778.     byte *data = (byte *)pi->data + sy * raster + (sx >> 3);
  779.     int init_mask = 0x80 >> (sx & 7);
  780.     int invert;
  781.     int yi;
  782. #define nrects 40
  783.     XRectangle rects[nrects];
  784.     XRectangle *rp = rects;
  785.     if ( xdev->fore_color != gx_no_color_index )
  786.       { if ( xdev->back_color != gx_no_color_index )
  787.           { XSetForeground(dpy, gc, xdev->back_color);
  788.         XFillRectangle(dpy, win, gc, dx, dy, w, h);
  789.           }
  790.         XSetForeground(dpy, gc, xdev->fore_color);
  791.         invert = 0;
  792.       }
  793.     else if ( xdev->back_color != gx_no_color_index )
  794.       { XSetForeground(dpy, gc, xdev->back_color);
  795.         invert = 0xff;
  796.       }
  797.     else
  798.       return;
  799.     for ( yi = 0; yi < h; yi++, data += raster )
  800.       { register int mask = init_mask;
  801.         register byte *dp = data;
  802.         register int xi = 0;
  803.         while ( xi < w )
  804.           { if ( (*dp ^ invert) & mask )
  805.           { int xleft = xi;
  806.             if ( rp == &rects[nrects] )
  807.               { XFillRectangles(dpy, win, gc, rects, nrects);
  808.             rp = rects;
  809.               }
  810.             /* Scan over a run of 1-bits */
  811.             rp->x = dx + xi, rp->y = dy + yi;
  812.             do
  813.               { if ( !(mask >>= 1) ) mask = 0x80, dp++;
  814.             xi++;
  815.               }
  816.             while ( xi < w && (*dp & mask) );
  817.             rp->width = xi - xleft, rp->height = 1;
  818.             rp++;
  819.           }
  820.         else
  821.           { if ( !(mask >>= 1) ) mask = 0x80, dp++;
  822.             xi++;
  823.           }
  824.           }
  825.       }
  826.     XFillRectangles(dpy, win, gc, rects, rp - rects);
  827. }
  828.