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