MagickCore  6.7.5
animate.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                AAA   N   N  IIIII  M   M   AAA   TTTTT  EEEEE               %
00007 %               A   A  NN  N    I    MM MM  A   A    T    E                   %
00008 %               AAAAA  N N N    I    M M M  AAAAA    T    EEE                 %
00009 %               A   A  N  NN    I    M   M  A   A    T    E                   %
00010 %               A   A  N   N  IIIII  M   M  A   A    T    EEEEE               %
00011 %                                                                             %
00012 %                                                                             %
00013 %              Methods to Interactively Animate an Image Sequence             %
00014 %                                                                             %
00015 %                             Software Design                                 %
00016 %                               John Cristy                                   %
00017 %                                July 1992                                    %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "MagickCore/studio.h"
00043 #include "MagickCore/animate.h"
00044 #include "MagickCore/animate-private.h"
00045 #include "MagickCore/client.h"
00046 #include "MagickCore/color.h"
00047 #include "MagickCore/color-private.h"
00048 #include "MagickCore/colorspace.h"
00049 #include "MagickCore/constitute.h"
00050 #include "MagickCore/delegate.h"
00051 #include "MagickCore/exception.h"
00052 #include "MagickCore/exception-private.h"
00053 #include "MagickCore/geometry.h"
00054 #include "MagickCore/image-private.h"
00055 #include "MagickCore/layer.h"
00056 #include "MagickCore/list.h"
00057 #include "MagickCore/log.h"
00058 #include "MagickCore/image.h"
00059 #include "MagickCore/memory_.h"
00060 #include "MagickCore/monitor.h"
00061 #include "MagickCore/monitor-private.h"
00062 #include "MagickCore/option.h"
00063 #include "MagickCore/pixel-accessor.h"
00064 #include "MagickCore/property.h"
00065 #include "MagickCore/resource_.h"
00066 #include "MagickCore/string_.h"
00067 #include "MagickCore/string-private.h"
00068 #include "MagickCore/transform.h"
00069 #include "MagickCore/utility.h"
00070 #include "MagickCore/utility-private.h"
00071 #include "MagickCore/version.h"
00072 #include "MagickCore/widget.h"
00073 #include "MagickCore/widget-private.h"
00074 #include "MagickCore/xwindow.h"
00075 #include "MagickCore/xwindow-private.h"
00076 
00077 #if defined(MAGICKCORE_X11_DELEGATE)
00078 /*
00079   Animate state declarations.
00080 */
00081 #define AutoReverseAnimationState 0x0004
00082 #define ForwardAnimationState 0x0008
00083 #define HighlightState  0x0010
00084 #define PlayAnimationState 0x0020
00085 #define RepeatAnimationState 0x0040
00086 #define StepAnimationState 0x0080
00087 
00088 /*
00089   Static declarations.
00090 */
00091 static const char
00092   *AnimateHelp[]=
00093   {
00094     "BUTTONS",
00095     "",
00096     "  Press any button to map or unmap the Command widget.",
00097     "",
00098     "COMMAND WIDGET",
00099     "  The Command widget lists a number of sub-menus and commands.",
00100     "  They are",
00101     "",
00102     "    Animate",
00103     "      Open...",
00104     "      Save...",
00105     "      Play",
00106     "      Step",
00107     "      Repeat",
00108     "      Auto Reverse",
00109     "    Speed",
00110     "      Slower",
00111     "      Faster",
00112     "    Direction",
00113     "      Forward",
00114     "      Reverse",
00115     "      Help",
00116     "        Overview",
00117     "        Browse Documentation",
00118     "        About Animate",
00119     "    Image Info",
00120     "    Quit",
00121     "",
00122     "  Menu items with a indented triangle have a sub-menu.  They",
00123     "  are represented above as the indented items.  To access a",
00124     "  sub-menu item, move the pointer to the appropriate menu and",
00125     "  press a button and drag.  When you find the desired sub-menu",
00126     "  item, release the button and the command is executed.  Move",
00127     "  the pointer away from the sub-menu if you decide not to",
00128     "  execute a particular command.",
00129     "",
00130     "KEYBOARD ACCELERATORS",
00131     "  Accelerators are one or two key presses that effect a",
00132     "  particular command.  The keyboard accelerators that",
00133     "  animate(1) understands is:",
00134     "",
00135     "  Ctl+O  Press to open an image from a file.",
00136     "",
00137     "  space  Press to display the next image in the sequence.",
00138     "",
00139     "  <      Press to speed-up the display of the images.  Refer to",
00140     "         -delay for more information.",
00141     "",
00142     "  >      Press to slow the display of the images.  Refer to",
00143     "         -delay for more information.",
00144     "",
00145     "  F1     Press to display helpful information about animate(1).",
00146     "",
00147     "  Find   Press to browse documentation about ImageMagick.",
00148     "",
00149     "  ?      Press to display information about the image.  Press",
00150     "         any key or button to erase the information.",
00151     "",
00152     "         This information is printed: image name;  image size;",
00153     "         and the total number of unique colors in the image.",
00154     "",
00155     "  Ctl-q  Press to discard all images and exit program.",
00156     (char *) NULL
00157   };
00158 
00159 /*
00160   Constant declarations.
00161 */
00162 static const char
00163   *PageSizes[]=
00164   {
00165     "Letter",
00166     "Tabloid",
00167     "Ledger",
00168     "Legal",
00169     "Statement",
00170     "Executive",
00171     "A3",
00172     "A4",
00173     "A5",
00174     "B4",
00175     "B5",
00176     "Folio",
00177     "Quarto",
00178     "10x14",
00179     (char *) NULL
00180   };
00181 
00182 static const unsigned char
00183   HighlightBitmap[8] =
00184   {
00185     (unsigned char) 0xaa,
00186     (unsigned char) 0x55,
00187     (unsigned char) 0xaa,
00188     (unsigned char) 0x55,
00189     (unsigned char) 0xaa,
00190     (unsigned char) 0x55,
00191     (unsigned char) 0xaa,
00192     (unsigned char) 0x55
00193   },
00194   ShadowBitmap[8] =
00195   {
00196     (unsigned char) 0x00,
00197     (unsigned char) 0x00,
00198     (unsigned char) 0x00,
00199     (unsigned char) 0x00,
00200     (unsigned char) 0x00,
00201     (unsigned char) 0x00,
00202     (unsigned char) 0x00,
00203     (unsigned char) 0x00
00204   };
00205 
00206 /*
00207   Enumeration declarations.
00208 */
00209 typedef enum
00210 {
00211   OpenCommand,
00212   SaveCommand,
00213   PlayCommand,
00214   StepCommand,
00215   RepeatCommand,
00216   AutoReverseCommand,
00217   SlowerCommand,
00218   FasterCommand,
00219   ForwardCommand,
00220   ReverseCommand,
00221   HelpCommand,
00222   BrowseDocumentationCommand,
00223   VersionCommand,
00224   InfoCommand,
00225   QuitCommand,
00226   StepBackwardCommand,
00227   StepForwardCommand,
00228   NullCommand
00229 } CommandType;
00230 
00231 /*
00232   Stipples.
00233 */
00234 #define HighlightWidth  8
00235 #define HighlightHeight  8
00236 #define ShadowWidth  8
00237 #define ShadowHeight  8
00238 
00239 /*
00240   Forward declarations.
00241 */
00242 static Image
00243   *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
00244     Image **,MagickStatusType *,ExceptionInfo *);
00245 
00246 static MagickBooleanType
00247   XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *);
00248 
00249 /*
00250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00251 %                                                                             %
00252 %                                                                             %
00253 %                                                                             %
00254 %   A n i m a t e I m a g e s                                                 %
00255 %                                                                             %
00256 %                                                                             %
00257 %                                                                             %
00258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00259 %
00260 %  AnimateImages() repeatedly displays an image sequence to any X window
00261 %  screen.  It returns a value other than 0 if successful.  Check the
00262 %  exception member of image to determine the reason for any failure.
00263 %
00264 %  The format of the AnimateImages method is:
00265 %
00266 %      MagickBooleanType AnimateImages(const ImageInfo *image_info,
00267 %        Image *images,ExceptionInfo *exception)
00268 %
00269 %  A description of each parameter follows:
00270 %
00271 %    o image_info: the image info.
00272 %
00273 %    o image: the image.
00274 %
00275 %    o exception: return any errors or warnings in this structure.
00276 %
00277 */
00278 MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
00279   Image *images,ExceptionInfo *exception)
00280 {
00281   char
00282     *argv[1];
00283 
00284   Display
00285     *display;
00286 
00287   MagickStatusType
00288     status;
00289 
00290   XrmDatabase
00291     resource_database;
00292 
00293   XResourceInfo
00294     resource_info;
00295 
00296   assert(image_info != (const ImageInfo *) NULL);
00297   assert(image_info->signature == MagickSignature);
00298   assert(images != (Image *) NULL);
00299   assert(images->signature == MagickSignature);
00300   if (images->debug != MagickFalse)
00301     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
00302   display=XOpenDisplay(image_info->server_name);
00303   if (display == (Display *) NULL)
00304     {
00305       (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
00306         "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
00307       return(MagickFalse);
00308     }
00309   if (exception->severity != UndefinedException)
00310     CatchException(exception);
00311   (void) XSetErrorHandler(XError);
00312   resource_database=XGetResourceDatabase(display,GetClientName());
00313   (void) ResetMagickMemory(&resource_info,0,sizeof(XResourceInfo));
00314   XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
00315   if (image_info->page != (char *) NULL)
00316     resource_info.image_geometry=AcquireString(image_info->page);
00317   resource_info.immutable=MagickTrue;
00318   argv[0]=AcquireString(GetClientName());
00319   (void) XAnimateImages(display,&resource_info,argv,1,images,exception);
00320   SetErrorHandler((ErrorHandler) NULL);
00321   SetWarningHandler((WarningHandler) NULL);
00322   SetErrorHandler((ErrorHandler) NULL);
00323   SetWarningHandler((WarningHandler) NULL);
00324   argv[0]=DestroyString(argv[0]);
00325   (void) XCloseDisplay(display);
00326   XDestroyResourceInfo(&resource_info);
00327   status=exception->severity == UndefinedException ? MagickTrue : MagickFalse;
00328   return(status != 0 ? MagickTrue : MagickFalse);
00329 }
00330 
00331 /*
00332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00333 %                                                                             %
00334 %                                                                             %
00335 %                                                                             %
00336 +   X M a g i c k C o m m a n d                                               %
00337 %                                                                             %
00338 %                                                                             %
00339 %                                                                             %
00340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00341 %
00342 %  XMagickCommand() makes a transform to the image or Image window as specified
00343 %  by a user menu button or keyboard command.
00344 %
00345 %  The format of the XMagickCommand method is:
00346 %
00347 %      Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
00348 %        XWindows *windows,const CommandType command_type,Image **image,
00349 %        MagickStatusType *state,ExceptionInfo *exception)
00350 %
00351 %  A description of each parameter follows:
00352 %
00353 %    o display: Specifies a connection to an X server; returned from
00354 %      XOpenDisplay.
00355 %
00356 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
00357 %
00358 %    o windows: Specifies a pointer to a XWindows structure.
00359 %
00360 %    o image: the image;  XMagickCommand
00361 %      may transform the image and return a new image pointer.
00362 %
00363 %    o state: Specifies a MagickStatusType;  XMagickCommand may return a
00364 %      modified state.
00365 %
00366 %    o exception: return any errors or warnings in this structure.
00367 %
00368 %
00369 */
00370 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
00371   XWindows *windows,const CommandType command_type,Image **image,
00372   MagickStatusType *state,ExceptionInfo *exception)
00373 {
00374   Image
00375     *nexus;
00376 
00377   MagickBooleanType
00378     proceed;
00379 
00380   MagickStatusType
00381     status;
00382 
00383   XTextProperty
00384     window_name;
00385 
00386   /*
00387     Process user command.
00388   */
00389   nexus=NewImageList();
00390   switch (command_type)
00391   {
00392     case OpenCommand:
00393     {
00394       char
00395         **filelist;
00396 
00397       Image
00398         *images,
00399         *next;
00400 
00401       ImageInfo
00402         *read_info;
00403 
00404       int
00405         number_files;
00406 
00407       register int
00408         i;
00409 
00410       static char
00411         filenames[MaxTextExtent] = "*";
00412 
00413       if (resource_info->immutable != MagickFalse)
00414         break;
00415       /*
00416         Request file name from user.
00417       */
00418       XFileBrowserWidget(display,windows,"Animate",filenames);
00419       if (*filenames == '\0')
00420         return((Image *) NULL);
00421       /*
00422         Expand the filenames.
00423       */
00424       filelist=(char **) AcquireMagickMemory(sizeof(char *));
00425       if (filelist == (char **) NULL)
00426         {
00427           ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
00428             filenames);
00429           return((Image *) NULL);
00430         }
00431       number_files=1;
00432       filelist[0]=filenames;
00433       status=ExpandFilenames(&number_files,&filelist);
00434       if ((status == MagickFalse) || (number_files == 0))
00435         {
00436           if (number_files == 0)
00437             {
00438               ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
00439              return((Image *) NULL);
00440             }
00441           ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
00442             filenames);
00443           return((Image *) NULL);
00444         }
00445       read_info=CloneImageInfo(resource_info->image_info);
00446       images=NewImageList();
00447       XSetCursorState(display,windows,MagickTrue);
00448       XCheckRefreshWindows(display,windows);
00449       for (i=0; i < number_files; i++)
00450       {
00451         (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
00452         filelist[i]=DestroyString(filelist[i]);
00453         *read_info->magick='\0';
00454         next=ReadImage(read_info,exception);
00455         CatchException(exception);
00456         if (next != (Image *) NULL)
00457           AppendImageToList(&images,next);
00458         if (number_files <= 5)
00459           continue;
00460         proceed=SetImageProgress(images,LoadImageTag,i,(MagickSizeType)
00461           number_files);
00462         if (proceed == MagickFalse)
00463           break;
00464       }
00465       filelist=(char **) RelinquishMagickMemory(filelist);
00466       read_info=DestroyImageInfo(read_info);
00467       if (images == (Image *) NULL)
00468         {
00469           XSetCursorState(display,windows,MagickFalse);
00470           ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
00471           return((Image *) NULL);
00472         }
00473       nexus=GetFirstImageInList(images);
00474       *state|=ExitState;
00475       break;
00476     }
00477     case PlayCommand:
00478     {
00479       char
00480         basename[MaxTextExtent];
00481 
00482       int
00483         status;
00484 
00485       /*
00486         Window name is the base of the filename.
00487       */
00488       *state|=PlayAnimationState;
00489       *state&=(~AutoReverseAnimationState);
00490       GetPathComponent((*image)->magick_filename,BasePath,basename);
00491       (void) FormatLocaleString(windows->image.name,MaxTextExtent,
00492         "%s: %s",MagickPackageName,basename);
00493       if (resource_info->title != (char *) NULL)
00494         {
00495           char
00496             *title;
00497 
00498           title=InterpretImageProperties(resource_info->image_info,*image,
00499             resource_info->title,exception);
00500           (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
00501           title=DestroyString(title);
00502         }
00503       status=XStringListToTextProperty(&windows->image.name,1,&window_name);
00504       if (status == 0)
00505         break;
00506       XSetWMName(display,windows->image.id,&window_name);
00507       (void) XFree((void *) window_name.value);
00508       break;
00509     }
00510     case StepCommand:
00511     case StepBackwardCommand:
00512     case StepForwardCommand:
00513     {
00514       *state|=StepAnimationState;
00515       *state&=(~PlayAnimationState);
00516       if (command_type == StepBackwardCommand)
00517         *state&=(~ForwardAnimationState);
00518       if (command_type == StepForwardCommand)
00519         *state|=ForwardAnimationState;
00520       if (resource_info->title != (char *) NULL)
00521         break;
00522       break;
00523     }
00524     case RepeatCommand:
00525     {
00526       *state|=RepeatAnimationState;
00527       *state&=(~AutoReverseAnimationState);
00528       *state|=PlayAnimationState;
00529       break;
00530     }
00531     case AutoReverseCommand:
00532     {
00533       *state|=AutoReverseAnimationState;
00534       *state&=(~RepeatAnimationState);
00535       *state|=PlayAnimationState;
00536       break;
00537     }
00538     case SaveCommand:
00539     {
00540       /*
00541         Save image.
00542       */
00543       status=XSaveImage(display,resource_info,windows,*image,exception);
00544       if (status == MagickFalse)
00545         {
00546           char
00547             message[MaxTextExtent];
00548 
00549           (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
00550             exception->reason != (char *) NULL ? exception->reason : "",
00551             exception->description != (char *) NULL ? exception->description :
00552             "");
00553           XNoticeWidget(display,windows,"Unable to save file:",message);
00554           break;
00555         }
00556       break;
00557     }
00558     case SlowerCommand:
00559     {
00560       resource_info->delay++;
00561       break;
00562     }
00563     case FasterCommand:
00564     {
00565       if (resource_info->delay == 0)
00566         break;
00567       resource_info->delay--;
00568       break;
00569     }
00570     case ForwardCommand:
00571     {
00572       *state=ForwardAnimationState;
00573       *state&=(~AutoReverseAnimationState);
00574       break;
00575     }
00576     case ReverseCommand:
00577     {
00578       *state&=(~ForwardAnimationState);
00579       *state&=(~AutoReverseAnimationState);
00580       break;
00581     }
00582     case InfoCommand:
00583     {
00584       XDisplayImageInfo(display,resource_info,windows,(Image *) NULL,*image,
00585         exception);
00586       break;
00587     }
00588     case HelpCommand:
00589     {
00590       /*
00591         User requested help.
00592       */
00593       XTextViewWidget(display,resource_info,windows,MagickFalse,
00594         "Help Viewer - Animate",AnimateHelp);
00595       break;
00596     }
00597     case BrowseDocumentationCommand:
00598     {
00599       Atom
00600         mozilla_atom;
00601 
00602       Window
00603         mozilla_window,
00604         root_window;
00605 
00606       /*
00607         Browse the ImageMagick documentation.
00608       */
00609       root_window=XRootWindow(display,XDefaultScreen(display));
00610       mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
00611       mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
00612       if (mozilla_window != (Window) NULL)
00613         {
00614           char
00615             command[MaxTextExtent],
00616             *url;
00617 
00618           /*
00619             Display documentation using Netscape remote control.
00620           */
00621           url=GetMagickHomeURL();
00622           (void) FormatLocaleString(command,MaxTextExtent,
00623             "openurl(%s,new-tab)",url);
00624           url=DestroyString(url);
00625           mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
00626           (void) XChangeProperty(display,mozilla_window,mozilla_atom,
00627             XA_STRING,8,PropModeReplace,(unsigned char *) command,
00628             (int) strlen(command));
00629           XSetCursorState(display,windows,MagickFalse);
00630           break;
00631         }
00632       XSetCursorState(display,windows,MagickTrue);
00633       XCheckRefreshWindows(display,windows);
00634       status=InvokeDelegate(resource_info->image_info,*image,"browse",
00635         (char *) NULL,exception);
00636       if (status == MagickFalse)
00637         XNoticeWidget(display,windows,"Unable to browse documentation",
00638           (char *) NULL);
00639       XDelay(display,1500);
00640       XSetCursorState(display,windows,MagickFalse);
00641       break;
00642     }
00643     case VersionCommand:
00644     {
00645       XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
00646         GetMagickCopyright());
00647       break;
00648     }
00649     case QuitCommand:
00650     {
00651       /*
00652         exit program
00653       */
00654       if (resource_info->confirm_exit == MagickFalse)
00655         XClientMessage(display,windows->image.id,windows->im_protocols,
00656           windows->im_exit,CurrentTime);
00657       else
00658         {
00659           int
00660             status;
00661 
00662           /*
00663             Confirm program exit.
00664           */
00665           status=XConfirmWidget(display,windows,"Do you really want to exit",
00666             resource_info->client_name);
00667           if (status != 0)
00668             XClientMessage(display,windows->image.id,windows->im_protocols,
00669               windows->im_exit,CurrentTime);
00670         }
00671       break;
00672     }
00673     default:
00674       break;
00675   }
00676   return(nexus);
00677 }
00678 
00679 /*
00680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00681 %                                                                             %
00682 %                                                                             %
00683 %                                                                             %
00684 +   X A n i m a t e B a c k g r o u n d I m a g e                             %
00685 %                                                                             %
00686 %                                                                             %
00687 %                                                                             %
00688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00689 %
00690 %  XAnimateBackgroundImage() animates an image sequence in the background of
00691 %  a window.
00692 %
00693 %  The format of the XAnimateBackgroundImage method is:
00694 %
00695 %      void XAnimateBackgroundImage(Display *display,
00696 %        XResourceInfo *resource_info,Image *images,ExceptionInfo *exception)
00697 %
00698 %  A description of each parameter follows:
00699 %
00700 %    o display: Specifies a connection to an X server;  returned from
00701 %      XOpenDisplay.
00702 %
00703 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
00704 %
00705 %    o images: the image list.
00706 %
00707 %    o exception: return any errors or warnings in this structure.
00708 %
00709 */
00710 
00711 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
00712 {
00713   if (x > y)
00714     return(x);
00715   return(y);
00716 }
00717 
00718 #if defined(__cplusplus) || defined(c_plusplus)
00719 extern "C" {
00720 #endif
00721 
00722 static int SceneCompare(const void *x,const void *y)
00723 {
00724   const Image
00725     **image_1,
00726     **image_2;
00727 
00728   image_1=(const Image **) x;
00729   image_2=(const Image **) y;
00730   return((int) ((*image_1)->scene-(*image_2)->scene));
00731 }
00732 
00733 #if defined(__cplusplus) || defined(c_plusplus)
00734 }
00735 #endif
00736 
00737 MagickExport void XAnimateBackgroundImage(Display *display,
00738   XResourceInfo *resource_info,Image *images,ExceptionInfo *exception)
00739 {
00740   char
00741     geometry[MaxTextExtent],
00742     visual_type[MaxTextExtent];
00743 
00744   Image
00745     *coalesce_image,
00746     *display_image,
00747     **image_list;
00748 
00749   int
00750     scene;
00751 
00752   MagickStatusType
00753     status;
00754 
00755   RectangleInfo
00756     geometry_info;
00757 
00758   register ssize_t
00759     i;
00760 
00761   size_t
00762     number_scenes;
00763 
00764   static XPixelInfo
00765     pixel;
00766 
00767   static XStandardColormap
00768     *map_info;
00769 
00770   static XVisualInfo
00771     *visual_info = (XVisualInfo *) NULL;
00772 
00773   static XWindowInfo
00774     window_info;
00775 
00776   unsigned int
00777     height,
00778     width;
00779 
00780   size_t
00781     delay;
00782 
00783   Window
00784     root_window;
00785 
00786   XEvent
00787     event;
00788 
00789   XGCValues
00790     context_values;
00791 
00792   XResourceInfo
00793     resources;
00794 
00795   XWindowAttributes
00796     window_attributes;
00797 
00798   /*
00799     Determine target window.
00800   */
00801   assert(images != (Image *) NULL);
00802   assert(images->signature == MagickSignature);
00803   if (images->debug != MagickFalse)
00804     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
00805   resources=(*resource_info);
00806   window_info.id=(Window) NULL;
00807   root_window=XRootWindow(display,XDefaultScreen(display));
00808   if (LocaleCompare(resources.window_id,"root") == 0)
00809     window_info.id=root_window;
00810   else
00811     {
00812       if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
00813         window_info.id=XWindowByID(display,root_window,
00814           (Window) strtol((char *) resources.window_id,(char **) NULL,0));
00815       if (window_info.id == (Window) NULL)
00816         window_info.id=
00817           XWindowByName(display,root_window,resources.window_id);
00818     }
00819   if (window_info.id == (Window) NULL)
00820     {
00821       ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
00822         resources.window_id);
00823       return;
00824     }
00825   /*
00826     Determine window visual id.
00827   */
00828   window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
00829   window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
00830   (void) CopyMagickString(visual_type,"default",MaxTextExtent);
00831   status=XGetWindowAttributes(display,window_info.id,&window_attributes) != 0 ?
00832     MagickTrue : MagickFalse;
00833   if (status != MagickFalse)
00834     (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
00835       XVisualIDFromVisual(window_attributes.visual));
00836   if (visual_info == (XVisualInfo *) NULL)
00837     {
00838       /*
00839         Allocate standard colormap.
00840       */
00841       map_info=XAllocStandardColormap();
00842       if (map_info == (XStandardColormap *) NULL)
00843         ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
00844           images->filename);
00845       map_info->colormap=(Colormap) NULL;
00846       pixel.pixels=(unsigned long *) NULL;
00847       /*
00848         Initialize visual info.
00849       */
00850       resources.map_type=(char *) NULL;
00851       resources.visual_type=visual_type;
00852       visual_info=XBestVisualInfo(display,map_info,&resources);
00853       if (visual_info == (XVisualInfo *) NULL)
00854         ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
00855           images->filename);
00856       /*
00857         Initialize window info.
00858       */
00859       window_info.ximage=(XImage *) NULL;
00860       window_info.matte_image=(XImage *) NULL;
00861       window_info.pixmap=(Pixmap) NULL;
00862       window_info.matte_pixmap=(Pixmap) NULL;
00863     }
00864   /*
00865     Free previous root colors.
00866   */
00867   if (window_info.id == root_window)
00868     XDestroyWindowColors(display,root_window);
00869   coalesce_image=CoalesceImages(images,exception);
00870   if (coalesce_image == (Image *) NULL)
00871     ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
00872       images->filename);
00873   images=coalesce_image;
00874   if (resources.map_type == (char *) NULL)
00875     if ((visual_info->klass != TrueColor) &&
00876         (visual_info->klass != DirectColor))
00877       {
00878         Image
00879           *next;
00880 
00881         /*
00882           Determine if the sequence of images has the identical colormap.
00883         */
00884         for (next=images; next != (Image *) NULL; )
00885         {
00886           next->matte=MagickFalse;
00887           if ((next->storage_class == DirectClass) ||
00888               (next->colors != images->colors) ||
00889               (next->colors > (size_t) visual_info->colormap_size))
00890             break;
00891           for (i=0; i < (ssize_t) images->colors; i++)
00892             if (IsPixelInfoEquivalent(next->colormap+i,images->colormap+i) == MagickFalse)
00893               break;
00894           if (i < (ssize_t) images->colors)
00895             break;
00896           next=GetNextImageInList(next);
00897         }
00898         if (next != (Image *) NULL)
00899           (void) RemapImages(resources.quantize_info,images,(Image *) NULL,
00900             exception);
00901       }
00902   /*
00903     Sort images by increasing scene number.
00904   */
00905   number_scenes=GetImageListLength(images);
00906   image_list=ImageListToArray(images,exception);
00907   if (image_list == (Image **) NULL)
00908     ThrowXWindowFatalException(ResourceLimitFatalError,
00909       "MemoryAllocationFailed",images->filename);
00910   for (i=0; i < (ssize_t) number_scenes; i++)
00911     if (image_list[i]->scene == 0)
00912       break;
00913   if (i == (ssize_t) number_scenes)
00914     qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
00915   /*
00916     Initialize Standard Colormap.
00917   */
00918   resources.colormap=SharedColormap;
00919   display_image=image_list[0];
00920   for (scene=0; scene < (int) number_scenes; scene++)
00921   {
00922     if ((resource_info->map_type != (char *) NULL) ||
00923         (visual_info->klass == TrueColor) ||
00924         (visual_info->klass == DirectColor))
00925       (void) SetImageType(image_list[scene],image_list[scene]->matte ==
00926         MagickFalse ? TrueColorType : TrueColorMatteType,exception);
00927     if ((display_image->columns < image_list[scene]->columns) &&
00928         (display_image->rows < image_list[scene]->rows))
00929       display_image=image_list[scene];
00930   }
00931   if ((resource_info->map_type != (char *) NULL) ||
00932       (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor))
00933     (void) SetImageType(display_image,display_image->matte == MagickFalse ?
00934       TrueColorType : TrueColorMatteType,exception);
00935   XMakeStandardColormap(display,visual_info,&resources,display_image,map_info,
00936     &pixel,exception);
00937   /*
00938     Graphic context superclass.
00939   */
00940   context_values.background=pixel.background_color.pixel;
00941   context_values.foreground=pixel.foreground_color.pixel;
00942   pixel.annotate_context=XCreateGC(display,window_info.id,(unsigned long)
00943     (GCBackground | GCForeground),&context_values);
00944   if (pixel.annotate_context == (GC) NULL)
00945     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
00946       images->filename);
00947   /*
00948     Initialize Image window attributes.
00949   */
00950   XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
00951     &resources,&window_info);
00952   /*
00953     Create the X image.
00954   */
00955   window_info.width=(unsigned int) image_list[0]->columns;
00956   window_info.height=(unsigned int) image_list[0]->rows;
00957   if ((image_list[0]->columns != window_info.width) ||
00958       (image_list[0]->rows != window_info.height))
00959     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
00960       image_list[0]->filename);
00961   (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
00962     window_attributes.width,window_attributes.height);
00963   geometry_info.width=window_info.width;
00964   geometry_info.height=window_info.height;
00965   geometry_info.x=(ssize_t) window_info.x;
00966   geometry_info.y=(ssize_t) window_info.y;
00967   (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
00968     &geometry_info.width,&geometry_info.height);
00969   window_info.width=(unsigned int) geometry_info.width;
00970   window_info.height=(unsigned int) geometry_info.height;
00971   window_info.x=(int) geometry_info.x;
00972   window_info.y=(int) geometry_info.y;
00973   status=XMakeImage(display,&resources,&window_info,image_list[0],
00974     window_info.width,window_info.height,exception);
00975   if (status == MagickFalse)
00976     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
00977       images->filename);
00978   window_info.x=0;
00979   window_info.y=0;
00980   if (display_image->debug != MagickFalse)
00981     {
00982       (void) LogMagickEvent(X11Event,GetMagickModule(),
00983         "Image: %s[%.20g] %.20gx%.20g ",image_list[0]->filename,(double)
00984         image_list[0]->scene,(double) image_list[0]->columns,(double)
00985         image_list[0]->rows);
00986       if (image_list[0]->colors != 0)
00987         (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
00988           image_list[0]->colors);
00989       (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
00990         image_list[0]->magick);
00991     }
00992   /*
00993     Adjust image dimensions as specified by backdrop or geometry options.
00994   */
00995   width=window_info.width;
00996   height=window_info.height;
00997   if (resources.backdrop != MagickFalse)
00998     {
00999       /*
01000         Center image on window.
01001       */
01002       window_info.x=(int) (window_attributes.width/2)-
01003         (window_info.ximage->width/2);
01004       window_info.y=(int) (window_attributes.height/2)-
01005         (window_info.ximage->height/2);
01006       width=(unsigned int) window_attributes.width;
01007       height=(unsigned int) window_attributes.height;
01008     }
01009   if (resources.image_geometry != (char *) NULL)
01010     {
01011       char
01012         default_geometry[MaxTextExtent];
01013 
01014       int
01015         flags,
01016         gravity;
01017 
01018       XSizeHints
01019         *size_hints;
01020 
01021       /*
01022         User specified geometry.
01023       */
01024       size_hints=XAllocSizeHints();
01025       if (size_hints == (XSizeHints *) NULL)
01026         ThrowXWindowFatalException(ResourceLimitFatalError,
01027           "MemoryAllocationFailed",images->filename);
01028       size_hints->flags=0L;
01029       (void) FormatLocaleString(default_geometry,MaxTextExtent,"%ux%u",width,
01030         height);
01031       flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
01032         default_geometry,window_info.border_width,size_hints,&window_info.x,
01033         &window_info.y,(int *) &width,(int *) &height,&gravity);
01034       if (((flags & (XValue | YValue))) != 0)
01035         {
01036           width=(unsigned int) window_attributes.width;
01037           height=(unsigned int) window_attributes.height;
01038         }
01039       (void) XFree((void *) size_hints);
01040     }
01041   /*
01042     Create the X pixmap.
01043   */
01044   window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
01045     (unsigned int) height,window_info.depth);
01046   if (window_info.pixmap == (Pixmap) NULL)
01047     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
01048       images->filename);
01049   /*
01050     Display pixmap on the window.
01051   */
01052   if (((unsigned int) width > window_info.width) ||
01053       ((unsigned int) height > window_info.height))
01054     (void) XFillRectangle(display,window_info.pixmap,
01055       window_info.annotate_context,0,0,(unsigned int) width,
01056       (unsigned int) height);
01057   (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
01058     window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
01059     window_info.height);
01060   (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
01061   (void) XClearWindow(display,window_info.id);
01062   /*
01063     Initialize image pixmaps structure.
01064   */
01065   window_info.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
01066     sizeof(*window_info.pixmaps));
01067   window_info.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
01068     sizeof(*window_info.matte_pixmaps));
01069   if ((window_info.pixmaps == (Pixmap *) NULL) ||
01070       (window_info.matte_pixmaps == (Pixmap *) NULL))
01071     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
01072       images->filename);
01073   window_info.pixmaps[0]=window_info.pixmap;
01074   window_info.matte_pixmaps[0]=window_info.pixmap;
01075   for (scene=1; scene < (int) number_scenes; scene++)
01076   {
01077     unsigned int
01078       columns,
01079       rows;
01080 
01081     /*
01082       Create X image.
01083     */
01084     window_info.pixmap=(Pixmap) NULL;
01085     window_info.matte_pixmap=(Pixmap) NULL;
01086     if ((resources.map_type != (char *) NULL) ||
01087         (visual_info->klass == TrueColor) ||
01088         (visual_info->klass == DirectColor))
01089       if (image_list[scene]->storage_class == PseudoClass)
01090         XGetPixelInfo(display,visual_info,map_info,&resources,
01091           image_list[scene],window_info.pixel_info);
01092     columns=(unsigned int) image_list[scene]->columns;
01093     rows=(unsigned int) image_list[scene]->rows;
01094     if ((image_list[scene]->columns != columns) ||
01095         (image_list[scene]->rows != rows))
01096       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
01097         image_list[scene]->filename);
01098     status=XMakeImage(display,&resources,&window_info,image_list[scene],
01099       columns,rows,exception);
01100     if (status == MagickFalse)
01101       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
01102         images->filename);
01103     if (display_image->debug != MagickFalse)
01104       {
01105         (void) LogMagickEvent(X11Event,GetMagickModule(),
01106           "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
01107           image_list[scene]->filename,(double) columns,(double) rows);
01108         if (image_list[scene]->colors != 0)
01109           (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
01110             image_list[scene]->colors);
01111         (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
01112           image_list[scene]->magick);
01113       }
01114     /*
01115       Create the X pixmap.
01116     */
01117     window_info.pixmap=XCreatePixmap(display,window_info.id,width,height,
01118       window_info.depth);
01119     if (window_info.pixmap == (Pixmap) NULL)
01120       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
01121         images->filename);
01122     /*
01123       Display pixmap on the window.
01124     */
01125     if ((width > window_info.width) || (height > window_info.height))
01126       (void) XFillRectangle(display,window_info.pixmap,
01127         window_info.annotate_context,0,0,width,height);
01128     (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
01129       window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
01130       window_info.height);
01131     (void) XSetWindowBackgroundPixmap(display,window_info.id,
01132       window_info.pixmap);
01133     (void) XClearWindow(display,window_info.id);
01134     window_info.pixmaps[scene]=window_info.pixmap;
01135     window_info.matte_pixmaps[scene]=window_info.matte_pixmap;
01136     if (image_list[scene]->matte)
01137       (void) XClearWindow(display,window_info.id);
01138     delay=1000*image_list[scene]->delay/MagickMax(
01139       image_list[scene]->ticks_per_second,1L);
01140     XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
01141   }
01142   window_info.pixel_info=(&pixel);
01143   /*
01144     Display pixmap on the window.
01145   */
01146   (void) XSelectInput(display,window_info.id,SubstructureNotifyMask);
01147   event.type=Expose;
01148   do
01149   {
01150     for (scene=0; scene < (int) number_scenes; scene++)
01151     {
01152       if (XEventsQueued(display,QueuedAfterFlush) > 0)
01153         {
01154           (void) XNextEvent(display,&event);
01155           if (event.type == DestroyNotify)
01156             break;
01157         }
01158       window_info.pixmap=window_info.pixmaps[scene];
01159       window_info.matte_pixmap=window_info.matte_pixmaps[scene];
01160       (void) XSetWindowBackgroundPixmap(display,window_info.id,
01161         window_info.pixmap);
01162       (void) XClearWindow(display,window_info.id);
01163       (void) XSync(display,MagickFalse);
01164       delay=1000*image_list[scene]->delay/MagickMax(
01165         image_list[scene]->ticks_per_second,1L);
01166       XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
01167     }
01168   } while (event.type != DestroyNotify);
01169   (void) XSync(display,MagickFalse);
01170   image_list=(Image **) RelinquishMagickMemory(image_list);
01171   images=DestroyImageList(images);
01172 }
01173 
01174 /*
01175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01176 %                                                                             %
01177 %                                                                             %
01178 %                                                                             %
01179 +   X A n i m a t e I m a g e s                                               %
01180 %                                                                             %
01181 %                                                                             %
01182 %                                                                             %
01183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01184 %
01185 %  XAnimateImages() displays an image via X11.
01186 %
01187 %  The format of the XAnimateImages method is:
01188 %
01189 %      Image *XAnimateImages(Display *display,XResourceInfo *resource_info,
01190 %        char **argv,const int argc,Image *images,ExceptionInfo *exception)
01191 %
01192 %  A description of each parameter follows:
01193 %
01194 %    o display: Specifies a connection to an X server;  returned from
01195 %      XOpenDisplay.
01196 %
01197 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
01198 %
01199 %    o argv: Specifies the application's argument list.
01200 %
01201 %    o argc: Specifies the number of arguments.
01202 %
01203 %    o images: the image list.
01204 %
01205 %    o exception: return any errors or warnings in this structure.
01206 %
01207 */
01208 MagickExport Image *XAnimateImages(Display *display,
01209   XResourceInfo *resource_info,char **argv,const int argc,Image *images,
01210   ExceptionInfo *exception)
01211 {
01212 #define MagickMenus  4
01213 #define MaXWindows  8
01214 #define MagickTitle  "Commands"
01215 
01216   static const char
01217     *CommandMenu[]=
01218     {
01219       "Animate",
01220       "Speed",
01221       "Direction",
01222       "Help",
01223       "Image Info",
01224       "Quit",
01225       (char *) NULL
01226     },
01227     *AnimateMenu[]=
01228     {
01229       "Open...",
01230       "Play",
01231       "Step",
01232       "Repeat",
01233       "Auto Reverse",
01234       "Save...",
01235       (char *) NULL
01236     },
01237     *SpeedMenu[]=
01238     {
01239       "Faster",
01240       "Slower",
01241       (char *) NULL
01242     },
01243     *DirectionMenu[]=
01244     {
01245       "Forward",
01246       "Reverse",
01247       (char *) NULL
01248     },
01249     *HelpMenu[]=
01250     {
01251       "Overview",
01252       "Browse Documentation",
01253       "About Animate",
01254       (char *) NULL
01255     };
01256 
01257   static const char
01258     **Menus[MagickMenus]=
01259     {
01260       AnimateMenu,
01261       SpeedMenu,
01262       DirectionMenu,
01263       HelpMenu
01264     };
01265 
01266   static const CommandType
01267     CommandMenus[]=
01268     {
01269       NullCommand,
01270       NullCommand,
01271       NullCommand,
01272       NullCommand,
01273       InfoCommand,
01274       QuitCommand
01275     },
01276     CommandTypes[]=
01277     {
01278       OpenCommand,
01279       PlayCommand,
01280       StepCommand,
01281       RepeatCommand,
01282       AutoReverseCommand,
01283       SaveCommand
01284     },
01285     SpeedCommands[]=
01286     {
01287       FasterCommand,
01288       SlowerCommand
01289     },
01290     DirectionCommands[]=
01291     {
01292       ForwardCommand,
01293       ReverseCommand
01294     },
01295     HelpCommands[]=
01296     {
01297       HelpCommand,
01298       BrowseDocumentationCommand,
01299       VersionCommand
01300     };
01301 
01302   static const CommandType
01303     *Commands[MagickMenus]=
01304     {
01305       CommandTypes,
01306       SpeedCommands,
01307       DirectionCommands,
01308       HelpCommands
01309     };
01310 
01311   char
01312     command[MaxTextExtent],
01313     *directory,
01314     geometry[MaxTextExtent],
01315     resource_name[MaxTextExtent];
01316 
01317   CommandType
01318     command_type;
01319 
01320   Image
01321     *coalesce_image,
01322     *display_image,
01323     *image,
01324     **image_list,
01325     *nexus;
01326 
01327   int
01328     status;
01329 
01330   KeySym
01331     key_symbol;
01332 
01333   MagickStatusType
01334     context_mask,
01335     state;
01336 
01337   RectangleInfo
01338     geometry_info;
01339 
01340   register char
01341     *p;
01342 
01343   register ssize_t
01344     i;
01345 
01346   ssize_t
01347     first_scene,
01348     iterations,
01349     scene;
01350 
01351   static char
01352     working_directory[MaxTextExtent];
01353 
01354   static size_t
01355     number_windows;
01356 
01357   static XWindowInfo
01358     *magick_windows[MaXWindows];
01359 
01360   time_t
01361     timestamp;
01362 
01363   size_t
01364     delay,
01365     number_scenes;
01366 
01367   WarningHandler
01368     warning_handler;
01369 
01370   Window
01371     root_window;
01372 
01373   XClassHint
01374     *class_hints;
01375 
01376   XEvent
01377     event;
01378 
01379   XFontStruct
01380     *font_info;
01381 
01382   XGCValues
01383     context_values;
01384 
01385   XPixelInfo
01386     *icon_pixel,
01387     *pixel;
01388 
01389   XResourceInfo
01390     *icon_resources;
01391 
01392   XStandardColormap
01393     *icon_map,
01394     *map_info;
01395 
01396   XTextProperty
01397     window_name;
01398 
01399   XVisualInfo
01400     *icon_visual,
01401     *visual_info;
01402 
01403   XWindowChanges
01404     window_changes;
01405 
01406   XWindows
01407     *windows;
01408 
01409   XWMHints
01410     *manager_hints;
01411 
01412   assert(images != (Image *) NULL);
01413   assert(images->signature == MagickSignature);
01414   if (images->debug != MagickFalse)
01415     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
01416   warning_handler=(WarningHandler) NULL;
01417   windows=XSetWindows((XWindows *) ~0);
01418   if (windows != (XWindows *) NULL)
01419     {
01420       int
01421         status;
01422 
01423       status=chdir(working_directory);
01424       if (status == -1)
01425         (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
01426           "UnableToOpenFile","%s",working_directory);
01427       warning_handler=resource_info->display_warnings ?
01428         SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
01429       warning_handler=resource_info->display_warnings ?
01430         SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
01431     }
01432   else
01433     {
01434       register Image
01435         *p;
01436 
01437       /*
01438         Initialize window structure.
01439       */
01440       for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
01441       {
01442         if (p->storage_class == DirectClass)
01443           {
01444             resource_info->colors=0;
01445             break;
01446           }
01447         if (p->colors > resource_info->colors)
01448           resource_info->colors=p->colors;
01449       }
01450       windows=XSetWindows(XInitializeWindows(display,resource_info));
01451       if (windows == (XWindows *) NULL)
01452         ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
01453           images->filename);
01454       /*
01455         Initialize window id's.
01456       */
01457       number_windows=0;
01458       magick_windows[number_windows++]=(&windows->icon);
01459       magick_windows[number_windows++]=(&windows->backdrop);
01460       magick_windows[number_windows++]=(&windows->image);
01461       magick_windows[number_windows++]=(&windows->info);
01462       magick_windows[number_windows++]=(&windows->command);
01463       magick_windows[number_windows++]=(&windows->widget);
01464       magick_windows[number_windows++]=(&windows->popup);
01465       for (i=0; i < (ssize_t) number_windows; i++)
01466         magick_windows[i]->id=(Window) NULL;
01467     }
01468   /*
01469     Initialize font info.
01470   */
01471   if (windows->font_info != (XFontStruct *) NULL)
01472     (void) XFreeFont(display,windows->font_info);
01473   windows->font_info=XBestFont(display,resource_info,MagickFalse);
01474   if (windows->font_info == (XFontStruct *) NULL)
01475     ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
01476       resource_info->font);
01477   /*
01478     Initialize Standard Colormap.
01479   */
01480   map_info=windows->map_info;
01481   icon_map=windows->icon_map;
01482   visual_info=windows->visual_info;
01483   icon_visual=windows->icon_visual;
01484   pixel=windows->pixel_info;
01485   icon_pixel=windows->icon_pixel;
01486   font_info=windows->font_info;
01487   icon_resources=windows->icon_resources;
01488   class_hints=windows->class_hints;
01489   manager_hints=windows->manager_hints;
01490   root_window=XRootWindow(display,visual_info->screen);
01491   coalesce_image=CoalesceImages(images,exception);
01492   if (coalesce_image == (Image *) NULL)
01493     ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
01494       images->filename);
01495   images=coalesce_image;
01496   if (resource_info->map_type == (char *) NULL)
01497     if ((visual_info->klass != TrueColor) &&
01498         (visual_info->klass != DirectColor))
01499       {
01500         Image
01501           *next;
01502 
01503         /*
01504           Determine if the sequence of images has the identical colormap.
01505         */
01506         for (next=images; next != (Image *) NULL; )
01507         {
01508           next->matte=MagickFalse;
01509           if ((next->storage_class == DirectClass) ||
01510               (next->colors != images->colors) ||
01511               (next->colors > (size_t) visual_info->colormap_size))
01512             break;
01513           for (i=0; i < (ssize_t) images->colors; i++)
01514             if (IsPixelInfoEquivalent(next->colormap+i,images->colormap+i) == MagickFalse)
01515               break;
01516           if (i < (ssize_t) images->colors)
01517             break;
01518           next=GetNextImageInList(next);
01519         }
01520         if (next != (Image *) NULL)
01521           (void) RemapImages(resource_info->quantize_info,images,
01522             (Image *) NULL,exception);
01523       }
01524   /*
01525     Sort images by increasing scene number.
01526   */
01527   number_scenes=GetImageListLength(images);
01528   image_list=ImageListToArray(images,exception);
01529   if (image_list == (Image **) NULL)
01530     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
01531       images->filename);
01532   for (scene=0; scene < (ssize_t) number_scenes; scene++)
01533     if (image_list[scene]->scene == 0)
01534       break;
01535   if (scene == (ssize_t) number_scenes)
01536     qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
01537   /*
01538     Initialize Standard Colormap.
01539   */
01540   nexus=NewImageList();
01541   display_image=image_list[0];
01542   for (scene=0; scene < (ssize_t) number_scenes; scene++)
01543   {
01544     if ((resource_info->map_type != (char *) NULL) ||
01545         (visual_info->klass == TrueColor) ||
01546         (visual_info->klass == DirectColor))
01547       (void) SetImageType(image_list[scene],image_list[scene]->matte ==
01548         MagickFalse ? TrueColorType : TrueColorMatteType,exception);
01549     if ((display_image->columns < image_list[scene]->columns) &&
01550         (display_image->rows < image_list[scene]->rows))
01551       display_image=image_list[scene];
01552   }
01553   if (display_image->debug != MagickFalse)
01554     {
01555       (void) LogMagickEvent(X11Event,GetMagickModule(),
01556         "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,(double)
01557         display_image->scene,(double) display_image->columns,(double)
01558         display_image->rows);
01559       if (display_image->colors != 0)
01560         (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
01561           display_image->colors);
01562       (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
01563         display_image->magick);
01564     }
01565   XMakeStandardColormap(display,visual_info,resource_info,display_image,
01566     map_info,pixel,exception);
01567   /*
01568     Initialize graphic context.
01569   */
01570   windows->context.id=(Window) NULL;
01571   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
01572     resource_info,&windows->context);
01573   (void) CloneString(&class_hints->res_name,resource_info->client_name);
01574   (void) CloneString(&class_hints->res_class,resource_info->client_name);
01575   class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
01576   manager_hints->flags=InputHint | StateHint;
01577   manager_hints->input=MagickFalse;
01578   manager_hints->initial_state=WithdrawnState;
01579   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
01580     &windows->context);
01581   if (display_image->debug != MagickFalse)
01582     (void) LogMagickEvent(X11Event,GetMagickModule(),
01583       "Window id: 0x%lx (context)",windows->context.id);
01584   context_values.background=pixel->background_color.pixel;
01585   context_values.font=font_info->fid;
01586   context_values.foreground=pixel->foreground_color.pixel;
01587   context_values.graphics_exposures=MagickFalse;
01588   context_mask=(MagickStatusType)
01589     (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
01590   if (pixel->annotate_context != (GC) NULL)
01591     (void) XFreeGC(display,pixel->annotate_context);
01592   pixel->annotate_context=
01593     XCreateGC(display,windows->context.id,context_mask,&context_values);
01594   if (pixel->annotate_context == (GC) NULL)
01595     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
01596       images->filename);
01597   context_values.background=pixel->depth_color.pixel;
01598   if (pixel->widget_context != (GC) NULL)
01599     (void) XFreeGC(display,pixel->widget_context);
01600   pixel->widget_context=
01601     XCreateGC(display,windows->context.id,context_mask,&context_values);
01602   if (pixel->widget_context == (GC) NULL)
01603     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
01604       images->filename);
01605   context_values.background=pixel->foreground_color.pixel;
01606   context_values.foreground=pixel->background_color.pixel;
01607   context_values.plane_mask=
01608     context_values.background ^ context_values.foreground;
01609   if (pixel->highlight_context != (GC) NULL)
01610     (void) XFreeGC(display,pixel->highlight_context);
01611   pixel->highlight_context=XCreateGC(display,windows->context.id,
01612     (size_t) (context_mask | GCPlaneMask),&context_values);
01613   if (pixel->highlight_context == (GC) NULL)
01614     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
01615       images->filename);
01616   (void) XDestroyWindow(display,windows->context.id);
01617   /*
01618     Initialize icon window.
01619   */
01620   XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
01621     icon_resources,&windows->icon);
01622   windows->icon.geometry=resource_info->icon_geometry;
01623   XBestIconSize(display,&windows->icon,display_image);
01624   windows->icon.attributes.colormap=
01625     XDefaultColormap(display,icon_visual->screen);
01626   windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
01627   manager_hints->flags=InputHint | StateHint;
01628   manager_hints->input=MagickFalse;
01629   manager_hints->initial_state=IconicState;
01630   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
01631     &windows->icon);
01632   if (display_image->debug != MagickFalse)
01633     (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
01634       windows->icon.id);
01635   /*
01636     Initialize graphic context for icon window.
01637   */
01638   if (icon_pixel->annotate_context != (GC) NULL)
01639     (void) XFreeGC(display,icon_pixel->annotate_context);
01640   context_values.background=icon_pixel->background_color.pixel;
01641   context_values.foreground=icon_pixel->foreground_color.pixel;
01642   icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
01643     (size_t) (GCBackground | GCForeground),&context_values);
01644   if (icon_pixel->annotate_context == (GC) NULL)
01645     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
01646       images->filename);
01647   windows->icon.annotate_context=icon_pixel->annotate_context;
01648   /*
01649     Initialize Image window.
01650   */
01651   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
01652     resource_info,&windows->image);
01653   windows->image.shape=MagickTrue;  /* non-rectangular shape hint */
01654   if (resource_info->use_shared_memory == MagickFalse)
01655     windows->image.shared_memory=MagickFalse;
01656   if (resource_info->title != (char *) NULL)
01657     {
01658       char
01659         *title;
01660 
01661       title=InterpretImageProperties(resource_info->image_info,display_image,
01662         resource_info->title,exception);
01663       (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
01664       (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
01665       title=DestroyString(title);
01666     }
01667   else
01668     {
01669       char
01670         filename[MaxTextExtent];
01671 
01672       /*
01673         Window name is the base of the filename.
01674       */
01675       GetPathComponent(display_image->magick_filename,TailPath,filename);
01676       (void) FormatLocaleString(windows->image.name,MaxTextExtent,
01677         "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,(double)
01678         display_image->scene,(double) number_scenes);
01679       (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
01680     }
01681   if (resource_info->immutable != MagickFalse)
01682     windows->image.immutable=MagickTrue;
01683   windows->image.shape=MagickTrue;
01684   windows->image.geometry=resource_info->image_geometry;
01685   (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
01686     XDisplayWidth(display,visual_info->screen),
01687     XDisplayHeight(display,visual_info->screen));
01688   geometry_info.width=display_image->columns;
01689   geometry_info.height=display_image->rows;
01690   geometry_info.x=0;
01691   geometry_info.y=0;
01692   (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
01693     &geometry_info.width,&geometry_info.height);
01694   windows->image.width=(unsigned int) geometry_info.width;
01695   windows->image.height=(unsigned int) geometry_info.height;
01696   windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
01697     ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
01698     KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
01699     PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
01700   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
01701     resource_info,&windows->backdrop);
01702   if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
01703     {
01704       /*
01705         Initialize backdrop window.
01706       */
01707       windows->backdrop.x=0;
01708       windows->backdrop.y=0;
01709       (void) CloneString(&windows->backdrop.name,"ImageMagick Backdrop");
01710       windows->backdrop.flags=(size_t) (USSize | USPosition);
01711       windows->backdrop.width=(unsigned int)
01712         XDisplayWidth(display,visual_info->screen);
01713       windows->backdrop.height=(unsigned int)
01714         XDisplayHeight(display,visual_info->screen);
01715       windows->backdrop.border_width=0;
01716       windows->backdrop.immutable=MagickTrue;
01717       windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
01718         ButtonReleaseMask;
01719       windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
01720         StructureNotifyMask;
01721       manager_hints->flags=IconWindowHint | InputHint | StateHint;
01722       manager_hints->icon_window=windows->icon.id;
01723       manager_hints->input=MagickTrue;
01724       manager_hints->initial_state=
01725         resource_info->iconic ? IconicState : NormalState;
01726       XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
01727         &windows->backdrop);
01728       if (display_image->debug != MagickFalse)
01729         (void) LogMagickEvent(X11Event,GetMagickModule(),
01730           "Window id: 0x%lx (backdrop)",windows->backdrop.id);
01731       (void) XMapWindow(display,windows->backdrop.id);
01732       (void) XClearWindow(display,windows->backdrop.id);
01733       if (windows->image.id != (Window) NULL)
01734         {
01735           (void) XDestroyWindow(display,windows->image.id);
01736           windows->image.id=(Window) NULL;
01737         }
01738       /*
01739         Position image in the center the backdrop.
01740       */
01741       windows->image.flags|=USPosition;
01742       windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
01743         (windows->image.width/2);
01744       windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
01745         (windows->image.height/2);
01746     }
01747   manager_hints->flags=IconWindowHint | InputHint | StateHint;
01748   manager_hints->icon_window=windows->icon.id;
01749   manager_hints->input=MagickTrue;
01750   manager_hints->initial_state=
01751     resource_info->iconic ? IconicState : NormalState;
01752   if (windows->group_leader.id != (Window) NULL)
01753     {
01754       /*
01755         Follow the leader.
01756       */
01757       manager_hints->flags|=(MagickStatusType) WindowGroupHint;
01758       manager_hints->window_group=windows->group_leader.id;
01759       (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
01760       if (display_image->debug != MagickFalse)
01761         (void) LogMagickEvent(X11Event,GetMagickModule(),
01762           "Window id: 0x%lx (group leader)",windows->group_leader.id);
01763     }
01764   XMakeWindow(display,
01765     (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
01766     argv,argc,class_hints,manager_hints,&windows->image);
01767   (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
01768     XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
01769   if (windows->group_leader.id != (Window) NULL)
01770     (void) XSetTransientForHint(display,windows->image.id,
01771       windows->group_leader.id);
01772   if (display_image->debug != MagickFalse)
01773     (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
01774       windows->image.id);
01775   /*
01776     Initialize Info widget.
01777   */
01778   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
01779     resource_info,&windows->info);
01780   (void) CloneString(&windows->info.name,"Info");
01781   (void) CloneString(&windows->info.icon_name,"Info");
01782   windows->info.border_width=1;
01783   windows->info.x=2;
01784   windows->info.y=2;
01785   windows->info.flags|=PPosition;
01786   windows->info.attributes.win_gravity=UnmapGravity;
01787   windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
01788     StructureNotifyMask;
01789   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
01790   manager_hints->input=MagickFalse;
01791   manager_hints->initial_state=NormalState;
01792   manager_hints->window_group=windows->image.id;
01793   XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
01794     &windows->info);
01795   windows->info.highlight_stipple=XCreateBitmapFromData(display,
01796     windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
01797   windows->info.shadow_stipple=XCreateBitmapFromData(display,
01798     windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
01799   (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
01800   if (windows->image.mapped)
01801     (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
01802   if (display_image->debug != MagickFalse)
01803     (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
01804       windows->info.id);
01805   /*
01806     Initialize Command widget.
01807   */
01808   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
01809     resource_info,&windows->command);
01810   windows->command.data=MagickMenus;
01811   (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
01812   (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
01813     resource_info->client_name);
01814   windows->command.geometry=XGetResourceClass(resource_info->resource_database,
01815     resource_name,"geometry",(char *) NULL);
01816   (void) CloneString(&windows->command.name,MagickTitle);
01817   windows->command.border_width=0;
01818   windows->command.flags|=PPosition;
01819   windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
01820     ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
01821     OwnerGrabButtonMask | StructureNotifyMask;
01822   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
01823   manager_hints->input=MagickTrue;
01824   manager_hints->initial_state=NormalState;
01825   manager_hints->window_group=windows->image.id;
01826   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
01827     &windows->command);
01828   windows->command.highlight_stipple=XCreateBitmapFromData(display,
01829     windows->command.id,(char *) HighlightBitmap,HighlightWidth,
01830     HighlightHeight);
01831   windows->command.shadow_stipple=XCreateBitmapFromData(display,
01832     windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
01833   (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
01834   if (display_image->debug != MagickFalse)
01835     (void) LogMagickEvent(X11Event,GetMagickModule(),
01836       "Window id: 0x%lx (command)",windows->command.id);
01837   /*
01838     Initialize Widget window.
01839   */
01840   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
01841     resource_info,&windows->widget);
01842   (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
01843     resource_info->client_name);
01844   windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
01845     resource_name,"geometry",(char *) NULL);
01846   windows->widget.border_width=0;
01847   windows->widget.flags|=PPosition;
01848   windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
01849     ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
01850     KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
01851     StructureNotifyMask;
01852   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
01853   manager_hints->input=MagickTrue;
01854   manager_hints->initial_state=NormalState;
01855   manager_hints->window_group=windows->image.id;
01856   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
01857     &windows->widget);
01858   windows->widget.highlight_stipple=XCreateBitmapFromData(display,
01859     windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
01860   windows->widget.shadow_stipple=XCreateBitmapFromData(display,
01861     windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
01862   (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
01863   if (display_image->debug != MagickFalse)
01864     (void) LogMagickEvent(X11Event,GetMagickModule(),
01865       "Window id: 0x%lx (widget)",windows->widget.id);
01866   /*
01867     Initialize popup window.
01868   */
01869   XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
01870     resource_info,&windows->popup);
01871   windows->popup.border_width=0;
01872   windows->popup.flags|=PPosition;
01873   windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
01874     ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
01875     KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
01876   manager_hints->flags=InputHint | StateHint | WindowGroupHint;
01877   manager_hints->input=MagickTrue;
01878   manager_hints->initial_state=NormalState;
01879   manager_hints->window_group=windows->image.id;
01880   XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
01881     &windows->popup);
01882   windows->popup.highlight_stipple=XCreateBitmapFromData(display,
01883     windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
01884   windows->popup.shadow_stipple=XCreateBitmapFromData(display,
01885     windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
01886   (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
01887   if (display_image->debug != MagickFalse)
01888     (void) LogMagickEvent(X11Event,GetMagickModule(),
01889       "Window id: 0x%lx (pop up)",windows->popup.id);
01890   /*
01891     Set out progress and warning handlers.
01892   */
01893   if (warning_handler == (WarningHandler) NULL)
01894     {
01895       warning_handler=resource_info->display_warnings ?
01896         SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
01897       warning_handler=resource_info->display_warnings ?
01898         SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
01899     }
01900   /*
01901     Initialize X image structure.
01902   */
01903   windows->image.x=0;
01904   windows->image.y=0;
01905   /*
01906     Initialize image pixmaps structure.
01907   */
01908   window_changes.width=(int) windows->image.width;
01909   window_changes.height=(int) windows->image.height;
01910   (void) XReconfigureWMWindow(display,windows->image.id,windows->command.screen,
01911     (unsigned int) (CWWidth | CWHeight),&window_changes);
01912   windows->image.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
01913     sizeof(*windows->image.pixmaps));
01914   windows->image.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
01915     sizeof(*windows->image.pixmaps));
01916   if ((windows->image.pixmaps == (Pixmap *) NULL) ||
01917       (windows->image.matte_pixmaps == (Pixmap *) NULL))
01918     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
01919       images->filename);
01920   if ((windows->image.mapped == MagickFalse) ||
01921       (windows->backdrop.id != (Window) NULL))
01922     (void) XMapWindow(display,windows->image.id);
01923   XSetCursorState(display,windows,MagickTrue);
01924   for (scene=0; scene < (ssize_t) number_scenes; scene++)
01925   {
01926     unsigned int
01927       columns,
01928       rows;
01929 
01930     /*
01931       Create X image.
01932     */
01933     (void) TransformImageColorspace(image_list[scene],RGBColorspace,exception);
01934     windows->image.pixmap=(Pixmap) NULL;
01935     windows->image.matte_pixmap=(Pixmap) NULL;
01936     if ((resource_info->map_type != (char *) NULL) ||
01937         (visual_info->klass == TrueColor) ||
01938         (visual_info->klass == DirectColor))
01939       if (image_list[scene]->storage_class == PseudoClass)
01940         XGetPixelInfo(display,visual_info,map_info,resource_info,
01941           image_list[scene],windows->image.pixel_info);
01942     columns=(unsigned int) image_list[scene]->columns;
01943     rows=(unsigned int) image_list[scene]->rows;
01944     if ((image_list[scene]->columns != columns) ||
01945         (image_list[scene]->rows != rows))
01946       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
01947         image_list[scene]->filename);
01948     status=XMakeImage(display,resource_info,&windows->image,image_list[scene],
01949       columns,rows,exception);
01950     if (status == MagickFalse)
01951       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
01952         images->filename);
01953     if (image_list[scene]->debug != MagickFalse)
01954       {
01955         (void) LogMagickEvent(X11Event,GetMagickModule(),
01956           "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
01957           image_list[scene]->filename,(double) columns,(double) rows);
01958         if (image_list[scene]->colors != 0)
01959           (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
01960             image_list[scene]->colors);
01961         (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
01962           image_list[scene]->magick);
01963       }
01964     /*
01965       Window name is the base of the filename.
01966     */
01967     if (resource_info->title != (char *) NULL)
01968       {
01969         char
01970           *title;
01971 
01972         title=InterpretImageProperties(resource_info->image_info,
01973           image_list[scene],resource_info->title,exception);
01974         (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
01975         title=DestroyString(title);
01976       }
01977     else
01978       {
01979         p=image_list[scene]->magick_filename+
01980           strlen(image_list[scene]->magick_filename)-1;
01981         while ((p > image_list[scene]->magick_filename) && (*(p-1) != '/'))
01982           p--;
01983         (void) FormatLocaleString(windows->image.name,MaxTextExtent,
01984           "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double) scene+1,
01985           (double) number_scenes);
01986       }
01987     status=XStringListToTextProperty(&windows->image.name,1,&window_name);
01988     if (status != Success)
01989       {
01990         XSetWMName(display,windows->image.id,&window_name);
01991         (void) XFree((void *) window_name.value);
01992       }
01993     windows->image.pixmaps[scene]=windows->image.pixmap;
01994     windows->image.matte_pixmaps[scene]=windows->image.matte_pixmap;
01995     if (scene == 0)
01996       {
01997         event.xexpose.x=0;
01998         event.xexpose.y=0;
01999         event.xexpose.width=(int) image_list[scene]->columns;
02000         event.xexpose.height=(int) image_list[scene]->rows;
02001         XRefreshWindow(display,&windows->image,&event);
02002         (void) XSync(display,MagickFalse);
02003     }
02004   }
02005   XSetCursorState(display,windows,MagickFalse);
02006   if (windows->command.mapped)
02007     (void) XMapRaised(display,windows->command.id);
02008   /*
02009     Respond to events.
02010   */
02011   nexus=NewImageList();
02012   scene=0;
02013   first_scene=0;
02014   iterations=0;
02015   image=image_list[0];
02016   state=(MagickStatusType) (ForwardAnimationState | RepeatAnimationState);
02017   (void) XMagickCommand(display,resource_info,windows,PlayCommand,&images,
02018     &state,exception);
02019   do
02020   {
02021     if (XEventsQueued(display,QueuedAfterFlush) == 0)
02022       if ((state & PlayAnimationState) || (state & StepAnimationState))
02023         {
02024           MagickBooleanType
02025             pause;
02026 
02027           pause=MagickFalse;
02028           delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
02029           XDelay(display,resource_info->delay*(delay == 0 ? 10 : delay));
02030           if (state & ForwardAnimationState)
02031             {
02032               /*
02033                 Forward animation:  increment scene number.
02034               */
02035               if (scene < ((ssize_t) number_scenes-1))
02036                 scene++;
02037               else
02038                 {
02039                   iterations++;
02040                   if (iterations == (ssize_t) image_list[0]->iterations)
02041                     {
02042                       iterations=0;
02043                       state|=ExitState;
02044                     }
02045                   if ((state & AutoReverseAnimationState) != 0)
02046                     {
02047                       state&=(~ForwardAnimationState);
02048                       scene--;
02049                     }
02050                   else
02051                     {
02052                       if ((state & RepeatAnimationState) == 0)
02053                         state&=(~PlayAnimationState);
02054                       scene=first_scene;
02055                       pause=MagickTrue;
02056                     }
02057                 }
02058             }
02059           else
02060             {
02061               /*
02062                 Reverse animation:  decrement scene number.
02063               */
02064               if (scene > first_scene)
02065                 scene--;
02066               else
02067                 {
02068                   iterations++;
02069                   if (iterations == (ssize_t) image_list[0]->iterations)
02070                     {
02071                       iterations=0;
02072                       state&=(~RepeatAnimationState);
02073                     }
02074                   if (state & AutoReverseAnimationState)
02075                     {
02076                       state|=ForwardAnimationState;
02077                       scene=first_scene;
02078                       pause=MagickTrue;
02079                     }
02080                   else
02081                     {
02082                       if ((state & RepeatAnimationState) == MagickFalse)
02083                         state&=(~PlayAnimationState);
02084                       scene=(ssize_t) number_scenes-1;
02085                     }
02086                 }
02087             }
02088           scene=MagickMax(scene,0);
02089           image=image_list[scene];
02090           if ((image != (Image *) NULL) && (image->start_loop != 0))
02091             first_scene=scene;
02092           if ((state & StepAnimationState) ||
02093               (resource_info->title != (char *) NULL))
02094             {
02095               /*
02096                 Update window title.
02097               */
02098               p=image_list[scene]->filename+
02099                 strlen(image_list[scene]->filename)-1;
02100               while ((p > image_list[scene]->filename) && (*(p-1) != '/'))
02101                 p--;
02102               (void) FormatLocaleString(windows->image.name,MaxTextExtent,
02103                 "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double)
02104                 scene+1,(double) number_scenes);
02105               if (resource_info->title != (char *) NULL)
02106                 {
02107                   char
02108                     *title;
02109 
02110                   title=InterpretImageProperties(resource_info->image_info,
02111                     image,resource_info->title,exception);
02112                   (void) CopyMagickString(windows->image.name,title,
02113                     MaxTextExtent);
02114                   title=DestroyString(title);
02115                 }
02116               status=XStringListToTextProperty(&windows->image.name,1,
02117                 &window_name);
02118               if (status != Success)
02119                 {
02120                   XSetWMName(display,windows->image.id,&window_name);
02121                   (void) XFree((void *) window_name.value);
02122                 }
02123             }
02124           /*
02125             Copy X pixmap to Image window.
02126           */
02127           XGetPixelInfo(display,visual_info,map_info,resource_info,
02128             image_list[scene],windows->image.pixel_info);
02129           windows->image.ximage->width=(int) image->columns;
02130           windows->image.ximage->height=(int) image->rows;
02131           windows->image.pixmap=windows->image.pixmaps[scene];
02132           windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
02133           event.xexpose.x=0;
02134           event.xexpose.y=0;
02135           event.xexpose.width=(int) image->columns;
02136           event.xexpose.height=(int) image->rows;
02137           if ((state & ExitState) == 0)
02138             {
02139               XRefreshWindow(display,&windows->image,&event);
02140               (void) XSync(display,MagickFalse);
02141             }
02142           state&=(~StepAnimationState);
02143           if (pause != MagickFalse)
02144             for (i=0; i < (ssize_t) resource_info->pause; i++)
02145             {
02146               int
02147                 status;
02148 
02149               status=XCheckTypedWindowEvent(display,windows->image.id,KeyPress,
02150                 &event);
02151               if (status != 0)
02152                 {
02153                   int
02154                     length;
02155 
02156                   length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
02157                     sizeof(command),&key_symbol,(XComposeStatus *) NULL);
02158                   *(command+length)='\0';
02159                   if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
02160                     {
02161                       XClientMessage(display,windows->image.id,
02162                         windows->im_protocols,windows->im_exit,CurrentTime);
02163                       break;
02164                     }
02165                 }
02166               (void) sleep(1);
02167             }
02168           continue;
02169         }
02170     /*
02171       Handle a window event.
02172     */
02173     timestamp=time((time_t *) NULL);
02174     (void) XNextEvent(display,&event);
02175     if (windows->image.stasis == MagickFalse)
02176       windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
02177         MagickTrue : MagickFalse;
02178     if (event.xany.window == windows->command.id)
02179       {
02180         int
02181           id;
02182 
02183         /*
02184           Select a command from the Command widget.
02185         */
02186         id=XCommandWidget(display,windows,CommandMenu,&event);
02187         if (id < 0)
02188           continue;
02189         (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
02190         command_type=CommandMenus[id];
02191         if (id < MagickMenus)
02192           {
02193             int
02194               entry;
02195 
02196             /*
02197               Select a command from a pop-up menu.
02198             */
02199             entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
02200               command);
02201             if (entry < 0)
02202               continue;
02203             (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
02204             command_type=Commands[id][entry];
02205           }
02206         if (command_type != NullCommand)
02207           nexus=XMagickCommand(display,resource_info,windows,
02208             command_type,&image,&state,exception);
02209         continue;
02210       }
02211     switch (event.type)
02212     {
02213       case ButtonPress:
02214       {
02215         if (display_image->debug != MagickFalse)
02216           (void) LogMagickEvent(X11Event,GetMagickModule(),
02217             "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
02218             event.xbutton.button,event.xbutton.x,event.xbutton.y);
02219         if ((event.xbutton.button == Button3) &&
02220             (event.xbutton.state & Mod1Mask))
02221           {
02222             /*
02223               Convert Alt-Button3 to Button2.
02224             */
02225             event.xbutton.button=Button2;
02226             event.xbutton.state&=(~Mod1Mask);
02227           }
02228         if (event.xbutton.window == windows->backdrop.id)
02229           {
02230             (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
02231               event.xbutton.time);
02232             break;
02233           }
02234         if (event.xbutton.window == windows->image.id)
02235           {
02236             if (resource_info->immutable != MagickFalse)
02237               {
02238                 state|=ExitState;
02239                 break;
02240               }
02241             /*
02242               Map/unmap Command widget.
02243             */
02244             if (windows->command.mapped)
02245               (void) XWithdrawWindow(display,windows->command.id,
02246                 windows->command.screen);
02247             else
02248               {
02249                 (void) XCommandWidget(display,windows,CommandMenu,
02250                   (XEvent *) NULL);
02251                 (void) XMapRaised(display,windows->command.id);
02252               }
02253           }
02254         break;
02255       }
02256       case ButtonRelease:
02257       {
02258         if (display_image->debug != MagickFalse)
02259           (void) LogMagickEvent(X11Event,GetMagickModule(),
02260             "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
02261             event.xbutton.button,event.xbutton.x,event.xbutton.y);
02262         break;
02263       }
02264       case ClientMessage:
02265       {
02266         if (display_image->debug != MagickFalse)
02267           (void) LogMagickEvent(X11Event,GetMagickModule(),
02268             "Client Message: 0x%lx 0x%lx %d 0x%lx",(unsigned long)
02269             event.xclient.window,(unsigned long) event.xclient.message_type,
02270             event.xclient.format,(unsigned long) event.xclient.data.l[0]);
02271         if (event.xclient.message_type == windows->im_protocols)
02272           {
02273             if (*event.xclient.data.l == (long) windows->im_update_colormap)
02274               {
02275                 /*
02276                   Update graphic context and window colormap.
02277                 */
02278                 for (i=0; i < (ssize_t) number_windows; i++)
02279                 {
02280                   if (magick_windows[i]->id == windows->icon.id)
02281                     continue;
02282                   context_values.background=pixel->background_color.pixel;
02283                   context_values.foreground=pixel->foreground_color.pixel;
02284                   (void) XChangeGC(display,magick_windows[i]->annotate_context,
02285                     context_mask,&context_values);
02286                   (void) XChangeGC(display,magick_windows[i]->widget_context,
02287                     context_mask,&context_values);
02288                   context_values.background=pixel->foreground_color.pixel;
02289                   context_values.foreground=pixel->background_color.pixel;
02290                   context_values.plane_mask=
02291                     context_values.background ^ context_values.foreground;
02292                   (void) XChangeGC(display,magick_windows[i]->highlight_context,
02293                     (size_t) (context_mask | GCPlaneMask),
02294                     &context_values);
02295                   magick_windows[i]->attributes.background_pixel=
02296                     pixel->background_color.pixel;
02297                   magick_windows[i]->attributes.border_pixel=
02298                     pixel->border_color.pixel;
02299                   magick_windows[i]->attributes.colormap=map_info->colormap;
02300                   (void) XChangeWindowAttributes(display,magick_windows[i]->id,
02301                     (unsigned long) magick_windows[i]->mask,
02302                     &magick_windows[i]->attributes);
02303                 }
02304                 if (windows->backdrop.id != (Window) NULL)
02305                   (void) XInstallColormap(display,map_info->colormap);
02306                 break;
02307               }
02308             if (*event.xclient.data.l == (long) windows->im_exit)
02309               {
02310                 state|=ExitState;
02311                 break;
02312               }
02313             break;
02314           }
02315         if (event.xclient.message_type == windows->dnd_protocols)
02316           {
02317             Atom
02318               selection,
02319               type;
02320 
02321             int
02322               format,
02323               status;
02324 
02325             unsigned char
02326               *data;
02327 
02328             unsigned long
02329               after,
02330               length;
02331 
02332             /*
02333               Display image named by the Drag-and-Drop selection.
02334             */
02335             if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
02336               break;
02337             selection=XInternAtom(display,"DndSelection",MagickFalse);
02338             status=XGetWindowProperty(display,root_window,selection,0L,2047L,
02339               MagickFalse,(Atom) AnyPropertyType,&type,&format,&length,&after,
02340               &data);
02341             if ((status != Success) || (length == 0))
02342               break;
02343             if (*event.xclient.data.l == 2)
02344               {
02345                 /*
02346                   Offix DND.
02347                 */
02348                 (void) CopyMagickString(resource_info->image_info->filename,
02349                   (char *) data,MaxTextExtent);
02350               }
02351             else
02352               {
02353                 /*
02354                   XDND.
02355                 */
02356                 if (LocaleNCompare((char *) data,"file:",5) != 0)
02357                   {
02358                     (void) XFree((void *) data);
02359                     break;
02360                   }
02361                 (void) CopyMagickString(resource_info->image_info->filename,
02362                   ((char *) data)+5,MaxTextExtent);
02363               }
02364             nexus=ReadImage(resource_info->image_info,exception);
02365             CatchException(exception);
02366             if (nexus != (Image *) NULL)
02367               state|=ExitState;
02368             (void) XFree((void *) data);
02369             break;
02370           }
02371         /*
02372           If client window delete message, exit.
02373         */
02374         if (event.xclient.message_type != windows->wm_protocols)
02375           break;
02376         if (*event.xclient.data.l == (long) windows->wm_take_focus)
02377           {
02378             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
02379               (Time) event.xclient.data.l[1]);
02380             break;
02381           }
02382         if (*event.xclient.data.l != (long) windows->wm_delete_window)
02383           break;
02384         (void) XWithdrawWindow(display,event.xclient.window,
02385           visual_info->screen);
02386         if (event.xclient.window == windows->image.id)
02387           {
02388             state|=ExitState;
02389             break;
02390           }
02391         break;
02392       }
02393       case ConfigureNotify:
02394       {
02395         if (display_image->debug != MagickFalse)
02396           (void) LogMagickEvent(X11Event,GetMagickModule(),
02397             "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
02398             event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
02399             event.xconfigure.y,event.xconfigure.send_event);
02400         if (event.xconfigure.window == windows->image.id)
02401           {
02402             if (event.xconfigure.send_event != 0)
02403               {
02404                 XWindowChanges
02405                   window_changes;
02406 
02407                 /*
02408                   Position the transient windows relative of the Image window.
02409                 */
02410                 if (windows->command.geometry == (char *) NULL)
02411                   if (windows->command.mapped == MagickFalse)
02412                     {
02413                        windows->command.x=
02414                           event.xconfigure.x-windows->command.width-25;
02415                         windows->command.y=event.xconfigure.y;
02416                         XConstrainWindowPosition(display,&windows->command);
02417                         window_changes.x=windows->command.x;
02418                         window_changes.y=windows->command.y;
02419                         (void) XReconfigureWMWindow(display,windows->command.id,
02420                           windows->command.screen,(unsigned int) (CWX | CWY),
02421                           &window_changes);
02422                     }
02423                 if (windows->widget.geometry == (char *) NULL)
02424                   if (windows->widget.mapped == MagickFalse)
02425                     {
02426                       windows->widget.x=
02427                         event.xconfigure.x+event.xconfigure.width/10;
02428                       windows->widget.y=
02429                         event.xconfigure.y+event.xconfigure.height/10;
02430                       XConstrainWindowPosition(display,&windows->widget);
02431                       window_changes.x=windows->widget.x;
02432                       window_changes.y=windows->widget.y;
02433                       (void) XReconfigureWMWindow(display,windows->widget.id,
02434                         windows->widget.screen,(unsigned int) (CWX | CWY),
02435                         &window_changes);
02436                     }
02437               }
02438             /*
02439               Image window has a new configuration.
02440             */
02441             windows->image.width=(unsigned int) event.xconfigure.width;
02442             windows->image.height=(unsigned int) event.xconfigure.height;
02443             break;
02444           }
02445         if (event.xconfigure.window == windows->icon.id)
02446           {
02447             /*
02448               Icon window has a new configuration.
02449             */
02450             windows->icon.width=(unsigned int) event.xconfigure.width;
02451             windows->icon.height=(unsigned int) event.xconfigure.height;
02452             break;
02453           }
02454         break;
02455       }
02456       case DestroyNotify:
02457       {
02458         /*
02459           Group leader has exited.
02460         */
02461         if (display_image->debug != MagickFalse)
02462           (void) LogMagickEvent(X11Event,GetMagickModule(),
02463             "Destroy Notify: 0x%lx",event.xdestroywindow.window);
02464         if (event.xdestroywindow.window == windows->group_leader.id)
02465           {
02466             state|=ExitState;
02467             break;
02468           }
02469         break;
02470       }
02471       case EnterNotify:
02472       {
02473         /*
02474           Selectively install colormap.
02475         */
02476         if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
02477           if (event.xcrossing.mode != NotifyUngrab)
02478             XInstallColormap(display,map_info->colormap);
02479         break;
02480       }
02481       case Expose:
02482       {
02483         if (display_image->debug != MagickFalse)
02484           (void) LogMagickEvent(X11Event,GetMagickModule(),
02485             "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
02486             event.xexpose.width,event.xexpose.height,event.xexpose.x,
02487             event.xexpose.y);
02488         /*
02489           Repaint windows that are now exposed.
02490         */
02491         if (event.xexpose.window == windows->image.id)
02492           {
02493             windows->image.pixmap=windows->image.pixmaps[scene];
02494             windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
02495             XRefreshWindow(display,&windows->image,&event);
02496             break;
02497           }
02498         if (event.xexpose.window == windows->icon.id)
02499           if (event.xexpose.count == 0)
02500             {
02501               XRefreshWindow(display,&windows->icon,&event);
02502               break;
02503             }
02504         break;
02505       }
02506       case KeyPress:
02507       {
02508         static int
02509           length;
02510 
02511         /*
02512           Respond to a user key press.
02513         */
02514         length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
02515           sizeof(command),&key_symbol,(XComposeStatus *) NULL);
02516         *(command+length)='\0';
02517         if (display_image->debug != MagickFalse)
02518           (void) LogMagickEvent(X11Event,GetMagickModule(),
02519             "Key press: 0x%lx (%c)",(unsigned long) key_symbol,*command);
02520         command_type=NullCommand;
02521         switch (key_symbol)
02522         {
02523           case XK_o:
02524           {
02525             if ((event.xkey.state & ControlMask) == MagickFalse)
02526               break;
02527             command_type=OpenCommand;
02528             break;
02529           }
02530           case XK_BackSpace:
02531           {
02532             command_type=StepBackwardCommand;
02533             break;
02534           }
02535           case XK_space:
02536           {
02537             command_type=StepForwardCommand;
02538             break;
02539           }
02540           case XK_less:
02541           {
02542             command_type=FasterCommand;
02543             break;
02544           }
02545           case XK_greater:
02546           {
02547             command_type=SlowerCommand;
02548             break;
02549           }
02550           case XK_F1:
02551           {
02552             command_type=HelpCommand;
02553             break;
02554           }
02555           case XK_Find:
02556           {
02557             command_type=BrowseDocumentationCommand;
02558             break;
02559           }
02560           case XK_question:
02561           {
02562             command_type=InfoCommand;
02563             break;
02564           }
02565           case XK_q:
02566           case XK_Escape:
02567           {
02568             command_type=QuitCommand;
02569             break;
02570           }
02571           default:
02572             break;
02573         }
02574         if (command_type != NullCommand)
02575           nexus=XMagickCommand(display,resource_info,windows,
02576             command_type,&image,&state,exception);
02577         break;
02578       }
02579       case KeyRelease:
02580       {
02581         /*
02582           Respond to a user key release.
02583         */
02584         (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
02585           sizeof(command),&key_symbol,(XComposeStatus *) NULL);
02586         if (display_image->debug != MagickFalse)
02587           (void) LogMagickEvent(X11Event,GetMagickModule(),
02588             "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
02589         break;
02590       }
02591       case LeaveNotify:
02592       {
02593         /*
02594           Selectively uninstall colormap.
02595         */
02596         if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
02597           if (event.xcrossing.mode != NotifyUngrab)
02598             XUninstallColormap(display,map_info->colormap);
02599         break;
02600       }
02601       case MapNotify:
02602       {
02603         if (display_image->debug != MagickFalse)
02604           (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
02605             event.xmap.window);
02606         if (event.xmap.window == windows->backdrop.id)
02607           {
02608             (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
02609               CurrentTime);
02610             windows->backdrop.mapped=MagickTrue;
02611             break;
02612           }
02613         if (event.xmap.window == windows->image.id)
02614           {
02615             if (windows->backdrop.id != (Window) NULL)
02616               (void) XInstallColormap(display,map_info->colormap);
02617             if (LocaleCompare(image_list[0]->magick,"LOGO") == 0)
02618               {
02619                 if (LocaleCompare(display_image->filename,"LOGO") == 0)
02620                   nexus=XMagickCommand(display,resource_info,windows,
02621                     OpenCommand,&image,&state,exception);
02622                 else
02623                   state|=ExitState;
02624               }
02625             windows->image.mapped=MagickTrue;
02626             break;
02627           }
02628         if (event.xmap.window == windows->info.id)
02629           {
02630             windows->info.mapped=MagickTrue;
02631             break;
02632           }
02633         if (event.xmap.window == windows->icon.id)
02634           {
02635             /*
02636               Create an icon image.
02637             */
02638             XMakeStandardColormap(display,icon_visual,icon_resources,
02639               display_image,icon_map,icon_pixel,exception);
02640             (void) XMakeImage(display,icon_resources,&windows->icon,
02641               display_image,windows->icon.width,windows->icon.height,
02642               exception);
02643             (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
02644               windows->icon.pixmap);
02645             (void) XClearWindow(display,windows->icon.id);
02646             (void) XWithdrawWindow(display,windows->info.id,
02647               windows->info.screen);
02648             windows->icon.mapped=MagickTrue;
02649             break;
02650           }
02651         if (event.xmap.window == windows->command.id)
02652           {
02653             windows->command.mapped=MagickTrue;
02654             break;
02655           }
02656         if (event.xmap.window == windows->popup.id)
02657           {
02658             windows->popup.mapped=MagickTrue;
02659             break;
02660           }
02661         if (event.xmap.window == windows->widget.id)
02662           {
02663             windows->widget.mapped=MagickTrue;
02664             break;
02665           }
02666         break;
02667       }
02668       case MappingNotify:
02669       {
02670         (void) XRefreshKeyboardMapping(&event.xmapping);
02671         break;
02672       }
02673       case NoExpose:
02674         break;
02675       case PropertyNotify:
02676       {
02677         Atom
02678           type;
02679 
02680         int
02681           format,
02682           status;
02683 
02684         unsigned char
02685           *data;
02686 
02687         unsigned long
02688           after,
02689           length;
02690 
02691         if (display_image->debug != MagickFalse)
02692           (void) LogMagickEvent(X11Event,GetMagickModule(),
02693             "Property Notify: 0x%lx 0x%lx %d",(unsigned long)
02694             event.xproperty.window,(unsigned long) event.xproperty.atom,
02695             event.xproperty.state);
02696         if (event.xproperty.atom != windows->im_remote_command)
02697           break;
02698         /*
02699           Display image named by the remote command protocol.
02700         */
02701         status=XGetWindowProperty(display,event.xproperty.window,
02702           event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
02703           AnyPropertyType,&type,&format,&length,&after,&data);
02704         if ((status != Success) || (length == 0))
02705           break;
02706         (void) CopyMagickString(resource_info->image_info->filename,
02707           (char *) data,MaxTextExtent);
02708         nexus=ReadImage(resource_info->image_info,exception);
02709         CatchException(exception);
02710         if (nexus != (Image *) NULL)
02711           state|=ExitState;
02712         (void) XFree((void *) data);
02713         break;
02714       }
02715       case ReparentNotify:
02716       {
02717         if (display_image->debug != MagickFalse)
02718           (void) LogMagickEvent(X11Event,GetMagickModule(),
02719             "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
02720             event.xreparent.window);
02721         break;
02722       }
02723       case UnmapNotify:
02724       {
02725         if (display_image->debug != MagickFalse)
02726           (void) LogMagickEvent(X11Event,GetMagickModule(),
02727             "Unmap Notify: 0x%lx",event.xunmap.window);
02728         if (event.xunmap.window == windows->backdrop.id)
02729           {
02730             windows->backdrop.mapped=MagickFalse;
02731             break;
02732           }
02733         if (event.xunmap.window == windows->image.id)
02734           {
02735             windows->image.mapped=MagickFalse;
02736             break;
02737           }
02738         if (event.xunmap.window == windows->info.id)
02739           {
02740             windows->info.mapped=MagickFalse;
02741             break;
02742           }
02743         if (event.xunmap.window == windows->icon.id)
02744           {
02745             if (map_info->colormap == icon_map->colormap)
02746               XConfigureImageColormap(display,resource_info,windows,
02747                 display_image,exception);
02748             (void) XFreeStandardColormap(display,icon_visual,icon_map,
02749               icon_pixel);
02750             windows->icon.mapped=MagickFalse;
02751             break;
02752           }
02753         if (event.xunmap.window == windows->command.id)
02754           {
02755             windows->command.mapped=MagickFalse;
02756             break;
02757           }
02758         if (event.xunmap.window == windows->popup.id)
02759           {
02760             if (windows->backdrop.id != (Window) NULL)
02761               (void) XSetInputFocus(display,windows->image.id,RevertToParent,
02762                 CurrentTime);
02763             windows->popup.mapped=MagickFalse;
02764             break;
02765           }
02766         if (event.xunmap.window == windows->widget.id)
02767           {
02768             if (windows->backdrop.id != (Window) NULL)
02769               (void) XSetInputFocus(display,windows->image.id,RevertToParent,
02770                 CurrentTime);
02771             windows->widget.mapped=MagickFalse;
02772             break;
02773           }
02774         break;
02775       }
02776       default:
02777       {
02778         if (display_image->debug != MagickFalse)
02779           (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
02780             event.type);
02781         break;
02782       }
02783     }
02784   }
02785   while (!(state & ExitState));
02786   image_list=(Image **) RelinquishMagickMemory(image_list);
02787   images=DestroyImageList(images);
02788   if ((windows->visual_info->klass == GrayScale) ||
02789       (windows->visual_info->klass == PseudoColor) ||
02790       (windows->visual_info->klass == DirectColor))
02791     {
02792       /*
02793         Withdraw windows.
02794       */
02795       if (windows->info.mapped)
02796         (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
02797       if (windows->command.mapped)
02798         (void) XWithdrawWindow(display,windows->command.id,
02799           windows->command.screen);
02800     }
02801   if (resource_info->backdrop == MagickFalse)
02802     if (windows->backdrop.mapped)
02803       {
02804         (void) XWithdrawWindow(display,windows->backdrop.id,\
02805           windows->backdrop.screen);
02806         (void) XDestroyWindow(display,windows->backdrop.id);
02807         windows->backdrop.id=(Window) NULL;
02808         (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);
02809         (void) XDestroyWindow(display,windows->image.id);
02810         windows->image.id=(Window) NULL;
02811       }
02812   XSetCursorState(display,windows,MagickTrue);
02813   XCheckRefreshWindows(display,windows);
02814   for (scene=1; scene < (ssize_t) number_scenes; scene++)
02815   {
02816     if (windows->image.pixmaps[scene] != (Pixmap) NULL)
02817       (void) XFreePixmap(display,windows->image.pixmaps[scene]);
02818     windows->image.pixmaps[scene]=(Pixmap) NULL;
02819     if (windows->image.matte_pixmaps[scene] != (Pixmap) NULL)
02820       (void) XFreePixmap(display,windows->image.matte_pixmaps[scene]);
02821     windows->image.matte_pixmaps[scene]=(Pixmap) NULL;
02822   }
02823   XSetCursorState(display,windows,MagickFalse);
02824   windows->image.pixmaps=(Pixmap *)
02825     RelinquishMagickMemory(windows->image.pixmaps);
02826   windows->image.matte_pixmaps=(Pixmap *)
02827     RelinquishMagickMemory(windows->image.matte_pixmaps);
02828   if (nexus == (Image *) NULL)
02829     {
02830       /*
02831         Free X resources.
02832       */
02833       if (windows->image.mapped != MagickFalse)
02834         (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);      XDelay(display,SuspendTime);
02835       (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
02836       if (resource_info->map_type == (char *) NULL)
02837         (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
02838       DestroyXResources();
02839     }
02840   (void) XSync(display,MagickFalse);
02841   /*
02842     Restore our progress monitor and warning handlers.
02843   */
02844   (void) SetErrorHandler(warning_handler);
02845   (void) SetWarningHandler(warning_handler);
02846   /*
02847     Change to home directory.
02848   */
02849   directory=getcwd(working_directory,MaxTextExtent);
02850   (void) directory;
02851   status=chdir(resource_info->home_directory);
02852   if (status == -1)
02853     (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
02854       "UnableToOpenFile","%s",resource_info->home_directory);
02855   return(nexus);
02856 }
02857 
02858 /*
02859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02860 %                                                                             %
02861 %                                                                             %
02862 %                                                                             %
02863 +   X S a v e I m a g e                                                       %
02864 %                                                                             %
02865 %                                                                             %
02866 %                                                                             %
02867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02868 %
02869 %  XSaveImage() saves an image to a file.
02870 %
02871 %  The format of the XSaveImage method is:
02872 %
02873 %      MagickBooleanType XSaveImage(Display *display,
02874 %        XResourceInfo *resource_info,XWindows *windows,Image *image,
02875 %        ExceptionInfo *exception)
02876 %
02877 %  A description of each parameter follows:
02878 %
02879 %    o status: Method XSaveImage return True if the image is
02880 %      written.  False is returned is there is a memory shortage or if the
02881 %      image fails to write.
02882 %
02883 %    o display: Specifies a connection to an X server; returned from
02884 %      XOpenDisplay.
02885 %
02886 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
02887 %
02888 %    o windows: Specifies a pointer to a XWindows structure.
02889 %
02890 %    o image: the image.
02891 %
02892 */
02893 static MagickBooleanType XSaveImage(Display *display,
02894   XResourceInfo *resource_info,XWindows *windows,Image *image,
02895   ExceptionInfo *exception)
02896 {
02897   char
02898     filename[MaxTextExtent];
02899 
02900   ImageInfo
02901     *image_info;
02902 
02903   MagickStatusType
02904     status;
02905 
02906   /*
02907     Request file name from user.
02908   */
02909   if (resource_info->write_filename != (char *) NULL)
02910     (void) CopyMagickString(filename,resource_info->write_filename,
02911       MaxTextExtent);
02912   else
02913     {
02914       char
02915         path[MaxTextExtent];
02916 
02917       int
02918         status;
02919 
02920       GetPathComponent(image->filename,HeadPath,path);
02921       GetPathComponent(image->filename,TailPath,filename);
02922       status=chdir(path);
02923       if (status == -1)
02924         (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
02925           "UnableToOpenFile","%s",path);
02926     }
02927   XFileBrowserWidget(display,windows,"Save",filename);
02928   if (*filename == '\0')
02929     return(MagickTrue);
02930   if (IsPathAccessible(filename) != MagickFalse)
02931     {
02932       int
02933         status;
02934 
02935       /*
02936         File exists-- seek user's permission before overwriting.
02937       */
02938       status=XConfirmWidget(display,windows,"Overwrite",filename);
02939       if (status == 0)
02940         return(MagickTrue);
02941     }
02942   image_info=CloneImageInfo(resource_info->image_info);
02943   (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
02944   (void) SetImageInfo(image_info,1,exception);
02945   if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
02946       (LocaleCompare(image_info->magick,"JPG") == 0))
02947     {
02948       char
02949         quality[MaxTextExtent];
02950 
02951       int
02952         status;
02953 
02954       /*
02955         Request JPEG quality from user.
02956       */
02957       (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
02958         image_info->quality);
02959       status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
02960         quality);
02961       if (*quality == '\0')
02962         return(MagickTrue);
02963       image->quality=StringToUnsignedLong(quality);
02964       image_info->interlace=status != MagickFalse ?  NoInterlace :
02965         PlaneInterlace;
02966     }
02967   if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
02968       (LocaleCompare(image_info->magick,"PDF") == 0) ||
02969       (LocaleCompare(image_info->magick,"PS") == 0) ||
02970       (LocaleCompare(image_info->magick,"PS2") == 0))
02971     {
02972       char
02973         geometry[MaxTextExtent];
02974 
02975       /*
02976         Request page geometry from user.
02977       */
02978       (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
02979       if (LocaleCompare(image_info->magick,"PDF") == 0)
02980         (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
02981       if (image_info->page != (char *) NULL)
02982         (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
02983       XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
02984         "Select page geometry:",geometry);
02985       if (*geometry != '\0')
02986         image_info->page=GetPageGeometry(geometry);
02987     }
02988   /*
02989     Write image.
02990   */
02991   image=GetFirstImageInList(image);
02992   status=WriteImages(image_info,image,filename,exception);
02993   if (status != MagickFalse)
02994     image->taint=MagickFalse;
02995   image_info=DestroyImageInfo(image_info);
02996   XSetCursorState(display,windows,MagickFalse);
02997   return(status != 0 ? MagickTrue : MagickFalse);
02998 }
02999 #else
03000 
03001 /*
03002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03003 %                                                                             %
03004 %                                                                             %
03005 %                                                                             %
03006 +   A n i m a t e I m a g e s                                                 %
03007 %                                                                             %
03008 %                                                                             %
03009 %                                                                             %
03010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03011 %
03012 %  AnimateImages() repeatedly displays an image sequence to any X window
03013 %  screen.  It returns a value other than 0 if successful.  Check the
03014 %  exception member of image to determine the reason for any failure.
03015 %
03016 %  The format of the AnimateImages method is:
03017 %
03018 %      MagickBooleanType AnimateImages(const ImageInfo *image_info,
03019 %        Image *images)
03020 %
03021 %  A description of each parameter follows:
03022 %
03023 %    o image_info: the image info.
03024 %
03025 %    o image: the image.
03026 %
03027 %    o exception: return any errors or warnings in this structure.
03028 %
03029 */
03030 MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
03031   Image *image,ExceptionInfo *exception)
03032 {
03033   assert(image_info != (const ImageInfo *) NULL);
03034   assert(image_info->signature == MagickSignature);
03035   assert(image != (Image *) NULL);
03036   assert(image->signature == MagickSignature);
03037   if (image->debug != MagickFalse)
03038     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03039   (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
03040     "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename);
03041   return(MagickFalse);
03042 }
03043 #endif