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