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

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

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%              AAA   N   N  IIIII  M   M   AAA   TTTTT  EEEEE                 %
%             A   A  NN  N    I    MM MM  A   A    T    E                     %
%             AAAAA  N N N    I    M M M  AAAAA    T    EEE                   %
%             A   A  N  NN    I    M   M  A   A    T    E                     %
%             A   A  N   N  IIIII  M   M  A   A    T    EEEEE                 %
%                                                                             %
%                                                                             %
%          Animate Machine Independent File Format Image via X11.             %
%                                                                             %
%                                                                             %
%                                                                             %
%                           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.      %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Animate displays a sequence of images in the MIFF format on any
%  workstation display running an X server.  Animate first determines the
%  hardware capabilities of the workstation.  If the number of unique
%  colors in an image is less than or equal to the number the workstation
%  can support, the image is displayed in an X window.  Otherwise the
%  number of colors in the image is first reduced to match the color
%  resolution of the workstation before it is displayed.
%
%  This means that a continuous-tone 24 bits-per-pixel image can display on a
%  8 bit pseudo-color device or monochrome device.  In most instances the
%  reduced color image closely resembles the original.  Alternatively, a
%  monochrome or pseudo-color image can display on a continuous-tone 24
%  bits-per-pixel device.
%
%  The Animate program command syntax is:
%
%  Usage: animate [options ...] file [ [options ...] file ...]
%
%  Where options include:
%    -backdrop            display image centered on a backdrop
%    -colormap type       Shared or Private
%    -colors value        preferred number of colors in the image
%    -colorspace type     GRAY, OHTA, RGB, XYZ, YCbCr, YIQ, YPbPr, or YUV
%    -crop geometry       preferred size and location of the cropped image
%    -delay milliseconds  display the next image after pausing
%    -density geometry    vertical and horizontal density of the image
%    -display server      display image to this X server
%    -dither              apply Floyd/Steinberg error diffusion to image
%    -gamma value         level of gamma correction
%    -geometry geometry   preferred size and location of the Image window
%    -interlace type      None, Line, Plane, or Partition
%    -map type            display image using this Standard Colormap
%    -matte               store matte channel if the image has one
%    -monochrome          transform image to black and white
%    -scene value         image scene number
%    -size geometry       width and height of image
%    -treedepth value     depth of the color classification tree
%    -verbose             print detailed information about the image
%    -visual type         display image using this visual type
%    -window id           display image to background of this window
%
%  In addition to those listed above, you can specify these standard X
%  resources as command line options:  -background, -bordercolor,
%  -borderwidth, -font, -foreground, -iconGeometry, -iconic, -name,
%  -mattecolor, -shared_memory, or -title.
%
%  Change '-' to '+' in any option above to reverse its effect.  For
%  example, specify +matte to suppress any image matte information.
%
%  By default, the image format of `file' is determined by its magic
%  number.  To specify a particular image format, precede the filename
%  with an image format name and a colon (i.e. ps:image) or specify the
%  image type as the filename suffix (i.e. image.ps).  Specify 'file' as
%  '-' for standard input or output.
%
%  Buttons:
%    Press any button to map or unmap the Command widget.
%
%
*/

/*
  Include declarations.
*/
#include "magick.h"
#include "animate.h"
#include "version.h"

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   U s a g e                                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function Usage displays the program command syntax.
%
%  The format of the Usage routine is:
%
%      Usage(client_name)
%
%  A description of each parameter follows:
%
%    o client_name: a character string representing the name of the client
%      program.
%
%
*/
static void Usage(const char *client_name)
{
  char
    **p;

  static char
    *buttons[]=
    {
      "Press any button to map or unmap the Command widget",
      (char *) NULL
    },
    *options[]=
    {
      "-backdrop            display image centered on a backdrop",
      "-colormap type       Shared or Private",
      "-colors value        preferred number of colors in the image",
      "-colorspace type     GRAY, OHTA, RGB, XYZ, YCbCr, YIQ, YPbPr, or YUV",
      "-crop geometry       preferred size and location of the cropped image",
      "-delay milliseconds  display the next image after pausing",
      "-density geometry    vertical and horizontal density of the image",
      "-display server      display image to this X server",
      "-dither              apply Floyd/Steinberg error diffusion to image",
      "-gamma value         level of gamma correction",
      "-geometry geometry   preferred size and location of the Image window",
      "-interlace type      None, Line, Plane, or Partition",
      "-matte               store matte channel if the image has one",
      "-map type            display image using this Standard Colormap",
      "-monochrome          transform image to black and white",
      "-scene value         image scene number",
      "-size geometry       width and height of image",
      "-treedepth value     depth of the color classification tree",
      "-verbose             print detailed information about the image",
      "-visual type         display image using this visual type",
      "-window id          display image to background of this window",
      (char *) NULL
    };

  (void) printf("Version: %s\n\n",Version);
  (void) printf(
    "Usage: %s [-options ...] file [ [-options ...] file ...]\n",client_name);
  (void) printf("\nWhere options include: \n");
  for (p=options; *p != (char *) NULL; p++)
    (void) printf("  %s\n",*p);
  (void) printf(
    "\nIn addition to those listed above, you can specify these standard X\n");
  (void) printf(
    "resources as command line options:  -background, -bordercolor,\n");
  (void) printf(
    "-borderwidth, -font, -foreground, -iconGeometry, -iconic, -name,\n");
  (void) printf("-mattecolor, -shared_memory, or -title.\n");
  (void) printf(
    "\nChange '-' to '+' in any option above to reverse its effect.  For\n");
  (void) printf(
    "example, specify +matte to suppress any image matte information.\n");
  (void) printf(
    "\nBy default, the image format of `file' is determined by its magic\n");
  (void) printf(
    "number.  To specify a particular image format, precede the filename\n");
  (void) printf(
    "with an image format name and a colon (i.e. ps:image) or specify the\n");
  (void) printf(
    "image type as the filename suffix (i.e. image.ps).  Specify 'file' as\n");
  (void) printf("'-' for standard input or output.\n");
  (void) printf("\nButtons: \n");
  for (p=buttons; *p != (char *) NULL; p++)
    (void) printf("  %s\n",*p);
  Exit(1);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X A n i m a t e B a c k g r o u n d I m a g e                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XAnimateBackgroundImage animates an image sequence in the
%  background of a window.
%
%  The format of the XAnimateBackgroundImage routine is:
%
%      XAnimateBackgroundImage(display,resource_info,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 image: Specifies a pointer to a Image structure; returned from
%      ReadImage.
%
%
*/

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);
}

static void XAnimateBackgroundImage(Display *display,
  XResourceInfo *resource_info,Image *image)
{
  char
    geometry[MaxTextExtent],
    visual_type[MaxTextExtent];

  Image
    **images;

  int
    i,
    scene;

  unsigned int
    height,
    number_scenes,
    sans,
    status,
    width;

  Window
    root_window;

  XEvent
    event;

  XGCValues
    context_values;

  XPixelInfo
    pixel_info,
    scene_info;

  XResourceInfo
    resources;

  XStandardColormap
    *map_info;

  XVisualInfo
    *visual_info;

  XWindowAttributes
    window_attributes;

  XWindowInfo
    window_info;

  /*
    Determine target window.
  */
  resources=(*resource_info);
  window_info.id=(Window) NULL;
  root_window=XRootWindow(display,XDefaultScreen(display));
  if (Latin1Compare(resources.window_id,"root") == 0)
    window_info.id=root_window;
  else
    {
      if (isdigit(*resources.window_id))
        window_info.id=XWindowByID(display,root_window,
          (Window) strtol((char *) resources.window_id,(char **) NULL,0));
      if (window_info.id == (Window) NULL)
        window_info.id=
          XWindowByName(display,root_window,resources.window_id);
    }
  if (window_info.id == (Window) NULL)
    Error("No window with specified id exists",resources.window_id);
  /*
    Determine window visual id.
  */
  window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
  window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
  (void) strcpy(visual_type,"default");
  status=XGetWindowAttributes(display,window_info.id,&window_attributes);
  if (status != False)
    (void) sprintf(visual_type,"0x%lx",
      XVisualIDFromVisual(window_attributes.visual));
  /*
    Allocate standard colormap.
  */
  map_info=XAllocStandardColormap();
  if (map_info == (XStandardColormap *) NULL)
    Error("Unable to create standard colormap","Memory allocation failed");
  map_info->colormap=(Colormap) NULL;
  pixel_info.pixels=(unsigned long *) NULL;
  pixel_info.gamma_map=(XColor *) NULL;
  /*
    Initialize visual info.
  */
  resources.map_type=(char *) NULL;
  resources.visual_type=visual_type;
  visual_info=XBestVisualInfo(display,map_info,&resources);
  if (visual_info == (XVisualInfo *) NULL)
    Error("Unable to get visual",resources.visual_type);
  /*
    Initialize window info.
  */
  window_info.ximage=(XImage *) NULL;
  window_info.matte_image=(XImage *) NULL;
  window_info.pixmap=(Pixmap) NULL;
  window_info.matte_pixmap=(Pixmap) NULL;
  window_info.shared_memory=False;
  /*
    Free previous root colors.
  */
  if (window_info.id == root_window)
    XDestroyWindowColors(display,root_window);
  if (visual_info == (XVisualInfo *) NULL)
    Error("Unable to get visual",resources.visual_type);
  if (resources.map_type == (char *) NULL)
    if ((visual_info->class != TrueColor) &&
        (visual_info->class != DirectColor))
      {
        Image
          *next_image;

        unsigned int
          global_colormap;

        /*
          Determine if the sequence of images has the identical colormap.
        */
        global_colormap=True;
        next_image=image;
        for ( ; next_image != (Image *) NULL; next_image=next_image->next)
        {
          next_image->matte=False;
          if ((next_image->class == DirectClass) ||
              (next_image->colors != image->colors) ||
              (next_image->colors > visual_info->colormap_size))
            {
              global_colormap=False;
              continue;
            }
          for (i=0; i < image->colors; i++)
            if (!ColorMatch(next_image->colormap[i],image->colormap[i],0))
              {
                global_colormap=False;
                break;
              }
        }
        if (!global_colormap)
          MapImages(image,(Image *) NULL,resources.dither);
      }
  /*
    Sort images by increasing scene number.
  */
  images=ListToGroupImage(image,&number_scenes);
  if (images == (Image **) NULL)
    Error("Unable to animate images","Memory allocation failed");
  for (scene=0; scene < number_scenes; scene++)
    if (images[scene]->scene == 0)
      break;
  if (scene == number_scenes)
    qsort((void *) images,number_scenes,sizeof(Image *),
      (int (*)(const void *, const void *)) SceneCompare);
  /*
    Initialize Standard Colormap.
  */
  resources.colormap=SharedColormap;
  XMakeStandardColormap(display,visual_info,&resources,images[0],map_info,
    &pixel_info);
  /*
    Graphic context superclass.
  */
  context_values.background=pixel_info.background_color.pixel;
  context_values.foreground=pixel_info.foreground_color.pixel;
  pixel_info.annotate_context=XCreateGC(display,window_info.id,GCBackground |
    GCForeground,&context_values);
  if (pixel_info.annotate_context == (GC) NULL)
    Error("Unable to create graphic context",(char *) NULL);
  /*
    Initialize Image window attributes.
  */
  XGetWindowInfo(display,visual_info,map_info,&pixel_info,(XFontStruct *) NULL,
    &resources,&window_info);
  /*
    Create the X image.
  */
  window_info.width=images[0]->columns;
  window_info.height=images[0]->rows;
  (void) sprintf(geometry,"%ux%u>",window_attributes.width,
    window_attributes.height);
  (void) ParseImageGeometry(geometry,&window_info.x,&window_info.y,
    &window_info.width,&window_info.height);
  status=XMakeImage(display,&resources,&window_info,images[0],window_info.width,
    window_info.height);
  if (status == False)
    Error("Unable to create X image",(char *) NULL);
  window_info.x=0;
  window_info.y=0;
  if (resources.debug)
    {
      (void) fprintf(stderr,"Image: %s[%u] %ux%u ",images[0]->filename,
        images[0]->scene,images[0]->columns,images[0]->rows);
      if (images[0]->colors != 0)
        (void) fprintf(stderr,"%uc ",images[0]->colors);
      (void) fprintf(stderr,"%s\n",images[0]->magick);
    }
  /*
    Adjust image dimensions as specified by backdrop or geometry options.
  */
  width=window_info.width;
  height=window_info.height;
  if (resources.backdrop)
    {
      /*
        Center image on window.
      */
      window_info.x=(window_attributes.width >> 1)-
        (window_info.ximage->width >> 1);
      window_info.y=(window_attributes.height >> 1)-
        (window_info.ximage->height >> 1);
      width=window_attributes.width;
      height=window_attributes.height;
    }
  if (resources.image_geometry != (char *) NULL)
    {
      char
        default_geometry[MaxTextExtent];

      int
        flags,
        gravity;

      XSizeHints
        *size_hints;

      /*
        User specified geometry.
      */
      size_hints=XAllocSizeHints();
      if (size_hints == (XSizeHints *) NULL)
        Error("Unable to display on window","Memory allocation failed");
      size_hints->flags=(long) NULL;
      (void) sprintf(default_geometry,"%ux%u",width,height);
      flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
        default_geometry,window_info.border_width,size_hints,&window_info.x,
        &window_info.y,(int *) &width,(int *) &height,&gravity);
      if (flags & (XValue | YValue))
        {
          width=window_attributes.width;
          height=window_attributes.height;
        }
      XFree((void *) size_hints);
    }
  /*
    Create the X pixmap.
  */
  window_info.pixmap=
    XCreatePixmap(display,window_info.id,width,height,window_info.depth);
  if (window_info.pixmap == (Pixmap) NULL)
    Error("Unable to create X pixmap",(char *) NULL);
  /*
    Display pixmap on the window.
  */
  if ((width > window_info.width) || (height > window_info.height))
    XFillRectangle(display,window_info.pixmap,window_info.annotate_context,
      0,0,width,height);
  XPutImage(display,window_info.pixmap,window_info.annotate_context,
    window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
    window_info.height);
  XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
  XClearWindow(display,window_info.id);
  /*
    Initialize image pixmaps structure.
  */
  window_info.pixmaps=(Pixmap *) malloc(number_scenes*sizeof(Pixmap));
  if (window_info.pixmaps == (Pixmap *) NULL)
    Error("Unable to animate images","Memory allocation failed");
  window_info.pixmaps[0]=window_info.pixmap;
  scene_info.pixels=(unsigned long *) NULL;
  scene_info.gamma_map=(XColor *) NULL;
  for (scene=1; scene < number_scenes; scene++)
  {
    /*
      Create X image.
    */
    window_info.pixmap=(Pixmap) NULL;
    if ((resources.map_type != (char *) NULL) ||
        (visual_info->class == TrueColor) ||
        (visual_info->class == DirectColor))
      if (images[scene]->class == PseudoClass)
        {
          /*
            Get pixel info for this scene.
          */
          XGetPixelInfo(display,visual_info,map_info,&resources,images[scene],
            &scene_info);
          window_info.pixel_info=(&scene_info);
        }
    status=XMakeImage(display,&resources,&window_info,images[scene],
      images[scene]->columns,images[scene]->rows);
    if (status == False)
      Error("Unable to create X image",(char *) NULL);
    if (resources.debug)
      {
        (void) fprintf(stderr,"Image: [%u] %s %ux%u ",images[scene]->scene,
          images[scene]->filename,images[scene]->columns,images[scene]->rows);
        if (images[scene]->colors != 0)
          (void) fprintf(stderr,"%uc ",images[scene]->colors);
        (void) fprintf(stderr,"%s\n",images[scene]->magick);
      }
    /*
      Create the X pixmap.
    */
    window_info.pixmap=
      XCreatePixmap(display,window_info.id,width,height,window_info.depth);
    if (window_info.pixmap == (Pixmap) NULL)
      Error("Unable to create X pixmap",(char *) NULL);
    /*
      Display pixmap on the window.
    */
    if ((width > window_info.width) || (height > window_info.height))
      XFillRectangle(display,window_info.pixmap,window_info.annotate_context,
        0,0,width,height);
    XPutImage(display,window_info.pixmap,window_info.annotate_context,
      window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
      window_info.height);
    XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
    XClearWindow(display,window_info.id);
    window_info.pixmaps[scene]=window_info.pixmap;
    if (images[scene]->matte)
      XClearWindow(display,window_info.id);
    if (resources.delay != 0)
      XDelay(display,(unsigned long) resources.delay);
    else
      XDelay(display,(unsigned long) image->delay*10);
  }
  window_info.pixel_info=(&pixel_info);
  /*
    Display pixmap on the window.
  */
  XSelectInput(display,window_info.id,SubstructureNotifyMask);
  event.type=Expose;
  do
  {
    for (scene=0; scene < number_scenes; scene++)
    {
      if (XEventsQueued(display,QueuedAfterFlush) > 0)
        {
          XNextEvent(display,&event);
          if (event.type == DestroyNotify)
            break;
        }
      window_info.pixmap=window_info.pixmaps[scene];
      XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
      XClearWindow(display,window_info.id);
      XSync(display,False);
      if (resources.delay != 0)
        XDelay(display,(unsigned long) resources.delay);
      else
        XDelay(display,(unsigned long) images[scene]->delay*10);
    }
  } while (event.type != DestroyNotify);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X A n i m a t e I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XAnimateImages displays an image via X11.
%
%  The format of the XAnimateImages routine is:
%
%      XAnimateImages(display,resource_info,argv,argc,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 argv: Specifies the application's argument list.
%
%    o argc: Specifies the number of arguments.
%
%    o image: Specifies a pointer to a Image structure; returned from
%      ReadImage.
%
%
*/
static Image *XAnimateImages(Display *display,XResourceInfo *resource_info,
  char **argv,const int argc,Image *image)
{
#define MagickMenus  3
#define MaxWindows  8
#define MagickTitle  "Commands"

  static char
    *CommandMenu[]=
    {
      "Animate",
      "Speed",
      "Direction",
      "Image Info",
      "Help",
      "Quit",
      (char *) NULL
    },
    *AnimateMenu[]=
    {
      "Open",
      "Play",
      "Step",
      "Repeat",
      "AutoReverse",
      (char *) NULL
    },
    *SpeedMenu[]=
    {
      "Faster",
      "Slower",
      (char *) NULL
    },
    *DirectionMenu[]=
    {
      "Forward",
      "Reverse",
      (char *) NULL
    };

  static char
    **Menus[MagickMenus]=
    {
      AnimateMenu,
      SpeedMenu,
      DirectionMenu
    };

  static CommandType
    CommandMenus[]=
    {
      NullCommand,
      NullCommand,
      NullCommand,
      InfoCommand,
      HelpCommand,
      QuitCommand
    },
    CommandTypes[]=
    {
      OpenCommand,
      PlayCommand,
      StepCommand,
      RepeatCommand,
      AutoReverseCommand
    },
    SpeedCommands[]=
    {
      FasterCommand,
      SlowerCommand
    },
    DirectionCommands[]=
    {
      ForwardCommand,
      ReverseCommand
    };

  static CommandType
    *Commands[MagickMenus]=
    {
      CommandTypes,
      SpeedCommands,
      DirectionCommands
    };

  static unsigned char
    HighlightBitmap[] = {0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55},
    ShadowBitmap[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

  char
    command[MaxTextExtent],
    image_signature[MaxTextExtent],
    resource_name[MaxTextExtent];

  CommandType
    command_type;

  Image
    *displayed_image,
    **images,
    *loaded_image;

  int
    entry,
    id,
    scene,
    status;

  KeySym
    key_symbol;

  MonitorHandler
    handler;

  register char
    *p;

  register int
    i;

  static char
    working_directory[MaxTextExtent];

  static Window
    root_window;

  static XClassHint
    *class_hints;

  static XFontStruct
    *font_info;

  static XPixelInfo
    icon_pixel,
    pixel_info,
    scene_info;

  static XResourceInfo
    icon_resources;

  static XStandardColormap
    *icon_map,
    *map_info;

  static XVisualInfo
    *icon_visual,
    *visual_info = (XVisualInfo *) NULL;

  static XWindowInfo
    *magick_windows[MaxWindows];

  static XWMHints
    *manager_hints;

  static unsigned int
    number_windows;

  struct stat
    file_info;

  time_t
    timestamp;

  unsigned int
    context_mask,
    number_scenes,
    sans,
    state;

  XEvent
    event;

  XGCValues
    context_values;

  XTextProperty
    window_name;

  XWindowChanges
    window_changes;

  if (visual_info != (XVisualInfo *) NULL)
    (void) chdir(working_directory);
  else
    {
      /*
        Allocate standard colormap.
      */
      if (resource_info->debug)
        {
          XSynchronize(display,True);
          (void) fprintf(stderr,"Version: %s\n",Version);
        }
      map_info=XAllocStandardColormap();
      icon_map=XAllocStandardColormap();
      if ((map_info == (XStandardColormap *) NULL) ||
          (icon_map == (XStandardColormap *) NULL))
        Error("Unable to create standard colormap","Memory allocation failed");
      map_info->colormap=(Colormap) NULL;
      icon_map->colormap=(Colormap) NULL;
      pixel_info.pixels=(unsigned long *) NULL;
      pixel_info.gamma_map=(XColor *) NULL;
      pixel_info.annotate_context=(GC) NULL;
      pixel_info.highlight_context=(GC) NULL;
      pixel_info.widget_context=(GC) NULL;
      font_info=(XFontStruct *) NULL;
      icon_pixel.annotate_context=(GC) NULL;
      icon_pixel.pixels=(unsigned long *) NULL;
      icon_pixel.gamma_map=(XColor *) NULL;
      /*
        Allocate visual.
      */
      icon_resources=(*resource_info);
      icon_resources.map_type=(char *) NULL;
      icon_resources.visual_type="default";
      icon_resources.colormap=SharedColormap;
      visual_info=XBestVisualInfo(display,map_info,resource_info);
      icon_visual=XBestVisualInfo(display,icon_map,&icon_resources);
      if ((visual_info == (XVisualInfo *) NULL) ||
          (icon_visual == (XVisualInfo *) NULL))
        Error("Unable to get visual",resource_info->visual_type);
      if (resource_info->debug)
        {
          (void) fprintf(stderr,"Visual:\n");
          (void) fprintf(stderr,"  visual id: 0x%lx\n",visual_info->visualid);
          (void) fprintf(stderr,"  class: %s\n",
            XVisualClassName(visual_info->class));
          (void) fprintf(stderr,"  depth: %d planes\n",visual_info->depth);
          (void) fprintf(stderr,"  size of colormap: %d entries\n",
            visual_info->colormap_size);
          (void) fprintf(stderr,"  red, green, blue masks: 0x%lx 0x%lx 0x%lx\n",
            visual_info->red_mask,visual_info->green_mask,
            visual_info->blue_mask);
          (void) fprintf(stderr,"  significant bits in color: %d bits\n",
            visual_info->bits_per_rgb);
        }
      /*
        Allocate atoms.
      */
      windows=(XWindows *) malloc(sizeof(XWindows));
      if (windows == (XWindows *) NULL)
        Error("Unable to create X windows","Memory allocation failed");
      windows->wm_protocols=XInternAtom(display,"WM_PROTOCOLS",False);
      windows->wm_delete_window=XInternAtom(display,"WM_DELETE_WINDOW",False);
      windows->wm_take_focus=XInternAtom(display,"WM_TAKE_FOCUS",False);
      windows->im_protocols=XInternAtom(display,"IM_PROTOCOLS",False);
      windows->im_update_widget=XInternAtom(display,"IM_UPDATE_WIDGET",False);
      windows->im_update_colormap=
        XInternAtom(display,"IM_UPDATE_COLORMAP",False);
      windows->im_update_signature=
        XInternAtom(display,"IM_UPDATE_SIGNATURE",False);
      *image_signature='\0';
      windows->im_former_image=XInternAtom(display,"IM_FORMER_IMAGE",False);
      windows->im_next_image=XInternAtom(display,"IM_NEXT_IMAGE",False);
      windows->im_retain_colors=XInternAtom(display,"IM_RETAIN_COLORS",False);
      windows->im_exit=XInternAtom(display,"IM_EXIT",False);
      windows->dnd_protocols=XInternAtom(display,"DndProtocol",False);
      if (resource_info->debug)
        {
          (void) fprintf(stderr,"Protocols:\n");
          (void) fprintf(stderr,"  Window Manager: 0x%lx\n",
            windows->wm_protocols);
          (void) fprintf(stderr,"    delete window: 0x%lx\n",
            windows->wm_delete_window);
          (void) fprintf(stderr,"    take focus: 0x%lx\n",
            windows->wm_take_focus);
          (void) fprintf(stderr,"  ImageMagick: 0x%lx\n",
            windows->im_protocols);
          (void) fprintf(stderr,"    update widget: 0x%lx\n",
            windows->im_update_widget);
          (void) fprintf(stderr,"    update colormap: 0x%lx\n",
            windows->im_update_colormap);
          (void) fprintf(stderr,"    update signature: 0x%lx\n",
            windows->im_update_signature);
          (void) fprintf(stderr,"    former image: 0x%lx\n",
            windows->im_former_image);
          (void) fprintf(stderr,"    next image: 0x%lx\n",
            windows->im_next_image);
          (void) fprintf(stderr,"    retain colors: 0x%lx\n",
            windows->im_retain_colors);
          (void) fprintf(stderr,"    exit: 0x%lx\n",windows->im_exit);
          (void) fprintf(stderr,"  Drag and Drop: 0x%lx\n",
            windows->dnd_protocols);
        }
      /*
        Allocate class and manager hints.
      */
      class_hints=XAllocClassHint();
      manager_hints=XAllocWMHints();
      if ((class_hints == (XClassHint *) NULL) ||
          (manager_hints == (XWMHints *) NULL))
        Error("Unable to allocate X hints",(char *) NULL);
      /*
        Determine group leader if we have one.
      */
      root_window=XRootWindow(display,visual_info->screen);
      windows->group_leader.id=(Window) NULL;
      if (resource_info->window_group != (char *) NULL)
        {
          if (isdigit(*resource_info->window_group))
            windows->group_leader.id=XWindowByID(display,root_window,(Window)
              strtol((char *) resource_info->window_group,(char **) NULL,0));
          if (windows->group_leader.id == (Window) NULL)
            windows->group_leader.id=
              XWindowByName(display,root_window,resource_info->window_group);
        }
      /*
        Initialize window id's.
      */
      number_windows=0;
      magick_windows[number_windows++]=(&windows->icon);
      magick_windows[number_windows++]=(&windows->backdrop);
      magick_windows[number_windows++]=(&windows->image);
      magick_windows[number_windows++]=(&windows->info);
      magick_windows[number_windows++]=(&windows->command);
      magick_windows[number_windows++]=(&windows->widget);
      magick_windows[number_windows++]=(&windows->popup);
      for (i=0; i < number_windows; i++)
        magick_windows[i]->id=(Window) NULL;
    }
  if (resource_info->map_type == (char *) NULL)
    if ((visual_info->class != TrueColor) &&
        (visual_info->class != DirectColor))
      {
        Image
          *next_image;

        unsigned int
          global_colormap;

        /*
          Determine if the sequence of images has the identical colormap.
        */
        global_colormap=True;
        next_image=image;
        for ( ; next_image != (Image *) NULL; next_image=next_image->next)
        {
          next_image->matte=False;
          if ((next_image->class == DirectClass) ||
              (next_image->colors != image->colors) ||
              (next_image->colors > visual_info->colormap_size))
            {
              global_colormap=False;
              continue;
            }
          for (i=0; i < image->colors; i++)
            if (!ColorMatch(next_image->colormap[i],image->colormap[i],0))
              {
                global_colormap=False;
                break;
              }
        }
        if (!global_colormap)
          MapImages(image,(Image *) NULL,resource_info->dither);
      }
  /*
    Sort images by increasing scene number.
  */
  images=ListToGroupImage(image,&number_scenes);
  if (images == (Image **) NULL)
    Error("Unable to animate images","Memory allocation failed");
  for (scene=0; scene < number_scenes; scene++)
    if (images[scene]->scene == 0)
      break;
  if (scene == number_scenes)
    qsort((void *) images,number_scenes,sizeof(Image *),
      (int (*)(const void *, const void *)) SceneCompare);
  /*
    Initialize Standard Colormap.
  */
  loaded_image=(Image *) NULL;
  displayed_image=image;
  if (resource_info->debug)
    {
      (void) fprintf(stderr,"Image: %s[%u] %ux%u ",displayed_image->filename,
        displayed_image->scene,displayed_image->columns,displayed_image->rows);
      if (displayed_image->colors != 0)
        (void) fprintf(stderr,"%uc ",displayed_image->colors);
      (void) fprintf(stderr,"%s\n",displayed_image->magick);
    }
  XMakeStandardColormap(display,visual_info,resource_info,displayed_image,
    map_info,&pixel_info);
  /*
    Initialize font info.
  */
  if (font_info != (XFontStruct *) NULL)
    XFreeFont(display,font_info);
  font_info=XBestFont(display,resource_info,False);
  if (font_info == (XFontStruct *) NULL)
    Error("Unable to load font",resource_info->font);
  /*
    Initialize graphic context.
  */
  windows->context.id=(Window) NULL;
  XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
    resource_info,&windows->context);
  class_hints->res_name="superclass";
  class_hints->res_class="Display";
  manager_hints->flags=InputHint | StateHint;
  manager_hints->input=False;
  manager_hints->initial_state=WithdrawnState;
  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
    &windows->context);
  if (resource_info->debug)
    (void) fprintf(stderr,"Window id: 0x%lx (context)\n",windows->context.id);
  context_values.background=pixel_info.background_color.pixel;
  context_values.font=font_info->fid;
  context_values.foreground=pixel_info.foreground_color.pixel;
  context_values.graphics_exposures=False;
  context_mask=GCBackground | GCFont | GCForeground | GCGraphicsExposures;
  if (pixel_info.annotate_context != (GC) NULL)
    XFreeGC(display,pixel_info.annotate_context);
  pixel_info.annotate_context=
    XCreateGC(display,windows->context.id,context_mask,&context_values);
  if (pixel_info.annotate_context == (GC) NULL)
    Error("Unable to create graphic context",(char *) NULL);
  context_values.background=pixel_info.depth_color.pixel;
  if (pixel_info.widget_context != (GC) NULL)
    XFreeGC(display,pixel_info.widget_context);
  pixel_info.widget_context=
    XCreateGC(display,windows->context.id,context_mask,&context_values);
  if (pixel_info.widget_context == (GC) NULL)
    Error("Unable to create graphic context",(char *) NULL);
  context_values.background=pixel_info.foreground_color.pixel;
  context_values.foreground=pixel_info.background_color.pixel;
  context_values.plane_mask=
    context_values.background ^ context_values.foreground;
  if (pixel_info.highlight_context != (GC) NULL)
    XFreeGC(display,pixel_info.highlight_context);
  pixel_info.highlight_context=XCreateGC(display,windows->context.id,
    context_mask | GCPlaneMask,&context_values);
  if (pixel_info.highlight_context == (GC) NULL)
    Error("Unable to create graphic context",(char *) NULL);
  XDestroyWindow(display,windows->context.id);
  /*
    Initialize icon window.
  */
  XGetWindowInfo(display,icon_visual,icon_map,&icon_pixel,(XFontStruct *) NULL,
    &icon_resources,&windows->icon);
  windows->icon.geometry=resource_info->icon_geometry;
  XBestIconSize(display,&windows->icon,displayed_image);
  windows->icon.attributes.colormap=
    XDefaultColormap(display,icon_visual->screen);
  windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
  class_hints->res_name="icon";
  manager_hints->flags=InputHint | StateHint;
  manager_hints->input=False;
  manager_hints->initial_state=IconicState;
  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
    &windows->icon);
  if (resource_info->debug)
    (void) fprintf(stderr,"Window id: 0x%lx (icon)\n",windows->icon.id);
  /*
    Initialize graphic context for icon window.
  */
  if (icon_pixel.annotate_context != (GC) NULL)
    XFreeGC(display,icon_pixel.annotate_context);
  context_values.background=icon_pixel.background_color.pixel;
  context_values.foreground=icon_pixel.foreground_color.pixel;
  icon_pixel.annotate_context=XCreateGC(display,windows->icon.id,
    GCBackground | GCForeground,&context_values);
  if (icon_pixel.annotate_context == (GC) NULL)
    Error("Unable to create graphic context",(char *) NULL);
  windows->icon.annotate_context=icon_pixel.annotate_context;
  /*
    Initialize Image window.
  */
  if (windows->image.id != (Window) NULL)
    {
      free((char *) windows->image.name);
      free((char *) windows->image.icon_name);
    }
  XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
    resource_info,&windows->image);
  windows->image.shape=True;
  windows->image.name=(char *) malloc(MaxTextExtent*sizeof(char));
  windows->image.icon_name=(char *) malloc(MaxTextExtent*sizeof(char));
  if ((windows->image.name == NULL) || (windows->image.icon_name == NULL))
    Error("Unable to create Image window","Memory allocation failed");
  if (resource_info->title != (char *) NULL)
    {
      /*
        User specified window name.
      */
      (void) strcpy(windows->image.name,resource_info->title);
      (void) strcpy(windows->image.icon_name,resource_info->title);
    }
  else
    {
      /*
        Window name is the base of the filename.
      */
      p=displayed_image->filename+Extent(displayed_image->filename)-1;
      while ((p > displayed_image->filename) && (*(p-1) != *BasenameSeparator))
        p--;
      (void) sprintf(windows->image.name,"ImageMagick: %s[%u of %u]",p,
        displayed_image->scene,number_scenes);
      (void) strcpy(windows->image.icon_name,p);
    }
  if (resource_info->immutable)
    windows->image.immutable=True;
  windows->image.shape=True;
  windows->image.geometry=resource_info->image_geometry;
  windows->image.width=displayed_image->columns;
  if (windows->image.width > XDisplayWidth(display,visual_info->screen))
    windows->image.width=XDisplayWidth(display,visual_info->screen);
  windows->image.height=displayed_image->rows;
  if (windows->image.height > XDisplayHeight(display,visual_info->screen))
    windows->image.height=XDisplayHeight(display,visual_info->screen);
  windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
    ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
    KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
    StructureNotifyMask | SubstructureNotifyMask;
  XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
    resource_info,&windows->backdrop);
  if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
    {
      /*
        Initialize backdrop window.
      */
      windows->backdrop.x=0;
      windows->backdrop.y=0;
      windows->backdrop.name="ImageMagick Backdrop";
      windows->backdrop.flags=USSize | USPosition;
      windows->backdrop.width=XDisplayWidth(display,visual_info->screen);
      windows->backdrop.height=XDisplayHeight(display,visual_info->screen);
      windows->backdrop.border_width=0;
      windows->backdrop.immutable=True;
      windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
        ButtonReleaseMask;
      windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
        StructureNotifyMask;
      windows->backdrop.attributes.override_redirect=True;
      class_hints->res_name="backdrop";
      manager_hints->flags=IconWindowHint | InputHint | StateHint;
      manager_hints->icon_window=windows->icon.id;
      manager_hints->input=True;
      manager_hints->initial_state=
        resource_info->iconic ? IconicState : NormalState;
      XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
        &windows->backdrop);
      if (resource_info->debug)
        (void) fprintf(stderr,"Window id: 0x%lx (backdrop)\n",
          windows->backdrop.id);
      XMapWindow(display,windows->backdrop.id);
      XClearWindow(display,windows->backdrop.id);
      if (windows->image.id != (Window) NULL)
        {
          XDestroyWindow(display,windows->image.id);
          windows->image.id=(Window) NULL;
        }
      /*
        Position image in the center the backdrop.
      */
      windows->image.flags|=USPosition;
      windows->image.x=(XDisplayWidth(display,visual_info->screen) >> 1)-
        (windows->image.width >> 1);
      windows->image.y=(XDisplayHeight(display,visual_info->screen) >> 1)-
        (windows->image.height >> 1);
    }
  if (resource_info->name == (char *) NULL)
    class_hints->res_name=resource_info->client_name;
  else
    class_hints->res_name=resource_info->name;
  manager_hints->flags=IconWindowHint | InputHint | StateHint;
  manager_hints->icon_window=windows->icon.id;
  manager_hints->input=True;
  manager_hints->initial_state=
    resource_info->iconic ? IconicState : NormalState;
  if (windows->group_leader.id != (Window) NULL)
    {
      /*
        Follow the leader.
      */
      manager_hints->flags|=WindowGroupHint;
      manager_hints->window_group=windows->group_leader.id;
      XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
      if (resource_info->debug)
        (void) fprintf(stderr,"Window id: 0x%lx (group leader)\n",
          windows->group_leader.id);
    }
  XMakeWindow(display,
    (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
    argv,argc,class_hints,manager_hints,&windows->image);
  if (windows->group_leader.id != (Window) NULL)
    XSetTransientForHint(display,windows->image.id,windows->group_leader.id);
  if (resource_info->debug)
    (void) fprintf(stderr,"Window id: 0x%lx (image)\n",windows->image.id);
  /*
    Initialize X image structure.
  */
  windows->image.x=0;
  windows->image.y=0;
  status=XMakeImage(display,resource_info,&windows->image,displayed_image,
    displayed_image->columns,displayed_image->rows);
  if (status == False)
    Error("Unable to create X image",(char *) NULL);
  if (!windows->image.mapped || (windows->backdrop.id != (Window) NULL))
    XMapWindow(display,windows->image.id);
  if (windows->image.mapped)
    XRefreshWindow(display,&windows->image,(XEvent *) NULL);
  XClientMessage(display,windows->image.id,windows->im_protocols,
    windows->im_update_signature,CurrentTime);
  /*
    Initialize Info widget.
  */
  XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
    resource_info,&windows->info);
  windows->info.name="Info";
  windows->info.icon_name="Info";
  windows->info.border_width=1;
  windows->info.x=2;
  windows->info.y=2;
  windows->info.flags|=PPosition;
  windows->info.attributes.win_gravity=UnmapGravity;
  windows->info.attributes.event_mask=
    ButtonPressMask | ExposureMask | StructureNotifyMask;
  class_hints->res_name="info";
  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
  manager_hints->input=False;
  manager_hints->initial_state=NormalState;
  manager_hints->window_group=windows->image.id;
  XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
    &windows->info);
  windows->info.highlight_stipple=XCreateBitmapFromData(display,
    windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
  windows->info.shadow_stipple=XCreateBitmapFromData(display,
    windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
  XSetTransientForHint(display,windows->info.id,windows->image.id);
  if (windows->image.mapped)
    XWithdrawWindow(display,windows->info.id,windows->info.screen);
  if (resource_info->debug)
    (void) fprintf(stderr,"Window id: 0x%lx (info)\n",windows->info.id);
  /*
    Initialize Command widget.
  */
  XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
    resource_info,&windows->command);
  windows->command.data=MagickMenus;
  (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
  (void) sprintf(resource_name,"%s.command",resource_info->client_name);
  windows->command.geometry=XGetResourceClass(resource_info->resource_database,
    resource_name,"geometry",(char *) NULL);
  windows->command.name=MagickTitle;
  windows->command.border_width=0;
  windows->command.flags|=PPosition;
  windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
    ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
    OwnerGrabButtonMask | StructureNotifyMask;
  class_hints->res_name="command";
  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
  manager_hints->input=False;
  manager_hints->initial_state=NormalState;
  manager_hints->window_group=windows->image.id;
  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
    &windows->command);
  windows->command.highlight_stipple=windows->info.highlight_stipple;
  windows->command.shadow_stipple=windows->info.shadow_stipple;
  XSetTransientForHint(display,windows->command.id,windows->image.id);
  if (resource_info->debug)
    (void) fprintf(stderr,"Window id: 0x%lx (command)\n",windows->command.id);
  /*
    Initialize Widget window.
  */
  if (windows->widget.id != (Window) NULL)
    free((char *) windows->widget.name);
  XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
    resource_info,&windows->widget);
  (void) sprintf(resource_name,"%s.widget",resource_info->client_name);
  windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
    resource_name,"geometry",(char *) NULL);
  windows->widget.name=(char *) malloc(MaxTextExtent*sizeof(char));
  if (windows->widget.name == NULL)
    Error("Unable to create Image window","Memory allocation failed");
  *windows->widget.name='\0';
  windows->widget.border_width=0;
  windows->widget.flags|=PPosition;
  windows->widget.attributes.backing_store=WhenMapped;
  windows->widget.attributes.save_under=True;
  windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
    ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
    KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
    StructureNotifyMask;
  class_hints->res_name="widget";
  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
  manager_hints->input=True;
  manager_hints->initial_state=NormalState;
  manager_hints->window_group=windows->image.id;
  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
    &windows->widget);
  windows->widget.highlight_stipple=windows->info.highlight_stipple;
  windows->widget.shadow_stipple=windows->info.shadow_stipple;
  XSetTransientForHint(display,windows->widget.id,windows->image.id);
  if (resource_info->debug)
    (void) fprintf(stderr,"Window id: 0x%lx (widget)\n",windows->widget.id);
  /*
    Initialize popup window.
  */
  if (windows->popup.id != (Window) NULL)
    free((char *) windows->popup.name);
  XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
    resource_info,&windows->popup);
  windows->popup.name=(char *) malloc(MaxTextExtent*sizeof(char));
  if (windows->popup.name == NULL)
    Error("Unable to create Image window","Memory allocation failed");
  *windows->popup.name='\0';
  windows->popup.border_width=0;
  windows->popup.flags|=PPosition;
  windows->popup.attributes.backing_store=WhenMapped;
  windows->popup.attributes.save_under=True;
  windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
    ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
    KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
  class_hints->res_name="popup";
  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
  manager_hints->input=True;
  manager_hints->initial_state=NormalState;
  manager_hints->window_group=windows->image.id;
  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
    &windows->popup);
  windows->popup.highlight_stipple=windows->info.highlight_stipple;
  windows->popup.shadow_stipple=windows->info.shadow_stipple;
  XSetTransientForHint(display,windows->popup.id,windows->image.id);
  if (resource_info->debug)
    (void) fprintf(stderr,"Window id: 0x%lx (pop up)\n",windows->popup.id);
  /*
    Set out progress and warning handlers.
  */
  (void) SetMonitorHandler(XProgressMonitor);
  (void) SetWarningHandler(XWarning);
  if (!resource_info->display_warnings)
    (void) SetWarningHandler((ErrorHandler) NULL);
  /*
    Initialize image pixmaps structure.
  */
  XMapWindow(display,windows->image.id);
  windows->image.pixmaps=(Pixmap *) malloc(number_scenes*sizeof(Pixmap));
  if (windows->image.pixmaps == (Pixmap *) NULL)
    Error("Unable to animate images","Memory allocation failed");
  windows->image.pixmaps[0]=windows->image.pixmap;
  scene_info.pixels=(unsigned long *) NULL;
  scene_info.gamma_map=(XColor *) NULL;
  for (scene=1; scene < number_scenes; scene++)
  {
    /*
      Create X image.
    */
    windows->image.pixmap=(Pixmap) NULL;
    if ((resource_info->map_type != (char *) NULL) ||
        (visual_info->class == TrueColor) ||
        (visual_info->class == DirectColor))
      if (images[scene]->class == PseudoClass)
        {
          /*
            Get pixel info for this scene.
          */
          XGetPixelInfo(display,visual_info,map_info,resource_info,
            images[scene],&scene_info);
          windows->image.pixel_info=(&scene_info);
        }
    status=XMakeImage(display,resource_info,&windows->image,images[scene],
      images[scene]->columns,images[scene]->rows);
    if (status == False)
      Error("Unable to create X image",(char *) NULL);
    if (resource_info->debug)
      {
        (void) fprintf(stderr,"Image: [%u] %s %ux%u ",images[scene]->scene,
          images[scene]->filename,images[scene]->columns,images[scene]->rows);
        if (images[scene]->colors != 0)
          (void) fprintf(stderr,"%uc ",images[scene]->colors);
        (void) fprintf(stderr,"%s\n",images[scene]->magick);
      }
    /*
      Window name is the base of the filename.
    */
    if (resource_info->title != (char *) NULL)
      (void) strcpy(windows->image.name,resource_info->title);
    else
      {
        p=images[scene]->filename+Extent(images[scene]->filename)-1;
        while ((p > images[scene]->filename) && (*(p-1) != '/'))
          p--;
        (void) sprintf(windows->image.name,"ImageMagick: %s[%u of %u]",p,
          scene,number_scenes);
      }
    status=XStringListToTextProperty(&windows->image.name,1,&window_name);
    if (status != 0)
      {
        XSetWMName(display,windows->image.id,&window_name);
        XFree((void *) window_name.value);
      }
    windows->image.pixmaps[scene]=windows->image.pixmap;
    if (images[scene]->matte)
      XClearWindow(display,windows->image.id);
    event.xexpose.x=0;
    event.xexpose.y=0;
    event.xexpose.width=images[scene]->columns;
    event.xexpose.height=images[scene]->rows;
    if (images[scene]->page != (char *) NULL)
      (void) XParseGeometry(images[scene]->page,&event.xexpose.x,
        &event.xexpose.y,&sans,&sans);
    windows->image.x=(-event.xexpose.x);
    windows->image.y=(-event.xexpose.y);
    XRefreshWindow(display,&windows->image,&event);
    if (resource_info->delay != 0)
      XDelay(display,(unsigned long) resource_info->delay);
    else
      XDelay(display,(unsigned long) image->delay*10);
  }
  windows->image.pixel_info=(&pixel_info);
  if (windows->command.mapped)
    XMapRaised(display,windows->command.id);
  /*
    Respond to events.
  */
  loaded_image=(Image *) NULL;
  scene=0;
  image=images[0];
  state=ForwardAnimationState | RepeatAnimationState;
  (void) XMagickCommand(display,resource_info,windows,PlayCommand,&image,
    &state);
  do
  {
    if (XEventsQueued(display,QueuedAfterFlush) == 0)
      if ((state & PlayAnimationState) || (state & StepAnimationState))
        {
          /*
            Copy X pixmap to Image window.
          */
          image=images[scene];
          windows->image.ximage->width=image->columns;
          windows->image.ximage->height=image->rows;
          windows->image.pixmap=windows->image.pixmaps[scene];
          if (image->matte)
            XClearWindow(display,windows->image.id);
          event.xexpose.x=0;
          event.xexpose.y=0;
          event.xexpose.width=image->columns;
          event.xexpose.height=image->rows;
          if (image->page != (char *) NULL)
            (void) XParseGeometry(image->page,&event.xexpose.x,&event.xexpose.y,
              &sans,&sans);
          windows->image.x=(-event.xexpose.x);
          windows->image.y=(-event.xexpose.y);
          XRefreshWindow(display,&windows->image,&event);
          XSync(display,False);
          state&=(~StepAnimationState);
          if (resource_info->delay != 0)
            XDelay(display,(unsigned long) resource_info->delay);
          else
            XDelay(display,(unsigned long) image->delay*10);
          if (state & ForwardAnimationState)
            {
              /*
                Forward animation:  increment scene number.
              */
              scene++;
              if (scene == number_scenes)
                if (state & AutoReverseAnimationState)
                  {
                    state&=(~ForwardAnimationState);
                    scene--;
                  }
                else
                  {
                    if (!(state & RepeatAnimationState))
                      state&=(~PlayAnimationState);
                    scene=0;
                    sleep(resource_info->pause);
                  }
            }
          else
            {
              /*
                Reverse animation:  decrement scene number.
              */
              scene--;
              if (scene < 0)
                if (state & AutoReverseAnimationState)
                  {
                    state|=ForwardAnimationState;
                    scene=0;
                    sleep(resource_info->pause);
                  }
                else
                  {
                    if (!(state & RepeatAnimationState))
                      state&=(~PlayAnimationState);
                    scene=number_scenes-1;
                  }
            }
          continue;
        }
    /*
      Handle a window event.
    */
    timestamp=time((time_t *) NULL);
    XNextEvent(display,&event);
    if (!windows->image.stasis)
      windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0;
    if (event.xany.window == windows->command.id)
      {
        int
          id;

        /*
          Select a command from the Command widget.
        */
        id=XCommandWidget(display,windows,CommandMenu,&event);
        if (id < 0)
          continue;
        (void) strcpy(command,CommandMenu[id]);
        command_type=CommandMenus[id];
        if (id < MagickMenus)
          {
            int
              entry;

            /*
              Select a command from a pop-up menu.
            */
            entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
              command);
            if (entry < 0)
              continue;
            (void) strcpy(command,Menus[id][entry]);
            command_type=Commands[id][entry];
          }
        if (command_type != NullCommand)
          loaded_image=XMagickCommand(display,resource_info,windows,
            command_type,&image,&state);
        continue;
      }
    switch (event.type)
    {
      case ButtonPress:
      {
        if (resource_info->debug)
          (void) fprintf(stderr,"Button Press: 0x%lx %u +%d+%d\n",
            event.xbutton.window,event.xbutton.button,event.xbutton.x,
            event.xbutton.y);
        if ((event.xbutton.button == Button3) &&
            (event.xbutton.state & Mod1Mask))
          {
            /*
              Convert Alt-Button3 to Button2.
            */
            event.xbutton.button=Button2;
            event.xbutton.state&=(~Mod1Mask);
          }
        if (event.xbutton.window == windows->backdrop.id)
          {
            XSetInputFocus(display,event.xbutton.window,RevertToParent,
              event.xbutton.time);
            break;
          }
        if (event.xbutton.window == windows->image.id)
          {
            /*
              Map/unmap Command widget.
            */
            if (windows->command.mapped)
              XWithdrawWindow(display,windows->command.id,
                windows->command.screen);
            else
              {
                (void) XCommandWidget(display,windows,CommandMenu,
                  (XEvent *) NULL);
                XMapRaised(display,windows->command.id);
              }
          }
        break;
      }
      case ButtonRelease:
      {
        if (resource_info->debug)
          (void) fprintf(stderr,"Button Release: 0x%lx %u +%d+%d\n",
            event.xbutton.window,event.xbutton.button,event.xbutton.x,
            event.xbutton.y);
        break;
      }
      case ClientMessage:
      {
        if (resource_info->debug)
          (void) fprintf(stderr,"Client Message: 0x%lx 0x%lx %d 0x%lx\n",
            event.xclient.window,event.xclient.message_type,
            event.xclient.format,(unsigned long) event.xclient.data.l[0]);
        if (event.xclient.message_type == windows->im_protocols)
          {
            if (*event.xclient.data.l == windows->im_update_colormap)
              {
                /*
                  Update graphic context and window colormap.
                */
                for (i=0; i < number_windows; i++)
                {
                  if (magick_windows[i]->id == windows->icon.id)
                    continue;
                  context_values.background=pixel_info.background_color.pixel;
                  context_values.foreground=pixel_info.foreground_color.pixel;
                  XChangeGC(display,magick_windows[i]->annotate_context,
                    context_mask,&context_values);
                  XChangeGC(display,magick_windows[i]->widget_context,
                    context_mask,&context_values);
                  context_values.background=pixel_info.foreground_color.pixel;
                  context_values.foreground=pixel_info.background_color.pixel;
                  context_values.plane_mask=
                    context_values.background ^ context_values.foreground;
                  XChangeGC(display,magick_windows[i]->highlight_context,
                    context_mask | GCPlaneMask,&context_values);
                  magick_windows[i]->attributes.background_pixel=
                    pixel_info.background_color.pixel;
                  magick_windows[i]->attributes.border_pixel=
                    pixel_info.border_color.pixel;
                  magick_windows[i]->attributes.colormap=map_info->colormap;
                  XChangeWindowAttributes(display,magick_windows[i]->id,
                    magick_windows[i]->mask,&magick_windows[i]->attributes);
                }
                if (windows->backdrop.id != (Window) NULL)
                  XInstallColormap(display,map_info->colormap);
                break;
              }
            break;
          }
        if (event.xclient.message_type == windows->dnd_protocols)
          {
            Atom
              selection,
              type;

            int
              format,
              status;

            unsigned char
              *data;

            unsigned long
              after,
              length;

            /*
              Display image named by the Drag-and-Drop selection.
            */
            if ((int) (*event.xclient.data.l) != 2)
              break;
            selection=XInternAtom(display,"DndSelection",False);
            status=XGetWindowProperty(display,root_window,selection,0L,2047L,
              False,(Atom) AnyPropertyType,&type,&format,&length,&after,&data);
            if ((status != Success) || (length == 0))
              break;
            (void) strcpy(resource_info->image_info->filename,(char *) data);
            loaded_image=ReadImage(resource_info->image_info);
            if (loaded_image != (Image *) NULL)
              state|=ExitState;
            XFree((void *) data);
            break;
          }
        /*
          If client window delete message, exit.
        */
        if (event.xclient.message_type != windows->wm_protocols)
          break;
        if (*event.xclient.data.l == windows->wm_take_focus)
          {
            XSetInputFocus(display,event.xclient.window,RevertToParent,
              event.xclient.data.l[1]);
            break;
          }
        if (*event.xclient.data.l != windows->wm_delete_window)
          break;
        XWithdrawWindow(display,event.xclient.window,visual_info->screen);
        if (event.xclient.window == windows->image.id)
          {
            state|=ExitState;
            break;
          }
        break;
      }
      case ConfigureNotify:
      {
        if (resource_info->debug)
          (void) fprintf(stderr,"Configure Notify: 0x%lx %dx%d+%d+%d %d\n",
            event.xconfigure.window,event.xconfigure.width,
            event.xconfigure.height,event.xconfigure.x,event.xconfigure.y,
            event.xconfigure.send_event);
        if (event.xconfigure.window == windows->image.id)
          {
            if (event.xconfigure.send_event != 0)
              if (windows->command.geometry == (char *) NULL)
                if (!windows->command.mapped)
                  {
                    XWindowChanges
                      window_changes;

                     windows->command.x=
                        event.xconfigure.x-windows->command.width-25;
                      windows->command.y=event.xconfigure.y;
                      XConstrainWindowPosition(display,&windows->command);
                      window_changes.x=windows->command.x;
                      window_changes.y=windows->command.y;
                      XReconfigureWMWindow(display,windows->command.id,
                        windows->command.screen,CWX | CWY,&window_changes);
                  }
            /*
              Image window has a new configuration.
            */
            windows->image.width=event.xconfigure.width;
            windows->image.height=event.xconfigure.height;
            break;
          }
        if (event.xconfigure.window == windows->icon.id)
          {
            /*
              Icon window has a new configuration.
            */
            windows->icon.width=event.xconfigure.width;
            windows->icon.height=event.xconfigure.height;
            break;
          }
        break;
      }
      case DestroyNotify:
      {
        /*
          Group leader has exited.
        */
        if (resource_info->debug)
          (void) fprintf(stderr,"Destroy Notify: 0x%lx\n",
            event.xdestroywindow.window);
        if (event.xdestroywindow.window == windows->group_leader.id)
          {
            state|=ExitState;
            break;
          }
        break;
      }
      case EnterNotify:
      {
        /*
          Selectively install colormap.
        */
        if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
          if (event.xcrossing.mode != NotifyUngrab)
            XInductColormap(display,map_info->colormap);
        break;
      }
      case Expose:
      {
        if (resource_info->debug)
          (void) fprintf(stderr,"Expose: 0x%lx %dx%d+%d+%d\n",
            event.xexpose.window,event.xexpose.width,event.xexpose.height,
            event.xexpose.x,event.xexpose.y);
        /*
          Repaint windows that are now exposed.
        */
        if (event.xexpose.window == windows->image.id)
          {
            windows->image.pixmap=windows->image.pixmaps[scene];
            XRefreshWindow(display,&windows->image,&event);
            break;
          }
        if (event.xexpose.window == windows->icon.id)
          if (event.xexpose.count == 0)
            {
              XRefreshWindow(display,&windows->icon,&event);
              break;
            }
        break;
      }
      case KeyPress:
      {
        static char
          command[MaxTextExtent];

        static int
          length;

        static KeySym
          key_symbol;

        /*
          Respond to a user key press.
        */
        length=XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
          &key_symbol,(XComposeStatus *) NULL);
        *(command+length)='\0';
        if (resource_info->debug)
          (void) fprintf(stderr,"Key press: 0x%lx (%c)\n",key_symbol,*command);
        command_type=NullCommand;
        switch (key_symbol)
        {
          case XK_o:
          {
            if (!(state & ControlMask))
              break;
            command_type=OpenCommand;
          }
          case XK_space:
          {
            command_type=StepCommand;
            break;
          }
          case XK_less:
          {
            command_type=FasterCommand;
            break;
          }
          case XK_greater:
          {
            command_type=SlowerCommand;
            break;
          }
          case XK_question:
          {
            command_type=InfoCommand;
            break;
          }
          case XK_q:
          case XK_Cancel:
          {
            if (!(state & ControlMask))
              break;
            command_type=QuitCommand;
            break;
          }
          default:
            break;
        }
        if (command_type != NullCommand)
          loaded_image=XMagickCommand(display,resource_info,windows,
            command_type,&image,&state);
        break;
      }
      case KeyRelease:
      {
        /*
          Respond to a user key release.
        */
        (void) XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
          &key_symbol,(XComposeStatus *) NULL);
        if (resource_info->debug)
          (void) fprintf(stderr,"Key release: 0x%lx (%c)\n",key_symbol,
            *command);
        break;
      }
      case LeaveNotify:
      {
        /*
          Selectively uninstall colormap.
        */
        if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
          if (event.xcrossing.mode != NotifyUngrab)
            XUninductColormap(display,map_info->colormap);
        break;
      }
      case MapNotify:
      {
        if (resource_info->debug)
          (void) fprintf(stderr,"Map Notify: 0x%lx\n",event.xmap.window);
        if (event.xmap.window == windows->backdrop.id)
          {
            XSetInputFocus(display,event.xmap.window,RevertToParent,
              CurrentTime);
            windows->backdrop.mapped=True;
            break;
          }
        if (event.xmap.window == windows->image.id)
          {
            if (windows->backdrop.id != (Window) NULL)
              XInstallColormap(display,map_info->colormap);
            if (strcmp(images[0]->magick,"LOGO") == 0)
              if (strcmp(displayed_image->filename,"Untitled") == 0)
                loaded_image=XMagickCommand(display,resource_info,windows,
                  OpenCommand,&image,&state);
              else
                state|=ExitState;
            windows->image.mapped=True;
            break;
          }
        if (event.xmap.window == windows->info.id)
          {
            windows->info.mapped=True;
            break;
          }
        if (event.xmap.window == windows->icon.id)
          {
            /*
              Create an icon image.
            */
            XMakeStandardColormap(display,icon_visual,&icon_resources,
              displayed_image,icon_map,&icon_pixel);
            (void) XMakeImage(display,&icon_resources,&windows->icon,
              displayed_image,windows->icon.width,windows->icon.height);
            XSetWindowBackgroundPixmap(display,windows->icon.id,
              windows->icon.pixmap);
            XClearWindow(display,windows->icon.id);
            XWithdrawWindow(display,windows->info.id,windows->info.screen);
            windows->icon.mapped=True;
            break;
          }
        if (event.xmap.window == windows->command.id)
          {
            windows->command.mapped=True;
            break;
          }
        if (event.xmap.window == windows->popup.id)
          {
            windows->popup.mapped=True;
            break;
          }
        if (event.xmap.window == windows->widget.id)
          {
            windows->widget.mapped=True;
            break;
          }
        break;
      }
      case MappingNotify:
      {
        XRefreshKeyboardMapping(&event.xmapping);
        break;
      }
      case NoExpose:
        break;
      case ReparentNotify:
      {
        if (resource_info->debug)
          (void) fprintf(stderr,"Reparent Notify: 0x%lx=>0x%lx\n",
            event.xreparent.parent,event.xreparent.window);
        break;
      }
      case UnmapNotify:
      {
        if (resource_info->debug)
          (void) fprintf(stderr,"Unmap Notify: 0x%lx\n",event.xunmap.window);
        if (event.xunmap.window == windows->backdrop.id)
          {
            windows->backdrop.mapped=False;
            break;
          }
        if (event.xunmap.window == windows->image.id)
          {
            windows->image.mapped=False;
            break;
          }
        if (event.xunmap.window == windows->info.id)
          {
            windows->info.mapped=False;
            break;
          }
        if (event.xunmap.window == windows->icon.id)
          {
            if (map_info->colormap == icon_map->colormap)
              XConfigureImageColormap(display,resource_info,windows,
                displayed_image);
            XFreeStandardColormap(display,icon_visual,icon_map,&icon_pixel);
            windows->icon.mapped=False;
            break;
          }
        if (event.xunmap.window == windows->command.id)
          {
            windows->command.mapped=False;
            break;
          }
        if (event.xunmap.window == windows->popup.id)
          {
            if (windows->backdrop.id != (Window) NULL)
              XSetInputFocus(display,windows->image.id,RevertToParent,
                CurrentTime);
            windows->popup.mapped=False;
            break;
          }
        if (event.xunmap.window == windows->widget.id)
          {
            if (windows->backdrop.id != (Window) NULL)
              XSetInputFocus(display,windows->image.id,RevertToParent,
                CurrentTime);
            windows->widget.mapped=False;
            break;
          }
        break;
      }
      default:
      {
        if (resource_info->debug)
          (void) fprintf(stderr,"Event type: %d\n",event.type);
        break;
      }
    }
  }
  while (!(state & ExitState));
  /*
    Withdraw windows.
  */
  if (windows->info.mapped)
    XWithdrawWindow(display,windows->info.id,windows->info.screen);
  if (windows->command.mapped)
    XWithdrawWindow(display,windows->command.id,windows->command.screen);
  if (!resource_info->backdrop)
    if (windows->backdrop.mapped)
      {
        XWithdrawWindow(display,windows->backdrop.id,windows->backdrop.screen);
        XDestroyWindow(display,windows->backdrop.id);
        windows->backdrop.id=(Window) NULL;
        XWithdrawWindow(display,windows->image.id,windows->image.screen);
        XDestroyWindow(display,windows->image.id);
        windows->image.id=(Window) NULL;
      }
  XSetCursorState(display,windows,True);
  XCheckRefreshWindows(display,windows);
  for (scene=1; scene < number_scenes; scene++)
    if (windows->image.pixmaps[scene] != (Pixmap) NULL)
      XFreePixmap(display,windows->image.pixmaps[scene]);
  /*
    Change to home directory.
  */
  getwd(working_directory);
  (void) chdir(resource_info->home_directory);
  return(loaded_image);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X C o n f i g u r e I m a g e C o l o r m a p                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XConfigureImageColormap creates a new X colormap.
%
%  The format of the XConfigureImageColormap routine is:
%
%    XConfigureImageColormap(display,resource_info,windows,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 image: Specifies a pointer to a Image structure;  returned from
%      ReadImage.
%
%
*/
static void XConfigureImageColormap(Display *display,
  XResourceInfo *resource_info,XWindows *windows,Image *image)
{
  Colormap
    colormap;

  /*
    Make standard colormap.
  */
  XSetCursorState(display,windows,True);
  XCheckRefreshWindows(display,windows);
  XMakeStandardColormap(display,windows->image.visual_info,resource_info,
    image,windows->image.map_info,windows->image.pixel_info);
  colormap=windows->image.map_info->colormap;
  XSetWindowColormap(display,windows->image.id,colormap);
  XSetWindowColormap(display,windows->command.id,colormap);
  XSetWindowColormap(display,windows->widget.id,colormap);
  XSetCursorState(display,windows,False);
  XClientMessage(display,windows->image.id,windows->im_protocols,
    windows->im_update_colormap,CurrentTime);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X M a g i c k C o m m a n d                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XMagickCommand makes a transform to the image or Image window as
%  specified by a user menu button or keyboard command.
%
%  The format of the XMagickCommand routine is:
%
%    XMagickCommand(display,resource_info,windows,image,command_type,state);
%
%  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 image: Specifies a pointer to a Image structure;  XMagickCommand
%      may transform the image and return a new image pointer.
%
%    o state: Specifies an unsigned int;  XMagickCommand may return a
%      modified state.
%
%
*/
static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
  XWindows *windows,const CommandType command_type,Image **image,
  unsigned int *state)
{
#define LoadImageText  "  Loading images...  "

  Image
    *loaded_image;

  int
    status;

  XTextProperty
    window_name;

  /*
    Process user command.
  */
  loaded_image=(Image *) NULL;
  switch (command_type)
  {
    case OpenCommand:
    {
      char
        **filelist;

      Image
        *image,
        *next_image;

      ImageInfo
        local_info;

      int
        number_files;

      MonitorHandler
        handler;

      register int
        i;

      static char
        filename[MaxTextExtent] = "\0",
        filenames[MaxTextExtent] = "*";

      /*
        Request file name from user.
      */
      XFileBrowserWidget(display,windows,"Animate",filenames);
      if (*filenames == '\0')
        return((Image *) NULL);
      /*
        Expand the filenames.
      */
      filelist=(char **) malloc(sizeof(char *));
      if (filelist == (char **) NULL)
        {
          Warning("Memory allocation error",(char *) NULL);
          return((Image *) NULL);
        }
      number_files=1;
      filelist[0]=filenames;
      ExpandFilenames(&number_files,&filelist);
      if (number_files == 0)
        {
          Warning("No image files were found",filenames);
          return((Image *) NULL);
        }
      local_info=(*resource_info->image_info);
      image=(Image *) NULL;
      XSetCursorState(display,windows,True);
      XCheckRefreshWindows(display,windows);
      for (i=0; i < number_files; i++)
      {
        if (number_files > 5)
          handler=SetMonitorHandler((MonitorHandler) NULL);
        local_info.filename=filelist[i];
        *local_info.magick='\0';
        next_image=ReadImage(&local_info);
        if (filelist[i] != filenames)
          free((char *) filelist[i]);
        if (next_image != (Image *) NULL)
          if (image == (Image *) NULL)
            image=next_image;
          else
            {
              image->next=next_image;
              image->next->previous=image;
              image=image->next;
            }
        if (number_files <= 5)
          continue;
        (void) SetMonitorHandler(handler);
        ProgressMonitor(LoadImageText,i,number_files);
      }
      if (image == (Image *) NULL)
        {
          XSetCursorState(display,windows,False);
          Warning("No images were loaded",filenames);
          return((Image *) NULL);
        }
      while (image->previous != (Image *) NULL)
        image=image->previous;
      loaded_image=image;
      *state|=ExitState;
      break;
    }
    case PlayCommand:
    {
      *state|=PlayAnimationState;
      *state&=(~AutoReverseAnimationState);
      XWithdrawWindow(display,windows->info.id,windows->info.screen);
      /*
        Window name is the base of the filename.
      */
      (void) sprintf(windows->image.name,"ImageMagick: %s",
        ClientName((*image)->filename));
      if (resource_info->title != (char *) NULL)
        (void) strcpy(windows->image.name,resource_info->title);
      status=XStringListToTextProperty(&windows->image.name,1,&window_name);
      if (status == 0)
        break;
      XSetWMName(display,windows->image.id,&window_name);
      XFree((void *) window_name.value);
      break;
    }
    case StepCommand:
    {
      register char
        *p;

      *state|=StepAnimationState;
      *state&=(~PlayAnimationState);
      if (resource_info->title != (char *) NULL)
        break;
      /*
        Window name is the base of the filename.
      */
      p=(*image)->filename+Extent((*image)->filename)-1;
      while ((p > (*image)->filename) && (*(p-1) != '/'))
        p--;
      (void) sprintf(windows->image.name,"%s [%u]",p,(*image)->scene);
      status=XStringListToTextProperty(&windows->image.name,1,&window_name);
      if (status == 0)
        break;
      XSetWMName(display,windows->image.id,&window_name);
      XInfoWidget(display,windows,windows->image.name);
      XFree((void *) window_name.value);
      break;
    }
    case RepeatCommand:
    {
      *state|=RepeatAnimationState;
      *state&=(~AutoReverseAnimationState);
      *state|=PlayAnimationState;
      break;
    }
    case AutoReverseCommand:
    {
      *state|=AutoReverseAnimationState;
      *state&=(~RepeatAnimationState);
      *state|=PlayAnimationState;
      break;
    }
    case SlowerCommand:
    {
      resource_info->delay<<=1;
      if (resource_info->delay == 0)
        resource_info->delay=1;
      break;
    }
    case FasterCommand:
    {
      resource_info->delay>>=1;
      break;
    }
    case ForwardCommand:
    {
      *state=ForwardAnimationState;
      *state&=(~AutoReverseAnimationState);
      break;
    }
    case ReverseCommand:
    {
      *state&=(~ForwardAnimationState);
      *state&=(~AutoReverseAnimationState);
      break;
    }
    case InfoCommand:
    {
      XDisplayImageInfo(display,resource_info,windows,(Image *) NULL,*image);
      break;
    }
    case HelpCommand:
    {
      XTextViewWidget(display,resource_info,windows,False,
        "Help Viewer - Animate",ImageMagickHelp);
      break;
    }
    case QuitCommand:
    {
      /*
        Exit program
      */
      if (!resource_info->confirm_exit)
        *state|=ExitState;
      else
        {
          int
            status;

          /*
            Confirm program exit.
          */
          status=XConfirmWidget(display,windows,"Do you really want to exit",
            resource_info->client_name);
          if (status > 0)
            *state|=ExitState;
        }
      break;
    }
    default:
      break;
  }
  return(loaded_image);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X P r o g r e s s M o n i t o r                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XProgressMonitor displays the progress a task is making in
%  completing a task.
%
%  The format of the XProgressMonitor routine is:
%
%      XProgressMonitor(task,quantum,span)
%
%  A description of each parameter follows:
%
%    o task: Identifies the task in progress.
%
%    o quantum: Specifies the quantum position within the span which represents
%      how much progress has been made in completing a task.
%
%    o span: Specifies the span relative to completing a task.
%
%
*/
static void XProgressMonitor(char *task,const unsigned int quantum,
  const unsigned int span)
{
  XMonitorWidget(display,windows,task,quantum,span);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   X W a r n i n g                                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function XWarning displays a warning message in a Notice widget.
%
%  The format of the XWarning routine is:
%
%      XWarning(message,qualifier)
%
%  A description of each parameter follows:
%
%    o message: Specifies the message to display before terminating the
%      program.
%
%    o qualifier: Specifies any qualifier to the message.
%
%
*/
static void XWarning(const char *message,const char *qualifier)
{
  char
    text[MaxTextExtent];

  if (message == (char *) NULL)
    return;
  (void) strcpy(text,message);
  (void) strcat(text,":");
  XNoticeWidget(display,windows,text,qualifier);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%    M a i n                                                                  %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
int main(int argc,char **argv)
{
  char
    *client_name,
    *option,
    *resource_value,
    *server_name;

  Image
    *image,
    *loaded_image,
    *next_image;

  ImageInfo
    image_info;

  int
    i,
    x,
    y;

  unsigned int
    first_scene,
    last_scene,
    scene;

  XResourceInfo
    resource_info;

  XrmDatabase
    resource_database;

  /*
    Set defaults.
  */
  ReadCommandlLine(argc,&argv);
  client_name=ClientName(*argv);
  display=(Display *) NULL;
  first_scene=0;
  GetImageInfo(&image_info);
  image=(Image *) NULL;
  last_scene=0;
  server_name=(char *) NULL;
  /*
    Check for server name specified on the command line.
  */
  ExpandFilenames(&argc,&argv);
  for (i=1; i < argc; i++)
  {
    /*
      Check command line for server name.
    */
    option=argv[i];
    if ((Extent(option) == 1) || ((*option != '-') && (*option != '+')))
      continue;
    if (strcmp("display",option+1) == 0)
      {
        /*
          User specified server name.
        */
        i++;
        if (i == argc)
          Error("Missing server name on -display",(char *) NULL);
        server_name=argv[i];
        break;
      }
    if (strncmp("help",option+1,2) == 0)
      Usage(client_name);
  }
  /*
    Get user defaults from X resource database.
  */
  display=XOpenDisplay(server_name);
  if (display == (Display *) NULL)
    Error("Unable to connect to X server",XDisplayName(server_name));
  XSetErrorHandler(XError);
  resource_database=XGetResourceDatabase(display,client_name);
  XGetResourceInfo(resource_database,client_name,&resource_info);
  resource_info.image_info=(&image_info);
  resource_value=XGetResourceClass(resource_database,client_name,"delay","60");
  resource_info.delay=0;
  resource_info.pause=0;
  (void) XParseGeometry(resource_value,&x,&y,&resource_info.delay,
    &resource_info.pause);
  image_info.density=
    XGetResourceClass(resource_database,client_name,"density","85");
  resource_value=
    XGetResourceClass(resource_database,client_name,"interlace","plane");
  image_info.interlace=UndefinedInterlace;
  if (Latin1Compare("none",resource_value) == 0)
    image_info.interlace=NoneInterlace;
  if (Latin1Compare("line",resource_value) == 0)
    image_info.interlace=LineInterlace;
  if (Latin1Compare("plane",resource_value) == 0)
    image_info.interlace=PlaneInterlace;
  if (Latin1Compare("partition",resource_value) == 0)
    image_info.interlace=PartitionInterlace;
  if (image_info.interlace == UndefinedInterlace)
    Warning("Unrecognized interlace type",resource_value);
  resource_value=
    XGetResourceClass(resource_database,client_name,"verbose","False");
  image_info.verbose=IsTrue(resource_value);
  /*
    Parse command line.
  */
  for (i=1; i <= argc; i++)
  {
    if (i < argc)
      option=argv[i];
    else
      if (image != (Image *) NULL)
        break;
      else
        if (!isatty(STDIN_FILENO))
          option="-";
        else
          option="logo:Untitled";
    if ((Extent(option) > 1) && ((*option == '-') || (*option == '+')))
      switch (*(option+1))
      {
        case 'b':
        {
          if (strncmp("backdrop",option+1,5) == 0)
            {
              resource_info.backdrop=(*option == '-');
              break;
            }
          if (strncmp("background",option+1,5) == 0)
            {
              resource_info.background_color=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing color on -background",(char *) NULL);
                  resource_info.background_color=argv[i];
                }
              break;
            }
          if (strncmp("bordercolor",option+1,7) == 0)
            {
              resource_info.border_color=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing color on -bordercolor",(char *) NULL);
                  resource_info.border_color=argv[i];
                }
              break;
            }
          if (strncmp("borderwidth",option+1,7) == 0)
            {
              resource_info.border_width=0;
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !sscanf(argv[i],"%d",&x))
                    Error("Missing width on -borderwidth",(char *) NULL);
                  resource_info.border_width=atoi(argv[i]);
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'c':
        {
          if (strncmp("colormap",option+1,6) == 0)
            {
              resource_info.colormap=PrivateColormap;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing type on -colormap",(char *) NULL);
                  option=argv[i];
                  resource_info.colormap=UndefinedColormap;
                  if (Latin1Compare("private",option) == 0)
                    resource_info.colormap=PrivateColormap;
                  if (Latin1Compare("shared",option) == 0)
                    resource_info.colormap=SharedColormap;
                  if (resource_info.colormap == UndefinedColormap)
                    Error("Invalid colormap type on -colormap",option);
                }
              break;
            }
          if (strncmp("colors",option+1,7) == 0)
            {
              resource_info.number_colors=0;
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !sscanf(argv[i],"%d",&x))
                    Error("Missing colors on -colors",(char *) NULL);
                  resource_info.number_colors=atoi(argv[i]);
                }
              break;
            }
          if (strncmp("colorspace",option+1,7) == 0)
            {
              resource_info.colorspace=RGBColorspace;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing type on -colorspace",(char *) NULL);
                  option=argv[i];
                  resource_info.colorspace=UndefinedColorspace;
                  if (Latin1Compare("gray",option) == 0)
                    {
                      resource_info.colorspace=GRAYColorspace;
                      resource_info.number_colors=256;
                      resource_info.tree_depth=8;
                    }
                  if (Latin1Compare("ohta",option) == 0)
                    resource_info.colorspace=OHTAColorspace;
                  if (Latin1Compare("rgb",option) == 0)
                    resource_info.colorspace=RGBColorspace;
                  if (Latin1Compare("transparent",option) == 0)
                    resource_info.colorspace=TransparentColorspace;
                  if (Latin1Compare("xyz",option) == 0)
                    resource_info.colorspace=XYZColorspace;
                  if (Latin1Compare("ycbcr",option) == 0)
                    resource_info.colorspace=YCbCrColorspace;
                  if (Latin1Compare("yiq",option) == 0)
                    resource_info.colorspace=YIQColorspace;
                  if (Latin1Compare("ypbpr",option) == 0)
                    resource_info.colorspace=YPbPrColorspace;
                  if (Latin1Compare("yuv",option) == 0)
                    resource_info.colorspace=YUVColorspace;
                  if (resource_info.colorspace == UndefinedColorspace)
                    Error("Invalid colorspace type on -colorspace",option);
                }
              break;
            }
          if (strncmp("crop",option+1,2) == 0)
            {
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !IsGeometry(argv[i]))
                    Error("Missing geometry on -crop",(char *) NULL);
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'd':
        {
          if (strncmp("debug",option+1,3) == 0)
            {
              resource_info.debug=(*option == '-');
              break;
            }
          if (strncmp("delay",option+1,3) == 0)
            {
              resource_info.delay=0;
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !sscanf(argv[i],"%d",&x))
                    Error("Missing seconds on -delay",(char *) NULL);
                  (void) XParseGeometry(argv[i],&x,&y,&resource_info.delay,
                    &resource_info.pause);
                }
              break;
            }
          if (strncmp("density",option+1,3) == 0)
            {
              image_info.density=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !IsGeometry(argv[i]))
                    Error("Missing geometry on -density",(char *) NULL);
                  image_info.density=argv[i];
                }
              break;
            }
          if (strcmp("display",option+1) == 0)
            {
              server_name=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing server name on -display",(char *) NULL);
                  server_name=argv[i];
                }
              break;
            }
          if (strncmp("dither",option+1,3) == 0)
            {
              resource_info.dither=(*option == '-');
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'f':
        {
          if (strncmp("font",option+1,3) == 0)
            {
              resource_info.font=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing font name on -font",(char *) NULL);
                  resource_info.font=argv[i];
                }
              break;
            }
          if (strncmp("foreground",option+1,3) == 0)
            {
              resource_info.foreground_color=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing foreground on -foreground",(char *) NULL);
                  resource_info.foreground_color=argv[i];
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'g':
        {
          if (strncmp("gamma",option+1,2) == 0)
            {
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !sscanf(argv[i],"%f",(float *) &x))
                    Error("Missing value on -gamma",(char *) NULL);
                }
              break;
            }
          if (strncmp("geometry",option+1,2) == 0)
            {
              resource_info.image_geometry=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !IsGeometry(argv[i]))
                    Error("Missing geometry on -geometry",(char *) NULL);
                  resource_info.image_geometry=argv[i];
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'h':
        {
          if (strncmp("help",option+1,2) == 0)
            {
              Usage(client_name);
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'i':
        {
          if (strncmp("iconGeometry",option+1,5) == 0)
            {
              resource_info.icon_geometry=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !IsGeometry(argv[i]))
                    Error("Missing geometry on -iconGeometry",(char *) NULL);
                  resource_info.icon_geometry=argv[i];
                }
              break;
            }
          if (strncmp("iconic",option+1,5) == 0)
            {
              resource_info.iconic=(*option == '-');
              break;
            }
          if (strncmp("interlace",option+1,3) == 0)
            {
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing type on -interlace",(char *) NULL);
                  option=argv[i];
                  image_info.interlace=UndefinedInterlace;
                  if (Latin1Compare("none",option) == 0)
                    image_info.interlace=NoneInterlace;
                  if (Latin1Compare("line",option) == 0)
                    image_info.interlace=LineInterlace;
                  if (Latin1Compare("plane",option) == 0)
                    image_info.interlace=PlaneInterlace;
                  if (Latin1Compare("partition",option) == 0)
                    image_info.interlace=PartitionInterlace;
                  if (image_info.interlace == UndefinedInterlace)
                    Error("Invalid interlace type on -interlace",option);
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'm':
        {
          if (strncmp("map",option+1,3) == 0)
            {
              argv[i]="+sans";
              resource_info.map_type=(char *) NULL;
              if (*option == '-')
                {
                  argv[i]="-sans";
                  i++;
                  if (i == argc)
                    Error("Missing map type on -map",(char *) NULL);
                  resource_info.map_type=argv[i];
                }
              break;
            }
          if (strcmp("matte",option+1) == 0)
            break;
          if (strncmp("mattecolor",option+1,6) == 0)
            {
              resource_info.matte_color=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing color on -mattecolor",(char *) NULL);
                  resource_info.matte_color=argv[i];
                }
              break;
            }
          if (strncmp("monochrome",option+1,2) == 0)
            {
              resource_info.monochrome=(*option == '-');
              if (resource_info.monochrome)
                {
                  resource_info.number_colors=2;
                  resource_info.tree_depth=8;
                  resource_info.colorspace=GRAYColorspace;
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'n':
        {
          resource_info.name=(char *) NULL;
          if (*option == '-')
            {
              i++;
              if (i == argc)
                Error("Missing name on -name",(char *) NULL);
              resource_info.name=argv[i];
            }
          break;
        }
        case 's':
        {
          if (strncmp("scene",option+1,3) == 0)
            {
              first_scene=0;
              last_scene=0;
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !sscanf(argv[i],"%d",&x))
                    Error("Missing scene number on -scene",(char *) NULL);
                  first_scene=atoi(argv[i]);
                  last_scene=first_scene;
                  (void) sscanf(argv[i],"%u-%u",&first_scene,&last_scene);
                }
              break;
            }
          if (strncmp("shared_memory",option+1,4) == 0)
            {
              resource_info.use_shared_memory=(*option == '-');
              break;
            }
          if (strncmp("size",option+1,2) == 0)
            {
              image_info.size=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !IsGeometry(argv[i]))
                    Error("Missing geometry on -size",(char *) NULL);
                  image_info.size=argv[i];
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 't':
        {
          if (strncmp("text_font",option+1,3) == 0)
            {
              resource_info.text_font=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing font name on -text_font",(char *) NULL);
                  resource_info.text_font=argv[i];
                }
              break;
            }
          if (strncmp("title",option+1,2) == 0)
            {
              resource_info.title=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing title on -title",(char *) NULL);
                  resource_info.title=argv[i];
                }
              break;
            }
          if (strncmp("treedepth",option+1,3) == 0)
            {
              resource_info.tree_depth=0;
              if (*option == '-')
                {
                  i++;
                  if ((i == argc) || !sscanf(argv[i],"%d",&x))
                    Error("Missing depth on -treedepth",(char *) NULL);
                  resource_info.tree_depth=atoi(argv[i]);
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'v':
        {
          if (strncmp("verbose",option+1,2) == 0)
            {
              image_info.verbose=(*option == '-');
              break;
            }
          if (strncmp("visual",option+1,2) == 0)
            {
              resource_info.visual_type=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing visual class on -visual",(char *) NULL);
                  resource_info.visual_type=argv[i];
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case 'w':
        {
          if (strncmp("window",option+1,2) == 0)
            {
              resource_info.window_id=(char *) NULL;
              if (*option == '-')
                {
                  i++;
                  if (i == argc)
                    Error("Missing id, name, or 'root' on -window",
                      (char *) NULL);
                  resource_info.window_id=argv[i];
                }
              break;
            }
          Error("Unrecognized option",option);
          break;
        }
        case '?':
        {
          Usage(client_name);
          break;
        }
        default:
        {
          Error("Unrecognized option",option);
          break;
        }
      }
    else
      {
        /*
          Option is a file name.
        */
        for (scene=first_scene; scene <= last_scene ; scene++)
        {
          /*
            Read image.
          */
          (void) strcpy(image_info.filename,option);
          if (first_scene != last_scene)
            {
              char
                filename[MaxTextExtent];

              /*
                Form filename for multi-part images.
              */
              (void) sprintf(filename,image_info.filename,scene);
              if (strcmp(filename,image_info.filename) == 0)
                (void) sprintf(filename,"%s[%u]",image_info.filename,scene);
              (void) strcpy(image_info.filename,filename);
            }
          (void) strcpy(image_info.magick,"MIFF");
          image_info.server_name=resource_info.server_name;
          image_info.font=resource_info.font;
          image_info.dither=resource_info.dither;
          image_info.monochrome=resource_info.monochrome;
          next_image=ReadImage(&image_info);
          if (next_image == (Image *) NULL)
            if (*option == '-')
              break;
            else
              continue;
          MogrifyImages(&image_info,i,argv,&next_image);
          if (image == (Image *) NULL)
            image=next_image;
          else
            {
              /*
                Link image into image list.
              */
              next_image->previous=image;
              image->next=next_image;
              while (image->next != (Image *) NULL)
                image=image->next;
            }
        }
      }
  }
  if (image == (Image *) NULL)
    Error("Missing an image file name",(char *) NULL);
  while (image->previous != (Image *) NULL)
    image=image->previous;
  if (resource_info.window_id != (char *) NULL)
    XAnimateBackgroundImage(display,&resource_info,image);
  else
    {
      /*
        Animate image to X server.
      */
      loaded_image=XAnimateImages(display,&resource_info,argv,argc,image);
      DestroyImages(image);
      while (loaded_image != (Image *) NULL)
      {
        image=loaded_image;
        MogrifyImage(&image_info,argc-1,argv,&image);
        loaded_image=XAnimateImages(display,&resource_info,argv,argc,image);
        DestroyImages(image);
      }
    }
  Exit(0);
  return(False);
}

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