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