]> granicus.if.org Git - imagemagick/blob - magick/animate.c
clearer explanation of what filter scale does in the comments
[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 **) AcquireMagickMemory(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         "%s: %s",MagickPackageName,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((size_t *) 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 ssize_t MagickMax(const ssize_t x,const ssize_t 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 ssize_t
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   size_t
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 > (size_t) visual_info->colormap_size))
876             break;
877           for (i=0; i < (ssize_t) images->colors; i++)
878             if (IsColorEqual(next->colormap+i,images->colormap+i) == MagickFalse)
879               break;
880           if (i < (ssize_t) 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 < (ssize_t) number_scenes; i++)
896     if (image_list[i]->scene == 0)
897       break;
898   if (i == (ssize_t) 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=(ssize_t) window_info.x;
951   geometry_info.y=(ssize_t) 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[%.20g] %.20gx%.20g ",image_list[0]->filename,(double)
969         image_list[0]->scene,(double) image_list[0]->columns,(double)
970         image_list[0]->rows);
971       if (image_list[0]->colors != 0)
972         (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
973           image_list[0]->colors);
974       (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
975         image_list[0]->magick);
976     }
977   /*
978     Adjust image dimensions as specified by backdrop or geometry options.
979   */
980   width=window_info.width;
981   height=window_info.height;
982   if (resources.backdrop != MagickFalse)
983     {
984       /*
985         Center image on window.
986       */
987       window_info.x=(int) (window_attributes.width/2)-
988         (window_info.ximage->width/2);
989       window_info.y=(int) (window_attributes.height/2)-
990         (window_info.ximage->height/2);
991       width=(unsigned int) window_attributes.width;
992       height=(unsigned int) window_attributes.height;
993     }
994   if (resources.image_geometry != (char *) NULL)
995     {
996       char
997         default_geometry[MaxTextExtent];
998
999       int
1000         flags,
1001         gravity;
1002
1003       XSizeHints
1004         *size_hints;
1005
1006       /*
1007         User specified geometry.
1008       */
1009       size_hints=XAllocSizeHints();
1010       if (size_hints == (XSizeHints *) NULL)
1011         ThrowXWindowFatalException(ResourceLimitFatalError,
1012           "MemoryAllocationFailed",images->filename);
1013       size_hints->flags=0L;
1014       (void) FormatMagickString(default_geometry,MaxTextExtent,"%ux%u",width,
1015         height);
1016       flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
1017         default_geometry,window_info.border_width,size_hints,&window_info.x,
1018         &window_info.y,(int *) &width,(int *) &height,&gravity);
1019       if (((flags & (XValue | YValue))) != 0)
1020         {
1021           width=(unsigned int) window_attributes.width;
1022           height=(unsigned int) window_attributes.height;
1023         }
1024       (void) XFree((void *) size_hints);
1025     }
1026   /*
1027     Create the X pixmap.
1028   */
1029   window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
1030     (unsigned int) height,window_info.depth);
1031   if (window_info.pixmap == (Pixmap) NULL)
1032     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
1033       images->filename);
1034   /*
1035     Display pixmap on the window.
1036   */
1037   if (((unsigned int) width > window_info.width) ||
1038       ((unsigned int) height > window_info.height))
1039     (void) XFillRectangle(display,window_info.pixmap,
1040       window_info.annotate_context,0,0,(unsigned int) width,
1041       (unsigned int) height);
1042   (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
1043     window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
1044     window_info.height);
1045   (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
1046   (void) XClearWindow(display,window_info.id);
1047   /*
1048     Initialize image pixmaps structure.
1049   */
1050   window_info.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1051     sizeof(*window_info.pixmaps));
1052   window_info.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1053     sizeof(*window_info.matte_pixmaps));
1054   if ((window_info.pixmaps == (Pixmap *) NULL) ||
1055       (window_info.matte_pixmaps == (Pixmap *) NULL))
1056     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1057       images->filename);
1058   window_info.pixmaps[0]=window_info.pixmap;
1059   window_info.matte_pixmaps[0]=window_info.pixmap;
1060   for (scene=1; scene < (int) number_scenes; scene++)
1061   {
1062     unsigned int
1063       columns,
1064       rows;
1065
1066     /*
1067       Create X image.
1068     */
1069     window_info.pixmap=(Pixmap) NULL;
1070     window_info.matte_pixmap=(Pixmap) NULL;
1071     if ((resources.map_type != (char *) NULL) ||
1072         (visual_info->klass == TrueColor) ||
1073         (visual_info->klass == DirectColor))
1074       if (image_list[scene]->storage_class == PseudoClass)
1075         XGetPixelPacket(display,visual_info,map_info,&resources,
1076           image_list[scene],window_info.pixel_info);
1077     columns=(unsigned int) image_list[scene]->columns;
1078     rows=(unsigned int) image_list[scene]->rows;
1079     if ((image_list[scene]->columns != columns) ||
1080         (image_list[scene]->rows != rows))
1081       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1082         image_list[scene]->filename);
1083     status=XMakeImage(display,&resources,&window_info,image_list[scene],
1084       columns,rows);
1085     if (status == MagickFalse)
1086       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1087         images->filename);
1088     if (display_image->debug != MagickFalse)
1089       {
1090         (void) LogMagickEvent(X11Event,GetMagickModule(),
1091           "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
1092           image_list[scene]->filename,(double) columns,(double) rows);
1093         if (image_list[scene]->colors != 0)
1094           (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1095             image_list[scene]->colors);
1096         (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1097           image_list[scene]->magick);
1098       }
1099     /*
1100       Create the X pixmap.
1101     */
1102     window_info.pixmap=XCreatePixmap(display,window_info.id,width,height,
1103       window_info.depth);
1104     if (window_info.pixmap == (Pixmap) NULL)
1105       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
1106         images->filename);
1107     /*
1108       Display pixmap on the window.
1109     */
1110     if ((width > window_info.width) || (height > window_info.height))
1111       (void) XFillRectangle(display,window_info.pixmap,
1112         window_info.annotate_context,0,0,width,height);
1113     (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
1114       window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
1115       window_info.height);
1116     (void) XSetWindowBackgroundPixmap(display,window_info.id,
1117       window_info.pixmap);
1118     (void) XClearWindow(display,window_info.id);
1119     window_info.pixmaps[scene]=window_info.pixmap;
1120     window_info.matte_pixmaps[scene]=window_info.matte_pixmap;
1121     if (image_list[scene]->matte)
1122       (void) XClearWindow(display,window_info.id);
1123     delay=1000*image_list[scene]->delay/MagickMax(
1124       image_list[scene]->ticks_per_second,1L);
1125     XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
1126   }
1127   window_info.pixel_info=(&pixel);
1128   /*
1129     Display pixmap on the window.
1130   */
1131   (void) XSelectInput(display,window_info.id,SubstructureNotifyMask);
1132   event.type=Expose;
1133   do
1134   {
1135     for (scene=0; scene < (int) number_scenes; scene++)
1136     {
1137       if (XEventsQueued(display,QueuedAfterFlush) > 0)
1138         {
1139           (void) XNextEvent(display,&event);
1140           if (event.type == DestroyNotify)
1141             break;
1142         }
1143       window_info.pixmap=window_info.pixmaps[scene];
1144       window_info.matte_pixmap=window_info.matte_pixmaps[scene];
1145       (void) XSetWindowBackgroundPixmap(display,window_info.id,
1146         window_info.pixmap);
1147       (void) XClearWindow(display,window_info.id);
1148       (void) XSync(display,MagickFalse);
1149       delay=1000*image_list[scene]->delay/MagickMax(
1150         image_list[scene]->ticks_per_second,1L);
1151       XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
1152     }
1153   } while (event.type != DestroyNotify);
1154   (void) XSync(display,MagickFalse);
1155   image_list=(Image **) RelinquishMagickMemory(image_list);
1156   images=DestroyImageList(images);
1157 }
1158 \f
1159 /*
1160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1161 %                                                                             %
1162 %                                                                             %
1163 %                                                                             %
1164 +   X A n i m a t e I m a g e s                                               %
1165 %                                                                             %
1166 %                                                                             %
1167 %                                                                             %
1168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169 %
1170 %  XAnimateImages() displays an image via X11.
1171 %
1172 %  The format of the XAnimateImages method is:
1173 %
1174 %      Image *XAnimateImages(Display *display,XResourceInfo *resource_info,
1175 %        char **argv,const int argc,Image *images)
1176 %
1177 %  A description of each parameter follows:
1178 %
1179 %    o display: Specifies a connection to an X server;  returned from
1180 %      XOpenDisplay.
1181 %
1182 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1183 %
1184 %    o argv: Specifies the application's argument list.
1185 %
1186 %    o argc: Specifies the number of arguments.
1187 %
1188 %    o images: the image list.
1189 %
1190 */
1191 MagickExport Image *XAnimateImages(Display *display,
1192   XResourceInfo *resource_info,char **argv,const int argc,Image *images)
1193 {
1194 #define MagickMenus  4
1195 #define MaXWindows  8
1196 #define MagickTitle  "Commands"
1197
1198   static const char
1199     *CommandMenu[]=
1200     {
1201       "Animate",
1202       "Speed",
1203       "Direction",
1204       "Help",
1205       "Image Info",
1206       "Quit",
1207       (char *) NULL
1208     },
1209     *AnimateMenu[]=
1210     {
1211       "Open...",
1212       "Play",
1213       "Step",
1214       "Repeat",
1215       "Auto Reverse",
1216       "Save...",
1217       (char *) NULL
1218     },
1219     *SpeedMenu[]=
1220     {
1221       "Faster",
1222       "Slower",
1223       (char *) NULL
1224     },
1225     *DirectionMenu[]=
1226     {
1227       "Forward",
1228       "Reverse",
1229       (char *) NULL
1230     },
1231     *HelpMenu[]=
1232     {
1233       "Overview",
1234       "Browse Documentation",
1235       "About Animate",
1236       (char *) NULL
1237     };
1238
1239   static const char
1240     **Menus[MagickMenus]=
1241     {
1242       AnimateMenu,
1243       SpeedMenu,
1244       DirectionMenu,
1245       HelpMenu
1246     };
1247
1248   static const CommandType
1249     CommandMenus[]=
1250     {
1251       NullCommand,
1252       NullCommand,
1253       NullCommand,
1254       NullCommand,
1255       InfoCommand,
1256       QuitCommand
1257     },
1258     CommandTypes[]=
1259     {
1260       OpenCommand,
1261       PlayCommand,
1262       StepCommand,
1263       RepeatCommand,
1264       AutoReverseCommand,
1265       SaveCommand
1266     },
1267     SpeedCommands[]=
1268     {
1269       FasterCommand,
1270       SlowerCommand
1271     },
1272     DirectionCommands[]=
1273     {
1274       ForwardCommand,
1275       ReverseCommand
1276     },
1277     HelpCommands[]=
1278     {
1279       HelpCommand,
1280       BrowseDocumentationCommand,
1281       VersionCommand
1282     };
1283
1284   static const CommandType
1285     *Commands[MagickMenus]=
1286     {
1287       CommandTypes,
1288       SpeedCommands,
1289       DirectionCommands,
1290       HelpCommands
1291     };
1292
1293   char
1294     command[MaxTextExtent],
1295     *cwd,
1296     geometry[MaxTextExtent],
1297     resource_name[MaxTextExtent];
1298
1299   CommandType
1300     command_type;
1301
1302   Image
1303     *coalesce_image,
1304     *display_image,
1305     *image,
1306     **image_list,
1307     *nexus;
1308
1309   int
1310     status;
1311
1312   ssize_t
1313     first_scene,
1314     iterations,
1315     scene;
1316
1317   KeySym
1318     key_symbol;
1319
1320   MagickStatusType
1321     context_mask,
1322     state;
1323
1324   RectangleInfo
1325     geometry_info;
1326
1327   register char
1328     *p;
1329
1330   register ssize_t
1331     i;
1332
1333   static char
1334     working_directory[MaxTextExtent];
1335
1336   static size_t
1337     number_windows;
1338
1339   static XWindowInfo
1340     *magick_windows[MaXWindows];
1341
1342   time_t
1343     timestamp;
1344
1345   size_t
1346     delay,
1347     number_scenes;
1348
1349   WarningHandler
1350     warning_handler;
1351
1352   Window
1353     root_window;
1354
1355   XClassHint
1356     *class_hints;
1357
1358   XEvent
1359     event;
1360
1361   XFontStruct
1362     *font_info;
1363
1364   XGCValues
1365     context_values;
1366
1367   XPixelInfo
1368     *icon_pixel,
1369     *pixel;
1370
1371   XResourceInfo
1372     *icon_resources;
1373
1374   XStandardColormap
1375     *icon_map,
1376     *map_info;
1377
1378   XTextProperty
1379     window_name;
1380
1381   XVisualInfo
1382     *icon_visual,
1383     *visual_info;
1384
1385   XWindowChanges
1386     window_changes;
1387
1388   XWindows
1389     *windows;
1390
1391   XWMHints
1392     *manager_hints;
1393
1394   assert(images != (Image *) NULL);
1395   assert(images->signature == MagickSignature);
1396   if (images->debug != MagickFalse)
1397     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1398   warning_handler=(WarningHandler) NULL;
1399   windows=XSetWindows((XWindows *) ~0);
1400   if (windows != (XWindows *) NULL)
1401     {
1402       int
1403         status;
1404
1405       status=chdir(working_directory);
1406       if (status == -1)
1407         (void) ThrowMagickException(&images->exception,GetMagickModule(),
1408           FileOpenError,"UnableToOpenFile","%s",working_directory);
1409       warning_handler=resource_info->display_warnings ?
1410         SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
1411       warning_handler=resource_info->display_warnings ?
1412         SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
1413     }
1414   else
1415     {
1416       register Image
1417         *p;
1418
1419       /*
1420         Initialize window structure.
1421       */
1422       for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1423       {
1424         if (p->storage_class == DirectClass)
1425           {
1426             resource_info->colors=0;
1427             break;
1428           }
1429         if (p->colors > resource_info->colors)
1430           resource_info->colors=p->colors;
1431       }
1432       windows=XSetWindows(XInitializeWindows(display,resource_info));
1433       if (windows == (XWindows *) NULL)
1434         ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
1435           images->filename);
1436       /*
1437         Initialize window id's.
1438       */
1439       number_windows=0;
1440       magick_windows[number_windows++]=(&windows->icon);
1441       magick_windows[number_windows++]=(&windows->backdrop);
1442       magick_windows[number_windows++]=(&windows->image);
1443       magick_windows[number_windows++]=(&windows->info);
1444       magick_windows[number_windows++]=(&windows->command);
1445       magick_windows[number_windows++]=(&windows->widget);
1446       magick_windows[number_windows++]=(&windows->popup);
1447       for (i=0; i < (ssize_t) number_windows; i++)
1448         magick_windows[i]->id=(Window) NULL;
1449     }
1450   /*
1451     Initialize font info.
1452   */
1453   if (windows->font_info != (XFontStruct *) NULL)
1454     (void) XFreeFont(display,windows->font_info);
1455   windows->font_info=XBestFont(display,resource_info,MagickFalse);
1456   if (windows->font_info == (XFontStruct *) NULL)
1457     ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
1458       resource_info->font);
1459   /*
1460     Initialize Standard Colormap.
1461   */
1462   map_info=windows->map_info;
1463   icon_map=windows->icon_map;
1464   visual_info=windows->visual_info;
1465   icon_visual=windows->icon_visual;
1466   pixel=windows->pixel_info;
1467   icon_pixel=windows->icon_pixel;
1468   font_info=windows->font_info;
1469   icon_resources=windows->icon_resources;
1470   class_hints=windows->class_hints;
1471   manager_hints=windows->manager_hints;
1472   root_window=XRootWindow(display,visual_info->screen);
1473   coalesce_image=CoalesceImages(images,&images->exception);
1474   if (coalesce_image == (Image *) NULL)
1475     ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
1476       images->filename);
1477   images=coalesce_image;
1478   if (resource_info->map_type == (char *) NULL)
1479     if ((visual_info->klass != TrueColor) &&
1480         (visual_info->klass != DirectColor))
1481       {
1482         Image
1483           *next;
1484
1485         /*
1486           Determine if the sequence of images has the identical colormap.
1487         */
1488         for (next=images; next != (Image *) NULL; )
1489         {
1490           next->matte=MagickFalse;
1491           if ((next->storage_class == DirectClass) ||
1492               (next->colors != images->colors) ||
1493               (next->colors > (size_t) visual_info->colormap_size))
1494             break;
1495           for (i=0; i < (ssize_t) images->colors; i++)
1496             if (IsColorEqual(next->colormap+i,images->colormap+i) == MagickFalse)
1497               break;
1498           if (i < (ssize_t) images->colors)
1499             break;
1500           next=GetNextImageInList(next);
1501         }
1502         if (next != (Image *) NULL)
1503           (void) RemapImages(resource_info->quantize_info,images,
1504             (Image *) NULL);
1505       }
1506   /*
1507     Sort images by increasing scene number.
1508   */
1509   number_scenes=GetImageListLength(images);
1510   image_list=ImageListToArray(images,&images->exception);
1511   if (image_list == (Image **) NULL)
1512     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1513       images->filename);
1514   for (scene=0; scene < (ssize_t) number_scenes; scene++)
1515     if (image_list[scene]->scene == 0)
1516       break;
1517   if (scene == (ssize_t) number_scenes)
1518     qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
1519   /*
1520     Initialize Standard Colormap.
1521   */
1522   nexus=NewImageList();
1523   display_image=image_list[0];
1524   for (scene=0; scene < (ssize_t) number_scenes; scene++)
1525   {
1526     if ((resource_info->map_type != (char *) NULL) ||
1527         (visual_info->klass == TrueColor) ||
1528         (visual_info->klass == DirectColor))
1529       (void) SetImageType(image_list[scene],image_list[scene]->matte ==
1530         MagickFalse ? TrueColorType : TrueColorMatteType);
1531     if ((display_image->columns < image_list[scene]->columns) &&
1532         (display_image->rows < image_list[scene]->rows))
1533       display_image=image_list[scene];
1534   }
1535   if (display_image->debug != MagickFalse)
1536     {
1537       (void) LogMagickEvent(X11Event,GetMagickModule(),
1538         "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,(double)
1539         display_image->scene,(double) display_image->columns,(double)
1540         display_image->rows);
1541       if (display_image->colors != 0)
1542         (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1543           display_image->colors);
1544       (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1545         display_image->magick);
1546     }
1547   XMakeStandardColormap(display,visual_info,resource_info,display_image,
1548     map_info,pixel);
1549   /*
1550     Initialize graphic context.
1551   */
1552   windows->context.id=(Window) NULL;
1553   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1554     resource_info,&windows->context);
1555   (void) CloneString(&class_hints->res_name,resource_info->client_name);
1556   (void) CloneString(&class_hints->res_class,resource_info->client_name);
1557   class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
1558   manager_hints->flags=InputHint | StateHint;
1559   manager_hints->input=MagickFalse;
1560   manager_hints->initial_state=WithdrawnState;
1561   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1562     &windows->context);
1563   if (display_image->debug != MagickFalse)
1564     (void) LogMagickEvent(X11Event,GetMagickModule(),
1565       "Window id: 0x%lx (context)",windows->context.id);
1566   context_values.background=pixel->background_color.pixel;
1567   context_values.font=font_info->fid;
1568   context_values.foreground=pixel->foreground_color.pixel;
1569   context_values.graphics_exposures=MagickFalse;
1570   context_mask=(MagickStatusType)
1571     (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
1572   if (pixel->annotate_context != (GC) NULL)
1573     (void) XFreeGC(display,pixel->annotate_context);
1574   pixel->annotate_context=
1575     XCreateGC(display,windows->context.id,context_mask,&context_values);
1576   if (pixel->annotate_context == (GC) NULL)
1577     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1578       images->filename);
1579   context_values.background=pixel->depth_color.pixel;
1580   if (pixel->widget_context != (GC) NULL)
1581     (void) XFreeGC(display,pixel->widget_context);
1582   pixel->widget_context=
1583     XCreateGC(display,windows->context.id,context_mask,&context_values);
1584   if (pixel->widget_context == (GC) NULL)
1585     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1586       images->filename);
1587   context_values.background=pixel->foreground_color.pixel;
1588   context_values.foreground=pixel->background_color.pixel;
1589   context_values.plane_mask=
1590     context_values.background ^ context_values.foreground;
1591   if (pixel->highlight_context != (GC) NULL)
1592     (void) XFreeGC(display,pixel->highlight_context);
1593   pixel->highlight_context=XCreateGC(display,windows->context.id,
1594     (size_t) (context_mask | GCPlaneMask),&context_values);
1595   if (pixel->highlight_context == (GC) NULL)
1596     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1597       images->filename);
1598   (void) XDestroyWindow(display,windows->context.id);
1599   /*
1600     Initialize icon window.
1601   */
1602   XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
1603     icon_resources,&windows->icon);
1604   windows->icon.geometry=resource_info->icon_geometry;
1605   XBestIconSize(display,&windows->icon,display_image);
1606   windows->icon.attributes.colormap=
1607     XDefaultColormap(display,icon_visual->screen);
1608   windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
1609   manager_hints->flags=InputHint | StateHint;
1610   manager_hints->input=MagickFalse;
1611   manager_hints->initial_state=IconicState;
1612   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1613     &windows->icon);
1614   if (display_image->debug != MagickFalse)
1615     (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
1616       windows->icon.id);
1617   /*
1618     Initialize graphic context for icon window.
1619   */
1620   if (icon_pixel->annotate_context != (GC) NULL)
1621     (void) XFreeGC(display,icon_pixel->annotate_context);
1622   context_values.background=icon_pixel->background_color.pixel;
1623   context_values.foreground=icon_pixel->foreground_color.pixel;
1624   icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
1625     (size_t) (GCBackground | GCForeground),&context_values);
1626   if (icon_pixel->annotate_context == (GC) NULL)
1627     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1628       images->filename);
1629   windows->icon.annotate_context=icon_pixel->annotate_context;
1630   /*
1631     Initialize Image window.
1632   */
1633   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1634     resource_info,&windows->image);
1635   windows->image.shape=MagickTrue;  /* non-rectangular shape hint */
1636   if (resource_info->use_shared_memory == MagickFalse)
1637     windows->image.shared_memory=MagickFalse;
1638   if (resource_info->title != (char *) NULL)
1639     {
1640       char
1641         *title;
1642
1643       title=InterpretImageProperties(resource_info->image_info,display_image,
1644         resource_info->title);
1645       (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
1646       (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
1647       title=DestroyString(title);
1648     }
1649   else
1650     {
1651       char
1652         filename[MaxTextExtent];
1653
1654       /*
1655         Window name is the base of the filename.
1656       */
1657       GetPathComponent(display_image->magick_filename,TailPath,filename);
1658       (void) FormatMagickString(windows->image.name,MaxTextExtent,
1659         "%s: %s[%.20g of %.20g]",MagickPackageName,filename,(double)
1660         display_image->scene,(double) number_scenes);
1661       (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
1662     }
1663   if (resource_info->immutable != MagickFalse)
1664     windows->image.immutable=MagickTrue;
1665   windows->image.shape=MagickTrue;
1666   windows->image.geometry=resource_info->image_geometry;
1667   (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>!",
1668     XDisplayWidth(display,visual_info->screen),
1669     XDisplayHeight(display,visual_info->screen));
1670   geometry_info.width=display_image->columns;
1671   geometry_info.height=display_image->rows;
1672   geometry_info.x=0;
1673   geometry_info.y=0;
1674   (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
1675     &geometry_info.width,&geometry_info.height);
1676   windows->image.width=(unsigned int) geometry_info.width;
1677   windows->image.height=(unsigned int) geometry_info.height;
1678   windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1679     ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1680     KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
1681     PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
1682   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1683     resource_info,&windows->backdrop);
1684   if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
1685     {
1686       /*
1687         Initialize backdrop window.
1688       */
1689       windows->backdrop.x=0;
1690       windows->backdrop.y=0;
1691       (void) CloneString(&windows->backdrop.name,"ImageMagick Backdrop");
1692       windows->backdrop.flags=(size_t) (USSize | USPosition);
1693       windows->backdrop.width=(unsigned int)
1694         XDisplayWidth(display,visual_info->screen);
1695       windows->backdrop.height=(unsigned int)
1696         XDisplayHeight(display,visual_info->screen);
1697       windows->backdrop.border_width=0;
1698       windows->backdrop.immutable=MagickTrue;
1699       windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
1700         ButtonReleaseMask;
1701       windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
1702         StructureNotifyMask;
1703       manager_hints->flags=IconWindowHint | InputHint | StateHint;
1704       manager_hints->icon_window=windows->icon.id;
1705       manager_hints->input=MagickTrue;
1706       manager_hints->initial_state=
1707         resource_info->iconic ? IconicState : NormalState;
1708       XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1709         &windows->backdrop);
1710       if (display_image->debug != MagickFalse)
1711         (void) LogMagickEvent(X11Event,GetMagickModule(),
1712           "Window id: 0x%lx (backdrop)",windows->backdrop.id);
1713       (void) XMapWindow(display,windows->backdrop.id);
1714       (void) XClearWindow(display,windows->backdrop.id);
1715       if (windows->image.id != (Window) NULL)
1716         {
1717           (void) XDestroyWindow(display,windows->image.id);
1718           windows->image.id=(Window) NULL;
1719         }
1720       /*
1721         Position image in the center the backdrop.
1722       */
1723       windows->image.flags|=USPosition;
1724       windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
1725         (windows->image.width/2);
1726       windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
1727         (windows->image.height/2);
1728     }
1729   manager_hints->flags=IconWindowHint | InputHint | StateHint;
1730   manager_hints->icon_window=windows->icon.id;
1731   manager_hints->input=MagickTrue;
1732   manager_hints->initial_state=
1733     resource_info->iconic ? IconicState : NormalState;
1734   if (windows->group_leader.id != (Window) NULL)
1735     {
1736       /*
1737         Follow the leader.
1738       */
1739       manager_hints->flags|=(MagickStatusType) WindowGroupHint;
1740       manager_hints->window_group=windows->group_leader.id;
1741       (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
1742       if (display_image->debug != MagickFalse)
1743         (void) LogMagickEvent(X11Event,GetMagickModule(),
1744           "Window id: 0x%lx (group leader)",windows->group_leader.id);
1745     }
1746   XMakeWindow(display,
1747     (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
1748     argv,argc,class_hints,manager_hints,&windows->image);
1749   (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
1750     XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
1751   if (windows->group_leader.id != (Window) NULL)
1752     (void) XSetTransientForHint(display,windows->image.id,
1753       windows->group_leader.id);
1754   if (display_image->debug != MagickFalse)
1755     (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
1756       windows->image.id);
1757   /*
1758     Initialize Info widget.
1759   */
1760   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1761     resource_info,&windows->info);
1762   (void) CloneString(&windows->info.name,"Info");
1763   (void) CloneString(&windows->info.icon_name,"Info");
1764   windows->info.border_width=1;
1765   windows->info.x=2;
1766   windows->info.y=2;
1767   windows->info.flags|=PPosition;
1768   windows->info.attributes.win_gravity=UnmapGravity;
1769   windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
1770     StructureNotifyMask;
1771   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1772   manager_hints->input=MagickFalse;
1773   manager_hints->initial_state=NormalState;
1774   manager_hints->window_group=windows->image.id;
1775   XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
1776     &windows->info);
1777   windows->info.highlight_stipple=XCreateBitmapFromData(display,
1778     windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1779   windows->info.shadow_stipple=XCreateBitmapFromData(display,
1780     windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1781   (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
1782   if (windows->image.mapped)
1783     (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
1784   if (display_image->debug != MagickFalse)
1785     (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
1786       windows->info.id);
1787   /*
1788     Initialize Command widget.
1789   */
1790   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1791     resource_info,&windows->command);
1792   windows->command.data=MagickMenus;
1793   (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
1794   (void) FormatMagickString(resource_name,MaxTextExtent,"%s.command",
1795     resource_info->client_name);
1796   windows->command.geometry=XGetResourceClass(resource_info->resource_database,
1797     resource_name,"geometry",(char *) NULL);
1798   (void) CloneString(&windows->command.name,MagickTitle);
1799   windows->command.border_width=0;
1800   windows->command.flags|=PPosition;
1801   windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1802     ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
1803     OwnerGrabButtonMask | StructureNotifyMask;
1804   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1805   manager_hints->input=MagickTrue;
1806   manager_hints->initial_state=NormalState;
1807   manager_hints->window_group=windows->image.id;
1808   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1809     &windows->command);
1810   windows->command.highlight_stipple=XCreateBitmapFromData(display,
1811     windows->command.id,(char *) HighlightBitmap,HighlightWidth,
1812     HighlightHeight);
1813   windows->command.shadow_stipple=XCreateBitmapFromData(display,
1814     windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1815   (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
1816   if (display_image->debug != MagickFalse)
1817     (void) LogMagickEvent(X11Event,GetMagickModule(),
1818       "Window id: 0x%lx (command)",windows->command.id);
1819   /*
1820     Initialize Widget window.
1821   */
1822   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1823     resource_info,&windows->widget);
1824   (void) FormatMagickString(resource_name,MaxTextExtent,"%s.widget",
1825     resource_info->client_name);
1826   windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
1827     resource_name,"geometry",(char *) NULL);
1828   windows->widget.border_width=0;
1829   windows->widget.flags|=PPosition;
1830   windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1831     ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1832     KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
1833     StructureNotifyMask;
1834   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1835   manager_hints->input=MagickTrue;
1836   manager_hints->initial_state=NormalState;
1837   manager_hints->window_group=windows->image.id;
1838   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1839     &windows->widget);
1840   windows->widget.highlight_stipple=XCreateBitmapFromData(display,
1841     windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1842   windows->widget.shadow_stipple=XCreateBitmapFromData(display,
1843     windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1844   (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
1845   if (display_image->debug != MagickFalse)
1846     (void) LogMagickEvent(X11Event,GetMagickModule(),
1847       "Window id: 0x%lx (widget)",windows->widget.id);
1848   /*
1849     Initialize popup window.
1850   */
1851   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1852     resource_info,&windows->popup);
1853   windows->popup.border_width=0;
1854   windows->popup.flags|=PPosition;
1855   windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1856     ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1857     KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
1858   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1859   manager_hints->input=MagickTrue;
1860   manager_hints->initial_state=NormalState;
1861   manager_hints->window_group=windows->image.id;
1862   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1863     &windows->popup);
1864   windows->popup.highlight_stipple=XCreateBitmapFromData(display,
1865     windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1866   windows->popup.shadow_stipple=XCreateBitmapFromData(display,
1867     windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1868   (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
1869   if (display_image->debug != MagickFalse)
1870     (void) LogMagickEvent(X11Event,GetMagickModule(),
1871       "Window id: 0x%lx (pop up)",windows->popup.id);
1872   /*
1873     Set out progress and warning handlers.
1874   */
1875   if (warning_handler == (WarningHandler) NULL)
1876     {
1877       warning_handler=resource_info->display_warnings ?
1878         SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
1879       warning_handler=resource_info->display_warnings ?
1880         SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
1881     }
1882   /*
1883     Initialize X image structure.
1884   */
1885   windows->image.x=0;
1886   windows->image.y=0;
1887   /*
1888     Initialize image pixmaps structure.
1889   */
1890   window_changes.width=(int) windows->image.width;
1891   window_changes.height=(int) windows->image.height;
1892   (void) XReconfigureWMWindow(display,windows->image.id,windows->command.screen,
1893     (unsigned int) (CWWidth | CWHeight),&window_changes);
1894   windows->image.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1895     sizeof(*windows->image.pixmaps));
1896   windows->image.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1897     sizeof(*windows->image.pixmaps));
1898   if ((windows->image.pixmaps == (Pixmap *) NULL) ||
1899       (windows->image.matte_pixmaps == (Pixmap *) NULL))
1900     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1901       images->filename);
1902   if ((windows->image.mapped == MagickFalse) ||
1903       (windows->backdrop.id != (Window) NULL))
1904     (void) XMapWindow(display,windows->image.id);
1905   XSetCursorState(display,windows,MagickTrue);
1906   for (scene=0; scene < (ssize_t) number_scenes; scene++)
1907   {
1908     unsigned int
1909       columns,
1910       rows;
1911
1912     /*
1913       Create X image.
1914     */
1915     (void) TransformImageColorspace(image_list[scene],RGBColorspace);
1916     windows->image.pixmap=(Pixmap) NULL;
1917     windows->image.matte_pixmap=(Pixmap) NULL;
1918     if ((resource_info->map_type != (char *) NULL) ||
1919         (visual_info->klass == TrueColor) ||
1920         (visual_info->klass == DirectColor))
1921       if (image_list[scene]->storage_class == PseudoClass)
1922         XGetPixelPacket(display,visual_info,map_info,resource_info,
1923           image_list[scene],windows->image.pixel_info);
1924     columns=(unsigned int) image_list[scene]->columns;
1925     rows=(unsigned int) image_list[scene]->rows;
1926     if ((image_list[scene]->columns != columns) ||
1927         (image_list[scene]->rows != rows))
1928       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1929         image_list[scene]->filename);
1930     status=XMakeImage(display,resource_info,&windows->image,image_list[scene],
1931       columns,rows);
1932     if (status == MagickFalse)
1933       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1934         images->filename);
1935     if (image_list[scene]->debug != MagickFalse)
1936       {
1937         (void) LogMagickEvent(X11Event,GetMagickModule(),
1938           "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
1939           image_list[scene]->filename,(double) columns,(double) rows);
1940         if (image_list[scene]->colors != 0)
1941           (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1942             image_list[scene]->colors);
1943         (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1944           image_list[scene]->magick);
1945       }
1946     /*
1947       Window name is the base of the filename.
1948     */
1949     if (resource_info->title != (char *) NULL)
1950       {
1951         char
1952           *title;
1953
1954         title=InterpretImageProperties(resource_info->image_info,
1955           image_list[scene],resource_info->title);
1956         (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
1957         title=DestroyString(title);
1958       }
1959     else
1960       {
1961         p=image_list[scene]->magick_filename+
1962           strlen(image_list[scene]->magick_filename)-1;
1963         while ((p > image_list[scene]->magick_filename) && (*(p-1) != '/'))
1964           p--;
1965         (void) FormatMagickString(windows->image.name,MaxTextExtent,
1966           "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double) scene+1,
1967           (double) number_scenes);
1968       }
1969     status=XStringListToTextProperty(&windows->image.name,1,&window_name);
1970     if (status != Success)
1971       {
1972         XSetWMName(display,windows->image.id,&window_name);
1973         (void) XFree((void *) window_name.value);
1974       }
1975     windows->image.pixmaps[scene]=windows->image.pixmap;
1976     windows->image.matte_pixmaps[scene]=windows->image.matte_pixmap;
1977     if (scene == 0)
1978       {
1979         event.xexpose.x=0;
1980         event.xexpose.y=0;
1981         event.xexpose.width=(int) image_list[scene]->columns;
1982         event.xexpose.height=(int) image_list[scene]->rows;
1983         XRefreshWindow(display,&windows->image,&event);
1984         (void) XSync(display,MagickFalse);
1985     }
1986   }
1987   XSetCursorState(display,windows,MagickFalse);
1988   if (windows->command.mapped)
1989     (void) XMapRaised(display,windows->command.id);
1990   /*
1991     Respond to events.
1992   */
1993   nexus=NewImageList();
1994   scene=0;
1995   first_scene=0;
1996   iterations=0;
1997   image=image_list[0];
1998   state=(MagickStatusType) (ForwardAnimationState | RepeatAnimationState);
1999   (void) XMagickCommand(display,resource_info,windows,PlayCommand,&images,
2000     &state);
2001   do
2002   {
2003     if (XEventsQueued(display,QueuedAfterFlush) == 0)
2004       if ((state & PlayAnimationState) || (state & StepAnimationState))
2005         {
2006           MagickBooleanType
2007             pause;
2008
2009           pause=MagickFalse;
2010           delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
2011           XDelay(display,resource_info->delay*(delay == 0 ? 10 : delay));
2012           if (state & ForwardAnimationState)
2013             {
2014               /*
2015                 Forward animation:  increment scene number.
2016               */
2017               if (scene < ((ssize_t) number_scenes-1))
2018                 scene++;
2019               else
2020                 {
2021                   iterations++;
2022                   if (iterations == (ssize_t) image_list[0]->iterations)
2023                     {
2024                       iterations=0;
2025                       state|=ExitState;
2026                     }
2027                   if ((state & AutoReverseAnimationState) != 0)
2028                     {
2029                       state&=(~ForwardAnimationState);
2030                       scene--;
2031                     }
2032                   else
2033                     {
2034                       if ((state & RepeatAnimationState) == 0)
2035                         state&=(~PlayAnimationState);
2036                       scene=first_scene;
2037                       pause=MagickTrue;
2038                     }
2039                 }
2040             }
2041           else
2042             {
2043               /*
2044                 Reverse animation:  decrement scene number.
2045               */
2046               if (scene > first_scene)
2047                 scene--;
2048               else
2049                 {
2050                   iterations++;
2051                   if (iterations == (ssize_t) image_list[0]->iterations)
2052                     {
2053                       iterations=0;
2054                       state&=(~RepeatAnimationState);
2055                     }
2056                   if (state & AutoReverseAnimationState)
2057                     {
2058                       state|=ForwardAnimationState;
2059                       scene=first_scene;
2060                       pause=MagickTrue;
2061                     }
2062                   else
2063                     {
2064                       if ((state & RepeatAnimationState) == MagickFalse)
2065                         state&=(~PlayAnimationState);
2066                       scene=(ssize_t) number_scenes-1;
2067                     }
2068                 }
2069             }
2070           scene=MagickMax(scene,0);
2071           image=image_list[scene];
2072           if ((image != (Image *) NULL) && (image->start_loop != 0))
2073             first_scene=scene;
2074           if ((state & StepAnimationState) ||
2075               (resource_info->title != (char *) NULL))
2076             {
2077               /*
2078                 Update window title.
2079               */
2080               p=image_list[scene]->filename+
2081                 strlen(image_list[scene]->filename)-1;
2082               while ((p > image_list[scene]->filename) && (*(p-1) != '/'))
2083                 p--;
2084               (void) FormatMagickString(windows->image.name,MaxTextExtent,
2085                 "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double)
2086                 scene+1,(double) number_scenes);
2087               if (resource_info->title != (char *) NULL)
2088                 {
2089                   char
2090                     *title;
2091
2092                   title=InterpretImageProperties(resource_info->image_info,
2093                     image,resource_info->title);
2094                   (void) CopyMagickString(windows->image.name,title,
2095                     MaxTextExtent);
2096                   title=DestroyString(title);
2097                 }
2098               status=XStringListToTextProperty(&windows->image.name,1,
2099                 &window_name);
2100               if (status != Success)
2101                 {
2102                   XSetWMName(display,windows->image.id,&window_name);
2103                   (void) XFree((void *) window_name.value);
2104                 }
2105             }
2106           /*
2107             Copy X pixmap to Image window.
2108           */
2109           XGetPixelPacket(display,visual_info,map_info,resource_info,
2110             image_list[scene],windows->image.pixel_info);
2111           windows->image.ximage->width=(int) image->columns;
2112           windows->image.ximage->height=(int) image->rows;
2113           windows->image.pixmap=windows->image.pixmaps[scene];
2114           windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
2115           event.xexpose.x=0;
2116           event.xexpose.y=0;
2117           event.xexpose.width=(int) image->columns;
2118           event.xexpose.height=(int) image->rows;
2119           if ((state & ExitState) == 0)
2120             {
2121               XRefreshWindow(display,&windows->image,&event);
2122               (void) XSync(display,MagickFalse);
2123             }
2124           state&=(~StepAnimationState);
2125           if (pause != MagickFalse)
2126             for (i=0; i < (ssize_t) resource_info->pause; i++)
2127             {
2128               int
2129                 status;
2130
2131               status=XCheckTypedWindowEvent(display,windows->image.id,KeyPress,
2132                 &event);
2133               if (status != 0)
2134                 {
2135                   int
2136                     length;
2137
2138                   length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2139                     sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2140                   *(command+length)='\0';
2141                   if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
2142                     {
2143                       XClientMessage(display,windows->image.id,
2144                         windows->im_protocols,windows->im_exit,CurrentTime);
2145                       break;
2146                     }
2147                 }
2148               (void) sleep(1);
2149             }
2150           continue;
2151         }
2152     /*
2153       Handle a window event.
2154     */
2155     timestamp=time((time_t *) NULL);
2156     (void) XNextEvent(display,&event);
2157     if (windows->image.stasis == MagickFalse)
2158       windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
2159         MagickTrue : MagickFalse;
2160     if (event.xany.window == windows->command.id)
2161       {
2162         int
2163           id;
2164
2165         /*
2166           Select a command from the Command widget.
2167         */
2168         id=XCommandWidget(display,windows,CommandMenu,&event);
2169         if (id < 0)
2170           continue;
2171         (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
2172         command_type=CommandMenus[id];
2173         if (id < MagickMenus)
2174           {
2175             int
2176               entry;
2177
2178             /*
2179               Select a command from a pop-up menu.
2180             */
2181             entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
2182               command);
2183             if (entry < 0)
2184               continue;
2185             (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
2186             command_type=Commands[id][entry];
2187           }
2188         if (command_type != NullCommand)
2189           nexus=XMagickCommand(display,resource_info,windows,
2190             command_type,&image,&state);
2191         continue;
2192       }
2193     switch (event.type)
2194     {
2195       case ButtonPress:
2196       {
2197         if (display_image->debug != MagickFalse)
2198           (void) LogMagickEvent(X11Event,GetMagickModule(),
2199             "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
2200             event.xbutton.button,event.xbutton.x,event.xbutton.y);
2201         if ((event.xbutton.button == Button3) &&
2202             (event.xbutton.state & Mod1Mask))
2203           {
2204             /*
2205               Convert Alt-Button3 to Button2.
2206             */
2207             event.xbutton.button=Button2;
2208             event.xbutton.state&=(~Mod1Mask);
2209           }
2210         if (event.xbutton.window == windows->backdrop.id)
2211           {
2212             (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
2213               event.xbutton.time);
2214             break;
2215           }
2216         if (event.xbutton.window == windows->image.id)
2217           {
2218             if (resource_info->immutable != MagickFalse)
2219               {
2220                 state|=ExitState;
2221                 break;
2222               }
2223             /*
2224               Map/unmap Command widget.
2225             */
2226             if (windows->command.mapped)
2227               (void) XWithdrawWindow(display,windows->command.id,
2228                 windows->command.screen);
2229             else
2230               {
2231                 (void) XCommandWidget(display,windows,CommandMenu,
2232                   (XEvent *) NULL);
2233                 (void) XMapRaised(display,windows->command.id);
2234               }
2235           }
2236         break;
2237       }
2238       case ButtonRelease:
2239       {
2240         if (display_image->debug != MagickFalse)
2241           (void) LogMagickEvent(X11Event,GetMagickModule(),
2242             "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
2243             event.xbutton.button,event.xbutton.x,event.xbutton.y);
2244         break;
2245       }
2246       case ClientMessage:
2247       {
2248         if (display_image->debug != MagickFalse)
2249           (void) LogMagickEvent(X11Event,GetMagickModule(),
2250             "Client Message: 0x%lx 0x%lx %d 0x%lx",(unsigned long)
2251             event.xclient.window,(unsigned long) event.xclient.message_type,
2252             event.xclient.format,(unsigned long) event.xclient.data.l[0]);
2253         if (event.xclient.message_type == windows->im_protocols)
2254           {
2255             if (*event.xclient.data.l == (long) windows->im_update_colormap)
2256               {
2257                 /*
2258                   Update graphic context and window colormap.
2259                 */
2260                 for (i=0; i < (ssize_t) number_windows; i++)
2261                 {
2262                   if (magick_windows[i]->id == windows->icon.id)
2263                     continue;
2264                   context_values.background=pixel->background_color.pixel;
2265                   context_values.foreground=pixel->foreground_color.pixel;
2266                   (void) XChangeGC(display,magick_windows[i]->annotate_context,
2267                     context_mask,&context_values);
2268                   (void) XChangeGC(display,magick_windows[i]->widget_context,
2269                     context_mask,&context_values);
2270                   context_values.background=pixel->foreground_color.pixel;
2271                   context_values.foreground=pixel->background_color.pixel;
2272                   context_values.plane_mask=
2273                     context_values.background ^ context_values.foreground;
2274                   (void) XChangeGC(display,magick_windows[i]->highlight_context,
2275                     (size_t) (context_mask | GCPlaneMask),
2276                     &context_values);
2277                   magick_windows[i]->attributes.background_pixel=
2278                     pixel->background_color.pixel;
2279                   magick_windows[i]->attributes.border_pixel=
2280                     pixel->border_color.pixel;
2281                   magick_windows[i]->attributes.colormap=map_info->colormap;
2282                   (void) XChangeWindowAttributes(display,magick_windows[i]->id,
2283                     magick_windows[i]->mask,&magick_windows[i]->attributes);
2284                 }
2285                 if (windows->backdrop.id != (Window) NULL)
2286                   (void) XInstallColormap(display,map_info->colormap);
2287                 break;
2288               }
2289             if (*event.xclient.data.l == (long) windows->im_exit)
2290               {
2291                 state|=ExitState;
2292                 break;
2293               }
2294             break;
2295           }
2296         if (event.xclient.message_type == windows->dnd_protocols)
2297           {
2298             Atom
2299               selection,
2300               type;
2301
2302             int
2303               format,
2304               status;
2305
2306             unsigned char
2307               *data;
2308
2309             unsigned long
2310               after,
2311               length;
2312
2313             /*
2314               Display image named by the Drag-and-Drop selection.
2315             */
2316             if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
2317               break;
2318             selection=XInternAtom(display,"DndSelection",MagickFalse);
2319             status=XGetWindowProperty(display,root_window,selection,0L,2047L,
2320               MagickFalse,(Atom) AnyPropertyType,&type,&format,&length,&after,
2321               &data);
2322             if ((status != Success) || (length == 0))
2323               break;
2324             if (*event.xclient.data.l == 2)
2325               {
2326                 /*
2327                   Offix DND.
2328                 */
2329                 (void) CopyMagickString(resource_info->image_info->filename,
2330                   (char *) data,MaxTextExtent);
2331               }
2332             else
2333               {
2334                 /*
2335                   XDND.
2336                 */
2337                 if (LocaleNCompare((char *) data,"file:",5) != 0)
2338                   {
2339                     (void) XFree((void *) data);
2340                     break;
2341                   }
2342                 (void) CopyMagickString(resource_info->image_info->filename,
2343                   ((char *) data)+5,MaxTextExtent);
2344               }
2345             nexus=ReadImage(resource_info->image_info,&image->exception);
2346             CatchException(&image->exception);
2347             if (nexus != (Image *) NULL)
2348               state|=ExitState;
2349             (void) XFree((void *) data);
2350             break;
2351           }
2352         /*
2353           If client window delete message, exit.
2354         */
2355         if (event.xclient.message_type != windows->wm_protocols)
2356           break;
2357         if (*event.xclient.data.l == (long) windows->wm_take_focus)
2358           {
2359             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2360               (Time) event.xclient.data.l[1]);
2361             break;
2362           }
2363         if (*event.xclient.data.l != (long) windows->wm_delete_window)
2364           break;
2365         (void) XWithdrawWindow(display,event.xclient.window,
2366           visual_info->screen);
2367         if (event.xclient.window == windows->image.id)
2368           {
2369             state|=ExitState;
2370             break;
2371           }
2372         break;
2373       }
2374       case ConfigureNotify:
2375       {
2376         if (display_image->debug != MagickFalse)
2377           (void) LogMagickEvent(X11Event,GetMagickModule(),
2378             "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
2379             event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
2380             event.xconfigure.y,event.xconfigure.send_event);
2381         if (event.xconfigure.window == windows->image.id)
2382           {
2383             if (event.xconfigure.send_event != 0)
2384               {
2385                 XWindowChanges
2386                   window_changes;
2387
2388                 /*
2389                   Position the transient windows relative of the Image window.
2390                 */
2391                 if (windows->command.geometry == (char *) NULL)
2392                   if (windows->command.mapped == MagickFalse)
2393                     {
2394                        windows->command.x=
2395                           event.xconfigure.x-windows->command.width-25;
2396                         windows->command.y=event.xconfigure.y;
2397                         XConstrainWindowPosition(display,&windows->command);
2398                         window_changes.x=windows->command.x;
2399                         window_changes.y=windows->command.y;
2400                         (void) XReconfigureWMWindow(display,windows->command.id,
2401                           windows->command.screen,(unsigned int) (CWX | CWY),
2402                           &window_changes);
2403                     }
2404                 if (windows->widget.geometry == (char *) NULL)
2405                   if (windows->widget.mapped == MagickFalse)
2406                     {
2407                       windows->widget.x=
2408                         event.xconfigure.x+event.xconfigure.width/10;
2409                       windows->widget.y=
2410                         event.xconfigure.y+event.xconfigure.height/10;
2411                       XConstrainWindowPosition(display,&windows->widget);
2412                       window_changes.x=windows->widget.x;
2413                       window_changes.y=windows->widget.y;
2414                       (void) XReconfigureWMWindow(display,windows->widget.id,
2415                         windows->widget.screen,(unsigned int) (CWX | CWY),
2416                         &window_changes);
2417                     }
2418               }
2419             /*
2420               Image window has a new configuration.
2421             */
2422             windows->image.width=(unsigned int) event.xconfigure.width;
2423             windows->image.height=(unsigned int) event.xconfigure.height;
2424             break;
2425           }
2426         if (event.xconfigure.window == windows->icon.id)
2427           {
2428             /*
2429               Icon window has a new configuration.
2430             */
2431             windows->icon.width=(unsigned int) event.xconfigure.width;
2432             windows->icon.height=(unsigned int) event.xconfigure.height;
2433             break;
2434           }
2435         break;
2436       }
2437       case DestroyNotify:
2438       {
2439         /*
2440           Group leader has exited.
2441         */
2442         if (display_image->debug != MagickFalse)
2443           (void) LogMagickEvent(X11Event,GetMagickModule(),
2444             "Destroy Notify: 0x%lx",event.xdestroywindow.window);
2445         if (event.xdestroywindow.window == windows->group_leader.id)
2446           {
2447             state|=ExitState;
2448             break;
2449           }
2450         break;
2451       }
2452       case EnterNotify:
2453       {
2454         /*
2455           Selectively install colormap.
2456         */
2457         if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2458           if (event.xcrossing.mode != NotifyUngrab)
2459             XInstallColormap(display,map_info->colormap);
2460         break;
2461       }
2462       case Expose:
2463       {
2464         if (display_image->debug != MagickFalse)
2465           (void) LogMagickEvent(X11Event,GetMagickModule(),
2466             "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
2467             event.xexpose.width,event.xexpose.height,event.xexpose.x,
2468             event.xexpose.y);
2469         /*
2470           Repaint windows that are now exposed.
2471         */
2472         if (event.xexpose.window == windows->image.id)
2473           {
2474             windows->image.pixmap=windows->image.pixmaps[scene];
2475             windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
2476             XRefreshWindow(display,&windows->image,&event);
2477             break;
2478           }
2479         if (event.xexpose.window == windows->icon.id)
2480           if (event.xexpose.count == 0)
2481             {
2482               XRefreshWindow(display,&windows->icon,&event);
2483               break;
2484             }
2485         break;
2486       }
2487       case KeyPress:
2488       {
2489         static int
2490           length;
2491
2492         /*
2493           Respond to a user key press.
2494         */
2495         length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2496           sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2497         *(command+length)='\0';
2498         if (display_image->debug != MagickFalse)
2499           (void) LogMagickEvent(X11Event,GetMagickModule(),
2500             "Key press: 0x%lx (%c)",(unsigned long) key_symbol,*command);
2501         command_type=NullCommand;
2502         switch (key_symbol)
2503         {
2504           case XK_o:
2505           {
2506             if ((event.xkey.state & ControlMask) == MagickFalse)
2507               break;
2508             command_type=OpenCommand;
2509             break;
2510           }
2511           case XK_BackSpace:
2512           {
2513             command_type=StepBackwardCommand;
2514             break;
2515           }
2516           case XK_space:
2517           {
2518             command_type=StepForwardCommand;
2519             break;
2520           }
2521           case XK_less:
2522           {
2523             command_type=FasterCommand;
2524             break;
2525           }
2526           case XK_greater:
2527           {
2528             command_type=SlowerCommand;
2529             break;
2530           }
2531           case XK_F1:
2532           {
2533             command_type=HelpCommand;
2534             break;
2535           }
2536           case XK_Find:
2537           {
2538             command_type=BrowseDocumentationCommand;
2539             break;
2540           }
2541           case XK_question:
2542           {
2543             command_type=InfoCommand;
2544             break;
2545           }
2546           case XK_q:
2547           case XK_Escape:
2548           {
2549             command_type=QuitCommand;
2550             break;
2551           }
2552           default:
2553             break;
2554         }
2555         if (command_type != NullCommand)
2556           nexus=XMagickCommand(display,resource_info,windows,
2557             command_type,&image,&state);
2558         break;
2559       }
2560       case KeyRelease:
2561       {
2562         /*
2563           Respond to a user key release.
2564         */
2565         (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2566           sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2567         if (display_image->debug != MagickFalse)
2568           (void) LogMagickEvent(X11Event,GetMagickModule(),
2569             "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
2570         break;
2571       }
2572       case LeaveNotify:
2573       {
2574         /*
2575           Selectively uninstall colormap.
2576         */
2577         if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2578           if (event.xcrossing.mode != NotifyUngrab)
2579             XUninstallColormap(display,map_info->colormap);
2580         break;
2581       }
2582       case MapNotify:
2583       {
2584         if (display_image->debug != MagickFalse)
2585           (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
2586             event.xmap.window);
2587         if (event.xmap.window == windows->backdrop.id)
2588           {
2589             (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
2590               CurrentTime);
2591             windows->backdrop.mapped=MagickTrue;
2592             break;
2593           }
2594         if (event.xmap.window == windows->image.id)
2595           {
2596             if (windows->backdrop.id != (Window) NULL)
2597               (void) XInstallColormap(display,map_info->colormap);
2598             if (LocaleCompare(image_list[0]->magick,"LOGO") == 0)
2599               {
2600                 if (LocaleCompare(display_image->filename,"LOGO") == 0)
2601                   nexus=XMagickCommand(display,resource_info,windows,
2602                     OpenCommand,&image,&state);
2603                 else
2604                   state|=ExitState;
2605               }
2606             windows->image.mapped=MagickTrue;
2607             break;
2608           }
2609         if (event.xmap.window == windows->info.id)
2610           {
2611             windows->info.mapped=MagickTrue;
2612             break;
2613           }
2614         if (event.xmap.window == windows->icon.id)
2615           {
2616             /*
2617               Create an icon image.
2618             */
2619             XMakeStandardColormap(display,icon_visual,icon_resources,
2620               display_image,icon_map,icon_pixel);
2621             (void) XMakeImage(display,icon_resources,&windows->icon,
2622               display_image,windows->icon.width,windows->icon.height);
2623             (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
2624               windows->icon.pixmap);
2625             (void) XClearWindow(display,windows->icon.id);
2626             (void) XWithdrawWindow(display,windows->info.id,
2627               windows->info.screen);
2628             windows->icon.mapped=MagickTrue;
2629             break;
2630           }
2631         if (event.xmap.window == windows->command.id)
2632           {
2633             windows->command.mapped=MagickTrue;
2634             break;
2635           }
2636         if (event.xmap.window == windows->popup.id)
2637           {
2638             windows->popup.mapped=MagickTrue;
2639             break;
2640           }
2641         if (event.xmap.window == windows->widget.id)
2642           {
2643             windows->widget.mapped=MagickTrue;
2644             break;
2645           }
2646         break;
2647       }
2648       case MappingNotify:
2649       {
2650         (void) XRefreshKeyboardMapping(&event.xmapping);
2651         break;
2652       }
2653       case NoExpose:
2654         break;
2655       case PropertyNotify:
2656       {
2657         Atom
2658           type;
2659
2660         int
2661           format,
2662           status;
2663
2664         unsigned char
2665           *data;
2666
2667         unsigned long
2668           after,
2669           length;
2670
2671         if (display_image->debug != MagickFalse)
2672           (void) LogMagickEvent(X11Event,GetMagickModule(),
2673             "Property Notify: 0x%lx 0x%lx %d",(unsigned long)
2674             event.xproperty.window,(unsigned long) event.xproperty.atom,
2675             event.xproperty.state);
2676         if (event.xproperty.atom != windows->im_remote_command)
2677           break;
2678         /*
2679           Display image named by the remote command protocol.
2680         */
2681         status=XGetWindowProperty(display,event.xproperty.window,
2682           event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
2683           AnyPropertyType,&type,&format,&length,&after,&data);
2684         if ((status != Success) || (length == 0))
2685           break;
2686         (void) CopyMagickString(resource_info->image_info->filename,
2687           (char *) data,MaxTextExtent);
2688         nexus=ReadImage(resource_info->image_info,&image->exception);
2689         CatchException(&image->exception);
2690         if (nexus != (Image *) NULL)
2691           state|=ExitState;
2692         (void) XFree((void *) data);
2693         break;
2694       }
2695       case ReparentNotify:
2696       {
2697         if (display_image->debug != MagickFalse)
2698           (void) LogMagickEvent(X11Event,GetMagickModule(),
2699             "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
2700             event.xreparent.window);
2701         break;
2702       }
2703       case UnmapNotify:
2704       {
2705         if (display_image->debug != MagickFalse)
2706           (void) LogMagickEvent(X11Event,GetMagickModule(),
2707             "Unmap Notify: 0x%lx",event.xunmap.window);
2708         if (event.xunmap.window == windows->backdrop.id)
2709           {
2710             windows->backdrop.mapped=MagickFalse;
2711             break;
2712           }
2713         if (event.xunmap.window == windows->image.id)
2714           {
2715             windows->image.mapped=MagickFalse;
2716             break;
2717           }
2718         if (event.xunmap.window == windows->info.id)
2719           {
2720             windows->info.mapped=MagickFalse;
2721             break;
2722           }
2723         if (event.xunmap.window == windows->icon.id)
2724           {
2725             if (map_info->colormap == icon_map->colormap)
2726               XConfigureImageColormap(display,resource_info,windows,
2727                 display_image);
2728             (void) XFreeStandardColormap(display,icon_visual,icon_map,
2729               icon_pixel);
2730             windows->icon.mapped=MagickFalse;
2731             break;
2732           }
2733         if (event.xunmap.window == windows->command.id)
2734           {
2735             windows->command.mapped=MagickFalse;
2736             break;
2737           }
2738         if (event.xunmap.window == windows->popup.id)
2739           {
2740             if (windows->backdrop.id != (Window) NULL)
2741               (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2742                 CurrentTime);
2743             windows->popup.mapped=MagickFalse;
2744             break;
2745           }
2746         if (event.xunmap.window == windows->widget.id)
2747           {
2748             if (windows->backdrop.id != (Window) NULL)
2749               (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2750                 CurrentTime);
2751             windows->widget.mapped=MagickFalse;
2752             break;
2753           }
2754         break;
2755       }
2756       default:
2757       {
2758         if (display_image->debug != MagickFalse)
2759           (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
2760             event.type);
2761         break;
2762       }
2763     }
2764   }
2765   while (!(state & ExitState));
2766   image_list=(Image **) RelinquishMagickMemory(image_list);
2767   images=DestroyImageList(images);
2768   if ((windows->visual_info->klass == GrayScale) ||
2769       (windows->visual_info->klass == PseudoColor) ||
2770       (windows->visual_info->klass == DirectColor))
2771     {
2772       /*
2773         Withdraw windows.
2774       */
2775       if (windows->info.mapped)
2776         (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2777       if (windows->command.mapped)
2778         (void) XWithdrawWindow(display,windows->command.id,
2779           windows->command.screen);
2780     }
2781   if (resource_info->backdrop == MagickFalse)
2782     if (windows->backdrop.mapped)
2783       {
2784         (void) XWithdrawWindow(display,windows->backdrop.id,\
2785           windows->backdrop.screen);
2786         (void) XDestroyWindow(display,windows->backdrop.id);
2787         windows->backdrop.id=(Window) NULL;
2788         (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);
2789         (void) XDestroyWindow(display,windows->image.id);
2790         windows->image.id=(Window) NULL;
2791       }
2792   XSetCursorState(display,windows,MagickTrue);
2793   XCheckRefreshWindows(display,windows);
2794   for (scene=1; scene < (ssize_t) number_scenes; scene++)
2795   {
2796     if (windows->image.pixmaps[scene] != (Pixmap) NULL)
2797       (void) XFreePixmap(display,windows->image.pixmaps[scene]);
2798     windows->image.pixmaps[scene]=(Pixmap) NULL;
2799     if (windows->image.matte_pixmaps[scene] != (Pixmap) NULL)
2800       (void) XFreePixmap(display,windows->image.matte_pixmaps[scene]);
2801     windows->image.matte_pixmaps[scene]=(Pixmap) NULL;
2802   }
2803   XSetCursorState(display,windows,MagickFalse);
2804   windows->image.pixmaps=(Pixmap *)
2805     RelinquishMagickMemory(windows->image.pixmaps);
2806   windows->image.matte_pixmaps=(Pixmap *)
2807     RelinquishMagickMemory(windows->image.matte_pixmaps);
2808   if (nexus == (Image *) NULL)
2809     {
2810       /*
2811         Free X resources.
2812       */
2813       if (windows->image.mapped != MagickFalse)
2814         (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);      XDelay(display,SuspendTime);
2815       (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
2816       if (resource_info->map_type == (char *) NULL)
2817         (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
2818       DestroyXResources();
2819     }
2820   (void) XSync(display,MagickFalse);
2821   /*
2822     Restore our progress monitor and warning handlers.
2823   */
2824   (void) SetErrorHandler(warning_handler);
2825   (void) SetWarningHandler(warning_handler);
2826   /*
2827     Change to home directory.
2828   */
2829   cwd=getcwd(working_directory,MaxTextExtent);
2830   status=chdir(resource_info->home_directory);
2831   if (status == -1)
2832     (void) ThrowMagickException(&images->exception,GetMagickModule(),
2833       FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
2834   return(nexus);
2835 }
2836 \f
2837 /*
2838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839 %                                                                             %
2840 %                                                                             %
2841 %                                                                             %
2842 +   X S a v e I m a g e                                                       %
2843 %                                                                             %
2844 %                                                                             %
2845 %                                                                             %
2846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847 %
2848 %  XSaveImage() saves an image to a file.
2849 %
2850 %  The format of the XSaveImage method is:
2851 %
2852 %      MagickBooleanType XSaveImage(Display *display,
2853 %        XResourceInfo *resource_info,XWindows *windows,Image *image)
2854 %
2855 %  A description of each parameter follows:
2856 %
2857 %    o status: Method XSaveImage return True if the image is
2858 %      written.  False is returned is there is a memory shortage or if the
2859 %      image fails to write.
2860 %
2861 %    o display: Specifies a connection to an X server; returned from
2862 %      XOpenDisplay.
2863 %
2864 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2865 %
2866 %    o windows: Specifies a pointer to a XWindows structure.
2867 %
2868 %    o image: the image.
2869 %
2870 */
2871 static MagickBooleanType XSaveImage(Display *display,
2872   XResourceInfo *resource_info,XWindows *windows,Image *image)
2873 {
2874   char
2875     filename[MaxTextExtent];
2876
2877   ImageInfo
2878     *image_info;
2879
2880   MagickStatusType
2881     status;
2882
2883   /*
2884     Request file name from user.
2885   */
2886   if (resource_info->write_filename != (char *) NULL)
2887     (void) CopyMagickString(filename,resource_info->write_filename,
2888       MaxTextExtent);
2889   else
2890     {
2891       char
2892         path[MaxTextExtent];
2893
2894       int
2895         status;
2896
2897       GetPathComponent(image->filename,HeadPath,path);
2898       GetPathComponent(image->filename,TailPath,filename);
2899       status=chdir(path);
2900       if (status == -1)
2901         (void) ThrowMagickException(&image->exception,GetMagickModule(),
2902           FileOpenError,"UnableToOpenFile","%s",path);
2903     }
2904   XFileBrowserWidget(display,windows,"Save",filename);
2905   if (*filename == '\0')
2906     return(MagickTrue);
2907   if (IsPathAccessible(filename) != MagickFalse)
2908     {
2909       int
2910         status;
2911
2912       /*
2913         File exists-- seek user's permission before overwriting.
2914       */
2915       status=XConfirmWidget(display,windows,"Overwrite",filename);
2916       if (status == 0)
2917         return(MagickTrue);
2918     }
2919   image_info=CloneImageInfo(resource_info->image_info);
2920   (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
2921   (void) SetImageInfo(image_info,1,&image->exception);
2922   if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
2923       (LocaleCompare(image_info->magick,"JPG") == 0))
2924     {
2925       char
2926         quality[MaxTextExtent];
2927
2928       int
2929         status;
2930
2931       /*
2932         Request JPEG quality from user.
2933       */
2934       (void) FormatMagickString(quality,MaxTextExtent,"%.20g",(double)
2935         image_info->quality);
2936       status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
2937         quality);
2938       if (*quality == '\0')
2939         return(MagickTrue);
2940       image->quality=StringToUnsignedLong(quality);
2941       image_info->interlace=status != MagickFalse ?  NoInterlace :
2942         PlaneInterlace;
2943     }
2944   if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
2945       (LocaleCompare(image_info->magick,"PDF") == 0) ||
2946       (LocaleCompare(image_info->magick,"PS") == 0) ||
2947       (LocaleCompare(image_info->magick,"PS2") == 0))
2948     {
2949       char
2950         geometry[MaxTextExtent];
2951
2952       /*
2953         Request page geometry from user.
2954       */
2955       (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
2956       if (LocaleCompare(image_info->magick,"PDF") == 0)
2957         (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
2958       if (image_info->page != (char *) NULL)
2959         (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
2960       XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
2961         "Select page geometry:",geometry);
2962       if (*geometry != '\0')
2963         image_info->page=GetPageGeometry(geometry);
2964     }
2965   /*
2966     Write image.
2967   */
2968   image=GetFirstImageInList(image);
2969   status=WriteImages(image_info,image,filename,&image->exception);
2970   if (status != MagickFalse)
2971     image->taint=MagickFalse;
2972   image_info=DestroyImageInfo(image_info);
2973   XSetCursorState(display,windows,MagickFalse);
2974   return(status != 0 ? MagickTrue : MagickFalse);
2975 }
2976 #else
2977 \f
2978 /*
2979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2980 %                                                                             %
2981 %                                                                             %
2982 %                                                                             %
2983 +   A n i m a t e I m a g e s                                                 %
2984 %                                                                             %
2985 %                                                                             %
2986 %                                                                             %
2987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2988 %
2989 %  AnimateImages() repeatedly displays an image sequence to any X window
2990 %  screen.  It returns a value other than 0 if successful.  Check the
2991 %  exception member of image to determine the reason for any failure.
2992 %
2993 %  The format of the AnimateImages method is:
2994 %
2995 %      MagickBooleanType AnimateImages(const ImageInfo *image_info,
2996 %        Image *images)
2997 %
2998 %  A description of each parameter follows:
2999 %
3000 %    o image_info: the image info.
3001 %
3002 %    o image: the image.
3003 %
3004 */
3005 MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
3006   Image *image)
3007 {
3008   assert(image_info != (const ImageInfo *) NULL);
3009   assert(image_info->signature == MagickSignature);
3010   assert(image != (Image *) NULL);
3011   assert(image->signature == MagickSignature);
3012   if (image->debug != MagickFalse)
3013     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3014   (void) ThrowMagickException(&image->exception,GetMagickModule(),
3015     MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
3016     image->filename);
3017   return(MagickFalse);
3018 }
3019 #endif