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