blob: a8a6402b5da04bd2d154ec74caa8b03798d8b629 [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 */
cristy73bd4a52010-10-05 11:24:23 +0000417 filelist=(char **) AcquireMagickMemory(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;
cristyf2faecf2010-05-28 19:19:36 +0000832 pixel.pixels=(unsigned long *) 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;
cristyecd0ab52010-05-30 14:59:20 +0000950 geometry_info.x=(ssize_t) window_info.x;
951 geometry_info.y=(ssize_t) window_info.y;
cristy3ed852e2009-09-05 21:47:34 +0000952 (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(),
cristye8c25f92010-06-03 00:53:06 +0000968 "Image: %s[%.20g] %.20gx%.20g ",image_list[0]->filename,(double)
969 image_list[0]->scene,(double) image_list[0]->columns,(double)
970 image_list[0]->rows);
cristy3ed852e2009-09-05 21:47:34 +0000971 if (image_list[0]->colors != 0)
cristye8c25f92010-06-03 00:53:06 +0000972 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
973 image_list[0]->colors);
cristy3ed852e2009-09-05 21:47:34 +0000974 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
975 image_list[0]->magick);
976 }
977 /*
978 Adjust image dimensions as specified by backdrop or geometry options.
979 */
980 width=window_info.width;
981 height=window_info.height;
982 if (resources.backdrop != MagickFalse)
983 {
984 /*
985 Center image on window.
986 */
987 window_info.x=(int) (window_attributes.width/2)-
988 (window_info.ximage->width/2);
989 window_info.y=(int) (window_attributes.height/2)-
990 (window_info.ximage->height/2);
991 width=(unsigned int) window_attributes.width;
992 height=(unsigned int) window_attributes.height;
993 }
994 if (resources.image_geometry != (char *) NULL)
995 {
996 char
997 default_geometry[MaxTextExtent];
998
999 int
1000 flags,
1001 gravity;
1002
1003 XSizeHints
1004 *size_hints;
1005
1006 /*
1007 User specified geometry.
1008 */
1009 size_hints=XAllocSizeHints();
1010 if (size_hints == (XSizeHints *) NULL)
1011 ThrowXWindowFatalException(ResourceLimitFatalError,
1012 "MemoryAllocationFailed",images->filename);
1013 size_hints->flags=0L;
1014 (void) FormatMagickString(default_geometry,MaxTextExtent,"%ux%u",width,
1015 height);
1016 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
1017 default_geometry,window_info.border_width,size_hints,&window_info.x,
1018 &window_info.y,(int *) &width,(int *) &height,&gravity);
1019 if (((flags & (XValue | YValue))) != 0)
1020 {
1021 width=(unsigned int) window_attributes.width;
1022 height=(unsigned int) window_attributes.height;
1023 }
1024 (void) XFree((void *) size_hints);
1025 }
1026 /*
1027 Create the X pixmap.
1028 */
1029 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
1030 (unsigned int) height,window_info.depth);
1031 if (window_info.pixmap == (Pixmap) NULL)
1032 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
1033 images->filename);
1034 /*
1035 Display pixmap on the window.
1036 */
1037 if (((unsigned int) width > window_info.width) ||
1038 ((unsigned int) height > window_info.height))
1039 (void) XFillRectangle(display,window_info.pixmap,
1040 window_info.annotate_context,0,0,(unsigned int) width,
1041 (unsigned int) height);
1042 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
1043 window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
1044 window_info.height);
1045 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
1046 (void) XClearWindow(display,window_info.id);
1047 /*
1048 Initialize image pixmaps structure.
1049 */
1050 window_info.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1051 sizeof(*window_info.pixmaps));
1052 window_info.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1053 sizeof(*window_info.matte_pixmaps));
1054 if ((window_info.pixmaps == (Pixmap *) NULL) ||
1055 (window_info.matte_pixmaps == (Pixmap *) NULL))
1056 ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1057 images->filename);
1058 window_info.pixmaps[0]=window_info.pixmap;
1059 window_info.matte_pixmaps[0]=window_info.pixmap;
1060 for (scene=1; scene < (int) number_scenes; scene++)
1061 {
1062 unsigned int
1063 columns,
1064 rows;
1065
1066 /*
1067 Create X image.
1068 */
1069 window_info.pixmap=(Pixmap) NULL;
1070 window_info.matte_pixmap=(Pixmap) NULL;
1071 if ((resources.map_type != (char *) NULL) ||
1072 (visual_info->klass == TrueColor) ||
1073 (visual_info->klass == DirectColor))
1074 if (image_list[scene]->storage_class == PseudoClass)
1075 XGetPixelPacket(display,visual_info,map_info,&resources,
1076 image_list[scene],window_info.pixel_info);
1077 columns=(unsigned int) image_list[scene]->columns;
1078 rows=(unsigned int) image_list[scene]->rows;
1079 if ((image_list[scene]->columns != columns) ||
1080 (image_list[scene]->rows != rows))
1081 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1082 image_list[scene]->filename);
1083 status=XMakeImage(display,&resources,&window_info,image_list[scene],
1084 columns,rows);
1085 if (status == MagickFalse)
1086 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1087 images->filename);
1088 if (display_image->debug != MagickFalse)
1089 {
1090 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00001091 "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
1092 image_list[scene]->filename,(double) columns,(double) rows);
cristy3ed852e2009-09-05 21:47:34 +00001093 if (image_list[scene]->colors != 0)
cristye8c25f92010-06-03 00:53:06 +00001094 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1095 image_list[scene]->colors);
cristy3ed852e2009-09-05 21:47:34 +00001096 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1097 image_list[scene]->magick);
1098 }
1099 /*
1100 Create the X pixmap.
1101 */
1102 window_info.pixmap=XCreatePixmap(display,window_info.id,width,height,
1103 window_info.depth);
1104 if (window_info.pixmap == (Pixmap) NULL)
1105 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
1106 images->filename);
1107 /*
1108 Display pixmap on the window.
1109 */
1110 if ((width > window_info.width) || (height > window_info.height))
1111 (void) XFillRectangle(display,window_info.pixmap,
1112 window_info.annotate_context,0,0,width,height);
1113 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
1114 window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
1115 window_info.height);
1116 (void) XSetWindowBackgroundPixmap(display,window_info.id,
1117 window_info.pixmap);
1118 (void) XClearWindow(display,window_info.id);
1119 window_info.pixmaps[scene]=window_info.pixmap;
1120 window_info.matte_pixmaps[scene]=window_info.matte_pixmap;
1121 if (image_list[scene]->matte)
1122 (void) XClearWindow(display,window_info.id);
1123 delay=1000*image_list[scene]->delay/MagickMax(
1124 image_list[scene]->ticks_per_second,1L);
1125 XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
1126 }
1127 window_info.pixel_info=(&pixel);
1128 /*
1129 Display pixmap on the window.
1130 */
1131 (void) XSelectInput(display,window_info.id,SubstructureNotifyMask);
1132 event.type=Expose;
1133 do
1134 {
1135 for (scene=0; scene < (int) number_scenes; scene++)
1136 {
1137 if (XEventsQueued(display,QueuedAfterFlush) > 0)
1138 {
1139 (void) XNextEvent(display,&event);
1140 if (event.type == DestroyNotify)
1141 break;
1142 }
1143 window_info.pixmap=window_info.pixmaps[scene];
1144 window_info.matte_pixmap=window_info.matte_pixmaps[scene];
1145 (void) XSetWindowBackgroundPixmap(display,window_info.id,
1146 window_info.pixmap);
1147 (void) XClearWindow(display,window_info.id);
1148 (void) XSync(display,MagickFalse);
1149 delay=1000*image_list[scene]->delay/MagickMax(
1150 image_list[scene]->ticks_per_second,1L);
1151 XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
1152 }
1153 } while (event.type != DestroyNotify);
1154 (void) XSync(display,MagickFalse);
1155 image_list=(Image **) RelinquishMagickMemory(image_list);
1156 images=DestroyImageList(images);
1157}
1158
1159/*
1160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1161% %
1162% %
1163% %
1164+ X A n i m a t e I m a g e s %
1165% %
1166% %
1167% %
1168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169%
1170% XAnimateImages() displays an image via X11.
1171%
1172% The format of the XAnimateImages method is:
1173%
1174% Image *XAnimateImages(Display *display,XResourceInfo *resource_info,
1175% char **argv,const int argc,Image *images)
1176%
1177% A description of each parameter follows:
1178%
1179% o display: Specifies a connection to an X server; returned from
1180% XOpenDisplay.
1181%
1182% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1183%
1184% o argv: Specifies the application's argument list.
1185%
1186% o argc: Specifies the number of arguments.
1187%
1188% o images: the image list.
1189%
1190*/
1191MagickExport Image *XAnimateImages(Display *display,
1192 XResourceInfo *resource_info,char **argv,const int argc,Image *images)
1193{
1194#define MagickMenus 4
1195#define MaXWindows 8
1196#define MagickTitle "Commands"
1197
1198 static const char
1199 *CommandMenu[]=
1200 {
1201 "Animate",
1202 "Speed",
1203 "Direction",
1204 "Help",
1205 "Image Info",
1206 "Quit",
1207 (char *) NULL
1208 },
1209 *AnimateMenu[]=
1210 {
1211 "Open...",
1212 "Play",
1213 "Step",
1214 "Repeat",
1215 "Auto Reverse",
1216 "Save...",
1217 (char *) NULL
1218 },
1219 *SpeedMenu[]=
1220 {
1221 "Faster",
1222 "Slower",
1223 (char *) NULL
1224 },
1225 *DirectionMenu[]=
1226 {
1227 "Forward",
1228 "Reverse",
1229 (char *) NULL
1230 },
1231 *HelpMenu[]=
1232 {
1233 "Overview",
1234 "Browse Documentation",
1235 "About Animate",
1236 (char *) NULL
1237 };
1238
1239 static const char
1240 **Menus[MagickMenus]=
1241 {
1242 AnimateMenu,
1243 SpeedMenu,
1244 DirectionMenu,
1245 HelpMenu
1246 };
1247
1248 static const CommandType
1249 CommandMenus[]=
1250 {
1251 NullCommand,
1252 NullCommand,
1253 NullCommand,
1254 NullCommand,
1255 InfoCommand,
1256 QuitCommand
1257 },
1258 CommandTypes[]=
1259 {
1260 OpenCommand,
1261 PlayCommand,
1262 StepCommand,
1263 RepeatCommand,
1264 AutoReverseCommand,
1265 SaveCommand
1266 },
1267 SpeedCommands[]=
1268 {
1269 FasterCommand,
1270 SlowerCommand
1271 },
1272 DirectionCommands[]=
1273 {
1274 ForwardCommand,
1275 ReverseCommand
1276 },
1277 HelpCommands[]=
1278 {
1279 HelpCommand,
1280 BrowseDocumentationCommand,
1281 VersionCommand
1282 };
1283
1284 static const CommandType
1285 *Commands[MagickMenus]=
1286 {
1287 CommandTypes,
1288 SpeedCommands,
1289 DirectionCommands,
1290 HelpCommands
1291 };
1292
1293 char
1294 command[MaxTextExtent],
1295 *cwd,
1296 geometry[MaxTextExtent],
1297 resource_name[MaxTextExtent];
1298
1299 CommandType
1300 command_type;
1301
1302 Image
1303 *coalesce_image,
1304 *display_image,
1305 *image,
1306 **image_list,
1307 *nexus;
1308
1309 int
1310 status;
1311
cristybb503372010-05-27 20:51:26 +00001312 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001313 first_scene,
1314 iterations,
1315 scene;
1316
1317 KeySym
1318 key_symbol;
1319
1320 MagickStatusType
1321 context_mask,
1322 state;
1323
1324 RectangleInfo
1325 geometry_info;
1326
1327 register char
1328 *p;
1329
cristybb503372010-05-27 20:51:26 +00001330 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001331 i;
1332
1333 static char
1334 working_directory[MaxTextExtent];
1335
cristybb503372010-05-27 20:51:26 +00001336 static size_t
cristy3ed852e2009-09-05 21:47:34 +00001337 number_windows;
1338
1339 static XWindowInfo
1340 *magick_windows[MaXWindows];
1341
1342 time_t
1343 timestamp;
1344
cristybb503372010-05-27 20:51:26 +00001345 size_t
cristy3ed852e2009-09-05 21:47:34 +00001346 delay,
1347 number_scenes;
1348
1349 WarningHandler
1350 warning_handler;
1351
1352 Window
1353 root_window;
1354
1355 XClassHint
1356 *class_hints;
1357
1358 XEvent
1359 event;
1360
1361 XFontStruct
1362 *font_info;
1363
1364 XGCValues
1365 context_values;
1366
1367 XPixelInfo
1368 *icon_pixel,
1369 *pixel;
1370
1371 XResourceInfo
1372 *icon_resources;
1373
1374 XStandardColormap
1375 *icon_map,
1376 *map_info;
1377
1378 XTextProperty
1379 window_name;
1380
1381 XVisualInfo
1382 *icon_visual,
1383 *visual_info;
1384
1385 XWindowChanges
1386 window_changes;
1387
1388 XWindows
1389 *windows;
1390
1391 XWMHints
1392 *manager_hints;
1393
1394 assert(images != (Image *) NULL);
1395 assert(images->signature == MagickSignature);
1396 if (images->debug != MagickFalse)
1397 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1398 warning_handler=(WarningHandler) NULL;
1399 windows=XSetWindows((XWindows *) ~0);
1400 if (windows != (XWindows *) NULL)
1401 {
1402 int
1403 status;
1404
1405 status=chdir(working_directory);
1406 if (status == -1)
1407 (void) ThrowMagickException(&images->exception,GetMagickModule(),
1408 FileOpenError,"UnableToOpenFile","%s",working_directory);
1409 warning_handler=resource_info->display_warnings ?
1410 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
1411 warning_handler=resource_info->display_warnings ?
1412 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
1413 }
1414 else
1415 {
1416 register Image
1417 *p;
1418
1419 /*
1420 Initialize window structure.
1421 */
1422 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1423 {
1424 if (p->storage_class == DirectClass)
1425 {
1426 resource_info->colors=0;
1427 break;
1428 }
1429 if (p->colors > resource_info->colors)
1430 resource_info->colors=p->colors;
1431 }
1432 windows=XSetWindows(XInitializeWindows(display,resource_info));
1433 if (windows == (XWindows *) NULL)
1434 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
1435 images->filename);
1436 /*
1437 Initialize window id's.
1438 */
1439 number_windows=0;
1440 magick_windows[number_windows++]=(&windows->icon);
1441 magick_windows[number_windows++]=(&windows->backdrop);
1442 magick_windows[number_windows++]=(&windows->image);
1443 magick_windows[number_windows++]=(&windows->info);
1444 magick_windows[number_windows++]=(&windows->command);
1445 magick_windows[number_windows++]=(&windows->widget);
1446 magick_windows[number_windows++]=(&windows->popup);
cristybb503372010-05-27 20:51:26 +00001447 for (i=0; i < (ssize_t) number_windows; i++)
cristy3ed852e2009-09-05 21:47:34 +00001448 magick_windows[i]->id=(Window) NULL;
1449 }
1450 /*
1451 Initialize font info.
1452 */
1453 if (windows->font_info != (XFontStruct *) NULL)
1454 (void) XFreeFont(display,windows->font_info);
1455 windows->font_info=XBestFont(display,resource_info,MagickFalse);
1456 if (windows->font_info == (XFontStruct *) NULL)
1457 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
1458 resource_info->font);
1459 /*
1460 Initialize Standard Colormap.
1461 */
1462 map_info=windows->map_info;
1463 icon_map=windows->icon_map;
1464 visual_info=windows->visual_info;
1465 icon_visual=windows->icon_visual;
1466 pixel=windows->pixel_info;
1467 icon_pixel=windows->icon_pixel;
1468 font_info=windows->font_info;
1469 icon_resources=windows->icon_resources;
1470 class_hints=windows->class_hints;
1471 manager_hints=windows->manager_hints;
1472 root_window=XRootWindow(display,visual_info->screen);
1473 coalesce_image=CoalesceImages(images,&images->exception);
1474 if (coalesce_image == (Image *) NULL)
1475 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
1476 images->filename);
1477 images=coalesce_image;
1478 if (resource_info->map_type == (char *) NULL)
1479 if ((visual_info->klass != TrueColor) &&
1480 (visual_info->klass != DirectColor))
1481 {
1482 Image
1483 *next;
1484
1485 /*
1486 Determine if the sequence of images has the identical colormap.
1487 */
1488 for (next=images; next != (Image *) NULL; )
1489 {
1490 next->matte=MagickFalse;
1491 if ((next->storage_class == DirectClass) ||
1492 (next->colors != images->colors) ||
cristybb503372010-05-27 20:51:26 +00001493 (next->colors > (size_t) visual_info->colormap_size))
cristy3ed852e2009-09-05 21:47:34 +00001494 break;
cristybb503372010-05-27 20:51:26 +00001495 for (i=0; i < (ssize_t) images->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001496 if (IsColorEqual(next->colormap+i,images->colormap+i) == MagickFalse)
1497 break;
cristybb503372010-05-27 20:51:26 +00001498 if (i < (ssize_t) images->colors)
cristy3ed852e2009-09-05 21:47:34 +00001499 break;
1500 next=GetNextImageInList(next);
1501 }
1502 if (next != (Image *) NULL)
1503 (void) RemapImages(resource_info->quantize_info,images,
1504 (Image *) NULL);
1505 }
1506 /*
1507 Sort images by increasing scene number.
1508 */
1509 number_scenes=GetImageListLength(images);
1510 image_list=ImageListToArray(images,&images->exception);
1511 if (image_list == (Image **) NULL)
1512 ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1513 images->filename);
cristybb503372010-05-27 20:51:26 +00001514 for (scene=0; scene < (ssize_t) number_scenes; scene++)
cristy3ed852e2009-09-05 21:47:34 +00001515 if (image_list[scene]->scene == 0)
1516 break;
cristybb503372010-05-27 20:51:26 +00001517 if (scene == (ssize_t) number_scenes)
cristy3ed852e2009-09-05 21:47:34 +00001518 qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
1519 /*
1520 Initialize Standard Colormap.
1521 */
1522 nexus=NewImageList();
1523 display_image=image_list[0];
cristybb503372010-05-27 20:51:26 +00001524 for (scene=0; scene < (ssize_t) number_scenes; scene++)
cristy3ed852e2009-09-05 21:47:34 +00001525 {
1526 if ((resource_info->map_type != (char *) NULL) ||
1527 (visual_info->klass == TrueColor) ||
1528 (visual_info->klass == DirectColor))
1529 (void) SetImageType(image_list[scene],image_list[scene]->matte ==
1530 MagickFalse ? TrueColorType : TrueColorMatteType);
1531 if ((display_image->columns < image_list[scene]->columns) &&
1532 (display_image->rows < image_list[scene]->rows))
1533 display_image=image_list[scene];
1534 }
1535 if (display_image->debug != MagickFalse)
1536 {
1537 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00001538 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,(double)
1539 display_image->scene,(double) display_image->columns,(double)
1540 display_image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001541 if (display_image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +00001542 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1543 display_image->colors);
cristy3ed852e2009-09-05 21:47:34 +00001544 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1545 display_image->magick);
1546 }
1547 XMakeStandardColormap(display,visual_info,resource_info,display_image,
1548 map_info,pixel);
1549 /*
1550 Initialize graphic context.
1551 */
1552 windows->context.id=(Window) NULL;
1553 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1554 resource_info,&windows->context);
1555 (void) CloneString(&class_hints->res_name,resource_info->client_name);
1556 (void) CloneString(&class_hints->res_class,resource_info->client_name);
1557 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
1558 manager_hints->flags=InputHint | StateHint;
1559 manager_hints->input=MagickFalse;
1560 manager_hints->initial_state=WithdrawnState;
1561 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1562 &windows->context);
1563 if (display_image->debug != MagickFalse)
1564 (void) LogMagickEvent(X11Event,GetMagickModule(),
1565 "Window id: 0x%lx (context)",windows->context.id);
1566 context_values.background=pixel->background_color.pixel;
1567 context_values.font=font_info->fid;
1568 context_values.foreground=pixel->foreground_color.pixel;
1569 context_values.graphics_exposures=MagickFalse;
1570 context_mask=(MagickStatusType)
1571 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
1572 if (pixel->annotate_context != (GC) NULL)
1573 (void) XFreeGC(display,pixel->annotate_context);
1574 pixel->annotate_context=
1575 XCreateGC(display,windows->context.id,context_mask,&context_values);
1576 if (pixel->annotate_context == (GC) NULL)
1577 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1578 images->filename);
1579 context_values.background=pixel->depth_color.pixel;
1580 if (pixel->widget_context != (GC) NULL)
1581 (void) XFreeGC(display,pixel->widget_context);
1582 pixel->widget_context=
1583 XCreateGC(display,windows->context.id,context_mask,&context_values);
1584 if (pixel->widget_context == (GC) NULL)
1585 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1586 images->filename);
1587 context_values.background=pixel->foreground_color.pixel;
1588 context_values.foreground=pixel->background_color.pixel;
1589 context_values.plane_mask=
1590 context_values.background ^ context_values.foreground;
1591 if (pixel->highlight_context != (GC) NULL)
1592 (void) XFreeGC(display,pixel->highlight_context);
1593 pixel->highlight_context=XCreateGC(display,windows->context.id,
cristybb503372010-05-27 20:51:26 +00001594 (size_t) (context_mask | GCPlaneMask),&context_values);
cristy3ed852e2009-09-05 21:47:34 +00001595 if (pixel->highlight_context == (GC) NULL)
1596 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1597 images->filename);
1598 (void) XDestroyWindow(display,windows->context.id);
1599 /*
1600 Initialize icon window.
1601 */
1602 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
1603 icon_resources,&windows->icon);
1604 windows->icon.geometry=resource_info->icon_geometry;
1605 XBestIconSize(display,&windows->icon,display_image);
1606 windows->icon.attributes.colormap=
1607 XDefaultColormap(display,icon_visual->screen);
1608 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
1609 manager_hints->flags=InputHint | StateHint;
1610 manager_hints->input=MagickFalse;
1611 manager_hints->initial_state=IconicState;
1612 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1613 &windows->icon);
1614 if (display_image->debug != MagickFalse)
1615 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
1616 windows->icon.id);
1617 /*
1618 Initialize graphic context for icon window.
1619 */
1620 if (icon_pixel->annotate_context != (GC) NULL)
1621 (void) XFreeGC(display,icon_pixel->annotate_context);
1622 context_values.background=icon_pixel->background_color.pixel;
1623 context_values.foreground=icon_pixel->foreground_color.pixel;
1624 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
cristybb503372010-05-27 20:51:26 +00001625 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +00001626 if (icon_pixel->annotate_context == (GC) NULL)
1627 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
1628 images->filename);
1629 windows->icon.annotate_context=icon_pixel->annotate_context;
1630 /*
1631 Initialize Image window.
1632 */
1633 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1634 resource_info,&windows->image);
1635 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
1636 if (resource_info->use_shared_memory == MagickFalse)
1637 windows->image.shared_memory=MagickFalse;
1638 if (resource_info->title != (char *) NULL)
1639 {
1640 char
1641 *title;
1642
1643 title=InterpretImageProperties(resource_info->image_info,display_image,
1644 resource_info->title);
1645 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
1646 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
1647 title=DestroyString(title);
1648 }
1649 else
1650 {
1651 char
1652 filename[MaxTextExtent];
1653
1654 /*
1655 Window name is the base of the filename.
1656 */
1657 GetPathComponent(display_image->magick_filename,TailPath,filename);
1658 (void) FormatMagickString(windows->image.name,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001659 "%s: %s[%.20g of %.20g]",MagickPackageName,filename,(double)
1660 display_image->scene,(double) number_scenes);
cristy3ed852e2009-09-05 21:47:34 +00001661 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
1662 }
1663 if (resource_info->immutable != MagickFalse)
1664 windows->image.immutable=MagickTrue;
1665 windows->image.shape=MagickTrue;
1666 windows->image.geometry=resource_info->image_geometry;
1667 (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>!",
1668 XDisplayWidth(display,visual_info->screen),
1669 XDisplayHeight(display,visual_info->screen));
1670 geometry_info.width=display_image->columns;
1671 geometry_info.height=display_image->rows;
1672 geometry_info.x=0;
1673 geometry_info.y=0;
1674 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
1675 &geometry_info.width,&geometry_info.height);
1676 windows->image.width=(unsigned int) geometry_info.width;
1677 windows->image.height=(unsigned int) geometry_info.height;
1678 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1679 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1680 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
1681 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
1682 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1683 resource_info,&windows->backdrop);
1684 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
1685 {
1686 /*
1687 Initialize backdrop window.
1688 */
1689 windows->backdrop.x=0;
1690 windows->backdrop.y=0;
1691 (void) CloneString(&windows->backdrop.name,"ImageMagick Backdrop");
cristybb503372010-05-27 20:51:26 +00001692 windows->backdrop.flags=(size_t) (USSize | USPosition);
cristy3ed852e2009-09-05 21:47:34 +00001693 windows->backdrop.width=(unsigned int)
1694 XDisplayWidth(display,visual_info->screen);
1695 windows->backdrop.height=(unsigned int)
1696 XDisplayHeight(display,visual_info->screen);
1697 windows->backdrop.border_width=0;
1698 windows->backdrop.immutable=MagickTrue;
1699 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
1700 ButtonReleaseMask;
1701 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
1702 StructureNotifyMask;
1703 manager_hints->flags=IconWindowHint | InputHint | StateHint;
1704 manager_hints->icon_window=windows->icon.id;
1705 manager_hints->input=MagickTrue;
1706 manager_hints->initial_state=
1707 resource_info->iconic ? IconicState : NormalState;
1708 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1709 &windows->backdrop);
1710 if (display_image->debug != MagickFalse)
1711 (void) LogMagickEvent(X11Event,GetMagickModule(),
1712 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
1713 (void) XMapWindow(display,windows->backdrop.id);
1714 (void) XClearWindow(display,windows->backdrop.id);
1715 if (windows->image.id != (Window) NULL)
1716 {
1717 (void) XDestroyWindow(display,windows->image.id);
1718 windows->image.id=(Window) NULL;
1719 }
1720 /*
1721 Position image in the center the backdrop.
1722 */
1723 windows->image.flags|=USPosition;
1724 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
1725 (windows->image.width/2);
1726 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
1727 (windows->image.height/2);
1728 }
1729 manager_hints->flags=IconWindowHint | InputHint | StateHint;
1730 manager_hints->icon_window=windows->icon.id;
1731 manager_hints->input=MagickTrue;
1732 manager_hints->initial_state=
1733 resource_info->iconic ? IconicState : NormalState;
1734 if (windows->group_leader.id != (Window) NULL)
1735 {
1736 /*
1737 Follow the leader.
1738 */
1739 manager_hints->flags|=(MagickStatusType) WindowGroupHint;
1740 manager_hints->window_group=windows->group_leader.id;
1741 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
1742 if (display_image->debug != MagickFalse)
1743 (void) LogMagickEvent(X11Event,GetMagickModule(),
1744 "Window id: 0x%lx (group leader)",windows->group_leader.id);
1745 }
1746 XMakeWindow(display,
1747 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
1748 argv,argc,class_hints,manager_hints,&windows->image);
1749 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
1750 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
1751 if (windows->group_leader.id != (Window) NULL)
1752 (void) XSetTransientForHint(display,windows->image.id,
1753 windows->group_leader.id);
1754 if (display_image->debug != MagickFalse)
1755 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
1756 windows->image.id);
1757 /*
1758 Initialize Info widget.
1759 */
1760 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1761 resource_info,&windows->info);
1762 (void) CloneString(&windows->info.name,"Info");
1763 (void) CloneString(&windows->info.icon_name,"Info");
1764 windows->info.border_width=1;
1765 windows->info.x=2;
1766 windows->info.y=2;
1767 windows->info.flags|=PPosition;
1768 windows->info.attributes.win_gravity=UnmapGravity;
1769 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
1770 StructureNotifyMask;
1771 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1772 manager_hints->input=MagickFalse;
1773 manager_hints->initial_state=NormalState;
1774 manager_hints->window_group=windows->image.id;
1775 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
1776 &windows->info);
1777 windows->info.highlight_stipple=XCreateBitmapFromData(display,
1778 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1779 windows->info.shadow_stipple=XCreateBitmapFromData(display,
1780 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1781 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
1782 if (windows->image.mapped)
1783 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
1784 if (display_image->debug != MagickFalse)
1785 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
1786 windows->info.id);
1787 /*
1788 Initialize Command widget.
1789 */
1790 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1791 resource_info,&windows->command);
1792 windows->command.data=MagickMenus;
1793 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
1794 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.command",
1795 resource_info->client_name);
1796 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
1797 resource_name,"geometry",(char *) NULL);
1798 (void) CloneString(&windows->command.name,MagickTitle);
1799 windows->command.border_width=0;
1800 windows->command.flags|=PPosition;
1801 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1802 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
1803 OwnerGrabButtonMask | StructureNotifyMask;
1804 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1805 manager_hints->input=MagickTrue;
1806 manager_hints->initial_state=NormalState;
1807 manager_hints->window_group=windows->image.id;
1808 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1809 &windows->command);
1810 windows->command.highlight_stipple=XCreateBitmapFromData(display,
1811 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
1812 HighlightHeight);
1813 windows->command.shadow_stipple=XCreateBitmapFromData(display,
1814 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1815 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
1816 if (display_image->debug != MagickFalse)
1817 (void) LogMagickEvent(X11Event,GetMagickModule(),
1818 "Window id: 0x%lx (command)",windows->command.id);
1819 /*
1820 Initialize Widget window.
1821 */
1822 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1823 resource_info,&windows->widget);
1824 (void) FormatMagickString(resource_name,MaxTextExtent,"%s.widget",
1825 resource_info->client_name);
1826 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
1827 resource_name,"geometry",(char *) NULL);
1828 windows->widget.border_width=0;
1829 windows->widget.flags|=PPosition;
1830 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1831 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1832 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
1833 StructureNotifyMask;
1834 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1835 manager_hints->input=MagickTrue;
1836 manager_hints->initial_state=NormalState;
1837 manager_hints->window_group=windows->image.id;
1838 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1839 &windows->widget);
1840 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
1841 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1842 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
1843 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1844 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
1845 if (display_image->debug != MagickFalse)
1846 (void) LogMagickEvent(X11Event,GetMagickModule(),
1847 "Window id: 0x%lx (widget)",windows->widget.id);
1848 /*
1849 Initialize popup window.
1850 */
1851 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
1852 resource_info,&windows->popup);
1853 windows->popup.border_width=0;
1854 windows->popup.flags|=PPosition;
1855 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
1856 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
1857 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
1858 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
1859 manager_hints->input=MagickTrue;
1860 manager_hints->initial_state=NormalState;
1861 manager_hints->window_group=windows->image.id;
1862 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
1863 &windows->popup);
1864 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
1865 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
1866 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
1867 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
1868 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
1869 if (display_image->debug != MagickFalse)
1870 (void) LogMagickEvent(X11Event,GetMagickModule(),
1871 "Window id: 0x%lx (pop up)",windows->popup.id);
cristy3ed852e2009-09-05 21:47:34 +00001872 /*
1873 Set out progress and warning handlers.
1874 */
1875 if (warning_handler == (WarningHandler) NULL)
1876 {
1877 warning_handler=resource_info->display_warnings ?
1878 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
1879 warning_handler=resource_info->display_warnings ?
1880 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
1881 }
1882 /*
1883 Initialize X image structure.
1884 */
1885 windows->image.x=0;
1886 windows->image.y=0;
cristy3ed852e2009-09-05 21:47:34 +00001887 /*
1888 Initialize image pixmaps structure.
1889 */
1890 window_changes.width=(int) windows->image.width;
1891 window_changes.height=(int) windows->image.height;
1892 (void) XReconfigureWMWindow(display,windows->image.id,windows->command.screen,
1893 (unsigned int) (CWWidth | CWHeight),&window_changes);
cristy3ed852e2009-09-05 21:47:34 +00001894 windows->image.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1895 sizeof(*windows->image.pixmaps));
1896 windows->image.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
1897 sizeof(*windows->image.pixmaps));
1898 if ((windows->image.pixmaps == (Pixmap *) NULL) ||
1899 (windows->image.matte_pixmaps == (Pixmap *) NULL))
1900 ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1901 images->filename);
cristy04e11fd2010-03-19 16:01:44 +00001902 if ((windows->image.mapped == MagickFalse) ||
1903 (windows->backdrop.id != (Window) NULL))
1904 (void) XMapWindow(display,windows->image.id);
1905 XSetCursorState(display,windows,MagickTrue);
cristybb503372010-05-27 20:51:26 +00001906 for (scene=0; scene < (ssize_t) number_scenes; scene++)
cristy3ed852e2009-09-05 21:47:34 +00001907 {
1908 unsigned int
1909 columns,
1910 rows;
1911
1912 /*
1913 Create X image.
1914 */
1915 (void) TransformImageColorspace(image_list[scene],RGBColorspace);
1916 windows->image.pixmap=(Pixmap) NULL;
1917 windows->image.matte_pixmap=(Pixmap) NULL;
1918 if ((resource_info->map_type != (char *) NULL) ||
1919 (visual_info->klass == TrueColor) ||
1920 (visual_info->klass == DirectColor))
1921 if (image_list[scene]->storage_class == PseudoClass)
1922 XGetPixelPacket(display,visual_info,map_info,resource_info,
1923 image_list[scene],windows->image.pixel_info);
1924 columns=(unsigned int) image_list[scene]->columns;
1925 rows=(unsigned int) image_list[scene]->rows;
1926 if ((image_list[scene]->columns != columns) ||
1927 (image_list[scene]->rows != rows))
1928 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1929 image_list[scene]->filename);
1930 status=XMakeImage(display,resource_info,&windows->image,image_list[scene],
1931 columns,rows);
1932 if (status == MagickFalse)
1933 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1934 images->filename);
1935 if (image_list[scene]->debug != MagickFalse)
1936 {
1937 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00001938 "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
1939 image_list[scene]->filename,(double) columns,(double) rows);
cristy3ed852e2009-09-05 21:47:34 +00001940 if (image_list[scene]->colors != 0)
cristye8c25f92010-06-03 00:53:06 +00001941 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1942 image_list[scene]->colors);
cristy3ed852e2009-09-05 21:47:34 +00001943 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1944 image_list[scene]->magick);
1945 }
1946 /*
1947 Window name is the base of the filename.
1948 */
1949 if (resource_info->title != (char *) NULL)
1950 {
1951 char
1952 *title;
1953
1954 title=InterpretImageProperties(resource_info->image_info,
1955 image_list[scene],resource_info->title);
1956 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
1957 title=DestroyString(title);
1958 }
1959 else
1960 {
1961 p=image_list[scene]->magick_filename+
1962 strlen(image_list[scene]->magick_filename)-1;
1963 while ((p > image_list[scene]->magick_filename) && (*(p-1) != '/'))
1964 p--;
1965 (void) FormatMagickString(windows->image.name,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001966 "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double) scene+1,
1967 (double) number_scenes);
cristy3ed852e2009-09-05 21:47:34 +00001968 }
1969 status=XStringListToTextProperty(&windows->image.name,1,&window_name);
1970 if (status != Success)
1971 {
1972 XSetWMName(display,windows->image.id,&window_name);
1973 (void) XFree((void *) window_name.value);
1974 }
1975 windows->image.pixmaps[scene]=windows->image.pixmap;
1976 windows->image.matte_pixmaps[scene]=windows->image.matte_pixmap;
cristy04e11fd2010-03-19 16:01:44 +00001977 if (scene == 0)
cristy3ed852e2009-09-05 21:47:34 +00001978 {
cristy04e11fd2010-03-19 16:01:44 +00001979 event.xexpose.x=0;
1980 event.xexpose.y=0;
1981 event.xexpose.width=(int) image_list[scene]->columns;
1982 event.xexpose.height=(int) image_list[scene]->rows;
1983 XRefreshWindow(display,&windows->image,&event);
1984 (void) XSync(display,MagickFalse);
1985 }
cristy3ed852e2009-09-05 21:47:34 +00001986 }
cristy04e11fd2010-03-19 16:01:44 +00001987 XSetCursorState(display,windows,MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001988 if (windows->command.mapped)
1989 (void) XMapRaised(display,windows->command.id);
1990 /*
1991 Respond to events.
1992 */
1993 nexus=NewImageList();
1994 scene=0;
1995 first_scene=0;
1996 iterations=0;
1997 image=image_list[0];
1998 state=(MagickStatusType) (ForwardAnimationState | RepeatAnimationState);
1999 (void) XMagickCommand(display,resource_info,windows,PlayCommand,&images,
2000 &state);
2001 do
2002 {
2003 if (XEventsQueued(display,QueuedAfterFlush) == 0)
2004 if ((state & PlayAnimationState) || (state & StepAnimationState))
2005 {
2006 MagickBooleanType
2007 pause;
2008
2009 pause=MagickFalse;
2010 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
2011 XDelay(display,resource_info->delay*(delay == 0 ? 10 : delay));
2012 if (state & ForwardAnimationState)
2013 {
2014 /*
2015 Forward animation: increment scene number.
2016 */
cristybb503372010-05-27 20:51:26 +00002017 if (scene < ((ssize_t) number_scenes-1))
cristy3ed852e2009-09-05 21:47:34 +00002018 scene++;
2019 else
2020 {
2021 iterations++;
cristybb503372010-05-27 20:51:26 +00002022 if (iterations == (ssize_t) image_list[0]->iterations)
cristy3ed852e2009-09-05 21:47:34 +00002023 {
2024 iterations=0;
2025 state|=ExitState;
2026 }
cristy04e11fd2010-03-19 16:01:44 +00002027 if ((state & AutoReverseAnimationState) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002028 {
2029 state&=(~ForwardAnimationState);
2030 scene--;
2031 }
2032 else
2033 {
cristy04e11fd2010-03-19 16:01:44 +00002034 if ((state & RepeatAnimationState) == 0)
cristy3ed852e2009-09-05 21:47:34 +00002035 state&=(~PlayAnimationState);
2036 scene=first_scene;
2037 pause=MagickTrue;
2038 }
2039 }
2040 }
2041 else
2042 {
2043 /*
2044 Reverse animation: decrement scene number.
2045 */
2046 if (scene > first_scene)
2047 scene--;
2048 else
2049 {
2050 iterations++;
cristybb503372010-05-27 20:51:26 +00002051 if (iterations == (ssize_t) image_list[0]->iterations)
cristy3ed852e2009-09-05 21:47:34 +00002052 {
2053 iterations=0;
2054 state&=(~RepeatAnimationState);
2055 }
2056 if (state & AutoReverseAnimationState)
2057 {
2058 state|=ForwardAnimationState;
2059 scene=first_scene;
2060 pause=MagickTrue;
2061 }
2062 else
2063 {
2064 if ((state & RepeatAnimationState) == MagickFalse)
2065 state&=(~PlayAnimationState);
cristybb503372010-05-27 20:51:26 +00002066 scene=(ssize_t) number_scenes-1;
cristy3ed852e2009-09-05 21:47:34 +00002067 }
2068 }
2069 }
2070 scene=MagickMax(scene,0);
2071 image=image_list[scene];
2072 if ((image != (Image *) NULL) && (image->start_loop != 0))
2073 first_scene=scene;
2074 if ((state & StepAnimationState) ||
2075 (resource_info->title != (char *) NULL))
2076 {
2077 /*
2078 Update window title.
2079 */
2080 p=image_list[scene]->filename+
2081 strlen(image_list[scene]->filename)-1;
2082 while ((p > image_list[scene]->filename) && (*(p-1) != '/'))
2083 p--;
2084 (void) FormatMagickString(windows->image.name,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00002085 "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double)
2086 scene+1,(double) number_scenes);
cristy3ed852e2009-09-05 21:47:34 +00002087 if (resource_info->title != (char *) NULL)
2088 {
2089 char
2090 *title;
2091
2092 title=InterpretImageProperties(resource_info->image_info,
2093 image,resource_info->title);
2094 (void) CopyMagickString(windows->image.name,title,
2095 MaxTextExtent);
2096 title=DestroyString(title);
2097 }
2098 status=XStringListToTextProperty(&windows->image.name,1,
2099 &window_name);
2100 if (status != Success)
2101 {
2102 XSetWMName(display,windows->image.id,&window_name);
2103 (void) XFree((void *) window_name.value);
2104 }
2105 }
2106 /*
2107 Copy X pixmap to Image window.
2108 */
2109 XGetPixelPacket(display,visual_info,map_info,resource_info,
2110 image_list[scene],windows->image.pixel_info);
2111 windows->image.ximage->width=(int) image->columns;
2112 windows->image.ximage->height=(int) image->rows;
2113 windows->image.pixmap=windows->image.pixmaps[scene];
2114 windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
2115 event.xexpose.x=0;
2116 event.xexpose.y=0;
2117 event.xexpose.width=(int) image->columns;
2118 event.xexpose.height=(int) image->rows;
cristy04e11fd2010-03-19 16:01:44 +00002119 if ((state & ExitState) == 0)
2120 {
2121 XRefreshWindow(display,&windows->image,&event);
2122 (void) XSync(display,MagickFalse);
2123 }
cristy3ed852e2009-09-05 21:47:34 +00002124 state&=(~StepAnimationState);
2125 if (pause != MagickFalse)
cristybb503372010-05-27 20:51:26 +00002126 for (i=0; i < (ssize_t) resource_info->pause; i++)
cristy3ed852e2009-09-05 21:47:34 +00002127 {
2128 int
2129 status;
2130
2131 status=XCheckTypedWindowEvent(display,windows->image.id,KeyPress,
2132 &event);
2133 if (status != 0)
2134 {
2135 int
2136 length;
2137
2138 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2139 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2140 *(command+length)='\0';
2141 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
2142 {
2143 XClientMessage(display,windows->image.id,
2144 windows->im_protocols,windows->im_exit,CurrentTime);
2145 break;
2146 }
2147 }
2148 (void) sleep(1);
2149 }
2150 continue;
2151 }
2152 /*
2153 Handle a window event.
2154 */
2155 timestamp=time((time_t *) NULL);
2156 (void) XNextEvent(display,&event);
2157 if (windows->image.stasis == MagickFalse)
2158 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
2159 MagickTrue : MagickFalse;
2160 if (event.xany.window == windows->command.id)
2161 {
2162 int
2163 id;
2164
2165 /*
2166 Select a command from the Command widget.
2167 */
2168 id=XCommandWidget(display,windows,CommandMenu,&event);
2169 if (id < 0)
2170 continue;
2171 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
2172 command_type=CommandMenus[id];
2173 if (id < MagickMenus)
2174 {
2175 int
2176 entry;
2177
2178 /*
2179 Select a command from a pop-up menu.
2180 */
2181 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
2182 command);
2183 if (entry < 0)
2184 continue;
2185 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
2186 command_type=Commands[id][entry];
2187 }
2188 if (command_type != NullCommand)
2189 nexus=XMagickCommand(display,resource_info,windows,
2190 command_type,&image,&state);
2191 continue;
2192 }
2193 switch (event.type)
2194 {
2195 case ButtonPress:
2196 {
2197 if (display_image->debug != MagickFalse)
2198 (void) LogMagickEvent(X11Event,GetMagickModule(),
2199 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
2200 event.xbutton.button,event.xbutton.x,event.xbutton.y);
2201 if ((event.xbutton.button == Button3) &&
2202 (event.xbutton.state & Mod1Mask))
2203 {
2204 /*
2205 Convert Alt-Button3 to Button2.
2206 */
2207 event.xbutton.button=Button2;
2208 event.xbutton.state&=(~Mod1Mask);
2209 }
2210 if (event.xbutton.window == windows->backdrop.id)
2211 {
2212 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
2213 event.xbutton.time);
2214 break;
2215 }
2216 if (event.xbutton.window == windows->image.id)
2217 {
2218 if (resource_info->immutable != MagickFalse)
2219 {
2220 state|=ExitState;
2221 break;
2222 }
2223 /*
2224 Map/unmap Command widget.
2225 */
2226 if (windows->command.mapped)
2227 (void) XWithdrawWindow(display,windows->command.id,
2228 windows->command.screen);
2229 else
2230 {
2231 (void) XCommandWidget(display,windows,CommandMenu,
2232 (XEvent *) NULL);
2233 (void) XMapRaised(display,windows->command.id);
2234 }
2235 }
2236 break;
2237 }
2238 case ButtonRelease:
2239 {
2240 if (display_image->debug != MagickFalse)
2241 (void) LogMagickEvent(X11Event,GetMagickModule(),
2242 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
2243 event.xbutton.button,event.xbutton.x,event.xbutton.y);
2244 break;
2245 }
2246 case ClientMessage:
2247 {
2248 if (display_image->debug != MagickFalse)
2249 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00002250 "Client Message: 0x%lx 0x%lx %d 0x%lx",(unsigned long)
2251 event.xclient.window,(unsigned long) event.xclient.message_type,
2252 event.xclient.format,(unsigned long) event.xclient.data.l[0]);
cristy3ed852e2009-09-05 21:47:34 +00002253 if (event.xclient.message_type == windows->im_protocols)
2254 {
cristyecd0ab52010-05-30 14:59:20 +00002255 if (*event.xclient.data.l == (long) windows->im_update_colormap)
cristy3ed852e2009-09-05 21:47:34 +00002256 {
2257 /*
2258 Update graphic context and window colormap.
2259 */
cristybb503372010-05-27 20:51:26 +00002260 for (i=0; i < (ssize_t) number_windows; i++)
cristy3ed852e2009-09-05 21:47:34 +00002261 {
2262 if (magick_windows[i]->id == windows->icon.id)
2263 continue;
2264 context_values.background=pixel->background_color.pixel;
2265 context_values.foreground=pixel->foreground_color.pixel;
2266 (void) XChangeGC(display,magick_windows[i]->annotate_context,
2267 context_mask,&context_values);
2268 (void) XChangeGC(display,magick_windows[i]->widget_context,
2269 context_mask,&context_values);
2270 context_values.background=pixel->foreground_color.pixel;
2271 context_values.foreground=pixel->background_color.pixel;
2272 context_values.plane_mask=
2273 context_values.background ^ context_values.foreground;
2274 (void) XChangeGC(display,magick_windows[i]->highlight_context,
cristybb503372010-05-27 20:51:26 +00002275 (size_t) (context_mask | GCPlaneMask),
cristy3ed852e2009-09-05 21:47:34 +00002276 &context_values);
2277 magick_windows[i]->attributes.background_pixel=
2278 pixel->background_color.pixel;
2279 magick_windows[i]->attributes.border_pixel=
2280 pixel->border_color.pixel;
2281 magick_windows[i]->attributes.colormap=map_info->colormap;
2282 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
2283 magick_windows[i]->mask,&magick_windows[i]->attributes);
2284 }
2285 if (windows->backdrop.id != (Window) NULL)
2286 (void) XInstallColormap(display,map_info->colormap);
2287 break;
2288 }
cristyecd0ab52010-05-30 14:59:20 +00002289 if (*event.xclient.data.l == (long) windows->im_exit)
cristy3ed852e2009-09-05 21:47:34 +00002290 {
2291 state|=ExitState;
2292 break;
2293 }
2294 break;
2295 }
2296 if (event.xclient.message_type == windows->dnd_protocols)
2297 {
2298 Atom
2299 selection,
2300 type;
2301
2302 int
2303 format,
2304 status;
2305
2306 unsigned char
2307 *data;
2308
cristyf2faecf2010-05-28 19:19:36 +00002309 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002310 after,
2311 length;
2312
2313 /*
2314 Display image named by the Drag-and-Drop selection.
2315 */
2316 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
2317 break;
2318 selection=XInternAtom(display,"DndSelection",MagickFalse);
2319 status=XGetWindowProperty(display,root_window,selection,0L,2047L,
2320 MagickFalse,(Atom) AnyPropertyType,&type,&format,&length,&after,
2321 &data);
2322 if ((status != Success) || (length == 0))
2323 break;
2324 if (*event.xclient.data.l == 2)
2325 {
2326 /*
2327 Offix DND.
2328 */
2329 (void) CopyMagickString(resource_info->image_info->filename,
2330 (char *) data,MaxTextExtent);
2331 }
2332 else
2333 {
2334 /*
2335 XDND.
2336 */
2337 if (LocaleNCompare((char *) data,"file:",5) != 0)
2338 {
2339 (void) XFree((void *) data);
2340 break;
2341 }
2342 (void) CopyMagickString(resource_info->image_info->filename,
2343 ((char *) data)+5,MaxTextExtent);
2344 }
2345 nexus=ReadImage(resource_info->image_info,&image->exception);
2346 CatchException(&image->exception);
2347 if (nexus != (Image *) NULL)
2348 state|=ExitState;
2349 (void) XFree((void *) data);
2350 break;
2351 }
2352 /*
2353 If client window delete message, exit.
2354 */
2355 if (event.xclient.message_type != windows->wm_protocols)
2356 break;
cristycee97112010-05-28 00:44:52 +00002357 if (*event.xclient.data.l == (long) windows->wm_take_focus)
cristy3ed852e2009-09-05 21:47:34 +00002358 {
2359 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2360 (Time) event.xclient.data.l[1]);
2361 break;
2362 }
cristycee97112010-05-28 00:44:52 +00002363 if (*event.xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +00002364 break;
2365 (void) XWithdrawWindow(display,event.xclient.window,
2366 visual_info->screen);
2367 if (event.xclient.window == windows->image.id)
2368 {
2369 state|=ExitState;
2370 break;
2371 }
2372 break;
2373 }
2374 case ConfigureNotify:
2375 {
2376 if (display_image->debug != MagickFalse)
2377 (void) LogMagickEvent(X11Event,GetMagickModule(),
2378 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
2379 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
2380 event.xconfigure.y,event.xconfigure.send_event);
2381 if (event.xconfigure.window == windows->image.id)
2382 {
2383 if (event.xconfigure.send_event != 0)
2384 {
2385 XWindowChanges
2386 window_changes;
2387
2388 /*
2389 Position the transient windows relative of the Image window.
2390 */
2391 if (windows->command.geometry == (char *) NULL)
2392 if (windows->command.mapped == MagickFalse)
2393 {
2394 windows->command.x=
2395 event.xconfigure.x-windows->command.width-25;
2396 windows->command.y=event.xconfigure.y;
2397 XConstrainWindowPosition(display,&windows->command);
2398 window_changes.x=windows->command.x;
2399 window_changes.y=windows->command.y;
2400 (void) XReconfigureWMWindow(display,windows->command.id,
2401 windows->command.screen,(unsigned int) (CWX | CWY),
2402 &window_changes);
2403 }
2404 if (windows->widget.geometry == (char *) NULL)
2405 if (windows->widget.mapped == MagickFalse)
2406 {
2407 windows->widget.x=
2408 event.xconfigure.x+event.xconfigure.width/10;
2409 windows->widget.y=
2410 event.xconfigure.y+event.xconfigure.height/10;
2411 XConstrainWindowPosition(display,&windows->widget);
2412 window_changes.x=windows->widget.x;
2413 window_changes.y=windows->widget.y;
2414 (void) XReconfigureWMWindow(display,windows->widget.id,
2415 windows->widget.screen,(unsigned int) (CWX | CWY),
2416 &window_changes);
2417 }
2418 }
2419 /*
2420 Image window has a new configuration.
2421 */
2422 windows->image.width=(unsigned int) event.xconfigure.width;
2423 windows->image.height=(unsigned int) event.xconfigure.height;
2424 break;
2425 }
2426 if (event.xconfigure.window == windows->icon.id)
2427 {
2428 /*
2429 Icon window has a new configuration.
2430 */
2431 windows->icon.width=(unsigned int) event.xconfigure.width;
2432 windows->icon.height=(unsigned int) event.xconfigure.height;
2433 break;
2434 }
2435 break;
2436 }
2437 case DestroyNotify:
2438 {
2439 /*
2440 Group leader has exited.
2441 */
2442 if (display_image->debug != MagickFalse)
2443 (void) LogMagickEvent(X11Event,GetMagickModule(),
2444 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
2445 if (event.xdestroywindow.window == windows->group_leader.id)
2446 {
2447 state|=ExitState;
2448 break;
2449 }
2450 break;
2451 }
2452 case EnterNotify:
2453 {
2454 /*
2455 Selectively install colormap.
2456 */
2457 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2458 if (event.xcrossing.mode != NotifyUngrab)
2459 XInstallColormap(display,map_info->colormap);
2460 break;
2461 }
2462 case Expose:
2463 {
2464 if (display_image->debug != MagickFalse)
2465 (void) LogMagickEvent(X11Event,GetMagickModule(),
2466 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
2467 event.xexpose.width,event.xexpose.height,event.xexpose.x,
2468 event.xexpose.y);
2469 /*
2470 Repaint windows that are now exposed.
2471 */
2472 if (event.xexpose.window == windows->image.id)
2473 {
2474 windows->image.pixmap=windows->image.pixmaps[scene];
2475 windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
2476 XRefreshWindow(display,&windows->image,&event);
2477 break;
2478 }
2479 if (event.xexpose.window == windows->icon.id)
2480 if (event.xexpose.count == 0)
2481 {
2482 XRefreshWindow(display,&windows->icon,&event);
2483 break;
2484 }
2485 break;
2486 }
2487 case KeyPress:
2488 {
2489 static int
2490 length;
2491
2492 /*
2493 Respond to a user key press.
2494 */
2495 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2496 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2497 *(command+length)='\0';
2498 if (display_image->debug != MagickFalse)
2499 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00002500 "Key press: 0x%lx (%c)",(unsigned long) key_symbol,*command);
cristy3ed852e2009-09-05 21:47:34 +00002501 command_type=NullCommand;
2502 switch (key_symbol)
2503 {
2504 case XK_o:
2505 {
2506 if ((event.xkey.state & ControlMask) == MagickFalse)
2507 break;
2508 command_type=OpenCommand;
2509 break;
2510 }
2511 case XK_BackSpace:
2512 {
2513 command_type=StepBackwardCommand;
2514 break;
2515 }
2516 case XK_space:
2517 {
2518 command_type=StepForwardCommand;
2519 break;
2520 }
2521 case XK_less:
2522 {
2523 command_type=FasterCommand;
2524 break;
2525 }
2526 case XK_greater:
2527 {
2528 command_type=SlowerCommand;
2529 break;
2530 }
2531 case XK_F1:
2532 {
2533 command_type=HelpCommand;
2534 break;
2535 }
2536 case XK_Find:
2537 {
2538 command_type=BrowseDocumentationCommand;
2539 break;
2540 }
2541 case XK_question:
2542 {
2543 command_type=InfoCommand;
2544 break;
2545 }
2546 case XK_q:
2547 case XK_Escape:
2548 {
2549 command_type=QuitCommand;
2550 break;
2551 }
2552 default:
2553 break;
2554 }
2555 if (command_type != NullCommand)
2556 nexus=XMagickCommand(display,resource_info,windows,
2557 command_type,&image,&state);
2558 break;
2559 }
2560 case KeyRelease:
2561 {
2562 /*
2563 Respond to a user key release.
2564 */
2565 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2566 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2567 if (display_image->debug != MagickFalse)
2568 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00002569 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
cristy3ed852e2009-09-05 21:47:34 +00002570 break;
2571 }
2572 case LeaveNotify:
2573 {
2574 /*
2575 Selectively uninstall colormap.
2576 */
2577 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
2578 if (event.xcrossing.mode != NotifyUngrab)
2579 XUninstallColormap(display,map_info->colormap);
2580 break;
2581 }
2582 case MapNotify:
2583 {
2584 if (display_image->debug != MagickFalse)
2585 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
2586 event.xmap.window);
2587 if (event.xmap.window == windows->backdrop.id)
2588 {
2589 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
2590 CurrentTime);
2591 windows->backdrop.mapped=MagickTrue;
2592 break;
2593 }
2594 if (event.xmap.window == windows->image.id)
2595 {
2596 if (windows->backdrop.id != (Window) NULL)
2597 (void) XInstallColormap(display,map_info->colormap);
2598 if (LocaleCompare(image_list[0]->magick,"LOGO") == 0)
2599 {
2600 if (LocaleCompare(display_image->filename,"LOGO") == 0)
2601 nexus=XMagickCommand(display,resource_info,windows,
2602 OpenCommand,&image,&state);
2603 else
2604 state|=ExitState;
2605 }
2606 windows->image.mapped=MagickTrue;
2607 break;
2608 }
2609 if (event.xmap.window == windows->info.id)
2610 {
2611 windows->info.mapped=MagickTrue;
2612 break;
2613 }
2614 if (event.xmap.window == windows->icon.id)
2615 {
2616 /*
2617 Create an icon image.
2618 */
2619 XMakeStandardColormap(display,icon_visual,icon_resources,
2620 display_image,icon_map,icon_pixel);
2621 (void) XMakeImage(display,icon_resources,&windows->icon,
2622 display_image,windows->icon.width,windows->icon.height);
2623 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
2624 windows->icon.pixmap);
2625 (void) XClearWindow(display,windows->icon.id);
2626 (void) XWithdrawWindow(display,windows->info.id,
2627 windows->info.screen);
2628 windows->icon.mapped=MagickTrue;
2629 break;
2630 }
2631 if (event.xmap.window == windows->command.id)
2632 {
2633 windows->command.mapped=MagickTrue;
2634 break;
2635 }
2636 if (event.xmap.window == windows->popup.id)
2637 {
2638 windows->popup.mapped=MagickTrue;
2639 break;
2640 }
2641 if (event.xmap.window == windows->widget.id)
2642 {
2643 windows->widget.mapped=MagickTrue;
2644 break;
2645 }
2646 break;
2647 }
2648 case MappingNotify:
2649 {
2650 (void) XRefreshKeyboardMapping(&event.xmapping);
2651 break;
2652 }
2653 case NoExpose:
2654 break;
2655 case PropertyNotify:
2656 {
2657 Atom
2658 type;
2659
2660 int
2661 format,
2662 status;
2663
2664 unsigned char
2665 *data;
2666
cristyf2faecf2010-05-28 19:19:36 +00002667 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002668 after,
2669 length;
2670
2671 if (display_image->debug != MagickFalse)
2672 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00002673 "Property Notify: 0x%lx 0x%lx %d",(unsigned long)
2674 event.xproperty.window,(unsigned long) event.xproperty.atom,
2675 event.xproperty.state);
cristy3ed852e2009-09-05 21:47:34 +00002676 if (event.xproperty.atom != windows->im_remote_command)
2677 break;
2678 /*
2679 Display image named by the remote command protocol.
2680 */
2681 status=XGetWindowProperty(display,event.xproperty.window,
cristycee97112010-05-28 00:44:52 +00002682 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
cristy3ed852e2009-09-05 21:47:34 +00002683 AnyPropertyType,&type,&format,&length,&after,&data);
2684 if ((status != Success) || (length == 0))
2685 break;
2686 (void) CopyMagickString(resource_info->image_info->filename,
2687 (char *) data,MaxTextExtent);
2688 nexus=ReadImage(resource_info->image_info,&image->exception);
2689 CatchException(&image->exception);
2690 if (nexus != (Image *) NULL)
2691 state|=ExitState;
2692 (void) XFree((void *) data);
2693 break;
2694 }
2695 case ReparentNotify:
2696 {
2697 if (display_image->debug != MagickFalse)
2698 (void) LogMagickEvent(X11Event,GetMagickModule(),
2699 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
2700 event.xreparent.window);
2701 break;
2702 }
2703 case UnmapNotify:
2704 {
2705 if (display_image->debug != MagickFalse)
2706 (void) LogMagickEvent(X11Event,GetMagickModule(),
2707 "Unmap Notify: 0x%lx",event.xunmap.window);
2708 if (event.xunmap.window == windows->backdrop.id)
2709 {
2710 windows->backdrop.mapped=MagickFalse;
2711 break;
2712 }
2713 if (event.xunmap.window == windows->image.id)
2714 {
2715 windows->image.mapped=MagickFalse;
2716 break;
2717 }
2718 if (event.xunmap.window == windows->info.id)
2719 {
2720 windows->info.mapped=MagickFalse;
2721 break;
2722 }
2723 if (event.xunmap.window == windows->icon.id)
2724 {
2725 if (map_info->colormap == icon_map->colormap)
2726 XConfigureImageColormap(display,resource_info,windows,
2727 display_image);
2728 (void) XFreeStandardColormap(display,icon_visual,icon_map,
2729 icon_pixel);
2730 windows->icon.mapped=MagickFalse;
2731 break;
2732 }
2733 if (event.xunmap.window == windows->command.id)
2734 {
2735 windows->command.mapped=MagickFalse;
2736 break;
2737 }
2738 if (event.xunmap.window == windows->popup.id)
2739 {
2740 if (windows->backdrop.id != (Window) NULL)
2741 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2742 CurrentTime);
2743 windows->popup.mapped=MagickFalse;
2744 break;
2745 }
2746 if (event.xunmap.window == windows->widget.id)
2747 {
2748 if (windows->backdrop.id != (Window) NULL)
2749 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
2750 CurrentTime);
2751 windows->widget.mapped=MagickFalse;
2752 break;
2753 }
2754 break;
2755 }
2756 default:
2757 {
2758 if (display_image->debug != MagickFalse)
2759 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
2760 event.type);
2761 break;
2762 }
2763 }
2764 }
2765 while (!(state & ExitState));
2766 image_list=(Image **) RelinquishMagickMemory(image_list);
2767 images=DestroyImageList(images);
2768 if ((windows->visual_info->klass == GrayScale) ||
2769 (windows->visual_info->klass == PseudoColor) ||
2770 (windows->visual_info->klass == DirectColor))
2771 {
2772 /*
2773 Withdraw windows.
2774 */
2775 if (windows->info.mapped)
2776 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2777 if (windows->command.mapped)
2778 (void) XWithdrawWindow(display,windows->command.id,
2779 windows->command.screen);
2780 }
2781 if (resource_info->backdrop == MagickFalse)
2782 if (windows->backdrop.mapped)
2783 {
2784 (void) XWithdrawWindow(display,windows->backdrop.id,\
2785 windows->backdrop.screen);
2786 (void) XDestroyWindow(display,windows->backdrop.id);
2787 windows->backdrop.id=(Window) NULL;
2788 (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);
2789 (void) XDestroyWindow(display,windows->image.id);
2790 windows->image.id=(Window) NULL;
2791 }
2792 XSetCursorState(display,windows,MagickTrue);
2793 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00002794 for (scene=1; scene < (ssize_t) number_scenes; scene++)
cristy3ed852e2009-09-05 21:47:34 +00002795 {
2796 if (windows->image.pixmaps[scene] != (Pixmap) NULL)
2797 (void) XFreePixmap(display,windows->image.pixmaps[scene]);
2798 windows->image.pixmaps[scene]=(Pixmap) NULL;
2799 if (windows->image.matte_pixmaps[scene] != (Pixmap) NULL)
2800 (void) XFreePixmap(display,windows->image.matte_pixmaps[scene]);
2801 windows->image.matte_pixmaps[scene]=(Pixmap) NULL;
2802 }
cristy04e11fd2010-03-19 16:01:44 +00002803 XSetCursorState(display,windows,MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00002804 windows->image.pixmaps=(Pixmap *)
2805 RelinquishMagickMemory(windows->image.pixmaps);
2806 windows->image.matte_pixmaps=(Pixmap *)
2807 RelinquishMagickMemory(windows->image.matte_pixmaps);
2808 if (nexus == (Image *) NULL)
2809 {
2810 /*
2811 Free X resources.
2812 */
2813 if (windows->image.mapped != MagickFalse)
2814 (void) XWithdrawWindow(display,windows->image.id,windows->image.screen); XDelay(display,SuspendTime);
2815 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
2816 if (resource_info->map_type == (char *) NULL)
2817 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
2818 DestroyXResources();
2819 }
2820 (void) XSync(display,MagickFalse);
2821 /*
2822 Restore our progress monitor and warning handlers.
2823 */
2824 (void) SetErrorHandler(warning_handler);
2825 (void) SetWarningHandler(warning_handler);
2826 /*
2827 Change to home directory.
2828 */
2829 cwd=getcwd(working_directory,MaxTextExtent);
2830 status=chdir(resource_info->home_directory);
2831 if (status == -1)
2832 (void) ThrowMagickException(&images->exception,GetMagickModule(),
2833 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
2834 return(nexus);
2835}
2836
2837/*
2838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839% %
2840% %
2841% %
2842+ X S a v e I m a g e %
2843% %
2844% %
2845% %
2846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847%
2848% XSaveImage() saves an image to a file.
2849%
2850% The format of the XSaveImage method is:
2851%
2852% MagickBooleanType XSaveImage(Display *display,
2853% XResourceInfo *resource_info,XWindows *windows,Image *image)
2854%
2855% A description of each parameter follows:
2856%
2857% o status: Method XSaveImage return True if the image is
2858% written. False is returned is there is a memory shortage or if the
2859% image fails to write.
2860%
2861% o display: Specifies a connection to an X server; returned from
2862% XOpenDisplay.
2863%
2864% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2865%
2866% o windows: Specifies a pointer to a XWindows structure.
2867%
2868% o image: the image.
2869%
2870*/
2871static MagickBooleanType XSaveImage(Display *display,
2872 XResourceInfo *resource_info,XWindows *windows,Image *image)
2873{
2874 char
2875 filename[MaxTextExtent];
2876
2877 ImageInfo
2878 *image_info;
2879
2880 MagickStatusType
2881 status;
2882
2883 /*
2884 Request file name from user.
2885 */
2886 if (resource_info->write_filename != (char *) NULL)
2887 (void) CopyMagickString(filename,resource_info->write_filename,
2888 MaxTextExtent);
2889 else
2890 {
2891 char
2892 path[MaxTextExtent];
2893
2894 int
2895 status;
2896
2897 GetPathComponent(image->filename,HeadPath,path);
2898 GetPathComponent(image->filename,TailPath,filename);
2899 status=chdir(path);
2900 if (status == -1)
2901 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2902 FileOpenError,"UnableToOpenFile","%s",path);
2903 }
2904 XFileBrowserWidget(display,windows,"Save",filename);
2905 if (*filename == '\0')
2906 return(MagickTrue);
2907 if (IsPathAccessible(filename) != MagickFalse)
2908 {
2909 int
2910 status;
2911
2912 /*
2913 File exists-- seek user's permission before overwriting.
2914 */
2915 status=XConfirmWidget(display,windows,"Overwrite",filename);
2916 if (status == 0)
2917 return(MagickTrue);
2918 }
2919 image_info=CloneImageInfo(resource_info->image_info);
2920 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00002921 (void) SetImageInfo(image_info,1,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00002922 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
2923 (LocaleCompare(image_info->magick,"JPG") == 0))
2924 {
2925 char
2926 quality[MaxTextExtent];
2927
2928 int
2929 status;
2930
2931 /*
2932 Request JPEG quality from user.
2933 */
cristye8c25f92010-06-03 00:53:06 +00002934 (void) FormatMagickString(quality,MaxTextExtent,"%.20g",(double)
2935 image_info->quality);
cristy3ed852e2009-09-05 21:47:34 +00002936 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
2937 quality);
2938 if (*quality == '\0')
2939 return(MagickTrue);
cristye27293e2009-12-18 02:53:20 +00002940 image->quality=StringToUnsignedLong(quality);
cristy3ed852e2009-09-05 21:47:34 +00002941 image_info->interlace=status != MagickFalse ? NoInterlace :
2942 PlaneInterlace;
2943 }
2944 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
2945 (LocaleCompare(image_info->magick,"PDF") == 0) ||
2946 (LocaleCompare(image_info->magick,"PS") == 0) ||
2947 (LocaleCompare(image_info->magick,"PS2") == 0))
2948 {
2949 char
2950 geometry[MaxTextExtent];
2951
2952 /*
2953 Request page geometry from user.
2954 */
cristy42c2d972009-09-13 01:12:39 +00002955 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00002956 if (LocaleCompare(image_info->magick,"PDF") == 0)
cristy42c2d972009-09-13 01:12:39 +00002957 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00002958 if (image_info->page != (char *) NULL)
2959 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
2960 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
2961 "Select page geometry:",geometry);
2962 if (*geometry != '\0')
2963 image_info->page=GetPageGeometry(geometry);
2964 }
2965 /*
2966 Write image.
2967 */
2968 image=GetFirstImageInList(image);
2969 status=WriteImages(image_info,image,filename,&image->exception);
2970 if (status != MagickFalse)
2971 image->taint=MagickFalse;
2972 image_info=DestroyImageInfo(image_info);
2973 XSetCursorState(display,windows,MagickFalse);
2974 return(status != 0 ? MagickTrue : MagickFalse);
2975}
2976#else
2977
2978/*
2979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2980% %
2981% %
2982% %
2983+ A n i m a t e I m a g e s %
2984% %
2985% %
2986% %
2987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2988%
2989% AnimateImages() repeatedly displays an image sequence to any X window
2990% screen. It returns a value other than 0 if successful. Check the
2991% exception member of image to determine the reason for any failure.
2992%
2993% The format of the AnimateImages method is:
2994%
2995% MagickBooleanType AnimateImages(const ImageInfo *image_info,
2996% Image *images)
2997%
2998% A description of each parameter follows:
2999%
3000% o image_info: the image info.
3001%
3002% o image: the image.
3003%
3004*/
3005MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
3006 Image *image)
3007{
3008 assert(image_info != (const ImageInfo *) NULL);
3009 assert(image_info->signature == MagickSignature);
3010 assert(image != (Image *) NULL);
3011 assert(image->signature == MagickSignature);
3012 if (image->debug != MagickFalse)
3013 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3014 (void) ThrowMagickException(&image->exception,GetMagickModule(),
3015 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
3016 image->filename);
3017 return(MagickFalse);
3018}
3019#endif