ftp.nice.ch/pub/next/unix/graphics/ImageMagick.3.8.6.s.tar.gz#/ImageMagick/magick/X.c

This is X.c in view mode; [Download] [Up]

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%                                   X   X                                     %
%                                    X X                                      %
%                                     X                                       %
%                                    X X                                      %
%                                   X   X                                     %
%                                                                             %
%                    X11 Utility Routines for ImageMagick.                    %
%                                                                             %
%                                                                             %
%                               Software Design                               %
%                                 John Cristy                                 %
%                                  July 1992                                  %
%                                                                             %
%                                                                             %
%  Copyright 1997 E. I. du Pont de Nemours and Company                        %
%                                                                             %
%  Permission to use, copy, modify, distribute, and sell this software and    %
%  its documentation for any purpose is hereby granted without fee,           %
%  provided that the above Copyright notice appear in all copies and that     %
%  both that Copyright notice and this permission notice appear in            %
%  supporting documentation, and that the name of E. I. du Pont de Nemours    %
%  and Company not be used in advertising or publicity pertaining to          %
%  distribution of the software without specific, written prior               %
%  permission.  E. I. du Pont de Nemours and Company makes no representations %
%  about the suitability of this software for any purpose.  It is provided    %
%  "as is" without express or implied warranty.                               %
%                                                                             %
%  E. I. du Pont de Nemours and Company disclaims all warranties with regard  %
%  to this software, including all implied warranties of merchantability      %
%  and fitness, in no event shall E. I. du Pont de Nemours and Company be     %
%  liable for any special, indirect or consequential damages or any           %
%  damages whatsoever resulting from loss of use, data or profits, whether    %
%  in an action of contract, negligence or other tortious action, arising     %
%  out of or in connection with the use or performance of this software.      %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/

/*
  Include declarations.
*/
#include "magick.h"
#include "Colorlist.h"

/*
  State declarations.
*/
#define ControlState  0x0001
#define DefaultState  0x0000
#define ExitState  0x0002

/*
  Global declarations.
*/
static unsigned int
  xerror_alert = False;

/*
  Function prototypes.
*/
static void
  XMakeImageLSBFirst(const XResourceInfo *,const XWindowInfo *,Image *,
    XImage *,XImage *),
  XMakeImageMSBFirst(const XResourceInfo *,const XWindowInfo *,Image *,
    XImage *,XImage *);

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   I s T r u e                                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function IsTrue returns True if the boolean is "true", "on", "yes" or "1".
%
%  The format of the IsTrue routine is:
%
%      option=IsTrue(boolean)
%
%  A description of each parameter follows:
%
%    o option: either True or False depending on the boolean parameter.
%
%    o boolean: Specifies a pointer to a character array.
%
%
*/
Export unsigned int IsTrue(const char *boolean)
{
  if (boolean == (char *) NULL)
    return(False);
  if (Latin1Compare(boolean,"true") == 0)
    return(True);
  if (Latin1Compare(boolean,"on") == 0)
    return(True);
  if (Latin1Compare(boolean,"yes") == 0)
    return(True);
  if (Latin1Compare(boolean,"1") == 0)
    return(True);
  return(False);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   L a t i n 1 C o m p a r e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function Latin1Compare compares two null terminated Latin-1 strings,
%  ignoring case differences, and returns an integer greater than, equal
%  to, or less than 0, according to whether first is lexicographically
%  greater than, equal to, or less than second.  The two strings are
%  assumed to be encoded using ISO 8859-1.
%
%  The format of the Latin1Compare routine is:
%
%      Latin1Compare(first,second)
%
%  A description of each parameter follows:
%
%    o first: A pointer to the string to convert to Latin1 string.
%
%    o second: A pointer to the string to convert to Latin1 string.
%
%
*/
Export int Latin1Compare(const char *first,const char *second)
{
  register unsigned char
   *p,
   *q;

  if (first == second)
    return(0);
  if (first == (char *) NULL)
    return(-1);
  if (second == (char *) NULL)
    return(1);
  p=(unsigned char *) first;
  q=(unsigned char *) second;
  while ((*p != '\0') && (*q != '\0'))
  {
    register unsigned char
      c,
      d;

    c=(*p);
    d=(*q);
    if (c != d)
      {
        /*
          Try lowercasing and try again.
        */
        if ((c >= XK_A) && (c <= XK_Z))
          c+=(XK_a-XK_A);
        else
          if ((c >= XK_Agrave) && (c <= XK_Odiaeresis))
            c+=(XK_agrave-XK_Agrave);
          else
            if ((c >= XK_Ooblique) && (c <= XK_Thorn))
              c+=(XK_oslash-XK_Ooblique);
        if ((d >= XK_A) && (d <= XK_Z))
          d+=(XK_a-XK_A);
        else
          if ((d >= XK_Agrave) && (d <= XK_Odiaeresis))
            d+=(XK_agrave-XK_Agrave);
          else if ((d >= XK_Ooblique) && (d <= XK_Thorn))
            d+=(XK_oslash-XK_Ooblique);
        if (c != d)
          return(((int) c)-((int) d));
      }
    p++;
    q++;
  }
  return(((int) *p)-((int) *q));
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   L a t i n 1 U p p e r                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function Latin1Upper copies a null terminated string from source to
%  destination (including the null), changing all Latin-1 lowercase letters
%  to uppercase.  The string is assumed to be encoded using ISO 8859-1.
%
%  The format of the Latin1Upper routine is:
%
%      Latin1Upper(string)
%
%  A description of each parameter follows:
%
%    o string: A pointer to the string to convert to upper-case Latin1.
%
%
*/
static void Latin1Upper(char *string)
{
  unsigned char
    c;

  if (string == (char *) NULL)
    return;
  c=(*string);
  while (c != '\0')
  {
    if ((c >= XK_a) && (c <= XK_z))
      *string=c-(XK_a-XK_A);
    else
      if ((c >= XK_agrave) && (c <= XK_odiaeresis))
        *string=c-(XK_agrave-XK_Agrave);
      else
        if ((c >= XK_oslash) && (c <= XK_thorn))
          *string=c-(XK_oslash-XK_Ooblique);
    string++;
    c=(*string);
  }
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X A n n o t a t e I m a g e                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XAnnotateImage annotates the image with text.
%
%  The format of the XAnnotateImage routine is:
%
%    status=XAnnotateImage(display,pixel_info,annotate_info,image)
%
%  A description of each parameter follows:
%
%    o status: Function XAnnotateImage returns True if the image is
%      successfully annotated with text.  False is returned is there is a
%      memory shortage.
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o pixel_info: Specifies a pointer to a XPixelInfo structure.
%
%    o annotate_info: Specifies a pointer to a XAnnotateInfo structure.
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%
*/
Export unsigned int XAnnotateImage(Display *display,
  const XPixelInfo *pixel_info,const XAnnotateInfo *annotate_info,Image *image)
{
  GC
    annotate_context;

  Image
    *annotate_image;

  int
    x,
    y;

  Pixmap
    annotate_pixmap;

  register int
    i;

  register RunlengthPacket
    *p;

  unsigned int
    depth,
    height,
    matte,
    width;

  Window
    root_window;

  XGCValues
    context_values;

  XImage
    *annotate_ximage;

  /*
    Initialize annotated image.
  */
  assert(display != (Display *) NULL);
  assert(pixel_info != (XPixelInfo *) NULL);
  assert(annotate_info != (XAnnotateInfo *) NULL);
  assert(image != (Image *) NULL);
  if (!UncompressImage(image))
    return(False);
  /*
    Initialize annotated pixmap.
  */
  root_window=XRootWindow(display,XDefaultScreen(display));
  depth=XDefaultDepth(display,XDefaultScreen(display));
  annotate_pixmap=XCreatePixmap(display,root_window,annotate_info->width,
    annotate_info->height,(int) depth);
  if (annotate_pixmap == (Pixmap) NULL)
    return(False);
  /*
    Initialize graphics info.
  */
  context_values.background=0;
  context_values.foreground=(unsigned long) (~0);
  context_values.font=annotate_info->font_info->fid;
  annotate_context=XCreateGC(display,root_window,GCBackground | GCFont |
    GCForeground,&context_values);
  if (annotate_context == (GC) NULL)
    return(False);
  /*
    Draw text to pixmap.
  */
  XDrawImageString(display,annotate_pixmap,annotate_context,0,
    (int) annotate_info->font_info->ascent,annotate_info->text,
    Extent(annotate_info->text));
  XFreeGC(display,annotate_context);
  /*
    Initialize annotated X image.
  */
  annotate_ximage=XGetImage(display,annotate_pixmap,0,0,annotate_info->width,
    annotate_info->height,AllPlanes,ZPixmap);
  if (annotate_ximage == (XImage *) NULL)
    return(False);
  XFreePixmap(display,annotate_pixmap);
  /*
    Initialize annotated image.
  */
  annotate_image=AllocateImage((ImageInfo *) NULL);
  if (annotate_image == (Image *) NULL)
    return(False);
  annotate_image->columns=annotate_info->width;
  annotate_image->rows=annotate_info->height;
  annotate_image->packets=annotate_image->columns*annotate_image->rows;
  annotate_image->pixels=(RunlengthPacket *)
    malloc((unsigned int) image->packets*sizeof(RunlengthPacket));
  if (annotate_image->pixels == (RunlengthPacket *) NULL)
    {
      DestroyImage(annotate_image);
      return(False);
    }
  /*
    Transfer annotated X image to image.
  */
  (void) XParseGeometry(annotate_info->geometry,&x,&y,&width,&height);
  p=image->pixels+y*image->columns+x;
  annotate_image->background_color.red=p->red;
  annotate_image->background_color.green=p->green;
  annotate_image->background_color.blue=p->blue;
  annotate_image->background_color.index=Transparent;
  annotate_image->matte=True;
  p=annotate_image->pixels;
  for (y=0; y < annotate_image->rows; y++)
    for (x=0; x < annotate_image->columns; x++)
    {
      p->index=(unsigned short) XGetPixel(annotate_ximage,x,y);
      if (p->index == 0)
        {
          /*
            Set this pixel to the background color.
          */
          p->red=XDownScale(pixel_info->box_color.red);
          p->green=XDownScale(pixel_info->box_color.green);
          p->blue=XDownScale(pixel_info->box_color.blue);
          p->index=Opaque;
          if (annotate_info->stencil == ForegroundStencil)
            {
              p->red=annotate_image->background_color.red;
              p->green=annotate_image->background_color.green;
              p->blue=annotate_image->background_color.blue;
              p->index=Transparent;
            }
        }
      else
        {
          /*
            Set this pixel to the pen color.
          */
          p->red=XDownScale(pixel_info->pen_color.red);
          p->green=XDownScale(pixel_info->pen_color.green);
          p->blue=XDownScale(pixel_info->pen_color.blue);
          p->index=Opaque;
          if (annotate_info->stencil == BackgroundStencil)
            {
              p->red=annotate_image->background_color.red;
              p->green=annotate_image->background_color.green;
              p->blue=annotate_image->background_color.blue;
              p->index=Transparent;
            }
        }
      p->length=0;
      p++;
    }
  XDestroyImage(annotate_ximage);
  /*
    Determine annotate geometry.
  */
  (void) XParseGeometry(annotate_info->geometry,&x,&y,&width,&height);
  if ((width != annotate_image->columns) || (height != annotate_image->rows))
    {
      char
        image_geometry[MaxTextExtent];

      /*
        Scale image.
      */
      (void) sprintf(image_geometry,"%ux%u",width,height);
      TransformImage(&annotate_image,(char *) NULL,image_geometry);
    }
  if (annotate_info->degrees != 0.0)
    {
      double
        normalized_degrees;

      Image
        *rotated_image;

      int
        rotations;

      /*
        Rotate image.
      */
      rotated_image=
        RotateImage(annotate_image,annotate_info->degrees,False,True);
      if (rotated_image == (Image *) NULL)
        return(False);
      DestroyImage(annotate_image);
      annotate_image=rotated_image;
      /*
        Annotation is relative to the degree of rotation.
      */
      normalized_degrees=annotate_info->degrees;
      while (normalized_degrees < -45.0)
        normalized_degrees+=360.0;
      for (rotations=0; normalized_degrees > 45.0; rotations++)
        normalized_degrees-=90.0;
      switch (rotations % 4)
      {
        default:
        case 0:
          break;
        case 1:
        {
          /*
            Rotate 90 degrees.
          */
          x-=annotate_image->columns >> 1;
          y+=annotate_image->columns >> 1;
          break;
        }
        case 2:
        {
          /*
            Rotate 180 degrees.
          */
          x-=annotate_image->columns;
          break;
        }
        case 3:
        {
          /*
            Rotate 270 degrees.
          */
          x-=annotate_image->columns >> 1;
          y-=annotate_image->rows-(annotate_image->columns >> 1);
          break;
        }
      }
    }
  /*
    Composite text onto the image.
  */
  p=annotate_image->pixels;
  for (i=0; i < annotate_image->packets; i++)
  {
    if (p->index != Transparent)
      p->index=Opaque;
    p++;
  }
  matte=image->matte;
  CompositeImage(image,OverCompositeOp,annotate_image,x,y);
  image->matte=matte;
  DestroyImage(annotate_image);
  return(True);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X B e s t F o n t                                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XBestFont returns the "best" font.  "Best" is defined as a font
%  specified in the X resource database or a font such that the text width
%  displayed with the font does not exceed the specified maximum width.
%
%  The format of the XBestFont routine is:
%
%      font=XBestFont(display,resource_info,text_font)
%
%  A description of each parameter follows:
%
%    o font: XBestFont returns a pointer to a XFontStruct structure.
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o text_font:  True is font should be mono-spaced (typewriter style).
%
%
*/

static char **FontToList(char *font)
{
  char
    **fontlist;

  register char
    *p,
    *q;

  register int
    i;

  unsigned int
    fonts;

  if (font == (char *) NULL)
    return((char **) NULL);
  /*
    Convert string to an ASCII list.
  */
  fonts=1;
  for (p=font; *p != '\0'; p++)
    if (*p == ':')
      fonts++;
  fontlist=(char **) malloc((fonts+1)*sizeof(char *));
  if (fontlist == (char **) NULL)
    {
      Warning("Unable to convert font","Memory allocation failed");
      return((char **) NULL);
    }
  p=font;
  for (i=0; i < fonts; i++)
  {
    for (q=p; *q != '\0'; q++)
      if (*q == ':')
        break;
    fontlist[i]=(char *) malloc((q-p+1)*sizeof(char));
    if (fontlist[i] == (char *) NULL)
      {
        Warning("Unable to convert font","Memory allocation failed");
        return((char **) NULL);
      }
    (void) strncpy(fontlist[i],p,q-p);
    fontlist[i][q-p]='\0';
    p=q+1;
  }
  fontlist[i]=(char *) NULL;
  return(fontlist);
}

Export XFontStruct *XBestFont(Display *display,
  const XResourceInfo *resource_info,const unsigned int text_font)
{
  static char
    *Fonts[]=
    {
      "-adobe-helvetica-medium-r-normal-*-14-*",
      "-*-helvetica-medium-r-*-*-14-*",
      "-*-lucida-medium-r-*-*-14-*",
      "8x13",
      "6x13",
      "fixed",
      "variable",
      (char *) NULL
    },
    *TextFonts[]=
    {
      "-adobe-courier-medium-r-*-*-14-*",
      "-*-fixed-medium-r-normal-*-14-*",
      "-*-fixed-medium-r-*-*-14-*",
      "8x13",
      "6x13",
      "fixed",
      (char *) NULL
    };

  char
    *font_name,
    **p;

  XFontStruct
    *font_info;

  font_info=(XFontStruct *) NULL;
  font_name=resource_info->font;
  if (text_font)
    font_name=resource_info->text_font;
  if (font_name != (char *) NULL)
    {
      char
        **fontlist;

      register int
        i;

      /*
        Load preferred font specified in the X resource database.
      */
      fontlist=FontToList(font_name);
      if (fontlist != (char **) NULL)
        {
          for (i=0; fontlist[i] != (char *) NULL; i++)
          {
            if (font_info == (XFontStruct *) NULL)
              font_info=XLoadQueryFont(display,fontlist[i]);
            free((char *) fontlist[i]);
          }
          free((char *) fontlist);
        }
      if (font_info == (XFontStruct *) NULL)
        Warning("Unable to load font",font_name);
    }
  /*
    Load fonts from list of fonts until one is found.
  */
  p=Fonts;
  if (text_font)
    p=TextFonts;
  while (*p != (char *) NULL)
  {
    if (font_info != (XFontStruct *) NULL)
      break;
    font_info=XLoadQueryFont(display,*p);
    p++;
  }
  return(font_info);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X B e s t I c o n S i z e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XBestIconSize returns the "best" icon size.  "Best" is defined as
%  an icon size that maintains the aspect ratio of the image.  If the window
%  manager has preferred icon sizes, one of the preferred sizes is used.
%
%  The format of the XBestIconSize routine is:
%
%      XBestIconSize(display,window,image)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%
*/
Export void XBestIconSize(Display *display,XWindowInfo *window,Image *image)
{
#define MaxIconSize  96

  int
    i,
    number_sizes;

  unsigned int
    height,
    icon_height,
    icon_width,
    width;

  unsigned long
    scale_factor;

  Window
    root_window;

  XIconSize
    *icon_size,
    *size_list;

  /*
    Determine if the window manager has specified preferred icon sizes.
  */
  assert(display != (Display *) NULL);
  assert(window != (XWindowInfo *) NULL);
  assert(image != (Image *) NULL);
  window->width=MaxIconSize;
  window->height=MaxIconSize;
  icon_size=(XIconSize *) NULL;
  number_sizes=0;
  root_window=XRootWindow(display,window->screen);
  if (XGetIconSizes(display,root_window,&size_list,&number_sizes) != 0)
    if ((number_sizes > 0) && (size_list != (XIconSize *) NULL))
      icon_size=size_list;
  if (icon_size == (XIconSize *) NULL)
    {
      /*
        Window manager does not restrict icon size.
      */
      icon_size=XAllocIconSize();
      if (icon_size == (XIconSize *) NULL)
        {
          Warning("Unable to choose best icon size","Memory allocation failed");
          return;
        }
      icon_size->min_width=1;
      icon_size->max_width=MaxIconSize;
      icon_size->min_height=1;
      icon_size->max_height=MaxIconSize;
      icon_size->width_inc=1;
      icon_size->height_inc=1;
    }
  /*
    Determine aspect ratio of image.
  */
  width=image->columns;
  height=image->rows;
  if (window->crop_geometry)
    (void) XParseGeometry(window->crop_geometry,&i,&i,&width,&height);
  /*
    Look for an icon size that maintains the aspect ratio of image.
  */
  scale_factor=UpShift(icon_size->max_width)/width;
  if (scale_factor > (UpShift(icon_size->max_height)/height))
    scale_factor=UpShift(icon_size->max_height)/height;
  icon_width=icon_size->min_width;
  while (icon_width < icon_size->max_width)
  {
    if (icon_width >= (DownShift(width*scale_factor)))
      break;
    icon_width+=icon_size->width_inc;
  }
  icon_height=icon_size->min_height;
  while (icon_height < icon_size->max_height)
  {
    if (icon_height >= (DownShift(height*scale_factor)))
      break;
    icon_height+=icon_size->height_inc;
  }
  XFree((void *) icon_size);
  window->width=icon_width;
  window->height=icon_height;
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X B e s t P i x e l                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XBestPixel returns a pixel from an array of pixels that is closest
%  to the requested color.  If the color array is NULL, the colors are obtained
%  from the X server.
%
%  The format of the XBestPixel routine is:
%
%      pixel=XBestPixel(display,colormap,colors,number_colors,color)
%
%  A description of each parameter follows:
%
%    o pixel: XBestPixel returns the pixel value closest to the requested
%      color.
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o colormap: Specifies the ID of the X server colormap.
%
%    o colors: Specifies an array of XColor structures.
%
%    o number_colors: Specifies the number of XColor structures in the
%      color definition array.
%
%    o color: Specifies the desired RGB value to find in the colors array.
%
%
*/
Export void XBestPixel(Display *display,const Colormap colormap,XColor *colors,
  unsigned int number_colors,XColor *color)
{
  double
    distance_squared,
    min_distance;

  int
    distance,
    query_server,
    status;

  register int
    i,
    j;

  /*
    Find closest representation for the requested RGB color.
  */
  assert(display != (Display *) NULL);
  assert(color != (XColor *) NULL);
  status=XAllocColor(display,colormap,color);
  if (status != 0)
    return;
  query_server=colors == (XColor *) NULL;
  if (query_server)
    {
      /*
        Read X server colormap.
      */
      colors=(XColor *) malloc(number_colors*sizeof(XColor));
      if (colors == (XColor *) NULL)
        Error("Unable to read X server colormap","Memory allocation failed");
      for (i=0; i < number_colors; i++)
        colors[i].pixel=(unsigned long) i;
      if (number_colors > 256)
        number_colors=256;
      XQueryColors(display,colormap,colors,number_colors);
    }
  min_distance=3.0*65536.0*65536.0;
  color->pixel=colors[0].pixel;
  j=0;
  for (i=0; i < number_colors; i++)
  {
    distance=(int) colors[i].red-(int) color->red;
    distance_squared=(unsigned int) (distance*distance);
    distance=(int) colors[i].green-(int) color->green;
    distance_squared+=(unsigned int) (distance*distance);
    distance=(int) colors[i].blue-(int) color->blue;
    distance_squared+=(unsigned int) (distance*distance);
    if (distance_squared < min_distance)
      {
        min_distance=distance_squared;
        color->pixel=colors[i].pixel;
        j=i;
      }
  }
  (void) XAllocColor(display,colormap,&colors[j]);
  if (query_server)
    free((char *) colors);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X B e s t V i s u a l I n f o                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XBestVisualInfo returns visual information for a visual that is
%  the "best" the server supports.  "Best" is defined as:
%
%    1. Restrict the visual list to those supported by the default screen.
%
%    2. If a visual type is specified, restrict the visual list to those of
%       that type.
%
%    3. If a map type is specified, choose the visual that matches the id
%       specified by the Standard Colormap.
%
%    4  From the list of visuals, choose one that can display the most
%       simultaneous colors.  If more than one visual can display the same
%       number of simultaneous colors, one is choosen based on a rank.
%
%  The format of the XBestVisualInfo routine is:
%
%      visual_info=XBestVisualInfo(display,map_info,resource_info)
%
%  A description of each parameter follows:
%
%    o visual_info: XBestVisualInfo returns a pointer to a X11 XVisualInfo
%      structure.
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o map_info: If map_type is specified, this structure is initialized
%      with info from the Standard Colormap.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%
*/
Export XVisualInfo *XBestVisualInfo(Display *display,
  XStandardColormap *map_info,XResourceInfo *resource_info)
{
#define MaxStandardColormaps  7
#define XVisualColormapSize(visual_info) Min( \
  (visual_info->class == TrueColor) || (visual_info->class == DirectColor) ? \
   visual_info->red_mask | visual_info->green_mask | visual_info->blue_mask : \
   visual_info->colormap_size,1 << visual_info->depth)

  char
    *map_type,
    *visual_type;

  register int
    i;

  static int
    number_visuals;

  static XVisualInfo
    visual_template;

  unsigned int
    visual_mask;

  XVisualInfo
    *visual_info,
    *visual_list;

  /*
    Restrict visual search by screen number.
  */
  assert(display != (Display *) NULL);
  assert(map_info != (XStandardColormap *) NULL);
  assert(resource_info != (XResourceInfo *) NULL);
  map_type=resource_info->map_type;
  visual_type=resource_info->visual_type;
  visual_mask=VisualScreenMask;
  visual_template.screen=XDefaultScreen(display);
  if (visual_type != (char *) NULL)
    {
      /*
        Restrict visual search by class or visual id.
      */
      if (Latin1Compare("staticgray",visual_type) == 0)
        {
          visual_mask|=VisualClassMask;
          visual_template.class=StaticGray;
        }
      else
        if (Latin1Compare("grayscale",visual_type) == 0)
          {
            visual_mask|=VisualClassMask;
            visual_template.class=GrayScale;
          }
        else
          if (Latin1Compare("staticcolor",visual_type) == 0)
            {
              visual_mask|=VisualClassMask;
              visual_template.class=StaticColor;
            }
          else
            if (Latin1Compare("pseudocolor",visual_type) == 0)
              {
                visual_mask|=VisualClassMask;
                visual_template.class=PseudoColor;
              }
            else
              if (Latin1Compare("truecolor",visual_type) == 0)
                {
                  visual_mask|=VisualClassMask;
                  visual_template.class=TrueColor;
                }
              else
                if (Latin1Compare("directcolor",visual_type) == 0)
                  {
                    visual_mask|=VisualClassMask;
                    visual_template.class=DirectColor;
                  }
                else
                  if (Latin1Compare("default",visual_type) == 0)
                    {
                      visual_mask|=VisualIDMask;
                      visual_template.visualid=XVisualIDFromVisual(
                        XDefaultVisual(display,XDefaultScreen(display)));
                    }
                  else
                    if (isdigit(*visual_type))
                      {
                        visual_mask|=VisualIDMask;
                        visual_template.visualid=
                          strtol(visual_type,(char **) NULL,0);
                      }
                    else
                      Warning("Invalid visual specifier",visual_type);
    }
  /*
    Get all visuals that meet our criteria so far.
  */
  number_visuals=0;
  visual_list=XGetVisualInfo(display,visual_mask,&visual_template,
    &number_visuals);
  visual_mask=VisualScreenMask | VisualIDMask;
  if ((number_visuals == 0) || (visual_list == (XVisualInfo *) NULL))
    {
      /*
        Failed to get visual;  try using the default visual.
      */
      Warning("Unable to get visual",visual_type);
      visual_template.visualid=
        XVisualIDFromVisual(XDefaultVisual(display,XDefaultScreen(display)));
      visual_list=XGetVisualInfo(display,visual_mask,&visual_template,
        &number_visuals);
      if ((number_visuals == 0) || (visual_list == (XVisualInfo *) NULL))
        return((XVisualInfo *) NULL);
      Warning("Using default visual",XVisualClassName(visual_list->class));
    }
  resource_info->color_recovery=False;
  if ((map_info != (XStandardColormap *) NULL) && (map_type != (char *) NULL))
    {
      Atom
        map_property;

      char
        map_name[MaxTextExtent];

      int
        j,
        number_maps,
        status;

      Window
        root_window;

      XStandardColormap
        *map_list;

      /*
        Choose a visual associated with a standard colormap.
      */
      root_window=XRootWindow(display,XDefaultScreen(display));
      status=0;
      if (strcmp(map_type,"list") != 0)
        {
          /*
            User specified Standard Colormap.
          */
          (void) sprintf((char *) map_name,"RGB_%s_MAP",map_type);
          Latin1Upper(map_name);
          map_property=XInternAtom(display,(char *) map_name,True);
          if (map_property == (Atom) NULL)
            Error("Unable to get Standard Colormap",map_type);
          status=XGetRGBColormaps(display,root_window,&map_list,&number_maps,
            map_property);
        }
      else
        {
          static char
            *colormap[]=
            {
              "_HP_RGB_SMOOTH_MAP_LIST",
              "RGB_BEST_MAP",
              "RGB_DEFAULT_MAP",
              "RGB_GRAY_MAP",
              "RGB_RED_MAP",
              "RGB_GREEN_MAP",
              "RGB_BLUE_MAP",
            };

          /*
            Choose a standard colormap from a list.
          */
          for (i=0; i < MaxStandardColormaps; i++)
          {
            map_property=XInternAtom(display,colormap[i],True);
            if (map_property == (Atom) NULL)
              continue;
            status=XGetRGBColormaps(display,root_window,&map_list,&number_maps,
              map_property);
            if (status != 0)
              break;
          }
          resource_info->color_recovery=(i == 0);  /* _HP_RGB_SMOOTH_MAP_LIST */
        }
      if (status == 0)
        Error("Unable to get Standard Colormap",map_type);
      /*
        Search all Standard Colormaps and visuals for ids that match.
      */
      *map_info=map_list[0];
#ifndef PRE_R4_ICCCM
      visual_template.visualid=XVisualIDFromVisual(visual_list[0].visual);
      for (i=0; i < number_maps; i++)
        for (j=0; j < number_visuals; j++)
          if (map_list[i].visualid ==
              XVisualIDFromVisual(visual_list[j].visual))
            {
              *map_info=map_list[i];
              visual_template.visualid=
                XVisualIDFromVisual(visual_list[j].visual);
              break;
            }
      if (map_info->visualid != visual_template.visualid)
        Error("Unable to match visual to Standard Colormap",map_type);
#endif
      if (map_info->colormap == (Colormap) NULL)
        Error("Standard Colormap is not initialized",map_type);
      XFree((void *) map_list);
    }
  else
    {
      static unsigned int
        rank[]=
          {
            StaticGray,
            GrayScale,
            StaticColor,
            DirectColor,
            TrueColor,
            PseudoColor
          };

      XVisualInfo
        *p;

      /*
        Pick one visual that displays the most simultaneous colors.
      */
      visual_info=visual_list;
      p=visual_list;
      for (i=1; i < number_visuals; i++)
      {
        p++;
        if (XVisualColormapSize(p) > XVisualColormapSize(visual_info))
          visual_info=p;
        else
          if (XVisualColormapSize(p) == XVisualColormapSize(visual_info))
            if (rank[p->class] > rank[visual_info->class])
              visual_info=p;
      }
      visual_template.visualid=XVisualIDFromVisual(visual_info->visual);
    }
  XFree((void *) visual_list);
  /*
    Retrieve only one visual by its screen & id number.
  */
  visual_info=XGetVisualInfo(display,visual_mask,&visual_template,
    &number_visuals);
  if ((number_visuals == 0) || (visual_info == (XVisualInfo *) NULL))
    return((XVisualInfo *) NULL);
  return(visual_info);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X C h e c k R e f r e s h W i n d o w s                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XCheckRefreshWindows checks the X server for exposure events for
%  a particular window and updates the area associated withe exposure event.
%
%  The format of the XCheckRefreshWindows routine is:
%
%      XCheckRefreshWindows(display,windows)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o windows: Specifies a pointer to a XWindows structure.
%
%
*/
Export void XCheckRefreshWindows(Display *display,XWindows *windows)
{
  XEvent
    event;

  assert(display != (Display *) NULL);
  assert(windows != (XWindows *) NULL);
  XDelay(display,SuspendTime);
  while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event))
    (void) XCommandWidget(display,windows,(char **) NULL,&event);
  while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event))
    XRefreshWindow(display,&windows->image,&event);
  XDelay(display,SuspendTime << 1);
  while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event))
    (void) XCommandWidget(display,windows,(char **) NULL,&event);
  while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event))
    XRefreshWindow(display,&windows->image,&event);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X C l i e n t M e s s a g e                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XClientMessage sends a message to a window with XSendEvent.  The
%  message is initialized with a particular protocol type and atom.
%
%  The format of the XClientMessage function is:
%
%      XClientMessage(display,window,protocol,message,timestamp)
%
%  A description of each parameter follows:
%
%    o display: Specifies a pointer to the Display structure;  returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a Window structure.
%
%    o protocol: Specifies an atom value.
%
%    o message: Specifies an atom value which is the message to send.
%
%    o timestamp: Specifies a value of type Time.
%
%
*/
Export void XClientMessage(Display *display,const Window window,
  const Atom protocol,const Atom message,const Time timestamp)
{
  XClientMessageEvent
    client_event;

  assert(display != (Display *) NULL);
  client_event.type=ClientMessage;
  client_event.window=window;
  client_event.message_type=protocol;
  client_event.format=32;
  client_event.data.l[0]=(long) message;
  client_event.data.l[1]=(long) timestamp;
  XSendEvent(display,window,False,NoEventMask,(XEvent *) &client_event);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X C l i e n t W i n d o w                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XClientWindow finds a window, at or below the specified window,
%  which has a WM_STATE property.  If such a window is found, it is returned,
%  otherwise the argument window is returned.
%
%  The format of the XClientWindow function is:
%
%      client_window=XClientWindow(display,target_window)
%
%  A description of each parameter follows:
%
%    o client_window: XClientWindow returns a window, at or below the specified
%      window, which has a WM_STATE property otherwise the argument
%      target_window is returned.
%
%    o display: Specifies a pointer to the Display structure;  returned from
%      XOpenDisplay.
%
%    o target_window: Specifies the window to find a WM_STATE property.
%
%
*/
Window XClientWindow(Display *display,Window target_window)
{
  Atom
    state,
    type;

  int
    format,
    status;

  unsigned char
    *data;

  unsigned long
    after,
    number_items;

  Window
    client_window;

  assert(display != (Display *) NULL);
  state=XInternAtom(display,"WM_STATE",True);
  if (state == (Atom) NULL)
    return(target_window);
  type=(Atom) NULL;
  status=XGetWindowProperty(display,target_window,state,0L,0L,False,
    (Atom) AnyPropertyType,&type,&format,&number_items,&after,&data);
  if ((status == Success) && (type != (Atom) NULL))
    return(target_window);
  client_window=XWindowByProperty(display,target_window,state);
  if (client_window == (Window) NULL)
    return(target_window);
  return(client_window);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X C o n s t r a i n W i n d o w P o s i t i o n                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XConstrainWindowPosition assures a window is positioned witin the
%  X server boundaries.
%
%  The format of the XConstrainWindowPosition routine is:
%
%      XConstrainWindowPosition(display,window_info)
%
%  A description of each parameter follows:
%
%    o display: Specifies a pointer to the Display structure;  returned from
%      XOpenDisplay.
%
%    o window_info: Specifies a pointer to a XWindowInfo structure.
%
%
*/
Export void XConstrainWindowPosition(Display *display,XWindowInfo *window_info)
{
  unsigned int
    limit;

  assert(display != (Display *) NULL);
  assert(window_info != (XWindowInfo *) NULL);
  limit=XDisplayWidth(display,window_info->screen)-window_info->width;
  if (window_info->x < 0)
    window_info->x=0;
  else
    if (window_info->x > limit)
      window_info->x=limit;
  limit=XDisplayHeight(display,window_info->screen)-window_info->height;
  if (window_info->y < 0)
    window_info->y=0;
  else
    if (window_info->y > limit)
      window_info->y=limit;
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X D e l a y                                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XDelay suspends program execution for the number of milliseconds
%  specified.
%
%  The format of the Delay routine is:
%
%      XDelay(display,milliseconds)
%
%  A description of each parameter follows:
%
%    o display: Specifies a pointer to the Display structure;  returned from
%      XOpenDisplay.
%
%    o milliseconds: Specifies the number of milliseconds to delay before
%      returning.
%
%
*/
Export void XDelay(Display *display,const unsigned long milliseconds)
{
  assert(display != (Display *) NULL);
  (void) XFlush(display);
  if (milliseconds == 0)
    return;
#if !defined(vms) && !defined(macintosh) && !defined(WIN32)
#ifdef sysv
  {
#include <sys/poll.h>

    (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
  }
#else
  {
    struct timeval
      timer;

    timer.tv_sec=(int) milliseconds/1000;
    timer.tv_usec=(int) (milliseconds % 1000)*1000;
    (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
  }
#endif
#endif
#if defined(vms)
  {
    float
      timer;

    timer=milliseconds/1000.0;
    lib$wait(&timer);
  }
#endif
#if defined(WIN32)
  Sleep(milliseconds);
#endif
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X D e s t r o y W i n d o w C o l o r s                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XDestroyWindowColors frees X11 color resources previously saved on
%  a window by XRetainWindowColors or programs like xsetroot.
%
%  The format of the XDestroyWindowColors routine is:
%
%      XDestroyWindowColors(display,window)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a Window structure.
%
%
*/
Export void XDestroyWindowColors(Display *display,Window window)
{
  Atom
    property,
    type;

  int
    format,
    status;

  unsigned char
    *data;

  unsigned long
    after,
    length;

  /*
    If there are previous resources on the root window, destroy them.
  */
  assert(display != (Display *) NULL);
  property=XInternAtom(display,"_XSETROOT_ID",False);
  if (property == (Atom) NULL)
    {
      Warning("Unable to create X property","_XSETROOT_ID");
      return;
    }
  status=XGetWindowProperty(display,window,property,0L,1L,True,
    (Atom) AnyPropertyType,&type,&format,&length,&after,&data);
  if (status != Success)
    return;
  if ((type == XA_PIXMAP) && (format == 32) && (length == 1) && (after == 0))
    {
      XKillClient(display,(XID) (*((Pixmap *) data)));
      XDeleteProperty(display,window,property);
    }
  if (type != None)
    XFree((void *) data);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X D i s p l a y I m a g e I n f o                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XDisplayImageInfo displays information about an X image.
%
%  The format of the XDisplayImageInfo routine is:
%
%      XDisplayImageInfo(display,resource_info,windows,undo_image,image)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o windows: Specifies a pointer to a XWindows structure.
%
%    o undo_image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%
*/
Export void XDisplayImageInfo(Display *display,
  const XResourceInfo *resource_info,XWindows *windows,Image *undo_image,
  Image *image)
{
  char
    *text,
    **textlist,
    title[MaxTextExtent];

  int
    length;

  Image
    *p;

  register int
    i;

  unsigned int
    bytes,
    count,
    levels;

  /*
    Display information about the image in the Text View widget.
  */
  assert(display != (Display *) NULL);
  assert(resource_info != (XResourceInfo *) NULL);
  assert(windows != (XWindows *) NULL);
  assert(image != (Image *) NULL);
  length=50*MaxTextExtent;
  if (image->directory != (char *) NULL)
    length+=Extent(image->directory);
  if (image->comments != (char *) NULL)
    length+=Extent(image->comments);
  text=(char *) malloc(length*sizeof(char));
  if (text == (char *) NULL)
    {
      XNoticeWidget(display,windows,"Unable to display image info:",
        "Memory allocation failed");
      return;
    }
  *text='\0';
  /*
    Display info about the X server.
  */
  (void) sprintf(title," Image Info: %s",image->filename);
  if (resource_info->gamma_correct)
    if (resource_info->display_gamma != (char *) NULL)
      (void) sprintf(text,"%sDisplay\n  gamma: %s\n\n",text,
        resource_info->display_gamma);
  /*
    Display info about the X image.
  */
  (void) sprintf(text,"%sX\n  visual: %s\n",text,
    XVisualClassName(windows->image.class));
  (void) sprintf(text,"%s  depth: %d\n",text,windows->image.ximage->depth);
  if (windows->image.visual_info->colormap_size != 0)
    (void) sprintf(text,"%s  colormap size: %d\n",text,
      windows->image.visual_info->colormap_size);
  if (resource_info->colormap== SharedColormap)
    (void) strcat(text,"  colormap type: Shared\n");
  else
    (void) strcat(text,"  colormap type: Private\n");
  (void) sprintf(text,"%s  geometry: %dx%d\n",text,
    windows->image.ximage->width,windows->image.ximage->height);
  if (windows->image.crop_geometry != (char *) NULL)
    (void) sprintf(text,"%s  crop geometry: %s\n",text,
      windows->image.crop_geometry);
  if (windows->image.pixmap == (Pixmap) NULL)
    (void) strcat(text,"  type: X Image\n");
  else
    (void) strcat(text,"  type: Pixmap\n");
  if (windows->image.shared_memory)
    (void) strcat(text,"  shared memory: True\n");
  else
    (void) strcat(text,"  shared memory: False\n");
  (void) strcat(text,"\n");
  /*
    Display info about the undo image cache.
  */
  bytes=0;
  for (levels=0; undo_image != (Image *) NULL; levels++)
  {
    bytes+=undo_image->list->packets*sizeof(RunlengthPacket);
    undo_image=undo_image->previous;
  }
  (void) sprintf(text,"%sUndo Edit Cache\n  levels: %u\n",text,levels);
  (void) sprintf(text,"%s  bytes: %umb\n",text,(bytes+(1 << 19)) >> 20);
  (void) sprintf(text,"%s  limit: %umb\n\n",text,resource_info->undo_cache);
  /*
    Display info about the image.
  */
  (void) sprintf(text,"%sImage\n  file: %s\n",text,image->filename);
  if (image->class == DirectClass)
    (void) strcat(text,"  class: DirectClass\n");
  else
    (void) strcat(text,"  class: PseudoClass\n");
  if (image->class == PseudoClass)
    {
      ColorPacket
        *p;

      register int
        i;

      register XColorlist
        *q;

      /*
        Display image colormap.
      */
      if (image->total_colors <= image->colors)
        (void) sprintf(text,"%s  colors: %u\n",text,image->colors);
      else
        (void) sprintf(text,"%s  colors: %lu=>%u\n",text,image->total_colors,
          image->colors);
      p=image->colormap;
      for (i=0; i < image->colors; i++)
      {
        (void) sprintf(text,"%s    %d: (%3d,%3d,%3d)  #%02x%02x%02x",
          text,i,p->red,p->green,p->blue,(unsigned int) p->red,
          (unsigned int) p->green,(unsigned int) p->blue);
        for (q=Colorlist; q->name != (char *) NULL; q++)
          if ((DownScale(p->red) == q->red) &&
              (DownScale(p->green) == q->green) &&
              (DownScale(p->blue) == q->blue))
            (void) sprintf(text,"%s  %s",text,q->name);
        (void) strcat(text,"\n");
        p++;
      }
    }
  if (image->signature != (char *) NULL)
    (void) sprintf(text,"%s  signature: %s\n",text,image->signature);
  if (image->matte)
    (void) strcat(text,"  matte: True\n");
  else
    (void) strcat(text,"  matte: False\n");
  if (image->gamma != 0.0)
    (void) sprintf(text,"%s  gamma: %f\n",text,image->gamma);
  if (image->packets < (image->columns*image->rows))
    (void) sprintf(text,"%s  runlength packets: %u of %u\n",text,image->packets,
      image->columns*image->rows);
  (void) sprintf(text,"%s  geometry: %ux%u\n",text,
    image->columns,image->rows);
  if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
    {
      /*
        Display image resolution.
      */
      (void) sprintf(text,"%s  resolution: %gx%g",text,
        image->x_resolution,image->y_resolution);
      if (image->units == UndefinedResolution)
        (void) sprintf(text,"%s pixels\n",text);
      else
        if (image->units == PixelsPerInchResolution)
          (void) sprintf(text,"%s pixels/inch\n",text);
        else
          if (image->units == PixelsPerCentimeterResolution)
            (void) sprintf(text,"%s pixels/centimeter\n",text);
          else
            (void) sprintf(text,"%s\n",text);
    }
  (void) sprintf(text,"%s  depth: %u\n",text,image->depth);
  if (image->filesize != 0)
    if (image->filesize >= (1 << 24))
      (void) sprintf(text,"%s  filesize: %ldmb\n",text,
        image->filesize/1024/1024);
    else
      if (image->filesize >= (1 << 14))
        (void) sprintf(text,"%s  filesize: %ldkb\n",text,image->filesize/1024);
      else
        (void) sprintf(text,"%s  filesize: %ldb\n",text,image->filesize);
  if (image->interlace)
    (void) strcat(text,"  interlaced: True\n");
  else
    (void) strcat(text,"  interlaced: False\n");
  if (image->page != (char *) NULL)
    (void) sprintf(text,"%s  page geometry: %s\n",text,image->page);
  if (image->dispose)
    (void) sprintf(text,"%s  dispose method: %d\n",text,image->dispose);
  if (image->delay)
    (void) sprintf(text,"%s  delay: %d\n",text,image->delay);
  if (image->iterations != 1)
    (void) sprintf(text,"%s  iterations: %d\n",text,image->iterations);
  (void) sprintf(text,"%s  format: %s\n",text,image->magick);
  p=image;
  while (p->previous != (Image *) NULL)
    p=p->previous;
  for (count=1; p->next != (Image *) NULL; count++)
    p=p->next;
  if (count > 1)
    (void) sprintf(text,"%s  scene: %u of %u\n",text,image->scene,count);
  else
    if (image->scene != 0)
      (void) sprintf(text,"%s  scene: %u\n",text,image->scene);
  if (image->label != (char *) NULL)
    (void) sprintf(text,"%s  label: %s\n",text,image->label);
  if (image->comments != (char *) NULL)
    {
      /*
        Display image comment.
      */
      (void) sprintf(text,"%s  comments:\n",text);
      textlist=StringToList(image->comments);
      if (textlist != (char **) NULL)
        {
          for (i=0; textlist[i] != (char *) NULL; i++)
          {
            (void) sprintf(text,"%s  %s\n",text,textlist[i]);
            free(textlist[i]);
          }
          free((char *) textlist);
        }
    }
  if (image->montage != (char *) NULL)
    (void) sprintf(text,"%s  montage: %s\n",text,image->montage);
  if (image->directory != (char *) NULL)
    {
      /*
        Display image directory.
      */
      (void) sprintf(text,"%s  directory:\n",text);
      textlist=StringToList(image->directory);
      if (textlist != (char **) NULL)
        {
          for (i=0; textlist[i] != (char *) NULL; i++)
          {
            (void) sprintf(text,"%s    %s\n",text,textlist[i]);
            free(textlist[i]);
          }
          free((char *) textlist);
        }
    }
  textlist=StringToList(text);
  if (textlist != (char **) NULL)
    {
      register int
        i;

      XTextViewWidget(display,resource_info,windows,True,title,textlist);
      for (i=0; textlist[i] != (char *) NULL; i++)
        free((char *) textlist[i]);
      free((char *) textlist);
    }
  free((char *) text);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%     X D i t h e r I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XDitherImage dithers the reference image as required by the HP
%  Color Recovery algorithm.  The color values are quantized to 3 bits of red
%  and green, and 2 bits of blue (3/3/2) and can be used as indices into a
%  8-bit X standard colormap.
%
%  The format of the XDitherImage routine is:
%
%      XDitherImage(image,ximage)
%
%  A description of each parameter follows:
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%    o ximage: Specifies a pointer to a XImage structure;  returned from
%      XCreateImage.
%
%
*/
static void XDitherImage(Image *image,XImage *ximage)
{
  static short int
    dither_red[2][16]=
    {
      {-16,  4, -1, 11,-14,  6, -3,  9,-15,  5, -2, 10,-13,  7, -4,  8},
      { 15, -5,  0,-12, 13, -7,  2,-10, 14, -6,  1,-11, 12, -8,  3, -9}
    },
    dither_green[2][16]=
    {
      { 11,-15,  7, -3,  8,-14,  4, -2, 10,-16,  6, -4,  9,-13,  5, -1},
      {-12, 14, -8,  2, -9, 13, -5,  1,-11, 15, -7,  3,-10, 12, -6,  0}
    },
    dither_blue[2][16]=
    {
      { -3,  9,-13,  7, -1, 11,-15,  5, -4,  8,-14,  6, -2, 10,-16,  4},
      {  2,-10, 12, -8,  0,-12, 14, -6,  3, -9, 13, -7,  1,-11, 15, -5}
    };

  ColorPacket
    color;

  int
    value,
    y;

  register char
    *q;

  register int
    i,
    j,
    x;

  register RunlengthPacket
    *p;

  unsigned int
    scanline_pad;

  register unsigned long
    pixel;

  unsigned short
    *blue_map[2][16],
    *green_map[2][16],
    *red_map[2][16];

  if (!UncompressImage(image))
    return;
  /*
    Allocate and initialize dither maps.
  */
  for (i=0; i < 2; i++)
    for (j=0; j < 16; j++)
    {
      red_map[i][j]=(unsigned short *) malloc(256*sizeof(unsigned short));
      green_map[i][j]=(unsigned short *) malloc(256*sizeof(unsigned short));
      blue_map[i][j]=(unsigned short *) malloc(256*sizeof(unsigned short));
      if ((red_map[i][j] == (unsigned short *) NULL) ||
          (green_map[i][j] == (unsigned short *) NULL) ||
          (blue_map[i][j] == (unsigned short *) NULL))
        {
          Warning("Unable to dither image","Memory allocation failed");
          return;
        }
    }
  /*
    Initialize dither tables.
  */
  for (i=0; i < 2; i++)
    for (j=0; j < 16; j++)
      for (x=0; x < 256; x++)
      {
        value=x-16;
        if (x < 48)
          value=x/2+8;
        value+=dither_red[i][j];
        red_map[i][j][x]=(unsigned short)
          ((value < 0) ? 0 : (value > MaxRGB) ? MaxRGB : value);
        value=x-16;
        if (x < 48)
          value=x/2+8;
        value+=dither_green[i][j];
        green_map[i][j][x]=(unsigned short)
          ((value < 0) ? 0 : (value > MaxRGB) ? MaxRGB : value);
        value=x-32;
        if (x < 112)
          value=x/2+24;
        value+=(dither_blue[i][j] << 1);
        blue_map[i][j][x]=(unsigned short)
          ((value < 0) ? 0 : (value > MaxRGB) ? MaxRGB : value);
      }
  /*
    Dither image.
  */
  scanline_pad=ximage->bytes_per_line-
    ((ximage->width*ximage->bits_per_pixel) >> 3);
  i=0;
  j=0;
  p=image->pixels;
  q=ximage->data;
  for (y=0; y < image->rows; y++)
  {
    for (x=0; x < image->columns; x++)
    {
      color.red=red_map[i][j][p->red];
      color.green=green_map[i][j][p->green];
      color.blue=blue_map[i][j][p->blue];
      pixel=(unsigned long) ((color.red & 0xe0) | ((color.green & 0xe0) >> 3) |
        ((color.blue & 0xc0) >> 6));
      *q++=(unsigned char) pixel;
      p++;
      j++;
      if (j == 16)
        j=0;
    }
    q+=scanline_pad;
    i++;
    if (i == 2)
      i=0;
  }
  /*
    Free allocated memory.
  */
  for (i=0; i < 2; i++)
    for (j=0; j < 16; j++)
    {
      free((char *) green_map[i][j]);
      free((char *) blue_map[i][j]);
      free((char *) red_map[i][j]);
    }
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X D r a w I m a g e                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XDrawImage draws a line on the image.
%
%  The format of the XDrawImage routine is:
%
%    status=XDrawImage(display,pixel_info,draw_info,image)
%
%  A description of each parameter follows:
%
%    o status: Function XDrawImage returns True if the image is
%      successfully drawd with text.  False is returned is there is a
%      memory shortage.
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o pixel_info: Specifies a pointer to a XPixelInfo structure.
%
%    o draw_info: Specifies a pointer to a XDrawInfo structure.
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%
*/
Export unsigned int XDrawImage(Display *display,const XPixelInfo *pixel_info,
  const XDrawInfo *draw_info,Image *image)
{
  GC
    draw_context;

  Image
    *draw_image;

  int
    x,
    y;

  Pixmap
    draw_pixmap;

  register int
    i;

  register RunlengthPacket
    *p,
    *q;

  unsigned int
    depth,
    height,
    matte,
    width;

  Window
    root_window;

  XGCValues
    context_values;

  XImage
    *draw_ximage;

  /*
    Initialize drawd image.
  */
  assert(display != (Display *) NULL);
  assert(pixel_info != (XPixelInfo *) NULL);
  assert(draw_info != (XDrawInfo *) NULL);
  assert(image != (Image *) NULL);
  if (!UncompressImage(image))
    return(False);
  /*
    Initialize drawd pixmap.
  */
  root_window=XRootWindow(display,XDefaultScreen(display));
  depth=XDefaultDepth(display,XDefaultScreen(display));
  draw_pixmap=XCreatePixmap(display,root_window,draw_info->width,
    draw_info->height,(int) depth);
  if (draw_pixmap == (Pixmap) NULL)
    return(False);
  /*
    Initialize graphics info.
  */
  context_values.background=(unsigned long) (~0);
  context_values.foreground=0;
  context_values.line_width=draw_info->line_width;
  draw_context=XCreateGC(display,root_window,GCBackground | GCForeground |
    GCLineWidth,&context_values);
  if (draw_context == (GC) NULL)
    return(False);
  /*
    Clear pixmap.
  */
  XFillRectangle(display,draw_pixmap,draw_context,0,0,draw_info->width,
    draw_info->height);
  /*
    Draw line to pixmap.
  */
  XSetBackground(display,draw_context,0);
  XSetForeground(display,draw_context,(unsigned long) (~0));
  XSetFillStyle(display,draw_context,FillOpaqueStippled);
  XSetStipple(display,draw_context,draw_info->stipple);
  switch (draw_info->primitive)
  {
    case PointPrimitive:
    default:
    {
      XDrawLines(display,draw_pixmap,draw_context,draw_info->coordinate_info,
        draw_info->number_coordinates,CoordModeOrigin);
      break;
    }
    case LinePrimitive:
    {
      XDrawLine(display,draw_pixmap,draw_context,draw_info->line_info.x1,
        draw_info->line_info.y1,draw_info->line_info.x2,
        draw_info->line_info.y2);
      break;
    }
    case RectanglePrimitive:
    {
      XDrawRectangle(display,draw_pixmap,draw_context,
        draw_info->rectangle_info.x,draw_info->rectangle_info.y,
        draw_info->rectangle_info.width,draw_info->rectangle_info.height);
      break;
    }
    case FillRectanglePrimitive:
    {
      XFillRectangle(display,draw_pixmap,draw_context,
        draw_info->rectangle_info.x,draw_info->rectangle_info.y,
        draw_info->rectangle_info.width,draw_info->rectangle_info.height);
      break;
    }
    case EllipsePrimitive:
    {
      XDrawArc(display,draw_pixmap,draw_context,
        draw_info->rectangle_info.x,draw_info->rectangle_info.y,
        draw_info->rectangle_info.width,draw_info->rectangle_info.height,
        0,360*64);
      break;
    }
    case FillEllipsePrimitive:
    {
      XFillArc(display,draw_pixmap,draw_context,
        draw_info->rectangle_info.x,draw_info->rectangle_info.y,
        draw_info->rectangle_info.width,draw_info->rectangle_info.height,
        0,360*64);
      break;
    }
    case PolygonPrimitive:
    {
      XPoint
        *coordinate_info;

      coordinate_info=draw_info->coordinate_info;
      XDrawLines(display,draw_pixmap,draw_context,coordinate_info,
        draw_info->number_coordinates,CoordModeOrigin);
      XDrawLine(display,draw_pixmap,draw_context,
        coordinate_info[draw_info->number_coordinates-1].x,
        coordinate_info[draw_info->number_coordinates-1].y,
        coordinate_info[0].x,coordinate_info[0].y);
      break;
    }
    case FillPolygonPrimitive:
    {
      XFillPolygon(display,draw_pixmap,draw_context,draw_info->coordinate_info,
        draw_info->number_coordinates,Complex,CoordModeOrigin);
      break;
    }
  }
  XFreeGC(display,draw_context);
  /*
    Initialize X image.
  */
  draw_ximage=XGetImage(display,draw_pixmap,0,0,draw_info->width,
    draw_info->height,AllPlanes,ZPixmap);
  if (draw_ximage == (XImage *) NULL)
    return(False);
  XFreePixmap(display,draw_pixmap);
  /*
    Initialize draw image.
  */
  draw_image=AllocateImage((ImageInfo *) NULL);
  if (draw_image == (Image *) NULL)
    return(False);
  draw_image->columns=draw_info->width;
  draw_image->rows=draw_info->height;
  draw_image->packets=draw_image->columns*draw_image->rows;
  draw_image->pixels=(RunlengthPacket *)
    malloc((unsigned int) image->packets*sizeof(RunlengthPacket));
  if (draw_image->pixels == (RunlengthPacket *) NULL)
    {
      DestroyImage(draw_image);
      return(False);
    }
  /*
    Transfer drawn X image to image.
  */
  (void) XParseGeometry(draw_info->geometry,&x,&y,&width,&height);
  q=image->pixels+y*image->columns+x;
  draw_image->background_color.red=q->red;
  draw_image->background_color.green=q->green;
  draw_image->background_color.blue=q->blue;
  draw_image->background_color.index=0;
  draw_image->matte=True;
  p=draw_image->pixels;
  for (y=0; y < draw_image->rows; y++)
    for (x=0; x < draw_image->columns; x++)
    {
      p->index=(unsigned short) XGetPixel(draw_ximage,x,y);
      if (p->index == 0)
        {
          /*
            Set this pixel to the background color.
          */
          p->red=draw_image->background_color.red;
          p->green=draw_image->background_color.green;
          p->blue=draw_image->background_color.blue;
          p->index=draw_info->stencil == OpaqueStencil ? Transparent : Opaque;
        }
      else
        {
          /*
            Set this pixel to the pen color.
          */
          p->red=XDownScale(pixel_info->pen_color.red);
          p->green=XDownScale(pixel_info->pen_color.green);
          p->blue=XDownScale(pixel_info->pen_color.blue);
          p->index=draw_info->stencil == OpaqueStencil ? Opaque : Transparent;
        }
      p->length=0;
      p++;
    }
  XDestroyImage(draw_ximage);
  /*
    Determine draw geometry.
  */
  (void) XParseGeometry(draw_info->geometry,&x,&y,&width,&height);
  if ((width != draw_image->columns) || (height != draw_image->rows))
    {
      char
        image_geometry[MaxTextExtent];

      /*
        Scale image.
      */
      (void) sprintf(image_geometry,"%ux%u",width,height);
      TransformImage(&draw_image,(char *) NULL,image_geometry);
    }
  if (draw_info->degrees != 0.0)
    {
      double
        normalized_degrees;

      Image
        *rotated_image;

      int
        rotations;

      /*
        Rotate image.
      */
      rotated_image=RotateImage(draw_image,draw_info->degrees,False,True);
      if (rotated_image == (Image *) NULL)
        return(False);
      DestroyImage(draw_image);
      draw_image=rotated_image;
      /*
        Annotation is relative to the degree of rotation.
      */
      normalized_degrees=draw_info->degrees;
      while (normalized_degrees < -45.0)
        normalized_degrees+=360.0;
      for (rotations=0; normalized_degrees > 45.0; rotations++)
        normalized_degrees-=90.0;
      switch (rotations % 4)
      {
        default:
        case 0:
          break;
        case 1:
        {
          /*
            Rotate 90 degrees.
          */
          x-=draw_image->columns >> 1;
          y+=draw_image->columns >> 1;
          break;
        }
        case 2:
        {
          /*
            Rotate 180 degrees.
          */
          x-=draw_image->columns;
          break;
        }
        case 3:
        {
          /*
            Rotate 270 degrees.
          */
          x-=draw_image->columns >> 1;
          y-=draw_image->rows-(draw_image->columns >> 1);
          break;
        }
      }
    }
  /*
    Composite text onto the image.
  */
  p=draw_image->pixels;
  for (i=0; i < draw_image->packets; i++)
  {
    if (p->index != Transparent)
      p->index=Opaque;
    p++;
  }
  if (draw_info->stencil == TransparentStencil)
    CompositeImage(image,MatteReplaceCompositeOp,draw_image,x,y);
  else
    {
      matte=image->matte;
      CompositeImage(image,OverCompositeOp,draw_image,x,y);
      image->matte=matte;
    }
  DestroyImage(draw_image);
  return(True);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X E r r o r                                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XError ignores BadWindow errors for XQueryTree and
%  XGetWindowAttributes, and ignores BadDrawable errors for XGetGeometry, and
%  ignores BadValue errors for XQueryColor.  It returns False in those cases.
%  Otherwise it returns True.
%
%  The format of the XError function is:
%
%      XError(display,error)
%
%  A description of each parameter follows:
%
%    o display: Specifies a pointer to the Display structure;  returned from
%      XOpenDisplay.
%
%    o error: Specifies the error event.
%
%
*/
Export int XError(Display *display,XErrorEvent *error)
{
  assert(display != (Display *) NULL);
  assert(error != (XErrorEvent *) NULL);
  xerror_alert=True;
  switch (error->request_code)
  {
    case X_GetGeometry:
    {
      if (error->error_code == BadDrawable)
        return(False);
      break;
    }
    case X_GetWindowAttributes:
    case X_QueryTree:
    {
      if (error->error_code == BadWindow)
        return(False);
      break;
    }
    case X_QueryColors:
    {
      if (error->error_code == BadValue)
        return(False);
      break;
    }
  }
  return(True);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X F r e e R e s o u r c e s                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XFreeResources frees X11 resources.
%
%  The format of the XFreeResources routine is:
%
%      XFreeResources(display,visual_info,map_info,pixel_info,font_info,
%        resource_info,window_info)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
%      returned from XGetVisualInfo.
%
%    o map_info: If map_type is specified, this structure is initialized
%      with info from the Standard Colormap.
%
%    o pixel_info: Specifies a pointer to a XPixelInfo structure.
%
%    o font_info: Specifies a pointer to a XFontStruct structure.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
%
%
*/
void XFreeResources(Display *display,XVisualInfo *visual_info,
  XStandardColormap *map_info,XPixelInfo *pixel_info,XFontStruct *font_info,
  XResourceInfo *resource_info,XWindowInfo *window_info)
{
  assert(display != (Display *) NULL);
  assert(resource_info != (XResourceInfo *) NULL);
  if (window_info != (XWindowInfo *) NULL)
    {
      /*
        Free X image.
      */
      if (window_info->ximage != (XImage *) NULL)
        XDestroyImage(window_info->ximage);
      if (window_info->id != (Window) NULL)
        {
          /*
            Free destroy window and free cursors.
          */
          if (window_info->id != XRootWindow(display,visual_info->screen))
            XDestroyWindow(display,window_info->id);
          if (window_info->annotate_context != (GC) NULL)
            XFreeGC(display,window_info->annotate_context);
          if (window_info->highlight_context != (GC) NULL)
            XFreeGC(display,window_info->highlight_context);
          if (window_info->widget_context != (GC) NULL)
            XFreeGC(display,window_info->widget_context);
          XFreeCursor(display,window_info->cursor);
          XFreeCursor(display,window_info->busy_cursor);
        }
    }
  /*
    Free font.
  */
  if (font_info != (XFontStruct *) NULL)
    XFreeFont(display,font_info);
  if (map_info != (XStandardColormap *) NULL)
    {
      /*
        Free X Standard Colormap.
      */
      if (resource_info->map_type == (char *) NULL)
        XFreeStandardColormap(display,visual_info,map_info,pixel_info);
      XFree((void *) map_info);
    }
  /*
    Free X visual info.
  */
  if (visual_info != (XVisualInfo *) NULL)
    XFree((void *) visual_info);
  if (resource_info->close_server)
    XCloseDisplay(display);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X F r e e S t a n d a r d C o l o r m a p                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XFreeStandardColormap frees an X11 colormap.
%
%  The format of the XFreeStandardColormap routine is:
%
%      XFreeStandardColormap(display,visual_info,map_info,pixel_info)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
%      returned from XGetVisualInfo.
%
%    o map_info: If map_type is specified, this structure is initialized
%      with info from the Standard Colormap.
%
%    o pixel_info: Specifies a pointer to a XPixelInfo structure.
%
%
*/
Export void XFreeStandardColormap(Display *display,
  const XVisualInfo *visual_info,XStandardColormap *map_info,
  XPixelInfo *pixel_info)
{
  /*
    Free colormap.
  */
  assert(display != (Display *) NULL);
  assert(visual_info != (XVisualInfo *) NULL);
  assert(map_info != (XStandardColormap *) NULL);
  XFlush(display);
  if (map_info->colormap != (Colormap) NULL)
    if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
      XFreeColormap(display,map_info->colormap);
    else
      if (pixel_info != (XPixelInfo *) NULL)
        if ((visual_info->class != TrueColor) &&
            (visual_info->class != DirectColor))
          XFreeColors(display,map_info->colormap,pixel_info->pixels,
            (int) pixel_info->colors,0);
  map_info->colormap=(Colormap) NULL;
  if (pixel_info != (XPixelInfo *) NULL)
    {
      if (pixel_info->gamma_map != (XColor *) NULL)
        free((char *) pixel_info->gamma_map);
      pixel_info->gamma_map=(XColor *) NULL;
      if (pixel_info->pixels != (unsigned long *) NULL)
        free((char *) pixel_info->pixels);
      pixel_info->pixels=(unsigned long *) NULL;
    }
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t A n n o t a t e I n f o                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetAnnotateInfo initializes the AnnotateInfo structure.
%
%  The format of the GetAnnotateInfo routine is:
%
%      XGetAnnotateInfo(annotate_info)
%
%  A description of each parameter follows:
%
%    o annotate_info: Specifies a pointer to a XAnnotateInfo structure.
%
%
*/
Export void XGetAnnotateInfo(XAnnotateInfo *annotate_info)
{
  /*
    Initialize annotate structure.
  */
  assert(annotate_info != (XAnnotateInfo *) NULL);
  annotate_info->x=0;
  annotate_info->y=0;
  annotate_info->width=0;
  annotate_info->height=0;
  annotate_info->stencil=ForegroundStencil;
  annotate_info->degrees=0.0;
  annotate_info->font_info=(XFontStruct *) NULL;
  annotate_info->text=(char *) NULL;
  *annotate_info->geometry='\0';
  annotate_info->previous=(XAnnotateInfo *) NULL;
  annotate_info->next=(XAnnotateInfo *) NULL;
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t M a p I n f o                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetMapInfo initializes the XStandardColormap structure.
%
%  The format of the XStandardColormap routine is:
%
%      XGetMapInfo(visual_info,colormap,map_info)
%
%  A description of each parameter follows:
%
%    o colormap: Specifies the ID of the X server colormap.
%
%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
%      returned from XGetVisualInfo.
%
%    o map_info: Specifies a pointer to a X11 XStandardColormap structure.
%
%
*/
void XGetMapInfo(const XVisualInfo *visual_info,const Colormap colormap,
  XStandardColormap *map_info)
{
  /*
    Initialize map info.
  */
  assert(visual_info != (XVisualInfo *) NULL);
  assert(map_info != (XStandardColormap *) NULL);
  map_info->colormap=colormap;
  map_info->red_max=visual_info->red_mask;
  map_info->red_mult=map_info->red_max != 0 ? 1 : 0;
  if (map_info->red_max != 0)
    while ((map_info->red_max & 0x01) == 0)
    {
      map_info->red_max>>=1;
      map_info->red_mult<<=1;
    }
  map_info->green_max=visual_info->green_mask;
  map_info->green_mult=map_info->green_max != 0 ? 1 : 0;
  if (map_info->green_max != 0)
    while ((map_info->green_max & 0x01) == 0)
    {
      map_info->green_max>>=1;
      map_info->green_mult<<=1;
    }
  map_info->blue_max=visual_info->blue_mask;
  map_info->blue_mult=map_info->blue_max != 0 ? 1 : 0;
  if (map_info->blue_max != 0)
    while ((map_info->blue_max & 0x01) == 0)
    {
      map_info->blue_max>>=1;
      map_info->blue_mult<<=1;
    }
  map_info->base_pixel=0;
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t M o n t a g e I n f o                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetMontageInfo initializes the MontageInfo structure.
%
%  The format of the GetMontageInfo routine is:
%
%      XGetMontageInfo(montage_info)
%
%  A description of each parameter follows:
%
%    o montage_info: Specifies a pointer to a MontageInfo structure.
%
%
*/
Export void XGetMontageInfo(XMontageInfo *montage_info)
{
  assert(montage_info != (XMontageInfo *) NULL);
  *montage_info->filename='\0';
  montage_info->shadow=False;
  montage_info->compose=ReplaceCompositeOp;
  montage_info->pointsize=atoi(DefaultPointSize);
  montage_info->frame=(char *) NULL;
  montage_info->tile=(char *) malloc(MaxTextExtent*sizeof(char));
  if (montage_info->tile != (char *) NULL)
    (void) strcpy(montage_info->tile,DefaultTilePageGeometry);
  montage_info->texture=(char *) NULL;
  montage_info->filter=MitchellFilter;
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t P i x e l I n f o                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetPixelInfo initializes the PixelInfo structure.
%
%  The format of the XGetPixelInfo routine is:
%
%      XGetPixelInfo(display,visual_info,map_info,resource_info,image,
%        pixel_info)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
%      returned from XGetVisualInfo.
%
%    o map_info: If map_type is specified, this structure is initialized
%      with info from the Standard Colormap.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%    o pixel_info: Specifies a pointer to a XPixelInfo structure.
%
%
*/
Export void XGetPixelInfo(Display *display,const XVisualInfo *visual_info,
  const XStandardColormap *map_info,const XResourceInfo *resource_info,
  Image *image,XPixelInfo *pixel_info)
{
  static char
    *PenColors[MaxNumberPens]=
    {
      Pen1Color,
      Pen2Color,
      Pen3Color,
      Pen4Color,
      Pen5Color,
      Pen6Color,
      Pen7Color,
      Pen8Color,
      Pen9Color,
      Pen0Color,
      Pen0Color
    };

  Colormap
    colormap;

  int
    status;

  register int
    i;

  unsigned int
    packets;

  /*
    Initialize pixel info.
  */
  assert(display != (Display *) NULL);
  assert(visual_info != (XVisualInfo *) NULL);
  assert(map_info != (XStandardColormap *) NULL);
  assert(resource_info != (XResourceInfo *) NULL);
  assert(pixel_info != (XPixelInfo *) NULL);
  pixel_info->colors=0;
  if (image != (Image *) NULL)
    if (image->class == PseudoClass)
      pixel_info->colors=image->colors;
  packets=Max(pixel_info->colors,visual_info->colormap_size)+MaxNumberPens;
  if (pixel_info->pixels != (unsigned long *) NULL)
    free((char *) pixel_info->pixels);
  pixel_info->pixels=(unsigned long *) malloc(packets*sizeof(unsigned long));
  if (pixel_info->pixels == (unsigned long *) NULL)
    Error("Unable to get pixel info","Memory allocation failed");
  /*
    Set foreground color.
  */
  colormap=map_info->colormap;
  (void) XParseColor(display,colormap,ForegroundColor,
    &pixel_info->foreground_color);
  status=XParseColor(display,colormap,resource_info->foreground_color,
    &pixel_info->foreground_color);
  if (status == 0)
    Warning("Color is not known to X server",resource_info->foreground_color);
  pixel_info->foreground_color.pixel=
    XStandardPixel(map_info,pixel_info->foreground_color,16);
  pixel_info->foreground_color.flags=DoRed | DoGreen | DoBlue;
  /*
    Set background color.
  */
  (void) XParseColor(display,colormap,BackgroundColor,
    &pixel_info->background_color);
  status=XParseColor(display,colormap,resource_info->background_color,
    &pixel_info->background_color);
  if (status == 0)
    Warning("Color is not known to X server",resource_info->background_color);
  pixel_info->background_color.pixel=
    XStandardPixel(map_info,pixel_info->background_color,16);
  pixel_info->background_color.flags=DoRed | DoGreen | DoBlue;
  /*
    Set border color.
  */
  (void) XParseColor(display,colormap,BorderColor,&pixel_info->border_color);
  status=XParseColor(display,colormap,resource_info->border_color,
    &pixel_info->border_color);
  if (status == 0)
    Warning("Color is not known to X server",resource_info->border_color);
  pixel_info->border_color.pixel=
    XStandardPixel(map_info,pixel_info->border_color,16);
  pixel_info->border_color.flags=DoRed | DoGreen | DoBlue;
  /*
    Set matte color.
  */
  pixel_info->matte_color=pixel_info->background_color;
  if (resource_info->matte_color != (char *) NULL)
    {
      /*
        Matte color is specified as a X resource or command line argument.
      */
      status=XParseColor(display,colormap,resource_info->matte_color,
        &pixel_info->matte_color);
      if (status == 0)
        Warning("Color is not known to X server",resource_info->matte_color);
      pixel_info->matte_color.pixel=
        XStandardPixel(map_info,pixel_info->matte_color,16);
      pixel_info->matte_color.flags=DoRed | DoGreen | DoBlue;
    }
  /*
    Set highlight color.
  */
  pixel_info->highlight_color.red=(unsigned int) (pixel_info->matte_color.red*
    HighlightModulate+(MaxRGB-HighlightModulate)*65535L)/MaxRGB;
  pixel_info->highlight_color.green=(unsigned int)
    (pixel_info->matte_color.green*HighlightModulate+
    (MaxRGB-HighlightModulate)*65535L)/MaxRGB;
  pixel_info->highlight_color.blue=(unsigned int) (pixel_info->matte_color.blue*
    HighlightModulate+(MaxRGB-HighlightModulate)*65535L)/MaxRGB;
  pixel_info->highlight_color.pixel=
    XStandardPixel(map_info,pixel_info->highlight_color,16);
  pixel_info->highlight_color.flags=DoRed | DoGreen | DoBlue;
  /*
    Set shadow color.
  */
  pixel_info->shadow_color.red=(unsigned int)
    (pixel_info->matte_color.red*ShadowModulate)/MaxRGB;
  pixel_info->shadow_color.green=(unsigned int)
    (pixel_info->matte_color.green*ShadowModulate)/MaxRGB;
  pixel_info->shadow_color.blue=(unsigned int)
    (pixel_info->matte_color.blue*ShadowModulate)/MaxRGB;
  pixel_info->shadow_color.pixel=
    XStandardPixel(map_info,pixel_info->shadow_color,16);
  pixel_info->shadow_color.flags=DoRed | DoGreen | DoBlue;
  /*
    Set depth color.
  */
  pixel_info->depth_color.red=(unsigned int)
    (pixel_info->matte_color.red*DepthModulate)/MaxRGB;
  pixel_info->depth_color.green=(unsigned int)
    (pixel_info->matte_color.green*DepthModulate)/MaxRGB;
  pixel_info->depth_color.blue=(unsigned int)
    (pixel_info->matte_color.blue*DepthModulate)/MaxRGB;
  pixel_info->depth_color.pixel=
    XStandardPixel(map_info,pixel_info->depth_color,16);
  pixel_info->depth_color.flags=DoRed | DoGreen | DoBlue;
  /*
    Set trough color.
  */
  pixel_info->trough_color.red=(unsigned int)
    (pixel_info->matte_color.red*TroughModulate)/MaxRGB;
  pixel_info->trough_color.green=(unsigned int)
    (pixel_info->matte_color.green*TroughModulate)/MaxRGB;
  pixel_info->trough_color.blue=(unsigned int)
    (pixel_info->matte_color.blue*TroughModulate)/MaxRGB;
  pixel_info->trough_color.pixel=
    XStandardPixel(map_info,pixel_info->trough_color,16);
  pixel_info->trough_color.flags=DoRed | DoGreen | DoBlue;
  /*
    Set pen color.
  */
  for (i=0; i < MaxNumberPens; i++)
  {
    (void) XParseColor(display,colormap,PenColors[i],
      &pixel_info->pen_colors[i]);
    status=XParseColor(display,colormap,resource_info->pen_colors[i],
      &pixel_info->pen_colors[i]);
    if (status == 0)
      Warning("Color is not known to X server",resource_info->pen_colors[i]);
    pixel_info->pen_colors[i].pixel=
      XStandardPixel(map_info,pixel_info->pen_colors[i],16);
    pixel_info->pen_colors[i].flags=DoRed | DoGreen | DoBlue;
  }
  pixel_info->box_color=pixel_info->background_color;
  pixel_info->pen_color=pixel_info->foreground_color;
  pixel_info->box_index=0;
  pixel_info->pen_index=1;
  /*
    Initialize gamma map to linear brightness.
  */
  if (pixel_info->gamma_map != (XColor *) NULL)
    free((char *) pixel_info->gamma_map);
  pixel_info->gamma_map=(XColor *) malloc((MaxRGB+1)*sizeof(XColor));
  if (pixel_info->gamma_map == (XColor *) NULL)
    Error("Unable to get pixel info","Memory allocation failed");
  for (i=0; i <= MaxRGB; i++)
  {
    pixel_info->gamma_map[i].red=i;
    pixel_info->gamma_map[i].green=i;
    pixel_info->gamma_map[i].blue=i;
  }
  if (image != (Image *) NULL)
    {
      if (resource_info->gamma_correct && (image->gamma != 0.0))
        {
          double
            blue_gamma,
            green_gamma,
            red_gamma;

          int
            count;

          /*
            Initialize map relative to display and image gamma.
          */
          red_gamma=1.0;
          green_gamma=1.0;
          blue_gamma=1.0;
          count=sscanf(resource_info->display_gamma,"%lf,%lf,%lf",
            &red_gamma,&green_gamma,&blue_gamma);
          if (count == 1)
            {
              green_gamma=red_gamma;
              blue_gamma=red_gamma;
            }
          red_gamma*=image->gamma;
          green_gamma*=image->gamma;
          blue_gamma*=image->gamma;
          for (i=0; i <= MaxRGB; i++)
          {
            pixel_info->gamma_map[i].red=(short unsigned int)
              ((pow((double) i/MaxRGB,1.0/red_gamma)*MaxRGB)+0.5);
            pixel_info->gamma_map[i].green=(short unsigned int)
              ((pow((double) i/MaxRGB,1.0/green_gamma)*MaxRGB)+0.5);
            pixel_info->gamma_map[i].blue=(short unsigned int)
              ((pow((double) i/MaxRGB,1.0/blue_gamma)*MaxRGB)+0.5);
          }
        }
      if (image->class == PseudoClass)
        {
          register XColor
            *gamma_map;

          /*
            Initialize pixel array for images of type PseudoClass.
          */
          gamma_map=pixel_info->gamma_map;
          for (i=0; i < image->colors; i++)
            pixel_info->pixels[i]=
              XGammaPixel(map_info,gamma_map,image->colormap+i,QuantumDepth);
          for (i=0; i < MaxNumberPens; i++)
            pixel_info->pixels[image->colors+i]=pixel_info->pen_colors[i].pixel;
          pixel_info->colors+=MaxNumberPens;
        }
    }
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t R e s o u r c e C l a s s                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetResourceClass queries the X server for the specified resource
%  name or class.  If the resource name or class is not defined in the
%  database, the supplied default value is returned.
%
%  The format of the XGetResourceClass routine is:
%
%      value=XGetResourceClass(database,client_name,keyword,resource_default)
%
%  A description of each parameter follows:
%
%    o value: Function XGetResourceClass returns the resource value associated
%      with the name or class.  If none is found, the supplied default value is
%      returned.
%
%    o database: Specifies a resource database; returned from
%      XrmGetStringDatabase.
%
%    o client_name:  Specifies the application name used to retrieve resource
%      info from the X server database.
%
%    o keyword: Specifies the keyword of the value being retrieved.
%
%    o resource_default: Specifies the default value to return if the query
%      fails to find the specified keyword/class.
%
%
*/
Export char *XGetResourceClass(XrmDatabase database,const char *client_name,
  const char *keyword,char *resource_default)
{
  char
    resource_class[MaxTextExtent],
    resource_name[MaxTextExtent];

  int
    status;

  static char
    *resource_type;

  XrmValue
    resource_value;

  if (database == (XrmDatabase) NULL)
    return(resource_default);
  *resource_name='\0';
  *resource_class='\0';
  if (keyword != (char *) NULL)
    {
      unsigned char
        c,
        k;

      /*
        Initialize resource keyword and class.
      */
      (void) sprintf(resource_name,"%s.%s",client_name,keyword);
      c=(*client_name);
      if ((c >= XK_a) && (c <= XK_z))
        c-=(XK_a-XK_A);
      else
        if ((c >= XK_agrave) && (c <= XK_odiaeresis))
          c-=(XK_agrave-XK_Agrave);
        else
          if ((c >= XK_oslash) && (c <= XK_thorn))
            c-=(XK_oslash-XK_Ooblique);
      k=(*keyword);
      if ((k >= XK_a) && (k <= XK_z))
        k-=(XK_a-XK_A);
      else
        if ((k >= XK_agrave) && (k <= XK_odiaeresis))
          k-=(XK_agrave-XK_Agrave);
        else
          if ((k >= XK_oslash) && (k <= XK_thorn))
            k-=(XK_oslash-XK_Ooblique);
      (void) sprintf(resource_class,"%c%s.%c%s",c,client_name+1,k,keyword+1);
    }
  status=XrmGetResource(database,resource_name,resource_class,&resource_type,
    &resource_value);
  if (status == False)
    return(resource_default);
  return(resource_value.addr);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t R e s o u r c e D a t a b a s e                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetResourceDatabase creates a new resource database and
%  initializes it.
%
%  The format of the XGetResourceDatabase routine is:
%
%      database=XGetResourceDatabase(display,client_name)
%
%  A description of each parameter follows:
%
%    o database: Function XGetResourceDatabase returns the database after
%      it is initialized.
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o client_name:  Specifies the application name used to retrieve resource
%      info from the X server database.
%
%
*/
Export XrmDatabase XGetResourceDatabase(Display *display,char *client_name)
{
  char
    filename[MaxTextExtent];

  register char
    *p;

  unsigned char
    c;

  XrmDatabase
    resource_database,
    server_database;

  if (display == (Display *) NULL)
    return((XrmDatabase) NULL);
  assert(client_name != (char *) NULL);
  /*
    Initialize resource database.
  */
  XrmInitialize();
  XGetDefault(display,client_name,"dummy");
  resource_database=XrmGetDatabase(display);
  /*
    Combine application database.
  */
  if (client_name != (char *) NULL)
    {
      /*
        Get basename of client.
      */
      p=client_name+(Extent(client_name)-1);
      while ((p > client_name) && (*p != '/'))
        p--;
      if (*p == '/')
        client_name=p+1;
    }
  c=(*client_name);
  if ((c >= XK_a) && (c <= XK_z))
    c-=(XK_a-XK_A);
  else
    if ((c >= XK_agrave) && (c <= XK_odiaeresis))
      c-=(XK_agrave-XK_Agrave);
    else
      if ((c >= XK_oslash) && (c <= XK_thorn))
        c-=(XK_oslash-XK_Ooblique);
  (void) sprintf(filename,"%s%c%s",ApplicationDefaults,c,client_name+1);
  XrmCombineFileDatabase(filename,&resource_database,False);
  if (XResourceManagerString(display) != (char *) NULL)
    {
      /*
        Combine server database.
      */
      server_database=XrmGetStringDatabase(XResourceManagerString(display));
      XrmCombineDatabase(server_database,&resource_database,False);
    }
  /*
    Merge user preferences database.
  */
  (void) sprintf(filename,"%s%src",PreferencesDefaults,client_name);
  ExpandFilename(filename);
  XrmCombineFileDatabase(filename,&resource_database,False);
  return(resource_database);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t R e s o u r c e I n f o                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetResourceInfo initializes the ResourceInfo structure.
%
%  The format of the XGetResourceInfo routine is:
%
%      XGetResourceInfo(database,client_name,resource_info)
%
%  A description of each parameter follows:
%
%    o database: Specifies a resource database; returned from
%      XrmGetStringDatabase.
%
%    o client_name:  Specifies the application name used to retrieve
%      resource info from the X server database.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%
*/
Export void XGetResourceInfo(XrmDatabase database,char *client_name,
  XResourceInfo *resource_info)
{
  char
    *resource_value;

  /*
    Initialize resource info fields.
  */
  assert(resource_info != (XResourceInfo *) NULL);
  resource_info->resource_database=database;
  resource_info->close_server=True;
  resource_info->client_name=client_name;
  resource_value=XGetResourceClass(database,client_name,"backdrop","False");
  resource_info->backdrop=IsTrue(resource_value);
  resource_info->background_color=XGetResourceInstance(database,client_name,
    "background",BackgroundColor);
  resource_info->border_color=XGetResourceInstance(database,client_name,
    "borderColor",BorderColor);
  resource_value=XGetResourceClass(database,client_name,"borderWidth","2");
  resource_info->border_width=atoi(resource_value);
  resource_info->browse_command=XGetResourceClass(database,client_name,
    "browseCommand",BrowseCommand);
  resource_value=XGetResourceClass(database,client_name,"colormap","shared");
  resource_info->colormap=UndefinedColormap;
  if (Latin1Compare("private",resource_value) == 0)
    resource_info->colormap=PrivateColormap;
  if (Latin1Compare("shared",resource_value) == 0)
    resource_info->colormap=SharedColormap;
  if (resource_info->colormap == UndefinedColormap)
    Warning("Unrecognized colormap type",resource_value);
  resource_value=
    XGetResourceClass(database,client_name,"colorRecovery","False");
  resource_info->color_recovery=IsTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"colorspace","rgb");
  resource_info->colorspace=UndefinedColorspace;
  if (Latin1Compare("gray",resource_value) == 0)
    resource_info->colorspace=GRAYColorspace;
  if (Latin1Compare("rgb",resource_value) == 0)
    resource_info->colorspace=RGBColorspace;
  if (Latin1Compare("ohta",resource_value) == 0)
    resource_info->colorspace=OHTAColorspace;
  if (Latin1Compare("xyz",resource_value) == 0)
    resource_info->colorspace=XYZColorspace;
  if (Latin1Compare("yiq",resource_value) == 0)
    resource_info->colorspace=YIQColorspace;
  if (Latin1Compare("yuv",resource_value) == 0)
    resource_info->colorspace=YUVColorspace;
  if (resource_info->colorspace == UndefinedColorspace)
    Warning("Unrecognized colorspace type",resource_value);
  resource_value=XGetResourceClass(database,client_name,"confirmExit","False");
  resource_info->confirm_exit=IsTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"debug","False");
  resource_info->debug=IsTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"delay","0");
  resource_info->delay=atoi(resource_value);
  resource_info->display_gamma=XGetResourceClass(database,client_name,
    "displayGamma",DefaultDisplayGamma);
  resource_value=
    XGetResourceClass(database,client_name,"displayWarnings","True");
  resource_info->display_warnings=IsTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"dither","True");
  resource_info->dither=IsTrue(resource_value);
  resource_info->editor_command=XGetResourceClass(database,client_name,
    "editorCommand",EditorCommand);
  resource_info->font=
    XGetResourceClass(database,client_name,"font",(char *) NULL);
  resource_info->font=XGetResourceClass(database,client_name,"fontList",
    resource_info->font);
  resource_info->font_name[0]=
    XGetResourceClass(database,client_name,"font1","fixed");
  resource_info->font_name[1]=
    XGetResourceClass(database,client_name,"font2","variable");
  resource_info->font_name[2]=
    XGetResourceClass(database,client_name,"font3","5x8");
  resource_info->font_name[3]=
    XGetResourceClass(database,client_name,"font4","6x10");
  resource_info->font_name[4]=
    XGetResourceClass(database,client_name,"font5","7x13bold");
  resource_info->font_name[5]=
    XGetResourceClass(database,client_name,"font6","8x13bold");
  resource_info->font_name[6]=
    XGetResourceClass(database,client_name,"font7","9x15bold");
  resource_info->font_name[7]=
    XGetResourceClass(database,client_name,"font8","10x20");
  resource_info->font_name[8]=
    XGetResourceClass(database,client_name,"font9","12x24");
  resource_info->font_name[9]=
    XGetResourceClass(database,client_name,"font0","fixed");
  resource_info->font_name[10]=
    XGetResourceClass(database,client_name,"font0","fixed");
  resource_info->foreground_color=XGetResourceInstance(database,client_name,
    "foreground",ForegroundColor);
  resource_value=XGetResourceClass(database,client_name,"gammaCorrect","True");
  resource_info->gamma_correct=IsTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"gravity","South");
  resource_info->gravity=(-1);
  if (Latin1Compare("Forget",resource_value) == 0)
    resource_info->gravity=ForgetGravity;
  if (Latin1Compare("NorthWest",resource_value) == 0)
    resource_info->gravity=NorthWestGravity;
  if (Latin1Compare("North",resource_value) == 0)
    resource_info->gravity=NorthGravity;
  if (Latin1Compare("NorthEast",resource_value) == 0)
    resource_info->gravity=NorthEastGravity;
  if (Latin1Compare("West",resource_value) == 0)
    resource_info->gravity=WestGravity;
  if (Latin1Compare("Center",resource_value) == 0)
    resource_info->gravity=CenterGravity;
  if (Latin1Compare("East",resource_value) == 0)
    resource_info->gravity=EastGravity;
  if (Latin1Compare("SouthWest",resource_value) == 0)
    resource_info->gravity=SouthWestGravity;
  if (Latin1Compare("South",resource_value) == 0)
    resource_info->gravity=SouthGravity;
  if (Latin1Compare("SouthEast",resource_value) == 0)
    resource_info->gravity=SouthEastGravity;
  if (Latin1Compare("Static",resource_value) == 0)
    resource_info->gravity=StaticGravity;
  if (resource_info->gravity == (-1))
    {
      Warning("Unrecognized gravity type",resource_value);
      resource_info->gravity=CenterGravity;
    }
  getwd(resource_info->home_directory);
  resource_info->icon_geometry=XGetResourceClass(database,client_name,
    "iconGeometry",(char *) NULL);
  resource_value=XGetResourceClass(database,client_name,"iconic","False");
  resource_info->iconic=IsTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"immutable","False");
  resource_info->immutable=IsTrue(resource_value);
  resource_info->image_geometry=XGetResourceClass(database,client_name,
    "geometry",(char *) NULL);
  resource_info->launch_command=XGetResourceClass(database,client_name,
    "launchCommand",LauncherCommand);
  resource_value=XGetResourceClass(database,client_name,"magnify","3");
  resource_info->magnify=atoi(resource_value);
  resource_info->map_type=
    XGetResourceClass(database,client_name,"map",(char *) NULL);
  resource_info->matte_color=XGetResourceInstance(database,client_name,
    "mattecolor",(char *) NULL);
  resource_value=XGetResourceClass(database,client_name,"monochrome","False");
  resource_info->monochrome=IsTrue(resource_value);
  resource_info->name=
    XGetResourceClass(database,client_name,"name",(char *) NULL);
  resource_value=XGetResourceClass(database,client_name,"colors","0");
  resource_info->number_colors=atoi(resource_value);
  resource_info->pen_colors[0]=
    XGetResourceClass(database,client_name,"pen1","black");
  resource_info->pen_colors[1]=
    XGetResourceClass(database,client_name,"pen2","blue");
  resource_info->pen_colors[2]=
    XGetResourceClass(database,client_name,"pen3","cyan");
  resource_info->pen_colors[3]=
    XGetResourceClass(database,client_name,"pen4","green");
  resource_info->pen_colors[4]=
    XGetResourceClass(database,client_name,"pen5","gray");
  resource_info->pen_colors[5]=
    XGetResourceClass(database,client_name,"pen6","red");
  resource_info->pen_colors[6]=
    XGetResourceClass(database,client_name,"pen7","magenta");
  resource_info->pen_colors[7]=
    XGetResourceClass(database,client_name,"pen8","yellow");
  resource_info->pen_colors[8]=
    XGetResourceClass(database,client_name,"pen9","white");
  resource_info->pen_colors[9]=
    XGetResourceClass(database,client_name,"pen0","gray");
  resource_info->pen_colors[10]=
    XGetResourceClass(database,client_name,"pen0","gray");
  resource_info->print_command=XGetResourceClass(database,client_name,
    "printCommand",PrinterCommand);
  resource_value=XGetResourceClass(database,client_name,"quantum","1");
  resource_info->quantum=atoi(resource_value);
  resource_info->server_name=
    XGetResourceClass(database,client_name,"serverName",(char *) NULL);
  resource_info->text_font=
    XGetResourceClass(database,client_name,"font",(char *) NULL);
  resource_info->text_font=XGetResourceClass(database,client_name,
    "textFontList",resource_info->text_font);
  resource_info->title=
    XGetResourceClass(database,client_name,"title",(char *) NULL);
  resource_value=XGetResourceClass(database,client_name,"treeDepth","0");
  resource_info->tree_depth=atoi(resource_value);
  resource_value=XGetResourceClass(database,client_name,"undoCache",UndoCache);
  resource_info->undo_cache=atoi(resource_value);
  resource_value=XGetResourceClass(database,client_name,"update","False");
  resource_info->update=IsTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"usePixmap","False");
  resource_info->use_pixmap=IsTrue(resource_value);
  resource_value= XGetResourceClass(database,client_name,"sharedMemory","True");
  resource_info->use_shared_memory=IsTrue(resource_value);
  resource_info->visual_type=
    XGetResourceClass(database,client_name,"visual",(char *) NULL);
  resource_info->window_group=XGetResourceClass(database,client_name,
    "windowGroup",(char *) NULL);
  resource_info->window_id=
    XGetResourceClass(database,client_name,"window",(char *) NULL);
  resource_info->write_filename=XGetResourceClass(database,client_name,
    "writeFilename",(char *) NULL);
  /*
    Handle side-effects.
  */
  if (resource_info->monochrome)
    {
      resource_info->number_colors=2;
      resource_info->tree_depth=8;
      resource_info->dither=True;
      resource_info->colorspace=GRAYColorspace;
    }
  if (resource_info->colorspace == GRAYColorspace)
    {
      resource_info->number_colors=256;
      resource_info->tree_depth=8;
    }
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t R e s o u r c e I n s t a n c e                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetResourceInstance queries the X server for the specified
%  resource name.  If the resource name is not defined in the database, the
%  supplied default value is returned.
%
%  The format of the XGetResourceInstance routine is:
%
%      value=XGetResourceInstance(database,client_name,keyword,resource_default)
%
%  A description of each parameter follows:
%
%    o value: Function XGetResourceInstance returns the resource value
%      associated with the name or class.  If none is found, the supplied
%      default value is returned.
%
%    o database: Specifies a resource database; returned from
%      XrmGetStringDatabase.
%
%    o client_name:  Specifies the application name used to retrieve
%      resource info from the X server database.
%
%    o keyword: Specifies the keyword of the value being retrieved.
%
%    o resource_default: Specifies the default value to return if the query
%      fails to find the specified keyword/class.
%
%
*/
Export char *XGetResourceInstance(XrmDatabase database,const char *client_name,
  const char *keyword,char *resource_default)
{
  char
    *resource_type,
    resource_name[MaxTextExtent];

  int
    status;

  XrmValue
    resource_value;

  if (database == (XrmDatabase) NULL)
    return(resource_default);
  *resource_name='\0';
  if (keyword != (char *) NULL)
    (void) sprintf(resource_name,"%s.%s",client_name,keyword);
  status=XrmGetResource(database,resource_name,"ImageMagick",&resource_type,
    &resource_value);
  if (status == False)
    return(resource_default);
  return(resource_value.addr);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t S u b w i n d o w                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetSubwindow returns the subwindow of a window choosen the
%  user with the pointer and a button press.
%
%  The format of the XGetSubwindow routine is:
%
%      subwindow=XGetSubwindow(display,window,x,y)
%
%  A description of each parameter follows:
%
%    o subwindow: Function XGetSubwindow returns NULL if no subwindow is found
%      otherwise the subwindow is returned.
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a Window.
%
%    o x: the x coordinate of the pointer relative to the origin of the
%      window.
%
%    o y: the y coordinate of the pointer relative to the origin of the
%      window.
%
%
*/
Window XGetSubwindow(Display *display,Window window,int x,int y)
{
  Window
    source_window,
    target_window;

  int
    status,
    x_offset,
    y_offset;

  assert(display != (Display *) NULL);
  source_window=XRootWindow(display,XDefaultScreen(display));
  if (window == (Window) NULL)
    return(source_window);
  target_window=window;
  for ( ; ; )
  {
    status=XTranslateCoordinates(display,source_window,window,x,y,
      &x_offset,&y_offset,&target_window);
    if (status != True)
      break;
    if (target_window == (Window) NULL)
      break;
    source_window=window;
    window=target_window;
    x=x_offset;
    y=y_offset;
  }
  if (target_window == (Window) NULL)
    target_window=window;
  return(target_window);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t W i n d o w C o l o r                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetWindowColor returns the color of a pixel interactively choosen
%  from the X server.
%
%  The format of the XGetWindowColor routine is:
%
%      status=XGetWindowColor(display,name)
%
%  A description of each parameter follows:
%
%    o status: Function XGetWindowColor returns True if the color is obtained
%      from the X server.  False is returned if any errors occurs.
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o name: The name of of the color if found in the X Color Database is
%      returned in this character string.
%
%
*/
unsigned int XGetWindowColor(Display *display,char *name)
{
  FILE
    *database;

  int
    x,
    y;

  RectangleInfo
    crop_info;

  unsigned int
    status;

  Window
    child,
    client_window,
    root_window,
    target_window;

  XColor
    color;

  XImage
    *ximage;

  XWindowAttributes
    window_attributes;

  /*
    Choose a pixel from the X server.
  */
  assert(display != (Display *) NULL);
  assert(name != (char *) NULL);
  target_window=XSelectWindow(display,&crop_info);
  root_window=XRootWindow(display,XDefaultScreen(display));
  client_window=target_window;
  if (target_window != root_window)
    {
      unsigned int
        d;

      /*
        Get client window.
      */
      status=XGetGeometry(display,target_window,&root_window,&x,&x,&d,&d,&d,&d);
      if (status != 0)
        {
          client_window=XClientWindow(display,target_window);
          target_window=client_window;
        }
    }
  /*
    Verify window is viewable.
  */
  status=XGetWindowAttributes(display,target_window,&window_attributes);
  if ((status == False) || (window_attributes.map_state != IsViewable))
    return(False);
  /*
    Get window X image.
  */
  XTranslateCoordinates(display,root_window,target_window,crop_info.x,
    crop_info.y,&x,&y,&child);
  ximage=XGetImage(display,target_window,x,y,1,1,AllPlanes,ZPixmap);
  if (ximage == (XImage *) NULL)
    return(False);
  color.pixel=XGetPixel(ximage,0,0);
  XDestroyImage(ximage);
  /*
    Query X server for pixel color.
  */
  XQueryColor(display,window_attributes.colormap,&color);
  (void) sprintf(name,"#%02x%02x%02x",XDownScale(color.red),
    XDownScale(color.green),XDownScale(color.blue));
  database=fopen(RGBColorDatabase,"r");
  if (database != (FILE *) NULL)
    {
      char
        colorname[MaxTextExtent],
        text[MaxTextExtent];

      int
        blue,
        count,
        green,
        red;

      /*
        Match color against the X color database.
      */
      while (fgets(text,MaxTextExtent,database) != (char *) NULL)
      {
        count=sscanf(text,"%d %d %d %[^\n]\n",&red,&green,&blue,colorname);
        if (count != 4)
          continue;
        if ((red == XDownScale(color.red)) &&
            (green == XDownScale(color.green)) &&
            (blue == XDownScale(color.blue)))
          {
            (void) strcpy(name,colorname);
            break;
          }
      }
      (void) fclose(database);
    }
  return(True);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t W i n d o w I m a g e                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetWindowImage reads an image from the target X window and returns
%  it.  XGetWindowImage optionally descends the window hierarchy and overlays
%  the target image with each subwindow image.
%
%  The format of the XGetWindowImage routine is:
%
%      image=XGetWindowImage(display,window,borders,level)
%
%  A description of each parameter follows:
%
%    o image: Function XGetWindowImage returns a MIFF image if it can be
%      successfully read from the X window.  A null image is returned if
%      any errors occurs.
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o window: Specifies the window to obtain the image from.
%
%    o borders: Specifies whether borders pixels are to be saved with
%      the image.
%
%    o level: Specifies an unsigned integer representing the level of
%      decent in the window hierarchy.  This value must be zero or one on
%      the initial call to XGetWindowImage.  A value of zero returns after
%      one call.  A value of one causes the function to descend the window
%      hierarchy and overlays the target image with each subwindow image.
%
%
*/
Image *XGetWindowImage(Display *display,const Window window,
  const unsigned int borders,const unsigned int level)
{
#define LoadImageText  "  Loading image...  "

  typedef struct _ColormapList
  {
    Colormap
      colormap;

    XColor
      *colors;

    struct _ColormapList
      *next;
  } ColormapList;

  GC
    annotate_context;

  Image
    *image;

  int
    display_height,
    display_width,
    number_colors,
    status,
    x_offset,
    y_offset;

  RectangleInfo
    crop_info;

  register int
    i,
    x,
    y;

  register RunlengthPacket
    *p;

  register unsigned long
    pixel;

  static ColormapList
    *colormap_list = (ColormapList *) NULL;

  Window
    child,
    root_window;

  XColor
    *colors;

  XGCValues
    context_values;

  XImage
    *ximage;

  XWindowAttributes
    window_attributes;

  /*
    Verify window is viewable.
  */
  assert(display != (Display *) NULL);
  status=XGetWindowAttributes(display,window,&window_attributes);
  if ((status == False) || (window_attributes.map_state != IsViewable))
    return((Image *) NULL);
  /*
    Cropping rectangle is relative to root window.
  */
  root_window=XRootWindow(display,XDefaultScreen(display));
  XTranslateCoordinates(display,window,root_window,0,0,&x_offset,&y_offset,
    &child);
  crop_info.x=x_offset;
  crop_info.y=y_offset;
  crop_info.width=window_attributes.width;
  crop_info.height=window_attributes.height;
  if (borders)
    {
      /*
        Include border in image.
      */
      crop_info.x-=window_attributes.border_width;
      crop_info.y-=window_attributes.border_width;
      crop_info.width+=window_attributes.border_width << 1;
      crop_info.height+=window_attributes.border_width << 1;
    }
  /*
    Crop to root window.
  */
  if (crop_info.x < 0)
    {
      if ((crop_info.x+(int) crop_info.width) < 0)
        return((Image *) NULL);
      crop_info.width+=crop_info.x;
      crop_info.x=0;
    }
  if (crop_info.y < 0)
    {
      if ((crop_info.y+(int) crop_info.height) < 0)
        return((Image *) NULL);
      crop_info.height+=crop_info.y;
      crop_info.y=0;
    }
  display_width=XDisplayWidth(display,XDefaultScreen(display));
  if ((crop_info.x+(int) crop_info.width) > display_width)
    {
      if (crop_info.x >= display_width)
        return((Image *) NULL);
      crop_info.width=display_width-crop_info.x;
    }
  display_height=XDisplayHeight(display,XDefaultScreen(display));
  if ((crop_info.y+(int) crop_info.height) > display_height)
    {
      if (crop_info.y >= display_height)
        return((Image *) NULL);
      crop_info.height=display_height-crop_info.y;
    }
  crop_info.x-=x_offset;
  crop_info.y-=y_offset;
  /*
    Alert user we are about to get an X region by flashing a border.
  */
  context_values.background=XBlackPixel(display,XDefaultScreen(display));
  context_values.foreground=XWhitePixel(display,XDefaultScreen(display));
  context_values.function=GXinvert;
  context_values.plane_mask=
    context_values.background ^ context_values.foreground;
  context_values.subwindow_mode=IncludeInferiors;
  annotate_context=XCreateGC(display,window,GCBackground | GCForeground |
    GCFunction | GCPlaneMask | GCSubwindowMode,&context_values);
  if (annotate_context != (GC) NULL)
    {
      XHighlightRectangle(display,window,annotate_context,&crop_info);
      XDelay(display,(unsigned long) (SuspendTime << 2));
      XHighlightRectangle(display,window,annotate_context,&crop_info);
    }
  /*
    Get window X image.
  */
  ximage=XGetImage(display,window,crop_info.x,crop_info.y,crop_info.width,
    crop_info.height,AllPlanes,ZPixmap);
  if (ximage == (XImage *) NULL)
    return((Image *) NULL);
  number_colors=0;
  colors=(XColor *) NULL;
  if (window_attributes.colormap != (Colormap) NULL)
    {
      ColormapList
        *p;

      /*
        Search colormap list for window colormap.
      */
      number_colors=window_attributes.visual->map_entries;
      for (p=colormap_list; p != (ColormapList *) NULL; p=p->next)
        if (p->colormap == window_attributes.colormap)
          break;
      if (p == (ColormapList *) NULL)
        {
          /*
            Get the window colormap.
          */
          colors=(XColor *) malloc(number_colors*sizeof(XColor));
          if (colors == (XColor *) NULL)
            {
              XDestroyImage(ximage);
              return((Image *) NULL);
            }
          if ((window_attributes.visual->class != DirectColor) &&
              (window_attributes.visual->class != TrueColor))
            for (i=0; i < number_colors; i++)
            {
              colors[i].pixel=i;
              colors[i].pad=0;
            }
          else
            {
              unsigned long
                blue,
                blue_bit,
                green,
                green_bit,
                red,
                red_bit;

              /*
                DirectColor or TrueColor visual.
              */
              red=0;
              green=0;
              blue=0;
              red_bit=window_attributes.visual->red_mask &
                (~(window_attributes.visual->red_mask)+1);
              green_bit=window_attributes.visual->green_mask &
                (~(window_attributes.visual->green_mask)+1);
              blue_bit=window_attributes.visual->blue_mask &
                (~(window_attributes.visual->blue_mask)+1);
              for (i=0; i < number_colors; i++)
              {
                colors[i].pixel=red | green | blue;
                colors[i].pad=0;
                red+=red_bit;
                if (red > window_attributes.visual->red_mask)
                  red=0;
                green+=green_bit;
                if (green > window_attributes.visual->green_mask)
                  green=0;
                blue+=blue_bit;
                if (blue > window_attributes.visual->blue_mask)
                  blue=0;
              }
            }
          XQueryColors(display,window_attributes.colormap,colors,
           (int) number_colors);
          /*
            Append colormap to colormap list.
          */
          p=(ColormapList *) malloc(sizeof(ColormapList));
          p->colormap=window_attributes.colormap;
          p->colors=colors;
          p->next=colormap_list;
          colormap_list=p;
        }
      colors=p->colors;
    }
  /*
    Allocate image structure.
  */
  image=AllocateImage((ImageInfo *) NULL);
  if (image == (Image *) NULL)
    {
      XDestroyImage(ximage);
      return((Image *) NULL);
    }
  /*
    Convert X image to MIFF format.
  */
  if ((window_attributes.visual->class != TrueColor) &&
      (window_attributes.visual->class != DirectColor))
    image->class=PseudoClass;
  image->columns=ximage->width;
  image->rows=ximage->height;
  image->packets=image->columns*image->rows;
  image->pixels=(RunlengthPacket *)
    malloc((unsigned int) image->packets*sizeof(RunlengthPacket));
  if (image->pixels == (RunlengthPacket *) NULL)
    {
      XDestroyImage(ximage);
      DestroyImage(image);
      return((Image *) NULL);
    }
  p=image->pixels;
  switch (image->class)
  {
    case DirectClass:
    default:
    {
      register unsigned long
        color,
        index;

      unsigned long
        blue_mask,
        blue_shift,
        green_mask,
        green_shift,
        red_mask,
        red_shift;

      /*
        Determine shift and mask for red, green, and blue.
      */
      red_mask=window_attributes.visual->red_mask;
      red_shift=0;
      while ((red_mask & 0x01) == 0)
      {
        red_mask>>=1;
        red_shift++;
      }
      green_mask=window_attributes.visual->green_mask;
      green_shift=0;
      while ((green_mask & 0x01) == 0)
      {
        green_mask>>=1;
        green_shift++;
      }
      blue_mask=window_attributes.visual->blue_mask;
      blue_shift=0;
      while ((blue_mask & 0x01) == 0)
      {
        blue_mask>>=1;
        blue_shift++;
      }
      /*
        Convert X image to DirectClass packets.
      */
      if ((number_colors > 0) &&
          (window_attributes.visual->class == DirectColor))
        for (y=0; y < image->rows; y++)
        {
          for (x=0; x < image->columns; x++)
          {
            pixel=XGetPixel(ximage,x,y);
            index=(pixel >> red_shift) & red_mask;
            p->red=XDownScale(colors[index].red);
            index=(pixel >> green_shift) & green_mask;
            p->green=XDownScale(colors[index].green);
            index=(pixel >> blue_shift) & blue_mask;
            p->blue=XDownScale(colors[index].blue);
            p->index=0;
            p->length=0;
            p++;
          }
        }
      else
        for (y=0; y < image->rows; y++)
        {
          for (x=0; x < image->columns; x++)
          {
            pixel=XGetPixel(ximage,x,y);
            color=(pixel >> red_shift) & red_mask;
            p->red=XDownScale((color*65535L)/red_mask);
            color=(pixel >> green_shift) & green_mask;
            p->green=XDownScale((color*65535L)/green_mask);
            color=(pixel >> blue_shift) & blue_mask;
            p->blue=XDownScale((color*65535L)/blue_mask);
            p->index=0;
            p->length=0;
            p++;
          }
        }
      break;
    }
    case PseudoClass:
    {
      /*
        Create colormap.
      */
      image->colors=number_colors;
      image->colormap=(ColorPacket *) malloc(image->colors*sizeof(ColorPacket));
      if (image->colormap == (ColorPacket *) NULL)
        {
          XDestroyImage(ximage);
          DestroyImage(image);
          return((Image *) NULL);
        }
      for (i=0; i < image->colors; i++)
      {
        image->colormap[colors[i].pixel].red=XDownScale(colors[i].red);
        image->colormap[colors[i].pixel].green=XDownScale(colors[i].green);
        image->colormap[colors[i].pixel].blue=XDownScale(colors[i].blue);
      }
      /*
        Convert X image to PseudoClass packets.
      */
      for (y=0; y < image->rows; y++)
      {
        for (x=0; x < image->columns; x++)
        {
          pixel=XGetPixel(ximage,x,y);
          p->index=(unsigned short) pixel;
          p->length=0;
          p++;
        }
      }
      SyncImage(image);
      break;
    }
  }
  XDestroyImage(ximage);
  if (annotate_context != (GC) NULL)
    {
      /*
        Alert user we got the X region by flashing a border.
      */
      XHighlightRectangle(display,window,annotate_context,&crop_info);
      XFlush(display);
      XHighlightRectangle(display,window,annotate_context,&crop_info);
      XFreeGC(display,annotate_context);
    }
  if (level != 0)
    {
      unsigned int
        number_children;

      Window
        *children,
        parent;

      /*
        Descend the window hierarchy and overlay with each subwindow image.
      */
      status=XQueryTree(display,window,&root_window,&parent,&children,
        &number_children);
      if ((status == True) && (number_children != 0))
        {
          Image
            *child_image;

          /*
            Composite any children in back-to-front order.
          */
          for (i=0; i < number_children; i++)
          {
            child_image=XGetWindowImage(display,children[i],False,level+1);
            if (child_image != (Image *) NULL)
              {
                /*
                  Composite child window image.
                */
                XTranslateCoordinates(display,children[i],window,0,0,&x_offset,
                  &y_offset,&child);
                x_offset-=crop_info.x;
                if (x_offset < 0)
                  x_offset=0;
                y_offset-=crop_info.y;
                if (y_offset < 0)
                  y_offset=0;
                CompositeImage(image,ReplaceCompositeOp,child_image,x_offset,
                  y_offset);
                DestroyImage(child_image);
              }
          }
          XFree((void *) children);
        }
    }
  if (level <= 1)
    {
      ColormapList
        *next;

      /*
        Free resources.
      */
      while (colormap_list != (ColormapList *) NULL)
      {
        next=colormap_list->next;
        free((char *) colormap_list->colors);
        free((char *) colormap_list);
        colormap_list=next;
      }
      if (image->class == PseudoClass)
        CompressColormap(image);
    }
  return(image);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X G e t W i n d o w I n f o                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XGetWindowInfo initializes the XWindowInfo structure.
%
%  The format of the XGetWindowInfo routine is:
%
%      XGetWindowInfo(display,visual_info,map_info,pixel_info,font_info,
%        resource_info,window)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
%      returned from XGetVisualInfo.
%
%    o map_info: If map_type is specified, this structure is initialized
%      with info from the Standard Colormap.
%
%    o pixel_info: Specifies a pointer to a XPixelInfo structure.
%
%    o font_info: Specifies a pointer to a XFontStruct structure.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%
*/
Export void XGetWindowInfo(Display *display,XVisualInfo *visual_info,
  XStandardColormap *map_info,XPixelInfo *pixel_info,XFontStruct *font_info,
  XResourceInfo *resource_info,XWindowInfo *window)
{
  /*
    Initialize window info.
  */
  assert(display != (Display *) NULL);
  assert(visual_info != (XVisualInfo *) NULL);
  assert(map_info != (XStandardColormap *) NULL);
  assert(pixel_info != (XPixelInfo *) NULL);
  assert(resource_info != (XResourceInfo *) NULL);
  assert(window != (XWindowInfo *) NULL);
  if (window->id != (Window) NULL)
    {
      XFreeCursor(display,window->cursor);
      XFreeCursor(display,window->busy_cursor);
      if (window->highlight_stipple != (Pixmap) NULL)
        XFreePixmap(display,window->highlight_stipple);
      if (window->shadow_stipple != (Pixmap) NULL)
        XFreePixmap(display,window->shadow_stipple);
    }
  else
    {
      window->id=(Window) NULL;
      window->x=XDisplayWidth(display,visual_info->screen) >> 1;
      window->y=XDisplayWidth(display,visual_info->screen) >> 1;
      window->ximage=(XImage *) NULL;
      window->matte_image=(XImage *) NULL;
      window->pixmap=(Pixmap) NULL;
      window->matte_pixmap=(Pixmap) NULL;
      window->mapped=False;
      window->stasis=False;
      window->shared_memory=False;
#ifdef HasSharedMemory
      window->shared_memory=False;
      if (resource_info->use_shared_memory)
        window->shared_memory=XShmQueryExtension(display);
      window->segment_info[0].shmid=(-1);
      window->segment_info[1].shmid=(-1);
      window->segment_info[2].shmid=(-1);
      window->segment_info[3].shmid=(-1);
#endif
    }
  window->screen=visual_info->screen;
  window->root=XRootWindow(display,visual_info->screen);
  window->visual=visual_info->visual;
  window->class=visual_info->class;
  window->depth=visual_info->depth;
  window->visual_info=visual_info;
  window->map_info=map_info;
  window->pixel_info=pixel_info;
  window->font_info=font_info;
  window->cursor=XCreateFontCursor(display,XC_left_ptr);
  window->busy_cursor=XCreateFontCursor(display,XC_watch);
  window->name="\0";
  window->geometry=(char *) NULL;
  window->icon_name="\0";
  window->icon_geometry=resource_info->icon_geometry;
  window->crop_geometry=(char *) NULL;
  window->flags=PSize;
  window->width=1;
  window->height=1;
  window->min_width=1;
  window->min_height=1;
  window->width_inc=1;
  window->height_inc=1;
  window->border_width=resource_info->border_width;
  window->annotate_context=pixel_info->annotate_context;
  window->highlight_context=pixel_info->highlight_context;
  window->widget_context=pixel_info->widget_context;
  window->shadow_stipple=(Pixmap) NULL;
  window->highlight_stipple=(Pixmap) NULL;
  window->use_pixmap=True;
  window->immutable=False;
  window->shape=False;
  window->data=0;
  window->mask=CWBackingStore | CWBackPixel | CWBackPixmap | CWBitGravity |
    CWBorderPixel | CWColormap | CWCursor | CWDontPropagate | CWEventMask |
    CWOverrideRedirect | CWSaveUnder | CWWinGravity;
  window->attributes.background_pixel=pixel_info->background_color.pixel;
  window->attributes.background_pixmap=(Pixmap) NULL;
  window->attributes.bit_gravity=ForgetGravity;
  window->attributes.backing_store=NotUseful;
  window->attributes.save_under=False;
  window->attributes.border_pixel=pixel_info->border_color.pixel;
  window->attributes.colormap=map_info->colormap;
  window->attributes.cursor=window->cursor;
  window->attributes.do_not_propagate_mask=NoEventMask;
  window->attributes.event_mask=NoEventMask;
  window->attributes.override_redirect=False;
  window->attributes.win_gravity=NorthWestGravity;
  window->orphan=False;
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X H i g h l i g h t E l l i p s e                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XHighlightEllipse puts a border on the X server around a region
%  defined by highlight_info.
%
%  The format of the XHighlightEllipse routine is:
%
%    XHighlightEllipse(display,window,annotate_context,highlight_info)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a Window structure.
%
%    o annotate_context: Specifies a pointer to a GC structure.
%
%    o highlight_info: Specifies a pointer to a RectangleInfo structure.  It
%      contains the extents of any highlighting rectangle.
%
%
*/
Export void XHighlightEllipse(Display *display,Window window,
  GC annotate_context,const RectangleInfo *highlight_info)
{
  assert(display != (Display *) NULL);
  assert(window != (Window) NULL);
  assert(annotate_context != (GC) NULL);
  assert(highlight_info != (RectangleInfo *) NULL);
  if ((highlight_info->width < 4) || (highlight_info->height < 4))
    return;
  XDrawArc(display,window,annotate_context,highlight_info->x,
    highlight_info->y,highlight_info->width-1,highlight_info->height-1,
    0,360*64);
  XDrawArc(display,window,annotate_context,highlight_info->x+1,
    highlight_info->y+1,highlight_info->width-3,highlight_info->height-3,
    0,360*64);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X H i g h l i g h t L i n e                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XHighlightLine puts a border on the X server around a region
%  defined by highlight_info.
%
%  The format of the XHighlightLine routine is:
%
%    XHighlightLine(display,window,annotate_context,highlight_info)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a Window structure.
%
%    o annotate_context: Specifies a pointer to a GC structure.
%
%    o highlight_info: Specifies a pointer to a RectangleInfo structure.  It
%      contains the extents of any highlighting rectangle.
%
%
*/
Export void XHighlightLine(Display *display,Window window,GC annotate_context,
  const XSegment *highlight_info)
{
  assert(display != (Display *) NULL);
  assert(window != (Window) NULL);
  assert(annotate_context != (GC) NULL);
  assert(highlight_info != (XSegment *) NULL);
  XDrawLine(display,window,annotate_context,highlight_info->x1,
    highlight_info->y1,highlight_info->x2,highlight_info->y2);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X H i g h l i g h t R e c t a n g l e                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XHighlightRectangle puts a border on the X server around a region
%  defined by highlight_info.
%
%  The format of the XHighlightRectangle routine is:
%
%    XHighlightRectangle(display,window,annotate_context,highlight_info)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a Window structure.
%
%    o annotate_context: Specifies a pointer to a GC structure.
%
%    o highlight_info: Specifies a pointer to a RectangleInfo structure.  It
%      contains the extents of any highlighting rectangle.
%
%
*/
Export void XHighlightRectangle(Display *display,Window window,
  GC annotate_context,const RectangleInfo *highlight_info)
{
  assert(display != (Display *) NULL);
  assert(window != (Window) NULL);
  assert(annotate_context != (GC) NULL);
  assert(highlight_info != (RectangleInfo *) NULL);
  if ((highlight_info->width < 4) || (highlight_info->height < 4))
    return;
  XDrawRectangle(display,window,annotate_context,highlight_info->x,
    highlight_info->y,highlight_info->width-1,highlight_info->height-1);
  XDrawRectangle(display,window,annotate_context,highlight_info->x+1,
    highlight_info->y+1,highlight_info->width-3,highlight_info->height-3);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M a k e C u r s o r                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMakeCursor creates a crosshairs X11 cursor.
%
%  The format of the XMakeCursor routine is:
%
%      XMakeCursor(display,window,colormap,background_color,foreground_color)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o window: Specifies the ID of the window for which the cursor is
%      assigned.
%
%    o colormap: Specifies the ID of the colormap from which the background
%      and foreground color will be retrieved.
%
%    o background_color: Specifies the color to use for the cursor background.
%
%    o foreground_color: Specifies the color to use for the cursor foreground.
%
%
*/
Export Cursor XMakeCursor(Display *display,Window window,Colormap colormap,
  char *background_color,char *foreground_color)
{
#define scope_height 17
#define scope_x_hot 8
#define scope_y_hot 8
#define scope_width 17

  static unsigned char
    scope_bits[] =
    {
      0x80, 0x03, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02,
      0x00, 0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x7f,
      0xfc, 0x01, 0x01, 0x00, 0x01, 0x7f, 0xfc, 0x01, 0x80, 0x02, 0x00,
      0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02,
      0x00, 0x80, 0x02, 0x00, 0x80, 0x03, 0x00
    };

  static unsigned char
    scope_mask_bits[] =
    {
      0xc0, 0x07, 0x00, 0xc0, 0x07, 0x00, 0xc0, 0x06, 0x00, 0xc0, 0x06,
      0x00, 0xc0, 0x06, 0x00, 0xc0, 0x06, 0x00, 0xff, 0xfe, 0x01, 0x7f,
      0xfc, 0x01, 0x03, 0x80, 0x01, 0x7f, 0xfc, 0x01, 0xff, 0xfe, 0x01,
      0xc0, 0x06, 0x00, 0xc0, 0x06, 0x00, 0xc0, 0x06, 0x00, 0xc0, 0x06,
      0x00, 0xc0, 0x07, 0x00, 0xc0, 0x07, 0x00
    };

  Cursor
    cursor;

  Pixmap
    mask,
    source;

  XColor
    background,
    foreground;

  assert(display != (Display *) NULL);
  assert(window != (Window) NULL);
  assert(colormap != (Colormap) NULL);
  assert(background_color != (char *) NULL);
  assert(foreground_color != (char *) NULL);
  source=XCreateBitmapFromData(display,window,(char *) scope_bits,scope_width,
    scope_height);
  mask=XCreateBitmapFromData(display,window,(char *) scope_mask_bits,
    scope_width,scope_height);
  if ((source == (Pixmap) NULL) || (mask == (Pixmap) NULL))
    Error("Unable to create pixmap",(char *) NULL);
  XParseColor(display,colormap,background_color,&background);
  XParseColor(display,colormap,foreground_color,&foreground);
  cursor=XCreatePixmapCursor(display,source,mask,&foreground,&background,
    scope_x_hot,scope_y_hot);
  XFreePixmap(display,source);
  XFreePixmap(display,mask);
  return(cursor);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M a k e I m a g e                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMakeImage creates an X11 image.  If the image size differs from
%  the X11 image size, the image is first resized.
%
%  The format of the XMakeImage routine is:
%
%      status=XMakeImage(display,resource_info,window,image,width,height)
%
%  A description of each parameter follows:
%
%    o status: Function XMakeImage returns True if the X image is
%      successfully created.  False is returned is there is a memory shortage.
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o window: Specifies a pointer to a XWindowInfo structure.
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%    o width: Specifies the width in pixels of the rectangular area to
%      display.
%
%    o height: Specifies the height in pixels of the rectangular area to
%      display.
%
%
*/
Export unsigned int XMakeImage(Display *display,
  const XResourceInfo *resource_info,XWindowInfo *window,Image *image,
  unsigned int width,unsigned int height)
{
  Image
    *transformed_image;

  int
    depth,
    format;

  Pixmap
    matte_pixmap;

  XImage
    *matte_image,
    *ximage;

  assert(display != (Display *) NULL);
  assert(resource_info != (XResourceInfo *) NULL);
  assert(window != (XWindowInfo *) NULL);
  assert(image != (Image *) NULL);
  assert(width > 0);
  assert(height > 0);
  if ((window->width == 0) || (window->height == 0))
    return(False);
  /*
    Apply user transforms to the image.
  */
  XDefineCursor(display,window->id,window->busy_cursor);
  XFlush(display);
  transformed_image=image;
  if (window->crop_geometry)
    {
      Image
        *cropped_image;

      RectangleInfo
        crop_info;

      /*
        Crop image.
      */
      (void) XParseGeometry(window->crop_geometry,&crop_info.x,&crop_info.y,
        &crop_info.width,&crop_info.height);
      transformed_image->orphan=True;
      cropped_image=CropImage(transformed_image,&crop_info);
      transformed_image->orphan=False;
      if (cropped_image != (Image *) NULL)
        {
          if (transformed_image != image)
            DestroyImage(transformed_image);
          transformed_image=cropped_image;
        }
    }
  if ((width != transformed_image->columns) ||
      (height != transformed_image->rows))
    {
      Image
        *zoomed_image;

      /*
        Scale image.
      */
      transformed_image->orphan=True;
      if ((window->pixel_info->colors != 0) || transformed_image->matte)
        zoomed_image=SampleImage(transformed_image,width,height);
      else
        zoomed_image=ScaleImage(transformed_image,width,height);
      if (zoomed_image != (Image *) NULL)
        {
          if (transformed_image != image)
            DestroyImage(transformed_image);
          transformed_image=zoomed_image;
        }
      transformed_image->orphan=False;
    }
  /*
    Create X image.
  */
  depth=window->depth;
  if (window->immutable)
    if (IsMonochromeImage(transformed_image))
      depth=1;
  format=(depth == 1) ? XYBitmap : ZPixmap;
  width=transformed_image->columns;
  height=transformed_image->rows;
  ximage=(XImage *) NULL;
#ifdef HasSharedMemory
  if (window->shared_memory)
    {
      ximage=XShmCreateImage(display,window->visual,depth,format,0,
        &window->segment_info[2],width,height);
      window->segment_info[2].shmid=shmget(IPC_PRIVATE,ximage->bytes_per_line*
        ximage->height,IPC_CREAT | 0777);
      window->shared_memory=window->segment_info[2].shmid >= 0;
      if (window->shared_memory)
        window->segment_info[2].shmaddr=(char *)
          shmat(window->segment_info[2].shmid,0,0);
    }
#endif
  if (!window->shared_memory)
    ximage=XCreateImage(display,window->visual,depth,format,0,(char *) NULL,
      width,height,XBitmapPad(display),0);
  if (ximage == (XImage *) NULL)
    {
      /*
        Unable to create X image.
      */
      if (transformed_image != image)
        DestroyImage(transformed_image);
      XDefineCursor(display,window->id,window->cursor);
      return(False);
    }
  if (resource_info->debug)
    {
      (void) fprintf(stderr,"XImage:\n");
      (void) fprintf(stderr,"  width, height: %dx%d\n",ximage->width,
        ximage->height);
      (void) fprintf(stderr,"  format: %d\n",ximage->format);
      (void) fprintf(stderr,"  byte order: %d\n",ximage->byte_order);
      (void) fprintf(stderr,"  bitmap unit, bit order, pad: %d %d %d\n",
        ximage->bitmap_unit,ximage->bitmap_bit_order,ximage->bitmap_pad);
      (void) fprintf(stderr,"  depth: %d\n",ximage->depth);
      (void) fprintf(stderr,"  bytes per line: %d\n",ximage->bytes_per_line);
      (void) fprintf(stderr,"  bits per pixel: %d\n",ximage->bits_per_pixel);
      (void) fprintf(stderr,"  red, green, blue masks: 0x%lx 0x%lx 0x%lx\n",
        ximage->red_mask,ximage->green_mask,ximage->blue_mask);
    }
  /*
    Allocate X image pixel data.
  */
#ifdef HasSharedMemory
  if (window->shared_memory)
    {
      xerror_alert=False;
      window->segment_info[2].readOnly=False;
      XShmAttach(display,&window->segment_info[2]);
      XSync(display,False);
      shmctl(window->segment_info[2].shmid,IPC_RMID,0);
      ximage->data=window->segment_info[2].shmaddr;
      if (xerror_alert)
        {
          xerror_alert=False;
          window->shared_memory=False;
          if (window->ximage != (XImage *) NULL)
            {
              XShmDetach(display,&window->segment_info[0]);
              window->ximage->data=(char *) NULL;
              XDestroyImage(window->ximage);
              window->ximage=(XImage *) NULL;
              shmdt(window->segment_info[0].shmaddr);
            }
        }
    }
#endif
  if (!window->shared_memory)
    if (ximage->format == XYBitmap)
      ximage->data=(char *)
        malloc(ximage->bytes_per_line*ximage->height*ximage->depth);
    else
      ximage->data=(char *) malloc(ximage->bytes_per_line*ximage->height);
  if (ximage->data == (char *) NULL)
    {
      /*
        Unable to allocate pixel data.
      */
      if (transformed_image != image)
        DestroyImage(transformed_image);
      XDestroyImage(ximage);
      XDefineCursor(display,window->id,window->cursor);
      return(False);
    }
  if (window->ximage != (XImage *) NULL)
    {
      /*
        Destroy previous X image.
      */
#ifdef HasSharedMemory
      if (window->shared_memory)
        {
          XShmDetach(display,&window->segment_info[0]);
          window->ximage->data=(char *) NULL;
          XDestroyImage(window->ximage);
          shmdt(window->segment_info[0].shmaddr);
        }
#endif
      if (!window->shared_memory)
        {
          if (window->ximage->data != (char *) NULL)
            free(window->ximage->data);
          window->ximage->data=(char *) NULL;
          XDestroyImage(window->ximage);
        }
    }
#ifdef HasSharedMemory
  window->segment_info[0]=window->segment_info[2];
#endif
  window->ximage=ximage;
  matte_image=(XImage *) NULL;
  if (transformed_image != (Image *) NULL)
    if (transformed_image->matte)
      {
        /*
          Create matte image.
        */
        matte_image=XCreateImage(display,window->visual,1,XYBitmap,0,
          (char *) NULL,width,height,XBitmapPad(display),0);
        if (resource_info->debug)
          {
            (void) fprintf(stderr,"Matte Image:\n");
            (void) fprintf(stderr,"  width, height: %dx%d\n",matte_image->width,
              matte_image->height);
          }
        if (matte_image != (XImage *) NULL)
          {
            /*
              Allocate matte image pixel data.
            */
            matte_image->data=(char *) malloc(matte_image->bytes_per_line*
              matte_image->height*matte_image->depth);
            if (matte_image->data == (char *) NULL)
              {
                XDestroyImage(matte_image);
                matte_image=(XImage *) NULL;
              }
          }
      }
  if (window->matte_image != (XImage *) NULL)
    {
      if (window->matte_image->data != (char *) NULL)
        (void) free(window->matte_image->data);
      window->matte_image->data=(char *) NULL;
      XDestroyImage(window->matte_image);
    }
  window->matte_image=matte_image;
  window->stasis=False;
  /*
    Convert runlength-encoded pixels to X image data.
  */
  if ((ximage->byte_order == LSBFirst) ||
      ((ximage->format == XYBitmap) && (ximage->bitmap_bit_order == LSBFirst)))
    XMakeImageLSBFirst(resource_info,window,transformed_image,ximage,
      matte_image);
  else
    XMakeImageMSBFirst(resource_info,window,transformed_image,ximage,
      matte_image);
  matte_pixmap=window->matte_pixmap;
  if (window->matte_pixmap != (Pixmap) NULL)
    XFreePixmap(display,window->matte_pixmap);
  window->matte_pixmap=(Pixmap) NULL;
  if (window->shape)
    if (window->matte_image != (XImage *) NULL)
      {
        /*
          Create matte pixmap.
        */
        window->matte_pixmap=XCreatePixmap(display,window->id,width,height,1);
        if (window->matte_pixmap != (Pixmap) NULL)
          {
            GC
              graphics_context;

            XGCValues
              context_values;

            /*
              Copy matte image to matte pixmap.
            */
            context_values.background=1;
            context_values.foreground=0;
            graphics_context=XCreateGC(display,window->matte_pixmap,
              GCBackground | GCForeground,&context_values);
            XPutImage(display,window->matte_pixmap,graphics_context,
              window->matte_image,0,0,0,0,width,height);
            XFreeGC(display,graphics_context);
          }
      }
#ifdef HasShape
  if (window->matte_pixmap != matte_pixmap)
    XShapeCombineMask(display,window->id,ShapeBounding,0,0,
      window->matte_pixmap,ShapeSet);
#endif
  if (transformed_image != image)
    DestroyImage(transformed_image);
  (void) XMakePixmap(display,resource_info,window);
  /*
    Restore cursor.
  */
  XDefineCursor(display,window->id,window->cursor);
  return(True);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M a k e I m a g e L S B F i r s t                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMakeImageLSBFirst initializes the pixel data of an X11 Image.
%  The X image pixels are copied in least-significant bit and byte first
%  order.  The server's scanline pad is respected.  Rather than using one or
%  two general cases, many special cases are found here to help speed up the
%  image conversion.
%
%  The format of the XMakeImageLSBFirst routine is:
%
%      XMakeImageLSBFirst(resource_info,window,image,ximage,matte_image)
%
%  A description of each parameter follows:
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o window: Specifies a pointer to a XWindowInfo structure.
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%    o ximage: Specifies a pointer to a XImage structure;  returned from
%      XCreateImage.
%
%    o matte_image: Specifies a pointer to a XImage structure;  returned from
%      XCreateImage.
%
*/
static void XMakeImageLSBFirst(const XResourceInfo *resource_info,
  const XWindowInfo *window,Image *image,XImage *ximage,XImage *matte_image)
{
  register int
    i,
    j,
    x;

  register RunlengthPacket
    *p;

  register unsigned char
    bit,
    byte,
    *q;

  register unsigned long
    pixel;

  register XColor
    *gamma_map;

  unsigned int
    scanline_pad;

  unsigned long
    *pixels;

  XStandardColormap
    *map_info;

  scanline_pad=ximage->bytes_per_line-
    ((ximage->width*ximage->bits_per_pixel) >> 3);
  map_info=window->map_info;
  pixels=window->pixel_info->pixels;
  gamma_map=window->pixel_info->gamma_map;
  p=image->pixels;
  q=(unsigned char *) ximage->data;
  x=0;
  if (ximage->format == XYBitmap)
    {
      register unsigned short
        polarity;

      unsigned char
        background,
        foreground;

      /*
        Convert image to big-endian bitmap.
      */
      background=(Intensity(window->pixel_info->foreground_color) <
        Intensity(window->pixel_info->background_color) ? 0x80 : 0x00);
      foreground=(Intensity(window->pixel_info->background_color) <
        Intensity(window->pixel_info->foreground_color) ? 0x80 : 0x00);
      polarity=Intensity(image->colormap[0]) < (MaxRGB >> 1);
      if (image->colors == 2)
        polarity=Intensity(image->colormap[0]) < Intensity(image->colormap[1]);
      bit=0;
      byte=0;
      for (i=0; i < image->packets; i++)
      {
        for (j=0; j <= ((int) p->length); j++)
        {
          byte>>=1;
          if (p->index == polarity)
            byte|=foreground;
          else
            byte|=background;
          bit++;
          if (bit == 8)
            {
              *q++=byte;
              bit=0;
              byte=0;
            }
          x++;
          if (x == ximage->width)
            {
              /*
                Advance to the next scanline.
              */
              if (bit != 0)
                *q=byte >> (8-bit);
              q+=scanline_pad;
              bit=0;
              byte=0;
              x=0;
            }
        }
        p++;
      }
    }
  else
    if (window->pixel_info->colors != 0)
      switch (ximage->bits_per_pixel)
      {
        case 2:
        {
          register unsigned int
            nibble;

          /*
            Convert to 2 bit color-mapped X image.
          */
          nibble=0;
          for (i=0; i < image->packets; i++)
          {
            pixel=pixels[p->index] & 0xf;
            for (j=0; j <= ((int) p->length); j++)
            {
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) pixel;
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 2);
                  nibble++;
                  break;
                }
                case 2:
                {
                  *q|=(unsigned char) (pixel << 4);
                  nibble++;
                  break;
                }
                case 3:
                {
                  *q|=(unsigned char) (pixel << 6);
                  q++;
                  nibble=0;
                  break;
                }
              }
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  nibble=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        case 4:
        {
          register unsigned int
            nibble;

          /*
            Convert to 4 bit color-mapped X image.
          */
          nibble=0;
          for (i=0; i < image->packets; i++)
          {
            pixel=pixels[p->index] & 0xf;
            for (j=0; j <= ((int) p->length); j++)
            {
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) pixel;
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 4);
                  q++;
                  nibble=0;
                  break;
                }
              }
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  nibble=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        case 6:
        case 8:
        {
          /*
            Convert to 8 bit color-mapped X image.
          */
          if (resource_info->color_recovery && resource_info->dither)
            {
              XDitherImage(image,ximage);
              break;
            }
          for (i=0; i < image->packets; i++)
          {
            pixel=pixels[p->index];
            for (j=0; j <= ((int) p->length); j++)
            {
              *q++=(unsigned char) pixel;
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        default:
        {
          register int
            k;

          register unsigned int
            bytes_per_pixel;

          unsigned char
            channel[sizeof(unsigned long)];

          /*
            Convert to multi-byte color-mapped X image.
          */
          bytes_per_pixel=ximage->bits_per_pixel >> 3;
          for (i=0; i < image->packets; i++)
          {
            pixel=pixels[p->index];
            for (k=0; k < bytes_per_pixel; k++)
            {
              channel[k]=(unsigned char) pixel;
              pixel>>=8;
            }
            for (j=0; j <= ((int) p->length); j++)
            {
              for (k=0; k < bytes_per_pixel; k++)
                *q++=channel[k];
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
      }
    else
      switch (ximage->bits_per_pixel)
      {
        case 2:
        {
          register unsigned int
            nibble;

          /*
            Convert to contiguous 2 bit continuous-tone X image.
          */
          nibble=0;
          for (i=0; i < image->packets; i++)
          {
            pixel=XGammaPixel(map_info,gamma_map,p,QuantumDepth);
            pixel&=0xf;
            for (j=0; j <= ((int) p->length); j++)
            {
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) pixel;
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 2);
                  nibble++;
                  break;
                }
                case 2:
                {
                  *q|=(unsigned char) (pixel << 4);
                  nibble++;
                  break;
                }
                case 3:
                {
                  *q|=(unsigned char) (pixel << 6);
                  q++;
                  nibble=0;
                  break;
                }
              }
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  nibble=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        case 4:
        {
          register unsigned int
            nibble;

          /*
            Convert to contiguous 4 bit continuous-tone X image.
          */
          nibble=0;
          for (i=0; i < image->packets; i++)
          {
            pixel=XGammaPixel(map_info,gamma_map,p,QuantumDepth);
            pixel&=0xf;
            for (j=0; j <= ((int) p->length); j++)
            {
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) pixel;
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 4);
                  q++;
                  nibble=0;
                  break;
                }
              }
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  nibble=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        case 6:
        case 8:
        {
          /*
            Convert to contiguous 8 bit continuous-tone X image.
          */
          if (resource_info->color_recovery && resource_info->dither)
            {
              XDitherImage(image,ximage);
              break;
            }
          for (i=0; i < image->packets; i++)
          {
            pixel=XGammaPixel(map_info,gamma_map,p,QuantumDepth);
            for (j=0; j <= ((int) p->length); j++)
            {
              *q++=(unsigned char) pixel;
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        default:
        {
          if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
              (map_info->green_max == 255) && (map_info->blue_max == 255) &&
              (map_info->red_mult == 65536) && (map_info->green_mult == 256) &&
              (map_info->blue_mult == 1))
            {
              /*
                Convert to 32 bit continuous-tone X image.
              */
              for (i=0; i < image->packets; i++)
              {
                for (j=0; j <= ((int) p->length); j++)
                {
                  *q++=DownScale(gamma_map[p->blue].blue);
                  *q++=DownScale(gamma_map[p->green].green);
                  *q++=DownScale(gamma_map[p->red].red);
                  *q++=0;
                }
                p++;
              }
            }
          else
            if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
                (map_info->green_max == 255) && (map_info->blue_max == 255) &&
                (map_info->red_mult == 1) && (map_info->green_mult == 256) &&
                (map_info->blue_mult == 65536))
              {
                /*
                  Convert to 32 bit continuous-tone X image.
                */
                for (i=0; i < image->packets; i++)
                {
                  for (j=0; j <= ((int) p->length); j++)
                  {
                    *q++=DownScale(gamma_map[p->red].red);
                    *q++=DownScale(gamma_map[p->green].green);
                    *q++=DownScale(gamma_map[p->blue].blue);
                    *q++=0;
                  }
                  p++;
                }
              }
            else
              {
                register int
                  k;

                register unsigned int
                  bytes_per_pixel;

                unsigned char
                  channel[sizeof(unsigned long)];

                /*
                  Convert to multi-byte continuous-tone X image.
                */
                bytes_per_pixel=ximage->bits_per_pixel >> 3;
                for (i=0; i < image->packets; i++)
                {
                  pixel=XGammaPixel(map_info,gamma_map,p,QuantumDepth);
                  for (k=0; k < bytes_per_pixel; k++)
                  {
                    channel[k]=(unsigned char) pixel;
                    pixel>>=8;
                  }
                  for (j=0; j <= ((int) p->length); j++)
                  {
                    for (k=0; k < bytes_per_pixel; k++)
                      *q++=channel[k];
                    x++;
                    if (x == ximage->width)
                      {
                        x=0;
                        q+=scanline_pad;
                      }
                  }
                  p++;
                }
              }
          break;
        }
      }
  if (matte_image != (XImage *) NULL)
    {
      /*
        Initialize matte image.
      */
      scanline_pad=matte_image->bytes_per_line-
        ((matte_image->width*matte_image->bits_per_pixel) >> 3);
      p=image->pixels;
      q=(unsigned char *) matte_image->data;
      bit=0;
      byte=0;
      for (i=0; i < image->packets; i++)
      {
        for (j=0; j <= ((int) p->length); j++)
        {
          byte>>=1;
          if (p->index == Transparent)
            byte|=0x01;
          bit++;
          if (bit == 8)
            {
              *q++=byte;
              bit=0;
              byte=0;
            }
          x++;
          if (x == matte_image->width)
            {
              /*
                Advance to the next scanline.
              */
              if (bit != 0)
                *q=byte >> (8-bit);
              q+=scanline_pad;
              bit=0;
              byte=0;
              x=0;
            }
        }
        p++;
      }
    }
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M a k e I m a g e M S B F i r s t                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMakeImageMSBFirst initializes the pixel data of an X11 Image.
%  The X image pixels are copied in most-significant bit and byte first order.
%  The server's scanline pad is also resprected. Rather than using one or two
%  general cases, many special cases are found here to help speed up the image
%  conversion.
%
%  The format of the XMakeImageMSBFirst routine is:
%
%      XMakeImageMSBFirst(resource_info,window,image,ximage,matte_image)
%
%  A description of each parameter follows:
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o window: Specifies a pointer to a XWindowInfo structure.
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%    o ximage: Specifies a pointer to a XImage structure;  returned from
%      XCreateImage.
%
%    o matte_image: Specifies a pointer to a XImage structure;  returned from
%      XCreateImage.
%
%
*/
static void XMakeImageMSBFirst(const XResourceInfo *resource_info,
  const XWindowInfo *window,Image *image,XImage *ximage,XImage *matte_image)
{
  register int
    i,
    j,
    x;

  register RunlengthPacket
    *p;

  register unsigned char
    bit,
    byte,
    *q;

  register unsigned long
    pixel;

  register XColor
    *gamma_map;

  unsigned int
    scanline_pad;

  unsigned long
    *pixels;

  XStandardColormap
    *map_info;

  scanline_pad=ximage->bytes_per_line-
    ((ximage->width*ximage->bits_per_pixel) >> 3);
  map_info=window->map_info;
  pixels=window->pixel_info->pixels;
  gamma_map=window->pixel_info->gamma_map;
  p=image->pixels;
  q=(unsigned char *) ximage->data;
  x=0;
  if (ximage->format == XYBitmap)
    {
      register unsigned short
        polarity;

      unsigned char
        background,
        foreground;

      /*
        Convert image to big-endian bitmap.
      */
      background=(Intensity(window->pixel_info->foreground_color) <
        Intensity(window->pixel_info->background_color) ? 0x01 : 0x00);
      foreground=(Intensity(window->pixel_info->background_color) <
        Intensity(window->pixel_info->foreground_color) ? 0x01 : 0x00);
      polarity=Intensity(image->colormap[0]) < (MaxRGB >> 1);
      if (image->colors == 2)
        polarity=Intensity(image->colormap[0]) < Intensity(image->colormap[1]);
      bit=0;
      byte=0;
      for (i=0; i < image->packets; i++)
      {
        for (j=0; j <= ((int) p->length); j++)
        {
          byte<<=1;
          if (p->index == polarity)
            byte|=foreground;
          else
            byte|=background;
          bit++;
          if (bit == 8)
            {
              *q++=byte;
              bit=0;
              byte=0;
            }
          x++;
          if (x == ximage->width)
            {
              /*
                Advance to the next scanline.
              */
              if (bit != 0)
                *q=byte << (8-bit);
              q+=scanline_pad;
              bit=0;
              byte=0;
              x=0;
            }
        }
        p++;
      }
    }
  else
    if (window->pixel_info->colors != 0)
      switch (ximage->bits_per_pixel)
      {
        case 2:
        {
          register unsigned int
            nibble;

          /*
            Convert to 2 bit color-mapped X image.
          */
          nibble=0;
          for (i=0; i < image->packets; i++)
          {
            pixel=pixels[p->index] & 0xf;
            for (j=0; j <= ((int) p->length); j++)
            {
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) (pixel << 6);
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 4);
                  nibble++;
                  break;
                }
                case 2:
                {
                  *q|=(unsigned char) (pixel << 2);
                  nibble++;
                  break;
                }
                case 3:
                {
                  *q|=(unsigned char) pixel;
                  q++;
                  nibble=0;
                  break;
                }
              }
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  nibble=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        case 4:
        {
          register unsigned int
            nibble;

          /*
            Convert to 4 bit color-mapped X image.
          */
          nibble=0;
          for (i=0; i < image->packets; i++)
          {
            pixel=pixels[p->index] & 0xf;
            for (j=0; j <= ((int) p->length); j++)
            {
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) (pixel << 4);
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) pixel;
                  q++;
                  nibble=0;
                  break;
                }
              }
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  nibble=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        case 6:
        case 8:
        {
          /*
            Convert to 8 bit color-mapped X image.
          */
          if (resource_info->color_recovery && resource_info->dither)
            {
              XDitherImage(image,ximage);
              break;
            }
          for (i=0; i < image->packets; i++)
          {
            pixel=pixels[p->index];
            for (j=0; j <= ((int) p->length); j++)
            {
              *q++=(unsigned char) pixel;
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        default:
        {
          register int
            k;

          register unsigned int
            bytes_per_pixel;

          unsigned char
            channel[sizeof(unsigned long)];

          /*
            Convert to 8 bit color-mapped X image.
          */
          bytes_per_pixel=ximage->bits_per_pixel >> 3;
          for (i=0; i < image->packets; i++)
          {
            pixel=pixels[p->index];
            for (k=bytes_per_pixel-1; k >= 0; k--)
            {
              channel[k]=(unsigned char) pixel;
              pixel>>=8;
            }
            for (j=0; j <= ((int) p->length); j++)
            {
              for (k=0; k < bytes_per_pixel; k++)
                *q++=channel[k];
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
      }
    else
      switch (ximage->bits_per_pixel)
      {
        case 2:
        {
          register unsigned int
            nibble;

          /*
            Convert to 4 bit continuous-tone X image.
          */
          nibble=0;
          for (i=0; i < image->packets; i++)
          {
            pixel=XGammaPixel(map_info,gamma_map,p,QuantumDepth);
            pixel&=0xf;
            for (j=0; j <= ((int) p->length); j++)
            {
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) (pixel << 6);
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 4);
                  nibble++;
                  break;
                }
                case 2:
                {
                  *q|=(unsigned char) (pixel << 2);
                  nibble++;
                  break;
                }
                case 3:
                {
                  *q|=(unsigned char) pixel;
                  q++;
                  nibble=0;
                  break;
                }
              }
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  nibble=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        case 4:
        {
          register unsigned int
            nibble;

          /*
            Convert to 4 bit continuous-tone X image.
          */
          nibble=0;
          for (i=0; i < image->packets; i++)
          {
            pixel=XGammaPixel(map_info,gamma_map,p,QuantumDepth);
            pixel&=0xf;
            for (j=0; j <= ((int) p->length); j++)
            {
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) (pixel << 4);
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) pixel;
                  q++;
                  nibble=0;
                  break;
                }
              }
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  nibble=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        case 6:
        case 8:
        {
          /*
            Convert to 8 bit continuous-tone X image.
          */
          if (resource_info->color_recovery && resource_info->dither)
            {
              XDitherImage(image,ximage);
              break;
            }
          for (i=0; i < image->packets; i++)
          {
            pixel=XGammaPixel(map_info,gamma_map,p,QuantumDepth);
            for (j=0; j <= ((int) p->length); j++)
            {
              *q++=(unsigned char) pixel;
              x++;
              if (x == ximage->width)
                {
                  x=0;
                  q+=scanline_pad;
                }
            }
            p++;
          }
          break;
        }
        default:
        {
          if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
              (map_info->green_max == 255) && (map_info->blue_max == 255) &&
              (map_info->red_mult == 65536) && (map_info->green_mult == 256) &&
              (map_info->blue_mult == 1))
            {
              /*
                Convert to 32 bit continuous-tone X image.
              */
              for (i=0; i < image->packets; i++)
              {
                for (j=0; j <= ((int) p->length); j++)
                {
                  *q++=0;
                  *q++=DownScale(gamma_map[p->red].red);
                  *q++=DownScale(gamma_map[p->green].green);
                  *q++=DownScale(gamma_map[p->blue].blue);
                }
                p++;
              }
            }
          else
            if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
                (map_info->green_max == 255) && (map_info->blue_max == 255) &&
                (map_info->red_mult == 1) && (map_info->green_mult == 256) &&
                (map_info->blue_mult == 65536))
              {
                /*
                  Convert to 32 bit continuous-tone X image.
                */
                for (i=0; i < image->packets; i++)
                {
                  for (j=0; j <= ((int) p->length); j++)
                  {
                    *q++=0;
                    *q++=DownScale(gamma_map[p->blue].blue);
                    *q++=DownScale(gamma_map[p->green].green);
                    *q++=DownScale(gamma_map[p->red].red);
                  }
                  p++;
                }
              }
            else
              {
                register int
                  k;

                register unsigned int
                  bytes_per_pixel;

                unsigned char
                  channel[sizeof(unsigned long)];

                /*
                  Convert to multi-byte continuous-tone X image.
                */
                bytes_per_pixel=ximage->bits_per_pixel >> 3;
                for (i=0; i < image->packets; i++)
                {
                  pixel=XGammaPixel(map_info,gamma_map,p,QuantumDepth);
                  for (k=bytes_per_pixel-1; k >= 0; k--)
                  {
                    channel[k]=(unsigned char) pixel;
                    pixel>>=8;
                  }
                  for (j=0; j <= ((int) p->length); j++)
                  {
                    for (k=0; k < bytes_per_pixel; k++)
                      *q++=channel[k];
                    x++;
                    if (x == ximage->width)
                      {
                        x=0;
                        q+=scanline_pad;
                      }
                  }
                  p++;
                }
              }
          break;
        }
      }
  if (matte_image != (XImage *) NULL)
    {
      /*
        Initialize matte image.
      */
      scanline_pad=matte_image->bytes_per_line-
        ((matte_image->width*matte_image->bits_per_pixel) >> 3);
      p=image->pixels;
      q=(unsigned char *) matte_image->data;
      bit=0;
      byte=0;
      for (i=0; i < image->packets; i++)
      {
        for (j=0; j <= ((int) p->length); j++)
        {
          byte<<=1;
          if (p->index == Transparent)
            byte|=0x01;
          bit++;
          if (bit == 8)
            {
              *q++=byte;
              bit=0;
              byte=0;
            }
          x++;
          if (x == matte_image->width)
            {
              /*
                Advance to the next scanline.
              */
              if (bit != 0)
                *q=byte << (8-bit);
              q+=scanline_pad;
              bit=0;
              byte=0;
              x=0;
            }
        }
        p++;
      }
    }
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M a k e M a g n i f y I m a g e                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMakeMagnifyImage magnifies a region of an X image and displays it.
%
%  The format of the XMakeMagnifyImage routine is:
%
%      XMakeMagnifyImage(display,windows)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o windows: Specifies a pointer to a XWindows structure.
%
%
*/
Export void XMakeMagnifyImage(Display *display,XWindows *windows)
{
#define Swap(x,y) ((x)^=(y), (y)^=(x), (x)^=(y))

  register int
    x,
    y;

  register unsigned char
    *p,
    *q;

  register unsigned int
    j,
    k,
    l;

  static char
    text[MaxTextExtent];

  static unsigned int
    previous_magnify = 0;

  static XWindowInfo
    magnify_window;

  unsigned int
    height,
    i,
    magnify,
    scanline_pad,
    width;

  XColor
    color;

  XImage
    *ximage;

  /*
    Check boundry conditions.
  */
  assert(display != (Display *) NULL);
  assert(windows != (XWindows *) NULL);
  magnify=1;
  for (i=1; i < windows->magnify.data; i++)
    magnify<<=1;
  while ((magnify*windows->image.ximage->width) < windows->magnify.width)
    magnify<<=1;
  while ((magnify*windows->image.ximage->height) < windows->magnify.height)
    magnify<<=1;
  while (magnify > windows->magnify.width)
    magnify>>=1;
  while (magnify > windows->magnify.height)
    magnify>>=1;
  if (magnify != previous_magnify)
    {
      unsigned int
        status;

      XTextProperty
        window_name;

      /*
        New magnify factor:  update magnify window name.
      */
      i=0;
      while ((1 << i) <= magnify)
        i++;
      (void) sprintf(windows->magnify.name,"Magnify %uX",i);
      status=XStringListToTextProperty(&windows->magnify.name,1,&window_name);
      if (status != 0)
        {
          XSetWMName(display,windows->magnify.id,&window_name);
          XSetWMIconName(display,windows->magnify.id,&window_name);
          XFree((void *) window_name.value);
        }
    }
  previous_magnify=magnify;
  ximage=windows->image.ximage;
  width=windows->magnify.ximage->width;
  height=windows->magnify.ximage->height;
  if ((windows->magnify.x < 0) ||
      (windows->magnify.x >= windows->image.ximage->width))
    windows->magnify.x=windows->image.ximage->width >> 1;
  x=windows->magnify.x-((width/magnify) >> 1);
  if (x < 0)
    x=0;
  else
    if (x > (ximage->width-(width/magnify)))
      x=ximage->width-width/magnify;
  if ((windows->magnify.y < 0) ||
      (windows->magnify.y >= windows->image.ximage->height))
    windows->magnify.y=windows->image.ximage->height >> 1;
  y=windows->magnify.y-((height/magnify) >> 1);
  if (y < 0)
    y=0;
  else
    if (y > (ximage->height-(height/magnify)))
      y=ximage->height-height/magnify;
  q=(unsigned char *) windows->magnify.ximage->data;
  scanline_pad=windows->magnify.ximage->bytes_per_line-
    ((width*windows->magnify.ximage->bits_per_pixel) >> 3);
  if (ximage->bits_per_pixel < 8)
    {
      register unsigned char
        background,
        byte,
        foreground,
        p_bit,
        q_bit;

      register unsigned int
        plane;

      XPixelInfo
        *pixel_info;

      pixel_info=windows->magnify.pixel_info;
      switch (ximage->bitmap_bit_order)
      {
        case LSBFirst:
        {
          /*
            Magnify little-endian bitmap.
          */
          background=0x00;
          foreground=0x80;
          if (ximage->format == XYBitmap)
            {
              background=(Intensity(pixel_info->foreground_color) <
                Intensity(pixel_info->background_color) ? 0x80 : 0x00);
              foreground=(Intensity(pixel_info->background_color) <
                Intensity(pixel_info->foreground_color) ? 0x80 : 0x00);
              if (windows->magnify.depth > 1)
                Swap(background,foreground);
            }
          for (i=0; i < height; i+=magnify)
          {
            /*
              Propogate pixel magnify rows.
            */
            for (j=0; j < magnify; j++)
            {
              p=(unsigned char *) ximage->data+y*ximage->bytes_per_line+
                ((x*ximage->bits_per_pixel) >> 3);
              p_bit=(x*ximage->bits_per_pixel) & 0x07;
              q_bit=0;
              byte=0;
              for (k=0; k < width; k+=magnify)
              {
                /*
                  Propogate pixel magnify columns.
                */
                for (l=0; l < magnify; l++)
                {
                  /*
                    Propogate each bit plane.
                  */
                  for (plane=0; plane < ximage->bits_per_pixel; plane++)
                  {
                    byte>>=1;
                    if (*p & (0x01 << (p_bit+plane)))
                      byte|=foreground;
                    else
                      byte|=background;
                    q_bit++;
                    if (q_bit == 8)
                      {
                        *q++=byte;
                        q_bit=0;
                        byte=0;
                      }
                  }
                }
                p_bit+=ximage->bits_per_pixel;
                if (p_bit == 8)
                  {
                    p++;
                    p_bit=0;
                  }
                if (q_bit != 0)
                  *q=byte >> (8-q_bit);
                q+=scanline_pad;
              }
            }
            y++;
          }
          break;
        }
        case MSBFirst:
        default:
        {
          /*
            Magnify big-endian bitmap.
          */
          background=0x00;
          foreground=0x01;
          if (ximage->format == XYBitmap)
            {
              background=(Intensity(pixel_info->foreground_color) <
                Intensity(pixel_info->background_color) ? 0x01 : 0x00);
              foreground=(Intensity(pixel_info->background_color) <
                Intensity(pixel_info->foreground_color) ? 0x01 : 0x00);
              if (windows->magnify.depth > 1)
                Swap(background,foreground);
            }
          for (i=0; i < height; i+=magnify)
          {
            /*
              Propogate pixel magnify rows.
            */
            for (j=0; j < magnify; j++)
            {
              p=(unsigned char *) ximage->data+y*ximage->bytes_per_line+
                ((x*ximage->bits_per_pixel) >> 3);
              p_bit=(x*ximage->bits_per_pixel) & 0x07;
              q_bit=0;
              byte=0;
              for (k=0; k < width; k+=magnify)
              {
                /*
                  Propogate pixel magnify columns.
                */
                for (l=0; l < magnify; l++)
                {
                  /*
                    Propogate each bit plane.
                  */
                  for (plane=0; plane < ximage->bits_per_pixel; plane++)
                  {
                    byte<<=1;
                    if (*p & (0x80 >> (p_bit+plane)))
                      byte|=foreground;
                    else
                      byte|=background;
                    q_bit++;
                    if (q_bit == 8)
                      {
                        *q++=byte;
                        q_bit=0;
                        byte=0;
                      }
                  }
                }
                p_bit+=ximage->bits_per_pixel;
                if (p_bit == 8)
                  {
                    p++;
                    p_bit=0;
                  }
                if (q_bit != 0)
                  *q=byte << (8-q_bit);
                q+=scanline_pad;
              }
            }
            y++;
          }
          break;
        }
      }
    }
  else
    switch (ximage->bits_per_pixel)
    {
      case 6:
      case 8:
      {
        /*
          Magnify 8 bit X image.
        */
        for (i=0; i < height; i+=magnify)
        {
          /*
            Propogate pixel magnify rows.
          */
          for (j=0; j < magnify; j++)
          {
            p=(unsigned char *) ximage->data+y*ximage->bytes_per_line+
              ((x*ximage->bits_per_pixel) >> 3);
            for (k=0; k < width; k+=magnify)
            {
              /*
                Propogate pixel magnify columns.
              */
              for (l=0; l < magnify; l++)
                *q++=(*p);
              p++;
            }
            q+=scanline_pad;
          }
          y++;
        }
        break;
      }
      default:
      {
        register unsigned int
          bytes_per_pixel,
          m;

        /*
          Magnify multi-byte X image.
        */
        bytes_per_pixel=ximage->bits_per_pixel >> 3;
        for (i=0; i < height; i+=magnify)
        {
          /*
            Propogate pixel magnify rows.
          */
          for (j=0; j < magnify; j++)
          {
            p=(unsigned char *) ximage->data+y*ximage->bytes_per_line+
              ((x*ximage->bits_per_pixel) >> 3);
            for (k=0; k < width; k+=magnify)
            {
              /*
                Propogate pixel magnify columns.
              */
              for (l=0; l < magnify; l++)
                for (m=0; m < bytes_per_pixel; m++)
                  *q++=(*(p+m));
              p+=bytes_per_pixel;
            }
            q+=scanline_pad;
          }
          y++;
        }
        break;
      }
    }
  /*
    Copy X image to magnify pixmap.
  */
  x=windows->magnify.x-((width/magnify) >> 1);
  if (x < 0)
    x=(width >> 1)-windows->magnify.x*magnify;
  else
    if (x > (ximage->width-(width/magnify)))
      x=(ximage->width-windows->magnify.x)*magnify-(width >> 1);
    else
      x=0;
  y=windows->magnify.y-((height/magnify) >> 1);
  if (y < 0)
    y=(height >> 1)-windows->magnify.y*magnify;
  else
    if (y > (ximage->height-(height/magnify)))
      y=(ximage->height-windows->magnify.y)*magnify-(height >> 1);
    else
      y=0;
  if ((x != 0) || (y != 0))
    XFillRectangle(display,windows->magnify.pixmap,
      windows->magnify.annotate_context,0,0,width,height);
  XPutImage(display,windows->magnify.pixmap,windows->magnify.annotate_context,
    windows->magnify.ximage,0,0,x,y,width-x,height-y);
  if ((magnify > 1) && ((magnify <= (width >> 1)) &&
      (magnify <= (height >> 1))))
    {
      RectangleInfo
        highlight_info;

      /*
        Highlight center pixel.
      */
      highlight_info.x=windows->magnify.width >> 1;
      highlight_info.y=windows->magnify.height >> 1;
      highlight_info.width=magnify;
      highlight_info.height=magnify;
      XDrawRectangle(display,windows->magnify.pixmap,
        windows->magnify.highlight_context,highlight_info.x,highlight_info.y,
        highlight_info.width-1,highlight_info.height-1);
      if (magnify > 2)
        XDrawRectangle(display,windows->magnify.pixmap,
          windows->magnify.annotate_context,highlight_info.x+1,
          highlight_info.y+1,highlight_info.width-3,highlight_info.height-3);
    }
  /*
    Show center pixel color.
  */
  color.pixel=
    XGetPixel(windows->image.ximage,windows->magnify.x,windows->magnify.y);
  XQueryColor(display,windows->image.map_info->colormap,&color);
  if (windows->magnify.depth > 12)
    (void) sprintf(text," %+d%+d  (%3u,%3u,%3u) ",
      windows->magnify.x,windows->magnify.y,XDownScale(color.red),
      XDownScale(color.green),XDownScale(color.blue));
  else
    (void) sprintf(text," %+d%+d  (%3u,%3u,%3u) %lu ",
      windows->magnify.x,windows->magnify.y,XDownScale(color.red),
      XDownScale(color.green),XDownScale(color.blue),color.pixel);
  height=windows->magnify.font_info->ascent+windows->magnify.font_info->descent;
  x=windows->magnify.font_info->max_bounds.width >> 1;
  y=windows->magnify.font_info->ascent+(height >> 2);
  XDrawImageString(display,windows->magnify.pixmap,
    windows->magnify.annotate_context,x,y,text,Extent(text));
  (void) sprintf(text," #%02x%02x%02x ",XDownScale(color.red),
    XDownScale(color.green),XDownScale(color.blue));
  y+=height;
  XDrawImageString(display,windows->magnify.pixmap,
    windows->magnify.annotate_context,x,y,text,Extent(text));
  /*
    Refresh magnify window.
  */
  magnify_window=windows->magnify;
  magnify_window.x=0;
  magnify_window.y=0;
  XRefreshWindow(display,&magnify_window,(XEvent *) NULL);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M a k e P i x m a p                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMakePixmap creates an X11 pixmap.
%
%  The format of the XMakePixmap routine is:
%
%      status=XMakePixmap(display,resource_info,window)
%
%  A description of each parameter follows:
%
%    o status: Function XMakePixmap returns True if the X pixmap is
%      successfully created.  False is returned is there is a memory shortage.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a XWindowInfo structure.
%
%
*/
unsigned int XMakePixmap(Display *display,const XResourceInfo *resource_info,
  XWindowInfo *window)
{
  unsigned int
    height,
    width;

  assert(display != (Display *) NULL);
  assert(resource_info != (XResourceInfo *) NULL);
  assert(window != (XWindowInfo  *) NULL);
  if (window->pixmap != (Pixmap) NULL)
    {
      /*
        Destroy previous X pixmap.
      */
      XFreePixmap(display,window->pixmap);
      window->pixmap=(Pixmap) NULL;
#ifdef HasSharedMemory
      if (window->shared_memory)
        if (window->segment_info[1].shmid >= 0)
          {
            XShmDetach(display,&window->segment_info[1]);
            XSync(display,False);
            shmdt(window->segment_info[1].shmaddr);
            window->segment_info[1].shmid=(-1);
          }
#endif
    }
  if (!window->use_pixmap)
    return(False);
  if (window->ximage == (XImage *) NULL)
    return(False);
  /*
    Display busy cursor.
  */
  XDefineCursor(display,window->id,window->busy_cursor);
  XFlush(display);
  /*
    Create pixmap.
  */
  width=window->ximage->width;
  height=window->ximage->height;
#ifdef HasSharedMemory
  if (window->shared_memory)
    {
      window->segment_info[3].shmid=(int) shmget(IPC_PRIVATE,
        window->ximage->bytes_per_line*height,IPC_CREAT | 0777);
      if (window->segment_info[3].shmid >= 0)
        {
          xerror_alert=False;
          window->segment_info[3].shmaddr=(char *)
            shmat(window->segment_info[3].shmid,0,0);
          window->segment_info[3].readOnly=False;
          XShmAttach(display,&window->segment_info[3]);
          window->pixmap=XShmCreatePixmap(display,window->id,
            window->segment_info[3].shmaddr,&window->segment_info[3],
            width,height,window->depth);
          if (window->pixmap != (Pixmap) NULL)
            window->segment_info[1]=window->segment_info[3];
          else
            {
              shmdt(window->segment_info[3].shmaddr);
              XShmDetach(display,&window->segment_info[3]);
            }
          XSync(display,False);
          shmctl(window->segment_info[3].shmid,IPC_RMID,0);
          if (xerror_alert)
            {
              window->pixmap=(Pixmap) NULL;
              xerror_alert=False;
            }
        }
    }
#endif
  if (window->pixmap == (Pixmap) NULL)
    window->pixmap=XCreatePixmap(display,window->id,width,height,window->depth);
  if (window->pixmap == (Pixmap) NULL)
    {
      /*
        Unable to allocate pixmap.
      */
      XDefineCursor(display,window->id,window->cursor);
      return(False);
    }
  /*
    Copy X image to pixmap.
  */
#ifdef HasSharedMemory
  if (window->shared_memory)
    XShmPutImage(display,window->pixmap,window->annotate_context,window->ximage,
      0,0,0,0,width,height,True);
#endif
  if (!window->shared_memory)
    XPutImage(display,window->pixmap,window->annotate_context,window->ximage,
      0,0,0,0,width,height);
  if (resource_info->debug)
    {
      (void) fprintf(stderr,"Pixmap:\n");
      (void) fprintf(stderr,"  width, height: %ux%u\n",width,height);
    }
  /*
    Restore cursor.
  */
  XDefineCursor(display,window->id,window->cursor);
  return(True);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M a k e S t a n d a r d C o l o r m a p                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMakeStandardColormap creates an X11 Standard Colormap.
%
%  The format of the XMakeStandardColormap routine is:
%
%      XMakeStandardColormap(display,visual_info,resource_info,image,
%        map_info,pixel_info)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
%      returned from XGetVisualInfo.
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%    o map_info: If a Standard Colormap type is specified, this structure is
%      initialized with info from the Standard Colormap.
%
%    o pixel_info: Specifies a pointer to a XPixelInfo structure.
%
%
*/

static int IntensityCompare(const void *x,const void *y)
{
  DiversityPacket
    *color_1,
    *color_2;

  color_1=(DiversityPacket *) x;
  color_2=(DiversityPacket *) y;
  return((int) Intensity(*color_2)-(int) Intensity(*color_1));
}

static int PopularityCompare(const void *x,const void *y)
{
  DiversityPacket
    *color_1,
    *color_2;

  color_1=(DiversityPacket *) x;
  color_2=(DiversityPacket *) y;
  return((int) color_2->count-(int) color_1->count);
}

Export void XMakeStandardColormap(Display *display,XVisualInfo *visual_info,
  XResourceInfo *resource_info,Image *image,XStandardColormap *map_info,
  XPixelInfo *pixel_info)
{
  Colormap
    colormap;

  int
    status;

  register int
    i;

  register XColor
    *gamma_map;

  unsigned int
    number_colors,
    retain_colors;

  unsigned short
    gray_value;

  XColor
    color,
    *colors,
    *p;

  assert(display != (Display *) NULL);
  assert(visual_info != (XVisualInfo *) NULL);
  assert(map_info != (XStandardColormap *) NULL);
  assert(resource_info != (XResourceInfo *) NULL);
  assert(pixel_info != (XPixelInfo *) NULL);
  if (resource_info->map_type != (char *) NULL)
    {
      /*
        Standard Colormap is already defined (i.e. xstdcmap).
      */
      XGetPixelInfo(display,visual_info,map_info,resource_info,image,
        pixel_info);
      number_colors=(unsigned int) (map_info->base_pixel+
        (map_info->red_max+1)*(map_info->green_max+1)*(map_info->blue_max+1));
      if ((map_info->red_max*map_info->green_max*map_info->blue_max) != 0)
        if (resource_info->dither && !resource_info->color_recovery &&
            (number_colors < MaxColormapSize) && !image->matte)
          {
            Image
              *map_image;

            register RunlengthPacket
              *p;

            /*
              Improve image appearance with error diffusion.
            */
            map_image=AllocateImage((ImageInfo *) NULL);
            if (map_image == (Image *) NULL)
              Error("Unable to dither image","Memory allocation failed");
            map_image->columns=number_colors;
            map_image->rows=1;
            map_image->packets=map_image->columns*map_image->rows;
            map_image->pixels=(RunlengthPacket *)
              malloc(map_image->packets*sizeof(RunlengthPacket));
            if (map_image->pixels == (RunlengthPacket *) NULL)
              Error("Unable to dither image","Memory allocation failed");
            /*
              Initialize colormap image.
            */
            p=map_image->pixels;
            for (i=0; i < number_colors; i++)
            {
              p->red=0;
              if (map_info->red_max != 0)
                p->red=(Quantum)
                  (((i/map_info->red_mult)*MaxRGB)/map_info->red_max);
              p->green=0;
              if (map_info->green_max != 0)
                p->green=(Quantum) ((((i/map_info->green_mult) %
                  (map_info->green_max+1))*MaxRGB)/map_info->green_max);
              p->blue=0;
              if (map_info->blue_max != 0)
                p->blue=(Quantum)
                  (((i % map_info->green_mult)*MaxRGB)/map_info->blue_max);
              p->index=0;
              p->length=0;
              p++;
            }
            MapImage(image,map_image,True);
            XGetPixelInfo(display,visual_info,map_info,resource_info,image,
              pixel_info);
            image->class=DirectClass;
            DestroyImage(map_image);
          }
      if (resource_info->debug)
        {
          (void) fprintf(stderr,"Standard Colormap:\n");
          (void) fprintf(stderr,"  colormap id: 0x%lx\n",map_info->colormap);
          (void) fprintf(stderr,"  red, green, blue max: %lu %lu %lu\n",
            map_info->red_max,map_info->green_max,map_info->blue_max);
          (void) fprintf(stderr,"  red, green, blue mult: %lu %lu %lu\n",
            map_info->red_mult,map_info->green_mult,map_info->blue_mult);
        }
      return;
    }
  if ((visual_info->class != DirectColor) && (visual_info->class != TrueColor))
    if ((image->class == DirectClass) ||
        (image->colors > visual_info->colormap_size))
      {
        QuantizeInfo
          quantize_info;

        /*
          Image has more colors than the visual supports.
        */
        if (image->matte)
          {
            ColorPacket
              background_color;

            register RunlengthPacket
              *p;

            /*
              Composite image with background color.
            */
            Warning("This visual does not support an image matte",
              XVisualClassName(visual_info->class));
            background_color=image->background_color;
            p=image->pixels;
            for (i=0; i < image->packets; i++)
            {
              if (p->index == Transparent)
                {
                  p->red=background_color.red;
                  p->green=background_color.green;
                  p->blue=background_color.blue;
                }
              else
                if (p->index != Opaque)
                  {
                    p->red=(long) (p->red*Opaque+background_color.red*
                      (Opaque-p->index))/Opaque;
                    p->green=(long) (p->green*Opaque+background_color.green*
                      (Opaque-p->index))/Opaque;
                    p->blue=(long) (p->blue*Opaque+background_color.blue*
                      (Opaque-p->index))/Opaque;
                  }
              p++;
            }
          }
        GetQuantizeInfo(&quantize_info);
        quantize_info.number_colors=visual_info->colormap_size;
        quantize_info.tree_depth=resource_info->tree_depth;
        quantize_info.dither=resource_info->dither;
        quantize_info.colorspace=resource_info->colorspace;
        QuantizeImage(&quantize_info,image);
        image->class=DirectClass;  /* promote to DirectClass */
      }
  /*
    Free previous and create new colormap.
  */
  XFreeStandardColormap(display,visual_info,map_info,pixel_info);
  colormap=XDefaultColormap(display,visual_info->screen);
  if (visual_info->visual != XDefaultVisual(display,visual_info->screen))
    colormap=XCreateColormap(display,XRootWindow(display,visual_info->screen),
      visual_info->visual,visual_info->class == DirectColor ?
      AllocAll : AllocNone);
  if (colormap == (Colormap) NULL)
    Error("Unable to create colormap",(char *) NULL);
  /*
    Initialize the map and pixel info structures.
  */
  XGetMapInfo(visual_info,colormap,map_info);
  XGetPixelInfo(display,visual_info,map_info,resource_info,image,pixel_info);
  gamma_map=pixel_info->gamma_map;
  /*
    Allocating colors in server colormap is based on visual class.
  */
  switch (visual_info->class)
  {
    case StaticGray:
    case StaticColor:
    {
      /*
        Define Standard Colormap for StaticGray or StaticColor visual.
      */
      number_colors=image->colors;
      colors=(XColor *) malloc(visual_info->colormap_size*sizeof(XColor));
      if (colors == (XColor *) NULL)
        Error("Unable to create colormap","Memory allocation failed");
      p=colors;
      color.flags=DoRed | DoGreen | DoBlue;
      if (visual_info->class == StaticColor)
        for (i=0; i < image->colors; i++)
        {
          color.red=XUpScale(gamma_map[image->colormap[i].red].red);
          color.green=XUpScale(gamma_map[image->colormap[i].green].green);
          color.blue=XUpScale(gamma_map[image->colormap[i].blue].blue);
          status=XAllocColor(display,colormap,&color);
          if (status == 0)
            {
              colormap=XCopyColormapAndFree(display,colormap);
              XAllocColor(display,colormap,&color);
            }
          pixel_info->pixels[i]=color.pixel;
          *p++=color;
        }
      else
        for (i=0; i < image->colors; i++)
        {
          gray_value=Intensity(gamma_map[Intensity(image->colormap[i])]);
          color.red=XUpScale(gray_value);
          color.green=XUpScale(gray_value);
          color.blue=XUpScale(gray_value);
          status=XAllocColor(display,colormap,&color);
          if (status == 0)
            {
              colormap=XCopyColormapAndFree(display,colormap);
              XAllocColor(display,colormap,&color);
            }
          pixel_info->pixels[i]=color.pixel;
          *p++=color;
        }
      break;
    }
    case GrayScale:
    case PseudoColor:
    {
      unsigned int
        colormap_type;

      /*
        Define Standard Colormap for GrayScale or PseudoColor visual.
      */
      number_colors=image->colors;
      colors=(XColor *) malloc(visual_info->colormap_size*sizeof(XColor));
      if (colors == (XColor *) NULL)
        Error("Unable to create colormap","Memory allocation failed");
      /*
        Preallocate our GUI colors.
      */
      (void) XAllocColor(display,colormap,&pixel_info->foreground_color);
      (void) XAllocColor(display,colormap,&pixel_info->background_color);
      (void) XAllocColor(display,colormap,&pixel_info->border_color);
      (void) XAllocColor(display,colormap,&pixel_info->matte_color);
      (void) XAllocColor(display,colormap,&pixel_info->highlight_color);
      (void) XAllocColor(display,colormap,&pixel_info->shadow_color);
      (void) XAllocColor(display,colormap,&pixel_info->depth_color);
      (void) XAllocColor(display,colormap,&pixel_info->trough_color);
      for (i=0; i < MaxNumberPens; i++)
        (void) XAllocColor(display,colormap,&pixel_info->pen_colors[i]);
      /*
        Determine if image colors will "fit" into X server colormap.
      */
      colormap_type=resource_info->colormap;
      status=XAllocColorCells(display,colormap,False,(unsigned long *) NULL,0,
        pixel_info->pixels,image->colors);
      if (status != 0)
        colormap_type=PrivateColormap;
      if (colormap_type == SharedColormap)
        {
          DiversityPacket
            *diversity;

          register RunlengthPacket
            *q;

          unsigned short
            index;

          /*
            Define Standard colormap for shared GrayScale or PseudoColor visual:
          */
          diversity=(DiversityPacket *)
            malloc(image->colors*sizeof(DiversityPacket));
          if (diversity == (DiversityPacket *) NULL)
            Error("Unable to create colormap","Memory allocation failed");
          for (i=0; i < image->colors; i++)
          {
            diversity[i].red=image->colormap[i].red;
            diversity[i].green=image->colormap[i].green;
            diversity[i].blue=image->colormap[i].blue;
            diversity[i].index=(unsigned short) i;
            diversity[i].count=0;
          }
          q=image->pixels;
          for (i=0; i < image->packets; i++)
          {
            diversity[q->index].count+=(q->length+1);
            q++;
          }
          /*
            Sort colors by decreasing intensity.
          */
          qsort((void *) diversity,image->colors,sizeof(DiversityPacket),
            (int (*)(const void *, const void *)) IntensityCompare);
          for (i=0; i < image->colors; i+=Max(image->colors >> 4,2))
            diversity[i].count<<=4;  /* increase this colors popularity */
          diversity[image->colors-1].count<<=4;
          qsort((void *) diversity,image->colors,sizeof(DiversityPacket),
            (int (*)(const void *, const void *)) PopularityCompare);
          /*
            Allocate colors.
          */
          p=colors;
          color.flags=DoRed | DoGreen | DoBlue;
          if (visual_info->class == PseudoColor)
            for (i=0; i < image->colors; i++)
            {
              index=diversity[i].index;
              color.red=XUpScale(gamma_map[image->colormap[index].red].red);
              color.green=
                XUpScale(gamma_map[image->colormap[index].green].green);
              color.blue=XUpScale(gamma_map[image->colormap[index].blue].blue);
              status=XAllocColor(display,colormap,&color);
              if (status == 0)
                break;
              pixel_info->pixels[index]=color.pixel;
              *p++=color;
            }
          else
            for (i=0; i < image->colors; i++)
            {
              index=diversity[i].index;
              gray_value=
                Intensity(gamma_map[Intensity(image->colormap[index])]);
              color.red=XUpScale(gray_value);
              color.green=XUpScale(gray_value);
              color.blue=XUpScale(gray_value);
              status=XAllocColor(display,colormap,&color);
              if (status == 0)
                break;
              pixel_info->pixels[index]=color.pixel;
              *p++=color;
            }
          if (i < image->colors)
            {
              register int
                j;

              XColor
                *server_colors;

              /*
                Read X server colormap.
              */
              server_colors=(XColor *)
                malloc(visual_info->colormap_size*sizeof(XColor));
              if (server_colors == (XColor *) NULL)
                Error("Unable to create colormap","Memory allocation failed");
              for (j=0; j < visual_info->colormap_size; j++)
                server_colors[j].pixel=(unsigned long) j;
              XQueryColors(display,colormap,server_colors,
                (int) Min(visual_info->colormap_size,256));
              /*
                Select remaining colors from X server colormap.
              */
              if (visual_info->class == PseudoColor)
                for (; i < image->colors; i++)
                {
                  index=diversity[i].index;
                  color.red=XUpScale(gamma_map[image->colormap[index].red].red);
                  color.green=
                    XUpScale(gamma_map[image->colormap[index].green].green);
                  color.blue=
                    XUpScale(gamma_map[image->colormap[index].blue].blue);
                  XBestPixel(display,colormap,server_colors,
                    (unsigned int) visual_info->colormap_size,&color);
                  pixel_info->pixels[index]=color.pixel;
                  *p++=color;
                }
              else
                for (; i < image->colors; i++)
                {
                  index=diversity[i].index;
                  gray_value=
                    Intensity(gamma_map[Intensity(image->colormap[index])]);
                  color.red=XUpScale(gray_value);
                  color.green=XUpScale(gray_value);
                  color.blue=XUpScale(gray_value);
                  XBestPixel(display,colormap,server_colors,
                    (unsigned int) visual_info->colormap_size,&color);
                  pixel_info->pixels[index]=color.pixel;
                  *p++=color;
                }
              if (image->colors < visual_info->colormap_size)
                {
                  /*
                    Fill up colors array-- more choices for pen colors.
                  */
                  retain_colors=
                    Min(visual_info->colormap_size-image->colors,256);
                  for (i=0; i < retain_colors; i++)
                    *p++=server_colors[i];
                  number_colors+=retain_colors;
                }
              free((char *) server_colors);
            }
          free((char *) diversity);
          break;
        }
      /*
        Define Standard colormap for private GrayScale or PseudoColor visual.
      */
      if (status == 0)
        {
          /*
            Not enough colormap entries in the colormap-- Create a new colormap.
          */
          colormap=XCreateColormap(display,
            XRootWindow(display,visual_info->screen),visual_info->visual,
            AllocNone);
          if (colormap == (Colormap) NULL)
            Error("Unable to create colormap",(char *) NULL);
          map_info->colormap=colormap;
          if (image->colors < visual_info->colormap_size)
            {
              /*
                Retain colors from the default colormap to help lessens the
                effects of colormap flashing.
              */
              retain_colors=Min(visual_info->colormap_size-image->colors,256);
              p=colors+image->colors;
              for (i=0; i < retain_colors; i++)
              {
                p->pixel=(unsigned long) i;
                p++;
              }
              XQueryColors(display,
                XDefaultColormap(display,visual_info->screen),
                colors+image->colors,(int) retain_colors);
              /*
                Transfer colors from default to private colormap.
              */
              XAllocColorCells(display,colormap,False,(unsigned long *) NULL,0,
                pixel_info->pixels,retain_colors);
              p=colors+image->colors;
              for (i=0; i < retain_colors; i++)
              {
                p->pixel=pixel_info->pixels[i];
                p++;
              }
              XStoreColors(display,colormap,colors+image->colors,retain_colors);
              number_colors+=retain_colors;
            }
          XAllocColorCells(display,colormap,False,(unsigned long *) NULL,0,
            pixel_info->pixels,image->colors);
        }
      /*
        Store the image colormap.
      */
      p=colors;
      color.flags=DoRed | DoGreen | DoBlue;
      if (visual_info->class == PseudoColor)
        for (i=0; i < image->colors; i++)
        {
          color.red=XUpScale(gamma_map[image->colormap[i].red].red);
          color.green=XUpScale(gamma_map[image->colormap[i].green].green);
          color.blue=XUpScale(gamma_map[image->colormap[i].blue].blue);
          color.pixel=pixel_info->pixels[i];
          *p++=color;
        }
      else
        for (i=0; i < image->colors; i++)
        {
          gray_value=Intensity(gamma_map[Intensity(image->colormap[i])]);
          color.red=XUpScale(gray_value);
          color.green=XUpScale(gray_value);
          color.blue=XUpScale(gray_value);
          color.pixel=pixel_info->pixels[i];
          *p++=color;
        }
      XStoreColors(display,colormap,colors,image->colors);
      break;
    }
    case TrueColor:
    case DirectColor:
    default:
    {
      unsigned int
        linear_colormap;

      /*
        Define Standard Colormap for TrueColor or DirectColor visual.
      */
      number_colors=(unsigned int) ((map_info->red_max*map_info->red_mult)+
        (map_info->green_max*map_info->green_mult)+
        (map_info->blue_max*map_info->blue_mult)+1);
      linear_colormap=(number_colors > 4096) ||
        (((map_info->red_max+1) == visual_info->colormap_size) &&
         ((map_info->green_max+1) == visual_info->colormap_size) &&
         ((map_info->blue_max+1) == visual_info->colormap_size));
      if (linear_colormap)
        number_colors=visual_info->colormap_size;
      /*
        Allocate color array.
      */
      colors=(XColor *) malloc(number_colors*sizeof(XColor));
      if (colors == (XColor *) NULL)
        Error("Unable to create colormap","Memory allocation failed");
      /*
        Initialize linear color ramp.
      */
      p=colors;
      color.flags=DoRed | DoGreen | DoBlue;
      if (linear_colormap)
        for (i=0; i < number_colors; i++)
        {
          color.blue=(unsigned short) 0;
          if (map_info->blue_max != 0)
            color.blue=(unsigned short)
              (((i % map_info->green_mult)*65535L)/map_info->blue_max);
          color.green=color.blue;
          color.red=color.blue;
          color.pixel=XStandardPixel(map_info,color,16);
          *p++=color;
        }
      else
        for (i=0; i < number_colors; i++)
        {
          color.red=(unsigned short) 0;
          if (map_info->red_max != 0)
            color.red=(unsigned short)
              (((i/map_info->red_mult)*65535L)/map_info->red_max);
          color.green=(unsigned short) 0;
          if (map_info->green_max != 0)
            color.green=(unsigned short) ((((i/map_info->green_mult) %
              (map_info->green_max+1))*65535L)/map_info->green_max);
          color.blue=(unsigned short) 0;
          if (map_info->blue_max != 0)
            color.blue=(unsigned short)
              (((i % map_info->green_mult)*65535L)/map_info->blue_max);
          color.pixel=XStandardPixel(map_info,color,16);
          *p++=color;
        }
      if ((visual_info->class == DirectColor) &&
          (colormap != XDefaultColormap(display,visual_info->screen)))
        XStoreColors(display,colormap,colors,number_colors);
      else
        for (i=0; i < number_colors; i++)
          XAllocColor(display,colormap,&colors[i]);
      break;
    }
  }
  if ((visual_info->class != DirectColor) && (visual_info->class != TrueColor))
    {
      /*
        Set foreground, background, border, etc. pixels.
      */
      XBestPixel(display,colormap,colors,number_colors,
        &pixel_info->foreground_color);
      XBestPixel(display,colormap,colors,number_colors,
        &pixel_info->background_color);
      if (pixel_info->background_color.pixel ==
          pixel_info->foreground_color.pixel)
        {
          /*
            Foreground and background colors must differ.
          */
          pixel_info->background_color.red=(~pixel_info->foreground_color.red);
          pixel_info->background_color.green=
            (~pixel_info->foreground_color.green);
          pixel_info->background_color.blue=
            (~pixel_info->foreground_color.blue);
          XBestPixel(display,colormap,colors,number_colors,
            &pixel_info->background_color);
        }
      XBestPixel(display,colormap,colors,number_colors,
        &pixel_info->border_color);
      XBestPixel(display,colormap,colors,number_colors,
        &pixel_info->matte_color);
      XBestPixel(display,colormap,colors,number_colors,
        &pixel_info->highlight_color);
      XBestPixel(display,colormap,colors,number_colors,
        &pixel_info->shadow_color);
      XBestPixel(display,colormap,colors,number_colors,
        &pixel_info->depth_color);
      XBestPixel(display,colormap,colors,number_colors,
        &pixel_info->trough_color);
      for (i=0; i < MaxNumberPens; i++)
      {
        XBestPixel(display,colormap,colors,number_colors,
          &pixel_info->pen_colors[i]);
        pixel_info->pixels[image->colors+i]=pixel_info->pen_colors[i].pixel;
      }
      pixel_info->colors=image->colors+MaxNumberPens;
    }
  free((char *) colors);
  if (resource_info->debug)
    {
      (void) fprintf(stderr,"Standard Colormap:\n");
      (void) fprintf(stderr,"  colormap id: 0x%lx\n",map_info->colormap);
      (void) fprintf(stderr,"  red, green, blue max: %lu %lu %lu\n",
        map_info->red_max,map_info->green_max,map_info->blue_max);
      (void) fprintf(stderr,"  red, green, blue mult: %lu %lu %lu\n",
        map_info->red_mult,map_info->green_mult,map_info->blue_mult);
    }
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M a k e W i n d o w                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMakeWindow creates an X11 window.
%
%  The format of the XMakeWindow routine is:
%
%      XMakeWindow(display,parent,argv,argc,class_hint,manager_hints,
%        window_info)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o parent: Specifies the parent window_info.
%
%    o argv: Specifies the application's argument list.
%
%    o argc: Specifies the number of arguments.
%
%    o class_hint: Specifies a pointer to a X11 XClassHint structure.
%
%    o manager_hints: Specifies a pointer to a X11 XWMHints structure.
%
%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
%
%
*/
Export void XMakeWindow(Display *display,Window parent,char **argv,int argc,
  XClassHint *class_hint,XWMHints *manager_hints,XWindowInfo *window_info)
{
#define MinWindowSize  64

  Atom
    atom_list[2];

  int
    gravity,
    status;

  static XTextProperty
    icon_name,
    window_name;

  XSizeHints
    *size_hints;

  /*
    Set window info hints.
  */
  assert(display != (Display *) NULL);
  assert(window_info != (XWindowInfo *) NULL);
  size_hints=XAllocSizeHints();
  if (size_hints == (XSizeHints *) NULL)
    Error("Unable to make X window","Memory allocation failed");
  size_hints->flags=(long) window_info->flags;
  size_hints->x=window_info->x;
  size_hints->y=window_info->y;
  size_hints->width=window_info->width;
  size_hints->height=window_info->height;
  if (window_info->immutable)
    {
      /*
        Window size cannot be changed.
      */
      size_hints->min_width=size_hints->width;
      size_hints->min_height=size_hints->height;
      size_hints->max_width=size_hints->width;
      size_hints->max_height=size_hints->height;
      size_hints->flags|=PMinSize;
      size_hints->flags|=PMaxSize;
    }
  else
    {
      /*
        Window size can be changed.
      */
      size_hints->min_width=window_info->min_width;
      size_hints->min_height=window_info->min_height;
      size_hints->flags|=PResizeInc;
      size_hints->width_inc=window_info->width_inc;
      size_hints->height_inc=window_info->height_inc;
#ifndef PRE_R4_ICCCM
      size_hints->flags|=PBaseSize;
      size_hints->base_width=size_hints->width_inc;
      size_hints->base_height=size_hints->height_inc;
#endif
    }
  gravity=NorthWestGravity;
  if (window_info->geometry != (char *) NULL)
    {
      char
        default_geometry[MaxTextExtent],
        geometry[MaxTextExtent];

      int
        flags;

      register char
        *p;

      /*
        User specified geometry.
      */
      (void) sprintf(default_geometry,"%dx%d",size_hints->width,
        size_hints->height);
      (void) strcpy(geometry,window_info->geometry);
      p=geometry;
      while (Extent(p) > 0)
      {
        if (!isspace(*p) && (*p != '%'))
          p++;
        else
          (void) strcpy(p,p+1);
      }
      flags=XWMGeometry(display,window_info->screen,geometry,default_geometry,
        window_info->border_width,size_hints,&size_hints->x,&size_hints->y,
        &size_hints->width,&size_hints->height,&gravity);
      if ((flags & WidthValue) && (flags & HeightValue))
        size_hints->flags|=USSize;
      if ((flags & XValue) && (flags & YValue))
        {
          size_hints->flags|=USPosition;
          window_info->x=size_hints->x;
          window_info->y=size_hints->y;
        }
    }
#ifndef PRE_R4_ICCCM
  size_hints->win_gravity=gravity;
  size_hints->flags|=PWinGravity;
#endif
  if (window_info->id == (Window) NULL)
    window_info->id=XCreateWindow(display,parent,window_info->x,window_info->y,
      window_info->width,window_info->height,window_info->border_width,
      window_info->depth,InputOutput,window_info->visual,window_info->mask,
      &window_info->attributes);
  else
    {
      unsigned int
        mask;

      XEvent
        sans_event;

      XWindowChanges
        window_changes;

      /*
        Window already exists;  change relevant attributes.
      */
      XChangeWindowAttributes(display,window_info->id,window_info->mask,
        &window_info->attributes);
      mask=ConfigureNotify;
      while (XCheckTypedWindowEvent(display,window_info->id,mask,&sans_event));
      window_changes.x=window_info->x;
      window_changes.y=window_info->y;
      window_changes.width=window_info->width;
      window_changes.height=window_info->height;
      mask=CWWidth | CWHeight;
      if (window_info->flags & USPosition)
        mask|=CWX | CWY;
      XReconfigureWMWindow(display,window_info->id,window_info->screen,mask,
        &window_changes);
    }
  if (window_info->id == (Window) NULL)
    Error("Unable to create window",window_info->name);
  status=XStringListToTextProperty(&window_info->name,1,&window_name);
  if (status == 0)
    Error("Unable to create text property",window_info->name);
  status=XStringListToTextProperty(&window_info->icon_name,1,&icon_name);
  if (status == 0)
    Error("Unable to create text property",window_info->icon_name);
  if (window_info->icon_geometry != (char *) NULL)
    {
      int
        flags,
        gravity,
        height,
        width;

      /*
        User specified icon geometry.
      */
      size_hints->flags|=USPosition;
      flags=XWMGeometry(display,window_info->screen,window_info->icon_geometry,
        (char *) NULL,0,size_hints,&manager_hints->icon_x,
        &manager_hints->icon_y,&width,&height,&gravity);
      if ((flags & XValue) && (flags & YValue))
        manager_hints->flags|=IconPositionHint;
    }
  XSetWMProperties(display,window_info->id,&window_name,&icon_name,argv,argc,
    size_hints,manager_hints,class_hint);
  if (window_name.nitems != 0)
    XFree((void *) window_name.value);
  if (icon_name.nitems != 0)
    XFree((void *) icon_name.value);
  atom_list[0]=XInternAtom(display,"WM_DELETE_WINDOW",False);
  atom_list[1]=XInternAtom(display,"WM_TAKE_FOCUS",False);
  XSetWMProtocols(display,window_info->id,atom_list,2);
  XFree((void *) size_hints);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M o n t a g e I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMontageImages creates a composite image by combining several
%  separate images.
%
%  The format of the MontageImages routine is:
%
%      XMontageImages(resource_info,montage_info,image)
%
%  A description of each parameter follows:
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%    o montage_info: Specifies a pointer to a XMontageInfo structure.
%
%    o image: Specifies a pointer to an array of Image structures.
%
%
*/

static void FormatLabel(XFontStruct *font_info,char *label,
  const unsigned int width)
{
  register char
    *p,
    *q;

  if (label == (char *) NULL)
    return;
  if (strchr(label,'\n') != (char *) NULL)
    return;
  /*
    Format label to fit within a specified width.
  */
  p=label;
  for (q=p; *q != '\0'; q++)
    if (XTextWidth(font_info,p,(int) (q-p)) > width)
      {
        while ((*q != ' ') && (q > p))
          q--;
        if (q == p)
          break;
        *q='\n';
        p=q+1;
      }
}

static int SceneCompare(const void *x,const void *y)
{
  Image
    **image_1,
    **image_2;

  image_1=(Image **) x;
  image_2=(Image **) y;
  return((int) (*image_1)->scene-(int) (*image_2)->scene);
}

Export Image *XMontageImages(const XResourceInfo *resource_info,
  XMontageInfo *montage_info,Image *image)
{
#define MontageImageText  "  Creating visual image directory...  "
#define TileImageText  "  Creating image tiles...  "

  AnnotateInfo
    annotate_info;

  char
    geometry[MaxTextExtent];

  ColorPacket
    background_color;

  Display
    *display;

  FrameInfo
    frame_info;

  Image
    **images,
    *montage_image,
    *sharpened_image,
    *tile_image;

  int
    x,
    x_offset,
    y,
    y_offset;

  MonitorHandler
    handler;

  register int
    i;

  register RunlengthPacket
    *p;

  RectangleInfo
    bounding_box,
    tile_info;

  unsigned int
    border_width,
    bevel_width,
    concatenate,
    count,
    font_height,
    height,
    images_per_page,
    max_height,
    number_images,
    number_lines,
    tile,
    tiles,
    tiles_per_column,
    tiles_per_row,
    tiles_per_page,
    title_offset,
    total_tiles,
    width;

  XColor
    color;

  assert(resource_info != (XResourceInfo *) NULL);
  assert(montage_info != (XMontageInfo *) NULL);
  assert(image != (Image *) NULL);
  /*
    Convert image list to an image group.
  */
  images=ListToGroupImage(image,&number_images);
  if (images == (Image **) NULL)
    {
      Warning("Unable to montage images","Memory allocation failed");
      return((Image *) NULL);
    }
  /*
    Create image tiles.
  */
  for (tile=0; tile < number_images; tile++)
  {
    handler=SetMonitorHandler((MonitorHandler) NULL);
    width=images[tile]->columns;
    height=images[tile]->rows;
    (void) ParseImageGeometry(resource_info->image_geometry,&x,&y,&width,
      &height);
    tile_image=ZoomImage(images[tile],width,height,montage_info->filter);
    if (tile_image == (Image *) NULL)
      {
        for (i=0; i < tile; i++)
          DestroyImage(images[i]);
        (void) SetMonitorHandler(handler);
        return((Image *) NULL);
      }
    images[tile]=tile_image;
    if ((tile_image->columns < 3) || (tile_image->rows < 3))
      continue;
    sharpened_image=SharpenImage(tile_image,SharpenFactor);
    if (sharpened_image != (Image *) NULL)
      {
        DestroyImage(tile_image);
        tile_image=sharpened_image;
      }
    images[tile]=tile_image;
    (void) SetMonitorHandler(handler);
    ProgressMonitor(TileImageText,tile,number_images);
  }
  /*
    Sort images by increasing tile number.
  */
  for (tile=0; tile < number_images; tile++)
    if (images[tile]->scene == 0)
      break;
  if (tile == number_images)
    qsort((void *) images,number_images,sizeof(Image *),
      (int (*)(const void *, const void *)) SceneCompare);
  /*
    Determine tiles per row and column.
  */
  tiles_per_row=1;
  tiles_per_column=1;
  while ((tiles_per_row*tiles_per_column) < number_images)
  {
    tiles_per_row++;
    tiles_per_column++;
  }
  if (montage_info->tile != (char *) NULL)
    {
      tiles_per_column=number_images;
      XParseGeometry(montage_info->tile,&x,&y,&tiles_per_row,&tiles_per_column);
    }
  /*
    Determine tile sizes.
  */
  border_width=resource_info->border_width;
  bevel_width=0;
  if (montage_info->frame != (char *) NULL)
    {
      int
        flags;

      frame_info.width=0;
      frame_info.height=0;
      flags=XParseGeometry(montage_info->frame,&frame_info.outer_bevel,
        &frame_info.inner_bevel,&frame_info.width,&frame_info.height);
      if ((flags & HeightValue) == 0)
        frame_info.height=frame_info.width;
      if ((flags & XValue) == 0)
        frame_info.outer_bevel=(frame_info.width >> 2)+1;
      if ((flags & YValue) == 0)
        frame_info.inner_bevel=frame_info.outer_bevel;
      frame_info.x=frame_info.width;
      frame_info.y=frame_info.height;
      bevel_width=Max(frame_info.inner_bevel,frame_info.outer_bevel);
      border_width=Max(frame_info.width,frame_info.height);
    }
  tile_info.x=resource_info->border_width;
  tile_info.y=resource_info->border_width;
  tile_info.width=images[0]->columns;
  tile_info.height=images[0]->rows;
  concatenate=False;
  if (resource_info->image_geometry != (char *) NULL)
    {
      int
        flags;

      /*
        Initialize tile geometry.
      */
      (void) strcpy(geometry,resource_info->image_geometry);
      (void) strcat(geometry,"~");
      flags=ParseImageGeometry(geometry,&tile_info.x,&tile_info.y,
        &tile_info.width,&tile_info.height);
      if ((tile_info.x == 0) && (tile_info.y == 0))
        concatenate=!((flags & WidthValue) || (flags & HeightValue));
      if (tile_info.x < 0)
        tile_info.x=0;
      if (tile_info.y < 0)
        tile_info.y=0;
    }
  for (tile=1; tile < number_images; tile++)
  {
    if (images[tile]->columns > tile_info.width)
      tile_info.width=images[tile]->columns;
    if (images[tile]->rows > tile_info.height)
      tile_info.height=images[tile]->rows;
  }
  /*
    Initialize tile colors.
  */
  (void) XQueryColorDatabase(resource_info->background_color,&color);
  background_color.red=XDownScale(color.red);
  background_color.green=XDownScale(color.green);
  background_color.blue=XDownScale(color.blue);
  background_color.index=0;
  /*
    Initialize annotate info.
  */
  GetAnnotateInfo(&annotate_info);
  annotate_info.server_name=resource_info->server_name;
  annotate_info.font=resource_info->font;
  annotate_info.pen=resource_info->foreground_color;
  annotate_info.pointsize=montage_info->pointsize;
  annotate_info.geometry=geometry;
  annotate_info.alignment=CenterAlignment;
  font_height=montage_info->pointsize;
  display=XOpenDisplay(resource_info->server_name);
  if (display != (Display *) NULL)
    {
      XFontStruct
        *font_info;

      /*
        Initialize font info.
      */
      font_info=XBestFont(display,resource_info,False);
      if (font_info == (XFontStruct *) NULL)
        {
          Warning("Unable to montage images","Memory allocation failed");
          return((Image *) NULL);
        }
      FormatLabel(font_info,resource_info->title,((tile_info.width+
        (border_width << 1))*Min(number_images,tiles_per_column)) >> 1);
      for (tile=0; tile < number_images; tile++)
        FormatLabel(font_info,images[tile]->label,tile_info.width+
          (border_width << 1));
      font_height=font_info->ascent+font_info->descent;
      XFreeFont(display,font_info);
      XCloseDisplay(display);
    }
  /*
    Determine the number of lines in an image label.
  */
  title_offset=0;
  if (resource_info->title != (char *) NULL)
    title_offset=((font_height*MultilineCensus(resource_info->title)) << 1)+
      (tile_info.y << 1);
  number_lines=0;
  for (tile=0; tile < number_images; tile++)
    if (MultilineCensus(images[tile]->label) > number_lines)
      number_lines=MultilineCensus(images[tile]->label);
  /*
    Allocate image structure.
  */
  montage_image=AllocateImage((ImageInfo *) NULL);
  if (montage_image == (Image *) NULL)
    {
      Warning("Unable to montage images","Memory allocation failed");
      return((Image *) NULL);
    }
  montage_image->scene=1;
  images_per_page=
    (number_images-1)/(tiles_per_row*tiles_per_column)+1;
  tiles=0;
  total_tiles=number_images;
  for (i=0; i < images_per_page; i++)
  {
    /*
      Determine bounding box.
    */
    tiles_per_page=Min(number_images,tiles_per_row*tiles_per_column);
    x_offset=0;
    y_offset=title_offset;
    max_height=0;
    bounding_box.width=0;
    bounding_box.height=0;
    for (tile=0; tile < tiles_per_page; tile++)
    {
      width=concatenate ? images[tile]->columns : tile_info.width;
      x_offset+=width+(tile_info.x+border_width)*2;
      if (x_offset > bounding_box.width)
        bounding_box.width=x_offset;
      if (images[tile]->rows > max_height)
        max_height=images[tile]->rows;
      if (((tile+1) == tiles_per_page) || (((tile+1) % tiles_per_row) == 0))
        {
          x_offset=0;
          height=concatenate ? max_height : tile_info.height;
          y_offset+=height+(tile_info.y+border_width)*2+(font_height+2)*
            number_lines+(montage_info->shadow ? 4 : 0);
          if (y_offset > bounding_box.height)
            bounding_box.height=y_offset;
          max_height=0;
        }
    }
    /*
      Initialize Image structure.
    */
    (void) strcpy(montage_image->filename,montage_info->filename);
    montage_image->columns=bounding_box.width;
    montage_image->rows=bounding_box.height;
    montage_image->packets=montage_image->columns*montage_image->rows;
    montage_image->pixels=(RunlengthPacket *)
      malloc((unsigned int) montage_image->packets*sizeof(RunlengthPacket));
    if (montage_image->pixels == (RunlengthPacket *) NULL)
      {
        Warning("Unable to montage images","Memory allocation failed");
        DestroyImages(montage_image);
        return((Image *) NULL);
      }
    if (!concatenate)
      {
        /*
          Set montage geometry.
        */
        montage_image->montage=(char *) malloc(MaxTextExtent*sizeof(char));
        count=1;
        for (tile=0; tile < tiles_per_page; tile++)
          count+=Extent(images[tile]->filename)+1;
        montage_image->directory=(char *) malloc(count*sizeof(char));
        if ((montage_image->montage == (char *) NULL) ||
            (montage_image->directory == (char *) NULL))
          {
            Warning("Unable to montage images","Memory allocation failed");
            DestroyImages(montage_image);
            return((Image *) NULL);
          }
        x_offset=0;
        y_offset=title_offset;
        (void) sprintf(montage_image->montage,"%dx%d%+d%+d",
          (int) (tile_info.width+(tile_info.x+border_width)*2),
          (int) (tile_info.height+(tile_info.y+border_width)*2+(font_height+2)*
          number_lines+(montage_info->shadow ? 4 : 0)),x_offset,y_offset);
        *montage_image->directory='\0';
        for (tile=0; tile < tiles_per_page; tile++)
        {
          (void) strcat(montage_image->directory,images[tile]->filename);
          (void) strcat(montage_image->directory,"\n");
        }
      }
    /*
      Initialize montage image to background color.
    */
    p=montage_image->pixels;
    for (x=0; x < montage_image->packets; x++)
    {
      p->red=background_color.red;
      p->green=background_color.green;
      p->blue=background_color.blue;
      p->index=0;
      p->length=0;
      p++;
    }
    handler=SetMonitorHandler((MonitorHandler) NULL);
    if (montage_info->texture != (char *) NULL)
      TextureImage(montage_image,montage_info->texture);
    if (resource_info->title != (char *) NULL)
      {
        /*
          Annotate composite image with title.
        */
        (void) sprintf(annotate_info.geometry,"%ux%u%+d%+d",
          montage_image->columns,font_height << 1,0,tile_info.y+4);
        annotate_info.text=resource_info->title;
        AnnotateImage(montage_image,&annotate_info);
      }
    (void) SetMonitorHandler(handler);
    /*
      Copy tile images to the composite image.
    */
    x_offset=tile_info.x;
    y_offset=title_offset+tile_info.y;
    max_height=0;
    for (tile=0; tile < tiles_per_page; tile++)
    {
      /*
        Copy this tile to the composite image.
      */
      handler=SetMonitorHandler((MonitorHandler) NULL);
      image=images[tile];
      width=concatenate ? image->columns : tile_info.width;
      if (image->rows > max_height)
        max_height=image->rows;
      height=concatenate ? max_height : tile_info.height;
      if (border_width != 0)
        {
          Image
            *bordered_image;

          RectangleInfo
            border_info;

          /*
            Put a border around the image.
          */
          border_info.width=border_width;
          border_info.height=border_width;
          if (montage_info->frame != (char *) NULL)
            {
              border_info.width=(width-image->columns+1) >> 1;
              border_info.height=(height-image->rows+1) >> 1;
            }
          bordered_image=BorderImage(image,&border_info);
          if (bordered_image != (Image *) NULL)
            {
              DestroyImage(image);
              image=bordered_image;
            }
          image->matte=False;
        }
      /*
        Gravitate image as specified by the tile gravity.
      */
      switch (resource_info->gravity)
      {
        case NorthWestGravity:
        {
          x=0;
          y=0;
          break;
        }
        case NorthGravity:
        {
          x=((width+(border_width << 1))-image->columns) >> 1;
          y=0;
          break;
        }
        case NorthEastGravity:
        {
          x=(width+(border_width << 1))-image->columns;
          y=0;
          break;
        }
        case WestGravity:
        {
          x=0;
          y=((height+(border_width << 1))-image->rows) >> 1;
          break;
        }
        case ForgetGravity:
        case StaticGravity:
        case CenterGravity:
        default:
        {
          x=((width+(border_width << 1))-image->columns) >> 1;
          y=((height+(border_width << 1))-image->rows) >> 1;
          break;
        }
        case EastGravity:
        {
          x=(width+(border_width << 1))-image->columns;
          y=((height+(border_width << 1))-image->rows) >> 1;
          break;
        }
        case SouthWestGravity:
        {
          x=0;
          y=(height+(border_width << 1))-image->rows;
          break;
        }
        case SouthGravity:
        {
          x=((width+(border_width << 1))-image->columns) >> 1;
          y=(height+(border_width << 1))-image->rows;
          break;
        }
        case SouthEastGravity:
        {
          x=(width+(border_width << 1))-image->columns;
          y=(height+(border_width << 1))-image->rows;
          break;
        }
      }
      if ((montage_info->frame != (char *) NULL) && (bevel_width != 0))
        {
          FrameInfo
            tile_info;

          Image
            *framed_image;

          /*
            Put an ornamental border around this tile.
          */
          tile_info=frame_info;
          tile_info.width=width+(frame_info.width << 1);
          tile_info.height=height+(frame_info.height << 1)+
            (font_height+2)*MultilineCensus(image->label);
          framed_image=FrameImage(image,&tile_info);
          if (framed_image != (Image *) NULL)
            {
              DestroyImage(image);
              image=framed_image;
            }
          x=0;
          y=0;
        }
      if (strcmp(image->magick,"NULL") != 0)
        {
          /*
            Composite background image with tile image.
          */
          CompositeImage(montage_image,montage_info->compose,image,
            x_offset+x,y_offset+y);
          if (montage_info->shadow)
            {
              register int
                columns,
                rows;

              /*
                Put a shadow under the tile to show depth.
              */
              for (rows=0; rows < ((int) image->rows-4); rows++)
              {
                p=montage_image->pixels+montage_image->columns*
                  (y_offset+y+rows+4)+x_offset+x+image->columns;
                for (columns=0; columns < Min(tile_info.x,4); columns++)
                {
                  if (p >= (montage_image->pixels+montage_image->packets))
                    continue;
                  Modulate(0.0,0.0,-25.0+4*columns,&p->red,&p->green,&p->blue);
                  p++;
                }
              }
              for (rows=0; rows < Min(tile_info.y,4); rows++)
              {
                p=montage_image->pixels+montage_image->columns*
                  (y_offset+y+image->rows+rows)+x_offset+x+4;
                for (columns=0; columns < image->columns; columns++)
                {
                  if (p >= (montage_image->pixels+montage_image->packets))
                    continue;
                  Modulate(0.0,0.0,-25.0+4*rows,&p->red,&p->green,&p->blue);
                  p++;
                }
              }
            }
          if (image->label != (char *) NULL)
            {
              /*
                Annotate composite image tile with label.
              */
              (void) sprintf(annotate_info.geometry,"%ux%u%+d%+d",
                (montage_info->frame ? image->columns : width)-
                (border_width << 1),font_height,(int) (x_offset+border_width),
                (int) (montage_info->frame ? y_offset+height+
                (border_width << 1)-bevel_width-2 : y_offset+tile_info.height+
                (border_width << 1)+2+(montage_info->shadow ? 4 : 0)));
              annotate_info.text=image->label;
              AnnotateImage(montage_image,&annotate_info);
            }
        }
      x_offset+=width+(tile_info.x+border_width)*2;
      if (((tile+1) == tiles_per_page) || (((tile+1) % tiles_per_row) == 0))
        {
          x_offset=tile_info.x;
          y_offset+=height+(tile_info.y+border_width)*2+(font_height+2)*
            number_lines+(montage_info->shadow ? 4 : 0);
          max_height=0;
        }
      DestroyImage(image);
      (void) SetMonitorHandler(handler);
      ProgressMonitor(MontageImageText,tiles,total_tiles);
      tiles++;
    }
    CompressImage(montage_image);
    if ((i+1) < images_per_page)
      {
        /*
          Allocate next image structure.
        */
        montage_image->next=AllocateImage((ImageInfo *) NULL);
        if (montage_image->next == (Image *) NULL)
          {
            DestroyImages(montage_image);
            return((Image *) NULL);
          }
        (void) strcpy(montage_image->next->filename,montage_info->filename);
        montage_image->next->file=montage_image->file;
        montage_image->next->scene=montage_image->scene+1;
        montage_image->next->previous=montage_image;
        montage_image=montage_image->next;
        images+=tiles_per_page;
        number_images-=tiles_per_page;
      }
  }
  free((char *) images);
  while (montage_image->previous != (Image *) NULL)
    montage_image=montage_image->previous;
  return(montage_image);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X Q u e r y C o l o r D a t a b a s e                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XQueryColorDatabase looks up a RGB values for a color given in the
%  target string.
%
%  The format of the XQueryColorDatabase routine is:
%
%    status=XQueryColorDatabase(target,color)
%
%  A description of each parameter follows:
%
%    o status:  Function XQueryColorDatabase returns True if the RGB values
%      of the target color is defined, otherwise False is returned.
%
%    o target: Specifies the color to lookup in the X color database.
%
%    o color: A pointer to an XColor structure.  The RGB value of the target
%      color is returned as this value.
%
%
*/
unsigned int XQueryColorDatabase(const char *target,XColor *color)
{
  char
    colorname[MaxTextExtent],
    text[MaxTextExtent];

  Colormap
    colormap;

  int
    blue,
    count,
    green,
    red,
    status;

  register XColorlist
    *p;

  static Display
    *display = (Display *) NULL;

  static FILE
    *database = (FILE *) NULL;

  /*
    Initialize color return value.
  */
  assert(color != (XColor *) NULL);
  color->red=0;
  color->green=0;
  color->blue=0;
  color->flags=DoRed | DoGreen | DoBlue;
  if (target == (char *) NULL)
    target=BackgroundColor;
  while (isspace(*target))
    target++;
  if (*target == '#')
    {
      char
        c;

      register int
        i;

      unsigned long
        n;

      /*
        Parse RGB specification.
      */
      target++;
      n=Extent(target);
      if ((n != 3) && (n != 6) && (n != 9) && (n != 12))
        return(False);
      n/=3;
      green=0;
      blue=0;
      do
      {
        red=green;
        green=blue;
        blue=0;
        for (i=(int) n-1; i >= 0; i--)
        {
          c=(*target++);
          blue<<=4;
          if ((c >= '0') && (c <= '9'))
            blue|=c-'0';
          else
            if ((c >= 'A') && (c <= 'F'))
              blue|=c-('A'-10);
            else
              if ((c >= 'a') && (c <= 'f'))
                blue|=c-('a'-10);
              else
                return(False);
         }
      } while (*target != '\0');
      n<<=2;
      n=16-n;
      color->red=red << n;
      color->green=green << n;
      color->blue=blue << n;
      return(True);
    }
  if (database == (FILE *) NULL)
    database=fopen(RGBColorDatabase,"r");
  if (database != (FILE *) NULL)
    {
      /*
        Match color against the X color database.
      */
      (void) fseek(database,0L,SEEK_SET);
      while (fgets(text,MaxTextExtent,database) != (char *) NULL)
      {
        count=sscanf(text,"%d %d %d %[^\n]\n",&red,&green,&blue,colorname);
        if (count != 4)
          continue;
        if (Latin1Compare(colorname,target) == 0)
          {
            color->red=red << 8;
            color->green=green << 8;
            color->blue=blue << 8;
            return(True);
          }
      }
    }
  /*
    Search our internal color database.
  */
  for (p=Colorlist; p->name != (char *) NULL; p++)
    if (Latin1Compare(p->name,target) == 0)
      {
        color->red=p->red << 8;
        color->green=p->green << 8;
        color->blue=p->blue << 8;
        return(True);
      }
  /*
    Let the X server define the color for us.
  */
  if (display == (Display *) NULL)
    display=XOpenDisplay((char *) NULL);
  if (display == (Display *) NULL)
    {
      Warning("Color is not known to X server",target);
      return(False);
    }
  colormap=XDefaultColormap(display,XDefaultScreen(display));
  status=XParseColor(display,colormap,target,color);
  if (status == False)
    Warning("Color is not known to X server",target);
  return(status != 0);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X Q u e r y P o s i t i o n                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XQueryPosition gets the pointer coodinates relative to a window.
%
%  The format of the XQueryPosition routine is:
%
%    XQueryPosition(display,window,x,y)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a Window.
%
%    o x: Return the x coordinate of the pointer relative to the origin of the
%      window.
%
%    o y: Return the y coordinate of the pointer relative to the origin of the
%      window.
%
%
*/
Export void XQueryPosition(Display *display,const Window window,int *x,int *y)
{
  int
    x_root,
    y_root;

  unsigned int
    mask;

  Window
    root_window;

  assert(display != (Display *) NULL);
  assert(window != (Window) NULL);
  assert(x != (int *) NULL);
  assert(y != (int *) NULL);
  (void) XQueryPointer(display,window,&root_window,&root_window,&x_root,&y_root,
    x,y,&mask);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X R e f r e s h W i n d o w                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XRefreshWindow refreshes an image in a X window.
%
%  The format of the XRefreshWindow routine is:
%
%      XRefreshWindow(display,window,event)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a XWindowInfo structure.
%
%    o event: Specifies a pointer to a XEvent structure.  If it is NULL,
%      the entire image is refreshed.
%
%
*/
Export void XRefreshWindow(Display *display,const XWindowInfo *window,
  const XEvent *event)
{
  int
    x,
    y;

  unsigned int
    height,
    width;

  assert(display != (Display *) NULL);
  assert(window != (XWindowInfo *) NULL);
  if (event != (XEvent *) NULL)
    {
      /*
        Determine geometry from expose event.
      */
      x=event->xexpose.x;
      y=event->xexpose.y;
      width=event->xexpose.width;
      height=event->xexpose.height;
    }
  else
    {
      XEvent
        sans_event;

      /*
        Refresh entire window; discard outstanding expose events.
      */
      x=0;
      y=0;
      width=window->width;
      height=window->height;
      while (XCheckTypedWindowEvent(display,window->id,Expose,&sans_event));
    }
  /*
    Check boundary conditions.
  */
  if ((window->ximage->width-(x+window->x)) < width)
    width=window->ximage->width-(x+window->x);
  if ((window->ximage->height-(y+window->y)) < height)
    height=window->ximage->height-(y+window->y);
  /*
    Refresh image.
  */
  XSetClipMask(display,window->annotate_context,window->matte_pixmap);
  if (window->pixmap != (Pixmap) NULL)
    {
      if (window->depth > 1)
        XCopyArea(display,window->pixmap,window->id,window->annotate_context,
          x+window->x,y+window->y,width,height,x,y);
      else
        XCopyPlane(display,window->pixmap,window->id,window->highlight_context,
          x+window->x,y+window->y,width,height,x,y,1L);
    }
  else
    {
#ifdef HasSharedMemory
      if (window->shared_memory)
        {
          XShmPutImage(display,window->id,window->annotate_context,
            window->ximage,x+window->x,y+window->y,x,y,width,height,True);
          XSync(display,False);
        }
#endif
      if (!window->shared_memory)
        XPutImage(display,window->id,window->annotate_context,window->ximage,
          x+window->x,y+window->y,x,y,width,height);
    }
  XSetClipMask(display,window->annotate_context,None);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X R e t a i n W i n d o w C o l o r s                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XRetainWindowColors sets X11 color resources on a window.  This
%  perserves the colors associated with an image displayed on the window.
%
%  The format of the XRetainWindowColors routine is:
%
%      XRetainWindowColors(display,window)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server; returned from
%      XOpenDisplay.
%
%    o window: Specifies a pointer to a XWindowInfo structure.
%
%
*/
Export void XRetainWindowColors(Display *display,const Window window)
{
  Atom
    property;

  Pixmap
    pixmap;

  /*
    Put property on the window.
  */
  assert(display != (Display *) NULL);
  assert(window != (Window) NULL);
  property=XInternAtom(display,"_XSETROOT_ID",False);
  if (property == (Atom) NULL)
    {
      Warning("Unable to create X property","_XSETROOT_ID");
      return;
    }
  pixmap=XCreatePixmap(display,window,1,1,1);
  if (pixmap == (Pixmap) NULL)
    {
      Warning("Unable to create X pixmap",(char *) NULL);
      return;
    }
  XChangeProperty(display,window,property,XA_PIXMAP,32,PropModeReplace,
    (unsigned char *) &pixmap,1);
  XSetCloseDownMode(display,RetainPermanent);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X S e l e c t W i n d o w                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XSelectWindow allows a user to select a window using the mouse.  If
%  the mouse moves, a cropping rectangle is drawn and the extents of the
%  rectangle is returned in the crop_info structure.
%
%  The format of the XSelectWindow function is:
%
%      target_window=XSelectWindow(display,crop_info)
%
%  A description of each parameter follows:
%
%    o window: XSelectWindow returns the window id.
%
%    o display: Specifies a pointer to the Display structure;  returned from
%      XOpenDisplay.
%
%    o crop_info: Specifies a pointer to a RectangleInfo structure.  It
%      contains the extents of any cropping rectangle.
%
%
*/
Window XSelectWindow(Display *display,RectangleInfo *crop_info)
{
#define MinimumCropArea  (unsigned int) 9

  Cursor
    target_cursor;

  GC
    annotate_context;

  int
    presses,
    status,
    x_offset,
    y_offset;

  Window
    root_window,
    target_window;

  XEvent
    event;

  XGCValues
    context_values;

  /*
    Initialize graphic context.
  */
  assert(display != (Display *) NULL);
  assert(crop_info != (RectangleInfo *) NULL);
  root_window=XRootWindow(display,XDefaultScreen(display));
  context_values.background=XBlackPixel(display,XDefaultScreen(display));
  context_values.foreground=XWhitePixel(display,XDefaultScreen(display));
  context_values.function=GXinvert;
  context_values.plane_mask=
    context_values.background ^ context_values.foreground;
  context_values.subwindow_mode=IncludeInferiors;
  annotate_context=XCreateGC(display,root_window,GCBackground | GCForeground |
    GCFunction | GCPlaneMask | GCSubwindowMode,&context_values);
  if (annotate_context == (GC) NULL)
    return(False);
  /*
    Grab the pointer using target cursor.
  */
  target_cursor=XMakeCursor(display,root_window,
    XDefaultColormap(display,XDefaultScreen(display)),"white","black");
  status=XGrabPointer(display,root_window,False,(unsigned int)
    (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask),GrabModeSync,
    GrabModeAsync,root_window,target_cursor,CurrentTime);
  if (status != GrabSuccess)
    Error("Unable to grab the mouse",(char *) NULL);
  /*
    Select a window.
  */
  crop_info->width=0;
  crop_info->height=0;
  presses=0;
  target_window=(Window) NULL;
  x_offset=0;
  y_offset=0;
  do
  {
    if ((crop_info->width*crop_info->height) >= MinimumCropArea)
      XDrawRectangle(display,root_window,annotate_context,crop_info->x,
        crop_info->y,crop_info->width-1,crop_info->height-1);
    /*
      Allow another event.
    */
    XAllowEvents(display,SyncPointer,CurrentTime);
    XWindowEvent(display,root_window,ButtonPressMask | ButtonReleaseMask |
      ButtonMotionMask,&event);
    if ((crop_info->width*crop_info->height) >= MinimumCropArea)
      XDrawRectangle(display,root_window,annotate_context,crop_info->x,
        crop_info->y,crop_info->width-1,crop_info->height-1);
    switch (event.type)
    {
      case ButtonPress:
      {
        target_window=XGetSubwindow(display,event.xbutton.subwindow,
          event.xbutton.x,event.xbutton.y);
        if (target_window == (Window) NULL)
          target_window=root_window;
        x_offset=event.xbutton.x_root;
        y_offset=event.xbutton.y_root;
        crop_info->x=x_offset;
        crop_info->y=y_offset;
        crop_info->width=0;
        crop_info->height=0;
        presses++;
        break;
      }
      case ButtonRelease:
      {
        presses--;
        break;
      }
      case MotionNotify:
      {
        /*
          Discard pending button motion events.
        */
        while (XCheckMaskEvent(display,ButtonMotionMask,&event));
        crop_info->x=event.xmotion.x;
        crop_info->y=event.xmotion.y;
        /*
          Check boundary conditions.
        */
        if (crop_info->x < x_offset)
          crop_info->width=(unsigned int) (x_offset-crop_info->x);
        else
          {
            crop_info->width=(unsigned int) (crop_info->x-x_offset);
            crop_info->x=x_offset;
          }
        if (crop_info->y < y_offset)
          crop_info->height=(unsigned int) (y_offset-crop_info->y);
        else
          {
            crop_info->height=(unsigned int) (crop_info->y-y_offset);
            crop_info->y=y_offset;
          }
      }
      default:
        break;
    }
  }
  while ((target_window == (Window) NULL) || (presses > 0));
  XUngrabPointer(display,CurrentTime);
  XFreeCursor(display,target_cursor);
  XFreeGC(display,annotate_context);
  if ((crop_info->width*crop_info->height) < MinimumCropArea)
    {
      crop_info->width=0;
      crop_info->height=0;
    }
  if ((crop_info->width != 0) && (crop_info->height != 0))
    target_window=root_window;
  return(target_window);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X S e t C u r s o r S t a t e                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XSetCursorState sets the  cursor state to busy, otherwise the
%  cursor are reset to their default.
%
%  The format of the XXSetCursorState routine is:
%
%      XSetCursorState(display,windows,state)
%
%  A description of each parameter follows:
%
%    o display: Specifies a connection to an X server;  returned from
%      XOpenDisplay.
%
%    o windows: Specifies a pointer to a XWindows structure.
%
%    o state: An unsigned integer greater than 0 sets the cursor state
%      to busy, otherwise the cursor are reset to their default.
%
%
*/
Export void XSetCursorState(Display *display,XWindows *windows,
  const unsigned int state)
{
  assert(display != (Display *) NULL);
  assert(windows != (XWindows *) NULL);
  if (state)
    {
      XDefineCursor(display,windows->image.id,windows->image.busy_cursor);
      XDefineCursor(display,windows->pan.id,windows->pan.busy_cursor);
      XDefineCursor(display,windows->magnify.id,windows->magnify.busy_cursor);
      XDefineCursor(display,windows->command.id,windows->command.busy_cursor);
    }
  else
    {
      XDefineCursor(display,windows->image.id,windows->image.cursor);
      XDefineCursor(display,windows->pan.id,windows->pan.cursor);
      XDefineCursor(display,windows->magnify.id,windows->magnify.cursor);
      XDefineCursor(display,windows->command.id,windows->command.cursor);
      XDefineCursor(display,windows->command.id,windows->widget.cursor);
      XWithdrawWindow(display,windows->info.id,windows->info.screen);
    }
  windows->info.mapped=False;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X U s e r P r e f e r e n c e s                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XUserPreferences saves the preferences in a configuration file in
%  the users' home directory.
%
%  The format of the XUserPreferences routine is:
%
%      XUserPreferences(resource_info)
%
%  A description of each parameter follows:
%
%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
%
%
*/
Export void XUserPreferences(XResourceInfo *resource_info)
{
  char
    cache[MaxTextExtent],
    filename[MaxTextExtent],
    specifier[MaxTextExtent],
    *value;

  XrmDatabase
    preferences_database;

  /*
    Save user preferences to the client configuration file.
  */
  assert(resource_info != (XResourceInfo *) NULL);
  preferences_database=XrmGetStringDatabase("");
  (void) sprintf(specifier,"%s.backdrop",client_name);
  value=resource_info->backdrop ? "True" : "False";
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(specifier,"%s.browseCommand",client_name);
  value=resource_info->browse_command;
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(specifier,"%s.colormap",client_name);
  value=resource_info->colormap == SharedColormap ? "Shared" : "Private";
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(specifier,"%s.confirmExit",client_name);
  value=resource_info->confirm_exit ? "True" : "False";
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(specifier,"%s.displayWarnings",client_name);
  value=resource_info->display_warnings ? "True" : "False";
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(specifier,"%s.dither",client_name);
  value=resource_info->dither ? "True" : "False";
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(specifier,"%s.editorCommand",client_name);
  value=resource_info->editor_command;
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(specifier,"%s.gammaCorrect",client_name);
  value=resource_info->gamma_correct ? "True" : "False";
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(specifier,"%s.printCommand",client_name);
  value=resource_info->print_command;
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(specifier,"%s.undoCache",client_name);
  (void) sprintf(cache,"%u",resource_info->undo_cache);
  XrmPutStringResource(&preferences_database,specifier,cache);
  (void) sprintf(specifier,"%s.usePixmap",client_name);
  value=resource_info->use_pixmap ? "True" : "False";
  XrmPutStringResource(&preferences_database,specifier,value);
  (void) sprintf(filename,"%s%src",PreferencesDefaults,client_name);
  ExpandFilename(filename);
  XrmPutFileDatabase(preferences_database,filename);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X V i s u a l C l a s s N a m e                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XVisualClassName returns the visual class name as a character
%  string.
%
%  The format of the XVisualClassName routine is:
%
%      visual_type=XVisualClassName(class)
%
%  A description of each parameter follows:
%
%    o visual_type: XVisualClassName returns the visual class as a character
%      string.
%
%    o class: Specifies the visual class.
%
%
*/
Export char *XVisualClassName(const int class)
{
  switch (class)
  {
    case StaticGray: return("StaticGray");
    case GrayScale: return("GrayScale");
    case StaticColor: return("StaticColor");
    case PseudoColor: return("PseudoColor");
    case TrueColor: return("TrueColor");
    case DirectColor: return("DirectColor");
  }
  return("unknown visual class");
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X W i n d o w B y I D                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XWindowByID locates a child window with a given ID.  If not window
%  with the given name is found, 0 is returned.   Only the window specified
%  and its subwindows are searched.
%
%  The format of the XWindowByID function is:
%
%      child=XWindowByID(display,window,id)
%
%  A description of each parameter follows:
%
%    o child: XWindowByID returns the window with the specified
%      id.  If no windows are found, XWindowByID returns 0.
%
%    o display: Specifies a pointer to the Display structure;  returned from
%      XOpenDisplay.
%
%    o id: Specifies the id of the window to locate.
%
%
*/
Export Window XWindowByID(Display *display,const Window root_window,
  const unsigned long id)
{
  RectangleInfo
    rectangle_info;

  register int
    i;

  unsigned int
    number_children;

  Window
    child,
    *children,
    window;

  assert(display != (Display *) NULL);
  assert(root_window != (Window) NULL);
  if (id == 0)
    return(XSelectWindow(display,&rectangle_info));
  if (root_window == id)
    return(id);
  if (!XQueryTree(display,root_window,&child,&child,&children,&number_children))
    return((Window) NULL);
  window=(Window) NULL;
  for (i=0; i < number_children; i++)
  {
    /*
      Search each child and their children.
    */
    window=XWindowByID(display,children[i],id);
    if (window != (Window) NULL)
      break;
  }
  if (children != (Window *) NULL)
    XFree((void *) children);
  return(window);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X W i n d o w B y N a m e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XWindowByName locates a window with a given name on a display.
%  If no window with the given name is found, 0 is returned. If more than
%  one window has the given name, the first one is returned.  Only root and
%  its children are searched.
%
%  The format of the XWindowByName function is:
%
%      window=XWindowByName(display,root_window,name)
%
%  A description of each parameter follows:
%
%    o window: XWindowByName returns the window id.
%
%    o display: Specifies a pointer to the Display structure;  returned from
%      XOpenDisplay.
%
%    o root_window: Specifies the id of the root window.
%
%    o name: Specifies the name of the window to locate.
%
%
*/
Export Window XWindowByName(Display *display,const Window root_window,
  const char *name)
{
  register int
    i;

  unsigned int
    number_children;

  Window
    *children,
    child,
    window;

  XTextProperty
    window_name;

  assert(display != (Display *) NULL);
  assert(root_window != (Window) NULL);
  assert(name != (char *) NULL);
  if (XGetWMName(display,root_window,&window_name) != 0)
    if (strcmp((char *) window_name.value,name) == 0)
      return(root_window);
  if (!XQueryTree(display,root_window,&child,&child,&children,&number_children))
    return((Window) NULL);
  window=(Window) NULL;
  for (i=0; i < number_children; i++)
  {
    /*
      Search each child and their children.
    */
    window=XWindowByName(display,children[i],name);
    if (window != (Window) NULL)
      break;
  }
  if (children != (Window *) NULL)
    XFree((void *) children);
  return(window);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X W i n d o w B y P r o p e r y                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XWindowByProperty locates a child window with a given property.
%  If no window with the given name is found, 0 is returned.  If more than
%  one window has the given property, the first one is returned.  Only the
%  window specified and its subwindows are searched.
%
%  The format of the XWindowByProperty function is:
%
%      child=XWindowByProperty(display,window,property)
%
%  A description of each parameter follows:
%
%    o child: XWindowByProperty returns the window id with the specified
%      property.  If no windows are found, XWindowByProperty returns 0.
%
%    o display: Specifies a pointer to the Display structure;  returned from
%      XOpenDisplay.
%
%    o property: Specifies the property of the window to locate.
%
%
*/
Export Window XWindowByProperty(Display *display,const Window window,
  const Atom property)
{
  Atom
    type;

  int
    format,
    status;

  unsigned char
    *data;

  unsigned int
    i,
    number_children;

  unsigned long
    after,
    number_items;

  Window
    child,
    *children,
    parent,
    root;

  assert(display != (Display *) NULL);
  assert(window != (Window) NULL);
  assert(property != (Atom) NULL);
  status=XQueryTree(display,window,&root,&parent,&children,&number_children);
  if (status == 0)
    return((Window) NULL);
  type=(Atom) NULL;
  child=(Window) NULL;
  for (i=0; (i < number_children) && (child == (Window) NULL); i++)
  {
    status=XGetWindowProperty(display,children[i],property,0L,0L,False,
      (Atom) AnyPropertyType,&type,&format,&number_items,&after,&data);
    if (data != NULL)
      XFree((void *) data);
    if ((status == Success) && (type != (Atom) NULL))
      child=children[i];
  }
  for (i=0; (i < number_children) && (child == (Window) NULL); i++)
    child=XWindowByProperty(display,children[i],property);
  if (children != (Window *) NULL)
    XFree((void *) children);
  return(child);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.