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