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