blob: cf4788103b6a73546142bd1292058b73c426cef9 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% AAA N N IIIII M M AAA TTTTT EEEEE %
7% A A NN N I MM MM A A T E %
8% AAAAA N N N I M M M AAAAA T EEE %
9% A A N NN I M M A A T E %
10% A A N N IIIII M M A A T EEEEE %
11% %
12% %
13% Methods to Interactively Animate an Image Sequence %
14% %
15% Software Design %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
cristyb56bb242014-11-25 17:12:48 +000020% Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/animate.h"
44#include "MagickCore/animate-private.h"
cristy228095b2012-06-21 01:42:50 +000045#include "MagickCore/attribute.h"
cristy4c08aed2011-07-01 19:47:50 +000046#include "MagickCore/client.h"
47#include "MagickCore/color.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/colorspace.h"
cristy707f0632012-02-15 23:40:22 +000050#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000051#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"
cristyd1dd6e42011-09-04 01:46:08 +000072#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000073#include "MagickCore/version.h"
74#include "MagickCore/widget.h"
cristybcbda3f2011-09-03 13:01:22 +000075#include "MagickCore/widget-private.h"
76#include "MagickCore/xwindow.h"
cristy4c08aed2011-07-01 19:47:50 +000077#include "MagickCore/xwindow-private.h"
cristy3ed852e2009-09-05 21:47:34 +000078
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,
cristy051718b2011-08-28 22:49:25 +0000246 Image **,MagickStatusType *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000247
248static MagickBooleanType
cristy051718b2011-08-28 22:49:25 +0000249 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000250
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,
cristy051718b2011-08-28 22:49:25 +0000269% Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000270%
271% A description of each parameter follows:
272%
273% o image_info: the image info.
274%
275% o image: the image.
276%
cristy051718b2011-08-28 22:49:25 +0000277% o exception: return any errors or warnings in this structure.
278%
cristy3ed852e2009-09-05 21:47:34 +0000279*/
280MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +0000281 Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000282{
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);
cristye1c94d92015-06-28 12:16:33 +0000299 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000300 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000301 assert(images->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000302 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 {
cristy051718b2011-08-28 22:49:25 +0000307 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
cristyefe601c2013-01-05 17:51:12 +0000308 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
cristy3ed852e2009-09-05 21:47:34 +0000309 return(MagickFalse);
310 }
cristy051718b2011-08-28 22:49:25 +0000311 if (exception->severity != UndefinedException)
312 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +0000313 (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());
cristy051718b2011-08-28 22:49:25 +0000321 (void) XAnimateImages(display,&resource_info,argv,1,images,exception);
cristye42f6582012-02-11 17:59:50 +0000322 (void) SetErrorHandler((ErrorHandler) NULL);
323 (void) SetWarningHandler((WarningHandler) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000324 argv[0]=DestroyString(argv[0]);
325 (void) XCloseDisplay(display);
326 XDestroyResourceInfo(&resource_info);
cristy051718b2011-08-28 22:49:25 +0000327 status=exception->severity == UndefinedException ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000328 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,
cristy051718b2011-08-28 22:49:25 +0000349% MagickStatusType *state,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000350%
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%
cristy051718b2011-08-28 22:49:25 +0000366% o exception: return any errors or warnings in this structure.
367%
cristy3ed852e2009-09-05 21:47:34 +0000368%
369*/
370static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
371 XWindows *windows,const CommandType command_type,Image **image,
cristy051718b2011-08-28 22:49:25 +0000372 MagickStatusType *state,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000373{
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
cristy3ed852e2009-09-05 21:47:34 +0000397 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
cristy151b66d2015-04-15 10:50:31 +0000411 filenames[MagickPathExtent] = "*";
cristy3ed852e2009-09-05 21:47:34 +0000412
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 */
cristy73bd4a52010-10-05 11:24:23 +0000424 filelist=(char **) AcquireMagickMemory(sizeof(char *));
cristy3ed852e2009-09-05 21:47:34 +0000425 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);
cristy3ed852e2009-09-05 21:47:34 +0000446 images=NewImageList();
447 XSetCursorState(display,windows,MagickTrue);
448 XCheckRefreshWindows(display,windows);
449 for (i=0; i < number_files; i++)
450 {
cristy151b66d2015-04-15 10:50:31 +0000451 (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000452 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);
cristy3ed852e2009-09-05 21:47:34 +0000466 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
cristy151b66d2015-04-15 10:50:31 +0000480 basename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000481
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);
cristy151b66d2015-04-15 10:50:31 +0000491 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
cristy40a08ad2010-02-09 02:27:44 +0000492 "%s: %s",MagickPackageName,basename);
cristy3ed852e2009-09-05 21:47:34 +0000493 if (resource_info->title != (char *) NULL)
494 {
495 char
496 *title;
497
498 title=InterpretImageProperties(resource_info->image_info,*image,
cristy018f07f2011-09-04 21:15:19 +0000499 resource_info->title,exception);
cristy151b66d2015-04-15 10:50:31 +0000500 (void) CopyMagickString(windows->image.name,title,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000501 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 */
cristy051718b2011-08-28 22:49:25 +0000543 status=XSaveImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000544 if (status == MagickFalse)
545 {
cristyc663dbd2011-09-16 19:43:14 +0000546 char
cristy151b66d2015-04-15 10:50:31 +0000547 message[MagickPathExtent];
cristyc663dbd2011-09-16 19:43:14 +0000548
cristy151b66d2015-04-15 10:50:31 +0000549 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",
cristyc663dbd2011-09-16 19:43:14 +0000550 exception->reason != (char *) NULL ? exception->reason : "",
551 exception->description != (char *) NULL ? exception->description :
552 "");
553 XNoticeWidget(display,windows,"Unable to save file:",message);
cristy3ed852e2009-09-05 21:47:34 +0000554 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 {
cristy6710d842011-10-20 23:23:00 +0000584 XDisplayImageInfo(display,resource_info,windows,(Image *) NULL,*image,
585 exception);
cristy3ed852e2009-09-05 21:47:34 +0000586 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
cristy151b66d2015-04-15 10:50:31 +0000615 command[MagickPathExtent],
cristy3ed852e2009-09-05 21:47:34 +0000616 *url;
617
618 /*
619 Display documentation using Netscape remote control.
620 */
621 url=GetMagickHomeURL();
cristy151b66d2015-04-15 10:50:31 +0000622 (void) FormatLocaleString(command,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000623 "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",
cristy051718b2011-08-28 22:49:25 +0000635 (char *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +0000636 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 {
cristybb503372010-05-27 20:51:26 +0000645 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
cristy3ed852e2009-09-05 21:47:34 +0000646 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,
cristy051718b2011-08-28 22:49:25 +0000696% XResourceInfo *resource_info,Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000697%
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%
cristy051718b2011-08-28 22:49:25 +0000707% o exception: return any errors or warnings in this structure.
708%
cristy3ed852e2009-09-05 21:47:34 +0000709*/
710
cristy3ed852e2009-09-05 21:47:34 +0000711#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,
cristy051718b2011-08-28 22:49:25 +0000731 XResourceInfo *resource_info,Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000732{
733 char
cristy151b66d2015-04-15 10:50:31 +0000734 geometry[MagickPathExtent],
735 visual_type[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000736
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
cristybb503372010-05-27 20:51:26 +0000751 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000752 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
cristybb503372010-05-27 20:51:26 +0000773 size_t
cristy3ed852e2009-09-05 21:47:34 +0000774 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);
cristye1c94d92015-06-28 12:16:33 +0000795 assert(images->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000796 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));
cristy151b66d2015-04-15 10:50:31 +0000823 (void) CopyMagickString(visual_type,"default",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000824 status=XGetWindowAttributes(display,window_info.id,&window_attributes) != 0 ?
825 MagickTrue : MagickFalse;
826 if (status != MagickFalse)
cristy151b66d2015-04-15 10:50:31 +0000827 (void) FormatLocaleString(visual_type,MagickPathExtent,"0x%lx",
cristy3ed852e2009-09-05 21:47:34 +0000828 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)
cristybeb1a6b2013-11-04 12:08:18 +0000836 ThrowXWindowFatalException(ResourceLimitFatalError,
837 "MemoryAllocationFailed",images->filename);
cristy3ed852e2009-09-05 21:47:34 +0000838 map_info->colormap=(Colormap) NULL;
cristyf2faecf2010-05-28 19:19:36 +0000839 pixel.pixels=(unsigned long *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000840 /*
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);
cristy051718b2011-08-28 22:49:25 +0000862 coalesce_image=CoalesceImages(images,exception);
cristy3ed852e2009-09-05 21:47:34 +0000863 if (coalesce_image == (Image *) NULL)
cristybeb1a6b2013-11-04 12:08:18 +0000864 ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
cristy3ed852e2009-09-05 21:47:34 +0000865 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 {
cristy8a46d822012-08-28 23:32:39 +0000879 next->alpha_trait=UndefinedPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +0000880 if ((next->storage_class == DirectClass) ||
881 (next->colors != images->colors) ||
cristybb503372010-05-27 20:51:26 +0000882 (next->colors > (size_t) visual_info->colormap_size))
cristy3ed852e2009-09-05 21:47:34 +0000883 break;
cristybb503372010-05-27 20:51:26 +0000884 for (i=0; i < (ssize_t) images->colors; i++)
cristy101ab702011-10-13 13:06:32 +0000885 if (IsPixelInfoEquivalent(next->colormap+i,images->colormap+i) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000886 break;
cristybb503372010-05-27 20:51:26 +0000887 if (i < (ssize_t) images->colors)
cristy3ed852e2009-09-05 21:47:34 +0000888 break;
889 next=GetNextImageInList(next);
890 }
891 if (next != (Image *) NULL)
cristy018f07f2011-09-04 21:15:19 +0000892 (void) RemapImages(resources.quantize_info,images,(Image *) NULL,
893 exception);
cristy3ed852e2009-09-05 21:47:34 +0000894 }
895 /*
896 Sort images by increasing scene number.
897 */
898 number_scenes=GetImageListLength(images);
cristy051718b2011-08-28 22:49:25 +0000899 image_list=ImageListToArray(images,exception);
cristy3ed852e2009-09-05 21:47:34 +0000900 if (image_list == (Image **) NULL)
901 ThrowXWindowFatalException(ResourceLimitFatalError,
902 "MemoryAllocationFailed",images->filename);
cristybb503372010-05-27 20:51:26 +0000903 for (i=0; i < (ssize_t) number_scenes; i++)
cristy3ed852e2009-09-05 21:47:34 +0000904 if (image_list[i]->scene == 0)
905 break;
cristybb503372010-05-27 20:51:26 +0000906 if (i == (ssize_t) number_scenes)
cristy3ed852e2009-09-05 21:47:34 +0000907 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))
cristy8a46d822012-08-28 23:32:39 +0000918 (void) SetImageType(image_list[scene],image_list[scene]->alpha_trait ==
cristydef23e52015-01-22 11:52:01 +0000919 BlendPixelTrait ? TrueColorType : TrueColorAlphaType,exception);
cristy3ed852e2009-09-05 21:47:34 +0000920 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))
cristy8a46d822012-08-28 23:32:39 +0000926 (void) SetImageType(display_image,display_image->alpha_trait !=
cristydef23e52015-01-22 11:52:01 +0000927 BlendPixelTrait ? TrueColorType : TrueColorAlphaType,exception);
cristy3ed852e2009-09-05 21:47:34 +0000928 XMakeStandardColormap(display,visual_info,&resources,display_image,map_info,
cristy6710d842011-10-20 23:23:00 +0000929 &pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +0000930 /*
931 Graphic context superclass.
932 */
933 context_values.background=pixel.background_color.pixel;
934 context_values.foreground=pixel.foreground_color.pixel;
cristycee97112010-05-28 00:44:52 +0000935 pixel.annotate_context=XCreateGC(display,window_info.id,(unsigned long)
936 (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +0000937 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);
cristy151b66d2015-04-15 10:50:31 +0000954 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>",
cristy3ed852e2009-09-05 21:47:34 +0000955 window_attributes.width,window_attributes.height);
956 geometry_info.width=window_info.width;
957 geometry_info.height=window_info.height;
cristyecd0ab52010-05-30 14:59:20 +0000958 geometry_info.x=(ssize_t) window_info.x;
959 geometry_info.y=(ssize_t) window_info.y;
cristy3ed852e2009-09-05 21:47:34 +0000960 (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],
cristy051718b2011-08-28 22:49:25 +0000967 window_info.width,window_info.height,exception);
cristy3ed852e2009-09-05 21:47:34 +0000968 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(),
cristye8c25f92010-06-03 00:53:06 +0000976 "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);
cristy3ed852e2009-09-05 21:47:34 +0000979 if (image_list[0]->colors != 0)
cristye8c25f92010-06-03 00:53:06 +0000980 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
981 image_list[0]->colors);
cristy3ed852e2009-09-05 21:47:34 +0000982 (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
cristy151b66d2015-04-15 10:50:31 +00001005 default_geometry[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001006
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;
cristy151b66d2015-04-15 10:50:31 +00001022 (void) FormatLocaleString(default_geometry,MagickPathExtent,"%ux%u",width,
cristy3ed852e2009-09-05 21:47:34 +00001023 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)
cristy4c08aed2011-07-01 19:47:50 +00001083 XGetPixelInfo(display,visual_info,map_info,&resources,
cristy3ed852e2009-09-05 21:47:34 +00001084 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],
cristy051718b2011-08-28 22:49:25 +00001092 columns,rows,exception);
cristy3ed852e2009-09-05 21:47:34 +00001093 if (status == MagickFalse)
1094 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1095 images->filename);
1096 if (display_image->debug != MagickFalse)
1097 {
1098 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00001099 "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
1100 image_list[scene]->filename,(double) columns,(double) rows);
cristy3ed852e2009-09-05 21:47:34 +00001101 if (image_list[scene]->colors != 0)
cristye8c25f92010-06-03 00:53:06 +00001102 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1103 image_list[scene]->colors);
cristy3ed852e2009-09-05 21:47:34 +00001104 (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;
cristy8a46d822012-08-28 23:32:39 +00001129 if (image_list[scene]->alpha_trait)
cristy3ed852e2009-09-05 21:47:34 +00001130 (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,
cristy051718b2011-08-28 22:49:25 +00001183% char **argv,const int argc,Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001184%
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%
cristy051718b2011-08-28 22:49:25 +00001198% o exception: return any errors or warnings in this structure.
1199%
cristy3ed852e2009-09-05 21:47:34 +00001200*/
1201MagickExport Image *XAnimateImages(Display *display,
cristy051718b2011-08-28 22:49:25 +00001202 XResourceInfo *resource_info,char **argv,const int argc,Image *images,
1203 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001204{
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
cristy151b66d2015-04-15 10:50:31 +00001305 command[MagickPathExtent],
cristy00976d82011-02-20 20:31:28 +00001306 *directory,
cristy151b66d2015-04-15 10:50:31 +00001307 geometry[MagickPathExtent],
1308 resource_name[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001309
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
cristy3ed852e2009-09-05 21:47:34 +00001323 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
cristybb503372010-05-27 20:51:26 +00001336 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001337 i;
1338
cristy9d314ff2011-03-09 01:30:28 +00001339 ssize_t
1340 first_scene,
1341 iterations,
1342 scene;
1343
cristy3ed852e2009-09-05 21:47:34 +00001344 static char
cristy151b66d2015-04-15 10:50:31 +00001345 working_directory[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001346
cristybb503372010-05-27 20:51:26 +00001347 static size_t
cristy3ed852e2009-09-05 21:47:34 +00001348 number_windows;
1349
1350 static XWindowInfo
1351 *magick_windows[MaXWindows];
1352
1353 time_t
1354 timestamp;
1355
cristybb503372010-05-27 20:51:26 +00001356 size_t
cristy3ed852e2009-09-05 21:47:34 +00001357 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);
cristye1c94d92015-06-28 12:16:33 +00001406 assert(images->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001407 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
cristy8a5d7f42013-01-06 15:24:33 +00001416 if (*working_directory == '\0')
cristy151b66d2015-04-15 10:50:31 +00001417 (void) CopyMagickString(working_directory,".",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001418 status=chdir(working_directory);
1419 if (status == -1)
cristy051718b2011-08-28 22:49:25 +00001420 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
1421 "UnableToOpenFile","%s",working_directory);
cristy3ed852e2009-09-05 21:47:34 +00001422 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);
cristybb503372010-05-27 20:51:26 +00001460 for (i=0; i < (ssize_t) number_windows; i++)
cristy3ed852e2009-09-05 21:47:34 +00001461 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);
cristy051718b2011-08-28 22:49:25 +00001486 coalesce_image=CoalesceImages(images,exception);
cristy3ed852e2009-09-05 21:47:34 +00001487 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 {
cristy8a46d822012-08-28 23:32:39 +00001503 next->alpha_trait=UndefinedPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +00001504 if ((next->storage_class == DirectClass) ||
1505 (next->colors != images->colors) ||
cristybb503372010-05-27 20:51:26 +00001506 (next->colors > (size_t) visual_info->colormap_size))
cristy3ed852e2009-09-05 21:47:34 +00001507 break;
cristybb503372010-05-27 20:51:26 +00001508 for (i=0; i < (ssize_t) images->colors; i++)
cristy101ab702011-10-13 13:06:32 +00001509 if (IsPixelInfoEquivalent(next->colormap+i,images->colormap+i) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001510 break;
cristybb503372010-05-27 20:51:26 +00001511 if (i < (ssize_t) images->colors)
cristy3ed852e2009-09-05 21:47:34 +00001512 break;
1513 next=GetNextImageInList(next);
1514 }
1515 if (next != (Image *) NULL)
1516 (void) RemapImages(resource_info->quantize_info,images,
cristy018f07f2011-09-04 21:15:19 +00001517 (Image *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +00001518 }
1519 /*
1520 Sort images by increasing scene number.
1521 */
1522 number_scenes=GetImageListLength(images);
cristy051718b2011-08-28 22:49:25 +00001523 image_list=ImageListToArray(images,exception);
cristy3ed852e2009-09-05 21:47:34 +00001524 if (image_list == (Image **) NULL)
1525 ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
1526 images->filename);
cristybb503372010-05-27 20:51:26 +00001527 for (scene=0; scene < (ssize_t) number_scenes; scene++)
cristy3ed852e2009-09-05 21:47:34 +00001528 if (image_list[scene]->scene == 0)
1529 break;
cristybb503372010-05-27 20:51:26 +00001530 if (scene == (ssize_t) number_scenes)
cristy3ed852e2009-09-05 21:47:34 +00001531 qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
1532 /*
1533 Initialize Standard Colormap.
1534 */
1535 nexus=NewImageList();
1536 display_image=image_list[0];
cristybb503372010-05-27 20:51:26 +00001537 for (scene=0; scene < (ssize_t) number_scenes; scene++)
cristy3ed852e2009-09-05 21:47:34 +00001538 {
1539 if ((resource_info->map_type != (char *) NULL) ||
1540 (visual_info->klass == TrueColor) ||
1541 (visual_info->klass == DirectColor))
cristy8a46d822012-08-28 23:32:39 +00001542 (void) SetImageType(image_list[scene],image_list[scene]->alpha_trait ==
cristydef23e52015-01-22 11:52:01 +00001543 BlendPixelTrait ? TrueColorType : TrueColorAlphaType,exception);
cristy3ed852e2009-09-05 21:47:34 +00001544 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(),
cristye8c25f92010-06-03 00:53:06 +00001551 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,(double)
1552 display_image->scene,(double) display_image->columns,(double)
1553 display_image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001554 if (display_image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +00001555 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1556 display_image->colors);
cristy3ed852e2009-09-05 21:47:34 +00001557 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
1558 display_image->magick);
1559 }
1560 XMakeStandardColormap(display,visual_info,resource_info,display_image,
cristy6710d842011-10-20 23:23:00 +00001561 map_info,pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +00001562 /*
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,
cristybb503372010-05-27 20:51:26 +00001607 (size_t) (context_mask | GCPlaneMask),&context_values);
cristy3ed852e2009-09-05 21:47:34 +00001608 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,
cristybb503372010-05-27 20:51:26 +00001638 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +00001639 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,
cristy018f07f2011-09-04 21:15:19 +00001657 resource_info->title,exception);
cristy151b66d2015-04-15 10:50:31 +00001658 (void) CopyMagickString(windows->image.name,title,MagickPathExtent);
1659 (void) CopyMagickString(windows->image.icon_name,title,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001660 title=DestroyString(title);
1661 }
1662 else
1663 {
1664 char
cristy151b66d2015-04-15 10:50:31 +00001665 filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001666
1667 /*
1668 Window name is the base of the filename.
1669 */
1670 GetPathComponent(display_image->magick_filename,TailPath,filename);
cristy151b66d2015-04-15 10:50:31 +00001671 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
cristy04d55062011-03-15 18:58:50 +00001672 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,(double)
cristye8c25f92010-06-03 00:53:06 +00001673 display_image->scene,(double) number_scenes);
cristy151b66d2015-04-15 10:50:31 +00001674 (void) CopyMagickString(windows->image.icon_name,filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001675 }
1676 if (resource_info->immutable != MagickFalse)
1677 windows->image.immutable=MagickTrue;
1678 windows->image.shape=MagickTrue;
1679 windows->image.geometry=resource_info->image_geometry;
cristy151b66d2015-04-15 10:50:31 +00001680 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
cristy3ed852e2009-09-05 21:47:34 +00001681 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");
cristybb503372010-05-27 20:51:26 +00001705 windows->backdrop.flags=(size_t) (USSize | USPosition);
cristy3ed852e2009-09-05 21:47:34 +00001706 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);
cristy151b66d2015-04-15 10:50:31 +00001807 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command",
cristy3ed852e2009-09-05 21:47:34 +00001808 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);
cristy151b66d2015-04-15 10:50:31 +00001837 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget",
cristy3ed852e2009-09-05 21:47:34 +00001838 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);
cristy3ed852e2009-09-05 21:47:34 +00001885 /*
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;
cristy3ed852e2009-09-05 21:47:34 +00001900 /*
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);
cristy3ed852e2009-09-05 21:47:34 +00001907 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);
cristy04e11fd2010-03-19 16:01:44 +00001915 if ((windows->image.mapped == MagickFalse) ||
1916 (windows->backdrop.id != (Window) NULL))
1917 (void) XMapWindow(display,windows->image.id);
1918 XSetCursorState(display,windows,MagickTrue);
cristybb503372010-05-27 20:51:26 +00001919 for (scene=0; scene < (ssize_t) number_scenes; scene++)
cristy3ed852e2009-09-05 21:47:34 +00001920 {
1921 unsigned int
1922 columns,
1923 rows;
1924
1925 /*
1926 Create X image.
1927 */
cristy3ed852e2009-09-05 21:47:34 +00001928 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)
cristy4c08aed2011-07-01 19:47:50 +00001934 XGetPixelInfo(display,visual_info,map_info,resource_info,
cristy3ed852e2009-09-05 21:47:34 +00001935 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],
cristy051718b2011-08-28 22:49:25 +00001943 columns,rows,exception);
cristy3ed852e2009-09-05 21:47:34 +00001944 if (status == MagickFalse)
1945 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
1946 images->filename);
1947 if (image_list[scene]->debug != MagickFalse)
1948 {
1949 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00001950 "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
1951 image_list[scene]->filename,(double) columns,(double) rows);
cristy3ed852e2009-09-05 21:47:34 +00001952 if (image_list[scene]->colors != 0)
cristye8c25f92010-06-03 00:53:06 +00001953 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
1954 image_list[scene]->colors);
cristy3ed852e2009-09-05 21:47:34 +00001955 (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,
cristy018f07f2011-09-04 21:15:19 +00001967 image_list[scene],resource_info->title,exception);
cristy151b66d2015-04-15 10:50:31 +00001968 (void) CopyMagickString(windows->image.name,title,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001969 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--;
cristy151b66d2015-04-15 10:50:31 +00001977 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +00001978 "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double) scene+1,
1979 (double) number_scenes);
cristy3ed852e2009-09-05 21:47:34 +00001980 }
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;
cristy04e11fd2010-03-19 16:01:44 +00001989 if (scene == 0)
cristy3ed852e2009-09-05 21:47:34 +00001990 {
cristy04e11fd2010-03-19 16:01:44 +00001991 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 }
cristy3ed852e2009-09-05 21:47:34 +00001998 }
cristy04e11fd2010-03-19 16:01:44 +00001999 XSetCursorState(display,windows,MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00002000 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,
cristy051718b2011-08-28 22:49:25 +00002012 &state,exception);
cristy3ed852e2009-09-05 21:47:34 +00002013 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 */
cristybb503372010-05-27 20:51:26 +00002029 if (scene < ((ssize_t) number_scenes-1))
cristy3ed852e2009-09-05 21:47:34 +00002030 scene++;
2031 else
2032 {
2033 iterations++;
cristybb503372010-05-27 20:51:26 +00002034 if (iterations == (ssize_t) image_list[0]->iterations)
cristy3ed852e2009-09-05 21:47:34 +00002035 {
2036 iterations=0;
2037 state|=ExitState;
2038 }
cristy04e11fd2010-03-19 16:01:44 +00002039 if ((state & AutoReverseAnimationState) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002040 {
2041 state&=(~ForwardAnimationState);
2042 scene--;
2043 }
2044 else
2045 {
cristy04e11fd2010-03-19 16:01:44 +00002046 if ((state & RepeatAnimationState) == 0)
cristy3ed852e2009-09-05 21:47:34 +00002047 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++;
cristybb503372010-05-27 20:51:26 +00002063 if (iterations == (ssize_t) image_list[0]->iterations)
cristy3ed852e2009-09-05 21:47:34 +00002064 {
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);
cristybb503372010-05-27 20:51:26 +00002078 scene=(ssize_t) number_scenes-1;
cristy3ed852e2009-09-05 21:47:34 +00002079 }
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--;
cristy151b66d2015-04-15 10:50:31 +00002096 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +00002097 "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double)
2098 scene+1,(double) number_scenes);
cristy3ed852e2009-09-05 21:47:34 +00002099 if (resource_info->title != (char *) NULL)
2100 {
2101 char
2102 *title;
2103
2104 title=InterpretImageProperties(resource_info->image_info,
cristy018f07f2011-09-04 21:15:19 +00002105 image,resource_info->title,exception);
cristy3ed852e2009-09-05 21:47:34 +00002106 (void) CopyMagickString(windows->image.name,title,
cristy151b66d2015-04-15 10:50:31 +00002107 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002108 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 */
cristy4c08aed2011-07-01 19:47:50 +00002121 XGetPixelInfo(display,visual_info,map_info,resource_info,
cristy3ed852e2009-09-05 21:47:34 +00002122 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;
cristy04e11fd2010-03-19 16:01:44 +00002131 if ((state & ExitState) == 0)
2132 {
2133 XRefreshWindow(display,&windows->image,&event);
2134 (void) XSync(display,MagickFalse);
2135 }
cristy3ed852e2009-09-05 21:47:34 +00002136 state&=(~StepAnimationState);
2137 if (pause != MagickFalse)
cristybb503372010-05-27 20:51:26 +00002138 for (i=0; i < (ssize_t) resource_info->pause; i++)
cristy3ed852e2009-09-05 21:47:34 +00002139 {
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 (void) sleep(1);
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;
cristy151b66d2015-04-15 10:50:31 +00002183 (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002184 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;
cristy151b66d2015-04-15 10:50:31 +00002197 (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002198 command_type=Commands[id][entry];
2199 }
2200 if (command_type != NullCommand)
2201 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +00002202 command_type,&image,&state,exception);
cristy3ed852e2009-09-05 21:47:34 +00002203 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(),
cristyf2faecf2010-05-28 19:19:36 +00002262 "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]);
cristy3ed852e2009-09-05 21:47:34 +00002265 if (event.xclient.message_type == windows->im_protocols)
2266 {
cristyecd0ab52010-05-30 14:59:20 +00002267 if (*event.xclient.data.l == (long) windows->im_update_colormap)
cristy3ed852e2009-09-05 21:47:34 +00002268 {
2269 /*
2270 Update graphic context and window colormap.
2271 */
cristybb503372010-05-27 20:51:26 +00002272 for (i=0; i < (ssize_t) number_windows; i++)
cristy3ed852e2009-09-05 21:47:34 +00002273 {
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,
cristybb503372010-05-27 20:51:26 +00002287 (size_t) (context_mask | GCPlaneMask),
cristy3ed852e2009-09-05 21:47:34 +00002288 &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,
cristy49e2d862010-11-12 02:50:30 +00002295 (unsigned long) magick_windows[i]->mask,
2296 &magick_windows[i]->attributes);
cristy3ed852e2009-09-05 21:47:34 +00002297 }
2298 if (windows->backdrop.id != (Window) NULL)
2299 (void) XInstallColormap(display,map_info->colormap);
2300 break;
2301 }
cristyecd0ab52010-05-30 14:59:20 +00002302 if (*event.xclient.data.l == (long) windows->im_exit)
cristy3ed852e2009-09-05 21:47:34 +00002303 {
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
cristyf2faecf2010-05-28 19:19:36 +00002322 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002323 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,
cristy151b66d2015-04-15 10:50:31 +00002343 (char *) data,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002344 }
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,
cristy151b66d2015-04-15 10:50:31 +00002356 ((char *) data)+5,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002357 }
cristy051718b2011-08-28 22:49:25 +00002358 nexus=ReadImage(resource_info->image_info,exception);
2359 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00002360 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;
cristycee97112010-05-28 00:44:52 +00002370 if (*event.xclient.data.l == (long) windows->wm_take_focus)
cristy3ed852e2009-09-05 21:47:34 +00002371 {
2372 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2373 (Time) event.xclient.data.l[1]);
2374 break;
2375 }
cristycee97112010-05-28 00:44:52 +00002376 if (*event.xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +00002377 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(),
cristyf2faecf2010-05-28 19:19:36 +00002513 "Key press: 0x%lx (%c)",(unsigned long) key_symbol,*command);
cristy3ed852e2009-09-05 21:47:34 +00002514 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,
cristy051718b2011-08-28 22:49:25 +00002570 command_type,&image,&state,exception);
cristy3ed852e2009-09-05 21:47:34 +00002571 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(),
cristyf2faecf2010-05-28 19:19:36 +00002582 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
cristy3ed852e2009-09-05 21:47:34 +00002583 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,
cristy051718b2011-08-28 22:49:25 +00002615 OpenCommand,&image,&state,exception);
cristy3ed852e2009-09-05 21:47:34 +00002616 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,
cristy6710d842011-10-20 23:23:00 +00002633 display_image,icon_map,icon_pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +00002634 (void) XMakeImage(display,icon_resources,&windows->icon,
cristy051718b2011-08-28 22:49:25 +00002635 display_image,windows->icon.width,windows->icon.height,
2636 exception);
cristy3ed852e2009-09-05 21:47:34 +00002637 (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
cristyf2faecf2010-05-28 19:19:36 +00002681 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002682 after,
2683 length;
2684
2685 if (display_image->debug != MagickFalse)
2686 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00002687 "Property Notify: 0x%lx 0x%lx %d",(unsigned long)
2688 event.xproperty.window,(unsigned long) event.xproperty.atom,
2689 event.xproperty.state);
cristy3ed852e2009-09-05 21:47:34 +00002690 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,
cristy151b66d2015-04-15 10:50:31 +00002696 event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom)
cristy3ed852e2009-09-05 21:47:34 +00002697 AnyPropertyType,&type,&format,&length,&after,&data);
2698 if ((status != Success) || (length == 0))
2699 break;
2700 (void) CopyMagickString(resource_info->image_info->filename,
cristy151b66d2015-04-15 10:50:31 +00002701 (char *) data,MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00002702 nexus=ReadImage(resource_info->image_info,exception);
2703 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00002704 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,
cristy6710d842011-10-20 23:23:00 +00002741 display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002742 (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);
cristybb503372010-05-27 20:51:26 +00002808 for (scene=1; scene < (ssize_t) number_scenes; scene++)
cristy3ed852e2009-09-05 21:47:34 +00002809 {
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 }
cristy04e11fd2010-03-19 16:01:44 +00002817 XSetCursorState(display,windows,MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00002818 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)
cristy8418c7e2014-05-18 18:38:26 +00002828 (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);
2829 XDelay(display,SuspendTime);
cristy3ed852e2009-09-05 21:47:34 +00002830 (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 */
cristy151b66d2015-04-15 10:50:31 +00002844 directory=getcwd(working_directory,MagickPathExtent);
cristy00976d82011-02-20 20:31:28 +00002845 (void) directory;
cristy8a5d7f42013-01-06 15:24:33 +00002846 if (*resource_info->home_directory == '\0')
cristy151b66d2015-04-15 10:50:31 +00002847 (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002848 status=chdir(resource_info->home_directory);
2849 if (status == -1)
cristy051718b2011-08-28 22:49:25 +00002850 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
2851 "UnableToOpenFile","%s",resource_info->home_directory);
cristy3ed852e2009-09-05 21:47:34 +00002852 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,
cristy051718b2011-08-28 22:49:25 +00002871% XResourceInfo *resource_info,XWindows *windows,Image *image,
2872% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002873%
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,
cristy051718b2011-08-28 22:49:25 +00002891 XResourceInfo *resource_info,XWindows *windows,Image *image,
2892 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002893{
2894 char
cristy151b66d2015-04-15 10:50:31 +00002895 filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002896
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,
cristy151b66d2015-04-15 10:50:31 +00002908 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002909 else
2910 {
2911 char
cristy151b66d2015-04-15 10:50:31 +00002912 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002913
2914 int
2915 status;
2916
2917 GetPathComponent(image->filename,HeadPath,path);
2918 GetPathComponent(image->filename,TailPath,filename);
cristy8a5d7f42013-01-06 15:24:33 +00002919 if (*path == '\0')
cristy151b66d2015-04-15 10:50:31 +00002920 (void) CopyMagickString(path,".",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002921 status=chdir(path);
2922 if (status == -1)
cristy051718b2011-08-28 22:49:25 +00002923 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
2924 "UnableToOpenFile","%s",path);
cristy3ed852e2009-09-05 21:47:34 +00002925 }
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);
cristy151b66d2015-04-15 10:50:31 +00002942 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00002943 (void) SetImageInfo(image_info,1,exception);
cristy3ed852e2009-09-05 21:47:34 +00002944 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
2945 (LocaleCompare(image_info->magick,"JPG") == 0))
2946 {
2947 char
cristy151b66d2015-04-15 10:50:31 +00002948 quality[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002949
2950 int
2951 status;
2952
2953 /*
2954 Request JPEG quality from user.
2955 */
cristy151b66d2015-04-15 10:50:31 +00002956 (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double)
cristye8c25f92010-06-03 00:53:06 +00002957 image_info->quality);
cristy3ed852e2009-09-05 21:47:34 +00002958 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
2959 quality);
2960 if (*quality == '\0')
2961 return(MagickTrue);
cristye27293e2009-12-18 02:53:20 +00002962 image->quality=StringToUnsignedLong(quality);
cristy3ed852e2009-09-05 21:47:34 +00002963 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
cristy151b66d2015-04-15 10:50:31 +00002972 geometry[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002973
2974 /*
2975 Request page geometry from user.
2976 */
cristy151b66d2015-04-15 10:50:31 +00002977 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002978 if (LocaleCompare(image_info->magick,"PDF") == 0)
cristy151b66d2015-04-15 10:50:31 +00002979 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002980 if (image_info->page != (char *) NULL)
cristy151b66d2015-04-15 10:50:31 +00002981 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002982 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);
cristy051718b2011-08-28 22:49:25 +00002991 status=WriteImages(image_info,image,filename,exception);
cristy3ed852e2009-09-05 21:47:34 +00002992 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%
cristy051718b2011-08-28 22:49:25 +00003026% o exception: return any errors or warnings in this structure.
3027%
cristy3ed852e2009-09-05 21:47:34 +00003028*/
3029MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +00003030 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003031{
3032 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003033 assert(image_info->signature == MagickCoreSignature);
cristy4f88ff72013-12-08 17:16:11 +00003034 (void) image_info;
cristy3ed852e2009-09-05 21:47:34 +00003035 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003036 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003037 if (image->debug != MagickFalse)
3038 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy051718b2011-08-28 22:49:25 +00003039 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
anthonye5b39652012-04-21 05:37:29 +00003040 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003041 return(MagickFalse);
3042}
3043#endif