]> granicus.if.org Git - imagemagick/blob - magick/animate.c
(no commit message)
[imagemagick] / magick / animate.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                AAA   N   N  IIIII  M   M   AAA   TTTTT  EEEEE               %
7 %               A   A  NN  N    I    MM MM  A   A    T    E                   %
8 %               AAAAA  N N N    I    M M M  AAAAA    T    EEE                 %
9 %               A   A  N  NN    I    M   M  A   A    T    E                   %
10 %               A   A  N   N  IIIII  M   M  A   A    T    EEEEE               %
11 %                                                                             %
12 %                                                                             %
13 %              Methods to Interactively Animate an Image Sequence             %
14 %                                                                             %
15 %                             Software Design                                 %
16 %                               John Cristy                                   %
17 %                                July 1992                                    %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2011 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                     (unsigned long) magick_windows[i]->mask,
2284                     &magick_windows[i]->attributes);
2285                 }
2286                 if (windows->backdrop.id != (Window) NULL)
2287                   (void) XInstallColormap(display,map_info->colormap);
2288                 break;
2289               }
2290             if (*event.xclient.data.l == (long) windows->im_exit)
2291               {
2292                 state|=ExitState;
2293                 break;
2294               }
2295             break;
2296           }
2297         if (event.xclient.message_type == windows->dnd_protocols)
2298           {
2299             Atom
2300               selection,
2301               type;
2302
2303             int
2304               format,
2305               status;
2306
2307             unsigned char
2308               *data;
2309
2310             unsigned long
2311               after,
2312               length;
2313
2314             /*
2315               Display image named by the Drag-and-Drop selection.
2316             */
2317             if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
2318               break;
2319             selection=XInternAtom(display,"DndSelection",MagickFalse);
2320             status=XGetWindowProperty(display,root_window,selection,0L,2047L,
2321               MagickFalse,(Atom) AnyPropertyType,&type,&format,&length,&after,
2322               &data);
2323             if ((status != Success) || (length == 0))
2324               break;
2325             if (*event.xclient.data.l == 2)
2326               {
2327                 /*
2328                   Offix DND.
2329                 */
2330                 (void) CopyMagickString(resource_info->image_info->filename,
2331                   (char *) data,MaxTextExtent);
2332               }
2333             else
2334               {
2335                 /*
2336                   XDND.
2337                 */
2338                 if (LocaleNCompare((char *) data,"file:",5) != 0)
2339                   {
2340                     (void) XFree((void *) data);
2341                     break;
2342                   }
2343                 (void) CopyMagickString(resource_info->image_info->filename,
2344                   ((char *) data)+5,MaxTextExtent);
2345               }
2346             nexus=ReadImage(resource_info->image_info,&image->exception);
2347             CatchException(&image->exception);
2348             if (nexus != (Image *) NULL)
2349               state|=ExitState;
2350             (void) XFree((void *) data);
2351             break;
2352           }
2353         /*
2354           If client window delete message, exit.
2355         */
2356         if (event.xclient.message_type != windows->wm_protocols)
2357           break;
2358         if (*event.xclient.data.l == (long) windows->wm_take_focus)
2359           {
2360             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2361               (Time) event.xclient.data.l[1]);
2362             break;
2363           }
2364         if (*event.xclient.data.l != (long) windows->wm_delete_window)
2365           break;
2366         (void) XWithdrawWindow(display,event.xclient.window,
2367           visual_info->screen);
2368         if (event.xclient.window == windows->image.id)
2369           {
2370             state|=ExitState;
2371             break;
2372           }
2373         break;
2374       }
2375       case ConfigureNotify:
2376       {
2377         if (display_image->debug != MagickFalse)
2378           (void) LogMagickEvent(X11Event,GetMagickModule(),
2379             "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
2380             event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
2381             event.xconfigure.y,event.xconfigure.send_event);
2382         if (event.xconfigure.window == windows->image.id)
2383           {
2384             if (event.xconfigure.send_event != 0)
2385               {
2386                 XWindowChanges
2387                   window_changes;
2388
2389                 /*
2390                   Position the transient windows relative of the Image window.
2391                 */
2392                 if (windows->command.geometry == (char *) NULL)
2393                   if (windows->command.mapped == MagickFalse)
2394                     {
2395                        windows->command.x=
2396                           event.xconfigure.x-windows->command.width-25;
2397                         windows->command.y=event.xconfigure.y;
2398                         XConstrainWindowPosition(display,&windows->command);
2399                         window_changes.x=windows->command.x;
2400                         window_changes.y=windows->command.y;
2401                         (void) XReconfigureWMWindow(display,windows->command.id,
2402                           windows->command.screen,(unsigned int) (CWX | CWY),
2403                           &window_changes);
2404                     }
2405                 if (windows->widget.geometry == (char *) NULL)
2406                   if (windows->widget.mapped == MagickFalse)
2407                     {
2408                       windows->widget.x=
2409                         event.xconfigure.x+event.xconfigure.width/10;
2410                       windows->widget.y=
2411                         event.xconfigure.y+event.xconfigure.height/10;
2412                       XConstrainWindowPosition(display,&windows->widget);
2413                       window_changes.x=windows->widget.x;
2414                       window_changes.y=windows->widget.y;
2415                       (void) XReconfigureWMWindow(display,windows->widget.id,
2416                         windows->widget.screen,(unsigned int) (CWX | CWY),
2417                         &window_changes);
2418                     }
2419               }
2420             /*
2421               Image window has a new configuration.
2422             */
2423             windows->image.width=(unsigned int) event.xconfigure.width;
2424             windows->image.height=(unsigned int) event.xconfigure.height;
2425             break;
2426           }
2427         if (event.xconfigure.window == windows->icon.id)
2428           {
2429             /*
2430               Icon window has a new configuration.
2431             */
2432             windows->icon.width=(unsigned int) event.xconfigure.width;
2433             windows->icon.height=(unsigned int) event.xconfigure.height;
2434             break;
2435           }
2436         break;
2437       }
2438       case DestroyNotify:
2439       {
2440         /*
2441           Group leader has exited.
2442         */
2443         if (display_image->debug != MagickFalse)
2444           (void) LogMagickEvent(X11Event,GetMagickModule(),
2445             "Destroy Notify: 0x%lx",event.xdestroywindow.window);
2446         if (event.xdestroywindow.window == windows->group_leader.id)
2447           {
2448             state|=ExitState;
2449             break;
2450           }
2451         break;
2452       }
2453       case EnterNotify:
2454       {
2455         /*
2456           Selectively install colormap.
2457         */
2458         if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2459           if (event.xcrossing.mode != NotifyUngrab)
2460             XInstallColormap(display,map_info->colormap);
2461         break;
2462       }
2463       case Expose:
2464       {
2465         if (display_image->debug != MagickFalse)
2466           (void) LogMagickEvent(X11Event,GetMagickModule(),
2467             "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
2468             event.xexpose.width,event.xexpose.height,event.xexpose.x,
2469             event.xexpose.y);
2470         /*
2471           Repaint windows that are now exposed.
2472         */
2473         if (event.xexpose.window == windows->image.id)
2474           {
2475             windows->image.pixmap=windows->image.pixmaps[scene];
2476             windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
2477             XRefreshWindow(display,&windows->image,&event);
2478             break;
2479           }
2480         if (event.xexpose.window == windows->icon.id)
2481           if (event.xexpose.count == 0)
2482             {
2483               XRefreshWindow(display,&windows->icon,&event);
2484               break;
2485             }
2486         break;
2487       }
2488       case KeyPress:
2489       {
2490         static int
2491           length;
2492
2493         /*
2494           Respond to a user key press.
2495         */
2496         length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2497           sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2498         *(command+length)='\0';
2499         if (display_image->debug != MagickFalse)
2500           (void) LogMagickEvent(X11Event,GetMagickModule(),
2501             "Key press: 0x%lx (%c)",(unsigned long) key_symbol,*command);
2502         command_type=NullCommand;
2503         switch (key_symbol)
2504         {
2505           case XK_o:
2506           {
2507             if ((event.xkey.state & ControlMask) == MagickFalse)
2508               break;
2509             command_type=OpenCommand;
2510             break;
2511           }
2512           case XK_BackSpace:
2513           {
2514             command_type=StepBackwardCommand;
2515             break;
2516           }
2517           case XK_space:
2518           {
2519             command_type=StepForwardCommand;
2520             break;
2521           }
2522           case XK_less:
2523           {
2524             command_type=FasterCommand;
2525             break;
2526           }
2527           case XK_greater:
2528           {
2529             command_type=SlowerCommand;
2530             break;
2531           }
2532           case XK_F1:
2533           {
2534             command_type=HelpCommand;
2535             break;
2536           }
2537           case XK_Find:
2538           {
2539             command_type=BrowseDocumentationCommand;
2540             break;
2541           }
2542           case XK_question:
2543           {
2544             command_type=InfoCommand;
2545             break;
2546           }
2547           case XK_q:
2548           case XK_Escape:
2549           {
2550             command_type=QuitCommand;
2551             break;
2552           }
2553           default:
2554             break;
2555         }
2556         if (command_type != NullCommand)
2557           nexus=XMagickCommand(display,resource_info,windows,
2558             command_type,&image,&state);
2559         break;
2560       }
2561       case KeyRelease:
2562       {
2563         /*
2564           Respond to a user key release.
2565         */
2566         (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2567           sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2568         if (display_image->debug != MagickFalse)
2569           (void) LogMagickEvent(X11Event,GetMagickModule(),
2570             "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
2571         break;
2572       }
2573       case LeaveNotify:
2574       {
2575         /*
2576           Selectively uninstall colormap.
2577         */
2578         if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2579           if (event.xcrossing.mode != NotifyUngrab)
2580             XUninstallColormap(display,map_info->colormap);
2581         break;
2582       }
2583       case MapNotify:
2584       {
2585         if (display_image->debug != MagickFalse)
2586           (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
2587             event.xmap.window);
2588         if (event.xmap.window == windows->backdrop.id)
2589           {
2590             (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
2591               CurrentTime);
2592             windows->backdrop.mapped=MagickTrue;
2593             break;
2594           }
2595         if (event.xmap.window == windows->image.id)
2596           {
2597             if (windows->backdrop.id != (Window) NULL)
2598               (void) XInstallColormap(display,map_info->colormap);
2599             if (LocaleCompare(image_list[0]->magick,"LOGO") == 0)
2600               {
2601                 if (LocaleCompare(display_image->filename,"LOGO") == 0)
2602                   nexus=XMagickCommand(display,resource_info,windows,
2603                     OpenCommand,&image,&state);
2604                 else
2605                   state|=ExitState;
2606               }
2607             windows->image.mapped=MagickTrue;
2608             break;
2609           }
2610         if (event.xmap.window == windows->info.id)
2611           {
2612             windows->info.mapped=MagickTrue;
2613             break;
2614           }
2615         if (event.xmap.window == windows->icon.id)
2616           {
2617             /*
2618               Create an icon image.
2619             */
2620             XMakeStandardColormap(display,icon_visual,icon_resources,
2621               display_image,icon_map,icon_pixel);
2622             (void) XMakeImage(display,icon_resources,&windows->icon,
2623               display_image,windows->icon.width,windows->icon.height);
2624             (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
2625               windows->icon.pixmap);
2626             (void) XClearWindow(display,windows->icon.id);
2627             (void) XWithdrawWindow(display,windows->info.id,
2628               windows->info.screen);
2629             windows->icon.mapped=MagickTrue;
2630             break;
2631           }
2632         if (event.xmap.window == windows->command.id)
2633           {
2634             windows->command.mapped=MagickTrue;
2635             break;
2636           }
2637         if (event.xmap.window == windows->popup.id)
2638           {
2639             windows->popup.mapped=MagickTrue;
2640             break;
2641           }
2642         if (event.xmap.window == windows->widget.id)
2643           {
2644             windows->widget.mapped=MagickTrue;
2645             break;
2646           }
2647         break;
2648       }
2649       case MappingNotify:
2650       {
2651         (void) XRefreshKeyboardMapping(&event.xmapping);
2652         break;
2653       }
2654       case NoExpose:
2655         break;
2656       case PropertyNotify:
2657       {
2658         Atom
2659           type;
2660
2661         int
2662           format,
2663           status;
2664
2665         unsigned char
2666           *data;
2667
2668         unsigned long
2669           after,
2670           length;
2671
2672         if (display_image->debug != MagickFalse)
2673           (void) LogMagickEvent(X11Event,GetMagickModule(),
2674             "Property Notify: 0x%lx 0x%lx %d",(unsigned long)
2675             event.xproperty.window,(unsigned long) event.xproperty.atom,
2676             event.xproperty.state);
2677         if (event.xproperty.atom != windows->im_remote_command)
2678           break;
2679         /*
2680           Display image named by the remote command protocol.
2681         */
2682         status=XGetWindowProperty(display,event.xproperty.window,
2683           event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
2684           AnyPropertyType,&type,&format,&length,&after,&data);
2685         if ((status != Success) || (length == 0))
2686           break;
2687         (void) CopyMagickString(resource_info->image_info->filename,
2688           (char *) data,MaxTextExtent);
2689         nexus=ReadImage(resource_info->image_info,&image->exception);
2690         CatchException(&image->exception);
2691         if (nexus != (Image *) NULL)
2692           state|=ExitState;
2693         (void) XFree((void *) data);
2694         break;
2695       }
2696       case ReparentNotify:
2697       {
2698         if (display_image->debug != MagickFalse)
2699           (void) LogMagickEvent(X11Event,GetMagickModule(),
2700             "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
2701             event.xreparent.window);
2702         break;
2703       }
2704       case UnmapNotify:
2705       {
2706         if (display_image->debug != MagickFalse)
2707           (void) LogMagickEvent(X11Event,GetMagickModule(),
2708             "Unmap Notify: 0x%lx",event.xunmap.window);
2709         if (event.xunmap.window == windows->backdrop.id)
2710           {
2711             windows->backdrop.mapped=MagickFalse;
2712             break;
2713           }
2714         if (event.xunmap.window == windows->image.id)
2715           {
2716             windows->image.mapped=MagickFalse;
2717             break;
2718           }
2719         if (event.xunmap.window == windows->info.id)
2720           {
2721             windows->info.mapped=MagickFalse;
2722             break;
2723           }
2724         if (event.xunmap.window == windows->icon.id)
2725           {
2726             if (map_info->colormap == icon_map->colormap)
2727               XConfigureImageColormap(display,resource_info,windows,
2728                 display_image);
2729             (void) XFreeStandardColormap(display,icon_visual,icon_map,
2730               icon_pixel);
2731             windows->icon.mapped=MagickFalse;
2732             break;
2733           }
2734         if (event.xunmap.window == windows->command.id)
2735           {
2736             windows->command.mapped=MagickFalse;
2737             break;
2738           }
2739         if (event.xunmap.window == windows->popup.id)
2740           {
2741             if (windows->backdrop.id != (Window) NULL)
2742               (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2743                 CurrentTime);
2744             windows->popup.mapped=MagickFalse;
2745             break;
2746           }
2747         if (event.xunmap.window == windows->widget.id)
2748           {
2749             if (windows->backdrop.id != (Window) NULL)
2750               (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2751                 CurrentTime);
2752             windows->widget.mapped=MagickFalse;
2753             break;
2754           }
2755         break;
2756       }
2757       default:
2758       {
2759         if (display_image->debug != MagickFalse)
2760           (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
2761             event.type);
2762         break;
2763       }
2764     }
2765   }
2766   while (!(state & ExitState));
2767   image_list=(Image **) RelinquishMagickMemory(image_list);
2768   images=DestroyImageList(images);
2769   if ((windows->visual_info->klass == GrayScale) ||
2770       (windows->visual_info->klass == PseudoColor) ||
2771       (windows->visual_info->klass == DirectColor))
2772     {
2773       /*
2774         Withdraw windows.
2775       */
2776       if (windows->info.mapped)
2777         (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2778       if (windows->command.mapped)
2779         (void) XWithdrawWindow(display,windows->command.id,
2780           windows->command.screen);
2781     }
2782   if (resource_info->backdrop == MagickFalse)
2783     if (windows->backdrop.mapped)
2784       {
2785         (void) XWithdrawWindow(display,windows->backdrop.id,\
2786           windows->backdrop.screen);
2787         (void) XDestroyWindow(display,windows->backdrop.id);
2788         windows->backdrop.id=(Window) NULL;
2789         (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);
2790         (void) XDestroyWindow(display,windows->image.id);
2791         windows->image.id=(Window) NULL;
2792       }
2793   XSetCursorState(display,windows,MagickTrue);
2794   XCheckRefreshWindows(display,windows);
2795   for (scene=1; scene < (ssize_t) number_scenes; scene++)
2796   {
2797     if (windows->image.pixmaps[scene] != (Pixmap) NULL)
2798       (void) XFreePixmap(display,windows->image.pixmaps[scene]);
2799     windows->image.pixmaps[scene]=(Pixmap) NULL;
2800     if (windows->image.matte_pixmaps[scene] != (Pixmap) NULL)
2801       (void) XFreePixmap(display,windows->image.matte_pixmaps[scene]);
2802     windows->image.matte_pixmaps[scene]=(Pixmap) NULL;
2803   }
2804   XSetCursorState(display,windows,MagickFalse);
2805   windows->image.pixmaps=(Pixmap *)
2806     RelinquishMagickMemory(windows->image.pixmaps);
2807   windows->image.matte_pixmaps=(Pixmap *)
2808     RelinquishMagickMemory(windows->image.matte_pixmaps);
2809   if (nexus == (Image *) NULL)
2810     {
2811       /*
2812         Free X resources.
2813       */
2814       if (windows->image.mapped != MagickFalse)
2815         (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);      XDelay(display,SuspendTime);
2816       (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
2817       if (resource_info->map_type == (char *) NULL)
2818         (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
2819       DestroyXResources();
2820     }
2821   (void) XSync(display,MagickFalse);
2822   /*
2823     Restore our progress monitor and warning handlers.
2824   */
2825   (void) SetErrorHandler(warning_handler);
2826   (void) SetWarningHandler(warning_handler);
2827   /*
2828     Change to home directory.
2829   */
2830   cwd=getcwd(working_directory,MaxTextExtent);
2831   status=chdir(resource_info->home_directory);
2832   if (status == -1)
2833     (void) ThrowMagickException(&images->exception,GetMagickModule(),
2834       FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
2835   return(nexus);
2836 }
2837 \f
2838 /*
2839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2840 %                                                                             %
2841 %                                                                             %
2842 %                                                                             %
2843 +   X S a v e I m a g e                                                       %
2844 %                                                                             %
2845 %                                                                             %
2846 %                                                                             %
2847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2848 %
2849 %  XSaveImage() saves an image to a file.
2850 %
2851 %  The format of the XSaveImage method is:
2852 %
2853 %      MagickBooleanType XSaveImage(Display *display,
2854 %        XResourceInfo *resource_info,XWindows *windows,Image *image)
2855 %
2856 %  A description of each parameter follows:
2857 %
2858 %    o status: Method XSaveImage return True if the image is
2859 %      written.  False is returned is there is a memory shortage or if the
2860 %      image fails to write.
2861 %
2862 %    o display: Specifies a connection to an X server; returned from
2863 %      XOpenDisplay.
2864 %
2865 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2866 %
2867 %    o windows: Specifies a pointer to a XWindows structure.
2868 %
2869 %    o image: the image.
2870 %
2871 */
2872 static MagickBooleanType XSaveImage(Display *display,
2873   XResourceInfo *resource_info,XWindows *windows,Image *image)
2874 {
2875   char
2876     filename[MaxTextExtent];
2877
2878   ImageInfo
2879     *image_info;
2880
2881   MagickStatusType
2882     status;
2883
2884   /*
2885     Request file name from user.
2886   */
2887   if (resource_info->write_filename != (char *) NULL)
2888     (void) CopyMagickString(filename,resource_info->write_filename,
2889       MaxTextExtent);
2890   else
2891     {
2892       char
2893         path[MaxTextExtent];
2894
2895       int
2896         status;
2897
2898       GetPathComponent(image->filename,HeadPath,path);
2899       GetPathComponent(image->filename,TailPath,filename);
2900       status=chdir(path);
2901       if (status == -1)
2902         (void) ThrowMagickException(&image->exception,GetMagickModule(),
2903           FileOpenError,"UnableToOpenFile","%s",path);
2904     }
2905   XFileBrowserWidget(display,windows,"Save",filename);
2906   if (*filename == '\0')
2907     return(MagickTrue);
2908   if (IsPathAccessible(filename) != MagickFalse)
2909     {
2910       int
2911         status;
2912
2913       /*
2914         File exists-- seek user's permission before overwriting.
2915       */
2916       status=XConfirmWidget(display,windows,"Overwrite",filename);
2917       if (status == 0)
2918         return(MagickTrue);
2919     }
2920   image_info=CloneImageInfo(resource_info->image_info);
2921   (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
2922   (void) SetImageInfo(image_info,1,&image->exception);
2923   if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
2924       (LocaleCompare(image_info->magick,"JPG") == 0))
2925     {
2926       char
2927         quality[MaxTextExtent];
2928
2929       int
2930         status;
2931
2932       /*
2933         Request JPEG quality from user.
2934       */
2935       (void) FormatMagickString(quality,MaxTextExtent,"%.20g",(double)
2936         image_info->quality);
2937       status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
2938         quality);
2939       if (*quality == '\0')
2940         return(MagickTrue);
2941       image->quality=StringToUnsignedLong(quality);
2942       image_info->interlace=status != MagickFalse ?  NoInterlace :
2943         PlaneInterlace;
2944     }
2945   if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
2946       (LocaleCompare(image_info->magick,"PDF") == 0) ||
2947       (LocaleCompare(image_info->magick,"PS") == 0) ||
2948       (LocaleCompare(image_info->magick,"PS2") == 0))
2949     {
2950       char
2951         geometry[MaxTextExtent];
2952
2953       /*
2954         Request page geometry from user.
2955       */
2956       (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
2957       if (LocaleCompare(image_info->magick,"PDF") == 0)
2958         (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
2959       if (image_info->page != (char *) NULL)
2960         (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
2961       XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
2962         "Select page geometry:",geometry);
2963       if (*geometry != '\0')
2964         image_info->page=GetPageGeometry(geometry);
2965     }
2966   /*
2967     Write image.
2968   */
2969   image=GetFirstImageInList(image);
2970   status=WriteImages(image_info,image,filename,&image->exception);
2971   if (status != MagickFalse)
2972     image->taint=MagickFalse;
2973   image_info=DestroyImageInfo(image_info);
2974   XSetCursorState(display,windows,MagickFalse);
2975   return(status != 0 ? MagickTrue : MagickFalse);
2976 }
2977 #else
2978 \f
2979 /*
2980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2981 %                                                                             %
2982 %                                                                             %
2983 %                                                                             %
2984 +   A n i m a t e I m a g e s                                                 %
2985 %                                                                             %
2986 %                                                                             %
2987 %                                                                             %
2988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2989 %
2990 %  AnimateImages() repeatedly displays an image sequence to any X window
2991 %  screen.  It returns a value other than 0 if successful.  Check the
2992 %  exception member of image to determine the reason for any failure.
2993 %
2994 %  The format of the AnimateImages method is:
2995 %
2996 %      MagickBooleanType AnimateImages(const ImageInfo *image_info,
2997 %        Image *images)
2998 %
2999 %  A description of each parameter follows:
3000 %
3001 %    o image_info: the image info.
3002 %
3003 %    o image: the image.
3004 %
3005 */
3006 MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
3007   Image *image)
3008 {
3009   assert(image_info != (const ImageInfo *) NULL);
3010   assert(image_info->signature == MagickSignature);
3011   assert(image != (Image *) NULL);
3012   assert(image->signature == MagickSignature);
3013   if (image->debug != MagickFalse)
3014     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3015   (void) ThrowMagickException(&image->exception,GetMagickModule(),
3016     MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
3017     image->filename);
3018   return(MagickFalse);
3019 }
3020 #endif