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