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