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