MagickCore  7.1.0
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 0x0004
86 #define ForwardAnimationState 0x0008
87 #define HighlightState 0x0010
88 #define PlayAnimationState 0x0020
89 #define RepeatAnimationState 0x0040
90 #define StepAnimationState 0x0080
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 } CommandType;
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 CommandType,
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 CommandType command_type,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 CommandType command_type,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 (command_type)
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 (command_type == StepBackwardCommand)
523  *state&=(~ForwardAnimationState);
524  if (command_type == 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/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/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 CommandType
1266  CommandMenus[]=
1267  {
1268  NullCommand,
1269  NullCommand,
1270  NullCommand,
1271  NullCommand,
1272  InfoCommand,
1273  QuitCommand
1274  },
1275  CommandTypes[]=
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 CommandType
1302  *Commands[MagickMenus]=
1303  {
1304  CommandTypes,
1305  SpeedCommands,
1306  DirectionCommands,
1307  HelpCommands
1308  };
1309 
1310  char
1311  command[MagickPathExtent],
1312  *directory,
1313  geometry[MagickPathExtent],
1314  resource_name[MagickPathExtent];
1315 
1316  CommandType
1317  command_type;
1318 
1319  Image
1320  *coalesce_image,
1321  *display_image,
1322  *image,
1323  **image_list,
1324  *nexus;
1325 
1326  int
1327  status;
1328 
1329  KeySym
1330  key_symbol;
1331 
1332  MagickStatusType
1333  context_mask,
1334  state;
1335 
1337  geometry_info;
1338 
1339  char
1340  *p;
1341 
1342  ssize_t
1343  i;
1344 
1345  ssize_t
1346  first_scene,
1347  iterations,
1348  scene;
1349 
1350  static char
1351  working_directory[MagickPathExtent];
1352 
1353  static size_t
1354  number_windows;
1355 
1356  static XWindowInfo
1357  *magick_windows[MaXWindows];
1358 
1359  time_t
1360  timestamp;
1361 
1362  size_t
1363  delay,
1364  number_scenes;
1365 
1366  WarningHandler
1367  warning_handler;
1368 
1369  Window
1370  root_window;
1371 
1372  XClassHint
1373  *class_hints;
1374 
1375  XEvent
1376  event;
1377 
1378  XFontStruct
1379  *font_info;
1380 
1381  XGCValues
1382  context_values;
1383 
1384  XPixelInfo
1385  *icon_pixel,
1386  *pixel;
1387 
1388  XResourceInfo
1389  *icon_resources;
1390 
1391  XStandardColormap
1392  *icon_map,
1393  *map_info;
1394 
1395  XTextProperty
1396  window_name;
1397 
1398  XVisualInfo
1399  *icon_visual,
1400  *visual_info;
1401 
1402  XWindowChanges
1403  window_changes;
1404 
1405  XWindows
1406  *windows;
1407 
1408  XWMHints
1409  *manager_hints;
1410 
1411  assert(images != (Image *) NULL);
1412  assert(images->signature == MagickCoreSignature);
1413  if (IsEventLogging() != MagickFalse)
1414  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1415  warning_handler=(WarningHandler) NULL;
1416  windows=XSetWindows((XWindows *) ~0);
1417  if (windows != (XWindows *) NULL)
1418  {
1419  int
1420  status;
1421 
1422  if (*working_directory == '\0')
1423  (void) CopyMagickString(working_directory,".",MagickPathExtent);
1424  status=chdir(working_directory);
1425  if (status == -1)
1426  (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
1427  "UnableToOpenFile","%s",working_directory);
1428  warning_handler=resource_info->display_warnings ?
1429  SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
1430  warning_handler=resource_info->display_warnings ?
1431  SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
1432  }
1433  else
1434  {
1435  Image
1436  *p;
1437 
1438  /*
1439  Initialize window structure.
1440  */
1441  for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1442  {
1443  if (p->storage_class == DirectClass)
1444  {
1445  resource_info->colors=0;
1446  break;
1447  }
1448  if (p->colors > resource_info->colors)
1449  resource_info->colors=p->colors;
1450  }
1451  windows=XSetWindows(XInitializeWindows(display,resource_info));
1452  if (windows == (XWindows *) NULL)
1453  ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
1454  images->filename);
1455  /*
1456  Initialize window id's.
1457  */
1458  number_windows=0;
1459  magick_windows[number_windows++]=(&windows->icon);
1460  magick_windows[number_windows++]=(&windows->backdrop);
1461  magick_windows[number_windows++]=(&windows->image);
1462  magick_windows[number_windows++]=(&windows->info);
1463  magick_windows[number_windows++]=(&windows->command);
1464  magick_windows[number_windows++]=(&windows->widget);
1465  magick_windows[number_windows++]=(&windows->popup);
1466  for (i=0; i < (ssize_t) number_windows; i++)
1467  magick_windows[i]->id=(Window) NULL;
1468  }
1469  /*
1470  Initialize font info.
1471  */
1472  if (windows->font_info != (XFontStruct *) NULL)
1473  (void) XFreeFont(display,windows->font_info);
1474  windows->font_info=XBestFont(display,resource_info,MagickFalse);
1475  if (windows->font_info == (XFontStruct *) NULL)
1476  ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
1477  resource_info->font);
1478  /*
1479  Initialize Standard Colormap.
1480  */
1481  map_info=windows->map_info;
1482  icon_map=windows->icon_map;
1483  visual_info=windows->visual_info;
1484  icon_visual=windows->icon_visual;
1485  pixel=windows->pixel_info;
1486  icon_pixel=windows->icon_pixel;
1487  font_info=windows->font_info;
1488  icon_resources=windows->icon_resources;
1489  class_hints=windows->class_hints;
1490  manager_hints=windows->manager_hints;
1491  root_window=XRootWindow(display,visual_info->screen);
1492  coalesce_image=CoalesceImages(images,exception);
1493  if (coalesce_image == (Image *) NULL)
1494  ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
1495  images->filename);
1496  images=coalesce_image;
1497  if (resource_info->map_type == (char *) NULL)
1498  if ((visual_info->klass != TrueColor) &&
1499  (visual_info->klass != DirectColor))
1500  {
1501  Image
1502  *next;
1503 
1504  /*
1505  Determine if the sequence of images has the identical colormap.
1506  */
1507  for (next=images; next != (Image *) NULL; )
1508  {
1509  next->alpha_trait=UndefinedPixelTrait;
1510  if ((next->storage_class == DirectClass) ||
1511  (next->colors != images->colors) ||
1512  (next->colors > (size_t) visual_info->colormap_size))
1513  break;
1514  for (i=0; i < (ssize_t) images->colors; i++)
1515  if (IsPixelInfoEquivalent(next->colormap+i,images->colormap+i) == MagickFalse)
1516  break;
1517  if (i < (ssize_t) images->colors)
1518  break;
1519  next=GetNextImageInList(next);
1520  }
1521  if (next != (Image *) NULL)
1522  (void) RemapImages(resource_info->quantize_info,images,
1523  (Image *) NULL,exception);
1524  }
1525  /*
1526  Sort images by increasing scene number.
1527  */
1528  number_scenes=GetImageListLength(images);
1529  image_list=ImageListToArray(images,exception);
1530  if (image_list == (Image **) NULL)
1531  ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1532  images->filename);
1533  for (scene=0; scene < (ssize_t) number_scenes; scene++)
1534  if (image_list[scene]->scene == 0)
1535  break;
1536  if (scene == (ssize_t) number_scenes)
1537  qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
1538  /*
1539  Initialize Standard Colormap.
1540  */
1541  nexus=NewImageList();
1542  display_image=image_list[0];
1543  for (scene=0; scene < (ssize_t) number_scenes; scene++)
1544  {
1545  if ((resource_info->map_type != (char *) NULL) ||
1546  (visual_info->klass == TrueColor) ||
1547  (visual_info->klass == DirectColor))
1548  (void) SetImageType(image_list[scene],image_list[scene]->alpha_trait ==
1549  BlendPixelTrait ? TrueColorType : TrueColorAlphaType,exception);
1550  if ((display_image->columns < image_list[scene]->columns) &&
1551  (display_image->rows < image_list[scene]->rows))
1552  display_image=image_list[scene];
1553  }
1554  if (resource_info->debug != MagickFalse)
1555  {
1556  (void) LogMagickEvent(X11Event,GetMagickModule(),
1557  "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,(double)
1558  display_image->scene,(double) display_image->columns,(double)
1559  display_image->rows);
1560  if (display_image->colors != 0)
1561  (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1562  display_image->colors);
1563  (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1564  display_image->magick);
1565  }
1566  XMakeStandardColormap(display,visual_info,resource_info,display_image,
1567  map_info,pixel,exception);
1568  /*
1569  Initialize graphic context.
1570  */
1571  windows->context.id=(Window) NULL;
1572  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1573  resource_info,&windows->context);
1574  (void) CloneString(&class_hints->res_name,resource_info->client_name);
1575  (void) CloneString(&class_hints->res_class,resource_info->client_name);
1576  class_hints->res_class[0]=(char) LocaleToUppercase((int)
1577  class_hints->res_class[0]);
1578  manager_hints->flags=InputHint | StateHint;
1579  manager_hints->input=MagickFalse;
1580  manager_hints->initial_state=WithdrawnState;
1581  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1582  &windows->context);
1583  if (resource_info->debug != MagickFalse)
1584  (void) LogMagickEvent(X11Event,GetMagickModule(),
1585  "Window id: 0x%lx (context)",windows->context.id);
1586  context_values.background=pixel->background_color.pixel;
1587  context_values.font=font_info->fid;
1588  context_values.foreground=pixel->foreground_color.pixel;
1589  context_values.graphics_exposures=MagickFalse;
1590  context_mask=(MagickStatusType)
1591  (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
1592  if (pixel->annotate_context != (GC) NULL)
1593  (void) XFreeGC(display,pixel->annotate_context);
1594  pixel->annotate_context=
1595  XCreateGC(display,windows->context.id,context_mask,&context_values);
1596  if (pixel->annotate_context == (GC) NULL)
1597  ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1598  images->filename);
1599  context_values.background=pixel->depth_color.pixel;
1600  if (pixel->widget_context != (GC) NULL)
1601  (void) XFreeGC(display,pixel->widget_context);
1602  pixel->widget_context=
1603  XCreateGC(display,windows->context.id,context_mask,&context_values);
1604  if (pixel->widget_context == (GC) NULL)
1605  ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1606  images->filename);
1607  context_values.background=pixel->foreground_color.pixel;
1608  context_values.foreground=pixel->background_color.pixel;
1609  context_values.plane_mask=
1610  context_values.background ^ context_values.foreground;
1611  if (pixel->highlight_context != (GC) NULL)
1612  (void) XFreeGC(display,pixel->highlight_context);
1613  pixel->highlight_context=XCreateGC(display,windows->context.id,
1614  (size_t) (context_mask | GCPlaneMask),&context_values);
1615  if (pixel->highlight_context == (GC) NULL)
1616  ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1617  images->filename);
1618  (void) XDestroyWindow(display,windows->context.id);
1619  /*
1620  Initialize icon window.
1621  */
1622  XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
1623  icon_resources,&windows->icon);
1624  windows->icon.geometry=resource_info->icon_geometry;
1625  XBestIconSize(display,&windows->icon,display_image);
1626  windows->icon.attributes.colormap=
1627  XDefaultColormap(display,icon_visual->screen);
1628  windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
1629  manager_hints->flags=InputHint | StateHint;
1630  manager_hints->input=MagickFalse;
1631  manager_hints->initial_state=IconicState;
1632  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1633  &windows->icon);
1634  if (resource_info->debug != MagickFalse)
1635  (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
1636  windows->icon.id);
1637  /*
1638  Initialize graphic context for icon window.
1639  */
1640  if (icon_pixel->annotate_context != (GC) NULL)
1641  (void) XFreeGC(display,icon_pixel->annotate_context);
1642  context_values.background=icon_pixel->background_color.pixel;
1643  context_values.foreground=icon_pixel->foreground_color.pixel;
1644  icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
1645  (size_t) (GCBackground | GCForeground),&context_values);
1646  if (icon_pixel->annotate_context == (GC) NULL)
1647  ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1648  images->filename);
1649  windows->icon.annotate_context=icon_pixel->annotate_context;
1650  /*
1651  Initialize Image window.
1652  */
1653  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1654  resource_info,&windows->image);
1655  windows->image.shape=MagickTrue; /* non-rectangular shape hint */
1656  if (resource_info->use_shared_memory == MagickFalse)
1657  windows->image.shared_memory=MagickFalse;
1658  if (resource_info->title != (char *) NULL)
1659  {
1660  char
1661  *title;
1662 
1663  title=InterpretImageProperties(resource_info->image_info,display_image,
1664  resource_info->title,exception);
1665  (void) CloneString(&windows->image.name,title);
1666  (void) CloneString(&windows->image.icon_name,title);
1667  title=DestroyString(title);
1668  }
1669  else
1670  {
1671  char
1672  filename[MagickPathExtent],
1673  window_name[MagickPathExtent];
1674 
1675  /*
1676  Window name is the base of the filename.
1677  */
1678  GetPathComponent(display_image->magick_filename,TailPath,filename);
1679  (void) FormatLocaleString(window_name,MagickPathExtent,
1680  "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,(double)
1681  display_image->scene,(double) number_scenes);
1682  (void) CloneString(&windows->image.name,window_name);
1683  (void) CloneString(&windows->image.icon_name,filename);
1684  }
1685  if (resource_info->immutable != MagickFalse)
1686  windows->image.immutable=MagickTrue;
1687  windows->image.shape=MagickTrue;
1688  windows->image.geometry=resource_info->image_geometry;
1689  (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
1690  XDisplayWidth(display,visual_info->screen),
1691  XDisplayHeight(display,visual_info->screen));
1692  geometry_info.width=display_image->columns;
1693  geometry_info.height=display_image->rows;
1694  geometry_info.x=0;
1695  geometry_info.y=0;
1696  (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
1697  &geometry_info.width,&geometry_info.height);
1698  windows->image.width=(unsigned int) geometry_info.width;
1699  windows->image.height=(unsigned int) geometry_info.height;
1700  windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1701  ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1702  KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
1703  PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
1704  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1705  resource_info,&windows->backdrop);
1706  if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
1707  {
1708  /*
1709  Initialize backdrop window.
1710  */
1711  windows->backdrop.x=0;
1712  windows->backdrop.y=0;
1713  (void) CloneString(&windows->backdrop.name,"ImageMagick Backdrop");
1714  windows->backdrop.flags=(size_t) (USSize | USPosition);
1715  windows->backdrop.width=(unsigned int)
1716  XDisplayWidth(display,visual_info->screen);
1717  windows->backdrop.height=(unsigned int)
1718  XDisplayHeight(display,visual_info->screen);
1719  windows->backdrop.border_width=0;
1720  windows->backdrop.immutable=MagickTrue;
1721  windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
1722  ButtonReleaseMask;
1723  windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
1724  StructureNotifyMask;
1725  manager_hints->flags=IconWindowHint | InputHint | StateHint;
1726  manager_hints->icon_window=windows->icon.id;
1727  manager_hints->input=MagickTrue;
1728  manager_hints->initial_state=
1729  resource_info->iconic ? IconicState : NormalState;
1730  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1731  &windows->backdrop);
1732  if (resource_info->debug != MagickFalse)
1733  (void) LogMagickEvent(X11Event,GetMagickModule(),
1734  "Window id: 0x%lx (backdrop)",windows->backdrop.id);
1735  (void) XMapWindow(display,windows->backdrop.id);
1736  (void) XClearWindow(display,windows->backdrop.id);
1737  if (windows->image.id != (Window) NULL)
1738  {
1739  (void) XDestroyWindow(display,windows->image.id);
1740  windows->image.id=(Window) NULL;
1741  }
1742  /*
1743  Position image in the center the backdrop.
1744  */
1745  windows->image.flags|=USPosition;
1746  windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
1747  (windows->image.width/2);
1748  windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
1749  (windows->image.height/2);
1750  }
1751  manager_hints->flags=IconWindowHint | InputHint | StateHint;
1752  manager_hints->icon_window=windows->icon.id;
1753  manager_hints->input=MagickTrue;
1754  manager_hints->initial_state=
1755  resource_info->iconic ? IconicState : NormalState;
1756  if (windows->group_leader.id != (Window) NULL)
1757  {
1758  /*
1759  Follow the leader.
1760  */
1761  manager_hints->flags|=(MagickStatusType) WindowGroupHint;
1762  manager_hints->window_group=windows->group_leader.id;
1763  (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
1764  if (resource_info->debug != MagickFalse)
1765  (void) LogMagickEvent(X11Event,GetMagickModule(),
1766  "Window id: 0x%lx (group leader)",windows->group_leader.id);
1767  }
1768  XMakeWindow(display,
1769  (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
1770  argv,argc,class_hints,manager_hints,&windows->image);
1771  (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
1772  XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
1773  if (windows->group_leader.id != (Window) NULL)
1774  (void) XSetTransientForHint(display,windows->image.id,
1775  windows->group_leader.id);
1776  if (resource_info->debug != MagickFalse)
1777  (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
1778  windows->image.id);
1779  /*
1780  Initialize Info widget.
1781  */
1782  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1783  resource_info,&windows->info);
1784  (void) CloneString(&windows->info.name,"Info");
1785  (void) CloneString(&windows->info.icon_name,"Info");
1786  windows->info.border_width=1;
1787  windows->info.x=2;
1788  windows->info.y=2;
1789  windows->info.flags|=PPosition;
1790  windows->info.attributes.win_gravity=UnmapGravity;
1791  windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
1792  StructureNotifyMask;
1793  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1794  manager_hints->input=MagickFalse;
1795  manager_hints->initial_state=NormalState;
1796  manager_hints->window_group=windows->image.id;
1797  XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
1798  &windows->info);
1799  windows->info.highlight_stipple=XCreateBitmapFromData(display,
1800  windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1801  windows->info.shadow_stipple=XCreateBitmapFromData(display,
1802  windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1803  (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
1804  if (windows->image.mapped)
1805  (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
1806  if (resource_info->debug != MagickFalse)
1807  (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
1808  windows->info.id);
1809  /*
1810  Initialize Command widget.
1811  */
1812  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1813  resource_info,&windows->command);
1814  windows->command.data=MagickMenus;
1815  (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
1816  (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command",
1817  resource_info->client_name);
1818  windows->command.geometry=XGetResourceClass(resource_info->resource_database,
1819  resource_name,"geometry",(char *) NULL);
1820  (void) CloneString(&windows->command.name,MagickTitle);
1821  windows->command.border_width=0;
1822  windows->command.flags|=PPosition;
1823  windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1824  ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
1825  OwnerGrabButtonMask | StructureNotifyMask;
1826  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1827  manager_hints->input=MagickTrue;
1828  manager_hints->initial_state=NormalState;
1829  manager_hints->window_group=windows->image.id;
1830  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1831  &windows->command);
1832  windows->command.highlight_stipple=XCreateBitmapFromData(display,
1833  windows->command.id,(char *) HighlightBitmap,HighlightWidth,
1834  HighlightHeight);
1835  windows->command.shadow_stipple=XCreateBitmapFromData(display,
1836  windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1837  (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
1838  if (resource_info->debug != MagickFalse)
1839  (void) LogMagickEvent(X11Event,GetMagickModule(),
1840  "Window id: 0x%lx (command)",windows->command.id);
1841  /*
1842  Initialize Widget window.
1843  */
1844  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1845  resource_info,&windows->widget);
1846  (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget",
1847  resource_info->client_name);
1848  windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
1849  resource_name,"geometry",(char *) NULL);
1850  windows->widget.border_width=0;
1851  windows->widget.flags|=PPosition;
1852  windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1853  ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1854  KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
1855  StructureNotifyMask;
1856  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1857  manager_hints->input=MagickTrue;
1858  manager_hints->initial_state=NormalState;
1859  manager_hints->window_group=windows->image.id;
1860  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1861  &windows->widget);
1862  windows->widget.highlight_stipple=XCreateBitmapFromData(display,
1863  windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1864  windows->widget.shadow_stipple=XCreateBitmapFromData(display,
1865  windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1866  (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
1867  if (resource_info->debug != MagickFalse)
1868  (void) LogMagickEvent(X11Event,GetMagickModule(),
1869  "Window id: 0x%lx (widget)",windows->widget.id);
1870  /*
1871  Initialize popup window.
1872  */
1873  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1874  resource_info,&windows->popup);
1875  windows->popup.border_width=0;
1876  windows->popup.flags|=PPosition;
1877  windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1878  ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1879  KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
1880  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1881  manager_hints->input=MagickTrue;
1882  manager_hints->initial_state=NormalState;
1883  manager_hints->window_group=windows->image.id;
1884  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1885  &windows->popup);
1886  windows->popup.highlight_stipple=XCreateBitmapFromData(display,
1887  windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1888  windows->popup.shadow_stipple=XCreateBitmapFromData(display,
1889  windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1890  (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
1891  if (resource_info->debug != MagickFalse)
1892  (void) LogMagickEvent(X11Event,GetMagickModule(),
1893  "Window id: 0x%lx (pop up)",windows->popup.id);
1894  /*
1895  Set out progress and warning handlers.
1896  */
1897  if (warning_handler == (WarningHandler) NULL)
1898  {
1899  warning_handler=resource_info->display_warnings ?
1900  SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
1901  warning_handler=resource_info->display_warnings ?
1902  SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
1903  }
1904  /*
1905  Initialize X image structure.
1906  */
1907  windows->image.x=0;
1908  windows->image.y=0;
1909  /*
1910  Initialize image pixmaps structure.
1911  */
1912  window_changes.width=(int) windows->image.width;
1913  window_changes.height=(int) windows->image.height;
1914  (void) XReconfigureWMWindow(display,windows->image.id,windows->command.screen,
1915  (unsigned int) (CWWidth | CWHeight),&window_changes);
1916  windows->image.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1917  sizeof(*windows->image.pixmaps));
1918  windows->image.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1919  sizeof(*windows->image.pixmaps));
1920  if ((windows->image.pixmaps == (Pixmap *) NULL) ||
1921  (windows->image.matte_pixmaps == (Pixmap *) NULL))
1922  ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1923  images->filename);
1924  if ((windows->image.mapped == MagickFalse) ||
1925  (windows->backdrop.id != (Window) NULL))
1926  (void) XMapWindow(display,windows->image.id);
1927  XSetCursorState(display,windows,MagickTrue);
1928  for (scene=0; scene < (ssize_t) number_scenes; scene++)
1929  {
1930  unsigned int
1931  columns,
1932  rows;
1933 
1934  /*
1935  Create X image.
1936  */
1937  windows->image.pixmap=(Pixmap) NULL;
1938  windows->image.matte_pixmap=(Pixmap) NULL;
1939  if ((resource_info->map_type != (char *) NULL) ||
1940  (visual_info->klass == TrueColor) ||
1941  (visual_info->klass == DirectColor))
1942  if (image_list[scene]->storage_class == PseudoClass)
1943  XGetPixelInfo(display,visual_info,map_info,resource_info,
1944  image_list[scene],windows->image.pixel_info);
1945  columns=(unsigned int) image_list[scene]->columns;
1946  rows=(unsigned int) image_list[scene]->rows;
1947  if ((image_list[scene]->columns != columns) ||
1948  (image_list[scene]->rows != rows))
1949  ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1950  image_list[scene]->filename);
1951  status=XMakeImage(display,resource_info,&windows->image,image_list[scene],
1952  columns,rows,exception);
1953  if (status == MagickFalse)
1954  ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1955  images->filename);
1956  if (image_list[scene]->debug != MagickFalse)
1957  {
1958  (void) LogMagickEvent(X11Event,GetMagickModule(),
1959  "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
1960  image_list[scene]->filename,(double) columns,(double) rows);
1961  if (image_list[scene]->colors != 0)
1962  (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1963  image_list[scene]->colors);
1964  (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1965  image_list[scene]->magick);
1966  }
1967  /*
1968  Window name is the base of the filename.
1969  */
1970  if (resource_info->title != (char *) NULL)
1971  {
1972  char
1973  *title;
1974 
1975  title=InterpretImageProperties(resource_info->image_info,
1976  image_list[scene],resource_info->title,exception);
1977  (void) CloneString(&windows->image.name,title);
1978  title=DestroyString(title);
1979  }
1980  else
1981  {
1982  char
1983  window_name[MagickPathExtent];
1984 
1985  p=image_list[scene]->magick_filename+
1986  strlen(image_list[scene]->magick_filename)-1;
1987  while ((p > image_list[scene]->magick_filename) && (*(p-1) != '/'))
1988  p--;
1989  (void) FormatLocaleString(window_name,MagickPathExtent,
1990  "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double) scene+1,
1991  (double) number_scenes);
1992  (void) CloneString(&windows->image.name,window_name);
1993  }
1994  status=XStringListToTextProperty(&windows->image.name,1,&window_name);
1995  if (status != Success)
1996  {
1997  XSetWMName(display,windows->image.id,&window_name);
1998  (void) XFree((void *) window_name.value);
1999  }
2000  windows->image.pixmaps[scene]=windows->image.pixmap;
2001  windows->image.matte_pixmaps[scene]=windows->image.matte_pixmap;
2002  if (scene == 0)
2003  {
2004  event.xexpose.x=0;
2005  event.xexpose.y=0;
2006  event.xexpose.width=(int) image_list[scene]->columns;
2007  event.xexpose.height=(int) image_list[scene]->rows;
2008  XRefreshWindow(display,&windows->image,&event);
2009  (void) XSync(display,MagickFalse);
2010  }
2011  }
2012  XSetCursorState(display,windows,MagickFalse);
2013  if (windows->command.mapped)
2014  (void) XMapRaised(display,windows->command.id);
2015  /*
2016  Respond to events.
2017  */
2018  nexus=NewImageList();
2019  scene=0;
2020  first_scene=0;
2021  iterations=0;
2022  image=image_list[0];
2023  state=(MagickStatusType) (ForwardAnimationState | RepeatAnimationState);
2024  (void) XMagickCommand(display,resource_info,windows,PlayCommand,&images,
2025  &state,exception);
2026  do
2027  {
2028  if (XEventsQueued(display,QueuedAfterFlush) == 0)
2029  if ((state & PlayAnimationState) || (state & StepAnimationState))
2030  {
2031  MagickBooleanType
2032  pause;
2033 
2034  pause=MagickFalse;
2035  delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
2036  XDelay(display,resource_info->delay*(delay == 0 ? 10 : delay));
2037  if (state & ForwardAnimationState)
2038  {
2039  /*
2040  Forward animation: increment scene number.
2041  */
2042  if (scene < ((ssize_t) number_scenes-1))
2043  scene++;
2044  else
2045  {
2046  iterations++;
2047  if (iterations == (ssize_t) image_list[0]->iterations)
2048  {
2049  iterations=0;
2050  state|=ExitState;
2051  }
2052  if ((state & AutoReverseAnimationState) != 0)
2053  {
2054  state&=(~ForwardAnimationState);
2055  scene--;
2056  }
2057  else
2058  {
2059  if ((state & RepeatAnimationState) == 0)
2060  state&=(~PlayAnimationState);
2061  scene=first_scene;
2062  pause=MagickTrue;
2063  }
2064  }
2065  }
2066  else
2067  {
2068  /*
2069  Reverse animation: decrement scene number.
2070  */
2071  if (scene > first_scene)
2072  scene--;
2073  else
2074  {
2075  iterations++;
2076  if (iterations == (ssize_t) image_list[0]->iterations)
2077  {
2078  iterations=0;
2079  state&=(~RepeatAnimationState);
2080  }
2081  if (state & AutoReverseAnimationState)
2082  {
2083  state|=ForwardAnimationState;
2084  scene=first_scene;
2085  pause=MagickTrue;
2086  }
2087  else
2088  {
2089  if ((state & RepeatAnimationState) == MagickFalse)
2090  state&=(~PlayAnimationState);
2091  scene=(ssize_t) number_scenes-1;
2092  }
2093  }
2094  }
2095  scene=MagickMax(scene,0);
2096  image=image_list[scene];
2097  if ((image != (Image *) NULL) && (image->start_loop != 0))
2098  first_scene=scene;
2099  if ((state & StepAnimationState) ||
2100  (resource_info->title != (char *) NULL))
2101  {
2102  char
2103  name[MagickPathExtent];
2104 
2105  /*
2106  Update window title.
2107  */
2108  p=image_list[scene]->filename+
2109  strlen(image_list[scene]->filename)-1;
2110  while ((p > image_list[scene]->filename) && (*(p-1) != '/'))
2111  p--;
2112  (void) FormatLocaleString(name,MagickPathExtent,
2113  "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double)
2114  scene+1,(double) number_scenes);
2115  (void) CloneString(&windows->image.name,name);
2116  if (resource_info->title != (char *) NULL)
2117  {
2118  char
2119  *title;
2120 
2121  title=InterpretImageProperties(resource_info->image_info,
2122  image,resource_info->title,exception);
2123  (void) CloneString(&windows->image.name,title);
2124  title=DestroyString(title);
2125  }
2126  status=XStringListToTextProperty(&windows->image.name,1,
2127  &window_name);
2128  if (status != Success)
2129  {
2130  XSetWMName(display,windows->image.id,&window_name);
2131  (void) XFree((void *) window_name.value);
2132  }
2133  }
2134  /*
2135  Copy X pixmap to Image window.
2136  */
2137  XGetPixelInfo(display,visual_info,map_info,resource_info,
2138  image_list[scene],windows->image.pixel_info);
2139  if (image != (Image *) NULL)
2140  {
2141  windows->image.ximage->width=(int) image->columns;
2142  windows->image.ximage->height=(int) image->rows;
2143  }
2144  windows->image.pixmap=windows->image.pixmaps[scene];
2145  windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
2146  event.xexpose.x=0;
2147  event.xexpose.y=0;
2148  event.xexpose.width=(int) image->columns;
2149  event.xexpose.height=(int) image->rows;
2150  if ((state & ExitState) == 0)
2151  {
2152  XRefreshWindow(display,&windows->image,&event);
2153  (void) XSync(display,MagickFalse);
2154  }
2155  state&=(~StepAnimationState);
2156  if (pause != MagickFalse)
2157  for (i=0; i < (ssize_t) resource_info->pause; i++)
2158  {
2159  int
2160  status;
2161 
2162  status=XCheckTypedWindowEvent(display,windows->image.id,KeyPress,
2163  &event);
2164  if (status != 0)
2165  {
2166  int
2167  length;
2168 
2169  length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2170  sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2171  *(command+length)='\0';
2172  if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
2173  {
2174  XClientMessage(display,windows->image.id,
2175  windows->im_protocols,windows->im_exit,CurrentTime);
2176  break;
2177  }
2178  }
2179  MagickDelay(1000);
2180  }
2181  continue;
2182  }
2183  /*
2184  Handle a window event.
2185  */
2186  timestamp=GetMagickTime();
2187  (void) XNextEvent(display,&event);
2188  if (windows->image.stasis == MagickFalse)
2189  windows->image.stasis=(GetMagickTime()-timestamp) > 0 ?
2190  MagickTrue : MagickFalse;
2191  if (event.xany.window == windows->command.id)
2192  {
2193  int
2194  id;
2195 
2196  /*
2197  Select a command from the Command widget.
2198  */
2199  id=XCommandWidget(display,windows,CommandMenu,&event);
2200  if (id < 0)
2201  continue;
2202  (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent);
2203  command_type=CommandMenus[id];
2204  if (id < MagickMenus)
2205  {
2206  int
2207  entry;
2208 
2209  /*
2210  Select a command from a pop-up menu.
2211  */
2212  entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
2213  command);
2214  if (entry < 0)
2215  continue;
2216  (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent);
2217  command_type=Commands[id][entry];
2218  }
2219  if (command_type != NullCommand)
2220  nexus=XMagickCommand(display,resource_info,windows,
2221  command_type,&image,&state,exception);
2222  continue;
2223  }
2224  switch (event.type)
2225  {
2226  case ButtonPress:
2227  {
2228  if (resource_info->debug != MagickFalse)
2229  (void) LogMagickEvent(X11Event,GetMagickModule(),
2230  "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
2231  event.xbutton.button,event.xbutton.x,event.xbutton.y);
2232  if ((event.xbutton.button == Button3) &&
2233  (event.xbutton.state & Mod1Mask))
2234  {
2235  /*
2236  Convert Alt-Button3 to Button2.
2237  */
2238  event.xbutton.button=Button2;
2239  event.xbutton.state&=(~Mod1Mask);
2240  }
2241  if (event.xbutton.window == windows->backdrop.id)
2242  {
2243  (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
2244  event.xbutton.time);
2245  break;
2246  }
2247  if (event.xbutton.window == windows->image.id)
2248  {
2249  if (resource_info->immutable != MagickFalse)
2250  {
2251  state|=ExitState;
2252  break;
2253  }
2254  /*
2255  Map/unmap Command widget.
2256  */
2257  if (windows->command.mapped)
2258  (void) XWithdrawWindow(display,windows->command.id,
2259  windows->command.screen);
2260  else
2261  {
2262  (void) XCommandWidget(display,windows,CommandMenu,
2263  (XEvent *) NULL);
2264  (void) XMapRaised(display,windows->command.id);
2265  }
2266  }
2267  break;
2268  }
2269  case ButtonRelease:
2270  {
2271  if (resource_info->debug != MagickFalse)
2272  (void) LogMagickEvent(X11Event,GetMagickModule(),
2273  "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
2274  event.xbutton.button,event.xbutton.x,event.xbutton.y);
2275  break;
2276  }
2277  case ClientMessage:
2278  {
2279  if (resource_info->debug != MagickFalse)
2280  (void) LogMagickEvent(X11Event,GetMagickModule(),
2281  "Client Message: 0x%lx 0x%lx %d 0x%lx",(unsigned long)
2282  event.xclient.window,(unsigned long) event.xclient.message_type,
2283  event.xclient.format,(unsigned long) event.xclient.data.l[0]);
2284  if (event.xclient.message_type == windows->im_protocols)
2285  {
2286  if (*event.xclient.data.l == (long) windows->im_update_colormap)
2287  {
2288  /*
2289  Update graphic context and window colormap.
2290  */
2291  for (i=0; i < (ssize_t) number_windows; i++)
2292  {
2293  if (magick_windows[i]->id == windows->icon.id)
2294  continue;
2295  context_values.background=pixel->background_color.pixel;
2296  context_values.foreground=pixel->foreground_color.pixel;
2297  (void) XChangeGC(display,magick_windows[i]->annotate_context,
2298  context_mask,&context_values);
2299  (void) XChangeGC(display,magick_windows[i]->widget_context,
2300  context_mask,&context_values);
2301  context_values.background=pixel->foreground_color.pixel;
2302  context_values.foreground=pixel->background_color.pixel;
2303  context_values.plane_mask=
2304  context_values.background ^ context_values.foreground;
2305  (void) XChangeGC(display,magick_windows[i]->highlight_context,
2306  (size_t) (context_mask | GCPlaneMask),
2307  &context_values);
2308  magick_windows[i]->attributes.background_pixel=
2309  pixel->background_color.pixel;
2310  magick_windows[i]->attributes.border_pixel=
2311  pixel->border_color.pixel;
2312  magick_windows[i]->attributes.colormap=map_info->colormap;
2313  (void) XChangeWindowAttributes(display,magick_windows[i]->id,
2314  (unsigned long) magick_windows[i]->mask,
2315  &magick_windows[i]->attributes);
2316  }
2317  if (windows->backdrop.id != (Window) NULL)
2318  (void) XInstallColormap(display,map_info->colormap);
2319  break;
2320  }
2321  if (*event.xclient.data.l == (long) windows->im_exit)
2322  {
2323  state|=ExitState;
2324  break;
2325  }
2326  break;
2327  }
2328  if (event.xclient.message_type == windows->dnd_protocols)
2329  {
2330  Atom
2331  selection,
2332  type;
2333 
2334  int
2335  format,
2336  status;
2337 
2338  unsigned char
2339  *data;
2340 
2341  unsigned long
2342  after,
2343  length;
2344 
2345  /*
2346  Display image named by the Drag-and-Drop selection.
2347  */
2348  if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
2349  break;
2350  selection=XInternAtom(display,"DndSelection",MagickFalse);
2351  status=XGetWindowProperty(display,root_window,selection,0L,2047L,
2352  MagickFalse,(Atom) AnyPropertyType,&type,&format,&length,&after,
2353  &data);
2354  if ((status != Success) || (length == 0))
2355  break;
2356  if (*event.xclient.data.l == 2)
2357  {
2358  /*
2359  Offix DND.
2360  */
2361  (void) CopyMagickString(resource_info->image_info->filename,
2362  (char *) data,MagickPathExtent);
2363  }
2364  else
2365  {
2366  /*
2367  XDND.
2368  */
2369  if (LocaleNCompare((char *) data,"file:",5) != 0)
2370  {
2371  (void) XFree((void *) data);
2372  break;
2373  }
2374  (void) CopyMagickString(resource_info->image_info->filename,
2375  ((char *) data)+5,MagickPathExtent);
2376  }
2377  nexus=ReadImage(resource_info->image_info,exception);
2378  CatchException(exception);
2379  if (nexus != (Image *) NULL)
2380  state|=ExitState;
2381  (void) XFree((void *) data);
2382  break;
2383  }
2384  /*
2385  If client window delete message, exit.
2386  */
2387  if (event.xclient.message_type != windows->wm_protocols)
2388  break;
2389  if (*event.xclient.data.l == (long) windows->wm_take_focus)
2390  {
2391  (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2392  (Time) event.xclient.data.l[1]);
2393  break;
2394  }
2395  if (*event.xclient.data.l != (long) windows->wm_delete_window)
2396  break;
2397  (void) XWithdrawWindow(display,event.xclient.window,
2398  visual_info->screen);
2399  if (event.xclient.window == windows->image.id)
2400  {
2401  state|=ExitState;
2402  break;
2403  }
2404  break;
2405  }
2406  case ConfigureNotify:
2407  {
2408  if (resource_info->debug != MagickFalse)
2409  (void) LogMagickEvent(X11Event,GetMagickModule(),
2410  "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
2411  event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
2412  event.xconfigure.y,event.xconfigure.send_event);
2413  if (event.xconfigure.window == windows->image.id)
2414  {
2415  if (event.xconfigure.send_event != 0)
2416  {
2417  XWindowChanges
2418  window_changes;
2419 
2420  /*
2421  Position the transient windows relative of the Image window.
2422  */
2423  if (windows->command.geometry == (char *) NULL)
2424  if (windows->command.mapped == MagickFalse)
2425  {
2426  windows->command.x=
2427  event.xconfigure.x-windows->command.width-25;
2428  windows->command.y=event.xconfigure.y;
2429  XConstrainWindowPosition(display,&windows->command);
2430  window_changes.x=windows->command.x;
2431  window_changes.y=windows->command.y;
2432  (void) XReconfigureWMWindow(display,windows->command.id,
2433  windows->command.screen,(unsigned int) (CWX | CWY),
2434  &window_changes);
2435  }
2436  if (windows->widget.geometry == (char *) NULL)
2437  if (windows->widget.mapped == MagickFalse)
2438  {
2439  windows->widget.x=
2440  event.xconfigure.x+event.xconfigure.width/10;
2441  windows->widget.y=
2442  event.xconfigure.y+event.xconfigure.height/10;
2443  XConstrainWindowPosition(display,&windows->widget);
2444  window_changes.x=windows->widget.x;
2445  window_changes.y=windows->widget.y;
2446  (void) XReconfigureWMWindow(display,windows->widget.id,
2447  windows->widget.screen,(unsigned int) (CWX | CWY),
2448  &window_changes);
2449  }
2450  }
2451  /*
2452  Image window has a new configuration.
2453  */
2454  windows->image.width=(unsigned int) event.xconfigure.width;
2455  windows->image.height=(unsigned int) event.xconfigure.height;
2456  break;
2457  }
2458  if (event.xconfigure.window == windows->icon.id)
2459  {
2460  /*
2461  Icon window has a new configuration.
2462  */
2463  windows->icon.width=(unsigned int) event.xconfigure.width;
2464  windows->icon.height=(unsigned int) event.xconfigure.height;
2465  break;
2466  }
2467  break;
2468  }
2469  case DestroyNotify:
2470  {
2471  /*
2472  Group leader has exited.
2473  */
2474  if (resource_info->debug != MagickFalse)
2475  (void) LogMagickEvent(X11Event,GetMagickModule(),
2476  "Destroy Notify: 0x%lx",event.xdestroywindow.window);
2477  if (event.xdestroywindow.window == windows->group_leader.id)
2478  {
2479  state|=ExitState;
2480  break;
2481  }
2482  break;
2483  }
2484  case EnterNotify:
2485  {
2486  /*
2487  Selectively install colormap.
2488  */
2489  if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2490  if (event.xcrossing.mode != NotifyUngrab)
2491  XInstallColormap(display,map_info->colormap);
2492  break;
2493  }
2494  case Expose:
2495  {
2496  if (resource_info->debug != MagickFalse)
2497  (void) LogMagickEvent(X11Event,GetMagickModule(),
2498  "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
2499  event.xexpose.width,event.xexpose.height,event.xexpose.x,
2500  event.xexpose.y);
2501  /*
2502  Repaint windows that are now exposed.
2503  */
2504  if (event.xexpose.window == windows->image.id)
2505  {
2506  windows->image.pixmap=windows->image.pixmaps[scene];
2507  windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
2508  XRefreshWindow(display,&windows->image,&event);
2509  break;
2510  }
2511  if (event.xexpose.window == windows->icon.id)
2512  if (event.xexpose.count == 0)
2513  {
2514  XRefreshWindow(display,&windows->icon,&event);
2515  break;
2516  }
2517  break;
2518  }
2519  case KeyPress:
2520  {
2521  static int
2522  length;
2523 
2524  /*
2525  Respond to a user key press.
2526  */
2527  length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2528  sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2529  *(command+length)='\0';
2530  if (resource_info->debug != MagickFalse)
2531  (void) LogMagickEvent(X11Event,GetMagickModule(),
2532  "Key press: 0x%lx (%c)",(unsigned long) key_symbol,*command);
2533  command_type=NullCommand;
2534  switch (key_symbol)
2535  {
2536  case XK_o:
2537  {
2538  if ((event.xkey.state & ControlMask) == MagickFalse)
2539  break;
2540  command_type=OpenCommand;
2541  break;
2542  }
2543  case XK_BackSpace:
2544  {
2545  command_type=StepBackwardCommand;
2546  break;
2547  }
2548  case XK_space:
2549  {
2550  command_type=StepForwardCommand;
2551  break;
2552  }
2553  case XK_less:
2554  {
2555  command_type=FasterCommand;
2556  break;
2557  }
2558  case XK_greater:
2559  {
2560  command_type=SlowerCommand;
2561  break;
2562  }
2563  case XK_F1:
2564  {
2565  command_type=HelpCommand;
2566  break;
2567  }
2568  case XK_Find:
2569  {
2570  command_type=BrowseDocumentationCommand;
2571  break;
2572  }
2573  case XK_question:
2574  {
2575  command_type=InfoCommand;
2576  break;
2577  }
2578  case XK_q:
2579  case XK_Escape:
2580  {
2581  command_type=QuitCommand;
2582  break;
2583  }
2584  default:
2585  break;
2586  }
2587  if (command_type != NullCommand)
2588  nexus=XMagickCommand(display,resource_info,windows,
2589  command_type,&image,&state,exception);
2590  break;
2591  }
2592  case KeyRelease:
2593  {
2594  /*
2595  Respond to a user key release.
2596  */
2597  (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2598  sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2599  if (resource_info->debug != MagickFalse)
2600  (void) LogMagickEvent(X11Event,GetMagickModule(),
2601  "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
2602  break;
2603  }
2604  case LeaveNotify:
2605  {
2606  /*
2607  Selectively uninstall colormap.
2608  */
2609  if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2610  if (event.xcrossing.mode != NotifyUngrab)
2611  XUninstallColormap(display,map_info->colormap);
2612  break;
2613  }
2614  case MapNotify:
2615  {
2616  if (resource_info->debug != MagickFalse)
2617  (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
2618  event.xmap.window);
2619  if (event.xmap.window == windows->backdrop.id)
2620  {
2621  (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
2622  CurrentTime);
2623  windows->backdrop.mapped=MagickTrue;
2624  break;
2625  }
2626  if (event.xmap.window == windows->image.id)
2627  {
2628  if (windows->backdrop.id != (Window) NULL)
2629  (void) XInstallColormap(display,map_info->colormap);
2630  if (LocaleCompare(image_list[0]->magick,"LOGO") == 0)
2631  {
2632  if (LocaleCompare(display_image->filename,"LOGO") == 0)
2633  nexus=XMagickCommand(display,resource_info,windows,
2634  OpenCommand,&image,&state,exception);
2635  else
2636  state|=ExitState;
2637  }
2638  windows->image.mapped=MagickTrue;
2639  break;
2640  }
2641  if (event.xmap.window == windows->info.id)
2642  {
2643  windows->info.mapped=MagickTrue;
2644  break;
2645  }
2646  if (event.xmap.window == windows->icon.id)
2647  {
2648  /*
2649  Create an icon image.
2650  */
2651  XMakeStandardColormap(display,icon_visual,icon_resources,
2652  display_image,icon_map,icon_pixel,exception);
2653  (void) XMakeImage(display,icon_resources,&windows->icon,
2654  display_image,windows->icon.width,windows->icon.height,
2655  exception);
2656  (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
2657  windows->icon.pixmap);
2658  (void) XClearWindow(display,windows->icon.id);
2659  (void) XWithdrawWindow(display,windows->info.id,
2660  windows->info.screen);
2661  windows->icon.mapped=MagickTrue;
2662  break;
2663  }
2664  if (event.xmap.window == windows->command.id)
2665  {
2666  windows->command.mapped=MagickTrue;
2667  break;
2668  }
2669  if (event.xmap.window == windows->popup.id)
2670  {
2671  windows->popup.mapped=MagickTrue;
2672  break;
2673  }
2674  if (event.xmap.window == windows->widget.id)
2675  {
2676  windows->widget.mapped=MagickTrue;
2677  break;
2678  }
2679  break;
2680  }
2681  case MappingNotify:
2682  {
2683  (void) XRefreshKeyboardMapping(&event.xmapping);
2684  break;
2685  }
2686  case NoExpose:
2687  break;
2688  case PropertyNotify:
2689  {
2690  Atom
2691  type;
2692 
2693  int
2694  format,
2695  status;
2696 
2697  unsigned char
2698  *data;
2699 
2700  unsigned long
2701  after,
2702  length;
2703 
2704  if (resource_info->debug != MagickFalse)
2705  (void) LogMagickEvent(X11Event,GetMagickModule(),
2706  "Property Notify: 0x%lx 0x%lx %d",(unsigned long)
2707  event.xproperty.window,(unsigned long) event.xproperty.atom,
2708  event.xproperty.state);
2709  if (event.xproperty.atom != windows->im_remote_command)
2710  break;
2711  /*
2712  Display image named by the remote command protocol.
2713  */
2714  status=XGetWindowProperty(display,event.xproperty.window,
2715  event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom)
2716  AnyPropertyType,&type,&format,&length,&after,&data);
2717  if ((status != Success) || (length == 0))
2718  break;
2719  (void) CopyMagickString(resource_info->image_info->filename,
2720  (char *) data,MagickPathExtent);
2721  nexus=ReadImage(resource_info->image_info,exception);
2722  CatchException(exception);
2723  if (nexus != (Image *) NULL)
2724  state|=ExitState;
2725  (void) XFree((void *) data);
2726  break;
2727  }
2728  case ReparentNotify:
2729  {
2730  if (resource_info->debug != MagickFalse)
2731  (void) LogMagickEvent(X11Event,GetMagickModule(),
2732  "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
2733  event.xreparent.window);
2734  break;
2735  }
2736  case UnmapNotify:
2737  {
2738  if (resource_info->debug != MagickFalse)
2739  (void) LogMagickEvent(X11Event,GetMagickModule(),
2740  "Unmap Notify: 0x%lx",event.xunmap.window);
2741  if (event.xunmap.window == windows->backdrop.id)
2742  {
2743  windows->backdrop.mapped=MagickFalse;
2744  break;
2745  }
2746  if (event.xunmap.window == windows->image.id)
2747  {
2748  windows->image.mapped=MagickFalse;
2749  break;
2750  }
2751  if (event.xunmap.window == windows->info.id)
2752  {
2753  windows->info.mapped=MagickFalse;
2754  break;
2755  }
2756  if (event.xunmap.window == windows->icon.id)
2757  {
2758  if (map_info->colormap == icon_map->colormap)
2759  XConfigureImageColormap(display,resource_info,windows,
2760  display_image,exception);
2761  (void) XFreeStandardColormap(display,icon_visual,icon_map,
2762  icon_pixel);
2763  windows->icon.mapped=MagickFalse;
2764  break;
2765  }
2766  if (event.xunmap.window == windows->command.id)
2767  {
2768  windows->command.mapped=MagickFalse;
2769  break;
2770  }
2771  if (event.xunmap.window == windows->popup.id)
2772  {
2773  if (windows->backdrop.id != (Window) NULL)
2774  (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2775  CurrentTime);
2776  windows->popup.mapped=MagickFalse;
2777  break;
2778  }
2779  if (event.xunmap.window == windows->widget.id)
2780  {
2781  if (windows->backdrop.id != (Window) NULL)
2782  (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2783  CurrentTime);
2784  windows->widget.mapped=MagickFalse;
2785  break;
2786  }
2787  break;
2788  }
2789  default:
2790  {
2791  if (resource_info->debug != MagickFalse)
2792  (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
2793  event.type);
2794  break;
2795  }
2796  }
2797  }
2798  while (!(state & ExitState));
2799  image_list=(Image **) RelinquishMagickMemory(image_list);
2800  images=DestroyImageList(images);
2801  if ((windows->visual_info->klass == GrayScale) ||
2802  (windows->visual_info->klass == PseudoColor) ||
2803  (windows->visual_info->klass == DirectColor))
2804  {
2805  /*
2806  Withdraw windows.
2807  */
2808  if (windows->info.mapped)
2809  (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2810  if (windows->command.mapped)
2811  (void) XWithdrawWindow(display,windows->command.id,
2812  windows->command.screen);
2813  }
2814  if (resource_info->backdrop == MagickFalse)
2815  if (windows->backdrop.mapped)
2816  {
2817  (void) XWithdrawWindow(display,windows->backdrop.id,\
2818  windows->backdrop.screen);
2819  (void) XDestroyWindow(display,windows->backdrop.id);
2820  windows->backdrop.id=(Window) NULL;
2821  (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);
2822  (void) XDestroyWindow(display,windows->image.id);
2823  windows->image.id=(Window) NULL;
2824  }
2825  XSetCursorState(display,windows,MagickTrue);
2826  XCheckRefreshWindows(display,windows);
2827  for (scene=1; scene < (ssize_t) number_scenes; scene++)
2828  {
2829  if (windows->image.pixmaps[scene] != (Pixmap) NULL)
2830  (void) XFreePixmap(display,windows->image.pixmaps[scene]);
2831  windows->image.pixmaps[scene]=(Pixmap) NULL;
2832  if (windows->image.matte_pixmaps[scene] != (Pixmap) NULL)
2833  (void) XFreePixmap(display,windows->image.matte_pixmaps[scene]);
2834  windows->image.matte_pixmaps[scene]=(Pixmap) NULL;
2835  }
2836  XSetCursorState(display,windows,MagickFalse);
2837  windows->image.pixmaps=(Pixmap *)
2838  RelinquishMagickMemory(windows->image.pixmaps);
2839  windows->image.matte_pixmaps=(Pixmap *)
2840  RelinquishMagickMemory(windows->image.matte_pixmaps);
2841  if (nexus == (Image *) NULL)
2842  {
2843  /*
2844  Free X resources.
2845  */
2846  if (windows->image.mapped != MagickFalse)
2847  (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);
2848  XDelay(display,SuspendTime);
2849  (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
2850  if (resource_info->map_type == (char *) NULL)
2851  (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
2852  DestroyXResources();
2853  }
2854  (void) XSync(display,MagickFalse);
2855  /*
2856  Restore our progress monitor and warning handlers.
2857  */
2858  (void) SetErrorHandler(warning_handler);
2859  (void) SetWarningHandler(warning_handler);
2860  /*
2861  Change to home directory.
2862  */
2863  directory=getcwd(working_directory,MagickPathExtent);
2864  (void) directory;
2865  if (*resource_info->home_directory == '\0')
2866  (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent);
2867  status=chdir(resource_info->home_directory);
2868  if (status == -1)
2869  (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
2870  "UnableToOpenFile","%s",resource_info->home_directory);
2871  return(nexus);
2872 }
2873 ␌
2874 /*
2875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876 % %
2877 % %
2878 % %
2879 + X S a v e I m a g e %
2880 % %
2881 % %
2882 % %
2883 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884 %
2885 % XSaveImage() saves an image to a file.
2886 %
2887 % The format of the XSaveImage method is:
2888 %
2889 % MagickBooleanType XSaveImage(Display *display,
2890 % XResourceInfo *resource_info,XWindows *windows,Image *image,
2891 % ExceptionInfo *exception)
2892 %
2893 % A description of each parameter follows:
2894 %
2895 % o status: Method XSaveImage return True if the image is
2896 % written. False is returned is there is a memory shortage or if the
2897 % image fails to write.
2898 %
2899 % o display: Specifies a connection to an X server; returned from
2900 % XOpenDisplay.
2901 %
2902 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2903 %
2904 % o windows: Specifies a pointer to a XWindows structure.
2905 %
2906 % o image: the image.
2907 %
2908 */
2909 static MagickBooleanType XSaveImage(Display *display,
2910  XResourceInfo *resource_info,XWindows *windows,Image *image,
2911  ExceptionInfo *exception)
2912 {
2913  char
2914  filename[MagickPathExtent];
2915 
2916  ImageInfo
2917  *image_info;
2918 
2919  MagickStatusType
2920  status;
2921 
2922  /*
2923  Request file name from user.
2924  */
2925  if (resource_info->write_filename != (char *) NULL)
2926  (void) CopyMagickString(filename,resource_info->write_filename,
2927  MagickPathExtent);
2928  else
2929  {
2930  char
2931  path[MagickPathExtent];
2932 
2933  int
2934  status;
2935 
2936  GetPathComponent(image->filename,HeadPath,path);
2937  GetPathComponent(image->filename,TailPath,filename);
2938  if (*path == '\0')
2939  (void) CopyMagickString(path,".",MagickPathExtent);
2940  status=chdir(path);
2941  if (status == -1)
2942  (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
2943  "UnableToOpenFile","%s",path);
2944  }
2945  XFileBrowserWidget(display,windows,"Save",filename);
2946  if (*filename == '\0')
2947  return(MagickTrue);
2948  if (IsPathAccessible(filename) != MagickFalse)
2949  {
2950  int
2951  status;
2952 
2953  /*
2954  File exists-- seek user's permission before overwriting.
2955  */
2956  status=XConfirmWidget(display,windows,"Overwrite",filename);
2957  if (status == 0)
2958  return(MagickTrue);
2959  }
2960  image_info=CloneImageInfo(resource_info->image_info);
2961  (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
2962  (void) SetImageInfo(image_info,1,exception);
2963  if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
2964  (LocaleCompare(image_info->magick,"JPG") == 0))
2965  {
2966  char
2967  quality[MagickPathExtent];
2968 
2969  int
2970  status;
2971 
2972  /*
2973  Request JPEG quality from user.
2974  */
2975  (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double)
2976  image_info->quality);
2977  status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
2978  quality);
2979  if (*quality == '\0')
2980  return(MagickTrue);
2981  image->quality=StringToUnsignedLong(quality);
2982  image_info->interlace=status != MagickFalse ? NoInterlace :
2983  PlaneInterlace;
2984  }
2985  if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
2986  (LocaleCompare(image_info->magick,"PDF") == 0) ||
2987  (LocaleCompare(image_info->magick,"PS") == 0) ||
2988  (LocaleCompare(image_info->magick,"PS2") == 0))
2989  {
2990  char
2991  geometry[MagickPathExtent];
2992 
2993  /*
2994  Request page geometry from user.
2995  */
2996  (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
2997  if (LocaleCompare(image_info->magick,"PDF") == 0)
2998  (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
2999  if (image_info->page != (char *) NULL)
3000  (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
3001  XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
3002  "Select page geometry:",geometry);
3003  if (*geometry != '\0')
3004  image_info->page=GetPageGeometry(geometry);
3005  }
3006  /*
3007  Write image.
3008  */
3009  image=GetFirstImageInList(image);
3010  status=WriteImages(image_info,image,filename,exception);
3011  if (status != MagickFalse)
3012  image->taint=MagickFalse;
3013  image_info=DestroyImageInfo(image_info);
3014  XSetCursorState(display,windows,MagickFalse);
3015  return(status != 0 ? MagickTrue : MagickFalse);
3016 }
3017 #else
3018 ␌
3019 /*
3020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3021 % %
3022 % %
3023 % %
3024 + A n i m a t e I m a g e s %
3025 % %
3026 % %
3027 % %
3028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3029 %
3030 % AnimateImages() repeatedly displays an image sequence to any X window
3031 % screen. It returns a value other than 0 if successful. Check the
3032 % exception member of image to determine the reason for any failure.
3033 %
3034 % The format of the AnimateImages method is:
3035 %
3036 % MagickBooleanType AnimateImages(const ImageInfo *image_info,
3037 % Image *images)
3038 %
3039 % A description of each parameter follows:
3040 %
3041 % o image_info: the image info.
3042 %
3043 % o image: the image.
3044 %
3045 % o exception: return any errors or warnings in this structure.
3046 %
3047 */
3048 MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
3049  Image *image,ExceptionInfo *exception)
3050 {
3051  assert(image_info != (const ImageInfo *) NULL);
3052  assert(image_info->signature == MagickCoreSignature);
3053  (void) image_info;
3054  assert(image != (Image *) NULL);
3055  assert(image->signature == MagickCoreSignature);
3056  if (IsEventLogging() != MagickFalse)
3057  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3058  (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
3059  "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename);
3060  return(MagickFalse);
3061 }
3062 #endif
Definition: image.h:152