/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % AAA N N IIIII M M AAA TTTTT EEEEE % % A A NN N I MM MM A A T E % % AAAAA N N N I M M M AAAAA T EEE % % A A N NN I M M A A T E % % A A N N IIIII M M A A T EEEEE % % % % % % Methods to Interactively Animate an Image Sequence % % % % Software Design % % Cristy % % July 1992 % % % % % % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % % obtain a copy of the License at % % % % https://imagemagick.org/script/license.php % % % % Unless required by applicable law or agreed to in writing, software % % distributed under the License is distributed on an "AS IS" BASIS, % % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % % See the License for the specific language governing permissions and % % limitations under the License. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % */ /* Include declarations. */ #include "MagickCore/studio.h" #include "MagickCore/animate.h" #include "MagickCore/animate-private.h" #include "MagickCore/attribute.h" #include "MagickCore/client.h" #include "MagickCore/color.h" #include "MagickCore/color-private.h" #include "MagickCore/colorspace.h" #include "MagickCore/colorspace-private.h" #include "MagickCore/constitute.h" #include "MagickCore/delegate.h" #include "MagickCore/exception.h" #include "MagickCore/exception-private.h" #include "MagickCore/geometry.h" #include "MagickCore/image-private.h" #include "MagickCore/layer.h" #include "MagickCore/list.h" #include "MagickCore/log.h" #include "MagickCore/image.h" #include "MagickCore/memory_.h" #include "MagickCore/monitor.h" #include "MagickCore/monitor-private.h" #include "MagickCore/option.h" #include "MagickCore/pixel-accessor.h" #include "MagickCore/property.h" #include "MagickCore/resource_.h" #include "MagickCore/string_.h" #include "MagickCore/string-private.h" #include "MagickCore/timer-private.h" #include "MagickCore/transform.h" #include "MagickCore/utility.h" #include "MagickCore/utility-private.h" #include "MagickCore/version.h" #include "MagickCore/widget.h" #include "MagickCore/widget-private.h" #include "MagickCore/xwindow.h" #include "MagickCore/xwindow-private.h" #if defined(MAGICKCORE_X11_DELEGATE) /* Animate state declarations. */ #define AutoReverseAnimationState 0x0004 #define ForwardAnimationState 0x0008 #define HighlightState 0x0010 #define PlayAnimationState 0x0020 #define RepeatAnimationState 0x0040 #define StepAnimationState 0x0080 /* Static declarations. */ static const char AnimateHelp[] = { "BUTTONS\n" "\n" " Press any button to map or unmap the Command widget.\n" "\n" "COMMAND WIDGET\n" " The Command widget lists a number of sub-menus and commands.\n" " They are\n" "\n" " Animate\n" " Open...\n" " Save...\n" " Play\n" " Step\n" " Repeat\n" " Auto Reverse\n" " Speed\n" " Slower\n" " Faster\n" " Direction\n" " Forward\n" " Reverse\n" " Help\n" " Overview\n" " Browse Documentation\n" " About Animate\n" " Image Info\n" " Quit\n" "\n" " Menu items with a indented triangle have a sub-menu. They\n" " are represented above as the indented items. To access a\n" " sub-menu item, move the pointer to the appropriate menu and\n" " press a button and drag. When you find the desired sub-menu\n" " item, release the button and the command is executed. Move\n" " the pointer away from the sub-menu if you decide not to\n" " execute a particular command.\n" "\n" "KEYBOARD ACCELERATORS\n" " Accelerators are one or two key presses that effect a\n" " particular command. The keyboard accelerators that\n" " animate(1) understands is:\n" "\n" " Ctl+O Press to open an image from a file.\n" "\n" " space Press to display the next image in the sequence.\n" "\n" " < Press to speed-up the display of the images. Refer to\n" " -delay for more information.\n" "\n" " > Press to slow the display of the images. Refer to\n" " -delay for more information.\n" "\n" " F1 Press to display helpful information about animate(1).\n" "\n" " Find Press to browse documentation about ImageMagick.\n" "\n" " ? Press to display information about the image. Press\n" " any key or button to erase the information.\n" "\n" " This information is printed: image name; image size;\n" " and the total number of unique colors in the image.\n" "\n" " Ctl-q Press to discard all images and exit program.\n" }; /* Constant declarations. */ static const char *PageSizes[] = { "Letter", "Tabloid", "Ledger", "Legal", "Statement", "Executive", "A3", "A4", "A5", "B4", "B5", "Folio", "Quarto", "10x14", (char *) NULL }; static const unsigned char HighlightBitmap[8] = { (unsigned char) 0xaa, (unsigned char) 0x55, (unsigned char) 0xaa, (unsigned char) 0x55, (unsigned char) 0xaa, (unsigned char) 0x55, (unsigned char) 0xaa, (unsigned char) 0x55 }, ShadowBitmap[8] = { (unsigned char) 0x00, (unsigned char) 0x00, (unsigned char) 0x00, (unsigned char) 0x00, (unsigned char) 0x00, (unsigned char) 0x00, (unsigned char) 0x00, (unsigned char) 0x00 }; /* Enumeration declarations. */ typedef enum { OpenCommand, SaveCommand, PlayCommand, StepCommand, RepeatCommand, AutoReverseCommand, SlowerCommand, FasterCommand, ForwardCommand, ReverseCommand, HelpCommand, BrowseDocumentationCommand, VersionCommand, InfoCommand, QuitCommand, StepBackwardCommand, StepForwardCommand, NullCommand } CommandType; /* Stipples. */ #define HighlightWidth 8 #define HighlightHeight 8 #define ShadowWidth 8 #define ShadowHeight 8 /* Forward declarations. */ static Image *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, Image **,MagickStatusType *,ExceptionInfo *); static MagickBooleanType XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % A n i m a t e I m a g e s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AnimateImages() repeatedly displays an image sequence to any X window % screen. It returns a value other than 0 if successful. Check the % exception member of image to determine the reason for any failure. % % The format of the AnimateImages method is: % % MagickBooleanType AnimateImages(const ImageInfo *image_info, % Image *images,ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o image: the image. % % o exception: return any errors or warnings in this structure. % */ MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info, Image *images,ExceptionInfo *exception) { char *argv[1]; Display *display; MagickStatusType status; XrmDatabase resource_database; XResourceInfo resource_info; assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickCoreSignature); assert(images != (Image *) NULL); assert(images->signature == MagickCoreSignature); if (images->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); display=XOpenDisplay(image_info->server_name); if (display == (Display *) NULL) { (void) ThrowMagickException(exception,GetMagickModule(),XServerError, "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); return(MagickFalse); } if (exception->severity != UndefinedException) CatchException(exception); (void) XSetErrorHandler(XError); resource_database=XGetResourceDatabase(display,GetClientName()); (void) memset(&resource_info,0,sizeof(XResourceInfo)); XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); if (image_info->page != (char *) NULL) resource_info.image_geometry=AcquireString(image_info->page); resource_info.immutable=MagickTrue; argv[0]=AcquireString(GetClientName()); (void) XAnimateImages(display,&resource_info,argv,1,images,exception); (void) SetErrorHandler((ErrorHandler) NULL); (void) SetWarningHandler((WarningHandler) NULL); argv[0]=DestroyString(argv[0]); (void) XCloseDisplay(display); XDestroyResourceInfo(&resource_info); status=exception->severity == UndefinedException ? MagickTrue : MagickFalse; return(status != 0 ? MagickTrue : MagickFalse); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X M a g i c k C o m m a n d % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XMagickCommand() makes a transform to the image or Image window as specified % by a user menu button or keyboard command. % % The format of the XMagickCommand method is: % % Image *XMagickCommand(Display *display,XResourceInfo *resource_info, % XWindows *windows,const CommandType command_type,Image **image, % MagickStatusType *state,ExceptionInfo *exception) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. % % o windows: Specifies a pointer to a XWindows structure. % % o image: the image; XMagickCommand % may transform the image and return a new image pointer. % % o state: Specifies a MagickStatusType; XMagickCommand may return a % modified state. % % o exception: return any errors or warnings in this structure. % % */ static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, XWindows *windows,const CommandType command_type,Image **image, MagickStatusType *state,ExceptionInfo *exception) { Image *nexus; MagickBooleanType proceed; MagickStatusType status; XTextProperty window_name; /* Process user command. */ nexus=NewImageList(); switch (command_type) { case OpenCommand: { char **filelist; Image *images, *next; ImageInfo *read_info; int number_files; int i; static char filenames[MagickPathExtent] = "*"; if (resource_info->immutable != MagickFalse) break; /* Request file name from user. */ XFileBrowserWidget(display,windows,"Animate",filenames); if (*filenames == '\0') return((Image *) NULL); /* Expand the filenames. */ filelist=(char **) AcquireMagickMemory(sizeof(char *)); if (filelist == (char **) NULL) { ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", filenames); return((Image *) NULL); } number_files=1; filelist[0]=filenames; status=ExpandFilenames(&number_files,&filelist); if ((status == MagickFalse) || (number_files == 0)) { for (i=0; i < number_files; i++) filelist[i]=DestroyString(filelist[i]); filelist=(char **) RelinquishMagickMemory(filelist); if (number_files == 0) { ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames); return((Image *) NULL); } ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", filenames); return((Image *) NULL); } read_info=CloneImageInfo(resource_info->image_info); images=NewImageList(); XSetCursorState(display,windows,MagickTrue); XCheckRefreshWindows(display,windows); for (i=0; i < number_files; i++) { (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent); filelist[i]=DestroyString(filelist[i]); *read_info->magick='\0'; next=ReadImage(read_info,exception); CatchException(exception); if (next != (Image *) NULL) AppendImageToList(&images,next); if (number_files <= 5) continue; proceed=SetImageProgress(images,LoadImageTag,i,(MagickSizeType) number_files); if (proceed == MagickFalse) break; } filelist=(char **) RelinquishMagickMemory(filelist); read_info=DestroyImageInfo(read_info); if (images == (Image *) NULL) { XSetCursorState(display,windows,MagickFalse); ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames); return((Image *) NULL); } nexus=GetFirstImageInList(images); *state|=ExitState; break; } case PlayCommand: { char basename[MagickPathExtent], name[MagickPathExtent]; int status; /* Window name is the base of the filename. */ *state|=PlayAnimationState; *state&=(~AutoReverseAnimationState); GetPathComponent((*image)->magick_filename,BasePath,basename); (void) FormatLocaleString(name,MagickPathExtent,"%s: %s", MagickPackageName,basename); (void) CloneString(&windows->image.name,name); if (resource_info->title != (char *) NULL) { char *title; title=InterpretImageProperties(resource_info->image_info,*image, resource_info->title,exception); (void) CloneString(&windows->image.name,title); title=DestroyString(title); } status=XStringListToTextProperty(&windows->image.name,1,&window_name); if (status == 0) break; XSetWMName(display,windows->image.id,&window_name); (void) XFree((void *) window_name.value); break; } case StepCommand: case StepBackwardCommand: case StepForwardCommand: { *state|=StepAnimationState; *state&=(~PlayAnimationState); if (command_type == StepBackwardCommand) *state&=(~ForwardAnimationState); if (command_type == StepForwardCommand) *state|=ForwardAnimationState; if (resource_info->title != (char *) NULL) break; break; } case RepeatCommand: { *state|=RepeatAnimationState; *state&=(~AutoReverseAnimationState); *state|=PlayAnimationState; break; } case AutoReverseCommand: { *state|=AutoReverseAnimationState; *state&=(~RepeatAnimationState); *state|=PlayAnimationState; break; } case SaveCommand: { /* Save image. */ status=XSaveImage(display,resource_info,windows,*image,exception); if (status == MagickFalse) { char message[MagickPathExtent]; (void) FormatLocaleString(message,MagickPathExtent,"%s:%s", exception->reason != (char *) NULL ? exception->reason : "", exception->description != (char *) NULL ? exception->description : ""); XNoticeWidget(display,windows,"Unable to save file:",message); break; } break; } case SlowerCommand: { resource_info->delay++; break; } case FasterCommand: { if (resource_info->delay == 0) break; resource_info->delay--; break; } case ForwardCommand: { *state=ForwardAnimationState; *state&=(~AutoReverseAnimationState); break; } case ReverseCommand: { *state&=(~ForwardAnimationState); *state&=(~AutoReverseAnimationState); break; } case InfoCommand: { XDisplayImageInfo(display,resource_info,windows,(Image *) NULL,*image, exception); break; } case HelpCommand: { /* User requested help. */ XTextViewHelp(display,resource_info,windows,MagickFalse, "Help Viewer - Animate",AnimateHelp); break; } case BrowseDocumentationCommand: { Atom mozilla_atom; Window mozilla_window, root_window; /* Browse the ImageMagick documentation. */ root_window=XRootWindow(display,XDefaultScreen(display)); mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); if (mozilla_window != (Window) NULL) { char command[MagickPathExtent]; /* Display documentation using Netscape remote control. */ (void) FormatLocaleString(command,MagickPathExtent, "openurl(%s,new-tab)",MagickAuthoritativeURL); mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); (void) XChangeProperty(display,mozilla_window,mozilla_atom, XA_STRING,8,PropModeReplace,(unsigned char *) command, (int) strlen(command)); XSetCursorState(display,windows,MagickFalse); break; } XSetCursorState(display,windows,MagickTrue); XCheckRefreshWindows(display,windows); status=InvokeDelegate(resource_info->image_info,*image,"browse", (char *) NULL,exception); if (status == MagickFalse) XNoticeWidget(display,windows,"Unable to browse documentation", (char *) NULL); XDelay(display,1500); XSetCursorState(display,windows,MagickFalse); break; } case VersionCommand: { XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), GetMagickCopyright()); break; } case QuitCommand: { /* exit program */ if (resource_info->confirm_exit == MagickFalse) XClientMessage(display,windows->image.id,windows->im_protocols, windows->im_exit,CurrentTime); else { int status; /* Confirm program exit. */ status=XConfirmWidget(display,windows,"Do you really want to exit", resource_info->client_name); if (status != 0) XClientMessage(display,windows->image.id,windows->im_protocols, windows->im_exit,CurrentTime); } break; } default: break; } return(nexus); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X A n i m a t e B a c k g r o u n d I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XAnimateBackgroundImage() animates an image sequence in the background of % a window. % % The format of the XAnimateBackgroundImage method is: % % void XAnimateBackgroundImage(Display *display, % XResourceInfo *resource_info,Image *images,ExceptionInfo *exception) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. % % o images: the image list. % % o exception: return any errors or warnings in this structure. % */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif static int SceneCompare(const void *x,const void *y) { const Image **image_1, **image_2; image_1=(const Image **) x; image_2=(const Image **) y; return((int) ((*image_1)->scene-(*image_2)->scene)); } #if defined(__cplusplus) || defined(c_plusplus) } #endif MagickExport void XAnimateBackgroundImage(Display *display, XResourceInfo *resource_info,Image *images,ExceptionInfo *exception) { char geometry[MagickPathExtent], visual_type[MagickPathExtent]; Image *coalesce_image, *display_image, **image_list; int scene; MagickStatusType status; RectangleInfo geometry_info; ssize_t i; size_t delay, number_scenes; ssize_t iterations; static XPixelInfo pixel; static XStandardColormap *map_info; static XVisualInfo *visual_info = (XVisualInfo *) NULL; static XWindowInfo window_info; unsigned int height, width; Window root_window; XEvent event; XGCValues context_values; XResourceInfo resources; XWindowAttributes window_attributes; /* Determine target window. */ assert(images != (Image *) NULL); assert(images->signature == MagickCoreSignature); if (images->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); resources=(*resource_info); window_info.id=(Window) NULL; root_window=XRootWindow(display,XDefaultScreen(display)); if (LocaleCompare(resources.window_id,"root") == 0) window_info.id=root_window; else { if (isdigit((int) ((unsigned char) *resources.window_id)) != 0) window_info.id=XWindowByID(display,root_window, (Window) strtol((char *) resources.window_id,(char **) NULL,0)); if (window_info.id == (Window) NULL) window_info.id= XWindowByName(display,root_window,resources.window_id); } if (window_info.id == (Window) NULL) { ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists", resources.window_id); return; } /* Determine window visual id. */ window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); (void) CopyMagickString(visual_type,"default",MagickPathExtent); status=XGetWindowAttributes(display,window_info.id,&window_attributes) != 0 ? MagickTrue : MagickFalse; if (status != MagickFalse) (void) FormatLocaleString(visual_type,MagickPathExtent,"0x%lx", XVisualIDFromVisual(window_attributes.visual)); if (visual_info == (XVisualInfo *) NULL) { /* Allocate standard colormap. */ map_info=XAllocStandardColormap(); if (map_info == (XStandardColormap *) NULL) ThrowXWindowFatalException(ResourceLimitFatalError, "MemoryAllocationFailed",images->filename); map_info->colormap=(Colormap) NULL; pixel.pixels=(unsigned long *) NULL; /* Initialize visual info. */ resources.map_type=(char *) NULL; resources.visual_type=visual_type; visual_info=XBestVisualInfo(display,map_info,&resources); if (visual_info == (XVisualInfo *) NULL) ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", images->filename); /* Initialize window info. */ window_info.ximage=(XImage *) NULL; window_info.matte_image=(XImage *) NULL; window_info.pixmap=(Pixmap) NULL; window_info.matte_pixmap=(Pixmap) NULL; } /* Free previous root colors. */ if (window_info.id == root_window) XDestroyWindowColors(display,root_window); coalesce_image=CoalesceImages(images,exception); if (coalesce_image == (Image *) NULL) ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed", images->filename); images=coalesce_image; if (resources.map_type == (char *) NULL) if ((visual_info->klass != TrueColor) && (visual_info->klass != DirectColor)) { Image *next; /* Determine if the sequence of images has the identical colormap. */ for (next=images; next != (Image *) NULL; ) { next->alpha_trait=UndefinedPixelTrait; if ((next->storage_class == DirectClass) || (next->colors != images->colors) || (next->colors > (size_t) visual_info->colormap_size)) break; for (i=0; i < (ssize_t) images->colors; i++) if (IsPixelInfoEquivalent(next->colormap+i,images->colormap+i) == MagickFalse) break; if (i < (ssize_t) images->colors) break; next=GetNextImageInList(next); } if (next != (Image *) NULL) (void) RemapImages(resources.quantize_info,images,(Image *) NULL, exception); } /* Sort images by increasing scene number. */ number_scenes=GetImageListLength(images); image_list=ImageListToArray(images,exception); if (image_list == (Image **) NULL) ThrowXWindowFatalException(ResourceLimitFatalError, "MemoryAllocationFailed",images->filename); for (i=0; i < (ssize_t) number_scenes; i++) if (image_list[i]->scene == 0) break; if (i == (ssize_t) number_scenes) qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare); /* Initialize Standard Colormap. */ resources.colormap=SharedColormap; display_image=image_list[0]; for (scene=0; scene < (int) number_scenes; scene++) { if ((resource_info->map_type != (char *) NULL) || (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor)) (void) SetImageType(image_list[scene],image_list[scene]->alpha_trait == BlendPixelTrait ? TrueColorType : TrueColorAlphaType,exception); if ((display_image->columns < image_list[scene]->columns) && (display_image->rows < image_list[scene]->rows)) display_image=image_list[scene]; } if ((resource_info->map_type != (char *) NULL) || (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor)) (void) SetImageType(display_image,display_image->alpha_trait != BlendPixelTrait ? TrueColorType : TrueColorAlphaType,exception); XMakeStandardColormap(display,visual_info,&resources,display_image,map_info, &pixel,exception); /* Graphic context superclass. */ context_values.background=pixel.background_color.pixel; context_values.foreground=pixel.foreground_color.pixel; pixel.annotate_context=XCreateGC(display,window_info.id,(unsigned long) (GCBackground | GCForeground),&context_values); if (pixel.annotate_context == (GC) NULL) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", images->filename); /* Initialize Image window attributes. */ XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, &resources,&window_info); /* Create the X image. */ window_info.width=(unsigned int) image_list[0]->columns; window_info.height=(unsigned int) image_list[0]->rows; if ((image_list[0]->columns != window_info.width) || (image_list[0]->rows != window_info.height)) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", image_list[0]->filename); (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>", window_attributes.width,window_attributes.height); geometry_info.width=window_info.width; geometry_info.height=window_info.height; geometry_info.x=(ssize_t) window_info.x; geometry_info.y=(ssize_t) window_info.y; (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, &geometry_info.width,&geometry_info.height); window_info.width=(unsigned int) geometry_info.width; window_info.height=(unsigned int) geometry_info.height; window_info.x=(int) geometry_info.x; window_info.y=(int) geometry_info.y; status=XMakeImage(display,&resources,&window_info,image_list[0], window_info.width,window_info.height,exception); if (status == MagickFalse) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", images->filename); window_info.x=0; window_info.y=0; if (display_image->debug != MagickFalse) { (void) LogMagickEvent(X11Event,GetMagickModule(), "Image: %s[%.20g] %.20gx%.20g ",image_list[0]->filename,(double) image_list[0]->scene,(double) image_list[0]->columns,(double) image_list[0]->rows); if (image_list[0]->colors != 0) (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) image_list[0]->colors); (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", image_list[0]->magick); } /* Adjust image dimensions as specified by backdrop or geometry options. */ width=window_info.width; height=window_info.height; if (resources.backdrop != MagickFalse) { /* Center image on window. */ window_info.x=(int) (window_attributes.width/2)- (window_info.ximage->width/2); window_info.y=(int) (window_attributes.height/2)- (window_info.ximage->height/2); width=(unsigned int) window_attributes.width; height=(unsigned int) window_attributes.height; } if (resources.image_geometry != (char *) NULL) { char default_geometry[MagickPathExtent]; int flags, gravity; XSizeHints *size_hints; /* User specified geometry. */ size_hints=XAllocSizeHints(); if (size_hints == (XSizeHints *) NULL) ThrowXWindowFatalException(ResourceLimitFatalError, "MemoryAllocationFailed",images->filename); size_hints->flags=0L; (void) FormatLocaleString(default_geometry,MagickPathExtent,"%ux%u",width, height); flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, default_geometry,window_info.border_width,size_hints,&window_info.x, &window_info.y,(int *) &width,(int *) &height,&gravity); if (((flags & (XValue | YValue))) != 0) { width=(unsigned int) window_attributes.width; height=(unsigned int) window_attributes.height; } (void) XFree((void *) size_hints); } /* Create the X pixmap. */ window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, (unsigned int) height,window_info.depth); if (window_info.pixmap == (Pixmap) NULL) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", images->filename); /* Display pixmap on the window. */ if (((unsigned int) width > window_info.width) || ((unsigned int) height > window_info.height)) (void) XFillRectangle(display,window_info.pixmap, window_info.annotate_context,0,0,(unsigned int) width, (unsigned int) height); (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, window_info.ximage,0,0,window_info.x,window_info.y,window_info.width, window_info.height); (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); (void) XClearWindow(display,window_info.id); /* Initialize image pixmaps structure. */ window_info.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes, sizeof(*window_info.pixmaps)); window_info.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes, sizeof(*window_info.matte_pixmaps)); if ((window_info.pixmaps == (Pixmap *) NULL) || (window_info.matte_pixmaps == (Pixmap *) NULL)) ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed", images->filename); window_info.pixmaps[0]=window_info.pixmap; window_info.matte_pixmaps[0]=window_info.pixmap; for (scene=1; scene < (int) number_scenes; scene++) { unsigned int columns, rows; /* Create X image. */ window_info.pixmap=(Pixmap) NULL; window_info.matte_pixmap=(Pixmap) NULL; if ((resources.map_type != (char *) NULL) || (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor)) if (image_list[scene]->storage_class == PseudoClass) XGetPixelInfo(display,visual_info,map_info,&resources, image_list[scene],window_info.pixel_info); columns=(unsigned int) image_list[scene]->columns; rows=(unsigned int) image_list[scene]->rows; if ((image_list[scene]->columns != columns) || (image_list[scene]->rows != rows)) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", image_list[scene]->filename); status=XMakeImage(display,&resources,&window_info,image_list[scene], columns,rows,exception); if (status == MagickFalse) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", images->filename); if (display_image->debug != MagickFalse) { (void) LogMagickEvent(X11Event,GetMagickModule(), "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene, image_list[scene]->filename,(double) columns,(double) rows); if (image_list[scene]->colors != 0) (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) image_list[scene]->colors); (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", image_list[scene]->magick); } /* Create the X pixmap. */ window_info.pixmap=XCreatePixmap(display,window_info.id,width,height, window_info.depth); if (window_info.pixmap == (Pixmap) NULL) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", images->filename); /* Display pixmap on the window. */ if ((width > window_info.width) || (height > window_info.height)) (void) XFillRectangle(display,window_info.pixmap, window_info.annotate_context,0,0,width,height); (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, window_info.ximage,0,0,window_info.x,window_info.y,window_info.width, window_info.height); (void) XSetWindowBackgroundPixmap(display,window_info.id, window_info.pixmap); (void) XClearWindow(display,window_info.id); window_info.pixmaps[scene]=window_info.pixmap; window_info.matte_pixmaps[scene]=window_info.matte_pixmap; if (image_list[scene]->alpha_trait) (void) XClearWindow(display,window_info.id); delay=1000*image_list[scene]->delay/MagickMax( image_list[scene]->ticks_per_second,1L); XDelay(display,resources.delay*(delay == 0 ? 10 : delay)); } window_info.pixel_info=(&pixel); /* Display pixmap on the window. */ (void) XSelectInput(display,window_info.id,SubstructureNotifyMask); event.type=Expose; iterations=0; do { for (scene=0; scene < (int) number_scenes; scene++) { if (XEventsQueued(display,QueuedAfterFlush) > 0) { (void) XNextEvent(display,&event); if (event.type == DestroyNotify) break; } window_info.pixmap=window_info.pixmaps[scene]; window_info.matte_pixmap=window_info.matte_pixmaps[scene]; (void) XSetWindowBackgroundPixmap(display,window_info.id, window_info.pixmap); (void) XClearWindow(display,window_info.id); (void) XSync(display,MagickFalse); delay=1000*image_list[scene]->delay/MagickMax( image_list[scene]->ticks_per_second,1L); XDelay(display,resources.delay*(delay == 0 ? 10 : delay)); } iterations++; if (iterations == (ssize_t) image_list[0]->iterations) break; } while (event.type != DestroyNotify); (void) XSync(display,MagickFalse); image_list=(Image **) RelinquishMagickMemory(image_list); images=DestroyImageList(images); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X A n i m a t e I m a g e s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XAnimateImages() displays an image via X11. % % The format of the XAnimateImages method is: % % Image *XAnimateImages(Display *display,XResourceInfo *resource_info, % char **argv,const int argc,Image *images,ExceptionInfo *exception) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. % % o argv: Specifies the application's argument list. % % o argc: Specifies the number of arguments. % % o images: the image list. % % o exception: return any errors or warnings in this structure. % */ MagickExport Image *XAnimateImages(Display *display, XResourceInfo *resource_info,char **argv,const int argc,Image *images, ExceptionInfo *exception) { #define MagickMenus 4 #define MaXWindows 8 #define MagickTitle "Commands" const char *const CommandMenu[]= { "Animate", "Speed", "Direction", "Help", "Image Info", "Quit", (char *) NULL }, *const AnimateMenu[]= { "Open...", "Play", "Step", "Repeat", "Auto Reverse", "Save...", (char *) NULL }, *const SpeedMenu[]= { "Faster", "Slower", (char *) NULL }, *const DirectionMenu[]= { "Forward", "Reverse", (char *) NULL }, *const HelpMenu[]= { "Overview", "Browse Documentation", "About Animate", (char *) NULL }; const char *const *Menus[MagickMenus]= { AnimateMenu, SpeedMenu, DirectionMenu, HelpMenu }; static const CommandType CommandMenus[]= { NullCommand, NullCommand, NullCommand, NullCommand, InfoCommand, QuitCommand }, CommandTypes[]= { OpenCommand, PlayCommand, StepCommand, RepeatCommand, AutoReverseCommand, SaveCommand }, SpeedCommands[]= { FasterCommand, SlowerCommand }, DirectionCommands[]= { ForwardCommand, ReverseCommand }, HelpCommands[]= { HelpCommand, BrowseDocumentationCommand, VersionCommand }; static const CommandType *Commands[MagickMenus]= { CommandTypes, SpeedCommands, DirectionCommands, HelpCommands }; char command[MagickPathExtent], *directory, geometry[MagickPathExtent], resource_name[MagickPathExtent]; CommandType command_type; Image *coalesce_image, *display_image, *image, **image_list, *nexus; int status; KeySym key_symbol; MagickStatusType context_mask, state; RectangleInfo geometry_info; char *p; ssize_t i; ssize_t first_scene, iterations, scene; static char working_directory[MagickPathExtent]; static size_t number_windows; static XWindowInfo *magick_windows[MaXWindows]; time_t timestamp; size_t delay, number_scenes; WarningHandler warning_handler; Window root_window; XClassHint *class_hints; XEvent event; XFontStruct *font_info; XGCValues context_values; XPixelInfo *icon_pixel, *pixel; XResourceInfo *icon_resources; XStandardColormap *icon_map, *map_info; XTextProperty window_name; XVisualInfo *icon_visual, *visual_info; XWindowChanges window_changes; XWindows *windows; XWMHints *manager_hints; assert(images != (Image *) NULL); assert(images->signature == MagickCoreSignature); if (images->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); warning_handler=(WarningHandler) NULL; windows=XSetWindows((XWindows *) ~0); if (windows != (XWindows *) NULL) { int status; if (*working_directory == '\0') (void) CopyMagickString(working_directory,".",MagickPathExtent); status=chdir(working_directory); if (status == -1) (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, "UnableToOpenFile","%s",working_directory); warning_handler=resource_info->display_warnings ? SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); warning_handler=resource_info->display_warnings ? SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); } else { Image *p; /* Initialize window structure. */ for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) { if (p->storage_class == DirectClass) { resource_info->colors=0; break; } if (p->colors > resource_info->colors) resource_info->colors=p->colors; } windows=XSetWindows(XInitializeWindows(display,resource_info)); if (windows == (XWindows *) NULL) ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", images->filename); /* Initialize window id's. */ number_windows=0; magick_windows[number_windows++]=(&windows->icon); magick_windows[number_windows++]=(&windows->backdrop); magick_windows[number_windows++]=(&windows->image); magick_windows[number_windows++]=(&windows->info); magick_windows[number_windows++]=(&windows->command); magick_windows[number_windows++]=(&windows->widget); magick_windows[number_windows++]=(&windows->popup); for (i=0; i < (ssize_t) number_windows; i++) magick_windows[i]->id=(Window) NULL; } /* Initialize font info. */ if (windows->font_info != (XFontStruct *) NULL) (void) XFreeFont(display,windows->font_info); windows->font_info=XBestFont(display,resource_info,MagickFalse); if (windows->font_info == (XFontStruct *) NULL) ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", resource_info->font); /* Initialize Standard Colormap. */ map_info=windows->map_info; icon_map=windows->icon_map; visual_info=windows->visual_info; icon_visual=windows->icon_visual; pixel=windows->pixel_info; icon_pixel=windows->icon_pixel; font_info=windows->font_info; icon_resources=windows->icon_resources; class_hints=windows->class_hints; manager_hints=windows->manager_hints; root_window=XRootWindow(display,visual_info->screen); coalesce_image=CoalesceImages(images,exception); if (coalesce_image == (Image *) NULL) ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", images->filename); images=coalesce_image; if (resource_info->map_type == (char *) NULL) if ((visual_info->klass != TrueColor) && (visual_info->klass != DirectColor)) { Image *next; /* Determine if the sequence of images has the identical colormap. */ for (next=images; next != (Image *) NULL; ) { next->alpha_trait=UndefinedPixelTrait; if ((next->storage_class == DirectClass) || (next->colors != images->colors) || (next->colors > (size_t) visual_info->colormap_size)) break; for (i=0; i < (ssize_t) images->colors; i++) if (IsPixelInfoEquivalent(next->colormap+i,images->colormap+i) == MagickFalse) break; if (i < (ssize_t) images->colors) break; next=GetNextImageInList(next); } if (next != (Image *) NULL) (void) RemapImages(resource_info->quantize_info,images, (Image *) NULL,exception); } /* Sort images by increasing scene number. */ number_scenes=GetImageListLength(images); image_list=ImageListToArray(images,exception); if (image_list == (Image **) NULL) ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed", images->filename); for (scene=0; scene < (ssize_t) number_scenes; scene++) if (image_list[scene]->scene == 0) break; if (scene == (ssize_t) number_scenes) qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare); /* Initialize Standard Colormap. */ nexus=NewImageList(); display_image=image_list[0]; for (scene=0; scene < (ssize_t) number_scenes; scene++) { if ((resource_info->map_type != (char *) NULL) || (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor)) (void) SetImageType(image_list[scene],image_list[scene]->alpha_trait == BlendPixelTrait ? TrueColorType : TrueColorAlphaType,exception); if ((display_image->columns < image_list[scene]->columns) && (display_image->rows < image_list[scene]->rows)) display_image=image_list[scene]; } if (display_image->debug != MagickFalse) { (void) LogMagickEvent(X11Event,GetMagickModule(), "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,(double) display_image->scene,(double) display_image->columns,(double) display_image->rows); if (display_image->colors != 0) (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) display_image->colors); (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", display_image->magick); } XMakeStandardColormap(display,visual_info,resource_info,display_image, map_info,pixel,exception); /* Initialize graphic context. */ windows->context.id=(Window) NULL; XGetWindowInfo(display,visual_info,map_info,pixel,font_info, resource_info,&windows->context); (void) CloneString(&class_hints->res_name,resource_info->client_name); (void) CloneString(&class_hints->res_class,resource_info->client_name); class_hints->res_class[0]=(char) LocaleUppercase((int) class_hints->res_class[0]); manager_hints->flags=InputHint | StateHint; manager_hints->input=MagickFalse; manager_hints->initial_state=WithdrawnState; XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, &windows->context); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Window id: 0x%lx (context)",windows->context.id); context_values.background=pixel->background_color.pixel; context_values.font=font_info->fid; context_values.foreground=pixel->foreground_color.pixel; context_values.graphics_exposures=MagickFalse; context_mask=(MagickStatusType) (GCBackground | GCFont | GCForeground | GCGraphicsExposures); if (pixel->annotate_context != (GC) NULL) (void) XFreeGC(display,pixel->annotate_context); pixel->annotate_context= XCreateGC(display,windows->context.id,context_mask,&context_values); if (pixel->annotate_context == (GC) NULL) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", images->filename); context_values.background=pixel->depth_color.pixel; if (pixel->widget_context != (GC) NULL) (void) XFreeGC(display,pixel->widget_context); pixel->widget_context= XCreateGC(display,windows->context.id,context_mask,&context_values); if (pixel->widget_context == (GC) NULL) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", images->filename); context_values.background=pixel->foreground_color.pixel; context_values.foreground=pixel->background_color.pixel; context_values.plane_mask= context_values.background ^ context_values.foreground; if (pixel->highlight_context != (GC) NULL) (void) XFreeGC(display,pixel->highlight_context); pixel->highlight_context=XCreateGC(display,windows->context.id, (size_t) (context_mask | GCPlaneMask),&context_values); if (pixel->highlight_context == (GC) NULL) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", images->filename); (void) XDestroyWindow(display,windows->context.id); /* Initialize icon window. */ XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, icon_resources,&windows->icon); windows->icon.geometry=resource_info->icon_geometry; XBestIconSize(display,&windows->icon,display_image); windows->icon.attributes.colormap= XDefaultColormap(display,icon_visual->screen); windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; manager_hints->flags=InputHint | StateHint; manager_hints->input=MagickFalse; manager_hints->initial_state=IconicState; XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, &windows->icon); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", windows->icon.id); /* Initialize graphic context for icon window. */ if (icon_pixel->annotate_context != (GC) NULL) (void) XFreeGC(display,icon_pixel->annotate_context); context_values.background=icon_pixel->background_color.pixel; context_values.foreground=icon_pixel->foreground_color.pixel; icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, (size_t) (GCBackground | GCForeground),&context_values); if (icon_pixel->annotate_context == (GC) NULL) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", images->filename); windows->icon.annotate_context=icon_pixel->annotate_context; /* Initialize Image window. */ XGetWindowInfo(display,visual_info,map_info,pixel,font_info, resource_info,&windows->image); windows->image.shape=MagickTrue; /* non-rectangular shape hint */ if (resource_info->use_shared_memory == MagickFalse) windows->image.shared_memory=MagickFalse; if (resource_info->title != (char *) NULL) { char *title; title=InterpretImageProperties(resource_info->image_info,display_image, resource_info->title,exception); (void) CloneString(&windows->image.name,title); (void) CloneString(&windows->image.icon_name,title); title=DestroyString(title); } else { char filename[MagickPathExtent], window_name[MagickPathExtent]; /* Window name is the base of the filename. */ GetPathComponent(display_image->magick_filename,TailPath,filename); (void) FormatLocaleString(window_name,MagickPathExtent, "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,(double) display_image->scene,(double) number_scenes); (void) CloneString(&windows->image.name,window_name); (void) CloneString(&windows->image.icon_name,filename); } if (resource_info->immutable != MagickFalse) windows->image.immutable=MagickTrue; windows->image.shape=MagickTrue; windows->image.geometry=resource_info->image_geometry; (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!", XDisplayWidth(display,visual_info->screen), XDisplayHeight(display,visual_info->screen)); geometry_info.width=display_image->columns; geometry_info.height=display_image->rows; geometry_info.x=0; geometry_info.y=0; (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, &geometry_info.width,&geometry_info.height); windows->image.width=(unsigned int) geometry_info.width; windows->image.height=(unsigned int) geometry_info.height; windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; XGetWindowInfo(display,visual_info,map_info,pixel,font_info, resource_info,&windows->backdrop); if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) { /* Initialize backdrop window. */ windows->backdrop.x=0; windows->backdrop.y=0; (void) CloneString(&windows->backdrop.name,"ImageMagick Backdrop"); windows->backdrop.flags=(size_t) (USSize | USPosition); windows->backdrop.width=(unsigned int) XDisplayWidth(display,visual_info->screen); windows->backdrop.height=(unsigned int) XDisplayHeight(display,visual_info->screen); windows->backdrop.border_width=0; windows->backdrop.immutable=MagickTrue; windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | ButtonReleaseMask; windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | StructureNotifyMask; manager_hints->flags=IconWindowHint | InputHint | StateHint; manager_hints->icon_window=windows->icon.id; manager_hints->input=MagickTrue; manager_hints->initial_state= resource_info->iconic ? IconicState : NormalState; XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, &windows->backdrop); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Window id: 0x%lx (backdrop)",windows->backdrop.id); (void) XMapWindow(display,windows->backdrop.id); (void) XClearWindow(display,windows->backdrop.id); if (windows->image.id != (Window) NULL) { (void) XDestroyWindow(display,windows->image.id); windows->image.id=(Window) NULL; } /* Position image in the center the backdrop. */ windows->image.flags|=USPosition; windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- (windows->image.width/2); windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- (windows->image.height/2); } manager_hints->flags=IconWindowHint | InputHint | StateHint; manager_hints->icon_window=windows->icon.id; manager_hints->input=MagickTrue; manager_hints->initial_state= resource_info->iconic ? IconicState : NormalState; if (windows->group_leader.id != (Window) NULL) { /* Follow the leader. */ manager_hints->flags|=(MagickStatusType) WindowGroupHint; manager_hints->window_group=windows->group_leader.id; (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Window id: 0x%lx (group leader)",windows->group_leader.id); } XMakeWindow(display, (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), argv,argc,class_hints,manager_hints,&windows->image); (void) XChangeProperty(display,windows->image.id,windows->im_protocols, XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); if (windows->group_leader.id != (Window) NULL) (void) XSetTransientForHint(display,windows->image.id, windows->group_leader.id); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", windows->image.id); /* Initialize Info widget. */ XGetWindowInfo(display,visual_info,map_info,pixel,font_info, resource_info,&windows->info); (void) CloneString(&windows->info.name,"Info"); (void) CloneString(&windows->info.icon_name,"Info"); windows->info.border_width=1; windows->info.x=2; windows->info.y=2; windows->info.flags|=PPosition; windows->info.attributes.win_gravity=UnmapGravity; windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | StructureNotifyMask; manager_hints->flags=InputHint | StateHint | WindowGroupHint; manager_hints->input=MagickFalse; manager_hints->initial_state=NormalState; manager_hints->window_group=windows->image.id; XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, &windows->info); windows->info.highlight_stipple=XCreateBitmapFromData(display, windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); windows->info.shadow_stipple=XCreateBitmapFromData(display, windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); (void) XSetTransientForHint(display,windows->info.id,windows->image.id); if (windows->image.mapped) (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", windows->info.id); /* Initialize Command widget. */ XGetWindowInfo(display,visual_info,map_info,pixel,font_info, resource_info,&windows->command); windows->command.data=MagickMenus; (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command", resource_info->client_name); windows->command.geometry=XGetResourceClass(resource_info->resource_database, resource_name,"geometry",(char *) NULL); (void) CloneString(&windows->command.name,MagickTitle); windows->command.border_width=0; windows->command.flags|=PPosition; windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | OwnerGrabButtonMask | StructureNotifyMask; manager_hints->flags=InputHint | StateHint | WindowGroupHint; manager_hints->input=MagickTrue; manager_hints->initial_state=NormalState; manager_hints->window_group=windows->image.id; XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, &windows->command); windows->command.highlight_stipple=XCreateBitmapFromData(display, windows->command.id,(char *) HighlightBitmap,HighlightWidth, HighlightHeight); windows->command.shadow_stipple=XCreateBitmapFromData(display, windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); (void) XSetTransientForHint(display,windows->command.id,windows->image.id); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Window id: 0x%lx (command)",windows->command.id); /* Initialize Widget window. */ XGetWindowInfo(display,visual_info,map_info,pixel,font_info, resource_info,&windows->widget); (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget", resource_info->client_name); windows->widget.geometry=XGetResourceClass(resource_info->resource_database, resource_name,"geometry",(char *) NULL); windows->widget.border_width=0; windows->widget.flags|=PPosition; windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | StructureNotifyMask; manager_hints->flags=InputHint | StateHint | WindowGroupHint; manager_hints->input=MagickTrue; manager_hints->initial_state=NormalState; manager_hints->window_group=windows->image.id; XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, &windows->widget); windows->widget.highlight_stipple=XCreateBitmapFromData(display, windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); windows->widget.shadow_stipple=XCreateBitmapFromData(display, windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Window id: 0x%lx (widget)",windows->widget.id); /* Initialize popup window. */ XGetWindowInfo(display,visual_info,map_info,pixel,font_info, resource_info,&windows->popup); windows->popup.border_width=0; windows->popup.flags|=PPosition; windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; manager_hints->flags=InputHint | StateHint | WindowGroupHint; manager_hints->input=MagickTrue; manager_hints->initial_state=NormalState; manager_hints->window_group=windows->image.id; XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, &windows->popup); windows->popup.highlight_stipple=XCreateBitmapFromData(display, windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); windows->popup.shadow_stipple=XCreateBitmapFromData(display, windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Window id: 0x%lx (pop up)",windows->popup.id); /* Set out progress and warning handlers. */ if (warning_handler == (WarningHandler) NULL) { warning_handler=resource_info->display_warnings ? SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); warning_handler=resource_info->display_warnings ? SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); } /* Initialize X image structure. */ windows->image.x=0; windows->image.y=0; /* Initialize image pixmaps structure. */ window_changes.width=(int) windows->image.width; window_changes.height=(int) windows->image.height; (void) XReconfigureWMWindow(display,windows->image.id,windows->command.screen, (unsigned int) (CWWidth | CWHeight),&window_changes); windows->image.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes, sizeof(*windows->image.pixmaps)); windows->image.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes, sizeof(*windows->image.pixmaps)); if ((windows->image.pixmaps == (Pixmap *) NULL) || (windows->image.matte_pixmaps == (Pixmap *) NULL)) ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed", images->filename); if ((windows->image.mapped == MagickFalse) || (windows->backdrop.id != (Window) NULL)) (void) XMapWindow(display,windows->image.id); XSetCursorState(display,windows,MagickTrue); for (scene=0; scene < (ssize_t) number_scenes; scene++) { unsigned int columns, rows; /* Create X image. */ windows->image.pixmap=(Pixmap) NULL; windows->image.matte_pixmap=(Pixmap) NULL; if ((resource_info->map_type != (char *) NULL) || (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor)) if (image_list[scene]->storage_class == PseudoClass) XGetPixelInfo(display,visual_info,map_info,resource_info, image_list[scene],windows->image.pixel_info); columns=(unsigned int) image_list[scene]->columns; rows=(unsigned int) image_list[scene]->rows; if ((image_list[scene]->columns != columns) || (image_list[scene]->rows != rows)) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", image_list[scene]->filename); status=XMakeImage(display,resource_info,&windows->image,image_list[scene], columns,rows,exception); if (status == MagickFalse) ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", images->filename); if (image_list[scene]->debug != MagickFalse) { (void) LogMagickEvent(X11Event,GetMagickModule(), "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene, image_list[scene]->filename,(double) columns,(double) rows); if (image_list[scene]->colors != 0) (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) image_list[scene]->colors); (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", image_list[scene]->magick); } /* Window name is the base of the filename. */ if (resource_info->title != (char *) NULL) { char *title; title=InterpretImageProperties(resource_info->image_info, image_list[scene],resource_info->title,exception); (void) CloneString(&windows->image.name,title); title=DestroyString(title); } else { char window_name[MagickPathExtent]; p=image_list[scene]->magick_filename+ strlen(image_list[scene]->magick_filename)-1; while ((p > image_list[scene]->magick_filename) && (*(p-1) != '/')) p--; (void) FormatLocaleString(window_name,MagickPathExtent, "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double) scene+1, (double) number_scenes); (void) CloneString(&windows->image.name,window_name); } status=XStringListToTextProperty(&windows->image.name,1,&window_name); if (status != Success) { XSetWMName(display,windows->image.id,&window_name); (void) XFree((void *) window_name.value); } windows->image.pixmaps[scene]=windows->image.pixmap; windows->image.matte_pixmaps[scene]=windows->image.matte_pixmap; if (scene == 0) { event.xexpose.x=0; event.xexpose.y=0; event.xexpose.width=(int) image_list[scene]->columns; event.xexpose.height=(int) image_list[scene]->rows; XRefreshWindow(display,&windows->image,&event); (void) XSync(display,MagickFalse); } } XSetCursorState(display,windows,MagickFalse); if (windows->command.mapped) (void) XMapRaised(display,windows->command.id); /* Respond to events. */ nexus=NewImageList(); scene=0; first_scene=0; iterations=0; image=image_list[0]; state=(MagickStatusType) (ForwardAnimationState | RepeatAnimationState); (void) XMagickCommand(display,resource_info,windows,PlayCommand,&images, &state,exception); do { if (XEventsQueued(display,QueuedAfterFlush) == 0) if ((state & PlayAnimationState) || (state & StepAnimationState)) { MagickBooleanType pause; pause=MagickFalse; delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); XDelay(display,resource_info->delay*(delay == 0 ? 10 : delay)); if (state & ForwardAnimationState) { /* Forward animation: increment scene number. */ if (scene < ((ssize_t) number_scenes-1)) scene++; else { iterations++; if (iterations == (ssize_t) image_list[0]->iterations) { iterations=0; state|=ExitState; } if ((state & AutoReverseAnimationState) != 0) { state&=(~ForwardAnimationState); scene--; } else { if ((state & RepeatAnimationState) == 0) state&=(~PlayAnimationState); scene=first_scene; pause=MagickTrue; } } } else { /* Reverse animation: decrement scene number. */ if (scene > first_scene) scene--; else { iterations++; if (iterations == (ssize_t) image_list[0]->iterations) { iterations=0; state&=(~RepeatAnimationState); } if (state & AutoReverseAnimationState) { state|=ForwardAnimationState; scene=first_scene; pause=MagickTrue; } else { if ((state & RepeatAnimationState) == MagickFalse) state&=(~PlayAnimationState); scene=(ssize_t) number_scenes-1; } } } scene=MagickMax(scene,0); image=image_list[scene]; if ((image != (Image *) NULL) && (image->start_loop != 0)) first_scene=scene; if ((state & StepAnimationState) || (resource_info->title != (char *) NULL)) { char name[MagickPathExtent]; /* Update window title. */ p=image_list[scene]->filename+ strlen(image_list[scene]->filename)-1; while ((p > image_list[scene]->filename) && (*(p-1) != '/')) p--; (void) FormatLocaleString(name,MagickPathExtent, "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double) scene+1,(double) number_scenes); (void) CloneString(&windows->image.name,name); if (resource_info->title != (char *) NULL) { char *title; title=InterpretImageProperties(resource_info->image_info, image,resource_info->title,exception); (void) CloneString(&windows->image.name,title); title=DestroyString(title); } status=XStringListToTextProperty(&windows->image.name,1, &window_name); if (status != Success) { XSetWMName(display,windows->image.id,&window_name); (void) XFree((void *) window_name.value); } } /* Copy X pixmap to Image window. */ XGetPixelInfo(display,visual_info,map_info,resource_info, image_list[scene],windows->image.pixel_info); windows->image.ximage->width=(int) image->columns; windows->image.ximage->height=(int) image->rows; windows->image.pixmap=windows->image.pixmaps[scene]; windows->image.matte_pixmap=windows->image.matte_pixmaps[scene]; event.xexpose.x=0; event.xexpose.y=0; event.xexpose.width=(int) image->columns; event.xexpose.height=(int) image->rows; if ((state & ExitState) == 0) { XRefreshWindow(display,&windows->image,&event); (void) XSync(display,MagickFalse); } state&=(~StepAnimationState); if (pause != MagickFalse) for (i=0; i < (ssize_t) resource_info->pause; i++) { int status; status=XCheckTypedWindowEvent(display,windows->image.id,KeyPress, &event); if (status != 0) { int length; length=XLookupString((XKeyEvent *) &event.xkey,command,(int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); *(command+length)='\0'; if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) { XClientMessage(display,windows->image.id, windows->im_protocols,windows->im_exit,CurrentTime); break; } } MagickDelay(1000); } continue; } /* Handle a window event. */ timestamp=GetMagickTime(); (void) XNextEvent(display,&event); if (windows->image.stasis == MagickFalse) windows->image.stasis=(GetMagickTime()-timestamp) > 0 ? MagickTrue : MagickFalse; if (event.xany.window == windows->command.id) { int id; /* Select a command from the Command widget. */ id=XCommandWidget(display,windows,CommandMenu,&event); if (id < 0) continue; (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent); command_type=CommandMenus[id]; if (id < MagickMenus) { int entry; /* Select a command from a pop-up menu. */ entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], command); if (entry < 0) continue; (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent); command_type=Commands[id][entry]; } if (command_type != NullCommand) nexus=XMagickCommand(display,resource_info,windows, command_type,&image,&state,exception); continue; } switch (event.type) { case ButtonPress: { if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, event.xbutton.button,event.xbutton.x,event.xbutton.y); if ((event.xbutton.button == Button3) && (event.xbutton.state & Mod1Mask)) { /* Convert Alt-Button3 to Button2. */ event.xbutton.button=Button2; event.xbutton.state&=(~Mod1Mask); } if (event.xbutton.window == windows->backdrop.id) { (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, event.xbutton.time); break; } if (event.xbutton.window == windows->image.id) { if (resource_info->immutable != MagickFalse) { state|=ExitState; break; } /* Map/unmap Command widget. */ if (windows->command.mapped) (void) XWithdrawWindow(display,windows->command.id, windows->command.screen); else { (void) XCommandWidget(display,windows,CommandMenu, (XEvent *) NULL); (void) XMapRaised(display,windows->command.id); } } break; } case ButtonRelease: { if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, event.xbutton.button,event.xbutton.x,event.xbutton.y); break; } case ClientMessage: { if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Client Message: 0x%lx 0x%lx %d 0x%lx",(unsigned long) event.xclient.window,(unsigned long) event.xclient.message_type, event.xclient.format,(unsigned long) event.xclient.data.l[0]); if (event.xclient.message_type == windows->im_protocols) { if (*event.xclient.data.l == (long) windows->im_update_colormap) { /* Update graphic context and window colormap. */ for (i=0; i < (ssize_t) number_windows; i++) { if (magick_windows[i]->id == windows->icon.id) continue; context_values.background=pixel->background_color.pixel; context_values.foreground=pixel->foreground_color.pixel; (void) XChangeGC(display,magick_windows[i]->annotate_context, context_mask,&context_values); (void) XChangeGC(display,magick_windows[i]->widget_context, context_mask,&context_values); context_values.background=pixel->foreground_color.pixel; context_values.foreground=pixel->background_color.pixel; context_values.plane_mask= context_values.background ^ context_values.foreground; (void) XChangeGC(display,magick_windows[i]->highlight_context, (size_t) (context_mask | GCPlaneMask), &context_values); magick_windows[i]->attributes.background_pixel= pixel->background_color.pixel; magick_windows[i]->attributes.border_pixel= pixel->border_color.pixel; magick_windows[i]->attributes.colormap=map_info->colormap; (void) XChangeWindowAttributes(display,magick_windows[i]->id, (unsigned long) magick_windows[i]->mask, &magick_windows[i]->attributes); } if (windows->backdrop.id != (Window) NULL) (void) XInstallColormap(display,map_info->colormap); break; } if (*event.xclient.data.l == (long) windows->im_exit) { state|=ExitState; break; } break; } if (event.xclient.message_type == windows->dnd_protocols) { Atom selection, type; int format, status; unsigned char *data; unsigned long after, length; /* Display image named by the Drag-and-Drop selection. */ if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) break; selection=XInternAtom(display,"DndSelection",MagickFalse); status=XGetWindowProperty(display,root_window,selection,0L,2047L, MagickFalse,(Atom) AnyPropertyType,&type,&format,&length,&after, &data); if ((status != Success) || (length == 0)) break; if (*event.xclient.data.l == 2) { /* Offix DND. */ (void) CopyMagickString(resource_info->image_info->filename, (char *) data,MagickPathExtent); } else { /* XDND. */ if (LocaleNCompare((char *) data,"file:",5) != 0) { (void) XFree((void *) data); break; } (void) CopyMagickString(resource_info->image_info->filename, ((char *) data)+5,MagickPathExtent); } nexus=ReadImage(resource_info->image_info,exception); CatchException(exception); if (nexus != (Image *) NULL) state|=ExitState; (void) XFree((void *) data); break; } /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (long) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (long) windows->wm_delete_window) break; (void) XWithdrawWindow(display,event.xclient.window, visual_info->screen); if (event.xclient.window == windows->image.id) { state|=ExitState; break; } break; } case ConfigureNotify: { if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, event.xconfigure.y,event.xconfigure.send_event); if (event.xconfigure.window == windows->image.id) { if (event.xconfigure.send_event != 0) { XWindowChanges window_changes; /* Position the transient windows relative of the Image window. */ if (windows->command.geometry == (char *) NULL) if (windows->command.mapped == MagickFalse) { windows->command.x= event.xconfigure.x-windows->command.width-25; windows->command.y=event.xconfigure.y; XConstrainWindowPosition(display,&windows->command); window_changes.x=windows->command.x; window_changes.y=windows->command.y; (void) XReconfigureWMWindow(display,windows->command.id, windows->command.screen,(unsigned int) (CWX | CWY), &window_changes); } if (windows->widget.geometry == (char *) NULL) if (windows->widget.mapped == MagickFalse) { windows->widget.x= event.xconfigure.x+event.xconfigure.width/10; windows->widget.y= event.xconfigure.y+event.xconfigure.height/10; XConstrainWindowPosition(display,&windows->widget); window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id, windows->widget.screen,(unsigned int) (CWX | CWY), &window_changes); } } /* Image window has a new configuration. */ windows->image.width=(unsigned int) event.xconfigure.width; windows->image.height=(unsigned int) event.xconfigure.height; break; } if (event.xconfigure.window == windows->icon.id) { /* Icon window has a new configuration. */ windows->icon.width=(unsigned int) event.xconfigure.width; windows->icon.height=(unsigned int) event.xconfigure.height; break; } break; } case DestroyNotify: { /* Group leader has exited. */ if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Destroy Notify: 0x%lx",event.xdestroywindow.window); if (event.xdestroywindow.window == windows->group_leader.id) { state|=ExitState; break; } break; } case EnterNotify: { /* Selectively install colormap. */ if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) if (event.xcrossing.mode != NotifyUngrab) XInstallColormap(display,map_info->colormap); break; } case Expose: { if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, event.xexpose.width,event.xexpose.height,event.xexpose.x, event.xexpose.y); /* Repaint windows that are now exposed. */ if (event.xexpose.window == windows->image.id) { windows->image.pixmap=windows->image.pixmaps[scene]; windows->image.matte_pixmap=windows->image.matte_pixmaps[scene]; XRefreshWindow(display,&windows->image,&event); break; } if (event.xexpose.window == windows->icon.id) if (event.xexpose.count == 0) { XRefreshWindow(display,&windows->icon,&event); break; } break; } case KeyPress: { static int length; /* Respond to a user key press. */ length=XLookupString((XKeyEvent *) &event.xkey,command,(int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); *(command+length)='\0'; if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Key press: 0x%lx (%c)",(unsigned long) key_symbol,*command); command_type=NullCommand; switch (key_symbol) { case XK_o: { if ((event.xkey.state & ControlMask) == MagickFalse) break; command_type=OpenCommand; break; } case XK_BackSpace: { command_type=StepBackwardCommand; break; } case XK_space: { command_type=StepForwardCommand; break; } case XK_less: { command_type=FasterCommand; break; } case XK_greater: { command_type=SlowerCommand; break; } case XK_F1: { command_type=HelpCommand; break; } case XK_Find: { command_type=BrowseDocumentationCommand; break; } case XK_question: { command_type=InfoCommand; break; } case XK_q: case XK_Escape: { command_type=QuitCommand; break; } default: break; } if (command_type != NullCommand) nexus=XMagickCommand(display,resource_info,windows, command_type,&image,&state,exception); break; } case KeyRelease: { /* Respond to a user key release. */ (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); break; } case LeaveNotify: { /* Selectively uninstall colormap. */ if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) if (event.xcrossing.mode != NotifyUngrab) XUninstallColormap(display,map_info->colormap); break; } case MapNotify: { if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", event.xmap.window); if (event.xmap.window == windows->backdrop.id) { (void) XSetInputFocus(display,event.xmap.window,RevertToParent, CurrentTime); windows->backdrop.mapped=MagickTrue; break; } if (event.xmap.window == windows->image.id) { if (windows->backdrop.id != (Window) NULL) (void) XInstallColormap(display,map_info->colormap); if (LocaleCompare(image_list[0]->magick,"LOGO") == 0) { if (LocaleCompare(display_image->filename,"LOGO") == 0) nexus=XMagickCommand(display,resource_info,windows, OpenCommand,&image,&state,exception); else state|=ExitState; } windows->image.mapped=MagickTrue; break; } if (event.xmap.window == windows->info.id) { windows->info.mapped=MagickTrue; break; } if (event.xmap.window == windows->icon.id) { /* Create an icon image. */ XMakeStandardColormap(display,icon_visual,icon_resources, display_image,icon_map,icon_pixel,exception); (void) XMakeImage(display,icon_resources,&windows->icon, display_image,windows->icon.width,windows->icon.height, exception); (void) XSetWindowBackgroundPixmap(display,windows->icon.id, windows->icon.pixmap); (void) XClearWindow(display,windows->icon.id); (void) XWithdrawWindow(display,windows->info.id, windows->info.screen); windows->icon.mapped=MagickTrue; break; } if (event.xmap.window == windows->command.id) { windows->command.mapped=MagickTrue; break; } if (event.xmap.window == windows->popup.id) { windows->popup.mapped=MagickTrue; break; } if (event.xmap.window == windows->widget.id) { windows->widget.mapped=MagickTrue; break; } break; } case MappingNotify: { (void) XRefreshKeyboardMapping(&event.xmapping); break; } case NoExpose: break; case PropertyNotify: { Atom type; int format, status; unsigned char *data; unsigned long after, length; if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Property Notify: 0x%lx 0x%lx %d",(unsigned long) event.xproperty.window,(unsigned long) event.xproperty.atom, event.xproperty.state); if (event.xproperty.atom != windows->im_remote_command) break; /* Display image named by the remote command protocol. */ status=XGetWindowProperty(display,event.xproperty.window, event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,&length,&after,&data); if ((status != Success) || (length == 0)) break; (void) CopyMagickString(resource_info->image_info->filename, (char *) data,MagickPathExtent); nexus=ReadImage(resource_info->image_info,exception); CatchException(exception); if (nexus != (Image *) NULL) state|=ExitState; (void) XFree((void *) data); break; } case ReparentNotify: { if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, event.xreparent.window); break; } case UnmapNotify: { if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(), "Unmap Notify: 0x%lx",event.xunmap.window); if (event.xunmap.window == windows->backdrop.id) { windows->backdrop.mapped=MagickFalse; break; } if (event.xunmap.window == windows->image.id) { windows->image.mapped=MagickFalse; break; } if (event.xunmap.window == windows->info.id) { windows->info.mapped=MagickFalse; break; } if (event.xunmap.window == windows->icon.id) { if (map_info->colormap == icon_map->colormap) XConfigureImageColormap(display,resource_info,windows, display_image,exception); (void) XFreeStandardColormap(display,icon_visual,icon_map, icon_pixel); windows->icon.mapped=MagickFalse; break; } if (event.xunmap.window == windows->command.id) { windows->command.mapped=MagickFalse; break; } if (event.xunmap.window == windows->popup.id) { if (windows->backdrop.id != (Window) NULL) (void) XSetInputFocus(display,windows->image.id,RevertToParent, CurrentTime); windows->popup.mapped=MagickFalse; break; } if (event.xunmap.window == windows->widget.id) { if (windows->backdrop.id != (Window) NULL) (void) XSetInputFocus(display,windows->image.id,RevertToParent, CurrentTime); windows->widget.mapped=MagickFalse; break; } break; } default: { if (display_image->debug != MagickFalse) (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", event.type); break; } } } while (!(state & ExitState)); image_list=(Image **) RelinquishMagickMemory(image_list); images=DestroyImageList(images); if ((windows->visual_info->klass == GrayScale) || (windows->visual_info->klass == PseudoColor) || (windows->visual_info->klass == DirectColor)) { /* Withdraw windows. */ if (windows->info.mapped) (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); if (windows->command.mapped) (void) XWithdrawWindow(display,windows->command.id, windows->command.screen); } if (resource_info->backdrop == MagickFalse) if (windows->backdrop.mapped) { (void) XWithdrawWindow(display,windows->backdrop.id,\ windows->backdrop.screen); (void) XDestroyWindow(display,windows->backdrop.id); windows->backdrop.id=(Window) NULL; (void) XWithdrawWindow(display,windows->image.id,windows->image.screen); (void) XDestroyWindow(display,windows->image.id); windows->image.id=(Window) NULL; } XSetCursorState(display,windows,MagickTrue); XCheckRefreshWindows(display,windows); for (scene=1; scene < (ssize_t) number_scenes; scene++) { if (windows->image.pixmaps[scene] != (Pixmap) NULL) (void) XFreePixmap(display,windows->image.pixmaps[scene]); windows->image.pixmaps[scene]=(Pixmap) NULL; if (windows->image.matte_pixmaps[scene] != (Pixmap) NULL) (void) XFreePixmap(display,windows->image.matte_pixmaps[scene]); windows->image.matte_pixmaps[scene]=(Pixmap) NULL; } XSetCursorState(display,windows,MagickFalse); windows->image.pixmaps=(Pixmap *) RelinquishMagickMemory(windows->image.pixmaps); windows->image.matte_pixmaps=(Pixmap *) RelinquishMagickMemory(windows->image.matte_pixmaps); if (nexus == (Image *) NULL) { /* Free X resources. */ if (windows->image.mapped != MagickFalse) (void) XWithdrawWindow(display,windows->image.id,windows->image.screen); XDelay(display,SuspendTime); (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); if (resource_info->map_type == (char *) NULL) (void) XFreeStandardColormap(display,visual_info,map_info,pixel); DestroyXResources(); } (void) XSync(display,MagickFalse); /* Restore our progress monitor and warning handlers. */ (void) SetErrorHandler(warning_handler); (void) SetWarningHandler(warning_handler); /* Change to home directory. */ directory=getcwd(working_directory,MagickPathExtent); (void) directory; if (*resource_info->home_directory == '\0') (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent); status=chdir(resource_info->home_directory); if (status == -1) (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, "UnableToOpenFile","%s",resource_info->home_directory); return(nexus); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X S a v e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XSaveImage() saves an image to a file. % % The format of the XSaveImage method is: % % MagickBooleanType XSaveImage(Display *display, % XResourceInfo *resource_info,XWindows *windows,Image *image, % ExceptionInfo *exception) % % A description of each parameter follows: % % o status: Method XSaveImage return True if the image is % written. False is returned is there is a memory shortage or if the % image fails to write. % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. % % o windows: Specifies a pointer to a XWindows structure. % % o image: the image. % */ static MagickBooleanType XSaveImage(Display *display, XResourceInfo *resource_info,XWindows *windows,Image *image, ExceptionInfo *exception) { char filename[MagickPathExtent]; ImageInfo *image_info; MagickStatusType status; /* Request file name from user. */ if (resource_info->write_filename != (char *) NULL) (void) CopyMagickString(filename,resource_info->write_filename, MagickPathExtent); else { char path[MagickPathExtent]; int status; GetPathComponent(image->filename,HeadPath,path); GetPathComponent(image->filename,TailPath,filename); if (*path == '\0') (void) CopyMagickString(path,".",MagickPathExtent); status=chdir(path); if (status == -1) (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, "UnableToOpenFile","%s",path); } XFileBrowserWidget(display,windows,"Save",filename); if (*filename == '\0') return(MagickTrue); if (IsPathAccessible(filename) != MagickFalse) { int status; /* File exists-- seek user's permission before overwriting. */ status=XConfirmWidget(display,windows,"Overwrite",filename); if (status == 0) return(MagickTrue); } image_info=CloneImageInfo(resource_info->image_info); (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); (void) SetImageInfo(image_info,1,exception); if ((LocaleCompare(image_info->magick,"JPEG") == 0) || (LocaleCompare(image_info->magick,"JPG") == 0)) { char quality[MagickPathExtent]; int status; /* Request JPEG quality from user. */ (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double) image_info->quality); status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", quality); if (*quality == '\0') return(MagickTrue); image->quality=StringToUnsignedLong(quality); image_info->interlace=status != MagickFalse ? NoInterlace : PlaneInterlace; } if ((LocaleCompare(image_info->magick,"EPS") == 0) || (LocaleCompare(image_info->magick,"PDF") == 0) || (LocaleCompare(image_info->magick,"PS") == 0) || (LocaleCompare(image_info->magick,"PS2") == 0)) { char geometry[MagickPathExtent]; /* Request page geometry from user. */ (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent); if (LocaleCompare(image_info->magick,"PDF") == 0) (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent); if (image_info->page != (char *) NULL) (void) CopyMagickString(geometry,image_info->page,MagickPathExtent); XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", "Select page geometry:",geometry); if (*geometry != '\0') image_info->page=GetPageGeometry(geometry); } /* Write image. */ image=GetFirstImageInList(image); status=WriteImages(image_info,image,filename,exception); if (status != MagickFalse) image->taint=MagickFalse; image_info=DestroyImageInfo(image_info); XSetCursorState(display,windows,MagickFalse); return(status != 0 ? MagickTrue : MagickFalse); } #else /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + A n i m a t e I m a g e s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AnimateImages() repeatedly displays an image sequence to any X window % screen. It returns a value other than 0 if successful. Check the % exception member of image to determine the reason for any failure. % % The format of the AnimateImages method is: % % MagickBooleanType AnimateImages(const ImageInfo *image_info, % Image *images) % % A description of each parameter follows: % % o image_info: the image info. % % o image: the image. % % o exception: return any errors or warnings in this structure. % */ MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info, Image *image,ExceptionInfo *exception) { assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickCoreSignature); (void) image_info; assert(image != (Image *) NULL); assert(image->signature == MagickCoreSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename); return(MagickFalse); } #endif