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