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