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