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