root/ImageMagick/trunk/magick/animate.c

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