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