]> granicus.if.org Git - imagemagick/blob - magick/animate.c
(no commit message)
[imagemagick] / magick / animate.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                AAA   N   N  IIIII  M   M   AAA   TTTTT  EEEEE               %
7 %               A   A  NN  N    I    MM MM  A   A    T    E                   %
8 %               AAAAA  N N N    I    M M M  AAAAA    T    EEE                 %
9 %               A   A  N  NN    I    M   M  A   A    T    E                   %
10 %               A   A  N   N  IIIII  M   M  A   A    T    EEEEE               %
11 %                                                                             %
12 %                                                                             %
13 %              Methods to Interactively Animate an Image Sequence             %
14 %                                                                             %
15 %                             Software Design                                 %
16 %                               John Cristy                                   %
17 %                                July 1992                                    %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/animate.h"
44 #include "magick/animate-private.h"
45 #include "magick/client.h"
46 #include "magick/color.h"
47 #include "magick/color-private.h"
48 #include "magick/colorspace.h"
49 #include "magick/constitute.h"
50 #include "magick/delegate.h"
51 #include "magick/exception.h"
52 #include "magick/exception-private.h"
53 #include "magick/geometry.h"
54 #include "magick/image-private.h"
55 #include "magick/layer.h"
56 #include "magick/list.h"
57 #include "magick/log.h"
58 #include "magick/image.h"
59 #include "magick/memory_.h"
60 #include "magick/monitor.h"
61 #include "magick/monitor-private.h"
62 #include "magick/option.h"
63 #include "magick/property.h"
64 #include "magick/resource_.h"
65 #include "magick/string_.h"
66 #include "magick/string-private.h"
67 #include "magick/transform.h"
68 #include "magick/utility.h"
69 #include "magick/version.h"
70 #include "magick/widget.h"
71 #include "magick/xwindow-private.h"
72 \f
73 #if defined(MAGICKCORE_X11_DELEGATE)
74 /*
75   Animate state declarations.
76 */
77 #define AutoReverseAnimationState 0x0004
78 #define ForwardAnimationState 0x0008
79 #define HighlightState  0x0010
80 #define PlayAnimationState 0x0020
81 #define RepeatAnimationState 0x0040
82 #define StepAnimationState 0x0080
83
84 /*
85   Static declarations.
86 */
87 static const char
88   *AnimateHelp[]=
89   {
90     "BUTTONS",
91     "",
92     "  Press any button to map or unmap the Command widget.",
93     "",
94     "COMMAND WIDGET",
95     "  The Command widget lists a number of sub-menus and commands.",
96     "  They are",
97     "",
98     "    Animate",
99     "      Open...",
100     "      Save...",
101     "      Play",
102     "      Step",
103     "      Repeat",
104     "      Auto Reverse",
105     "    Speed",
106     "      Slower",
107     "      Faster",
108     "    Direction",
109     "      Forward",
110     "      Reverse",
111     "      Help",
112     "        Overview",
113     "        Browse Documentation",
114     "        About Animate",
115     "    Image Info",
116     "    Quit",
117     "",
118     "  Menu items with a indented triangle have a sub-menu.  They",
119     "  are represented above as the indented items.  To access a",
120     "  sub-menu item, move the pointer to the appropriate menu and",
121     "  press a button and drag.  When you find the desired sub-menu",
122     "  item, release the button and the command is executed.  Move",
123     "  the pointer away from the sub-menu if you decide not to",
124     "  execute a particular command.",
125     "",
126     "KEYBOARD ACCELERATORS",
127     "  Accelerators are one or two key presses that effect a",
128     "  particular command.  The keyboard accelerators that",
129     "  animate(1) understands is:",
130     "",
131     "  Ctl+O  Press to open an image from a file.",
132     "",
133     "  space  Press to display the next image in the sequence.",
134     "",
135     "  <      Press to speed-up the display of the images.  Refer to",
136     "         -delay for more information.",
137     "",
138     "  >      Press to slow the display of the images.  Refer to",
139     "         -delay for more information.",
140     "",
141     "  F1     Press to display helpful information about animate(1).",
142     "",
143     "  Find   Press to browse documentation about ImageMagick.",
144     "",
145     "  ?      Press to display information about the image.  Press",
146     "         any key or button to erase the information.",
147     "",
148     "         This information is printed: image name;  image size;",
149     "         and the total number of unique colors in the image.",
150     "",
151     "  Ctl-q  Press to discard all images and exit program.",
152     (char *) NULL
153   };
154 \f
155 /*
156   Constant declarations.
157 */
158 static const char
159   *PageSizes[]=
160   {
161     "Letter",
162     "Tabloid",
163     "Ledger",
164     "Legal",
165     "Statement",
166     "Executive",
167     "A3",
168     "A4",
169     "A5",
170     "B4",
171     "B5",
172     "Folio",
173     "Quarto",
174     "10x14",
175     (char *) NULL
176   };
177
178 static const unsigned char
179   HighlightBitmap[8] =
180   {
181     (unsigned char) 0xaa,
182     (unsigned char) 0x55,
183     (unsigned char) 0xaa,
184     (unsigned char) 0x55,
185     (unsigned char) 0xaa,
186     (unsigned char) 0x55,
187     (unsigned char) 0xaa,
188     (unsigned char) 0x55
189   },
190   ShadowBitmap[8] =
191   {
192     (unsigned char) 0x00,
193     (unsigned char) 0x00,
194     (unsigned char) 0x00,
195     (unsigned char) 0x00,
196     (unsigned char) 0x00,
197     (unsigned char) 0x00,
198     (unsigned char) 0x00,
199     (unsigned char) 0x00
200   };
201 \f
202 /*
203   Enumeration declarations.
204 */
205 typedef enum
206 {
207   OpenCommand,
208   SaveCommand,
209   PlayCommand,
210   StepCommand,
211   RepeatCommand,
212   AutoReverseCommand,
213   SlowerCommand,
214   FasterCommand,
215   ForwardCommand,
216   ReverseCommand,
217   HelpCommand,
218   BrowseDocumentationCommand,
219   VersionCommand,
220   InfoCommand,
221   QuitCommand,
222   StepBackwardCommand,
223   StepForwardCommand,
224   NullCommand
225 } CommandType;
226 \f
227 /*
228   Stipples.
229 */
230 #define HighlightWidth  8
231 #define HighlightHeight  8
232 #define ShadowWidth  8
233 #define ShadowHeight  8
234 \f
235 /*
236   Forward declarations.
237 */
238 static Image
239   *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
240     Image **,MagickStatusType *);
241
242 static MagickBooleanType
243   XSaveImage(Display *,XResourceInfo *,XWindows *,Image *);
244 \f
245 /*
246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 %                                                                             %
248 %                                                                             %
249 %                                                                             %
250 %   A n i m a t e I m a g e s                                                 %
251 %                                                                             %
252 %                                                                             %
253 %                                                                             %
254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255 %
256 %  AnimateImages() repeatedly displays an image sequence to any X window
257 %  screen.  It returns a value other than 0 if successful.  Check the
258 %  exception member of image to determine the reason for any failure.
259 %
260 %  The format of the AnimateImages method is:
261 %
262 %      MagickBooleanType AnimateImages(const ImageInfo *image_info,
263 %        Image *images)
264 %
265 %  A description of each parameter follows:
266 %
267 %    o image_info: the image info.
268 %
269 %    o image: the image.
270 %
271 */
272 MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
273   Image *images)
274 {
275   char
276     *argv[1];
277
278   Display
279     *display;
280
281   MagickStatusType
282     status;
283
284   XrmDatabase
285     resource_database;
286
287   XResourceInfo
288     resource_info;
289
290   assert(image_info != (const ImageInfo *) NULL);
291   assert(image_info->signature == MagickSignature);
292   assert(images != (Image *) NULL);
293   assert(images->signature == MagickSignature);
294   if (images->debug != MagickFalse)
295     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
296   display=XOpenDisplay(image_info->server_name);
297   if (display == (Display *) NULL)
298     {
299       (void) ThrowMagickException(&images->exception,GetMagickModule(),
300         XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
301         image_info->server_name));
302       return(MagickFalse);
303     }
304   if (images->exception.severity != UndefinedException)
305     CatchException(&images->exception);
306   (void) XSetErrorHandler(XError);
307   resource_database=XGetResourceDatabase(display,GetClientName());
308   (void) ResetMagickMemory(&resource_info,0,sizeof(XResourceInfo));
309   XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
310   if (image_info->page != (char *) NULL)
311     resource_info.image_geometry=AcquireString(image_info->page);
312   resource_info.immutable=MagickTrue;
313   argv[0]=AcquireString(GetClientName());
314   (void) XAnimateImages(display,&resource_info,argv,1,images);
315   argv[0]=DestroyString(argv[0]);
316   (void) XCloseDisplay(display);
317   XDestroyResourceInfo(&resource_info);
318   status=images->exception.severity == UndefinedException ?
319     MagickTrue : MagickFalse;
320   return(status != 0 ? MagickTrue : MagickFalse);
321 }
322 \f
323 /*
324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325 %                                                                             %
326 %                                                                             %
327 %                                                                             %
328 +   X M a g i c k C o m m a n d                                               %
329 %                                                                             %
330 %                                                                             %
331 %                                                                             %
332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333 %
334 %  XMagickCommand() makes a transform to the image or Image window as specified
335 %  by a user menu button or keyboard command.
336 %
337 %  The format of the XMagickCommand method is:
338 %
339 %      Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
340 %        XWindows *windows,const CommandType command_type,Image **image,
341 %        MagickStatusType *state)
342 %
343 %  A description of each parameter follows:
344 %
345 %    o display: Specifies a connection to an X server; returned from
346 %      XOpenDisplay.
347 %
348 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
349 %
350 %    o windows: Specifies a pointer to a XWindows structure.
351 %
352 %    o image: the image;  XMagickCommand
353 %      may transform the image and return a new image pointer.
354 %
355 %    o state: Specifies a MagickStatusType;  XMagickCommand may return a
356 %      modified state.
357 %
358 %
359 */
360 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
361   XWindows *windows,const CommandType command_type,Image **image,
362   MagickStatusType *state)
363 {
364   Image
365     *nexus;
366
367   MagickBooleanType
368     proceed;
369
370   MagickStatusType
371     status;
372
373   XTextProperty
374     window_name;
375
376   /*
377     Process user command.
378   */
379   nexus=NewImageList();
380   switch (command_type)
381   {
382     case OpenCommand:
383     {
384       char
385         **filelist;
386
387       ExceptionInfo
388         *exception;
389
390       Image
391         *images,
392         *next;
393
394       ImageInfo
395         *read_info;
396
397       int
398         number_files;
399
400       register int
401         i;
402
403       static char
404         filenames[MaxTextExtent] = "*";
405
406       if (resource_info->immutable != MagickFalse)
407         break;
408       /*
409         Request file name from user.
410       */
411       XFileBrowserWidget(display,windows,"Animate",filenames);
412       if (*filenames == '\0')
413         return((Image *) NULL);
414       /*
415         Expand the filenames.
416       */
417       filelist=(char **) AcquireAlignedMemory(1,sizeof(char *));
418       if (filelist == (char **) NULL)
419         {
420           ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
421             filenames);
422           return((Image *) NULL);
423         }
424       number_files=1;
425       filelist[0]=filenames;
426       status=ExpandFilenames(&number_files,&filelist);
427       if ((status == MagickFalse) || (number_files == 0))
428         {
429           if (number_files == 0)
430             {
431               ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
432              return((Image *) NULL);
433             }
434           ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
435             filenames);
436           return((Image *) NULL);
437         }
438       read_info=CloneImageInfo(resource_info->image_info);
439       exception=AcquireExceptionInfo();
440       images=NewImageList();
441       XSetCursorState(display,windows,MagickTrue);
442       XCheckRefreshWindows(display,windows);
443       for (i=0; i < number_files; i++)
444       {
445         (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
446         filelist[i]=DestroyString(filelist[i]);
447         *read_info->magick='\0';
448         next=ReadImage(read_info,exception);
449         CatchException(exception);
450         if (next != (Image *) NULL)
451           AppendImageToList(&images,next);
452         if (number_files <= 5)
453           continue;
454         proceed=SetImageProgress(images,LoadImageTag,i,(MagickSizeType)
455           number_files);
456         if (proceed == MagickFalse)
457           break;
458       }
459       filelist=(char **) RelinquishMagickMemory(filelist);
460       exception=DestroyExceptionInfo(exception);
461       read_info=DestroyImageInfo(read_info);
462       if (images == (Image *) NULL)
463         {
464           XSetCursorState(display,windows,MagickFalse);
465           ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
466           return((Image *) NULL);
467         }
468       nexus=GetFirstImageInList(images);
469       *state|=ExitState;
470       break;
471     }
472     case PlayCommand:
473     {
474       char
475         basename[MaxTextExtent];
476
477       int
478         status;
479
480       /*
481         Window name is the base of the filename.
482       */
483       *state|=PlayAnimationState;
484       *state&=(~AutoReverseAnimationState);
485       GetPathComponent((*image)->magick_filename,BasePath,basename);
486       (void) FormatMagickString(windows->image.name,MaxTextExtent,
487         "ImageMagick: %s",basename);
488       if (resource_info->title != (char *) NULL)
489         {
490           char
491             *title;
492
493           title=InterpretImageProperties(resource_info->image_info,*image,
494             resource_info->title);
495           (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
496           title=DestroyString(title);
497         }
498       status=XStringListToTextProperty(&windows->image.name,1,&window_name);
499       if (status == 0)
500         break;
501       XSetWMName(display,windows->image.id,&window_name);
502       (void) XFree((void *) window_name.value);
503       break;
504     }
505     case StepCommand:
506     case StepBackwardCommand:
507     case StepForwardCommand:
508     {
509       *state|=StepAnimationState;
510       *state&=(~PlayAnimationState);
511       if (command_type == StepBackwardCommand)
512         *state&=(~ForwardAnimationState);
513       if (command_type == StepForwardCommand)
514         *state|=ForwardAnimationState;
515       if (resource_info->title != (char *) NULL)
516         break;
517       break;
518     }
519     case RepeatCommand:
520     {
521       *state|=RepeatAnimationState;
522       *state&=(~AutoReverseAnimationState);
523       *state|=PlayAnimationState;
524       break;
525     }
526     case AutoReverseCommand:
527     {
528       *state|=AutoReverseAnimationState;
529       *state&=(~RepeatAnimationState);
530       *state|=PlayAnimationState;
531       break;
532     }
533     case SaveCommand:
534     {
535       /*
536         Save image.
537       */
538       status=XSaveImage(display,resource_info,windows,*image);
539       if (status == MagickFalse)
540         {
541           XNoticeWidget(display,windows,"Unable to write X image:",
542             (*image)->filename);
543           break;
544         }
545       break;
546     }
547     case SlowerCommand:
548     {
549       resource_info->delay++;
550       break;
551     }
552     case FasterCommand:
553     {
554       if (resource_info->delay == 0)
555         break;
556       resource_info->delay--;
557       break;
558     }
559     case ForwardCommand:
560     {
561       *state=ForwardAnimationState;
562       *state&=(~AutoReverseAnimationState);
563       break;
564     }
565     case ReverseCommand:
566     {
567       *state&=(~ForwardAnimationState);
568       *state&=(~AutoReverseAnimationState);
569       break;
570     }
571     case InfoCommand:
572     {
573       XDisplayImageInfo(display,resource_info,windows,(Image *) NULL,*image);
574       break;
575     }
576     case HelpCommand:
577     {
578       /*
579         User requested help.
580       */
581       XTextViewWidget(display,resource_info,windows,MagickFalse,
582         "Help Viewer - Animate",AnimateHelp);
583       break;
584     }
585     case BrowseDocumentationCommand:
586     {
587       Atom
588         mozilla_atom;
589
590       Window
591         mozilla_window,
592         root_window;
593
594       /*
595         Browse the ImageMagick documentation.
596       */
597       root_window=XRootWindow(display,XDefaultScreen(display));
598       mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
599       mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
600       if (mozilla_window != (Window) NULL)
601         {
602           char
603             command[MaxTextExtent],
604             *url;
605
606           /*
607             Display documentation using Netscape remote control.
608           */
609           url=GetMagickHomeURL();
610           (void) FormatMagickString(command,MaxTextExtent,
611             "openurl(%s,new-tab)",url);
612           url=DestroyString(url);
613           mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
614           (void) XChangeProperty(display,mozilla_window,mozilla_atom,
615             XA_STRING,8,PropModeReplace,(unsigned char *) command,
616             (int) strlen(command));
617           XSetCursorState(display,windows,MagickFalse);
618           break;
619         }
620       XSetCursorState(display,windows,MagickTrue);
621       XCheckRefreshWindows(display,windows);
622       status=InvokeDelegate(resource_info->image_info,*image,"browse",
623         (char *) NULL,&(*image)->exception);
624       if (status == MagickFalse)
625         XNoticeWidget(display,windows,"Unable to browse documentation",
626           (char *) NULL);
627       XDelay(display,1500);
628       XSetCursorState(display,windows,MagickFalse);
629       break;
630     }
631     case VersionCommand:
632     {
633       XNoticeWidget(display,windows,GetMagickVersion((unsigned long *) NULL),
634         GetMagickCopyright());
635       break;
636     }
637     case QuitCommand:
638     {
639       /*
640         exit program
641       */
642       if (resource_info->confirm_exit == MagickFalse)
643         XClientMessage(display,windows->image.id,windows->im_protocols,
644           windows->im_exit,CurrentTime);
645       else
646         {
647           int
648             status;
649
650           /*
651             Confirm program exit.
652           */
653           status=XConfirmWidget(display,windows,"Do you really want to exit",
654             resource_info->client_name);
655           if (status != 0)
656             XClientMessage(display,windows->image.id,windows->im_protocols,
657               windows->im_exit,CurrentTime);
658         }
659       break;
660     }
661     default:
662       break;
663   }
664   return(nexus);
665 }
666 \f
667 /*
668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669 %                                                                             %
670 %                                                                             %
671 %                                                                             %
672 +   X A n i m a t e B a c k g r o u n d I m a g e                             %
673 %                                                                             %
674 %                                                                             %
675 %                                                                             %
676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677 %
678 %  XAnimateBackgroundImage() animates an image sequence in the background of
679 %  a window.
680 %
681 %  The format of the XAnimateBackgroundImage method is:
682 %
683 %      void XAnimateBackgroundImage(Display *display,
684 %        XResourceInfo *resource_info,Image *images)
685 %
686 %  A description of each parameter follows:
687 %
688 %    o display: Specifies a connection to an X server;  returned from
689 %      XOpenDisplay.
690 %
691 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
692 %
693 %    o images: the image list.
694 %
695 */
696
697 static inline long MagickMax(const long x,const long y)
698 {
699   if (x > y)
700     return(x);
701   return(y);
702 }
703
704 #if defined(__cplusplus) || defined(c_plusplus)
705 extern "C" {
706 #endif
707
708 static int SceneCompare(const void *x,const void *y)
709 {
710   const Image
711     **image_1,
712     **image_2;
713
714   image_1=(const Image **) x;
715   image_2=(const Image **) y;
716   return((int) ((*image_1)->scene-(*image_2)->scene));
717 }
718
719 #if defined(__cplusplus) || defined(c_plusplus)
720 }
721 #endif
722
723 MagickExport void XAnimateBackgroundImage(Display *display,
724   XResourceInfo *resource_info,Image *images)
725 {
726   char
727     geometry[MaxTextExtent],
728     visual_type[MaxTextExtent];
729
730   Image
731     *coalesce_image,
732     *display_image,
733     **image_list;
734
735   int
736     scene;
737
738   MagickStatusType
739     status;
740
741   RectangleInfo
742     geometry_info;
743
744   register long
745     i;
746
747   size_t
748     number_scenes;
749
750   static XPixelInfo
751     pixel;
752
753   static XStandardColormap
754     *map_info;
755
756   static XVisualInfo
757     *visual_info = (XVisualInfo *) NULL;
758
759   static XWindowInfo
760     window_info;
761
762   unsigned int
763     height,
764     width;
765
766   unsigned long
767     delay;
768
769   Window
770     root_window;
771
772   XEvent
773     event;
774
775   XGCValues
776     context_values;
777
778   XResourceInfo
779     resources;
780
781   XWindowAttributes
782     window_attributes;
783
784   /*
785     Determine target window.
786   */
787   assert(images != (Image *) NULL);
788   assert(images->signature == MagickSignature);
789   if (images->debug != MagickFalse)
790     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
791   resources=(*resource_info);
792   window_info.id=(Window) NULL;
793   root_window=XRootWindow(display,XDefaultScreen(display));
794   if (LocaleCompare(resources.window_id,"root") == 0)
795     window_info.id=root_window;
796   else
797     {
798       if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
799         window_info.id=XWindowByID(display,root_window,
800           (Window) strtol((char *) resources.window_id,(char **) NULL,0));
801       if (window_info.id == (Window) NULL)
802         window_info.id=
803           XWindowByName(display,root_window,resources.window_id);
804     }
805   if (window_info.id == (Window) NULL)
806     {
807       ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
808         resources.window_id);
809       return;
810     }
811   /*
812     Determine window visual id.
813   */
814   window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
815   window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
816   (void) CopyMagickString(visual_type,"default",MaxTextExtent);
817   status=XGetWindowAttributes(display,window_info.id,&window_attributes) != 0 ?
818     MagickTrue : MagickFalse;
819   if (status != MagickFalse)
820     (void) FormatMagickString(visual_type,MaxTextExtent,"0x%lx",
821       XVisualIDFromVisual(window_attributes.visual));
822   if (visual_info == (XVisualInfo *) NULL)
823     {
824       /*
825         Allocate standard colormap.
826       */
827       map_info=XAllocStandardColormap();
828       if (map_info == (XStandardColormap *) NULL)
829         ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
830           images->filename);
831       map_info->colormap=(Colormap) NULL;
832       pixel.pixels=(unsigned long *) NULL;
833       /*
834         Initialize visual info.
835       */
836       resources.map_type=(char *) NULL;
837       resources.visual_type=visual_type;
838       visual_info=XBestVisualInfo(display,map_info,&resources);
839       if (visual_info == (XVisualInfo *) NULL)
840         ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
841           images->filename);
842       /*
843         Initialize window info.
844       */
845       window_info.ximage=(XImage *) NULL;
846       window_info.matte_image=(XImage *) NULL;
847       window_info.pixmap=(Pixmap) NULL;
848       window_info.matte_pixmap=(Pixmap) NULL;
849     }
850   /*
851     Free previous root colors.
852   */
853   if (window_info.id == root_window)
854     XDestroyWindowColors(display,root_window);
855   coalesce_image=CoalesceImages(images,&images->exception);
856   if (coalesce_image == (Image *) NULL)
857     ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
858       images->filename);
859   images=coalesce_image;
860   if (resources.map_type == (char *) NULL)
861     if ((visual_info->klass != TrueColor) &&
862         (visual_info->klass != DirectColor))
863       {
864         Image
865           *next;
866
867         /*
868           Determine if the sequence of images has the identical colormap.
869         */
870         for (next=images; next != (Image *) NULL; )
871         {
872           next->matte=MagickFalse;
873           if ((next->storage_class == DirectClass) ||
874               (next->colors != images->colors) ||
875               (next->colors > (unsigned long) visual_info->colormap_size))
876             break;
877           for (i=0; i < (long) images->colors; i++)
878             if (IsColorEqual(next->colormap+i,images->colormap+i) == MagickFalse)
879               break;
880           if (i < (long) images->colors)
881             break;
882           next=GetNextImageInList(next);
883         }
884         if (next != (Image *) NULL)
885           (void) RemapImages(resources.quantize_info,images,(Image *) NULL);
886       }
887   /*
888     Sort images by increasing scene number.
889   */
890   number_scenes=GetImageListLength(images);
891   image_list=ImageListToArray(images,&images->exception);
892   if (image_list == (Image **) NULL)
893     ThrowXWindowFatalException(ResourceLimitFatalError,
894       "MemoryAllocationFailed",images->filename);
895   for (i=0; i < (long) number_scenes; i++)
896     if (image_list[i]->scene == 0)
897       break;
898   if (i == (long) number_scenes)
899     qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
900   /*
901     Initialize Standard Colormap.
902   */
903   resources.colormap=SharedColormap;
904   display_image=image_list[0];
905   for (scene=0; scene < (int) number_scenes; scene++)
906   {
907     if ((resource_info->map_type != (char *) NULL) ||
908         (visual_info->klass == TrueColor) ||
909         (visual_info->klass == DirectColor))
910       (void) SetImageType(image_list[scene],image_list[scene]->matte ==
911         MagickFalse ? TrueColorType : TrueColorMatteType);
912     if ((display_image->columns < image_list[scene]->columns) &&
913         (display_image->rows < image_list[scene]->rows))
914       display_image=image_list[scene];
915   }
916   if ((resource_info->map_type != (char *) NULL) ||
917       (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor))
918     (void) SetImageType(display_image,display_image->matte == MagickFalse ?
919       TrueColorType : TrueColorMatteType);
920   XMakeStandardColormap(display,visual_info,&resources,display_image,map_info,
921     &pixel);
922   /*
923     Graphic context superclass.
924   */
925   context_values.background=pixel.background_color.pixel;
926   context_values.foreground=pixel.foreground_color.pixel;
927   pixel.annotate_context=XCreateGC(display,window_info.id,(unsigned long)
928     GCBackground | GCForeground,&context_values);
929   if (pixel.annotate_context == (GC) NULL)
930     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
931       images->filename);
932   /*
933     Initialize Image window attributes.
934   */
935   XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
936     &resources,&window_info);
937   /*
938     Create the X image.
939   */
940   window_info.width=(unsigned int) image_list[0]->columns;
941   window_info.height=(unsigned int) image_list[0]->rows;
942   if ((image_list[0]->columns != window_info.width) ||
943       (image_list[0]->rows != window_info.height))
944     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
945       image_list[0]->filename);
946   (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>",
947     window_attributes.width,window_attributes.height);
948   geometry_info.width=window_info.width;
949   geometry_info.height=window_info.height;
950   geometry_info.x=window_info.x;
951   geometry_info.y=window_info.y;
952   (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
953     &geometry_info.width,&geometry_info.height);
954   window_info.width=(unsigned int) geometry_info.width;
955   window_info.height=(unsigned int) geometry_info.height;
956   window_info.x=(int) geometry_info.x;
957   window_info.y=(int) geometry_info.y;
958   status=XMakeImage(display,&resources,&window_info,image_list[0],
959     window_info.width,window_info.height);
960   if (status == MagickFalse)
961     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
962       images->filename);
963   window_info.x=0;
964   window_info.y=0;
965   if (display_image->debug != MagickFalse)
966     {
967       (void) LogMagickEvent(X11Event,GetMagickModule(),
968         "Image: %s[%lu] %lux%lu ",image_list[0]->filename,
969         image_list[0]->scene,image_list[0]->columns,image_list[0]->rows);
970       if (image_list[0]->colors != 0)
971         (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
972           image_list[0]->colors);
973       (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
974         image_list[0]->magick);
975     }
976   /*
977     Adjust image dimensions as specified by backdrop or geometry options.
978   */
979   width=window_info.width;
980   height=window_info.height;
981   if (resources.backdrop != MagickFalse)
982     {
983       /*
984         Center image on window.
985       */
986       window_info.x=(int) (window_attributes.width/2)-
987         (window_info.ximage->width/2);
988       window_info.y=(int) (window_attributes.height/2)-
989         (window_info.ximage->height/2);
990       width=(unsigned int) window_attributes.width;
991       height=(unsigned int) window_attributes.height;
992     }
993   if (resources.image_geometry != (char *) NULL)
994     {
995       char
996         default_geometry[MaxTextExtent];
997
998       int
999         flags,
1000         gravity;
1001
1002       XSizeHints
1003         *size_hints;
1004
1005       /*
1006         User specified geometry.
1007       */
1008       size_hints=XAllocSizeHints();
1009       if (size_hints == (XSizeHints *) NULL)
1010         ThrowXWindowFatalException(ResourceLimitFatalError,
1011           "MemoryAllocationFailed",images->filename);
1012       size_hints->flags=0L;
1013       (void) FormatMagickString(default_geometry,MaxTextExtent,"%ux%u",width,
1014         height);
1015       flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
1016         default_geometry,window_info.border_width,size_hints,&window_info.x,
1017         &window_info.y,(int *) &width,(int *) &height,&gravity);
1018       if (((flags & (XValue | YValue))) != 0)
1019         {
1020           width=(unsigned int) window_attributes.width;
1021           height=(unsigned int) window_attributes.height;
1022         }
1023       (void) XFree((void *) size_hints);
1024     }
1025   /*
1026     Create the X pixmap.
1027   */
1028   window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
1029     (unsigned int) height,window_info.depth);
1030   if (window_info.pixmap == (Pixmap) NULL)
1031     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
1032       images->filename);
1033   /*
1034     Display pixmap on the window.
1035   */
1036   if (((unsigned int) width > window_info.width) ||
1037       ((unsigned int) height > window_info.height))
1038     (void) XFillRectangle(display,window_info.pixmap,
1039       window_info.annotate_context,0,0,(unsigned int) width,
1040       (unsigned int) height);
1041   (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
1042     window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
1043     window_info.height);
1044   (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
1045   (void) XClearWindow(display,window_info.id);
1046   /*
1047     Initialize image pixmaps structure.
1048   */
1049   window_info.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1050     sizeof(*window_info.pixmaps));
1051   window_info.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1052     sizeof(*window_info.matte_pixmaps));
1053   if ((window_info.pixmaps == (Pixmap *) NULL) ||
1054       (window_info.matte_pixmaps == (Pixmap *) NULL))
1055     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1056       images->filename);
1057   window_info.pixmaps[0]=window_info.pixmap;
1058   window_info.matte_pixmaps[0]=window_info.pixmap;
1059   for (scene=1; scene < (int) number_scenes; scene++)
1060   {
1061     unsigned int
1062       columns,
1063       rows;
1064
1065     /*
1066       Create X image.
1067     */
1068     window_info.pixmap=(Pixmap) NULL;
1069     window_info.matte_pixmap=(Pixmap) NULL;
1070     if ((resources.map_type != (char *) NULL) ||
1071         (visual_info->klass == TrueColor) ||
1072         (visual_info->klass == DirectColor))
1073       if (image_list[scene]->storage_class == PseudoClass)
1074         XGetPixelPacket(display,visual_info,map_info,&resources,
1075           image_list[scene],window_info.pixel_info);
1076     columns=(unsigned int) image_list[scene]->columns;
1077     rows=(unsigned int) image_list[scene]->rows;
1078     if ((image_list[scene]->columns != columns) ||
1079         (image_list[scene]->rows != rows))
1080       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1081         image_list[scene]->filename);
1082     status=XMakeImage(display,&resources,&window_info,image_list[scene],
1083       columns,rows);
1084     if (status == MagickFalse)
1085       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1086         images->filename);
1087     if (display_image->debug != MagickFalse)
1088       {
1089         (void) LogMagickEvent(X11Event,GetMagickModule(),
1090           "Image: [%lu] %s %ux%u ",image_list[scene]->scene,
1091           image_list[scene]->filename,columns,rows);
1092         if (image_list[scene]->colors != 0)
1093           (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
1094             image_list[scene]->colors);
1095         (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1096           image_list[scene]->magick);
1097       }
1098     /*
1099       Create the X pixmap.
1100     */
1101     window_info.pixmap=XCreatePixmap(display,window_info.id,width,height,
1102       window_info.depth);
1103     if (window_info.pixmap == (Pixmap) NULL)
1104       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
1105         images->filename);
1106     /*
1107       Display pixmap on the window.
1108     */
1109     if ((width > window_info.width) || (height > window_info.height))
1110       (void) XFillRectangle(display,window_info.pixmap,
1111         window_info.annotate_context,0,0,width,height);
1112     (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
1113       window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
1114       window_info.height);
1115     (void) XSetWindowBackgroundPixmap(display,window_info.id,
1116       window_info.pixmap);
1117     (void) XClearWindow(display,window_info.id);
1118     window_info.pixmaps[scene]=window_info.pixmap;
1119     window_info.matte_pixmaps[scene]=window_info.matte_pixmap;
1120     if (image_list[scene]->matte)
1121       (void) XClearWindow(display,window_info.id);
1122     delay=1000*image_list[scene]->delay/MagickMax(
1123       image_list[scene]->ticks_per_second,1L);
1124     XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
1125   }
1126   window_info.pixel_info=(&pixel);
1127   /*
1128     Display pixmap on the window.
1129   */
1130   (void) XSelectInput(display,window_info.id,SubstructureNotifyMask);
1131   event.type=Expose;
1132   do
1133   {
1134     for (scene=0; scene < (int) number_scenes; scene++)
1135     {
1136       if (XEventsQueued(display,QueuedAfterFlush) > 0)
1137         {
1138           (void) XNextEvent(display,&event);
1139           if (event.type == DestroyNotify)
1140             break;
1141         }
1142       window_info.pixmap=window_info.pixmaps[scene];
1143       window_info.matte_pixmap=window_info.matte_pixmaps[scene];
1144       (void) XSetWindowBackgroundPixmap(display,window_info.id,
1145         window_info.pixmap);
1146       (void) XClearWindow(display,window_info.id);
1147       (void) XSync(display,MagickFalse);
1148       delay=1000*image_list[scene]->delay/MagickMax(
1149         image_list[scene]->ticks_per_second,1L);
1150       XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
1151     }
1152   } while (event.type != DestroyNotify);
1153   (void) XSync(display,MagickFalse);
1154   image_list=(Image **) RelinquishMagickMemory(image_list);
1155   images=DestroyImageList(images);
1156 }
1157 \f
1158 /*
1159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160 %                                                                             %
1161 %                                                                             %
1162 %                                                                             %
1163 +   X A n i m a t e I m a g e s                                               %
1164 %                                                                             %
1165 %                                                                             %
1166 %                                                                             %
1167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1168 %
1169 %  XAnimateImages() displays an image via X11.
1170 %
1171 %  The format of the XAnimateImages method is:
1172 %
1173 %      Image *XAnimateImages(Display *display,XResourceInfo *resource_info,
1174 %        char **argv,const int argc,Image *images)
1175 %
1176 %  A description of each parameter follows:
1177 %
1178 %    o display: Specifies a connection to an X server;  returned from
1179 %      XOpenDisplay.
1180 %
1181 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1182 %
1183 %    o argv: Specifies the application's argument list.
1184 %
1185 %    o argc: Specifies the number of arguments.
1186 %
1187 %    o images: the image list.
1188 %
1189 */
1190 MagickExport Image *XAnimateImages(Display *display,
1191   XResourceInfo *resource_info,char **argv,const int argc,Image *images)
1192 {
1193 #define MagickMenus  4
1194 #define MaXWindows  8
1195 #define MagickTitle  "Commands"
1196
1197   static const char
1198     *CommandMenu[]=
1199     {
1200       "Animate",
1201       "Speed",
1202       "Direction",
1203       "Help",
1204       "Image Info",
1205       "Quit",
1206       (char *) NULL
1207     },
1208     *AnimateMenu[]=
1209     {
1210       "Open...",
1211       "Play",
1212       "Step",
1213       "Repeat",
1214       "Auto Reverse",
1215       "Save...",
1216       (char *) NULL
1217     },
1218     *SpeedMenu[]=
1219     {
1220       "Faster",
1221       "Slower",
1222       (char *) NULL
1223     },
1224     *DirectionMenu[]=
1225     {
1226       "Forward",
1227       "Reverse",
1228       (char *) NULL
1229     },
1230     *HelpMenu[]=
1231     {
1232       "Overview",
1233       "Browse Documentation",
1234       "About Animate",
1235       (char *) NULL
1236     };
1237
1238   static const char
1239     **Menus[MagickMenus]=
1240     {
1241       AnimateMenu,
1242       SpeedMenu,
1243       DirectionMenu,
1244       HelpMenu
1245     };
1246
1247   static const CommandType
1248     CommandMenus[]=
1249     {
1250       NullCommand,
1251       NullCommand,
1252       NullCommand,
1253       NullCommand,
1254       InfoCommand,
1255       QuitCommand
1256     },
1257     CommandTypes[]=
1258     {
1259       OpenCommand,
1260       PlayCommand,
1261       StepCommand,
1262       RepeatCommand,
1263       AutoReverseCommand,
1264       SaveCommand
1265     },
1266     SpeedCommands[]=
1267     {
1268       FasterCommand,
1269       SlowerCommand
1270     },
1271     DirectionCommands[]=
1272     {
1273       ForwardCommand,
1274       ReverseCommand
1275     },
1276     HelpCommands[]=
1277     {
1278       HelpCommand,
1279       BrowseDocumentationCommand,
1280       VersionCommand
1281     };
1282
1283   static const CommandType
1284     *Commands[MagickMenus]=
1285     {
1286       CommandTypes,
1287       SpeedCommands,
1288       DirectionCommands,
1289       HelpCommands
1290     };
1291
1292   char
1293     command[MaxTextExtent],
1294     *cwd,
1295     geometry[MaxTextExtent],
1296     resource_name[MaxTextExtent];
1297
1298   CommandType
1299     command_type;
1300
1301   Image
1302     *coalesce_image,
1303     *display_image,
1304     *image,
1305     **image_list,
1306     *nexus;
1307
1308   int
1309     status;
1310
1311   long
1312     first_scene,
1313     iterations,
1314     scene;
1315
1316   KeySym
1317     key_symbol;
1318
1319   MagickStatusType
1320     context_mask,
1321     state;
1322
1323   RectangleInfo
1324     geometry_info;
1325
1326   register char
1327     *p;
1328
1329   register long
1330     i;
1331
1332   static char
1333     working_directory[MaxTextExtent];
1334
1335   static unsigned long
1336     number_windows;
1337
1338   static XWindowInfo
1339     *magick_windows[MaXWindows];
1340
1341   time_t
1342     timestamp;
1343
1344   unsigned long
1345     delay,
1346     number_scenes;
1347
1348   WarningHandler
1349     warning_handler;
1350
1351   Window
1352     root_window;
1353
1354   XClassHint
1355     *class_hints;
1356
1357   XEvent
1358     event;
1359
1360   XFontStruct
1361     *font_info;
1362
1363   XGCValues
1364     context_values;
1365
1366   XPixelInfo
1367     *icon_pixel,
1368     *pixel;
1369
1370   XResourceInfo
1371     *icon_resources;
1372
1373   XStandardColormap
1374     *icon_map,
1375     *map_info;
1376
1377   XTextProperty
1378     window_name;
1379
1380   XVisualInfo
1381     *icon_visual,
1382     *visual_info;
1383
1384   XWindowChanges
1385     window_changes;
1386
1387   XWindows
1388     *windows;
1389
1390   XWMHints
1391     *manager_hints;
1392
1393   assert(images != (Image *) NULL);
1394   assert(images->signature == MagickSignature);
1395   if (images->debug != MagickFalse)
1396     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1397   warning_handler=(WarningHandler) NULL;
1398   windows=XSetWindows((XWindows *) ~0);
1399   if (windows != (XWindows *) NULL)
1400     {
1401       int
1402         status;
1403
1404       status=chdir(working_directory);
1405       if (status == -1)
1406         (void) ThrowMagickException(&images->exception,GetMagickModule(),
1407           FileOpenError,"UnableToOpenFile","%s",working_directory);
1408       warning_handler=resource_info->display_warnings ?
1409         SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
1410       warning_handler=resource_info->display_warnings ?
1411         SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
1412     }
1413   else
1414     {
1415       register Image
1416         *p;
1417
1418       /*
1419         Initialize window structure.
1420       */
1421       for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1422       {
1423         if (p->storage_class == DirectClass)
1424           {
1425             resource_info->colors=0;
1426             break;
1427           }
1428         if (p->colors > resource_info->colors)
1429           resource_info->colors=p->colors;
1430       }
1431       windows=XSetWindows(XInitializeWindows(display,resource_info));
1432       if (windows == (XWindows *) NULL)
1433         ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
1434           images->filename);
1435       /*
1436         Initialize window id's.
1437       */
1438       number_windows=0;
1439       magick_windows[number_windows++]=(&windows->icon);
1440       magick_windows[number_windows++]=(&windows->backdrop);
1441       magick_windows[number_windows++]=(&windows->image);
1442       magick_windows[number_windows++]=(&windows->info);
1443       magick_windows[number_windows++]=(&windows->command);
1444       magick_windows[number_windows++]=(&windows->widget);
1445       magick_windows[number_windows++]=(&windows->popup);
1446       for (i=0; i < (long) number_windows; i++)
1447         magick_windows[i]->id=(Window) NULL;
1448     }
1449   /*
1450     Initialize font info.
1451   */
1452   if (windows->font_info != (XFontStruct *) NULL)
1453     (void) XFreeFont(display,windows->font_info);
1454   windows->font_info=XBestFont(display,resource_info,MagickFalse);
1455   if (windows->font_info == (XFontStruct *) NULL)
1456     ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
1457       resource_info->font);
1458   /*
1459     Initialize Standard Colormap.
1460   */
1461   map_info=windows->map_info;
1462   icon_map=windows->icon_map;
1463   visual_info=windows->visual_info;
1464   icon_visual=windows->icon_visual;
1465   pixel=windows->pixel_info;
1466   icon_pixel=windows->icon_pixel;
1467   font_info=windows->font_info;
1468   icon_resources=windows->icon_resources;
1469   class_hints=windows->class_hints;
1470   manager_hints=windows->manager_hints;
1471   root_window=XRootWindow(display,visual_info->screen);
1472   coalesce_image=CoalesceImages(images,&images->exception);
1473   if (coalesce_image == (Image *) NULL)
1474     ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
1475       images->filename);
1476   images=coalesce_image;
1477   if (resource_info->map_type == (char *) NULL)
1478     if ((visual_info->klass != TrueColor) &&
1479         (visual_info->klass != DirectColor))
1480       {
1481         Image
1482           *next;
1483
1484         /*
1485           Determine if the sequence of images has the identical colormap.
1486         */
1487         for (next=images; next != (Image *) NULL; )
1488         {
1489           next->matte=MagickFalse;
1490           if ((next->storage_class == DirectClass) ||
1491               (next->colors != images->colors) ||
1492               (next->colors > (unsigned long) visual_info->colormap_size))
1493             break;
1494           for (i=0; i < (long) images->colors; i++)
1495             if (IsColorEqual(next->colormap+i,images->colormap+i) == MagickFalse)
1496               break;
1497           if (i < (long) images->colors)
1498             break;
1499           next=GetNextImageInList(next);
1500         }
1501         if (next != (Image *) NULL)
1502           (void) RemapImages(resource_info->quantize_info,images,
1503             (Image *) NULL);
1504       }
1505   /*
1506     Sort images by increasing scene number.
1507   */
1508   number_scenes=GetImageListLength(images);
1509   image_list=ImageListToArray(images,&images->exception);
1510   if (image_list == (Image **) NULL)
1511     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1512       images->filename);
1513   for (scene=0; scene < (long) number_scenes; scene++)
1514     if (image_list[scene]->scene == 0)
1515       break;
1516   if (scene == (long) number_scenes)
1517     qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
1518   /*
1519     Initialize Standard Colormap.
1520   */
1521   nexus=NewImageList();
1522   display_image=image_list[0];
1523   for (scene=0; scene < (long) number_scenes; scene++)
1524   {
1525     if ((resource_info->map_type != (char *) NULL) ||
1526         (visual_info->klass == TrueColor) ||
1527         (visual_info->klass == DirectColor))
1528       (void) SetImageType(image_list[scene],image_list[scene]->matte ==
1529         MagickFalse ? TrueColorType : TrueColorMatteType);
1530     if ((display_image->columns < image_list[scene]->columns) &&
1531         (display_image->rows < image_list[scene]->rows))
1532       display_image=image_list[scene];
1533   }
1534   if (display_image->debug != MagickFalse)
1535     {
1536       (void) LogMagickEvent(X11Event,GetMagickModule(),
1537         "Image: %s[%lu] %lux%lu ",display_image->filename,
1538         display_image->scene,display_image->columns,display_image->rows);
1539       if (display_image->colors != 0)
1540         (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
1541           display_image->colors);
1542       (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1543         display_image->magick);
1544     }
1545   XMakeStandardColormap(display,visual_info,resource_info,display_image,
1546     map_info,pixel);
1547   /*
1548     Initialize graphic context.
1549   */
1550   windows->context.id=(Window) NULL;
1551   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1552     resource_info,&windows->context);
1553   (void) CloneString(&class_hints->res_name,resource_info->client_name);
1554   (void) CloneString(&class_hints->res_class,resource_info->client_name);
1555   class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
1556   manager_hints->flags=InputHint | StateHint;
1557   manager_hints->input=MagickFalse;
1558   manager_hints->initial_state=WithdrawnState;
1559   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1560     &windows->context);
1561   if (display_image->debug != MagickFalse)
1562     (void) LogMagickEvent(X11Event,GetMagickModule(),
1563       "Window id: 0x%lx (context)",windows->context.id);
1564   context_values.background=pixel->background_color.pixel;
1565   context_values.font=font_info->fid;
1566   context_values.foreground=pixel->foreground_color.pixel;
1567   context_values.graphics_exposures=MagickFalse;
1568   context_mask=(MagickStatusType)
1569     (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
1570   if (pixel->annotate_context != (GC) NULL)
1571     (void) XFreeGC(display,pixel->annotate_context);
1572   pixel->annotate_context=
1573     XCreateGC(display,windows->context.id,context_mask,&context_values);
1574   if (pixel->annotate_context == (GC) NULL)
1575     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1576       images->filename);
1577   context_values.background=pixel->depth_color.pixel;
1578   if (pixel->widget_context != (GC) NULL)
1579     (void) XFreeGC(display,pixel->widget_context);
1580   pixel->widget_context=
1581     XCreateGC(display,windows->context.id,context_mask,&context_values);
1582   if (pixel->widget_context == (GC) NULL)
1583     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1584       images->filename);
1585   context_values.background=pixel->foreground_color.pixel;
1586   context_values.foreground=pixel->background_color.pixel;
1587   context_values.plane_mask=
1588     context_values.background ^ context_values.foreground;
1589   if (pixel->highlight_context != (GC) NULL)
1590     (void) XFreeGC(display,pixel->highlight_context);
1591   pixel->highlight_context=XCreateGC(display,windows->context.id,
1592     (unsigned long) (context_mask | GCPlaneMask),&context_values);
1593   if (pixel->highlight_context == (GC) NULL)
1594     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1595       images->filename);
1596   (void) XDestroyWindow(display,windows->context.id);
1597   /*
1598     Initialize icon window.
1599   */
1600   XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
1601     icon_resources,&windows->icon);
1602   windows->icon.geometry=resource_info->icon_geometry;
1603   XBestIconSize(display,&windows->icon,display_image);
1604   windows->icon.attributes.colormap=
1605     XDefaultColormap(display,icon_visual->screen);
1606   windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
1607   manager_hints->flags=InputHint | StateHint;
1608   manager_hints->input=MagickFalse;
1609   manager_hints->initial_state=IconicState;
1610   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1611     &windows->icon);
1612   if (display_image->debug != MagickFalse)
1613     (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
1614       windows->icon.id);
1615   /*
1616     Initialize graphic context for icon window.
1617   */
1618   if (icon_pixel->annotate_context != (GC) NULL)
1619     (void) XFreeGC(display,icon_pixel->annotate_context);
1620   context_values.background=icon_pixel->background_color.pixel;
1621   context_values.foreground=icon_pixel->foreground_color.pixel;
1622   icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
1623     (unsigned long) (GCBackground | GCForeground),&context_values);
1624   if (icon_pixel->annotate_context == (GC) NULL)
1625     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1626       images->filename);
1627   windows->icon.annotate_context=icon_pixel->annotate_context;
1628   /*
1629     Initialize Image window.
1630   */
1631   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1632     resource_info,&windows->image);
1633   windows->image.shape=MagickTrue;  /* non-rectangular shape hint */
1634   if (resource_info->use_shared_memory == MagickFalse)
1635     windows->image.shared_memory=MagickFalse;
1636   if (resource_info->title != (char *) NULL)
1637     {
1638       char
1639         *title;
1640
1641       title=InterpretImageProperties(resource_info->image_info,display_image,
1642         resource_info->title);
1643       (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
1644       (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
1645       title=DestroyString(title);
1646     }
1647   else
1648     {
1649       char
1650         filename[MaxTextExtent];
1651
1652       /*
1653         Window name is the base of the filename.
1654       */
1655       GetPathComponent(display_image->magick_filename,TailPath,filename);
1656       (void) FormatMagickString(windows->image.name,MaxTextExtent,
1657         "ImageMagick: %s[%lu of %lu]",filename,display_image->scene,
1658         number_scenes);
1659       (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
1660     }
1661   if (resource_info->immutable != MagickFalse)
1662     windows->image.immutable=MagickTrue;
1663   windows->image.shape=MagickTrue;
1664   windows->image.geometry=resource_info->image_geometry;
1665   (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>!",
1666     XDisplayWidth(display,visual_info->screen),
1667     XDisplayHeight(display,visual_info->screen));
1668   geometry_info.width=display_image->columns;
1669   geometry_info.height=display_image->rows;
1670   geometry_info.x=0;
1671   geometry_info.y=0;
1672   (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
1673     &geometry_info.width,&geometry_info.height);
1674   windows->image.width=(unsigned int) geometry_info.width;
1675   windows->image.height=(unsigned int) geometry_info.height;
1676   windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1677     ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1678     KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
1679     PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
1680   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1681     resource_info,&windows->backdrop);
1682   if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
1683     {
1684       /*
1685         Initialize backdrop window.
1686       */
1687       windows->backdrop.x=0;
1688       windows->backdrop.y=0;
1689       (void) CloneString(&windows->backdrop.name,"ImageMagick Backdrop");
1690       windows->backdrop.flags=(unsigned long) (USSize | USPosition);
1691       windows->backdrop.width=(unsigned int)
1692         XDisplayWidth(display,visual_info->screen);
1693       windows->backdrop.height=(unsigned int)
1694         XDisplayHeight(display,visual_info->screen);
1695       windows->backdrop.border_width=0;
1696       windows->backdrop.immutable=MagickTrue;
1697       windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
1698         ButtonReleaseMask;
1699       windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
1700         StructureNotifyMask;
1701       manager_hints->flags=IconWindowHint | InputHint | StateHint;
1702       manager_hints->icon_window=windows->icon.id;
1703       manager_hints->input=MagickTrue;
1704       manager_hints->initial_state=
1705         resource_info->iconic ? IconicState : NormalState;
1706       XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1707         &windows->backdrop);
1708       if (display_image->debug != MagickFalse)
1709         (void) LogMagickEvent(X11Event,GetMagickModule(),
1710           "Window id: 0x%lx (backdrop)",windows->backdrop.id);
1711       (void) XMapWindow(display,windows->backdrop.id);
1712       (void) XClearWindow(display,windows->backdrop.id);
1713       if (windows->image.id != (Window) NULL)
1714         {
1715           (void) XDestroyWindow(display,windows->image.id);
1716           windows->image.id=(Window) NULL;
1717         }
1718       /*
1719         Position image in the center the backdrop.
1720       */
1721       windows->image.flags|=USPosition;
1722       windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
1723         (windows->image.width/2);
1724       windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
1725         (windows->image.height/2);
1726     }
1727   manager_hints->flags=IconWindowHint | InputHint | StateHint;
1728   manager_hints->icon_window=windows->icon.id;
1729   manager_hints->input=MagickTrue;
1730   manager_hints->initial_state=
1731     resource_info->iconic ? IconicState : NormalState;
1732   if (windows->group_leader.id != (Window) NULL)
1733     {
1734       /*
1735         Follow the leader.
1736       */
1737       manager_hints->flags|=(MagickStatusType) WindowGroupHint;
1738       manager_hints->window_group=windows->group_leader.id;
1739       (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
1740       if (display_image->debug != MagickFalse)
1741         (void) LogMagickEvent(X11Event,GetMagickModule(),
1742           "Window id: 0x%lx (group leader)",windows->group_leader.id);
1743     }
1744   XMakeWindow(display,
1745     (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
1746     argv,argc,class_hints,manager_hints,&windows->image);
1747   (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
1748     XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
1749   if (windows->group_leader.id != (Window) NULL)
1750     (void) XSetTransientForHint(display,windows->image.id,
1751       windows->group_leader.id);
1752   if (display_image->debug != MagickFalse)
1753     (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
1754       windows->image.id);
1755   /*
1756     Initialize Info widget.
1757   */
1758   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1759     resource_info,&windows->info);
1760   (void) CloneString(&windows->info.name,"Info");
1761   (void) CloneString(&windows->info.icon_name,"Info");
1762   windows->info.border_width=1;
1763   windows->info.x=2;
1764   windows->info.y=2;
1765   windows->info.flags|=PPosition;
1766   windows->info.attributes.win_gravity=UnmapGravity;
1767   windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
1768     StructureNotifyMask;
1769   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1770   manager_hints->input=MagickFalse;
1771   manager_hints->initial_state=NormalState;
1772   manager_hints->window_group=windows->image.id;
1773   XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
1774     &windows->info);
1775   windows->info.highlight_stipple=XCreateBitmapFromData(display,
1776     windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1777   windows->info.shadow_stipple=XCreateBitmapFromData(display,
1778     windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1779   (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
1780   if (windows->image.mapped)
1781     (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
1782   if (display_image->debug != MagickFalse)
1783     (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
1784       windows->info.id);
1785   /*
1786     Initialize Command widget.
1787   */
1788   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1789     resource_info,&windows->command);
1790   windows->command.data=MagickMenus;
1791   (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
1792   (void) FormatMagickString(resource_name,MaxTextExtent,"%s.command",
1793     resource_info->client_name);
1794   windows->command.geometry=XGetResourceClass(resource_info->resource_database,
1795     resource_name,"geometry",(char *) NULL);
1796   (void) CloneString(&windows->command.name,MagickTitle);
1797   windows->command.border_width=0;
1798   windows->command.flags|=PPosition;
1799   windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1800     ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
1801     OwnerGrabButtonMask | StructureNotifyMask;
1802   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1803   manager_hints->input=MagickTrue;
1804   manager_hints->initial_state=NormalState;
1805   manager_hints->window_group=windows->image.id;
1806   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1807     &windows->command);
1808   windows->command.highlight_stipple=XCreateBitmapFromData(display,
1809     windows->command.id,(char *) HighlightBitmap,HighlightWidth,
1810     HighlightHeight);
1811   windows->command.shadow_stipple=XCreateBitmapFromData(display,
1812     windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1813   (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
1814   if (display_image->debug != MagickFalse)
1815     (void) LogMagickEvent(X11Event,GetMagickModule(),
1816       "Window id: 0x%lx (command)",windows->command.id);
1817   /*
1818     Initialize Widget window.
1819   */
1820   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1821     resource_info,&windows->widget);
1822   (void) FormatMagickString(resource_name,MaxTextExtent,"%s.widget",
1823     resource_info->client_name);
1824   windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
1825     resource_name,"geometry",(char *) NULL);
1826   windows->widget.border_width=0;
1827   windows->widget.flags|=PPosition;
1828   windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1829     ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1830     KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
1831     StructureNotifyMask;
1832   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1833   manager_hints->input=MagickTrue;
1834   manager_hints->initial_state=NormalState;
1835   manager_hints->window_group=windows->image.id;
1836   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1837     &windows->widget);
1838   windows->widget.highlight_stipple=XCreateBitmapFromData(display,
1839     windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1840   windows->widget.shadow_stipple=XCreateBitmapFromData(display,
1841     windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1842   (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
1843   if (display_image->debug != MagickFalse)
1844     (void) LogMagickEvent(X11Event,GetMagickModule(),
1845       "Window id: 0x%lx (widget)",windows->widget.id);
1846   /*
1847     Initialize popup window.
1848   */
1849   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1850     resource_info,&windows->popup);
1851   windows->popup.border_width=0;
1852   windows->popup.flags|=PPosition;
1853   windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1854     ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1855     KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
1856   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1857   manager_hints->input=MagickTrue;
1858   manager_hints->initial_state=NormalState;
1859   manager_hints->window_group=windows->image.id;
1860   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1861     &windows->popup);
1862   windows->popup.highlight_stipple=XCreateBitmapFromData(display,
1863     windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1864   windows->popup.shadow_stipple=XCreateBitmapFromData(display,
1865     windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1866   (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
1867   if (display_image->debug != MagickFalse)
1868     (void) LogMagickEvent(X11Event,GetMagickModule(),
1869       "Window id: 0x%lx (pop up)",windows->popup.id);
1870   if ((windows->image.mapped == MagickFalse) ||
1871       (windows->backdrop.id != (Window) NULL))
1872     (void) XMapWindow(display,windows->image.id);
1873   /*
1874     Set out progress and warning handlers.
1875   */
1876   if (warning_handler == (WarningHandler) NULL)
1877     {
1878       warning_handler=resource_info->display_warnings ?
1879         SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
1880       warning_handler=resource_info->display_warnings ?
1881         SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
1882     }
1883   /*
1884     Initialize X image structure.
1885   */
1886   windows->image.x=0;
1887   windows->image.y=0;
1888   status=XMakeImage(display,resource_info,&windows->image,display_image,
1889     (unsigned int) display_image->columns,(unsigned int) display_image->rows);
1890   if (status == MagickFalse)
1891     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1892       images->filename);
1893   if (windows->image.mapped)
1894     XRefreshWindow(display,&windows->image,(XEvent *) NULL);
1895   /*
1896     Initialize image pixmaps structure.
1897   */
1898   window_changes.width=(int) windows->image.width;
1899   window_changes.height=(int) windows->image.height;
1900   (void) XReconfigureWMWindow(display,windows->image.id,windows->command.screen,
1901     (unsigned int) (CWWidth | CWHeight),&window_changes);
1902   (void) XMapWindow(display,windows->image.id);
1903   windows->image.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1904     sizeof(*windows->image.pixmaps));
1905   windows->image.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1906     sizeof(*windows->image.pixmaps));
1907   if ((windows->image.pixmaps == (Pixmap *) NULL) ||
1908       (windows->image.matte_pixmaps == (Pixmap *) NULL))
1909     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1910       images->filename);
1911   windows->image.pixmaps[0]=windows->image.pixmap;
1912   windows->image.matte_pixmaps[0]=windows->image.matte_pixmap;
1913   for (scene=1; scene < (long) number_scenes; scene++)
1914   {
1915     unsigned int
1916       columns,
1917       rows;
1918
1919     /*
1920       Create X image.
1921     */
1922     (void) TransformImageColorspace(image_list[scene],RGBColorspace);
1923     windows->image.pixmap=(Pixmap) NULL;
1924     windows->image.matte_pixmap=(Pixmap) NULL;
1925     if ((resource_info->map_type != (char *) NULL) ||
1926         (visual_info->klass == TrueColor) ||
1927         (visual_info->klass == DirectColor))
1928       if (image_list[scene]->storage_class == PseudoClass)
1929         XGetPixelPacket(display,visual_info,map_info,resource_info,
1930           image_list[scene],windows->image.pixel_info);
1931     columns=(unsigned int) image_list[scene]->columns;
1932     rows=(unsigned int) image_list[scene]->rows;
1933     if ((image_list[scene]->columns != columns) ||
1934         (image_list[scene]->rows != rows))
1935       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1936         image_list[scene]->filename);
1937     status=XMakeImage(display,resource_info,&windows->image,image_list[scene],
1938       columns,rows);
1939     if (status == MagickFalse)
1940       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1941         images->filename);
1942     if (image_list[scene]->debug != MagickFalse)
1943       {
1944         (void) LogMagickEvent(X11Event,GetMagickModule(),
1945           "Image: [%lu] %s %ux%u ",image_list[scene]->scene,
1946           image_list[scene]->filename,columns,rows);
1947         if (image_list[scene]->colors != 0)
1948           (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
1949             image_list[scene]->colors);
1950         (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1951           image_list[scene]->magick);
1952       }
1953     /*
1954       Window name is the base of the filename.
1955     */
1956     if (resource_info->title != (char *) NULL)
1957       {
1958         char
1959           *title;
1960
1961         title=InterpretImageProperties(resource_info->image_info,
1962           image_list[scene],resource_info->title);
1963         (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
1964         title=DestroyString(title);
1965       }
1966     else
1967       {
1968         p=image_list[scene]->magick_filename+
1969           strlen(image_list[scene]->magick_filename)-1;
1970         while ((p > image_list[scene]->magick_filename) && (*(p-1) != '/'))
1971           p--;
1972         (void) FormatMagickString(windows->image.name,MaxTextExtent,
1973           "ImageMagick: %s[%lu of %lu]",p,scene+1,number_scenes);
1974       }
1975     status=XStringListToTextProperty(&windows->image.name,1,&window_name);
1976     if (status != Success)
1977       {
1978         XSetWMName(display,windows->image.id,&window_name);
1979         (void) XFree((void *) window_name.value);
1980       }
1981     windows->image.pixmaps[scene]=windows->image.pixmap;
1982     windows->image.matte_pixmaps[scene]=windows->image.matte_pixmap;
1983     event.xexpose.x=0;
1984     event.xexpose.y=0;
1985     event.xexpose.width=(int) image_list[scene]->columns;
1986     event.xexpose.height=(int) image_list[scene]->rows;
1987     XRefreshWindow(display,&windows->image,&event);
1988     (void) XSync(display,MagickFalse);
1989     delay=1000*image_list[scene]->delay/MagickMax(images->ticks_per_second,1L);
1990     XDelay(display,resource_info->delay*(delay == 0 ? 10 : delay));
1991     if (XCheckTypedWindowEvent(display,windows->image.id,KeyPress,&event) != 0)
1992       {
1993         int
1994           length;
1995
1996         length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
1997           sizeof(command),&key_symbol,(XComposeStatus *) NULL);
1998         *(command+length)='\0';
1999         if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
2000           {
2001             XClientMessage(display,windows->image.id,windows->im_protocols,
2002               windows->im_exit,CurrentTime);
2003             break;
2004           }
2005       }
2006   }
2007   if (windows->command.mapped)
2008     (void) XMapRaised(display,windows->command.id);
2009   /*
2010     Respond to events.
2011   */
2012   nexus=NewImageList();
2013   scene=0;
2014   first_scene=0;
2015   iterations=0;
2016   image=image_list[0];
2017   state=(MagickStatusType) (ForwardAnimationState | RepeatAnimationState);
2018   (void) XMagickCommand(display,resource_info,windows,PlayCommand,&images,
2019     &state);
2020   do
2021   {
2022     if (XEventsQueued(display,QueuedAfterFlush) == 0)
2023       if ((state & PlayAnimationState) || (state & StepAnimationState))
2024         {
2025           MagickBooleanType
2026             pause;
2027
2028           pause=MagickFalse;
2029           delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
2030           XDelay(display,resource_info->delay*(delay == 0 ? 10 : delay));
2031           if (state & ForwardAnimationState)
2032             {
2033               /*
2034                 Forward animation:  increment scene number.
2035               */
2036               if (scene < ((long) number_scenes-1))
2037                 scene++;
2038               else
2039                 {
2040                   iterations++;
2041                   if (iterations == (long) image_list[0]->iterations)
2042                     {
2043                       iterations=0;
2044                       state|=ExitState;
2045                     }
2046                   if (state & AutoReverseAnimationState)
2047                     {
2048                       state&=(~ForwardAnimationState);
2049                       scene--;
2050                     }
2051                   else
2052                     {
2053                       if ((state & RepeatAnimationState) == MagickFalse)
2054                         state&=(~PlayAnimationState);
2055                       scene=first_scene;
2056                       pause=MagickTrue;
2057                     }
2058                 }
2059             }
2060           else
2061             {
2062               /*
2063                 Reverse animation:  decrement scene number.
2064               */
2065               if (scene > first_scene)
2066                 scene--;
2067               else
2068                 {
2069                   iterations++;
2070                   if (iterations == (long) image_list[0]->iterations)
2071                     {
2072                       iterations=0;
2073                       state&=(~RepeatAnimationState);
2074                     }
2075                   if (state & AutoReverseAnimationState)
2076                     {
2077                       state|=ForwardAnimationState;
2078                       scene=first_scene;
2079                       pause=MagickTrue;
2080                     }
2081                   else
2082                     {
2083                       if ((state & RepeatAnimationState) == MagickFalse)
2084                         state&=(~PlayAnimationState);
2085                       scene=(long) number_scenes-1;
2086                     }
2087                 }
2088             }
2089           scene=MagickMax(scene,0);
2090           image=image_list[scene];
2091           if ((image != (Image *) NULL) && (image->start_loop != 0))
2092             first_scene=scene;
2093           if ((state & StepAnimationState) ||
2094               (resource_info->title != (char *) NULL))
2095             {
2096               /*
2097                 Update window title.
2098               */
2099               p=image_list[scene]->filename+
2100                 strlen(image_list[scene]->filename)-1;
2101               while ((p > image_list[scene]->filename) && (*(p-1) != '/'))
2102                 p--;
2103               (void) FormatMagickString(windows->image.name,MaxTextExtent,
2104                 "ImageMagick: %s[%lu of %lu]",p,scene+1,number_scenes);
2105               if (resource_info->title != (char *) NULL)
2106                 {
2107                   char
2108                     *title;
2109
2110                   title=InterpretImageProperties(resource_info->image_info,
2111                     image,resource_info->title);
2112                   (void) CopyMagickString(windows->image.name,title,
2113                     MaxTextExtent);
2114                   title=DestroyString(title);
2115                 }
2116               status=XStringListToTextProperty(&windows->image.name,1,
2117                 &window_name);
2118               if (status != Success)
2119                 {
2120                   XSetWMName(display,windows->image.id,&window_name);
2121                   (void) XFree((void *) window_name.value);
2122                 }
2123             }
2124           /*
2125             Copy X pixmap to Image window.
2126           */
2127           XGetPixelPacket(display,visual_info,map_info,resource_info,
2128             image_list[scene],windows->image.pixel_info);
2129           windows->image.ximage->width=(int) image->columns;
2130           windows->image.ximage->height=(int) image->rows;
2131           windows->image.pixmap=windows->image.pixmaps[scene];
2132           windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
2133           event.xexpose.x=0;
2134           event.xexpose.y=0;
2135           event.xexpose.width=(int) image->columns;
2136           event.xexpose.height=(int) image->rows;
2137           XRefreshWindow(display,&windows->image,&event);
2138           (void) XSync(display,MagickFalse);
2139           state&=(~StepAnimationState);
2140           if (pause != MagickFalse)
2141             for (i=0; i < (long) resource_info->pause; i++)
2142             {
2143               int
2144                 status;
2145
2146               status=XCheckTypedWindowEvent(display,windows->image.id,KeyPress,
2147                 &event);
2148               if (status != 0)
2149                 {
2150                   int
2151                     length;
2152
2153                   length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2154                     sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2155                   *(command+length)='\0';
2156                   if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
2157                     {
2158                       XClientMessage(display,windows->image.id,
2159                         windows->im_protocols,windows->im_exit,CurrentTime);
2160                       break;
2161                     }
2162                 }
2163               (void) sleep(1);
2164             }
2165           continue;
2166         }
2167     /*
2168       Handle a window event.
2169     */
2170     timestamp=time((time_t *) NULL);
2171     (void) XNextEvent(display,&event);
2172     if (windows->image.stasis == MagickFalse)
2173       windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
2174         MagickTrue : MagickFalse;
2175     if (event.xany.window == windows->command.id)
2176       {
2177         int
2178           id;
2179
2180         /*
2181           Select a command from the Command widget.
2182         */
2183         id=XCommandWidget(display,windows,CommandMenu,&event);
2184         if (id < 0)
2185           continue;
2186         (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
2187         command_type=CommandMenus[id];
2188         if (id < MagickMenus)
2189           {
2190             int
2191               entry;
2192
2193             /*
2194               Select a command from a pop-up menu.
2195             */
2196             entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
2197               command);
2198             if (entry < 0)
2199               continue;
2200             (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
2201             command_type=Commands[id][entry];
2202           }
2203         if (command_type != NullCommand)
2204           nexus=XMagickCommand(display,resource_info,windows,
2205             command_type,&image,&state);
2206         continue;
2207       }
2208     switch (event.type)
2209     {
2210       case ButtonPress:
2211       {
2212         if (display_image->debug != MagickFalse)
2213           (void) LogMagickEvent(X11Event,GetMagickModule(),
2214             "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
2215             event.xbutton.button,event.xbutton.x,event.xbutton.y);
2216         if ((event.xbutton.button == Button3) &&
2217             (event.xbutton.state & Mod1Mask))
2218           {
2219             /*
2220               Convert Alt-Button3 to Button2.
2221             */
2222             event.xbutton.button=Button2;
2223             event.xbutton.state&=(~Mod1Mask);
2224           }
2225         if (event.xbutton.window == windows->backdrop.id)
2226           {
2227             (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
2228               event.xbutton.time);
2229             break;
2230           }
2231         if (event.xbutton.window == windows->image.id)
2232           {
2233             if (resource_info->immutable != MagickFalse)
2234               {
2235                 state|=ExitState;
2236                 break;
2237               }
2238             /*
2239               Map/unmap Command widget.
2240             */
2241             if (windows->command.mapped)
2242               (void) XWithdrawWindow(display,windows->command.id,
2243                 windows->command.screen);
2244             else
2245               {
2246                 (void) XCommandWidget(display,windows,CommandMenu,
2247                   (XEvent *) NULL);
2248                 (void) XMapRaised(display,windows->command.id);
2249               }
2250           }
2251         break;
2252       }
2253       case ButtonRelease:
2254       {
2255         if (display_image->debug != MagickFalse)
2256           (void) LogMagickEvent(X11Event,GetMagickModule(),
2257             "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
2258             event.xbutton.button,event.xbutton.x,event.xbutton.y);
2259         break;
2260       }
2261       case ClientMessage:
2262       {
2263         if (display_image->debug != MagickFalse)
2264           (void) LogMagickEvent(X11Event,GetMagickModule(),
2265             "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
2266             event.xclient.message_type,event.xclient.format,(unsigned long)
2267             event.xclient.data.l[0]);
2268         if (event.xclient.message_type == windows->im_protocols)
2269           {
2270             if (*event.xclient.data.l == (long) windows->im_update_colormap)
2271               {
2272                 /*
2273                   Update graphic context and window colormap.
2274                 */
2275                 for (i=0; i < (long) number_windows; i++)
2276                 {
2277                   if (magick_windows[i]->id == windows->icon.id)
2278                     continue;
2279                   context_values.background=pixel->background_color.pixel;
2280                   context_values.foreground=pixel->foreground_color.pixel;
2281                   (void) XChangeGC(display,magick_windows[i]->annotate_context,
2282                     context_mask,&context_values);
2283                   (void) XChangeGC(display,magick_windows[i]->widget_context,
2284                     context_mask,&context_values);
2285                   context_values.background=pixel->foreground_color.pixel;
2286                   context_values.foreground=pixel->background_color.pixel;
2287                   context_values.plane_mask=
2288                     context_values.background ^ context_values.foreground;
2289                   (void) XChangeGC(display,magick_windows[i]->highlight_context,
2290                     (unsigned long) (context_mask | GCPlaneMask),
2291                     &context_values);
2292                   magick_windows[i]->attributes.background_pixel=
2293                     pixel->background_color.pixel;
2294                   magick_windows[i]->attributes.border_pixel=
2295                     pixel->border_color.pixel;
2296                   magick_windows[i]->attributes.colormap=map_info->colormap;
2297                   (void) XChangeWindowAttributes(display,magick_windows[i]->id,
2298                     magick_windows[i]->mask,&magick_windows[i]->attributes);
2299                 }
2300                 if (windows->backdrop.id != (Window) NULL)
2301                   (void) XInstallColormap(display,map_info->colormap);
2302                 break;
2303               }
2304             if (*event.xclient.data.l == (long) windows->im_exit)
2305               {
2306                 state|=ExitState;
2307                 break;
2308               }
2309             break;
2310           }
2311         if (event.xclient.message_type == windows->dnd_protocols)
2312           {
2313             Atom
2314               selection,
2315               type;
2316
2317             int
2318               format,
2319               status;
2320
2321             unsigned char
2322               *data;
2323
2324             unsigned long
2325               after,
2326               length;
2327
2328             /*
2329               Display image named by the Drag-and-Drop selection.
2330             */
2331             if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
2332               break;
2333             selection=XInternAtom(display,"DndSelection",MagickFalse);
2334             status=XGetWindowProperty(display,root_window,selection,0L,2047L,
2335               MagickFalse,(Atom) AnyPropertyType,&type,&format,&length,&after,
2336               &data);
2337             if ((status != Success) || (length == 0))
2338               break;
2339             if (*event.xclient.data.l == 2)
2340               {
2341                 /*
2342                   Offix DND.
2343                 */
2344                 (void) CopyMagickString(resource_info->image_info->filename,
2345                   (char *) data,MaxTextExtent);
2346               }
2347             else
2348               {
2349                 /*
2350                   XDND.
2351                 */
2352                 if (LocaleNCompare((char *) data,"file:",5) != 0)
2353                   {
2354                     (void) XFree((void *) data);
2355                     break;
2356                   }
2357                 (void) CopyMagickString(resource_info->image_info->filename,
2358                   ((char *) data)+5,MaxTextExtent);
2359               }
2360             nexus=ReadImage(resource_info->image_info,&image->exception);
2361             CatchException(&image->exception);
2362             if (nexus != (Image *) NULL)
2363               state|=ExitState;
2364             (void) XFree((void *) data);
2365             break;
2366           }
2367         /*
2368           If client window delete message, exit.
2369         */
2370         if (event.xclient.message_type != windows->wm_protocols)
2371           break;
2372         if (*event.xclient.data.l == (long) windows->wm_take_focus)
2373           {
2374             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2375               (Time) event.xclient.data.l[1]);
2376             break;
2377           }
2378         if (*event.xclient.data.l != (long) windows->wm_delete_window)
2379           break;
2380         (void) XWithdrawWindow(display,event.xclient.window,
2381           visual_info->screen);
2382         if (event.xclient.window == windows->image.id)
2383           {
2384             state|=ExitState;
2385             break;
2386           }
2387         break;
2388       }
2389       case ConfigureNotify:
2390       {
2391         if (display_image->debug != MagickFalse)
2392           (void) LogMagickEvent(X11Event,GetMagickModule(),
2393             "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
2394             event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
2395             event.xconfigure.y,event.xconfigure.send_event);
2396         if (event.xconfigure.window == windows->image.id)
2397           {
2398             if (event.xconfigure.send_event != 0)
2399               {
2400                 XWindowChanges
2401                   window_changes;
2402
2403                 /*
2404                   Position the transient windows relative of the Image window.
2405                 */
2406                 if (windows->command.geometry == (char *) NULL)
2407                   if (windows->command.mapped == MagickFalse)
2408                     {
2409                        windows->command.x=
2410                           event.xconfigure.x-windows->command.width-25;
2411                         windows->command.y=event.xconfigure.y;
2412                         XConstrainWindowPosition(display,&windows->command);
2413                         window_changes.x=windows->command.x;
2414                         window_changes.y=windows->command.y;
2415                         (void) XReconfigureWMWindow(display,windows->command.id,
2416                           windows->command.screen,(unsigned int) (CWX | CWY),
2417                           &window_changes);
2418                     }
2419                 if (windows->widget.geometry == (char *) NULL)
2420                   if (windows->widget.mapped == MagickFalse)
2421                     {
2422                       windows->widget.x=
2423                         event.xconfigure.x+event.xconfigure.width/10;
2424                       windows->widget.y=
2425                         event.xconfigure.y+event.xconfigure.height/10;
2426                       XConstrainWindowPosition(display,&windows->widget);
2427                       window_changes.x=windows->widget.x;
2428                       window_changes.y=windows->widget.y;
2429                       (void) XReconfigureWMWindow(display,windows->widget.id,
2430                         windows->widget.screen,(unsigned int) (CWX | CWY),
2431                         &window_changes);
2432                     }
2433               }
2434             /*
2435               Image window has a new configuration.
2436             */
2437             windows->image.width=(unsigned int) event.xconfigure.width;
2438             windows->image.height=(unsigned int) event.xconfigure.height;
2439             break;
2440           }
2441         if (event.xconfigure.window == windows->icon.id)
2442           {
2443             /*
2444               Icon window has a new configuration.
2445             */
2446             windows->icon.width=(unsigned int) event.xconfigure.width;
2447             windows->icon.height=(unsigned int) event.xconfigure.height;
2448             break;
2449           }
2450         break;
2451       }
2452       case DestroyNotify:
2453       {
2454         /*
2455           Group leader has exited.
2456         */
2457         if (display_image->debug != MagickFalse)
2458           (void) LogMagickEvent(X11Event,GetMagickModule(),
2459             "Destroy Notify: 0x%lx",event.xdestroywindow.window);
2460         if (event.xdestroywindow.window == windows->group_leader.id)
2461           {
2462             state|=ExitState;
2463             break;
2464           }
2465         break;
2466       }
2467       case EnterNotify:
2468       {
2469         /*
2470           Selectively install colormap.
2471         */
2472         if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2473           if (event.xcrossing.mode != NotifyUngrab)
2474             XInstallColormap(display,map_info->colormap);
2475         break;
2476       }
2477       case Expose:
2478       {
2479         if (display_image->debug != MagickFalse)
2480           (void) LogMagickEvent(X11Event,GetMagickModule(),
2481             "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
2482             event.xexpose.width,event.xexpose.height,event.xexpose.x,
2483             event.xexpose.y);
2484         /*
2485           Repaint windows that are now exposed.
2486         */
2487         if (event.xexpose.window == windows->image.id)
2488           {
2489             windows->image.pixmap=windows->image.pixmaps[scene];
2490             windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
2491             XRefreshWindow(display,&windows->image,&event);
2492             break;
2493           }
2494         if (event.xexpose.window == windows->icon.id)
2495           if (event.xexpose.count == 0)
2496             {
2497               XRefreshWindow(display,&windows->icon,&event);
2498               break;
2499             }
2500         break;
2501       }
2502       case KeyPress:
2503       {
2504         static int
2505           length;
2506
2507         /*
2508           Respond to a user key press.
2509         */
2510         length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2511           sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2512         *(command+length)='\0';
2513         if (display_image->debug != MagickFalse)
2514           (void) LogMagickEvent(X11Event,GetMagickModule(),
2515             "Key press: 0x%lx (%c)",(unsigned long) key_symbol,*command);
2516         command_type=NullCommand;
2517         switch (key_symbol)
2518         {
2519           case XK_o:
2520           {
2521             if ((event.xkey.state & ControlMask) == MagickFalse)
2522               break;
2523             command_type=OpenCommand;
2524             break;
2525           }
2526           case XK_BackSpace:
2527           {
2528             command_type=StepBackwardCommand;
2529             break;
2530           }
2531           case XK_space:
2532           {
2533             command_type=StepForwardCommand;
2534             break;
2535           }
2536           case XK_less:
2537           {
2538             command_type=FasterCommand;
2539             break;
2540           }
2541           case XK_greater:
2542           {
2543             command_type=SlowerCommand;
2544             break;
2545           }
2546           case XK_F1:
2547           {
2548             command_type=HelpCommand;
2549             break;
2550           }
2551           case XK_Find:
2552           {
2553             command_type=BrowseDocumentationCommand;
2554             break;
2555           }
2556           case XK_question:
2557           {
2558             command_type=InfoCommand;
2559             break;
2560           }
2561           case XK_q:
2562           case XK_Escape:
2563           {
2564             command_type=QuitCommand;
2565             break;
2566           }
2567           default:
2568             break;
2569         }
2570         if (command_type != NullCommand)
2571           nexus=XMagickCommand(display,resource_info,windows,
2572             command_type,&image,&state);
2573         break;
2574       }
2575       case KeyRelease:
2576       {
2577         /*
2578           Respond to a user key release.
2579         */
2580         (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2581           sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2582         if (display_image->debug != MagickFalse)
2583           (void) LogMagickEvent(X11Event,GetMagickModule(),
2584             "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
2585         break;
2586       }
2587       case LeaveNotify:
2588       {
2589         /*
2590           Selectively uninstall colormap.
2591         */
2592         if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2593           if (event.xcrossing.mode != NotifyUngrab)
2594             XUninstallColormap(display,map_info->colormap);
2595         break;
2596       }
2597       case MapNotify:
2598       {
2599         if (display_image->debug != MagickFalse)
2600           (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
2601             event.xmap.window);
2602         if (event.xmap.window == windows->backdrop.id)
2603           {
2604             (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
2605               CurrentTime);
2606             windows->backdrop.mapped=MagickTrue;
2607             break;
2608           }
2609         if (event.xmap.window == windows->image.id)
2610           {
2611             if (windows->backdrop.id != (Window) NULL)
2612               (void) XInstallColormap(display,map_info->colormap);
2613             if (LocaleCompare(image_list[0]->magick,"LOGO") == 0)
2614               {
2615                 if (LocaleCompare(display_image->filename,"LOGO") == 0)
2616                   nexus=XMagickCommand(display,resource_info,windows,
2617                     OpenCommand,&image,&state);
2618                 else
2619                   state|=ExitState;
2620               }
2621             windows->image.mapped=MagickTrue;
2622             break;
2623           }
2624         if (event.xmap.window == windows->info.id)
2625           {
2626             windows->info.mapped=MagickTrue;
2627             break;
2628           }
2629         if (event.xmap.window == windows->icon.id)
2630           {
2631             /*
2632               Create an icon image.
2633             */
2634             XMakeStandardColormap(display,icon_visual,icon_resources,
2635               display_image,icon_map,icon_pixel);
2636             (void) XMakeImage(display,icon_resources,&windows->icon,
2637               display_image,windows->icon.width,windows->icon.height);
2638             (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
2639               windows->icon.pixmap);
2640             (void) XClearWindow(display,windows->icon.id);
2641             (void) XWithdrawWindow(display,windows->info.id,
2642               windows->info.screen);
2643             windows->icon.mapped=MagickTrue;
2644             break;
2645           }
2646         if (event.xmap.window == windows->command.id)
2647           {
2648             windows->command.mapped=MagickTrue;
2649             break;
2650           }
2651         if (event.xmap.window == windows->popup.id)
2652           {
2653             windows->popup.mapped=MagickTrue;
2654             break;
2655           }
2656         if (event.xmap.window == windows->widget.id)
2657           {
2658             windows->widget.mapped=MagickTrue;
2659             break;
2660           }
2661         break;
2662       }
2663       case MappingNotify:
2664       {
2665         (void) XRefreshKeyboardMapping(&event.xmapping);
2666         break;
2667       }
2668       case NoExpose:
2669         break;
2670       case PropertyNotify:
2671       {
2672         Atom
2673           type;
2674
2675         int
2676           format,
2677           status;
2678
2679         unsigned char
2680           *data;
2681
2682         unsigned long
2683           after,
2684           length;
2685
2686         if (display_image->debug != MagickFalse)
2687           (void) LogMagickEvent(X11Event,GetMagickModule(),
2688             "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
2689             event.xproperty.atom,event.xproperty.state);
2690         if (event.xproperty.atom != windows->im_remote_command)
2691           break;
2692         /*
2693           Display image named by the remote command protocol.
2694         */
2695         status=XGetWindowProperty(display,event.xproperty.window,
2696           event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
2697           AnyPropertyType,&type,&format,&length,&after,&data);
2698         if ((status != Success) || (length == 0))
2699           break;
2700         (void) CopyMagickString(resource_info->image_info->filename,
2701           (char *) data,MaxTextExtent);
2702         nexus=ReadImage(resource_info->image_info,&image->exception);
2703         CatchException(&image->exception);
2704         if (nexus != (Image *) NULL)
2705           state|=ExitState;
2706         (void) XFree((void *) data);
2707         break;
2708       }
2709       case ReparentNotify:
2710       {
2711         if (display_image->debug != MagickFalse)
2712           (void) LogMagickEvent(X11Event,GetMagickModule(),
2713             "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
2714             event.xreparent.window);
2715         break;
2716       }
2717       case UnmapNotify:
2718       {
2719         if (display_image->debug != MagickFalse)
2720           (void) LogMagickEvent(X11Event,GetMagickModule(),
2721             "Unmap Notify: 0x%lx",event.xunmap.window);
2722         if (event.xunmap.window == windows->backdrop.id)
2723           {
2724             windows->backdrop.mapped=MagickFalse;
2725             break;
2726           }
2727         if (event.xunmap.window == windows->image.id)
2728           {
2729             windows->image.mapped=MagickFalse;
2730             break;
2731           }
2732         if (event.xunmap.window == windows->info.id)
2733           {
2734             windows->info.mapped=MagickFalse;
2735             break;
2736           }
2737         if (event.xunmap.window == windows->icon.id)
2738           {
2739             if (map_info->colormap == icon_map->colormap)
2740               XConfigureImageColormap(display,resource_info,windows,
2741                 display_image);
2742             (void) XFreeStandardColormap(display,icon_visual,icon_map,
2743               icon_pixel);
2744             windows->icon.mapped=MagickFalse;
2745             break;
2746           }
2747         if (event.xunmap.window == windows->command.id)
2748           {
2749             windows->command.mapped=MagickFalse;
2750             break;
2751           }
2752         if (event.xunmap.window == windows->popup.id)
2753           {
2754             if (windows->backdrop.id != (Window) NULL)
2755               (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2756                 CurrentTime);
2757             windows->popup.mapped=MagickFalse;
2758             break;
2759           }
2760         if (event.xunmap.window == windows->widget.id)
2761           {
2762             if (windows->backdrop.id != (Window) NULL)
2763               (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2764                 CurrentTime);
2765             windows->widget.mapped=MagickFalse;
2766             break;
2767           }
2768         break;
2769       }
2770       default:
2771       {
2772         if (display_image->debug != MagickFalse)
2773           (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
2774             event.type);
2775         break;
2776       }
2777     }
2778   }
2779   while (!(state & ExitState));
2780   image_list=(Image **) RelinquishMagickMemory(image_list);
2781   images=DestroyImageList(images);
2782   if ((windows->visual_info->klass == GrayScale) ||
2783       (windows->visual_info->klass == PseudoColor) ||
2784       (windows->visual_info->klass == DirectColor))
2785     {
2786       /*
2787         Withdraw windows.
2788       */
2789       if (windows->info.mapped)
2790         (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2791       if (windows->command.mapped)
2792         (void) XWithdrawWindow(display,windows->command.id,
2793           windows->command.screen);
2794     }
2795   if (resource_info->backdrop == MagickFalse)
2796     if (windows->backdrop.mapped)
2797       {
2798         (void) XWithdrawWindow(display,windows->backdrop.id,\
2799           windows->backdrop.screen);
2800         (void) XDestroyWindow(display,windows->backdrop.id);
2801         windows->backdrop.id=(Window) NULL;
2802         (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);
2803         (void) XDestroyWindow(display,windows->image.id);
2804         windows->image.id=(Window) NULL;
2805       }
2806   XSetCursorState(display,windows,MagickTrue);
2807   XCheckRefreshWindows(display,windows);
2808   for (scene=1; scene < (long) number_scenes; scene++)
2809   {
2810     if (windows->image.pixmaps[scene] != (Pixmap) NULL)
2811       (void) XFreePixmap(display,windows->image.pixmaps[scene]);
2812     windows->image.pixmaps[scene]=(Pixmap) NULL;
2813     if (windows->image.matte_pixmaps[scene] != (Pixmap) NULL)
2814       (void) XFreePixmap(display,windows->image.matte_pixmaps[scene]);
2815     windows->image.matte_pixmaps[scene]=(Pixmap) NULL;
2816   }
2817   windows->image.pixmaps=(Pixmap *)
2818     RelinquishMagickMemory(windows->image.pixmaps);
2819   windows->image.matte_pixmaps=(Pixmap *)
2820     RelinquishMagickMemory(windows->image.matte_pixmaps);
2821   if (nexus == (Image *) NULL)
2822     {
2823       /*
2824         Free X resources.
2825       */
2826       if (windows->image.mapped != MagickFalse)
2827         (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);      XDelay(display,SuspendTime);
2828       (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
2829       if (resource_info->map_type == (char *) NULL)
2830         (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
2831       DestroyXResources();
2832     }
2833   (void) XSync(display,MagickFalse);
2834   /*
2835     Restore our progress monitor and warning handlers.
2836   */
2837   (void) SetErrorHandler(warning_handler);
2838   (void) SetWarningHandler(warning_handler);
2839   /*
2840     Change to home directory.
2841   */
2842   cwd=getcwd(working_directory,MaxTextExtent);
2843   status=chdir(resource_info->home_directory);
2844   if (status == -1)
2845     (void) ThrowMagickException(&images->exception,GetMagickModule(),
2846       FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
2847   return(nexus);
2848 }
2849 \f
2850 /*
2851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2852 %                                                                             %
2853 %                                                                             %
2854 %                                                                             %
2855 +   X S a v e I m a g e                                                       %
2856 %                                                                             %
2857 %                                                                             %
2858 %                                                                             %
2859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2860 %
2861 %  XSaveImage() saves an image to a file.
2862 %
2863 %  The format of the XSaveImage method is:
2864 %
2865 %      MagickBooleanType XSaveImage(Display *display,
2866 %        XResourceInfo *resource_info,XWindows *windows,Image *image)
2867 %
2868 %  A description of each parameter follows:
2869 %
2870 %    o status: Method XSaveImage return True if the image is
2871 %      written.  False is returned is there is a memory shortage or if the
2872 %      image fails to write.
2873 %
2874 %    o display: Specifies a connection to an X server; returned from
2875 %      XOpenDisplay.
2876 %
2877 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2878 %
2879 %    o windows: Specifies a pointer to a XWindows structure.
2880 %
2881 %    o image: the image.
2882 %
2883 */
2884 static MagickBooleanType XSaveImage(Display *display,
2885   XResourceInfo *resource_info,XWindows *windows,Image *image)
2886 {
2887   char
2888     filename[MaxTextExtent];
2889
2890   ImageInfo
2891     *image_info;
2892
2893   MagickStatusType
2894     status;
2895
2896   /*
2897     Request file name from user.
2898   */
2899   if (resource_info->write_filename != (char *) NULL)
2900     (void) CopyMagickString(filename,resource_info->write_filename,
2901       MaxTextExtent);
2902   else
2903     {
2904       char
2905         path[MaxTextExtent];
2906
2907       int
2908         status;
2909
2910       GetPathComponent(image->filename,HeadPath,path);
2911       GetPathComponent(image->filename,TailPath,filename);
2912       status=chdir(path);
2913       if (status == -1)
2914         (void) ThrowMagickException(&image->exception,GetMagickModule(),
2915           FileOpenError,"UnableToOpenFile","%s",path);
2916     }
2917   XFileBrowserWidget(display,windows,"Save",filename);
2918   if (*filename == '\0')
2919     return(MagickTrue);
2920   if (IsPathAccessible(filename) != MagickFalse)
2921     {
2922       int
2923         status;
2924
2925       /*
2926         File exists-- seek user's permission before overwriting.
2927       */
2928       status=XConfirmWidget(display,windows,"Overwrite",filename);
2929       if (status == 0)
2930         return(MagickTrue);
2931     }
2932   image_info=CloneImageInfo(resource_info->image_info);
2933   (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
2934   (void) SetImageInfo(image_info,MagickFalse,&image->exception);
2935   if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
2936       (LocaleCompare(image_info->magick,"JPG") == 0))
2937     {
2938       char
2939         quality[MaxTextExtent];
2940
2941       int
2942         status;
2943
2944       /*
2945         Request JPEG quality from user.
2946       */
2947       (void) FormatMagickString(quality,MaxTextExtent,"%lu",
2948         image_info->quality);
2949       status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
2950         quality);
2951       if (*quality == '\0')
2952         return(MagickTrue);
2953       image->quality=StringToUnsignedLong(quality);
2954       image_info->interlace=status != MagickFalse ?  NoInterlace :
2955         PlaneInterlace;
2956     }
2957   if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
2958       (LocaleCompare(image_info->magick,"PDF") == 0) ||
2959       (LocaleCompare(image_info->magick,"PS") == 0) ||
2960       (LocaleCompare(image_info->magick,"PS2") == 0))
2961     {
2962       char
2963         geometry[MaxTextExtent];
2964
2965       /*
2966         Request page geometry from user.
2967       */
2968       (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
2969       if (LocaleCompare(image_info->magick,"PDF") == 0)
2970         (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
2971       if (image_info->page != (char *) NULL)
2972         (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
2973       XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
2974         "Select page geometry:",geometry);
2975       if (*geometry != '\0')
2976         image_info->page=GetPageGeometry(geometry);
2977     }
2978   /*
2979     Write image.
2980   */
2981   image=GetFirstImageInList(image);
2982   status=WriteImages(image_info,image,filename,&image->exception);
2983   if (status != MagickFalse)
2984     image->taint=MagickFalse;
2985   image_info=DestroyImageInfo(image_info);
2986   XSetCursorState(display,windows,MagickFalse);
2987   return(status != 0 ? MagickTrue : MagickFalse);
2988 }
2989 #else
2990 \f
2991 /*
2992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2993 %                                                                             %
2994 %                                                                             %
2995 %                                                                             %
2996 +   A n i m a t e I m a g e s                                                 %
2997 %                                                                             %
2998 %                                                                             %
2999 %                                                                             %
3000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001 %
3002 %  AnimateImages() repeatedly displays an image sequence to any X window
3003 %  screen.  It returns a value other than 0 if successful.  Check the
3004 %  exception member of image to determine the reason for any failure.
3005 %
3006 %  The format of the AnimateImages method is:
3007 %
3008 %      MagickBooleanType AnimateImages(const ImageInfo *image_info,
3009 %        Image *images)
3010 %
3011 %  A description of each parameter follows:
3012 %
3013 %    o image_info: the image info.
3014 %
3015 %    o image: the image.
3016 %
3017 */
3018 MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
3019   Image *image)
3020 {
3021   assert(image_info != (const ImageInfo *) NULL);
3022   assert(image_info->signature == MagickSignature);
3023   assert(image != (Image *) NULL);
3024   assert(image->signature == MagickSignature);
3025   if (image->debug != MagickFalse)
3026     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3027   (void) ThrowMagickException(&image->exception,GetMagickModule(),
3028     MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
3029     image->filename);
3030   return(MagickFalse);
3031 }
3032 #endif