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