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