]> granicus.if.org Git - imagemagick/blob - magick/widget.c
(no commit message)
[imagemagick] / magick / widget.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                                                                             %
7 %                  W   W  IIIII  DDDD    GGGG  EEEEE  TTTTT                   %
8 %                  W   W    I    D   D  G      E        T                     %
9 %                  W W W    I    D   D  G  GG  EEE      T                     %
10 %                  WW WW    I    D   D  G   G  E        T                     %
11 %                  W   W  IIIII  DDDD    GGGG  EEEEE    T                     %
12 %                                                                             %
13 %                                                                             %
14 %                   MagickCore X11 User Interface Methods                     %
15 %                                                                             %
16 %                              Software Design                                %
17 %                                John Cristy                                  %
18 %                              September 1993                                 %
19 %                                                                             %
20 %                                                                             %
21 %  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
22 %  dedicated to making software imaging solutions freely available.           %
23 %                                                                             %
24 %  You may not use this file except in compliance with the License.  You may  %
25 %  obtain a copy of the License at                                            %
26 %                                                                             %
27 %    http://www.imagemagick.org/script/license.php                            %
28 %                                                                             %
29 %  Unless required by applicable law or agreed to in writing, software        %
30 %  distributed under the License is distributed on an "AS IS" BASIS,          %
31 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32 %  See the License for the specific language governing permissions and        %
33 %  limitations under the License.                                             %
34 %                                                                             %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "magick/studio.h"
44 #include "magick/color.h"
45 #include "magick/color-private.h"
46 #include "magick/exception.h"
47 #include "magick/exception-private.h"
48 #include "magick/image.h"
49 #include "magick/magick.h"
50 #include "magick/memory_.h"
51 #include "magick/PreRvIcccm.h"
52 #include "magick/string_.h"
53 #include "magick/token.h"
54 #include "magick/utility.h"
55 #include "magick/xwindow-private.h"
56 #include "magick/widget.h"
57
58 #if defined(MAGICKCORE_X11_DELEGATE)
59 \f
60 /*
61   Define declarations.
62 */
63 #define AreaIsActive(matte_info,position)  ( \
64   ((position.y >= (int) (matte_info.y-matte_info.bevel_width)) &&  \
65    (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
66    ? MagickTrue : MagickFalse)
67 #define Extent(s)  ((int) strlen(s))
68 #define MatteIsActive(matte_info,position)  ( \
69   ((position.x >= (int) (matte_info.x-matte_info.bevel_width)) && \
70    (position.y >= (int) (matte_info.y-matte_info.bevel_width)) &&  \
71    (position.x < (int) (matte_info.x+matte_info.width+matte_info.bevel_width)) &&  \
72    (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
73    ? MagickTrue : MagickFalse)
74 #define MaxTextWidth  ((unsigned int) (255*XTextWidth(font_info,"_",1)))
75 #define MinTextWidth  (26*XTextWidth(font_info,"_",1))
76 #define QuantumMargin   MagickMax(font_info->max_bounds.width,12)
77 #define WidgetTextWidth(font_info,text)  \
78   ((unsigned int) XTextWidth(font_info,text,Extent(text)))
79 #define WindowIsActive(window_info,position)  ( \
80   ((position.x >= 0) && (position.y >= 0) &&  \
81    (position.x < (int) window_info.width) &&  \
82    (position.y < (int) window_info.height)) ? MagickTrue : MagickFalse)
83 \f
84 /*
85   Enum declarations.
86 */
87 typedef enum
88 {
89   ControlState = 0x0001,
90   InactiveWidgetState = 0x0004,
91   JumpListState = 0x0008,
92   RedrawActionState = 0x0010,
93   RedrawListState = 0x0020,
94   RedrawWidgetState = 0x0040,
95   UpdateListState = 0x0100
96 } WidgetState;
97
98 /*
99   Typedef declarations.
100 */
101 typedef struct _XWidgetInfo
102 {
103   char
104     *cursor,
105     *text,
106     *marker;
107
108   int
109     id;
110
111   unsigned int
112     bevel_width,
113     width,
114     height;
115
116   int
117     x,
118     y,
119     min_y,
120     max_y;
121
122   MagickStatusType
123     raised,
124     active,
125     center,
126     trough,
127     highlight;
128 } XWidgetInfo;
129 \f
130 /*
131   Variable declarations.
132 */
133 static XWidgetInfo
134   monitor_info =
135   {
136     (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
137     MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
138   },
139   submenu_info =
140   {
141     (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
142     MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
143   },
144   *selection_info = (XWidgetInfo *) NULL,
145   toggle_info =
146   {
147     (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
148     MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
149   };
150 \f
151 /*
152   Constant declarations.
153 */
154 static const int
155   BorderOffset = 4,
156   DoubleClick = 250;
157 \f
158 /*
159   Method prototypes.
160 */
161 static void
162   XDrawMatte(Display *,const XWindowInfo *,const XWidgetInfo *),
163   XSetBevelColor(Display *,const XWindowInfo *,const MagickStatusType),
164   XSetMatteColor(Display *,const XWindowInfo *,const MagickStatusType),
165   XSetTextColor(Display *,const XWindowInfo *,const MagickStatusType);
166 \f
167 /*
168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169 %                                                                             %
170 %                                                                             %
171 %                                                                             %
172 %   D e s t r o y X W i d g e t                                               %
173 %                                                                             %
174 %                                                                             %
175 %                                                                             %
176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177 %
178 %  DestroyXWidget() destroys resources associated with the X widget.
179 %
180 %  The format of the DestroyXWidget method is:
181 %
182 %      void DestroyXWidget()
183 %
184 %  A description of each parameter follows:
185 %
186 */
187 MagickExport void DestroyXWidget(void)
188 {
189   if (selection_info != (XWidgetInfo *) NULL)
190     selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
191 }
192 \f
193 /*
194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195 %                                                                             %
196 %                                                                             %
197 %                                                                             %
198 +   X D r a w B e v e l                                                       %
199 %                                                                             %
200 %                                                                             %
201 %                                                                             %
202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
203 %
204 %  XDrawBevel() "sets off" an area with a highlighted upper and left bevel and
205 %  a shadowed lower and right bevel.  The highlighted and shadowed bevels
206 %  create a 3-D effect.
207 %
208 %  The format of the XDrawBevel function is:
209 %
210 %      XDrawBevel(display,window_info,bevel_info)
211 %
212 %  A description of each parameter follows:
213 %
214 %    o display: Specifies a pointer to the Display structure;  returned from
215 %      XOpenDisplay.
216 %
217 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
218 %
219 %    o bevel_info: Specifies a pointer to a XWidgetInfo structure.  It
220 %      contains the extents of the bevel.
221 %
222 */
223 static void XDrawBevel(Display *display,const XWindowInfo *window_info,
224   const XWidgetInfo *bevel_info)
225 {
226   int
227     x1,
228     x2,
229     y1,
230     y2;
231
232   unsigned int
233     bevel_width;
234
235   XPoint
236     points[6];
237
238   /*
239     Draw upper and left beveled border.
240   */
241   x1=bevel_info->x;
242   y1=bevel_info->y+bevel_info->height;
243   x2=bevel_info->x+bevel_info->width;
244   y2=bevel_info->y;
245   bevel_width=bevel_info->bevel_width;
246   points[0].x=x1;
247   points[0].y=y1;
248   points[1].x=x1;
249   points[1].y=y2;
250   points[2].x=x2;
251   points[2].y=y2;
252   points[3].x=x2+bevel_width;
253   points[3].y=y2-bevel_width;
254   points[4].x=x1-bevel_width;
255   points[4].y=y2-bevel_width;
256   points[5].x=x1-bevel_width;
257   points[5].y=y1+bevel_width;
258   XSetBevelColor(display,window_info,bevel_info->raised);
259   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
260     points,6,Complex,CoordModeOrigin);
261   /*
262     Draw lower and right beveled border.
263   */
264   points[0].x=x1;
265   points[0].y=y1;
266   points[1].x=x2;
267   points[1].y=y1;
268   points[2].x=x2;
269   points[2].y=y2;
270   points[3].x=x2+bevel_width;
271   points[3].y=y2-bevel_width;
272   points[4].x=x2+bevel_width;
273   points[4].y=y1+bevel_width;
274   points[5].x=x1-bevel_width;
275   points[5].y=y1+bevel_width;
276   XSetBevelColor(display,window_info,!bevel_info->raised);
277   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
278     points,6,Complex,CoordModeOrigin);
279   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
280 }
281 \f
282 /*
283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284 %                                                                             %
285 %                                                                             %
286 %                                                                             %
287 +   X D r a w B e v e l e d B u t t o n                                       %
288 %                                                                             %
289 %                                                                             %
290 %                                                                             %
291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 %
293 %  XDrawBeveledButton() draws a button with a highlighted upper and left bevel
294 %  and a shadowed lower and right bevel.  The highlighted and shadowed bevels
295 %  create a 3-D effect.
296 %
297 %  The format of the XDrawBeveledButton function is:
298 %
299 %      XDrawBeveledButton(display,window_info,button_info)
300 %
301 %  A description of each parameter follows:
302 %
303 %    o display: Specifies a pointer to the Display structure;  returned from
304 %      XOpenDisplay.
305 %
306 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
307 %
308 %    o button_info: Specifies a pointer to a XWidgetInfo structure.  It
309 %      contains the extents of the button.
310 %
311 */
312
313 static inline int MagickAbsoluteValue(const int x)
314 {
315   if (x < 0)
316     return(-x);
317   return(x);
318 }
319
320 static inline int MagickMax(const int x,const int y)
321 {
322   if (x > y)
323     return(x);
324   return(y);
325 }
326
327 static inline int MagickMin(const int x,const int y)
328 {
329   if (x < y)
330     return(x);
331   return(y);
332 }
333
334 static void XDrawBeveledButton(Display *display,const XWindowInfo *window_info,
335   const XWidgetInfo *button_info)
336 {
337   int
338     x,
339     y;
340
341   unsigned int
342     width;
343
344   XFontStruct
345     *font_info;
346
347   XRectangle
348     crop_info;
349
350   /*
351     Draw matte.
352   */
353   XDrawBevel(display,window_info,button_info);
354   XSetMatteColor(display,window_info,button_info->raised);
355   (void) XFillRectangle(display,window_info->id,window_info->widget_context,
356     button_info->x,button_info->y,button_info->width,button_info->height);
357   x=button_info->x-button_info->bevel_width-1;
358   y=button_info->y-button_info->bevel_width-1;
359   (void) XSetForeground(display,window_info->widget_context,
360     window_info->pixel_info->trough_color.pixel);
361   if (button_info->raised || (window_info->depth == 1))
362     (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
363       x,y,button_info->width+(button_info->bevel_width << 1)+1,
364       button_info->height+(button_info->bevel_width << 1)+1);
365   if (button_info->text == (char *) NULL)
366     return;
367   /*
368     Set cropping region.
369   */
370   crop_info.width=(unsigned short) button_info->width;
371   crop_info.height=(unsigned short) button_info->height;
372   crop_info.x=button_info->x;
373   crop_info.y=button_info->y;
374   /*
375     Draw text.
376   */
377   font_info=window_info->font_info;
378   width=WidgetTextWidth(font_info,button_info->text);
379   x=button_info->x+(QuantumMargin >> 1);
380   if (button_info->center)
381     x=button_info->x+(button_info->width >> 1)-(width >> 1);
382   y=button_info->y+((button_info->height-
383     (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
384   if ((int) button_info->width == (QuantumMargin >> 1))
385     {
386       /*
387         Option button-- write label to right of button.
388       */
389       XSetTextColor(display,window_info,MagickTrue);
390       x=button_info->x+button_info->width+button_info->bevel_width+
391         (QuantumMargin >> 1);
392       (void) XDrawString(display,window_info->id,window_info->widget_context,
393         x,y,button_info->text,Extent(button_info->text));
394       return;
395     }
396   (void) XSetClipRectangles(display,window_info->widget_context,0,0,&crop_info,
397     1,Unsorted);
398   XSetTextColor(display,window_info,button_info->raised);
399   (void) XDrawString(display,window_info->id,window_info->widget_context,x,y,
400     button_info->text,Extent(button_info->text));
401   (void) XSetClipMask(display,window_info->widget_context,None);
402   if (button_info->raised == MagickFalse)
403     XDelay(display,SuspendTime << 2);
404 }
405 \f
406 /*
407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408 %                                                                             %
409 %                                                                             %
410 %                                                                             %
411 +   X D r a w B e v e l e d M a t t e                                         %
412 %                                                                             %
413 %                                                                             %
414 %                                                                             %
415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
416 %
417 %  XDrawBeveledMatte() draws a matte with a shadowed upper and left bevel and
418 %  a highlighted lower and right bevel.  The highlighted and shadowed bevels
419 %  create a 3-D effect.
420 %
421 %  The format of the XDrawBeveledMatte function is:
422 %
423 %      XDrawBeveledMatte(display,window_info,matte_info)
424 %
425 %  A description of each parameter follows:
426 %
427 %    o display: Specifies a pointer to the Display structure;  returned from
428 %      XOpenDisplay.
429 %
430 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
431 %
432 %    o matte_info: Specifies a pointer to a XWidgetInfo structure.  It
433 %      contains the extents of the matte.
434 %
435 */
436 static void XDrawBeveledMatte(Display *display,const XWindowInfo *window_info,
437   const XWidgetInfo *matte_info)
438 {
439   /*
440     Draw matte.
441   */
442   XDrawBevel(display,window_info,matte_info);
443   XDrawMatte(display,window_info,matte_info);
444 }
445 \f
446 /*
447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448 %                                                                             %
449 %                                                                             %
450 %                                                                             %
451 +   X D r a w M a t t e                                                       %
452 %                                                                             %
453 %                                                                             %
454 %                                                                             %
455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456 %
457 %  XDrawMatte() fills a rectangular area with the matte color.
458 %
459 %  The format of the XDrawMatte function is:
460 %
461 %      XDrawMatte(display,window_info,matte_info)
462 %
463 %  A description of each parameter follows:
464 %
465 %    o display: Specifies a pointer to the Display structure;  returned from
466 %      XOpenDisplay.
467 %
468 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
469 %
470 %    o matte_info: Specifies a pointer to a XWidgetInfo structure.  It
471 %      contains the extents of the matte.
472 %
473 */
474 static void XDrawMatte(Display *display,const XWindowInfo *window_info,
475   const XWidgetInfo *matte_info)
476 {
477   /*
478     Draw matte.
479   */
480   if ((matte_info->trough == MagickFalse) || (window_info->depth == 1))
481     (void) XFillRectangle(display,window_info->id,
482       window_info->highlight_context,matte_info->x,matte_info->y,
483       matte_info->width,matte_info->height);
484   else
485     {
486       (void) XSetForeground(display,window_info->widget_context,
487         window_info->pixel_info->trough_color.pixel);
488       (void) XFillRectangle(display,window_info->id,window_info->widget_context,
489         matte_info->x,matte_info->y,matte_info->width,matte_info->height);
490     }
491 }
492 \f
493 /*
494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495 %                                                                             %
496 %                                                                             %
497 %                                                                             %
498 +   X D r a w M a t t e T e x t                                               %
499 %                                                                             %
500 %                                                                             %
501 %                                                                             %
502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
503 %
504 %  XDrawMatteText() draws a matte with text.  If the text exceeds the extents
505 %  of the text, a portion of the text relative to the cursor is displayed.
506 %
507 %  The format of the XDrawMatteText function is:
508 %
509 %      XDrawMatteText(display,window_info,text_info)
510 %
511 %  A description of each parameter follows:
512 %
513 %    o display: Specifies a pointer to the Display structure;  returned from
514 %      XOpenDisplay.
515 %
516 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
517 %
518 %    o text_info: Specifies a pointer to a XWidgetInfo structure.  It
519 %      contains the extents of the text.
520 %
521 */
522 static void XDrawMatteText(Display *display,const XWindowInfo *window_info,
523   XWidgetInfo *text_info)
524 {
525   const char
526     *text;
527
528   int
529     n,
530     x,
531     y;
532
533   register int
534     i;
535
536   unsigned int
537     height,
538     width;
539
540   XFontStruct
541     *font_info;
542
543   XRectangle
544     crop_info;
545
546   /*
547     Clear the text area.
548   */
549   XSetMatteColor(display,window_info,MagickFalse);
550   (void) XFillRectangle(display,window_info->id,window_info->widget_context,
551     text_info->x,text_info->y,text_info->width,text_info->height);
552   if (text_info->text == (char *) NULL)
553     return;
554   XSetTextColor(display,window_info,text_info->highlight);
555   font_info=window_info->font_info;
556   x=text_info->x+(QuantumMargin >> 2);
557   y=text_info->y+font_info->ascent+(text_info->height >> 2);
558   width=text_info->width-(QuantumMargin >> 1);
559   height=(unsigned int) (font_info->ascent+font_info->descent);
560   if (*text_info->text == '\0')
561     {
562       /*
563         No text-- just draw cursor.
564       */
565       (void) XDrawLine(display,window_info->id,window_info->annotate_context,
566         x,y+3,x,y-height+3);
567       return;
568     }
569   /*
570     Set cropping region.
571   */
572   crop_info.width=(unsigned short) text_info->width;
573   crop_info.height=(unsigned short) text_info->height;
574   crop_info.x=text_info->x;
575   crop_info.y=text_info->y;
576   /*
577     Determine beginning of the visible text.
578   */
579   if (text_info->cursor < text_info->marker)
580     text_info->marker=text_info->cursor;
581   else
582     {
583       text=text_info->marker;
584       if (XTextWidth(font_info,(char *) text,(int) (text_info->cursor-text)) >
585           (int) width)
586         {
587           text=text_info->text;
588           for (i=0; i < Extent(text); i++)
589           {
590             n=XTextWidth(font_info,(char *) text+i,(int)
591               (text_info->cursor-text-i));
592             if (n <= (int) width)
593               break;
594           }
595           text_info->marker=(char *) text+i;
596         }
597     }
598   /*
599     Draw text and cursor.
600   */
601   if (text_info->highlight == MagickFalse)
602     {
603       (void) XSetClipRectangles(display,window_info->widget_context,0,0,
604         &crop_info,1,Unsorted);
605       (void) XDrawString(display,window_info->id,window_info->widget_context,
606         x,y,text_info->marker,Extent(text_info->marker));
607       (void) XSetClipMask(display,window_info->widget_context,None);
608     }
609   else
610     {
611       (void) XSetClipRectangles(display,window_info->annotate_context,0,0,
612         &crop_info,1,Unsorted);
613       width=WidgetTextWidth(font_info,text_info->marker);
614       (void) XFillRectangle(display,window_info->id,
615         window_info->annotate_context,x,y-font_info->ascent,width,height);
616       (void) XSetClipMask(display,window_info->annotate_context,None);
617       (void) XSetClipRectangles(display,window_info->highlight_context,0,0,
618         &crop_info,1,Unsorted);
619       (void) XDrawString(display,window_info->id,
620         window_info->highlight_context,x,y,text_info->marker,
621         Extent(text_info->marker));
622       (void) XSetClipMask(display,window_info->highlight_context,None);
623     }
624   x+=XTextWidth(font_info,text_info->marker,(int)
625     (text_info->cursor-text_info->marker));
626   (void) XDrawLine(display,window_info->id,window_info->annotate_context,x,y+3,
627     x,y-height+3);
628 }
629 \f
630 /*
631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632 %                                                                             %
633 %                                                                             %
634 %                                                                             %
635 +   X D r a w T r i a n g l e E a s t                                         %
636 %                                                                             %
637 %                                                                             %
638 %                                                                             %
639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
640 %
641 %  XDrawTriangleEast() draws a triangle with a highlighted left bevel and a
642 %  shadowed right and lower bevel.  The highlighted and shadowed bevels create
643 %  a 3-D effect.
644 %
645 %  The format of the XDrawTriangleEast function is:
646 %
647 %      XDrawTriangleEast(display,window_info,triangle_info)
648 %
649 %  A description of each parameter follows:
650 %
651 %    o display: Specifies a pointer to the Display structure;  returned from
652 %      XOpenDisplay.
653 %
654 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
655 %
656 %    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
657 %      contains the extents of the triangle.
658 %
659 */
660 static void XDrawTriangleEast(Display *display,const XWindowInfo *window_info,
661   const XWidgetInfo *triangle_info)
662 {
663   int
664     x1,
665     x2,
666     x3,
667     y1,
668     y2,
669     y3;
670
671   unsigned int
672     bevel_width;
673
674   XFontStruct
675     *font_info;
676
677   XPoint
678     points[4];
679
680   /*
681     Draw triangle matte.
682   */
683   x1=triangle_info->x;
684   y1=triangle_info->y;
685   x2=triangle_info->x+triangle_info->width;
686   y2=triangle_info->y+(triangle_info->height >> 1);
687   x3=triangle_info->x;
688   y3=triangle_info->y+triangle_info->height;
689   bevel_width=triangle_info->bevel_width;
690   points[0].x=x1;
691   points[0].y=y1;
692   points[1].x=x2;
693   points[1].y=y2;
694   points[2].x=x3;
695   points[2].y=y3;
696   XSetMatteColor(display,window_info,triangle_info->raised);
697   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
698     points,3,Complex,CoordModeOrigin);
699   /*
700     Draw bottom bevel.
701   */
702   points[0].x=x2;
703   points[0].y=y2;
704   points[1].x=x3;
705   points[1].y=y3;
706   points[2].x=x3-bevel_width;
707   points[2].y=y3+bevel_width;
708   points[3].x=x2+bevel_width;
709   points[3].y=y2;
710   XSetBevelColor(display,window_info,!triangle_info->raised);
711   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
712     points,4,Complex,CoordModeOrigin);
713   /*
714     Draw Left bevel.
715   */
716   points[0].x=x3;
717   points[0].y=y3;
718   points[1].x=x1;
719   points[1].y=y1;
720   points[2].x=x1-bevel_width+1;
721   points[2].y=y1-bevel_width;
722   points[3].x=x3-bevel_width+1;
723   points[3].y=y3+bevel_width;
724   XSetBevelColor(display,window_info,triangle_info->raised);
725   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
726     points,4,Complex,CoordModeOrigin);
727   /*
728     Draw top bevel.
729   */
730   points[0].x=x1;
731   points[0].y=y1;
732   points[1].x=x2;
733   points[1].y=y2;
734   points[2].x=x2+bevel_width;
735   points[2].y=y2;
736   points[3].x=x1-bevel_width;
737   points[3].y=y1-bevel_width;
738   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
739     points,4,Complex,CoordModeOrigin);
740   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
741   if (triangle_info->text == (char *) NULL)
742     return;
743   /*
744     Write label to right of triangle.
745   */
746   font_info=window_info->font_info;
747   XSetTextColor(display,window_info,MagickTrue);
748   x1=triangle_info->x+triangle_info->width+triangle_info->bevel_width+
749     (QuantumMargin >> 1);
750   y1=triangle_info->y+((triangle_info->height-
751     (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
752   (void) XDrawString(display,window_info->id,window_info->widget_context,x1,y1,
753     triangle_info->text,Extent(triangle_info->text));
754 }
755 \f
756 /*
757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758 %                                                                             %
759 %                                                                             %
760 %                                                                             %
761 +   X D r a w T r i a n g l e N o r t h                                       %
762 %                                                                             %
763 %                                                                             %
764 %                                                                             %
765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766 %
767 %  XDrawTriangleNorth() draws a triangle with a highlighted left bevel and a
768 %  shadowed right and lower bevel.  The highlighted and shadowed bevels create
769 %  a 3-D effect.
770 %
771 %  The format of the XDrawTriangleNorth function is:
772 %
773 %      XDrawTriangleNorth(display,window_info,triangle_info)
774 %
775 %  A description of each parameter follows:
776 %
777 %    o display: Specifies a pointer to the Display structure;  returned from
778 %      XOpenDisplay.
779 %
780 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
781 %
782 %    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
783 %      contains the extents of the triangle.
784 %
785 */
786 static void XDrawTriangleNorth(Display *display,const XWindowInfo *window_info,
787   const XWidgetInfo *triangle_info)
788 {
789   int
790     x1,
791     x2,
792     x3,
793     y1,
794     y2,
795     y3;
796
797   unsigned int
798     bevel_width;
799
800   XPoint
801     points[4];
802
803   /*
804     Draw triangle matte.
805   */
806   x1=triangle_info->x;
807   y1=triangle_info->y+triangle_info->height;
808   x2=triangle_info->x+(triangle_info->width >> 1);
809   y2=triangle_info->y;
810   x3=triangle_info->x+triangle_info->width;
811   y3=triangle_info->y+triangle_info->height;
812   bevel_width=triangle_info->bevel_width;
813   points[0].x=x1;
814   points[0].y=y1;
815   points[1].x=x2;
816   points[1].y=y2;
817   points[2].x=x3;
818   points[2].y=y3;
819   XSetMatteColor(display,window_info,triangle_info->raised);
820   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
821     points,3,Complex,CoordModeOrigin);
822   /*
823     Draw left bevel.
824   */
825   points[0].x=x1;
826   points[0].y=y1;
827   points[1].x=x2;
828   points[1].y=y2;
829   points[2].x=x2;
830   points[2].y=y2-bevel_width-2;
831   points[3].x=x1-bevel_width-1;
832   points[3].y=y1+bevel_width;
833   XSetBevelColor(display,window_info,triangle_info->raised);
834   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
835     points,4,Complex,CoordModeOrigin);
836   /*
837     Draw right bevel.
838   */
839   points[0].x=x2;
840   points[0].y=y2;
841   points[1].x=x3;
842   points[1].y=y3;
843   points[2].x=x3+bevel_width;
844   points[2].y=y3+bevel_width;
845   points[3].x=x2;
846   points[3].y=y2-bevel_width;
847   XSetBevelColor(display,window_info,!triangle_info->raised);
848   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
849     points,4,Complex,CoordModeOrigin);
850   /*
851     Draw lower bevel.
852   */
853   points[0].x=x3;
854   points[0].y=y3;
855   points[1].x=x1;
856   points[1].y=y1;
857   points[2].x=x1-bevel_width;
858   points[2].y=y1+bevel_width;
859   points[3].x=x3+bevel_width;
860   points[3].y=y3+bevel_width;
861   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
862     points,4,Complex,CoordModeOrigin);
863   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
864 }
865 \f
866 /*
867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
868 %                                                                             %
869 %                                                                             %
870 %                                                                             %
871 +   X D r a w T r i a n g l e S o u t h                                       %
872 %                                                                             %
873 %                                                                             %
874 %                                                                             %
875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
876 %
877 %  XDrawTriangleSouth() draws a border with a highlighted left and right bevel
878 %  and a shadowed lower bevel.  The highlighted and shadowed bevels create a
879 %  3-D effect.
880 %
881 %  The format of the XDrawTriangleSouth function is:
882 %
883 %      XDrawTriangleSouth(display,window_info,triangle_info)
884 %
885 %  A description of each parameter follows:
886 %
887 %    o display: Specifies a pointer to the Display structure;  returned from
888 %      XOpenDisplay.
889 %
890 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
891 %
892 %    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
893 %      contains the extents of the triangle.
894 %
895 */
896 static void XDrawTriangleSouth(Display *display,const XWindowInfo *window_info,
897   const XWidgetInfo *triangle_info)
898 {
899   int
900     x1,
901     x2,
902     x3,
903     y1,
904     y2,
905     y3;
906
907   unsigned int
908     bevel_width;
909
910   XPoint
911     points[4];
912
913   /*
914     Draw triangle matte.
915   */
916   x1=triangle_info->x;
917   y1=triangle_info->y;
918   x2=triangle_info->x+(triangle_info->width >> 1);
919   y2=triangle_info->y+triangle_info->height;
920   x3=triangle_info->x+triangle_info->width;
921   y3=triangle_info->y;
922   bevel_width=triangle_info->bevel_width;
923   points[0].x=x1;
924   points[0].y=y1;
925   points[1].x=x2;
926   points[1].y=y2;
927   points[2].x=x3;
928   points[2].y=y3;
929   XSetMatteColor(display,window_info,triangle_info->raised);
930   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
931     points,3,Complex,CoordModeOrigin);
932   /*
933     Draw top bevel.
934   */
935   points[0].x=x3;
936   points[0].y=y3;
937   points[1].x=x1;
938   points[1].y=y1;
939   points[2].x=x1-bevel_width;
940   points[2].y=y1-bevel_width;
941   points[3].x=x3+bevel_width;
942   points[3].y=y3-bevel_width;
943   XSetBevelColor(display,window_info,triangle_info->raised);
944   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
945     points,4,Complex,CoordModeOrigin);
946   /*
947     Draw right bevel.
948   */
949   points[0].x=x2;
950   points[0].y=y2;
951   points[1].x=x3+1;
952   points[1].y=y3-bevel_width;
953   points[2].x=x3+bevel_width;
954   points[2].y=y3-bevel_width;
955   points[3].x=x2;
956   points[3].y=y2+bevel_width;
957   XSetBevelColor(display,window_info,!triangle_info->raised);
958   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
959     points,4,Complex,CoordModeOrigin);
960   /*
961     Draw left bevel.
962   */
963   points[0].x=x1;
964   points[0].y=y1;
965   points[1].x=x2;
966   points[1].y=y2;
967   points[2].x=x2;
968   points[2].y=y2+bevel_width;
969   points[3].x=x1-bevel_width;
970   points[3].y=y1-bevel_width;
971   XSetBevelColor(display,window_info,triangle_info->raised);
972   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
973     points,4,Complex,CoordModeOrigin);
974   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
975 }
976 \f
977 /*
978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
979 %                                                                             %
980 %                                                                             %
981 %                                                                             %
982 +   X D r a w W i d g e t T e x t                                             %
983 %                                                                             %
984 %                                                                             %
985 %                                                                             %
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 %
988 %  XDrawWidgetText() first clears the widget and draws a text string justifed
989 %  left (or center) in the x-direction and centered within the y-direction.
990 %
991 %  The format of the XDrawWidgetText function is:
992 %
993 %      XDrawWidgetText(display,window_info,text_info)
994 %
995 %  A description of each parameter follows:
996 %
997 %    o display: Specifies a pointer to the Display structure;  returned from
998 %      XOpenDisplay.
999 %
1000 %    o window_info: Specifies a pointer to a XWindowText structure.
1001 %
1002 %    o text_info: Specifies a pointer to XWidgetInfo structure.
1003 %
1004 */
1005 static void XDrawWidgetText(Display *display,const XWindowInfo *window_info,
1006   XWidgetInfo *text_info)
1007 {
1008   GC
1009     widget_context;
1010
1011   int
1012     x,
1013     y;
1014
1015   unsigned int
1016     height,
1017     width;
1018
1019   XFontStruct
1020     *font_info;
1021
1022   XRectangle
1023     crop_info;
1024
1025   /*
1026     Clear the text area.
1027   */
1028   widget_context=window_info->annotate_context;
1029   if (text_info->raised)
1030     (void) XClearArea(display,window_info->id,text_info->x,text_info->y,
1031       text_info->width,text_info->height,MagickFalse);
1032   else
1033     {
1034       (void) XFillRectangle(display,window_info->id,widget_context,text_info->x,
1035         text_info->y,text_info->width,text_info->height);
1036       widget_context=window_info->highlight_context;
1037     }
1038   if (text_info->text == (char *) NULL)
1039     return;
1040   if (*text_info->text == '\0')
1041     return;
1042   /*
1043     Set cropping region.
1044   */
1045   font_info=window_info->font_info;
1046   crop_info.width=(unsigned short) text_info->width;
1047   crop_info.height=(unsigned short) text_info->height;
1048   crop_info.x=text_info->x;
1049   crop_info.y=text_info->y;
1050   /*
1051     Draw text.
1052   */
1053   width=WidgetTextWidth(font_info,text_info->text);
1054   x=text_info->x+(QuantumMargin >> 1);
1055   if (text_info->center)
1056     x=text_info->x+(text_info->width >> 1)-(width >> 1);
1057   if (text_info->raised)
1058     if (width > (text_info->width-QuantumMargin))
1059       x+=(text_info->width-QuantumMargin-width);
1060   height=(unsigned int) (font_info->ascent+font_info->descent);
1061   y=text_info->y+((text_info->height-height) >> 1)+font_info->ascent;
1062   (void) XSetClipRectangles(display,widget_context,0,0,&crop_info,1,Unsorted);
1063   (void) XDrawString(display,window_info->id,widget_context,x,y,text_info->text,
1064     Extent(text_info->text));
1065   (void) XSetClipMask(display,widget_context,None);
1066   if (x < text_info->x)
1067     (void) XDrawLine(display,window_info->id,window_info->annotate_context,
1068       text_info->x,text_info->y,text_info->x,text_info->y+text_info->height-1);
1069 }
1070 \f
1071 /*
1072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073 %                                                                             %
1074 %                                                                             %
1075 %                                                                             %
1076 +   X E d i t T e x t                                                         %
1077 %                                                                             %
1078 %                                                                             %
1079 %                                                                             %
1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 %
1082 %  XEditText() edits a text string as indicated by the key symbol.
1083 %
1084 %  The format of the XEditText function is:
1085 %
1086 %      XEditText(display,text_info,key_symbol,text,state)
1087 %
1088 %  A description of each parameter follows:
1089 %
1090 %    o display: Specifies a connection to an X server;  returned from
1091 %      XOpenDisplay.
1092 %
1093 %    o text_info: Specifies a pointer to a XWidgetInfo structure.  It
1094 %      contains the extents of the text.
1095 %
1096 %    o key_symbol:  A X11 KeySym that indicates what editing function to
1097 %      perform to the text.
1098 %
1099 %    o text: A character string to insert into the text.
1100 %
1101 %    o state:  An size_t that indicates whether the key symbol is a
1102 %      control character or not.
1103 %
1104 */
1105 static void XEditText(Display *display,XWidgetInfo *text_info,
1106   const KeySym key_symbol,char *text,const size_t state)
1107 {
1108   switch ((int) key_symbol)
1109   {
1110     case XK_BackSpace:
1111     case XK_Delete:
1112     {
1113       if (text_info->highlight)
1114         {
1115           /*
1116             Erase the entire line of text.
1117           */
1118           *text_info->text='\0';
1119           text_info->cursor=text_info->text;
1120           text_info->marker=text_info->text;
1121           text_info->highlight=MagickFalse;
1122         }
1123       /*
1124         Erase one character.
1125       */
1126       if (text_info->cursor != text_info->text)
1127         {
1128           text_info->cursor--;
1129           (void) CopyMagickString(text_info->cursor,text_info->cursor+1,
1130             MaxTextExtent);
1131           text_info->highlight=MagickFalse;
1132           break;
1133         }
1134     }
1135     case XK_Left:
1136     case XK_KP_Left:
1137     {
1138       /*
1139         Move cursor one position left.
1140       */
1141       if (text_info->cursor == text_info->text)
1142         break;
1143       text_info->cursor--;
1144       break;
1145     }
1146     case XK_Right:
1147     case XK_KP_Right:
1148     {
1149       /*
1150         Move cursor one position right.
1151       */
1152       if (text_info->cursor == (text_info->text+Extent(text_info->text)))
1153         break;
1154       text_info->cursor++;
1155       break;
1156     }
1157     default:
1158     {
1159       register char
1160         *p,
1161         *q;
1162
1163       register int
1164         i;
1165
1166       if (state & ControlState)
1167         break;
1168       if (*text == '\0')
1169         break;
1170       if ((Extent(text_info->text)+1) >= (int) MaxTextExtent)
1171         (void) XBell(display,0);
1172       else
1173         {
1174           if (text_info->highlight)
1175             {
1176               /*
1177                 Erase the entire line of text.
1178               */
1179               *text_info->text='\0';
1180               text_info->cursor=text_info->text;
1181               text_info->marker=text_info->text;
1182               text_info->highlight=MagickFalse;
1183             }
1184           /*
1185             Insert a string into the text.
1186           */
1187           q=text_info->text+Extent(text_info->text)+strlen(text);
1188           for (i=0; i <= Extent(text_info->cursor); i++)
1189           {
1190             *q=(*(q-Extent(text)));
1191             q--;
1192           }
1193           p=text;
1194           for (i=0; i < Extent(text); i++)
1195             *text_info->cursor++=(*p++);
1196         }
1197       break;
1198     }
1199   }
1200 }
1201 \f
1202 /*
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1204 %                                                                             %
1205 %                                                                             %
1206 %                                                                             %
1207 +   X G e t W i d g e t I n f o                                               %
1208 %                                                                             %
1209 %                                                                             %
1210 %                                                                             %
1211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212 %
1213 %  XGetWidgetInfo() initializes the XWidgetInfo structure.
1214 %
1215 %  The format of the XGetWidgetInfo function is:
1216 %
1217 %      XGetWidgetInfo(text,widget_info)
1218 %
1219 %  A description of each parameter follows:
1220 %
1221 %    o text: A string of characters associated with the widget.
1222 %
1223 %    o widget_info: Specifies a pointer to a X11 XWidgetInfo structure.
1224 %
1225 */
1226 static void XGetWidgetInfo(const char *text,XWidgetInfo *widget_info)
1227 {
1228   /*
1229     Initialize widget info.
1230   */
1231   widget_info->id=(~0);
1232   widget_info->bevel_width=3;
1233   widget_info->width=1;
1234   widget_info->height=1;
1235   widget_info->x=0;
1236   widget_info->y=0;
1237   widget_info->min_y=0;
1238   widget_info->max_y=0;
1239   widget_info->raised=MagickTrue;
1240   widget_info->active=MagickFalse;
1241   widget_info->center=MagickTrue;
1242   widget_info->trough=MagickFalse;
1243   widget_info->highlight=MagickFalse;
1244   widget_info->text=(char *) text;
1245   widget_info->cursor=(char *) text;
1246   if (text != (char *) NULL)
1247     widget_info->cursor+=Extent(text);
1248   widget_info->marker=(char *) text;
1249 }
1250 \f
1251 /*
1252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1253 %                                                                             %
1254 %                                                                             %
1255 %                                                                             %
1256 +   X H i g h l i g h t W i d g e t                                           %
1257 %                                                                             %
1258 %                                                                             %
1259 %                                                                             %
1260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1261 %
1262 %  XHighlightWidget() draws a highlighted border around a window.
1263 %
1264 %  The format of the XHighlightWidget function is:
1265 %
1266 %      XHighlightWidget(display,window_info,x,y)
1267 %
1268 %  A description of each parameter follows:
1269 %
1270 %    o display: Specifies a pointer to the Display structure;  returned from
1271 %      XOpenDisplay.
1272 %
1273 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1274 %
1275 %    o x: Specifies an integer representing the rectangle offset in the
1276 %      x-direction.
1277 %
1278 %    o y: Specifies an integer representing the rectangle offset in the
1279 %      y-direction.
1280 %
1281 */
1282 static void XHighlightWidget(Display *display,const XWindowInfo *window_info,
1283   const int x,const int y)
1284 {
1285   /*
1286     Draw the widget highlighting rectangle.
1287   */
1288   XSetBevelColor(display,window_info,MagickTrue);
1289   (void) XDrawRectangle(display,window_info->id,window_info->widget_context,x,y,
1290     window_info->width-(x << 1),window_info->height-(y << 1));
1291   (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
1292     x-1,y-1,window_info->width-(x << 1)+1,window_info->height-(y << 1)+1);
1293   XSetBevelColor(display,window_info,MagickFalse);
1294   (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
1295     x-1,y-1,window_info->width-(x << 1),window_info->height-(y << 1));
1296   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
1297 }
1298 \f
1299 /*
1300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301 %                                                                             %
1302 %                                                                             %
1303 %                                                                             %
1304 +   X S c r e e n E v e n t                                                   %
1305 %                                                                             %
1306 %                                                                             %
1307 %                                                                             %
1308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 %
1310 %  XScreenEvent() returns MagickTrue if the any event on the X server queue is
1311 %  associated with the widget window.
1312 %
1313 %  The format of the XScreenEvent function is:
1314 %
1315 %      int XScreenEvent(Display *display,XEvent *event,char *data)
1316 %
1317 %  A description of each parameter follows:
1318 %
1319 %    o display: Specifies a pointer to the Display structure;  returned from
1320 %      XOpenDisplay.
1321 %
1322 %    o event: Specifies a pointer to a X11 XEvent structure.
1323 %
1324 %    o data: Specifies a pointer to a XWindows structure.
1325 %
1326 */
1327
1328 #if defined(__cplusplus) || defined(c_plusplus)
1329 extern "C" {
1330 #endif
1331
1332 static int XScreenEvent(Display *display,XEvent *event,char *data)
1333 {
1334   XWindows
1335     *windows;
1336
1337   windows=(XWindows *) data;
1338   if (event->xany.window == windows->popup.id)
1339     {
1340       if (event->type == MapNotify)
1341         windows->popup.mapped=MagickTrue;
1342       if (event->type == UnmapNotify)
1343         windows->popup.mapped=MagickFalse;
1344       return(MagickTrue);
1345     }
1346   if (event->xany.window == windows->widget.id)
1347     {
1348       if (event->type == MapNotify)
1349         windows->widget.mapped=MagickTrue;
1350       if (event->type == UnmapNotify)
1351         windows->widget.mapped=MagickFalse;
1352       return(MagickTrue);
1353     }
1354   switch (event->type)
1355   {
1356     case ButtonPress:
1357     {
1358       if ((event->xbutton.button == Button3) &&
1359           (event->xbutton.state & Mod1Mask))
1360         {
1361           /*
1362             Convert Alt-Button3 to Button2.
1363           */
1364           event->xbutton.button=Button2;
1365           event->xbutton.state&=(~Mod1Mask);
1366         }
1367       return(MagickTrue);
1368     }
1369     case Expose:
1370     {
1371       if (event->xexpose.window == windows->image.id)
1372         {
1373           XRefreshWindow(display,&windows->image,event);
1374           break;
1375         }
1376       if (event->xexpose.window == windows->magnify.id)
1377         if (event->xexpose.count == 0)
1378           if (windows->magnify.mapped)
1379             {
1380               XMakeMagnifyImage(display,windows);
1381               break;
1382             }
1383       if (event->xexpose.window == windows->command.id)
1384         if (event->xexpose.count == 0)
1385           {
1386             (void) XCommandWidget(display,windows,(const char **) NULL,event);
1387             break;
1388           }
1389       break;
1390     }
1391     case FocusOut:
1392     {
1393       /*
1394         Set input focus for backdrop window.
1395       */
1396       if (event->xfocus.window == windows->image.id)
1397         (void) XSetInputFocus(display,windows->image.id,RevertToNone,
1398           CurrentTime);
1399       return(MagickTrue);
1400     }
1401     case ButtonRelease:
1402     case KeyPress:
1403     case KeyRelease:
1404     case MotionNotify:
1405     case SelectionNotify:
1406       return(MagickTrue);
1407     default:
1408       break;
1409   }
1410   return(MagickFalse);
1411 }
1412
1413 #if defined(__cplusplus) || defined(c_plusplus)
1414 }
1415 #endif
1416 \f
1417 /*
1418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419 %                                                                             %
1420 %                                                                             %
1421 %                                                                             %
1422 +   X S e t B e v e l C o l o r                                               %
1423 %                                                                             %
1424 %                                                                             %
1425 %                                                                             %
1426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427 %
1428 %  XSetBevelColor() sets the graphic context for drawing a beveled border.
1429 %
1430 %  The format of the XSetBevelColor function is:
1431 %
1432 %      XSetBevelColor(display,window_info,raised)
1433 %
1434 %  A description of each parameter follows:
1435 %
1436 %    o display: Specifies a pointer to the Display structure;  returned from
1437 %      XOpenDisplay.
1438 %
1439 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1440 %
1441 %    o raised: A value other than zero indicates the color show be a
1442 %      "highlight" color, otherwise the "shadow" color is set.
1443 %
1444 */
1445 static void XSetBevelColor(Display *display,const XWindowInfo *window_info,
1446   const MagickStatusType raised)
1447 {
1448   if (window_info->depth == 1)
1449     {
1450       Pixmap
1451         stipple;
1452
1453       /*
1454         Monochrome window.
1455       */
1456       (void) XSetBackground(display,window_info->widget_context,
1457         XBlackPixel(display,window_info->screen));
1458       (void) XSetForeground(display,window_info->widget_context,
1459         XWhitePixel(display,window_info->screen));
1460       (void) XSetFillStyle(display,window_info->widget_context,
1461         FillOpaqueStippled);
1462       stipple=window_info->highlight_stipple;
1463       if (raised == MagickFalse)
1464         stipple=window_info->shadow_stipple;
1465       (void) XSetStipple(display,window_info->widget_context,stipple);
1466     }
1467   else
1468     if (raised)
1469       (void) XSetForeground(display,window_info->widget_context,
1470         window_info->pixel_info->highlight_color.pixel);
1471     else
1472       (void) XSetForeground(display,window_info->widget_context,
1473         window_info->pixel_info->shadow_color.pixel);
1474 }
1475 \f
1476 /*
1477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1478 %                                                                             %
1479 %                                                                             %
1480 %                                                                             %
1481 +   X S e t M a t t e C o l o r                                               %
1482 %                                                                             %
1483 %                                                                             %
1484 %                                                                             %
1485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1486 %
1487 %  XSetMatteColor() sets the graphic context for drawing the matte.
1488 %
1489 %  The format of the XSetMatteColor function is:
1490 %
1491 %      XSetMatteColor(display,window_info,raised)
1492 %
1493 %  A description of each parameter follows:
1494 %
1495 %    o display: Specifies a pointer to the Display structure;  returned from
1496 %      XOpenDisplay.
1497 %
1498 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1499 %
1500 %    o raised: A value other than zero indicates the matte is active.
1501 %
1502 */
1503 static void XSetMatteColor(Display *display,const XWindowInfo *window_info,
1504   const MagickStatusType raised)
1505 {
1506   if (window_info->depth == 1)
1507     {
1508       /*
1509         Monochrome window.
1510       */
1511       if (raised)
1512         (void) XSetForeground(display,window_info->widget_context,
1513           XWhitePixel(display,window_info->screen));
1514       else
1515         (void) XSetForeground(display,window_info->widget_context,
1516           XBlackPixel(display,window_info->screen));
1517     }
1518   else
1519     if (raised)
1520       (void) XSetForeground(display,window_info->widget_context,
1521         window_info->pixel_info->matte_color.pixel);
1522     else
1523       (void) XSetForeground(display,window_info->widget_context,
1524         window_info->pixel_info->depth_color.pixel);
1525 }
1526 \f
1527 /*
1528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1529 %                                                                             %
1530 %                                                                             %
1531 %                                                                             %
1532 +   X S e t T e x t C o l o r                                                 %
1533 %                                                                             %
1534 %                                                                             %
1535 %                                                                             %
1536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1537 %
1538 %  XSetTextColor() sets the graphic context for drawing text on a matte.
1539 %
1540 %  The format of the XSetTextColor function is:
1541 %
1542 %      XSetTextColor(display,window_info,raised)
1543 %
1544 %  A description of each parameter follows:
1545 %
1546 %    o display: Specifies a pointer to the Display structure;  returned from
1547 %      XOpenDisplay.
1548 %
1549 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1550 %
1551 %    o raised: A value other than zero indicates the color show be a
1552 %      "highlight" color, otherwise the "shadow" color is set.
1553 %
1554 */
1555 static void XSetTextColor(Display *display,const XWindowInfo *window_info,
1556   const MagickStatusType raised)
1557 {
1558   ssize_t
1559     foreground,
1560     matte;
1561
1562   if (window_info->depth == 1)
1563     {
1564       /*
1565         Monochrome window.
1566       */
1567       if (raised)
1568         (void) XSetForeground(display,window_info->widget_context,
1569           XBlackPixel(display,window_info->screen));
1570       else
1571         (void) XSetForeground(display,window_info->widget_context,
1572           XWhitePixel(display,window_info->screen));
1573       return;
1574     }
1575   foreground=(ssize_t) XPixelIntensity(
1576     &window_info->pixel_info->foreground_color);
1577   matte=(ssize_t) XPixelIntensity(&window_info->pixel_info->matte_color);
1578   if (MagickAbsoluteValue((int) (foreground-matte)) > (65535L >> 3))
1579     (void) XSetForeground(display,window_info->widget_context,
1580       window_info->pixel_info->foreground_color.pixel);
1581   else
1582     (void) XSetForeground(display,window_info->widget_context,
1583       window_info->pixel_info->background_color.pixel);
1584 }
1585 \f
1586 /*
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 %                                                                             %
1589 %                                                                             %
1590 %                                                                             %
1591 %   X C o l o r B r o w s e r W i d g e t                                     %
1592 %                                                                             %
1593 %                                                                             %
1594 %                                                                             %
1595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 %
1597 %  XColorBrowserWidget() displays a Color Browser widget with a color query
1598 %  to the user.  The user keys a reply and presses the Action or Cancel button
1599 %  to exit.  The typed text is returned as the reply function parameter.
1600 %
1601 %  The format of the XColorBrowserWidget method is:
1602 %
1603 %      void XColorBrowserWidget(Display *display,XWindows *windows,
1604 %        const char *action,char *reply)
1605 %
1606 %  A description of each parameter follows:
1607 %
1608 %    o display: Specifies a connection to an X server;  returned from
1609 %      XOpenDisplay.
1610 %
1611 %    o window: Specifies a pointer to a XWindows structure.
1612 %
1613 %    o action: Specifies a pointer to the action of this widget.
1614 %
1615 %    o reply: the response from the user is returned in this parameter.
1616 %
1617 */
1618 MagickExport void XColorBrowserWidget(Display *display,XWindows *windows,
1619   const char *action,char *reply)
1620 {
1621 #define CancelButtonText  "Cancel"
1622 #define ColornameText  "Name:"
1623 #define ColorPatternText  "Pattern:"
1624 #define GrabButtonText  "Grab"
1625 #define ResetButtonText  "Reset"
1626
1627   char
1628     **colorlist,
1629     primary_selection[MaxTextExtent],
1630     reset_pattern[MaxTextExtent],
1631     text[MaxTextExtent];
1632
1633   ExceptionInfo
1634     *exception;
1635
1636   int
1637     x,
1638     y;
1639
1640   register int
1641     i;
1642
1643   static char
1644     glob_pattern[MaxTextExtent] = "*";
1645
1646   static MagickStatusType
1647     mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
1648
1649   Status
1650     status;
1651
1652   unsigned int
1653     height,
1654     text_width,
1655     visible_colors,
1656     width;
1657
1658   size_t
1659     colors,
1660     delay,
1661     state;
1662
1663   XColor
1664     color;
1665
1666   XEvent
1667     event;
1668
1669   XFontStruct
1670     *font_info;
1671
1672   XTextProperty
1673     window_name;
1674
1675   XWidgetInfo
1676     action_info,
1677     cancel_info,
1678     expose_info,
1679     grab_info,
1680     list_info,
1681     mode_info,
1682     north_info,
1683     reply_info,
1684     reset_info,
1685     scroll_info,
1686     selection_info,
1687     slider_info,
1688     south_info,
1689     text_info;
1690
1691   XWindowChanges
1692     window_changes;
1693
1694   /*
1695     Get color list and sort in ascending order.
1696   */
1697   assert(display != (Display *) NULL);
1698   assert(windows != (XWindows *) NULL);
1699   assert(action != (char *) NULL);
1700   assert(reply != (char *) NULL);
1701   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
1702   XSetCursorState(display,windows,MagickTrue);
1703   XCheckRefreshWindows(display,windows);
1704   (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
1705   exception=AcquireExceptionInfo();
1706   colorlist=GetColorList(glob_pattern,&colors,exception);
1707   if (colorlist == (char **) NULL)
1708     {
1709       /*
1710         Pattern failed, obtain all the colors.
1711       */
1712       (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
1713       colorlist=GetColorList(glob_pattern,&colors,exception);
1714       if (colorlist == (char **) NULL)
1715         {
1716           XNoticeWidget(display,windows,"Unable to obtain colors names:",
1717             glob_pattern);
1718           (void) XDialogWidget(display,windows,action,"Enter color name:",
1719             reply);
1720           return;
1721         }
1722     }
1723   /*
1724     Determine Color Browser widget attributes.
1725   */
1726   font_info=windows->widget.font_info;
1727   text_width=0;
1728   for (i=0; i < (int) colors; i++)
1729     if (WidgetTextWidth(font_info,colorlist[i]) > text_width)
1730       text_width=WidgetTextWidth(font_info,colorlist[i]);
1731   width=WidgetTextWidth(font_info,(char *) action);
1732   if (WidgetTextWidth(font_info,CancelButtonText) > width)
1733     width=WidgetTextWidth(font_info,CancelButtonText);
1734   if (WidgetTextWidth(font_info,ResetButtonText) > width)
1735     width=WidgetTextWidth(font_info,ResetButtonText);
1736   if (WidgetTextWidth(font_info,GrabButtonText) > width)
1737     width=WidgetTextWidth(font_info,GrabButtonText);
1738   width+=QuantumMargin;
1739   if (WidgetTextWidth(font_info,ColorPatternText) > width)
1740     width=WidgetTextWidth(font_info,ColorPatternText);
1741   if (WidgetTextWidth(font_info,ColornameText) > width)
1742     width=WidgetTextWidth(font_info,ColornameText);
1743   height=(unsigned int) (font_info->ascent+font_info->descent);
1744   /*
1745     Position Color Browser widget.
1746   */
1747   windows->widget.width=(unsigned int)
1748     (width+MagickMin((int) text_width,(int) MaxTextWidth)+6*QuantumMargin);
1749   windows->widget.min_width=(unsigned int)
1750     (width+MinTextWidth+4*QuantumMargin);
1751   if (windows->widget.width < windows->widget.min_width)
1752     windows->widget.width=windows->widget.min_width;
1753   windows->widget.height=(unsigned int)
1754     ((81*height) >> 2)+((13*QuantumMargin) >> 1)+4;
1755   windows->widget.min_height=(unsigned int)
1756     (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
1757   if (windows->widget.height < windows->widget.min_height)
1758     windows->widget.height=windows->widget.min_height;
1759   XConstrainWindowPosition(display,&windows->widget);
1760   /*
1761     Map Color Browser widget.
1762   */
1763   (void) CopyMagickString(windows->widget.name,"Browse and Select a Color",
1764     MaxTextExtent);
1765   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
1766   if (status != False)
1767     {
1768       XSetWMName(display,windows->widget.id,&window_name);
1769       XSetWMIconName(display,windows->widget.id,&window_name);
1770       (void) XFree((void *) window_name.value);
1771     }
1772   window_changes.width=(int) windows->widget.width;
1773   window_changes.height=(int) windows->widget.height;
1774   window_changes.x=windows->widget.x;
1775   window_changes.y=windows->widget.y;
1776   (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
1777     mask,&window_changes);
1778   (void) XMapRaised(display,windows->widget.id);
1779   windows->widget.mapped=MagickFalse;
1780   /*
1781     Respond to X events.
1782   */
1783   XGetWidgetInfo((char *) NULL,&slider_info);
1784   XGetWidgetInfo((char *) NULL,&north_info);
1785   XGetWidgetInfo((char *) NULL,&south_info);
1786   XGetWidgetInfo((char *) NULL,&expose_info);
1787   visible_colors=0;
1788   delay=SuspendTime << 2;
1789   state=UpdateConfigurationState;
1790   do
1791   {
1792     if (state & UpdateConfigurationState)
1793       {
1794         int
1795           id;
1796
1797         /*
1798           Initialize button information.
1799         */
1800         XGetWidgetInfo(CancelButtonText,&cancel_info);
1801         cancel_info.width=width;
1802         cancel_info.height=(unsigned int) ((3*height) >> 1);
1803         cancel_info.x=(int)
1804           (windows->widget.width-cancel_info.width-QuantumMargin-2);
1805         cancel_info.y=(int)
1806           (windows->widget.height-cancel_info.height-QuantumMargin);
1807         XGetWidgetInfo(action,&action_info);
1808         action_info.width=width;
1809         action_info.height=(unsigned int) ((3*height) >> 1);
1810         action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
1811           (action_info.bevel_width << 1));
1812         action_info.y=cancel_info.y;
1813         XGetWidgetInfo(GrabButtonText,&grab_info);
1814         grab_info.width=width;
1815         grab_info.height=(unsigned int) ((3*height) >> 1);
1816         grab_info.x=QuantumMargin;
1817         grab_info.y=((5*QuantumMargin) >> 1)+height;
1818         XGetWidgetInfo(ResetButtonText,&reset_info);
1819         reset_info.width=width;
1820         reset_info.height=(unsigned int) ((3*height) >> 1);
1821         reset_info.x=QuantumMargin;
1822         reset_info.y=grab_info.y+grab_info.height+QuantumMargin;
1823         /*
1824           Initialize reply information.
1825         */
1826         XGetWidgetInfo(reply,&reply_info);
1827         reply_info.raised=MagickFalse;
1828         reply_info.bevel_width--;
1829         reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
1830         reply_info.height=height << 1;
1831         reply_info.x=(int) (width+(QuantumMargin << 1));
1832         reply_info.y=action_info.y-reply_info.height-QuantumMargin;
1833         /*
1834           Initialize mode information.
1835         */
1836         XGetWidgetInfo((char *) NULL,&mode_info);
1837         mode_info.active=MagickTrue;
1838         mode_info.bevel_width=0;
1839         mode_info.width=(unsigned int) (action_info.x-(QuantumMargin << 1));
1840         mode_info.height=action_info.height;
1841         mode_info.x=QuantumMargin;
1842         mode_info.y=action_info.y;
1843         /*
1844           Initialize scroll information.
1845         */
1846         XGetWidgetInfo((char *) NULL,&scroll_info);
1847         scroll_info.bevel_width--;
1848         scroll_info.width=height;
1849         scroll_info.height=(unsigned int) (reply_info.y-grab_info.y-
1850           (QuantumMargin >> 1));
1851         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
1852         scroll_info.y=grab_info.y-reply_info.bevel_width;
1853         scroll_info.raised=MagickFalse;
1854         scroll_info.trough=MagickTrue;
1855         north_info=scroll_info;
1856         north_info.raised=MagickTrue;
1857         north_info.width-=(north_info.bevel_width << 1);
1858         north_info.height=north_info.width-1;
1859         north_info.x+=north_info.bevel_width;
1860         north_info.y+=north_info.bevel_width;
1861         south_info=north_info;
1862         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
1863           south_info.height;
1864         id=slider_info.id;
1865         slider_info=north_info;
1866         slider_info.id=id;
1867         slider_info.width-=2;
1868         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
1869           slider_info.bevel_width+2;
1870         slider_info.height=scroll_info.height-((slider_info.min_y-
1871           scroll_info.y+1) << 1)+4;
1872         visible_colors=scroll_info.height/(height+(height >> 3));
1873         if (colors > visible_colors)
1874           slider_info.height=(unsigned int)
1875             ((visible_colors*slider_info.height)/colors);
1876         slider_info.max_y=south_info.y-south_info.bevel_width-
1877           slider_info.bevel_width-2;
1878         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
1879         slider_info.y=slider_info.min_y;
1880         expose_info=scroll_info;
1881         expose_info.y=slider_info.y;
1882         /*
1883           Initialize list information.
1884         */
1885         XGetWidgetInfo((char *) NULL,&list_info);
1886         list_info.raised=MagickFalse;
1887         list_info.bevel_width--;
1888         list_info.width=(unsigned int)
1889           (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
1890         list_info.height=scroll_info.height;
1891         list_info.x=reply_info.x;
1892         list_info.y=scroll_info.y;
1893         if (windows->widget.mapped == MagickFalse)
1894           state|=JumpListState;
1895         /*
1896           Initialize text information.
1897         */
1898         *text='\0';
1899         XGetWidgetInfo(text,&text_info);
1900         text_info.center=MagickFalse;
1901         text_info.width=reply_info.width;
1902         text_info.height=height;
1903         text_info.x=list_info.x-(QuantumMargin >> 1);
1904         text_info.y=QuantumMargin;
1905         /*
1906           Initialize selection information.
1907         */
1908         XGetWidgetInfo((char *) NULL,&selection_info);
1909         selection_info.center=MagickFalse;
1910         selection_info.width=list_info.width;
1911         selection_info.height=(unsigned int) ((9*height) >> 3);
1912         selection_info.x=list_info.x;
1913         state&=(~UpdateConfigurationState);
1914       }
1915     if (state & RedrawWidgetState)
1916       {
1917         /*
1918           Redraw Color Browser window.
1919         */
1920         x=QuantumMargin;
1921         y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
1922         (void) XDrawString(display,windows->widget.id,
1923           windows->widget.annotate_context,x,y,ColorPatternText,
1924           Extent(ColorPatternText));
1925         (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
1926         XDrawWidgetText(display,&windows->widget,&text_info);
1927         XDrawBeveledButton(display,&windows->widget,&grab_info);
1928         XDrawBeveledButton(display,&windows->widget,&reset_info);
1929         XDrawBeveledMatte(display,&windows->widget,&list_info);
1930         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
1931         XDrawTriangleNorth(display,&windows->widget,&north_info);
1932         XDrawBeveledButton(display,&windows->widget,&slider_info);
1933         XDrawTriangleSouth(display,&windows->widget,&south_info);
1934         x=QuantumMargin;
1935         y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
1936         (void) XDrawString(display,windows->widget.id,
1937           windows->widget.annotate_context,x,y,ColornameText,
1938           Extent(ColornameText));
1939         XDrawBeveledMatte(display,&windows->widget,&reply_info);
1940         XDrawMatteText(display,&windows->widget,&reply_info);
1941         XDrawBeveledButton(display,&windows->widget,&action_info);
1942         XDrawBeveledButton(display,&windows->widget,&cancel_info);
1943         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
1944         selection_info.id=(~0);
1945         state|=RedrawActionState;
1946         state|=RedrawListState;
1947         state&=(~RedrawWidgetState);
1948       }
1949     if (state & UpdateListState)
1950       {
1951         char
1952           **checklist;
1953
1954         size_t
1955           number_colors;
1956
1957         status=XParseColor(display,windows->widget.map_info->colormap,
1958           glob_pattern,&color);
1959         if ((status != False) || (strchr(glob_pattern,'-') != (char *) NULL))
1960           {
1961             /*
1962               Reply is a single color name-- exit.
1963             */
1964             (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
1965             (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
1966             action_info.raised=MagickFalse;
1967             XDrawBeveledButton(display,&windows->widget,&action_info);
1968             break;
1969           }
1970         /*
1971           Update color list.
1972         */
1973         checklist=GetColorList(glob_pattern,&number_colors,exception);
1974         if (number_colors == 0)
1975           {
1976             (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
1977             (void) XBell(display,0);
1978           }
1979         else
1980           {
1981             for (i=0; i < (int) colors; i++)
1982               colorlist[i]=DestroyString(colorlist[i]);
1983             if (colorlist != (char **) NULL)
1984               colorlist=(char **) RelinquishMagickMemory(colorlist);
1985             colorlist=checklist;
1986             colors=number_colors;
1987           }
1988         /*
1989           Sort color list in ascending order.
1990         */
1991         slider_info.height=
1992           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
1993         if (colors > visible_colors)
1994           slider_info.height=(unsigned int)
1995             ((visible_colors*slider_info.height)/colors);
1996         slider_info.max_y=south_info.y-south_info.bevel_width-
1997           slider_info.bevel_width-2;
1998         slider_info.id=0;
1999         slider_info.y=slider_info.min_y;
2000         expose_info.y=slider_info.y;
2001         selection_info.id=(~0);
2002         list_info.id=(~0);
2003         state|=RedrawListState;
2004         /*
2005           Redraw color name & reply.
2006         */
2007         *reply_info.text='\0';
2008         reply_info.cursor=reply_info.text;
2009         (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
2010         XDrawWidgetText(display,&windows->widget,&text_info);
2011         XDrawMatteText(display,&windows->widget,&reply_info);
2012         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
2013         XDrawTriangleNorth(display,&windows->widget,&north_info);
2014         XDrawBeveledButton(display,&windows->widget,&slider_info);
2015         XDrawTriangleSouth(display,&windows->widget,&south_info);
2016         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
2017         state&=(~UpdateListState);
2018       }
2019     if (state & JumpListState)
2020       {
2021         /*
2022           Jump scroll to match user color.
2023         */
2024         list_info.id=(~0);
2025         for (i=0; i < (int) colors; i++)
2026           if (LocaleCompare(colorlist[i],reply) >= 0)
2027             {
2028               list_info.id=LocaleCompare(colorlist[i],reply) == 0 ? i : ~0;
2029               break;
2030             }
2031         if ((i < slider_info.id) ||
2032             (i >= (int) (slider_info.id+visible_colors)))
2033           slider_info.id=i-(visible_colors >> 1);
2034         selection_info.id=(~0);
2035         state|=RedrawListState;
2036         state&=(~JumpListState);
2037       }
2038     if (state & RedrawListState)
2039       {
2040         /*
2041           Determine slider id and position.
2042         */
2043         if (slider_info.id >= (int) (colors-visible_colors))
2044           slider_info.id=(int) (colors-visible_colors);
2045         if ((slider_info.id < 0) || (colors <= visible_colors))
2046           slider_info.id=0;
2047         slider_info.y=slider_info.min_y;
2048         if (colors != 0)
2049           slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
2050             slider_info.min_y+1)/colors);
2051         if (slider_info.id != selection_info.id)
2052           {
2053             /*
2054               Redraw scroll bar and file names.
2055             */
2056             selection_info.id=slider_info.id;
2057             selection_info.y=list_info.y+(height >> 3)+2;
2058             for (i=0; i < (int) visible_colors; i++)
2059             {
2060               selection_info.raised=(slider_info.id+i) != list_info.id ?
2061                 MagickTrue : MagickFalse;
2062               selection_info.text=(char *) NULL;
2063               if ((slider_info.id+i) < (int) colors)
2064                 selection_info.text=colorlist[slider_info.id+i];
2065               XDrawWidgetText(display,&windows->widget,&selection_info);
2066               selection_info.y+=(int) selection_info.height;
2067             }
2068             /*
2069               Update slider.
2070             */
2071             if (slider_info.y > expose_info.y)
2072               {
2073                 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
2074                 expose_info.y=slider_info.y-expose_info.height-
2075                   slider_info.bevel_width-1;
2076               }
2077             else
2078               {
2079                 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
2080                 expose_info.y=slider_info.y+slider_info.height+
2081                   slider_info.bevel_width+1;
2082               }
2083             XDrawTriangleNorth(display,&windows->widget,&north_info);
2084             XDrawMatte(display,&windows->widget,&expose_info);
2085             XDrawBeveledButton(display,&windows->widget,&slider_info);
2086             XDrawTriangleSouth(display,&windows->widget,&south_info);
2087             expose_info.y=slider_info.y;
2088           }
2089         state&=(~RedrawListState);
2090       }
2091     if (state & RedrawActionState)
2092       {
2093         static char
2094           colorname[MaxTextExtent];
2095
2096         /*
2097           Display the selected color in a drawing area.
2098         */
2099         color=windows->widget.pixel_info->matte_color;
2100         (void) XParseColor(display,windows->widget.map_info->colormap,
2101           reply_info.text,&windows->widget.pixel_info->matte_color);
2102         XBestPixel(display,windows->widget.map_info->colormap,(XColor *) NULL,
2103           (unsigned int) windows->widget.visual_info->colormap_size,
2104           &windows->widget.pixel_info->matte_color);
2105         mode_info.text=colorname;
2106         (void) FormatMagickString(mode_info.text,MaxTextExtent,"#%02x%02x%02x",
2107           windows->widget.pixel_info->matte_color.red,
2108           windows->widget.pixel_info->matte_color.green,
2109           windows->widget.pixel_info->matte_color.blue);
2110         XDrawBeveledButton(display,&windows->widget,&mode_info);
2111         windows->widget.pixel_info->matte_color=color;
2112         state&=(~RedrawActionState);
2113       }
2114     /*
2115       Wait for next event.
2116     */
2117     if (north_info.raised && south_info.raised)
2118       (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
2119     else
2120       {
2121         /*
2122           Brief delay before advancing scroll bar.
2123         */
2124         XDelay(display,delay);
2125         delay=SuspendTime;
2126         (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
2127         if (north_info.raised == MagickFalse)
2128           if (slider_info.id > 0)
2129             {
2130               /*
2131                 Move slider up.
2132               */
2133               slider_info.id--;
2134               state|=RedrawListState;
2135             }
2136         if (south_info.raised == MagickFalse)
2137           if (slider_info.id < (int) colors)
2138             {
2139               /*
2140                 Move slider down.
2141               */
2142               slider_info.id++;
2143               state|=RedrawListState;
2144             }
2145         if (event.type != ButtonRelease)
2146           continue;
2147       }
2148     switch (event.type)
2149     {
2150       case ButtonPress:
2151       {
2152         if (MatteIsActive(slider_info,event.xbutton))
2153           {
2154             /*
2155               Track slider.
2156             */
2157             slider_info.active=MagickTrue;
2158             break;
2159           }
2160         if (MatteIsActive(north_info,event.xbutton))
2161           if (slider_info.id > 0)
2162             {
2163               /*
2164                 Move slider up.
2165               */
2166               north_info.raised=MagickFalse;
2167               slider_info.id--;
2168               state|=RedrawListState;
2169               break;
2170             }
2171         if (MatteIsActive(south_info,event.xbutton))
2172           if (slider_info.id < (int) colors)
2173             {
2174               /*
2175                 Move slider down.
2176               */
2177               south_info.raised=MagickFalse;
2178               slider_info.id++;
2179               state|=RedrawListState;
2180               break;
2181             }
2182         if (MatteIsActive(scroll_info,event.xbutton))
2183           {
2184             /*
2185               Move slider.
2186             */
2187             if (event.xbutton.y < slider_info.y)
2188               slider_info.id-=(visible_colors-1);
2189             else
2190               slider_info.id+=(visible_colors-1);
2191             state|=RedrawListState;
2192             break;
2193           }
2194         if (MatteIsActive(list_info,event.xbutton))
2195           {
2196             int
2197               id;
2198
2199             /*
2200               User pressed list matte.
2201             */
2202             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
2203               selection_info.height;
2204             if (id >= (int) colors)
2205               break;
2206             (void) CopyMagickString(reply_info.text,colorlist[id],
2207               MaxTextExtent);
2208             reply_info.highlight=MagickFalse;
2209             reply_info.marker=reply_info.text;
2210             reply_info.cursor=reply_info.text+Extent(reply_info.text);
2211             XDrawMatteText(display,&windows->widget,&reply_info);
2212             state|=RedrawActionState;
2213             if (id == list_info.id)
2214               {
2215                 (void) CopyMagickString(glob_pattern,reply_info.text,
2216                   MaxTextExtent);
2217                 state|=UpdateListState;
2218               }
2219             selection_info.id=(~0);
2220             list_info.id=id;
2221             state|=RedrawListState;
2222             break;
2223           }
2224         if (MatteIsActive(grab_info,event.xbutton))
2225           {
2226             /*
2227               User pressed Grab button.
2228             */
2229             grab_info.raised=MagickFalse;
2230             XDrawBeveledButton(display,&windows->widget,&grab_info);
2231             break;
2232           }
2233         if (MatteIsActive(reset_info,event.xbutton))
2234           {
2235             /*
2236               User pressed Reset button.
2237             */
2238             reset_info.raised=MagickFalse;
2239             XDrawBeveledButton(display,&windows->widget,&reset_info);
2240             break;
2241           }
2242         if (MatteIsActive(mode_info,event.xbutton))
2243           {
2244             /*
2245               User pressed mode button.
2246             */
2247             (void) CopyMagickString(reply_info.text,mode_info.text,
2248               MaxTextExtent);
2249             (void) CopyMagickString(primary_selection,reply_info.text,
2250               MaxTextExtent);
2251             (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
2252               event.xbutton.time);
2253             reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
2254               windows->widget.id ? MagickTrue : MagickFalse;
2255             reply_info.marker=reply_info.text;
2256             reply_info.cursor=reply_info.text+Extent(reply_info.text);
2257             XDrawMatteText(display,&windows->widget,&reply_info);
2258             break;
2259           }
2260         if (MatteIsActive(action_info,event.xbutton))
2261           {
2262             /*
2263               User pressed action button.
2264             */
2265             action_info.raised=MagickFalse;
2266             XDrawBeveledButton(display,&windows->widget,&action_info);
2267             break;
2268           }
2269         if (MatteIsActive(cancel_info,event.xbutton))
2270           {
2271             /*
2272               User pressed Cancel button.
2273             */
2274             cancel_info.raised=MagickFalse;
2275             XDrawBeveledButton(display,&windows->widget,&cancel_info);
2276             break;
2277           }
2278         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
2279           break;
2280         if (event.xbutton.button != Button2)
2281           {
2282             static Time
2283               click_time;
2284
2285             /*
2286               Move text cursor to position of button press.
2287             */
2288             x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
2289             for (i=1; i <= Extent(reply_info.marker); i++)
2290               if (XTextWidth(font_info,reply_info.marker,i) > x)
2291                 break;
2292             reply_info.cursor=reply_info.marker+i-1;
2293             if (event.xbutton.time > (click_time+DoubleClick))
2294               reply_info.highlight=MagickFalse;
2295             else
2296               {
2297                 /*
2298                   Become the XA_PRIMARY selection owner.
2299                 */
2300                 (void) CopyMagickString(primary_selection,reply_info.text,
2301                   MaxTextExtent);
2302                 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
2303                   event.xbutton.time);
2304                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
2305                   windows->widget.id ? MagickTrue : MagickFalse;
2306               }
2307             XDrawMatteText(display,&windows->widget,&reply_info);
2308             click_time=event.xbutton.time;
2309             break;
2310           }
2311         /*
2312           Request primary selection.
2313         */
2314         (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2315           windows->widget.id,event.xbutton.time);
2316         break;
2317       }
2318       case ButtonRelease:
2319       {
2320         if (windows->widget.mapped == MagickFalse)
2321           break;
2322         if (north_info.raised == MagickFalse)
2323           {
2324             /*
2325               User released up button.
2326             */
2327             delay=SuspendTime << 2;
2328             north_info.raised=MagickTrue;
2329             XDrawTriangleNorth(display,&windows->widget,&north_info);
2330           }
2331         if (south_info.raised == MagickFalse)
2332           {
2333             /*
2334               User released down button.
2335             */
2336             delay=SuspendTime << 2;
2337             south_info.raised=MagickTrue;
2338             XDrawTriangleSouth(display,&windows->widget,&south_info);
2339           }
2340         if (slider_info.active)
2341           {
2342             /*
2343               Stop tracking slider.
2344             */
2345             slider_info.active=MagickFalse;
2346             break;
2347           }
2348         if (grab_info.raised == MagickFalse)
2349           {
2350             if (event.xbutton.window == windows->widget.id)
2351               if (MatteIsActive(grab_info,event.xbutton))
2352                 {
2353                   /*
2354                     Select a pen color from the X server.
2355                   */
2356                   (void) XGetWindowColor(display,windows,reply_info.text);
2357                   reply_info.marker=reply_info.text;
2358                   reply_info.cursor=reply_info.text+Extent(reply_info.text);
2359                   XDrawMatteText(display,&windows->widget,&reply_info);
2360                   state|=RedrawActionState;
2361                 }
2362             grab_info.raised=MagickTrue;
2363             XDrawBeveledButton(display,&windows->widget,&grab_info);
2364           }
2365         if (reset_info.raised == MagickFalse)
2366           {
2367             if (event.xbutton.window == windows->widget.id)
2368               if (MatteIsActive(reset_info,event.xbutton))
2369                 {
2370                   (void) CopyMagickString(glob_pattern,reset_pattern,
2371                     MaxTextExtent);
2372                   state|=UpdateListState;
2373                 }
2374             reset_info.raised=MagickTrue;
2375             XDrawBeveledButton(display,&windows->widget,&reset_info);
2376           }
2377         if (action_info.raised == MagickFalse)
2378           {
2379             if (event.xbutton.window == windows->widget.id)
2380               {
2381                 if (MatteIsActive(action_info,event.xbutton))
2382                   {
2383                     if (*reply_info.text == '\0')
2384                       (void) XBell(display,0);
2385                     else
2386                       state|=ExitState;
2387                   }
2388               }
2389             action_info.raised=MagickTrue;
2390             XDrawBeveledButton(display,&windows->widget,&action_info);
2391           }
2392         if (cancel_info.raised == MagickFalse)
2393           {
2394             if (event.xbutton.window == windows->widget.id)
2395               if (MatteIsActive(cancel_info,event.xbutton))
2396                 {
2397                   *reply_info.text='\0';
2398                   state|=ExitState;
2399                 }
2400             cancel_info.raised=MagickTrue;
2401             XDrawBeveledButton(display,&windows->widget,&cancel_info);
2402           }
2403         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
2404           break;
2405         break;
2406       }
2407       case ClientMessage:
2408       {
2409         /*
2410           If client window delete message, exit.
2411         */
2412         if (event.xclient.message_type != windows->wm_protocols)
2413           break;
2414         if (*event.xclient.data.l == (int) windows->wm_take_focus)
2415           {
2416             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2417               (Time) event.xclient.data.l[1]);
2418             break;
2419           }
2420         if (*event.xclient.data.l != (int) windows->wm_delete_window)
2421           break;
2422         if (event.xclient.window == windows->widget.id)
2423           {
2424             *reply_info.text='\0';
2425             state|=ExitState;
2426             break;
2427           }
2428         break;
2429       }
2430       case ConfigureNotify:
2431       {
2432         /*
2433           Update widget configuration.
2434         */
2435         if (event.xconfigure.window != windows->widget.id)
2436           break;
2437         if ((event.xconfigure.width == (int) windows->widget.width) &&
2438             (event.xconfigure.height == (int) windows->widget.height))
2439           break;
2440         windows->widget.width=(unsigned int)
2441           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
2442         windows->widget.height=(unsigned int)
2443           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
2444         state|=UpdateConfigurationState;
2445         break;
2446       }
2447       case EnterNotify:
2448       {
2449         if (event.xcrossing.window != windows->widget.id)
2450           break;
2451         state&=(~InactiveWidgetState);
2452         break;
2453       }
2454       case Expose:
2455       {
2456         if (event.xexpose.window != windows->widget.id)
2457           break;
2458         if (event.xexpose.count != 0)
2459           break;
2460         state|=RedrawWidgetState;
2461         break;
2462       }
2463       case KeyPress:
2464       {
2465         static char
2466           command[MaxTextExtent];
2467
2468         static int
2469           length;
2470
2471         static KeySym
2472           key_symbol;
2473
2474         /*
2475           Respond to a user key press.
2476         */
2477         if (event.xkey.window != windows->widget.id)
2478           break;
2479         length=XLookupString((XKeyEvent *) &event.xkey,command,
2480           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2481         *(command+length)='\0';
2482         if (AreaIsActive(scroll_info,event.xkey))
2483           {
2484             /*
2485               Move slider.
2486             */
2487             switch ((int) key_symbol)
2488             {
2489               case XK_Home:
2490               case XK_KP_Home:
2491               {
2492                 slider_info.id=0;
2493                 break;
2494               }
2495               case XK_Up:
2496               case XK_KP_Up:
2497               {
2498                 slider_info.id--;
2499                 break;
2500               }
2501               case XK_Down:
2502               case XK_KP_Down:
2503               {
2504                 slider_info.id++;
2505                 break;
2506               }
2507               case XK_Prior:
2508               case XK_KP_Prior:
2509               {
2510                 slider_info.id-=visible_colors;
2511                 break;
2512               }
2513               case XK_Next:
2514               case XK_KP_Next:
2515               {
2516                 slider_info.id+=visible_colors;
2517                 break;
2518               }
2519               case XK_End:
2520               case XK_KP_End:
2521               {
2522                 slider_info.id=(int) colors;
2523                 break;
2524               }
2525             }
2526             state|=RedrawListState;
2527             break;
2528           }
2529         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
2530           {
2531             /*
2532               Read new color or glob patterm.
2533             */
2534             if (*reply_info.text == '\0')
2535               break;
2536             (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
2537             state|=UpdateListState;
2538             break;
2539           }
2540         if (key_symbol == XK_Control_L)
2541           {
2542             state|=ControlState;
2543             break;
2544           }
2545         if (state & ControlState)
2546           switch ((int) key_symbol)
2547           {
2548             case XK_u:
2549             case XK_U:
2550             {
2551               /*
2552                 Erase the entire line of text.
2553               */
2554               *reply_info.text='\0';
2555               reply_info.cursor=reply_info.text;
2556               reply_info.marker=reply_info.text;
2557               reply_info.highlight=MagickFalse;
2558               break;
2559             }
2560             default:
2561               break;
2562           }
2563         XEditText(display,&reply_info,key_symbol,command,state);
2564         XDrawMatteText(display,&windows->widget,&reply_info);
2565         state|=JumpListState;
2566         status=XParseColor(display,windows->widget.map_info->colormap,
2567           reply_info.text,&color);
2568         if (status != False)
2569           state|=RedrawActionState;
2570         break;
2571       }
2572       case KeyRelease:
2573       {
2574         static char
2575           command[MaxTextExtent];
2576
2577         static KeySym
2578           key_symbol;
2579
2580         /*
2581           Respond to a user key release.
2582         */
2583         if (event.xkey.window != windows->widget.id)
2584           break;
2585         (void) XLookupString((XKeyEvent *) &event.xkey,command,
2586           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2587         if (key_symbol == XK_Control_L)
2588           state&=(~ControlState);
2589         break;
2590       }
2591       case LeaveNotify:
2592       {
2593         if (event.xcrossing.window != windows->widget.id)
2594           break;
2595         state|=InactiveWidgetState;
2596         break;
2597       }
2598       case MapNotify:
2599       {
2600         mask&=(~CWX);
2601         mask&=(~CWY);
2602         break;
2603       }
2604       case MotionNotify:
2605       {
2606         /*
2607           Discard pending button motion events.
2608         */
2609         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
2610         if (slider_info.active)
2611           {
2612             /*
2613               Move slider matte.
2614             */
2615             slider_info.y=event.xmotion.y-
2616               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
2617             if (slider_info.y < slider_info.min_y)
2618               slider_info.y=slider_info.min_y;
2619             if (slider_info.y > slider_info.max_y)
2620               slider_info.y=slider_info.max_y;
2621             slider_info.id=0;
2622             if (slider_info.y != slider_info.min_y)
2623               slider_info.id=(int) ((colors*(slider_info.y-
2624                 slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
2625             state|=RedrawListState;
2626             break;
2627           }
2628         if (state & InactiveWidgetState)
2629           break;
2630         if (grab_info.raised == MatteIsActive(grab_info,event.xmotion))
2631           {
2632             /*
2633               Grab button status changed.
2634             */
2635             grab_info.raised=!grab_info.raised;
2636             XDrawBeveledButton(display,&windows->widget,&grab_info);
2637             break;
2638           }
2639         if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
2640           {
2641             /*
2642               Reset button status changed.
2643             */
2644             reset_info.raised=!reset_info.raised;
2645             XDrawBeveledButton(display,&windows->widget,&reset_info);
2646             break;
2647           }
2648         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
2649           {
2650             /*
2651               Action button status changed.
2652             */
2653             action_info.raised=action_info.raised == MagickFalse ?
2654               MagickTrue : MagickFalse;
2655             XDrawBeveledButton(display,&windows->widget,&action_info);
2656             break;
2657           }
2658         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
2659           {
2660             /*
2661               Cancel button status changed.
2662             */
2663             cancel_info.raised=cancel_info.raised == MagickFalse ?
2664               MagickTrue : MagickFalse;
2665             XDrawBeveledButton(display,&windows->widget,&cancel_info);
2666             break;
2667           }
2668         break;
2669       }
2670       case SelectionClear:
2671       {
2672         reply_info.highlight=MagickFalse;
2673         XDrawMatteText(display,&windows->widget,&reply_info);
2674         break;
2675       }
2676       case SelectionNotify:
2677       {
2678         Atom
2679           type;
2680
2681         int
2682           format;
2683
2684         unsigned char
2685           *data;
2686
2687         unsigned long
2688           after,
2689           length;
2690
2691         /*
2692           Obtain response from primary selection.
2693         */
2694         if (event.xselection.property == (Atom) None)
2695           break;
2696         status=XGetWindowProperty(display,event.xselection.requestor,
2697           event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
2698           &format,&length,&after,&data);
2699         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2700             (length == 0))
2701           break;
2702         if ((Extent(reply_info.text)+length) >= MaxTextExtent)
2703           (void) XBell(display,0);
2704         else
2705           {
2706             /*
2707               Insert primary selection in reply text.
2708             */
2709             *(data+length)='\0';
2710             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
2711               state);
2712             XDrawMatteText(display,&windows->widget,&reply_info);
2713             state|=JumpListState;
2714             state|=RedrawActionState;
2715           }
2716         (void) XFree((void *) data);
2717         break;
2718       }
2719       case SelectionRequest:
2720       {
2721         XSelectionEvent
2722           notify;
2723
2724         XSelectionRequestEvent
2725           *request;
2726
2727         if (reply_info.highlight == MagickFalse)
2728           break;
2729         /*
2730           Set primary selection.
2731         */
2732         request=(&(event.xselectionrequest));
2733         (void) XChangeProperty(request->display,request->requestor,
2734           request->property,request->target,8,PropModeReplace,
2735           (unsigned char *) primary_selection,Extent(primary_selection));
2736         notify.type=SelectionNotify;
2737         notify.send_event=MagickTrue;
2738         notify.display=request->display;
2739         notify.requestor=request->requestor;
2740         notify.selection=request->selection;
2741         notify.target=request->target;
2742         notify.time=request->time;
2743         if (request->property == None)
2744           notify.property=request->target;
2745         else
2746           notify.property=request->property;
2747         (void) XSendEvent(request->display,request->requestor,False,
2748           NoEventMask,(XEvent *) &notify);
2749       }
2750       default:
2751         break;
2752     }
2753   } while ((state & ExitState) == 0);
2754   XSetCursorState(display,windows,MagickFalse);
2755   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
2756   XCheckRefreshWindows(display,windows);
2757   /*
2758     Free color list.
2759   */
2760   for (i=0; i < (int) colors; i++)
2761     colorlist[i]=DestroyString(colorlist[i]);
2762   if (colorlist != (char **) NULL)
2763     colorlist=(char **) RelinquishMagickMemory(colorlist);
2764   exception=DestroyExceptionInfo(exception);
2765   if ((*reply == '\0') || (strchr(reply,'-') != (char *) NULL))
2766     return;
2767   status=XParseColor(display,windows->widget.map_info->colormap,reply,&color);
2768   if (status != False)
2769     return;
2770   XNoticeWidget(display,windows,"Color is unknown to X server:",reply);
2771   (void) CopyMagickString(reply,"gray",MaxTextExtent);
2772 }
2773 \f
2774 /*
2775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776 %                                                                             %
2777 %                                                                             %
2778 %                                                                             %
2779 %   X C o m m a n d W i d g e t                                               %
2780 %                                                                             %
2781 %                                                                             %
2782 %                                                                             %
2783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784 %
2785 %  XCommandWidget() maps a menu and returns the command pointed to by the user
2786 %  when the button is released.
2787 %
2788 %  The format of the XCommandWidget method is:
2789 %
2790 %      int XCommandWidget(Display *display,XWindows *windows,
2791 %        const char **selections,XEvent *event)
2792 %
2793 %  A description of each parameter follows:
2794 %
2795 %    o selection_number: Specifies the number of the selection that the
2796 %      user choose.
2797 %
2798 %    o display: Specifies a connection to an X server;  returned from
2799 %      XOpenDisplay.
2800 %
2801 %    o window: Specifies a pointer to a XWindows structure.
2802 %
2803 %    o selections: Specifies a pointer to one or more strings that comprise
2804 %      the choices in the menu.
2805 %
2806 %    o event: Specifies a pointer to a X11 XEvent structure.
2807 %
2808 */
2809 MagickExport int XCommandWidget(Display *display,XWindows *windows,
2810   const char **selections,XEvent *event)
2811 {
2812 #define tile_width 112
2813 #define tile_height 70
2814
2815   static const unsigned char
2816     tile_bits[]=
2817     {
2818       0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2819       0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2820       0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2821       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
2822       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
2823       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
2824       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2825       0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2826       0x00, 0x00, 0x1e, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2827       0x00, 0x00, 0x00, 0x00, 0x1e, 0xbc, 0x9f, 0x03, 0x00, 0x3e, 0x00, 0xc0,
2828       0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x0f, 0x80, 0x3f,
2829       0x00, 0xf0, 0x1f, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x1f,
2830       0xe0, 0x3f, 0x00, 0xfc, 0x1f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc,
2831       0xff, 0x1f, 0xf0, 0x3f, 0x00, 0xfe, 0x1f, 0xf8, 0x0f, 0x00, 0x00, 0x00,
2832       0x1e, 0xfc, 0xfc, 0x3f, 0xf8, 0x3f, 0x00, 0xff, 0x1e, 0xfc, 0x0f, 0x00,
2833       0x00, 0x00, 0x1e, 0x7c, 0xfc, 0x3e, 0xf8, 0x3c, 0x80, 0x1f, 0x1e, 0x7c,
2834       0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, 0xc0, 0x0f,
2835       0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c,
2836       0xc0, 0x07, 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c,
2837       0x7c, 0x7c, 0xc0, 0x0f, 0x1e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x78,
2838       0x78, 0x3c, 0xfc, 0x7c, 0x80, 0x7f, 0x1e, 0x7c, 0x00, 0x00, 0x00, 0x00,
2839       0x1e, 0xf8, 0x78, 0x7c, 0xf8, 0xff, 0x00, 0xff, 0x1f, 0xf8, 0xff, 0x00,
2840       0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xfe, 0x1f, 0xf8,
2841       0xff, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xf8,
2842       0x1f, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xc0, 0xef,
2843       0x07, 0xe0, 0x1f, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0x70, 0x40, 0x78,
2844       0x00, 0xc7, 0x07, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00,
2845       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
2846       0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
2847       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
2848       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
2849       0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2850       0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2851       0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2852       0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
2853       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00,
2854       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
2855       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
2856       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2857       0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x02, 0x00,
2858       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
2859       0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2860       0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2861       0x60, 0x00, 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2862       0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
2863       0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00,
2864       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0x9f, 0x7f, 0x00,
2865       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0xdf,
2866       0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x00,
2867       0xe0, 0xdf, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0c,
2868       0x78, 0x30, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
2869       0x00, 0x0f, 0xf8, 0x70, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x1f, 0x00, 0xe0,
2870       0x0f, 0x1e, 0x80, 0x0f, 0xf8, 0x78, 0xf0, 0xfd, 0xf9, 0x00, 0xc0, 0x1f,
2871       0x00, 0xf8, 0x0f, 0x00, 0xe0, 0x1f, 0xf8, 0x7c, 0xf0, 0xfc, 0xf9, 0x00,
2872       0xf0, 0x1f, 0x00, 0xfe, 0x0f, 0x00, 0xf0, 0x07, 0xf8, 0x3e, 0xf8, 0xfc,
2873       0xf0, 0x01, 0xf8, 0x1f, 0x00, 0xff, 0x0f, 0x1e, 0xf0, 0x03, 0xf8, 0x3f,
2874       0xf8, 0xf8, 0xf0, 0x01, 0xfc, 0x1f, 0x80, 0x7f, 0x0f, 0x1e, 0xf8, 0x00,
2875       0xf8, 0x1f, 0x78, 0x18, 0xf0, 0x01, 0x7c, 0x1e, 0xc0, 0x0f, 0x0f, 0x1e,
2876       0x7c, 0x00, 0xf0, 0x0f, 0x78, 0x00, 0xf0, 0x01, 0x3e, 0x1e, 0xe0, 0x07,
2877       0x0f, 0x1e, 0x7c, 0x00, 0xf0, 0x07, 0x7c, 0x00, 0xe0, 0x01, 0x3e, 0x1e,
2878       0xe0, 0x03, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x0f, 0x7c, 0x00, 0xe0, 0x03,
2879       0x3e, 0x3e, 0xe0, 0x07, 0x0f, 0x1e, 0x1e, 0x00, 0xf0, 0x1f, 0x3c, 0x00,
2880       0xe0, 0x03, 0x7e, 0x3e, 0xc0, 0x3f, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x1f,
2881       0x3e, 0x00, 0xe0, 0x03, 0xfc, 0x7f, 0x80, 0xff, 0x0f, 0x1e, 0xfc, 0x00,
2882       0xf0, 0x3e, 0x3e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xff, 0x0f, 0x1e,
2883       0xfc, 0x07, 0xf0, 0x7c, 0x1e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xfc,
2884       0x0f, 0x1e, 0xf8, 0x1f, 0xf0, 0xf8, 0x1e, 0x00, 0xc0, 0x03, 0xe0, 0xf7,
2885       0x03, 0xf0, 0x0f, 0x1e, 0xe0, 0x3f, 0xf0, 0x78, 0x1c, 0x00, 0x80, 0x03,
2886       0x80, 0xe3, 0x03, 0x00, 0x0f, 0x1e, 0xc0, 0x3f, 0xf0, 0x30, 0x00, 0x00,
2887       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0x3e, 0x00, 0x00,
2888       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x10,
2889       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
2890       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
2891       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2892       0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2893       0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2894       0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2895       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
2896       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
2897       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
2898       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2899       0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2900     };
2901
2902   int
2903     id,
2904     y;
2905
2906   register int
2907     i;
2908
2909   static unsigned int
2910     number_selections;
2911
2912   unsigned int
2913     height;
2914
2915   size_t
2916     state;
2917
2918   XFontStruct
2919     *font_info;
2920
2921   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2922   assert(display != (Display *) NULL);
2923   assert(windows != (XWindows *) NULL);
2924   font_info=windows->command.font_info;
2925   height=(unsigned int) (font_info->ascent+font_info->descent);
2926   id=(~0);
2927   state=DefaultState;
2928   if (event == (XEvent *) NULL)
2929     {
2930       unsigned int
2931         width;
2932
2933       XTextProperty
2934         window_name;
2935
2936       XWindowChanges
2937         window_changes;
2938
2939       /*
2940         Determine command window attributes.
2941       */
2942       assert(selections != (const char **) NULL);
2943       windows->command.width=0;
2944       for (i=0; selections[i] != (char *) NULL; i++)
2945       {
2946         width=WidgetTextWidth(font_info,(char *) selections[i]);
2947         if (width > windows->command.width)
2948           windows->command.width=width;
2949       }
2950       number_selections=(unsigned int) i;
2951       windows->command.width+=3*QuantumMargin+10;
2952       if ((int) windows->command.width < (tile_width+QuantumMargin+10))
2953         windows->command.width=(unsigned  int) (tile_width+QuantumMargin+10);
2954       windows->command.height=(unsigned  int) (number_selections*
2955         (((3*height) >> 1)+10)+tile_height+20);
2956       windows->command.min_width=windows->command.width;
2957       windows->command.min_height=windows->command.height;
2958       XConstrainWindowPosition(display,&windows->command);
2959       if (windows->command.id != (Window) NULL)
2960         {
2961           Status
2962             status;
2963
2964           /*
2965             Reconfigure command window.
2966           */
2967           status=XStringListToTextProperty(&windows->command.name,1,
2968             &window_name);
2969           if (status != False)
2970             {
2971               XSetWMName(display,windows->command.id,&window_name);
2972               XSetWMIconName(display,windows->command.id,&window_name);
2973               (void) XFree((void *) window_name.value);
2974             }
2975           window_changes.width=(int) windows->command.width;
2976           window_changes.height=(int) windows->command.height;
2977           (void) XReconfigureWMWindow(display,windows->command.id,
2978             windows->command.screen,(unsigned int) (CWWidth | CWHeight),
2979             &window_changes);
2980         }
2981       /*
2982         Allocate selection info memory.
2983       */
2984       if (selection_info != (XWidgetInfo *) NULL)
2985         selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
2986       selection_info=(XWidgetInfo *) AcquireQuantumMemory(number_selections,
2987         sizeof(*selection_info));
2988       if (selection_info == (XWidgetInfo *) NULL)
2989         {
2990           ThrowXWindowFatalException(ResourceLimitError,
2991             "MemoryAllocationFailed","...");
2992           return(id);
2993         }
2994       state|=UpdateConfigurationState | RedrawWidgetState;
2995     }
2996   /*
2997     Wait for next event.
2998   */
2999   if (event != (XEvent *) NULL)
3000     switch (event->type)
3001     {
3002       case ButtonPress:
3003       {
3004         for (i=0; i < (int) number_selections; i++)
3005         {
3006           if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
3007             continue;
3008           if (i >= (int) windows->command.data)
3009             {
3010               selection_info[i].raised=MagickFalse;
3011               XDrawBeveledButton(display,&windows->command,&selection_info[i]);
3012               break;
3013             }
3014           submenu_info=selection_info[i];
3015           submenu_info.active=MagickTrue;
3016           toggle_info.y=
3017             submenu_info.y+(submenu_info.height >> 1)-(toggle_info.height >> 1);
3018           id=i;
3019           (void) XCheckWindowEvent(display,windows->widget.id,LeaveWindowMask,
3020             event);
3021           break;
3022         }
3023         break;
3024       }
3025       case ButtonRelease:
3026       {
3027         for (i=0; i < (int) number_selections; i++)
3028         {
3029           if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
3030             continue;
3031           id=i;
3032           if (id >= (int) windows->command.data)
3033             {
3034               selection_info[id].raised=MagickTrue;
3035               XDrawBeveledButton(display,&windows->command,&selection_info[id]);
3036               break;
3037             }
3038           break;
3039         }
3040         break;
3041       }
3042       case ClientMessage:
3043       {
3044         /*
3045           If client window delete message, withdraw command widget.
3046         */
3047         if (event->xclient.message_type != windows->wm_protocols)
3048           break;
3049         if (*event->xclient.data.l != (int) windows->wm_delete_window)
3050           break;
3051         (void) XWithdrawWindow(display,windows->command.id,
3052           windows->command.screen);
3053         break;
3054       }
3055       case ConfigureNotify:
3056       {
3057         /*
3058           Update widget configuration.
3059         */
3060         if (event->xconfigure.window != windows->command.id)
3061           break;
3062         if (event->xconfigure.send_event != 0)
3063           {
3064             windows->command.x=event->xconfigure.x;
3065             windows->command.y=event->xconfigure.y;
3066           }
3067         if ((event->xconfigure.width == (int) windows->command.width) &&
3068             (event->xconfigure.height == (int) windows->command.height))
3069           break;
3070         windows->command.width=(unsigned int)
3071           MagickMax(event->xconfigure.width,(int) windows->command.min_width);
3072         windows->command.height=(unsigned int)
3073           MagickMax(event->xconfigure.height,(int) windows->command.min_height);
3074         state|=UpdateConfigurationState;
3075         break;
3076       }
3077       case Expose:
3078       {
3079         if (event->xexpose.window != windows->command.id)
3080           break;
3081         if (event->xexpose.count != 0)
3082           break;
3083         state|=RedrawWidgetState;
3084         break;
3085       }
3086       case MotionNotify:
3087       {
3088         /*
3089           Return the ID of the highlighted menu entry.
3090         */
3091         for ( ; ; )
3092         {
3093           for (i=0; i < (int) number_selections; i++)
3094           {
3095             if (i >= (int) windows->command.data)
3096               {
3097                 if (selection_info[i].raised ==
3098                     MatteIsActive(selection_info[i],event->xmotion))
3099                   {
3100                     /*
3101                       Button status changed.
3102                     */
3103                     selection_info[i].raised=!selection_info[i].raised;
3104                     XDrawBeveledButton(display,&windows->command,
3105                       &selection_info[i]);
3106                   }
3107                 continue;
3108               }
3109             if (MatteIsActive(selection_info[i],event->xmotion) == MagickFalse)
3110               continue;
3111             submenu_info=selection_info[i];
3112             submenu_info.active=MagickTrue;
3113             toggle_info.raised=MagickTrue;
3114             toggle_info.y=submenu_info.y+(submenu_info.height >> 1)-
3115               (toggle_info.height >> 1);
3116             XDrawTriangleEast(display,&windows->command,&toggle_info);
3117             id=i;
3118           }
3119           XDelay(display,SuspendTime);
3120           if (XCheckMaskEvent(display,ButtonMotionMask,event) == MagickFalse)
3121             break;
3122           while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
3123           toggle_info.raised=MagickFalse;
3124           if (windows->command.data != 0)
3125             XDrawTriangleEast(display,&windows->command,&toggle_info);
3126         }
3127         break;
3128       }
3129       case MapNotify:
3130       {
3131         windows->command.mapped=MagickTrue;
3132         break;
3133       }
3134       case UnmapNotify:
3135       {
3136         windows->command.mapped=MagickFalse;
3137         break;
3138       }
3139       default:
3140         break;
3141     }
3142   if (state & UpdateConfigurationState)
3143     {
3144       /*
3145         Initialize button information.
3146       */
3147       assert(selections != (const char **) NULL);
3148       y=tile_height+20;
3149       for (i=0; i < (int) number_selections; i++)
3150       {
3151         XGetWidgetInfo(selections[i],&selection_info[i]);
3152         selection_info[i].center=MagickFalse;
3153         selection_info[i].bevel_width--;
3154         selection_info[i].height=(unsigned int) ((3*height) >> 1);
3155         selection_info[i].x=(QuantumMargin >> 1)+4;
3156         selection_info[i].width=(unsigned int)
3157           (windows->command.width-(selection_info[i].x << 1));
3158         selection_info[i].y=y;
3159         y+=selection_info[i].height+(selection_info[i].bevel_width << 1)+6;
3160       }
3161       XGetWidgetInfo((char *) NULL,&toggle_info);
3162       toggle_info.bevel_width--;
3163       toggle_info.width=(unsigned int)
3164         (((5*height) >> 3)-(toggle_info.bevel_width << 1));
3165       toggle_info.height=toggle_info.width;
3166       toggle_info.x=selection_info[0].x+selection_info[0].width-
3167         toggle_info.width-(QuantumMargin >> 1);
3168       if (windows->command.mapped)
3169         (void) XClearWindow(display,windows->command.id);
3170     }
3171   if (state & RedrawWidgetState)
3172     {
3173       Pixmap
3174         tile_pixmap;
3175
3176       /*
3177         Draw command buttons.
3178       */
3179       tile_pixmap=XCreatePixmapFromBitmapData(display,windows->command.id,
3180         (char *) tile_bits,tile_width,tile_height,1L,0L,1);
3181       if (tile_pixmap != (Pixmap) NULL)
3182         {
3183           (void) XCopyPlane(display,tile_pixmap,windows->command.id,
3184             windows->command.annotate_context,0,0,tile_width,tile_height,
3185             (int) ((windows->command.width-tile_width) >> 1),10,1L);
3186           (void) XFreePixmap(display,tile_pixmap);
3187         }
3188       for (i=0; i < (int) number_selections; i++)
3189       {
3190         XDrawBeveledButton(display,&windows->command,&selection_info[i]);
3191         if (i >= (int) windows->command.data)
3192           continue;
3193         toggle_info.raised=i == id ? MagickTrue : MagickFalse;
3194         toggle_info.y=selection_info[i].y+
3195           (selection_info[i].height >> 1)-(toggle_info.height >> 1);
3196         XDrawTriangleEast(display,&windows->command,&toggle_info);
3197       }
3198       XHighlightWidget(display,&windows->command,BorderOffset,BorderOffset);
3199     }
3200   return(id);
3201 }
3202 \f
3203 /*
3204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3205 %                                                                             %
3206 %                                                                             %
3207 %                                                                             %
3208 %   X C o n f i r m W i d g e t                                               %
3209 %                                                                             %
3210 %                                                                             %
3211 %                                                                             %
3212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3213 %
3214 %  XConfirmWidget() displays a Confirm widget with a notice to the user. The
3215 %  function returns -1 if Dismiss is pressed, 0 for Cancel, and 1 for Yes.
3216 %
3217 %  The format of the XConfirmWidget method is:
3218 %
3219 %      int XConfirmWidget(Display *display,XWindows *windows,
3220 %        const char *reason,const char *description)
3221 %
3222 %  A description of each parameter follows:
3223 %
3224 %    o display: Specifies a connection to an X server;  returned from
3225 %      XOpenDisplay.
3226 %
3227 %    o window: Specifies a pointer to a XWindows structure.
3228 %
3229 %    o reason: Specifies the message to display before terminating the
3230 %      program.
3231 %
3232 %    o description: Specifies any description to the message.
3233 %
3234 */
3235 MagickExport int XConfirmWidget(Display *display,XWindows *windows,
3236   const char *reason,const char *description)
3237 {
3238 #define CancelButtonText  "Cancel"
3239 #define DismissButtonText  "Dismiss"
3240 #define YesButtonText  "Yes"
3241
3242   int
3243     confirm,
3244     x,
3245     y;
3246
3247   Status
3248     status;
3249
3250   unsigned int
3251     height,
3252     width;
3253
3254   size_t
3255     state;
3256
3257   XEvent
3258     event;
3259
3260   XFontStruct
3261     *font_info;
3262
3263   XTextProperty
3264     window_name;
3265
3266   XWidgetInfo
3267     cancel_info,
3268     dismiss_info,
3269     yes_info;
3270
3271   XWindowChanges
3272     window_changes;
3273
3274   /*
3275     Determine Confirm widget attributes.
3276   */
3277   assert(display != (Display *) NULL);
3278   assert(windows != (XWindows *) NULL);
3279   assert(reason != (char *) NULL);
3280   assert(description != (char *) NULL);
3281   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
3282   XCheckRefreshWindows(display,windows);
3283   font_info=windows->widget.font_info;
3284   width=WidgetTextWidth(font_info,CancelButtonText);
3285   if (WidgetTextWidth(font_info,DismissButtonText) > width)
3286     width=WidgetTextWidth(font_info,DismissButtonText);
3287   if (WidgetTextWidth(font_info,YesButtonText) > width)
3288     width=WidgetTextWidth(font_info,YesButtonText);
3289   width<<=1;
3290   if (description != (char *) NULL)
3291     if (WidgetTextWidth(font_info,(char *) description) > width)
3292       width=WidgetTextWidth(font_info,(char *) description);
3293   height=(unsigned int) (font_info->ascent+font_info->descent);
3294   /*
3295     Position Confirm widget.
3296   */
3297   windows->widget.width=(unsigned int) (width+9*QuantumMargin);
3298   windows->widget.min_width=(unsigned int) (9*QuantumMargin+
3299     WidgetTextWidth(font_info,CancelButtonText)+
3300     WidgetTextWidth(font_info,DismissButtonText)+
3301     WidgetTextWidth(font_info,YesButtonText));
3302   if (windows->widget.width < windows->widget.min_width)
3303     windows->widget.width=windows->widget.min_width;
3304   windows->widget.height=(unsigned int) (12*height);
3305   windows->widget.min_height=(unsigned int) (7*height);
3306   if (windows->widget.height < windows->widget.min_height)
3307     windows->widget.height=windows->widget.min_height;
3308   XConstrainWindowPosition(display,&windows->widget);
3309   /*
3310     Map Confirm widget.
3311   */
3312   (void) CopyMagickString(windows->widget.name,"Confirm",MaxTextExtent);
3313   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
3314   if (status != False)
3315     {
3316       XSetWMName(display,windows->widget.id,&window_name);
3317       XSetWMIconName(display,windows->widget.id,&window_name);
3318       (void) XFree((void *) window_name.value);
3319     }
3320   window_changes.width=(int) windows->widget.width;
3321   window_changes.height=(int) windows->widget.height;
3322   window_changes.x=windows->widget.x;
3323   window_changes.y=windows->widget.y;
3324   (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
3325     (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
3326   (void) XMapRaised(display,windows->widget.id);
3327   windows->widget.mapped=MagickFalse;
3328   /*
3329     Respond to X events.
3330   */
3331   confirm=0;
3332   state=UpdateConfigurationState;
3333   XSetCursorState(display,windows,MagickTrue);
3334   do
3335   {
3336     if (state & UpdateConfigurationState)
3337       {
3338         /*
3339           Initialize button information.
3340         */
3341         XGetWidgetInfo(CancelButtonText,&cancel_info);
3342         cancel_info.width=(unsigned int) QuantumMargin+
3343           WidgetTextWidth(font_info,CancelButtonText);
3344         cancel_info.height=(unsigned int) ((3*height) >> 1);
3345         cancel_info.x=(int) (windows->widget.width-cancel_info.width-
3346           QuantumMargin);
3347         cancel_info.y=(int) (windows->widget.height-(cancel_info.height << 1));
3348         dismiss_info=cancel_info;
3349         dismiss_info.text=(char *) DismissButtonText;
3350         if (LocaleCompare(description,"Do you want to save it") == 0)
3351           dismiss_info.text=(char *) "Don't Save";
3352         dismiss_info.width=(unsigned int) QuantumMargin+
3353           WidgetTextWidth(font_info,dismiss_info.text);
3354         dismiss_info.x=(int)
3355           ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
3356         yes_info=cancel_info;
3357         yes_info.text=(char *) YesButtonText;
3358         if (LocaleCompare(description,"Do you want to save it") == 0)
3359           yes_info.text=(char *) "Save";
3360         yes_info.width=(unsigned int) QuantumMargin+
3361           WidgetTextWidth(font_info,yes_info.text);
3362         if (yes_info.width < cancel_info.width)
3363           yes_info.width=cancel_info.width;
3364         yes_info.x=QuantumMargin;
3365         state&=(~UpdateConfigurationState);
3366       }
3367     if (state & RedrawWidgetState)
3368       {
3369         /*
3370           Redraw Confirm widget.
3371         */
3372         width=WidgetTextWidth(font_info,(char *) reason);
3373         x=(int) ((windows->widget.width >> 1)-(width >> 1));
3374         y=(int) ((windows->widget.height >> 1)-(height << 1));
3375         (void) XDrawString(display,windows->widget.id,
3376           windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
3377         if (description != (char *) NULL)
3378           {
3379             char
3380               question[MaxTextExtent];
3381
3382             (void) CopyMagickString(question,description,MaxTextExtent);
3383             (void) ConcatenateMagickString(question,"?",MaxTextExtent);
3384             width=WidgetTextWidth(font_info,question);
3385             x=(int) ((windows->widget.width >> 1)-(width >> 1));
3386             y+=height;
3387             (void) XDrawString(display,windows->widget.id,
3388               windows->widget.annotate_context,x,y,question,Extent(question));
3389           }
3390         XDrawBeveledButton(display,&windows->widget,&cancel_info);
3391         XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3392         XDrawBeveledButton(display,&windows->widget,&yes_info);
3393         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
3394         state&=(~RedrawWidgetState);
3395       }
3396     /*
3397       Wait for next event.
3398     */
3399     (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
3400     switch (event.type)
3401     {
3402       case ButtonPress:
3403       {
3404         if (MatteIsActive(cancel_info,event.xbutton))
3405           {
3406             /*
3407               User pressed No button.
3408             */
3409             cancel_info.raised=MagickFalse;
3410             XDrawBeveledButton(display,&windows->widget,&cancel_info);
3411             break;
3412           }
3413         if (MatteIsActive(dismiss_info,event.xbutton))
3414           {
3415             /*
3416               User pressed Dismiss button.
3417             */
3418             dismiss_info.raised=MagickFalse;
3419             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3420             break;
3421           }
3422         if (MatteIsActive(yes_info,event.xbutton))
3423           {
3424             /*
3425               User pressed Yes button.
3426             */
3427             yes_info.raised=MagickFalse;
3428             XDrawBeveledButton(display,&windows->widget,&yes_info);
3429             break;
3430           }
3431         break;
3432       }
3433       case ButtonRelease:
3434       {
3435         if (windows->widget.mapped == MagickFalse)
3436           break;
3437         if (cancel_info.raised == MagickFalse)
3438           {
3439             if (event.xbutton.window == windows->widget.id)
3440               if (MatteIsActive(cancel_info,event.xbutton))
3441                 {
3442                   confirm=0;
3443                   state|=ExitState;
3444                 }
3445             cancel_info.raised=MagickTrue;
3446             XDrawBeveledButton(display,&windows->widget,&cancel_info);
3447           }
3448         if (dismiss_info.raised == MagickFalse)
3449           {
3450             if (event.xbutton.window == windows->widget.id)
3451               if (MatteIsActive(dismiss_info,event.xbutton))
3452                 {
3453                   confirm=(-1);
3454                   state|=ExitState;
3455                 }
3456             dismiss_info.raised=MagickTrue;
3457             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3458           }
3459         if (yes_info.raised == MagickFalse)
3460           {
3461             if (event.xbutton.window == windows->widget.id)
3462               if (MatteIsActive(yes_info,event.xbutton))
3463                 {
3464                   confirm=1;
3465                   state|=ExitState;
3466                 }
3467             yes_info.raised=MagickTrue;
3468             XDrawBeveledButton(display,&windows->widget,&yes_info);
3469           }
3470         break;
3471       }
3472       case ClientMessage:
3473       {
3474         /*
3475           If client window delete message, exit.
3476         */
3477         if (event.xclient.message_type != windows->wm_protocols)
3478           break;
3479         if (*event.xclient.data.l == (int) windows->wm_take_focus)
3480           {
3481             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
3482               (Time) event.xclient.data.l[1]);
3483             break;
3484           }
3485         if (*event.xclient.data.l != (int) windows->wm_delete_window)
3486           break;
3487         if (event.xclient.window == windows->widget.id)
3488           {
3489             state|=ExitState;
3490             break;
3491           }
3492         break;
3493       }
3494       case ConfigureNotify:
3495       {
3496         /*
3497           Update widget configuration.
3498         */
3499         if (event.xconfigure.window != windows->widget.id)
3500           break;
3501         if ((event.xconfigure.width == (int) windows->widget.width) &&
3502             (event.xconfigure.height == (int) windows->widget.height))
3503           break;
3504         windows->widget.width=(unsigned int)
3505           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
3506         windows->widget.height=(unsigned int)
3507           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
3508         state|=UpdateConfigurationState;
3509         break;
3510       }
3511       case EnterNotify:
3512       {
3513         if (event.xcrossing.window != windows->widget.id)
3514           break;
3515         state&=(~InactiveWidgetState);
3516         break;
3517       }
3518       case Expose:
3519       {
3520         if (event.xexpose.window != windows->widget.id)
3521           break;
3522         if (event.xexpose.count != 0)
3523           break;
3524         state|=RedrawWidgetState;
3525         break;
3526       }
3527       case KeyPress:
3528       {
3529         static char
3530           command[MaxTextExtent];
3531
3532         static KeySym
3533           key_symbol;
3534
3535         /*
3536           Respond to a user key press.
3537         */
3538         if (event.xkey.window != windows->widget.id)
3539           break;
3540         (void) XLookupString((XKeyEvent *) &event.xkey,command,
3541           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3542         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
3543           {
3544             yes_info.raised=MagickFalse;
3545             XDrawBeveledButton(display,&windows->widget,&yes_info);
3546             confirm=1;
3547             state|=ExitState;
3548             break;
3549           }
3550         break;
3551       }
3552       case LeaveNotify:
3553       {
3554         if (event.xcrossing.window != windows->widget.id)
3555           break;
3556         state|=InactiveWidgetState;
3557         break;
3558       }
3559       case MotionNotify:
3560       {
3561         /*
3562           Discard pending button motion events.
3563         */
3564         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
3565         if (state & InactiveWidgetState)
3566           break;
3567         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
3568           {
3569             /*
3570               Cancel button status changed.
3571             */
3572             cancel_info.raised=cancel_info.raised == MagickFalse ?
3573               MagickTrue : MagickFalse;
3574             XDrawBeveledButton(display,&windows->widget,&cancel_info);
3575             break;
3576           }
3577         if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
3578           {
3579             /*
3580               Dismiss button status changed.
3581             */
3582             dismiss_info.raised=cancel_info.raised == MagickFalse ?
3583               MagickTrue : MagickFalse;
3584             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3585             break;
3586           }
3587         if (yes_info.raised == MatteIsActive(yes_info,event.xmotion))
3588           {
3589             /*
3590               Yes button status changed.
3591             */
3592             yes_info.raised=yes_info.raised == MagickFalse ?
3593               MagickTrue : MagickFalse;
3594             XDrawBeveledButton(display,&windows->widget,&yes_info);
3595             break;
3596           }
3597         break;
3598       }
3599       default:
3600         break;
3601     }
3602   } while ((state & ExitState) == 0);
3603   XSetCursorState(display,windows,MagickFalse);
3604   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
3605   XCheckRefreshWindows(display,windows);
3606   return(confirm);
3607 }
3608 \f
3609 /*
3610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3611 %                                                                             %
3612 %                                                                             %
3613 %                                                                             %
3614 %   X D i a l o g W i d g e t                                                 %
3615 %                                                                             %
3616 %                                                                             %
3617 %                                                                             %
3618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3619 %
3620 %  XDialogWidget() displays a Dialog widget with a query to the user.  The user
3621 %  keys a reply and presses the Ok or Cancel button to exit.  The typed text is
3622 %  returned as the reply function parameter.
3623 %
3624 %  The format of the XDialogWidget method is:
3625 %
3626 %      int XDialogWidget(Display *display,XWindows *windows,const char *action,
3627 %        const char *query,char *reply)
3628 %
3629 %  A description of each parameter follows:
3630 %
3631 %    o display: Specifies a connection to an X server;  returned from
3632 %      XOpenDisplay.
3633 %
3634 %    o window: Specifies a pointer to a XWindows structure.
3635 %
3636 %    o action: Specifies a pointer to the action of this widget.
3637 %
3638 %    o query: Specifies a pointer to the query to present to the user.
3639 %
3640 %    o reply: the response from the user is returned in this parameter.
3641 %
3642 */
3643 MagickExport int XDialogWidget(Display *display,XWindows *windows,
3644   const char *action,const char *query,char *reply)
3645 {
3646 #define CancelButtonText  "Cancel"
3647
3648   char
3649     primary_selection[MaxTextExtent];
3650
3651   int
3652     x;
3653
3654   register int
3655     i;
3656
3657   static MagickBooleanType
3658     raised = MagickFalse;
3659
3660   Status
3661     status;
3662
3663   unsigned int
3664     anomaly,
3665     height,
3666     width;
3667
3668   size_t
3669     state;
3670
3671   XEvent
3672     event;
3673
3674   XFontStruct
3675     *font_info;
3676
3677   XTextProperty
3678     window_name;
3679
3680   XWidgetInfo
3681     action_info,
3682     cancel_info,
3683     reply_info,
3684     special_info,
3685     text_info;
3686
3687   XWindowChanges
3688     window_changes;
3689
3690   /*
3691     Determine Dialog widget attributes.
3692   */
3693   assert(display != (Display *) NULL);
3694   assert(windows != (XWindows *) NULL);
3695   assert(action != (char *) NULL);
3696   assert(query != (char *) NULL);
3697   assert(reply != (char *) NULL);
3698   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
3699   XCheckRefreshWindows(display,windows);
3700   font_info=windows->widget.font_info;
3701   width=WidgetTextWidth(font_info,(char *) action);
3702   if (WidgetTextWidth(font_info,CancelButtonText) > width)
3703     width=WidgetTextWidth(font_info,CancelButtonText);
3704   width+=(3*QuantumMargin) >> 1;
3705   height=(unsigned int) (font_info->ascent+font_info->descent);
3706   /*
3707     Position Dialog widget.
3708   */
3709   windows->widget.width=(unsigned int) MagickMax((int) (2*width),(int)
3710     WidgetTextWidth(font_info,(char *) query));
3711   if (windows->widget.width < WidgetTextWidth(font_info,reply))
3712     windows->widget.width=WidgetTextWidth(font_info,reply);
3713   windows->widget.width+=6*QuantumMargin;
3714   windows->widget.min_width=(unsigned int)
3715     (width+28*XTextWidth(font_info,"#",1)+4*QuantumMargin);
3716   if (windows->widget.width < windows->widget.min_width)
3717     windows->widget.width=windows->widget.min_width;
3718   windows->widget.height=(unsigned int) (7*height+(QuantumMargin << 1));
3719   windows->widget.min_height=windows->widget.height;
3720   if (windows->widget.height < windows->widget.min_height)
3721     windows->widget.height=windows->widget.min_height;
3722   XConstrainWindowPosition(display,&windows->widget);
3723   /*
3724     Map Dialog widget.
3725   */
3726   (void) CopyMagickString(windows->widget.name,"Dialog",MaxTextExtent);
3727   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
3728   if (status != False)
3729     {
3730       XSetWMName(display,windows->widget.id,&window_name);
3731       XSetWMIconName(display,windows->widget.id,&window_name);
3732       (void) XFree((void *) window_name.value);
3733     }
3734   window_changes.width=(int) windows->widget.width;
3735   window_changes.height=(int) windows->widget.height;
3736   window_changes.x=windows->widget.x;
3737   window_changes.y=windows->widget.y;
3738   (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
3739     (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
3740   (void) XMapRaised(display,windows->widget.id);
3741   windows->widget.mapped=MagickFalse;
3742   /*
3743     Respond to X events.
3744   */
3745   anomaly=(LocaleCompare(action,"Background") == 0) ||
3746     (LocaleCompare(action,"New") == 0) ||
3747     (LocaleCompare(action,"Quantize") == 0) ||
3748     (LocaleCompare(action,"Resize") == 0) ||
3749     (LocaleCompare(action,"Save") == 0) ||
3750     (LocaleCompare(action,"Shade") == 0);
3751   state=UpdateConfigurationState;
3752   XSetCursorState(display,windows,MagickTrue);
3753   do
3754   {
3755     if (state & UpdateConfigurationState)
3756       {
3757         /*
3758           Initialize button information.
3759         */
3760         XGetWidgetInfo(CancelButtonText,&cancel_info);
3761         cancel_info.width=width;
3762         cancel_info.height=(unsigned int) ((3*height) >> 1);
3763         cancel_info.x=(int)
3764           (windows->widget.width-cancel_info.width-((3*QuantumMargin) >> 1));
3765         cancel_info.y=(int)
3766           (windows->widget.height-cancel_info.height-((3*QuantumMargin) >> 1));
3767         XGetWidgetInfo(action,&action_info);
3768         action_info.width=width;
3769         action_info.height=(unsigned int) ((3*height) >> 1);
3770         action_info.x=cancel_info.x-(cancel_info.width+QuantumMargin+
3771           (action_info.bevel_width << 1));
3772         action_info.y=cancel_info.y;
3773         /*
3774           Initialize reply information.
3775         */
3776         XGetWidgetInfo(reply,&reply_info);
3777         reply_info.raised=MagickFalse;
3778         reply_info.bevel_width--;
3779         reply_info.width=windows->widget.width-(3*QuantumMargin);
3780         reply_info.height=height << 1;
3781         reply_info.x=(3*QuantumMargin) >> 1;
3782         reply_info.y=action_info.y-reply_info.height-QuantumMargin;
3783         /*
3784           Initialize option information.
3785         */
3786         XGetWidgetInfo("Dither",&special_info);
3787         special_info.raised=raised;
3788         special_info.bevel_width--;
3789         special_info.width=(unsigned int) QuantumMargin >> 1;
3790         special_info.height=(unsigned int) QuantumMargin >> 1;
3791         special_info.x=reply_info.x;
3792         special_info.y=action_info.y+action_info.height-special_info.height;
3793         if (LocaleCompare(action,"Background") == 0)
3794           special_info.text=(char *) "Backdrop";
3795         if (LocaleCompare(action,"New") == 0)
3796           special_info.text=(char *) "Gradation";
3797         if (LocaleCompare(action,"Resize") == 0)
3798           special_info.text=(char *) "Constrain ratio";
3799         if (LocaleCompare(action,"Save") == 0)
3800           special_info.text=(char *) "Non-progressive";
3801         if (LocaleCompare(action,"Shade") == 0)
3802           special_info.text=(char *) "Color shading";
3803         /*
3804           Initialize text information.
3805         */
3806         XGetWidgetInfo(query,&text_info);
3807         text_info.width=reply_info.width;
3808         text_info.height=height;
3809         text_info.x=reply_info.x-(QuantumMargin >> 1);
3810         text_info.y=QuantumMargin;
3811         text_info.center=MagickFalse;
3812         state&=(~UpdateConfigurationState);
3813       }
3814     if (state & RedrawWidgetState)
3815       {
3816         /*
3817           Redraw Dialog widget.
3818         */
3819         XDrawWidgetText(display,&windows->widget,&text_info);
3820         XDrawBeveledMatte(display,&windows->widget,&reply_info);
3821         XDrawMatteText(display,&windows->widget,&reply_info);
3822         if (anomaly)
3823           XDrawBeveledButton(display,&windows->widget,&special_info);
3824         XDrawBeveledButton(display,&windows->widget,&action_info);
3825         XDrawBeveledButton(display,&windows->widget,&cancel_info);
3826         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
3827         state&=(~RedrawWidgetState);
3828       }
3829     /*
3830       Wait for next event.
3831     */
3832     (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
3833     switch (event.type)
3834     {
3835       case ButtonPress:
3836       {
3837         if (anomaly)
3838           if (MatteIsActive(special_info,event.xbutton))
3839             {
3840               /*
3841                 Option button status changed.
3842               */
3843               special_info.raised=!special_info.raised;
3844               XDrawBeveledButton(display,&windows->widget,&special_info);
3845               break;
3846             }
3847         if (MatteIsActive(action_info,event.xbutton))
3848           {
3849             /*
3850               User pressed Action button.
3851             */
3852             action_info.raised=MagickFalse;
3853             XDrawBeveledButton(display,&windows->widget,&action_info);
3854             break;
3855           }
3856         if (MatteIsActive(cancel_info,event.xbutton))
3857           {
3858             /*
3859               User pressed Cancel button.
3860             */
3861             cancel_info.raised=MagickFalse;
3862             XDrawBeveledButton(display,&windows->widget,&cancel_info);
3863             break;
3864           }
3865         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
3866           break;
3867         if (event.xbutton.button != Button2)
3868           {
3869             static Time
3870               click_time;
3871
3872             /*
3873               Move text cursor to position of button press.
3874             */
3875             x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
3876             for (i=1; i <= Extent(reply_info.marker); i++)
3877               if (XTextWidth(font_info,reply_info.marker,i) > x)
3878                 break;
3879             reply_info.cursor=reply_info.marker+i-1;
3880             if (event.xbutton.time > (click_time+DoubleClick))
3881               reply_info.highlight=MagickFalse;
3882             else
3883               {
3884                 /*
3885                   Become the XA_PRIMARY selection owner.
3886                 */
3887                 (void) CopyMagickString(primary_selection,reply_info.text,
3888                   MaxTextExtent);
3889                 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
3890                   event.xbutton.time);
3891                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
3892                   windows->widget.id ? MagickTrue : MagickFalse;
3893               }
3894             XDrawMatteText(display,&windows->widget,&reply_info);
3895             click_time=event.xbutton.time;
3896             break;
3897           }
3898         /*
3899           Request primary selection.
3900         */
3901         (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
3902           windows->widget.id,event.xbutton.time);
3903         break;
3904       }
3905       case ButtonRelease:
3906       {
3907         if (windows->widget.mapped == MagickFalse)
3908           break;
3909         if (action_info.raised == MagickFalse)
3910           {
3911             if (event.xbutton.window == windows->widget.id)
3912               if (MatteIsActive(action_info,event.xbutton))
3913                 state|=ExitState;
3914             action_info.raised=MagickTrue;
3915             XDrawBeveledButton(display,&windows->widget,&action_info);
3916           }
3917         if (cancel_info.raised == MagickFalse)
3918           {
3919             if (event.xbutton.window == windows->widget.id)
3920               if (MatteIsActive(cancel_info,event.xbutton))
3921                 {
3922                   *reply_info.text='\0';
3923                   state|=ExitState;
3924                 }
3925             cancel_info.raised=MagickTrue;
3926             XDrawBeveledButton(display,&windows->widget,&cancel_info);
3927           }
3928         break;
3929       }
3930       case ClientMessage:
3931       {
3932         /*
3933           If client window delete message, exit.
3934         */
3935         if (event.xclient.message_type != windows->wm_protocols)
3936           break;
3937         if (*event.xclient.data.l == (int) windows->wm_take_focus)
3938           {
3939             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
3940               (Time) event.xclient.data.l[1]);
3941             break;
3942           }
3943         if (*event.xclient.data.l != (int) windows->wm_delete_window)
3944           break;
3945         if (event.xclient.window == windows->widget.id)
3946           {
3947             *reply_info.text='\0';
3948             state|=ExitState;
3949             break;
3950           }
3951         break;
3952       }
3953       case ConfigureNotify:
3954       {
3955         /*
3956           Update widget configuration.
3957         */
3958         if (event.xconfigure.window != windows->widget.id)
3959           break;
3960         if ((event.xconfigure.width == (int) windows->widget.width) &&
3961             (event.xconfigure.height == (int) windows->widget.height))
3962           break;
3963         windows->widget.width=(unsigned int)
3964           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
3965         windows->widget.height=(unsigned int)
3966           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
3967         state|=UpdateConfigurationState;
3968         break;
3969       }
3970       case EnterNotify:
3971       {
3972         if (event.xcrossing.window != windows->widget.id)
3973           break;
3974         state&=(~InactiveWidgetState);
3975         break;
3976       }
3977       case Expose:
3978       {
3979         if (event.xexpose.window != windows->widget.id)
3980           break;
3981         if (event.xexpose.count != 0)
3982           break;
3983         state|=RedrawWidgetState;
3984         break;
3985       }
3986       case KeyPress:
3987       {
3988         static char
3989           command[MaxTextExtent];
3990
3991         static int
3992           length;
3993
3994         static KeySym
3995           key_symbol;
3996
3997         /*
3998           Respond to a user key press.
3999         */
4000         if (event.xkey.window != windows->widget.id)
4001           break;
4002         length=XLookupString((XKeyEvent *) &event.xkey,command,
4003           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4004         *(command+length)='\0';
4005         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
4006           {
4007             action_info.raised=MagickFalse;
4008             XDrawBeveledButton(display,&windows->widget,&action_info);
4009             state|=ExitState;
4010             break;
4011           }
4012         if (key_symbol == XK_Control_L)
4013           {
4014             state|=ControlState;
4015             break;
4016           }
4017         if (state & ControlState)
4018           switch ((int) key_symbol)
4019           {
4020             case XK_u:
4021             case XK_U:
4022             {
4023               /*
4024                 Erase the entire line of text.
4025               */
4026               *reply_info.text='\0';
4027               reply_info.cursor=reply_info.text;
4028               reply_info.marker=reply_info.text;
4029               reply_info.highlight=MagickFalse;
4030               break;
4031             }
4032             default:
4033               break;
4034           }
4035         XEditText(display,&reply_info,key_symbol,command,state);
4036         XDrawMatteText(display,&windows->widget,&reply_info);
4037         break;
4038       }
4039       case KeyRelease:
4040       {
4041         static char
4042           command[MaxTextExtent];
4043
4044         static KeySym
4045           key_symbol;
4046
4047         /*
4048           Respond to a user key release.
4049         */
4050         if (event.xkey.window != windows->widget.id)
4051           break;
4052         (void) XLookupString((XKeyEvent *) &event.xkey,command,
4053           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4054         if (key_symbol == XK_Control_L)
4055           state&=(~ControlState);
4056         break;
4057       }
4058       case LeaveNotify:
4059       {
4060         if (event.xcrossing.window != windows->widget.id)
4061           break;
4062         state|=InactiveWidgetState;
4063         break;
4064       }
4065       case MotionNotify:
4066       {
4067         /*
4068           Discard pending button motion events.
4069         */
4070         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
4071         if (state & InactiveWidgetState)
4072           break;
4073         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
4074           {
4075             /*
4076               Action button status changed.
4077             */
4078             action_info.raised=action_info.raised == MagickFalse ?
4079               MagickTrue : MagickFalse;
4080             XDrawBeveledButton(display,&windows->widget,&action_info);
4081             break;
4082           }
4083         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
4084           {
4085             /*
4086               Cancel button status changed.
4087             */
4088             cancel_info.raised=cancel_info.raised == MagickFalse ?
4089               MagickTrue : MagickFalse;
4090             XDrawBeveledButton(display,&windows->widget,&cancel_info);
4091             break;
4092           }
4093         break;
4094       }
4095       case SelectionClear:
4096       {
4097         reply_info.highlight=MagickFalse;
4098         XDrawMatteText(display,&windows->widget,&reply_info);
4099         break;
4100       }
4101       case SelectionNotify:
4102       {
4103         Atom
4104           type;
4105
4106         int
4107           format;
4108
4109         unsigned char
4110           *data;
4111
4112         unsigned long
4113           after,
4114           length;
4115
4116         /*
4117           Obtain response from primary selection.
4118         */
4119         if (event.xselection.property == (Atom) None)
4120           break;
4121         status=XGetWindowProperty(display,event.xselection.requestor,
4122           event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
4123           &format,&length,&after,&data);
4124         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
4125             (length == 0))
4126           break;
4127         if ((Extent(reply_info.text)+length) >= MaxTextExtent)
4128           (void) XBell(display,0);
4129         else
4130           {
4131             /*
4132               Insert primary selection in reply text.
4133             */
4134             *(data+length)='\0';
4135             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
4136               state);
4137             XDrawMatteText(display,&windows->widget,&reply_info);
4138           }
4139         (void) XFree((void *) data);
4140         break;
4141       }
4142       case SelectionRequest:
4143       {
4144         XSelectionEvent
4145           notify;
4146
4147         XSelectionRequestEvent
4148           *request;
4149
4150         if (reply_info.highlight == MagickFalse)
4151           break;
4152         /*
4153           Set primary selection.
4154         */
4155         request=(&(event.xselectionrequest));
4156         (void) XChangeProperty(request->display,request->requestor,
4157           request->property,request->target,8,PropModeReplace,
4158           (unsigned char *) primary_selection,Extent(primary_selection));
4159         notify.type=SelectionNotify;
4160         notify.display=request->display;
4161         notify.requestor=request->requestor;
4162         notify.selection=request->selection;
4163         notify.target=request->target;
4164         notify.time=request->time;
4165         if (request->property == None)
4166           notify.property=request->target;
4167         else
4168           notify.property=request->property;
4169         (void) XSendEvent(request->display,request->requestor,False,0,
4170           (XEvent *) &notify);
4171       }
4172       default:
4173         break;
4174     }
4175   } while ((state & ExitState) == 0);
4176   XSetCursorState(display,windows,MagickFalse);
4177   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
4178   XCheckRefreshWindows(display,windows);
4179   if (anomaly)
4180     if (special_info.raised)
4181       if (*reply != '\0')
4182         raised=MagickTrue;
4183   return(raised == MagickFalse);
4184 }
4185 \f
4186 /*
4187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4188 %                                                                             %
4189 %                                                                             %
4190 %                                                                             %
4191 %   X F i l e B r o w s e r W i d g e t                                       %
4192 %                                                                             %
4193 %                                                                             %
4194 %                                                                             %
4195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4196 %
4197 %  XFileBrowserWidget() displays a File Browser widget with a file query to the
4198 %  user.  The user keys a reply and presses the Action or Cancel button to
4199 %  exit.  The typed text is returned as the reply function parameter.
4200 %
4201 %  The format of the XFileBrowserWidget method is:
4202 %
4203 %      void XFileBrowserWidget(Display *display,XWindows *windows,
4204 %        const char *action,char *reply)
4205 %
4206 %  A description of each parameter follows:
4207 %
4208 %    o display: Specifies a connection to an X server;  returned from
4209 %      XOpenDisplay.
4210 %
4211 %    o window: Specifies a pointer to a XWindows structure.
4212 %
4213 %    o action: Specifies a pointer to the action of this widget.
4214 %
4215 %    o reply: the response from the user is returned in this parameter.
4216 %
4217 */
4218 MagickExport void XFileBrowserWidget(Display *display,XWindows *windows,
4219   const char *action,char *reply)
4220 {
4221 #define CancelButtonText  "Cancel"
4222 #define DirectoryText  "Directory:"
4223 #define FilenameText  "File name:"
4224 #define GrabButtonText  "Grab"
4225 #define FormatButtonText  "Format"
4226 #define HomeButtonText  "Home"
4227 #define UpButtonText  "Up"
4228
4229   char
4230     *cwd,
4231     **filelist,
4232     home_directory[MaxTextExtent],
4233     primary_selection[MaxTextExtent],
4234     text[MaxTextExtent],
4235     working_path[MaxTextExtent];
4236
4237   int
4238     x,
4239     y;
4240
4241   register ssize_t
4242     i;
4243
4244   static char
4245     glob_pattern[MaxTextExtent] = "*",
4246     format[MaxTextExtent] = "miff";
4247
4248   static MagickStatusType
4249     mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
4250
4251   Status
4252     status;
4253
4254   unsigned int
4255     anomaly,
4256     height,
4257     text_width,
4258     visible_files,
4259     width;
4260
4261   size_t
4262     delay,
4263     files,
4264     state;
4265
4266   XEvent
4267     event;
4268
4269   XFontStruct
4270     *font_info;
4271
4272   XTextProperty
4273     window_name;
4274
4275   XWidgetInfo
4276     action_info,
4277     cancel_info,
4278     expose_info,
4279     special_info,
4280     list_info,
4281     home_info,
4282     north_info,
4283     reply_info,
4284     scroll_info,
4285     selection_info,
4286     slider_info,
4287     south_info,
4288     text_info,
4289     up_info;
4290
4291   XWindowChanges
4292     window_changes;
4293
4294   /*
4295     Read filelist from current directory.
4296   */
4297   assert(display != (Display *) NULL);
4298   assert(windows != (XWindows *) NULL);
4299   assert(action != (char *) NULL);
4300   assert(reply != (char *) NULL);
4301   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
4302   XSetCursorState(display,windows,MagickTrue);
4303   XCheckRefreshWindows(display,windows);
4304   cwd=getcwd(home_directory,MaxTextExtent);
4305   (void) CopyMagickString(working_path,home_directory,MaxTextExtent);
4306   filelist=ListFiles(working_path,glob_pattern,&files);
4307   if (filelist == (char **) NULL)
4308     {
4309       /*
4310         Directory read failed.
4311       */
4312       XNoticeWidget(display,windows,"Unable to read directory:",working_path);
4313       (void) XDialogWidget(display,windows,action,"Enter filename:",reply);
4314       return;
4315     }
4316   /*
4317     Determine File Browser widget attributes.
4318   */
4319   font_info=windows->widget.font_info;
4320   text_width=0;
4321   for (i=0; i < (ssize_t) files; i++)
4322     if (WidgetTextWidth(font_info,filelist[i]) > text_width)
4323       text_width=WidgetTextWidth(font_info,filelist[i]);
4324   width=WidgetTextWidth(font_info,(char *) action);
4325   if (WidgetTextWidth(font_info,GrabButtonText) > width)
4326     width=WidgetTextWidth(font_info,GrabButtonText);
4327   if (WidgetTextWidth(font_info,FormatButtonText) > width)
4328     width=WidgetTextWidth(font_info,FormatButtonText);
4329   if (WidgetTextWidth(font_info,CancelButtonText) > width)
4330     width=WidgetTextWidth(font_info,CancelButtonText);
4331   if (WidgetTextWidth(font_info,HomeButtonText) > width)
4332     width=WidgetTextWidth(font_info,HomeButtonText);
4333   if (WidgetTextWidth(font_info,UpButtonText) > width)
4334     width=WidgetTextWidth(font_info,UpButtonText);
4335   width+=QuantumMargin;
4336   if (WidgetTextWidth(font_info,DirectoryText) > width)
4337     width=WidgetTextWidth(font_info,DirectoryText);
4338   if (WidgetTextWidth(font_info,FilenameText) > width)
4339     width=WidgetTextWidth(font_info,FilenameText);
4340   height=(unsigned int) (font_info->ascent+font_info->descent);
4341   /*
4342     Position File Browser widget.
4343   */
4344   windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
4345     6*QuantumMargin;
4346   windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
4347   if (windows->widget.width < windows->widget.min_width)
4348     windows->widget.width=windows->widget.min_width;
4349   windows->widget.height=(unsigned int)
4350     (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
4351   windows->widget.min_height=(unsigned int)
4352     (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
4353   if (windows->widget.height < windows->widget.min_height)
4354     windows->widget.height=windows->widget.min_height;
4355   XConstrainWindowPosition(display,&windows->widget);
4356   /*
4357     Map File Browser widget.
4358   */
4359   (void) CopyMagickString(windows->widget.name,"Browse and Select a File",
4360     MaxTextExtent);
4361   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
4362   if (status != False)
4363     {
4364       XSetWMName(display,windows->widget.id,&window_name);
4365       XSetWMIconName(display,windows->widget.id,&window_name);
4366       (void) XFree((void *) window_name.value);
4367     }
4368   window_changes.width=(int) windows->widget.width;
4369   window_changes.height=(int) windows->widget.height;
4370   window_changes.x=windows->widget.x;
4371   window_changes.y=windows->widget.y;
4372   (void) XReconfigureWMWindow(display,windows->widget.id,
4373     windows->widget.screen,mask,&window_changes);
4374   (void) XMapRaised(display,windows->widget.id);
4375   windows->widget.mapped=MagickFalse;
4376   /*
4377     Respond to X events.
4378   */
4379   XGetWidgetInfo((char *) NULL,&slider_info);
4380   XGetWidgetInfo((char *) NULL,&north_info);
4381   XGetWidgetInfo((char *) NULL,&south_info);
4382   XGetWidgetInfo((char *) NULL,&expose_info);
4383   visible_files=0;
4384   anomaly=(LocaleCompare(action,"Composite") == 0) ||
4385     (LocaleCompare(action,"Open") == 0) || (LocaleCompare(action,"Map") == 0);
4386   *reply='\0';
4387   delay=SuspendTime << 2;
4388   state=UpdateConfigurationState;
4389   do
4390   {
4391     if (state & UpdateConfigurationState)
4392       {
4393         int
4394           id;
4395
4396         /*
4397           Initialize button information.
4398         */
4399         XGetWidgetInfo(CancelButtonText,&cancel_info);
4400         cancel_info.width=width;
4401         cancel_info.height=(unsigned int) ((3*height) >> 1);
4402         cancel_info.x=(int)
4403           (windows->widget.width-cancel_info.width-QuantumMargin-2);
4404         cancel_info.y=(int)
4405           (windows->widget.height-cancel_info.height-QuantumMargin);
4406         XGetWidgetInfo(action,&action_info);
4407         action_info.width=width;
4408         action_info.height=(unsigned int) ((3*height) >> 1);
4409         action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
4410           (action_info.bevel_width << 1));
4411         action_info.y=cancel_info.y;
4412         XGetWidgetInfo(GrabButtonText,&special_info);
4413         special_info.width=width;
4414         special_info.height=(unsigned int) ((3*height) >> 1);
4415         special_info.x=action_info.x-(action_info.width+(QuantumMargin >> 1)+
4416           (special_info.bevel_width << 1));
4417         special_info.y=action_info.y;
4418         if (anomaly == MagickFalse)
4419           {
4420             register char
4421               *p;
4422
4423             special_info.text=(char *) FormatButtonText;
4424             p=reply+Extent(reply)-1;
4425             while ((p > (reply+1)) && (*(p-1) != '.'))
4426               p--;
4427             if ((p > (reply+1)) && (*(p-1) == '.'))
4428               (void) CopyMagickString(format,p,MaxTextExtent);
4429           }
4430         XGetWidgetInfo(UpButtonText,&up_info);
4431         up_info.width=width;
4432         up_info.height=(unsigned int) ((3*height) >> 1);
4433         up_info.x=QuantumMargin;
4434         up_info.y=((5*QuantumMargin) >> 1)+height;
4435         XGetWidgetInfo(HomeButtonText,&home_info);
4436         home_info.width=width;
4437         home_info.height=(unsigned int) ((3*height) >> 1);
4438         home_info.x=QuantumMargin;
4439         home_info.y=up_info.y+up_info.height+QuantumMargin;
4440         /*
4441           Initialize reply information.
4442         */
4443         XGetWidgetInfo(reply,&reply_info);
4444         reply_info.raised=MagickFalse;
4445         reply_info.bevel_width--;
4446         reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
4447         reply_info.height=height << 1;
4448         reply_info.x=(int) (width+(QuantumMargin << 1));
4449         reply_info.y=action_info.y-reply_info.height-QuantumMargin;
4450         /*
4451           Initialize scroll information.
4452         */
4453         XGetWidgetInfo((char *) NULL,&scroll_info);
4454         scroll_info.bevel_width--;
4455         scroll_info.width=height;
4456         scroll_info.height=(unsigned int)
4457           (reply_info.y-up_info.y-(QuantumMargin >> 1));
4458         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
4459         scroll_info.y=up_info.y-reply_info.bevel_width;
4460         scroll_info.raised=MagickFalse;
4461         scroll_info.trough=MagickTrue;
4462         north_info=scroll_info;
4463         north_info.raised=MagickTrue;
4464         north_info.width-=(north_info.bevel_width << 1);
4465         north_info.height=north_info.width-1;
4466         north_info.x+=north_info.bevel_width;
4467         north_info.y+=north_info.bevel_width;
4468         south_info=north_info;
4469         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
4470           south_info.height;
4471         id=slider_info.id;
4472         slider_info=north_info;
4473         slider_info.id=id;
4474         slider_info.width-=2;
4475         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
4476           slider_info.bevel_width+2;
4477         slider_info.height=scroll_info.height-((slider_info.min_y-
4478           scroll_info.y+1) << 1)+4;
4479         visible_files=scroll_info.height/(height+(height >> 3));
4480         if (files > visible_files)
4481           slider_info.height=(unsigned int)
4482             ((visible_files*slider_info.height)/files);
4483         slider_info.max_y=south_info.y-south_info.bevel_width-
4484           slider_info.bevel_width-2;
4485         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
4486         slider_info.y=slider_info.min_y;
4487         expose_info=scroll_info;
4488         expose_info.y=slider_info.y;
4489         /*
4490           Initialize list information.
4491         */
4492         XGetWidgetInfo((char *) NULL,&list_info);
4493         list_info.raised=MagickFalse;
4494         list_info.bevel_width--;
4495         list_info.width=(unsigned int)
4496           (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
4497         list_info.height=scroll_info.height;
4498         list_info.x=reply_info.x;
4499         list_info.y=scroll_info.y;
4500         if (windows->widget.mapped == MagickFalse)
4501           state|=JumpListState;
4502         /*
4503           Initialize text information.
4504         */
4505         *text='\0';
4506         XGetWidgetInfo(text,&text_info);
4507         text_info.center=MagickFalse;
4508         text_info.width=reply_info.width;
4509         text_info.height=height;
4510         text_info.x=list_info.x-(QuantumMargin >> 1);
4511         text_info.y=QuantumMargin;
4512         /*
4513           Initialize selection information.
4514         */
4515         XGetWidgetInfo((char *) NULL,&selection_info);
4516         selection_info.center=MagickFalse;
4517         selection_info.width=list_info.width;
4518         selection_info.height=(unsigned int) ((9*height) >> 3);
4519         selection_info.x=list_info.x;
4520         state&=(~UpdateConfigurationState);
4521       }
4522     if (state & RedrawWidgetState)
4523       {
4524         /*
4525           Redraw File Browser window.
4526         */
4527         x=QuantumMargin;
4528         y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
4529         (void) XDrawString(display,windows->widget.id,
4530           windows->widget.annotate_context,x,y,DirectoryText,
4531           Extent(DirectoryText));
4532         (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
4533         (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
4534           MaxTextExtent);
4535         (void) ConcatenateMagickString(text_info.text,glob_pattern,
4536           MaxTextExtent);
4537         XDrawWidgetText(display,&windows->widget,&text_info);
4538         XDrawBeveledButton(display,&windows->widget,&up_info);
4539         XDrawBeveledButton(display,&windows->widget,&home_info);
4540         XDrawBeveledMatte(display,&windows->widget,&list_info);
4541         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
4542         XDrawTriangleNorth(display,&windows->widget,&north_info);
4543         XDrawBeveledButton(display,&windows->widget,&slider_info);
4544         XDrawTriangleSouth(display,&windows->widget,&south_info);
4545         x=QuantumMargin;
4546         y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
4547         (void) XDrawString(display,windows->widget.id,
4548           windows->widget.annotate_context,x,y,FilenameText,
4549           Extent(FilenameText));
4550         XDrawBeveledMatte(display,&windows->widget,&reply_info);
4551         XDrawMatteText(display,&windows->widget,&reply_info);
4552         XDrawBeveledButton(display,&windows->widget,&special_info);
4553         XDrawBeveledButton(display,&windows->widget,&action_info);
4554         XDrawBeveledButton(display,&windows->widget,&cancel_info);
4555         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
4556         selection_info.id=(~0);
4557         state|=RedrawListState;
4558         state&=(~RedrawWidgetState);
4559       }
4560     if (state & UpdateListState)
4561       {
4562         char
4563           **checklist;
4564
4565         size_t
4566           number_files;
4567
4568         /*
4569           Update file list.
4570         */
4571         checklist=ListFiles(working_path,glob_pattern,&number_files);
4572         if (checklist == (char **) NULL)
4573           {
4574             /*
4575               Reply is a filename, exit.
4576             */
4577             action_info.raised=MagickFalse;
4578             XDrawBeveledButton(display,&windows->widget,&action_info);
4579             break;
4580           }
4581         for (i=0; i < (ssize_t) files; i++)
4582           filelist[i]=DestroyString(filelist[i]);
4583         if (filelist != (char **) NULL)
4584           filelist=(char **) RelinquishMagickMemory(filelist);
4585         filelist=checklist;
4586         files=number_files;
4587         /*
4588           Update file list.
4589         */
4590         slider_info.height=
4591           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
4592         if (files > visible_files)
4593           slider_info.height=(unsigned int)
4594             ((visible_files*slider_info.height)/files);
4595         slider_info.max_y=south_info.y-south_info.bevel_width-
4596           slider_info.bevel_width-2;
4597         slider_info.id=0;
4598         slider_info.y=slider_info.min_y;
4599         expose_info.y=slider_info.y;
4600         selection_info.id=(~0);
4601         list_info.id=(~0);
4602         state|=RedrawListState;
4603         /*
4604           Redraw directory name & reply.
4605         */
4606         if (IsGlob(reply_info.text) == MagickFalse)
4607           {
4608             *reply_info.text='\0';
4609             reply_info.cursor=reply_info.text;
4610           }
4611         (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
4612         (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
4613           MaxTextExtent);
4614         (void) ConcatenateMagickString(text_info.text,glob_pattern,
4615           MaxTextExtent);
4616         XDrawWidgetText(display,&windows->widget,&text_info);
4617         XDrawMatteText(display,&windows->widget,&reply_info);
4618         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
4619         XDrawTriangleNorth(display,&windows->widget,&north_info);
4620         XDrawBeveledButton(display,&windows->widget,&slider_info);
4621         XDrawTriangleSouth(display,&windows->widget,&south_info);
4622         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
4623         state&=(~UpdateListState);
4624       }
4625     if (state & JumpListState)
4626       {
4627         /*
4628           Jump scroll to match user filename.
4629         */
4630         list_info.id=(~0);
4631         for (i=0; i < (ssize_t) files; i++)
4632           if (LocaleCompare(filelist[i],reply) >= 0)
4633             {
4634               list_info.id=(int)
4635                 (LocaleCompare(filelist[i],reply) == 0 ? i : ~0);
4636               break;
4637             }
4638         if ((i < (ssize_t) slider_info.id) ||
4639             (i >= (ssize_t) (slider_info.id+visible_files)))
4640           slider_info.id=(int) i-(visible_files >> 1);
4641         selection_info.id=(~0);
4642         state|=RedrawListState;
4643         state&=(~JumpListState);
4644       }
4645     if (state & RedrawListState)
4646       {
4647         /*
4648           Determine slider id and position.
4649         */
4650         if (slider_info.id >= (int) (files-visible_files))
4651           slider_info.id=(int) (files-visible_files);
4652         if ((slider_info.id < 0) || (files <= visible_files))
4653           slider_info.id=0;
4654         slider_info.y=slider_info.min_y;
4655         if (files > 0)
4656           slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
4657             slider_info.min_y+1)/files);
4658         if (slider_info.id != selection_info.id)
4659           {
4660             /*
4661               Redraw scroll bar and file names.
4662             */
4663             selection_info.id=slider_info.id;
4664             selection_info.y=list_info.y+(height >> 3)+2;
4665             for (i=0; i < (ssize_t) visible_files; i++)
4666             {
4667               selection_info.raised=(int) (slider_info.id+i) != list_info.id ?
4668                 MagickTrue : MagickFalse;
4669               selection_info.text=(char *) NULL;
4670               if ((slider_info.id+i) < (ssize_t) files)
4671                 selection_info.text=filelist[slider_info.id+i];
4672               XDrawWidgetText(display,&windows->widget,&selection_info);
4673               selection_info.y+=(int) selection_info.height;
4674             }
4675             /*
4676               Update slider.
4677             */
4678             if (slider_info.y > expose_info.y)
4679               {
4680                 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
4681                 expose_info.y=slider_info.y-expose_info.height-
4682                   slider_info.bevel_width-1;
4683               }
4684             else
4685               {
4686                 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
4687                 expose_info.y=slider_info.y+slider_info.height+
4688                   slider_info.bevel_width+1;
4689               }
4690             XDrawTriangleNorth(display,&windows->widget,&north_info);
4691             XDrawMatte(display,&windows->widget,&expose_info);
4692             XDrawBeveledButton(display,&windows->widget,&slider_info);
4693             XDrawTriangleSouth(display,&windows->widget,&south_info);
4694             expose_info.y=slider_info.y;
4695           }
4696         state&=(~RedrawListState);
4697       }
4698     /*
4699       Wait for next event.
4700     */
4701     if (north_info.raised && south_info.raised)
4702       (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
4703     else
4704       {
4705         /*
4706           Brief delay before advancing scroll bar.
4707         */
4708         XDelay(display,delay);
4709         delay=SuspendTime;
4710         (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
4711         if (north_info.raised == MagickFalse)
4712           if (slider_info.id > 0)
4713             {
4714               /*
4715                 Move slider up.
4716               */
4717               slider_info.id--;
4718               state|=RedrawListState;
4719             }
4720         if (south_info.raised == MagickFalse)
4721           if (slider_info.id < (int) files)
4722             {
4723               /*
4724                 Move slider down.
4725               */
4726               slider_info.id++;
4727               state|=RedrawListState;
4728             }
4729         if (event.type != ButtonRelease)
4730           continue;
4731       }
4732     switch (event.type)
4733     {
4734       case ButtonPress:
4735       {
4736         if (MatteIsActive(slider_info,event.xbutton))
4737           {
4738             /*
4739               Track slider.
4740             */
4741             slider_info.active=MagickTrue;
4742             break;
4743           }
4744         if (MatteIsActive(north_info,event.xbutton))
4745           if (slider_info.id > 0)
4746             {
4747               /*
4748                 Move slider up.
4749               */
4750               north_info.raised=MagickFalse;
4751               slider_info.id--;
4752               state|=RedrawListState;
4753               break;
4754             }
4755         if (MatteIsActive(south_info,event.xbutton))
4756           if (slider_info.id < (int) files)
4757             {
4758               /*
4759                 Move slider down.
4760               */
4761               south_info.raised=MagickFalse;
4762               slider_info.id++;
4763               state|=RedrawListState;
4764               break;
4765             }
4766         if (MatteIsActive(scroll_info,event.xbutton))
4767           {
4768             /*
4769               Move slider.
4770             */
4771             if (event.xbutton.y < slider_info.y)
4772               slider_info.id-=(visible_files-1);
4773             else
4774               slider_info.id+=(visible_files-1);
4775             state|=RedrawListState;
4776             break;
4777           }
4778         if (MatteIsActive(list_info,event.xbutton))
4779           {
4780             int
4781               id;
4782
4783             /*
4784               User pressed file matte.
4785             */
4786             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
4787               selection_info.height;
4788             if (id >= (int) files)
4789               break;
4790             (void) CopyMagickString(reply_info.text,filelist[id],MaxTextExtent);
4791             reply_info.highlight=MagickFalse;
4792             reply_info.marker=reply_info.text;
4793             reply_info.cursor=reply_info.text+Extent(reply_info.text);
4794             XDrawMatteText(display,&windows->widget,&reply_info);
4795             if (id == list_info.id)
4796               {
4797                 register char
4798                   *p;
4799
4800                 p=reply_info.text+strlen(reply_info.text)-1;
4801                 if (*p == *DirectorySeparator)
4802                   ChopPathComponents(reply_info.text,1);
4803                 (void) ConcatenateMagickString(working_path,DirectorySeparator,
4804                   MaxTextExtent);
4805                 (void) ConcatenateMagickString(working_path,reply_info.text,
4806                   MaxTextExtent);
4807                 *reply='\0';
4808                 state|=UpdateListState;
4809               }
4810             selection_info.id=(~0);
4811             list_info.id=id;
4812             state|=RedrawListState;
4813             break;
4814           }
4815         if (MatteIsActive(up_info,event.xbutton))
4816           {
4817             /*
4818               User pressed Up button.
4819             */
4820             up_info.raised=MagickFalse;
4821             XDrawBeveledButton(display,&windows->widget,&up_info);
4822             break;
4823           }
4824         if (MatteIsActive(home_info,event.xbutton))
4825           {
4826             /*
4827               User pressed Home button.
4828             */
4829             home_info.raised=MagickFalse;
4830             XDrawBeveledButton(display,&windows->widget,&home_info);
4831             break;
4832           }
4833         if (MatteIsActive(special_info,event.xbutton))
4834           {
4835             /*
4836               User pressed Special button.
4837             */
4838             special_info.raised=MagickFalse;
4839             XDrawBeveledButton(display,&windows->widget,&special_info);
4840             break;
4841           }
4842         if (MatteIsActive(action_info,event.xbutton))
4843           {
4844             /*
4845               User pressed action button.
4846             */
4847             action_info.raised=MagickFalse;
4848             XDrawBeveledButton(display,&windows->widget,&action_info);
4849             break;
4850           }
4851         if (MatteIsActive(cancel_info,event.xbutton))
4852           {
4853             /*
4854               User pressed Cancel button.
4855             */
4856             cancel_info.raised=MagickFalse;
4857             XDrawBeveledButton(display,&windows->widget,&cancel_info);
4858             break;
4859           }
4860         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
4861           break;
4862         if (event.xbutton.button != Button2)
4863           {
4864             static Time
4865               click_time;
4866
4867             /*
4868               Move text cursor to position of button press.
4869             */
4870             x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
4871             for (i=1; i <= (ssize_t) Extent(reply_info.marker); i++)
4872               if (XTextWidth(font_info,reply_info.marker,(int) i) > x)
4873                 break;
4874             reply_info.cursor=reply_info.marker+i-1;
4875             if (event.xbutton.time > (click_time+DoubleClick))
4876               reply_info.highlight=MagickFalse;
4877             else
4878               {
4879                 /*
4880                   Become the XA_PRIMARY selection owner.
4881                 */
4882                 (void) CopyMagickString(primary_selection,reply_info.text,
4883                   MaxTextExtent);
4884                 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
4885                   event.xbutton.time);
4886                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
4887                   windows->widget.id ? MagickTrue : MagickFalse;
4888               }
4889             XDrawMatteText(display,&windows->widget,&reply_info);
4890             click_time=event.xbutton.time;
4891             break;
4892           }
4893         /*
4894           Request primary selection.
4895         */
4896         (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
4897           windows->widget.id,event.xbutton.time);
4898         break;
4899       }
4900       case ButtonRelease:
4901       {
4902         if (windows->widget.mapped == MagickFalse)
4903           break;
4904         if (north_info.raised == MagickFalse)
4905           {
4906             /*
4907               User released up button.
4908             */
4909             delay=SuspendTime << 2;
4910             north_info.raised=MagickTrue;
4911             XDrawTriangleNorth(display,&windows->widget,&north_info);
4912           }
4913         if (south_info.raised == MagickFalse)
4914           {
4915             /*
4916               User released down button.
4917             */
4918             delay=SuspendTime << 2;
4919             south_info.raised=MagickTrue;
4920             XDrawTriangleSouth(display,&windows->widget,&south_info);
4921           }
4922         if (slider_info.active)
4923           {
4924             /*
4925               Stop tracking slider.
4926             */
4927             slider_info.active=MagickFalse;
4928             break;
4929           }
4930         if (up_info.raised == MagickFalse)
4931           {
4932             if (event.xbutton.window == windows->widget.id)
4933               if (MatteIsActive(up_info,event.xbutton))
4934                 {
4935                   ChopPathComponents(working_path,1);
4936                   if (*working_path == '\0')
4937                     (void) CopyMagickString(working_path,DirectorySeparator,
4938                       MaxTextExtent);
4939                   state|=UpdateListState;
4940                 }
4941             up_info.raised=MagickTrue;
4942             XDrawBeveledButton(display,&windows->widget,&up_info);
4943           }
4944         if (home_info.raised == MagickFalse)
4945           {
4946             if (event.xbutton.window == windows->widget.id)
4947               if (MatteIsActive(home_info,event.xbutton))
4948                 {
4949                   (void) CopyMagickString(working_path,home_directory,
4950                     MaxTextExtent);
4951                   state|=UpdateListState;
4952                 }
4953             home_info.raised=MagickTrue;
4954             XDrawBeveledButton(display,&windows->widget,&home_info);
4955           }
4956         if (special_info.raised == MagickFalse)
4957           {
4958             if (anomaly == MagickFalse)
4959               {
4960                 char
4961                   **formats;
4962
4963                 ExceptionInfo
4964                   *exception;
4965
4966                 size_t
4967                   number_formats;
4968
4969                 /*
4970                   Let user select image format.
4971                 */
4972                 exception=AcquireExceptionInfo();
4973                 formats=GetMagickList("*",&number_formats,exception);
4974                 exception=DestroyExceptionInfo(exception);
4975                 (void) XCheckDefineCursor(display,windows->widget.id,
4976                   windows->widget.busy_cursor);
4977                 windows->popup.x=windows->widget.x+60;
4978                 windows->popup.y=windows->widget.y+60;
4979                 XListBrowserWidget(display,windows,&windows->popup,
4980                   (const char **) formats,"Select","Select image format type:",
4981                   format);
4982                 XSetCursorState(display,windows,MagickTrue);
4983                 (void) XCheckDefineCursor(display,windows->widget.id,
4984                   windows->widget.cursor);
4985                 LocaleLower(format);
4986                 AppendImageFormat(format,reply_info.text);
4987                 reply_info.cursor=reply_info.text+Extent(reply_info.text);
4988                 XDrawMatteText(display,&windows->widget,&reply_info);
4989                 special_info.raised=MagickTrue;
4990                 XDrawBeveledButton(display,&windows->widget,&special_info);
4991                 for (i=0; i < (ssize_t) number_formats; i++)
4992                   formats[i]=DestroyString(formats[i]);
4993                 formats=(char **) RelinquishMagickMemory(formats);
4994                 break;
4995               }
4996             if (event.xbutton.window == windows->widget.id)
4997               if (MatteIsActive(special_info,event.xbutton))
4998                 {
4999                   (void) CopyMagickString(working_path,"x:",MaxTextExtent);
5000                   state|=ExitState;
5001                 }
5002             special_info.raised=MagickTrue;
5003             XDrawBeveledButton(display,&windows->widget,&special_info);
5004           }
5005         if (action_info.raised == MagickFalse)
5006           {
5007             if (event.xbutton.window == windows->widget.id)
5008               {
5009                 if (MatteIsActive(action_info,event.xbutton))
5010                   {
5011                     if (*reply_info.text == '\0')
5012                       (void) XBell(display,0);
5013                     else
5014                       state|=ExitState;
5015                   }
5016               }
5017             action_info.raised=MagickTrue;
5018             XDrawBeveledButton(display,&windows->widget,&action_info);
5019           }
5020         if (cancel_info.raised == MagickFalse)
5021           {
5022             if (event.xbutton.window == windows->widget.id)
5023               if (MatteIsActive(cancel_info,event.xbutton))
5024                 {
5025                   *reply_info.text='\0';
5026                   *reply='\0';
5027                   state|=ExitState;
5028                 }
5029             cancel_info.raised=MagickTrue;
5030             XDrawBeveledButton(display,&windows->widget,&cancel_info);
5031           }
5032         break;
5033       }
5034       case ClientMessage:
5035       {
5036         /*
5037           If client window delete message, exit.
5038         */
5039         if (event.xclient.message_type != windows->wm_protocols)
5040           break;
5041         if (*event.xclient.data.l == (int) windows->wm_take_focus)
5042           {
5043             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
5044               (Time) event.xclient.data.l[1]);
5045             break;
5046           }
5047         if (*event.xclient.data.l != (int) windows->wm_delete_window)
5048           break;
5049         if (event.xclient.window == windows->widget.id)
5050           {
5051             *reply_info.text='\0';
5052             state|=ExitState;
5053             break;
5054           }
5055         break;
5056       }
5057       case ConfigureNotify:
5058       {
5059         /*
5060           Update widget configuration.
5061         */
5062         if (event.xconfigure.window != windows->widget.id)
5063           break;
5064         if ((event.xconfigure.width == (int) windows->widget.width) &&
5065             (event.xconfigure.height == (int) windows->widget.height))
5066           break;
5067         windows->widget.width=(unsigned int)
5068           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
5069         windows->widget.height=(unsigned int)
5070           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
5071         state|=UpdateConfigurationState;
5072         break;
5073       }
5074       case EnterNotify:
5075       {
5076         if (event.xcrossing.window != windows->widget.id)
5077           break;
5078         state&=(~InactiveWidgetState);
5079         break;
5080       }
5081       case Expose:
5082       {
5083         if (event.xexpose.window != windows->widget.id)
5084           break;
5085         if (event.xexpose.count != 0)
5086           break;
5087         state|=RedrawWidgetState;
5088         break;
5089       }
5090       case KeyPress:
5091       {
5092         static char
5093           command[MaxTextExtent];
5094
5095         static int
5096           length;
5097
5098         static KeySym
5099           key_symbol;
5100
5101         /*
5102           Respond to a user key press.
5103         */
5104         if (event.xkey.window != windows->widget.id)
5105           break;
5106         length=XLookupString((XKeyEvent *) &event.xkey,command,
5107           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5108         *(command+length)='\0';
5109         if (AreaIsActive(scroll_info,event.xkey))
5110           {
5111             /*
5112               Move slider.
5113             */
5114             switch ((int) key_symbol)
5115             {
5116               case XK_Home:
5117               case XK_KP_Home:
5118               {
5119                 slider_info.id=0;
5120                 break;
5121               }
5122               case XK_Up:
5123               case XK_KP_Up:
5124               {
5125                 slider_info.id--;
5126                 break;
5127               }
5128               case XK_Down:
5129               case XK_KP_Down:
5130               {
5131                 slider_info.id++;
5132                 break;
5133               }
5134               case XK_Prior:
5135               case XK_KP_Prior:
5136               {
5137                 slider_info.id-=visible_files;
5138                 break;
5139               }
5140               case XK_Next:
5141               case XK_KP_Next:
5142               {
5143                 slider_info.id+=visible_files;
5144                 break;
5145               }
5146               case XK_End:
5147               case XK_KP_End:
5148               {
5149                 slider_info.id=(int) files;
5150                 break;
5151               }
5152             }
5153             state|=RedrawListState;
5154             break;
5155           }
5156         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
5157           {
5158             /*
5159               Read new directory or glob patterm.
5160             */
5161             if (*reply_info.text == '\0')
5162               break;
5163             if (IsGlob(reply_info.text))
5164               (void) CopyMagickString(glob_pattern,reply_info.text,
5165                 MaxTextExtent);
5166             else
5167               {
5168                 (void) ConcatenateMagickString(working_path,DirectorySeparator,
5169                   MaxTextExtent);
5170                 (void) ConcatenateMagickString(working_path,reply_info.text,
5171                   MaxTextExtent);
5172                 if (*working_path == '~')
5173                   ExpandFilename(working_path);
5174                 *reply='\0';
5175               }
5176             state|=UpdateListState;
5177             break;
5178           }
5179         if (key_symbol == XK_Control_L)
5180           {
5181             state|=ControlState;
5182             break;
5183           }
5184         if (state & ControlState)
5185           switch ((int) key_symbol)
5186           {
5187             case XK_u:
5188             case XK_U:
5189             {
5190               /*
5191                 Erase the entire line of text.
5192               */
5193               *reply_info.text='\0';
5194               reply_info.cursor=reply_info.text;
5195               reply_info.marker=reply_info.text;
5196               reply_info.highlight=MagickFalse;
5197               break;
5198             }
5199             default:
5200               break;
5201           }
5202         XEditText(display,&reply_info,key_symbol,command,state);
5203         XDrawMatteText(display,&windows->widget,&reply_info);
5204         state|=JumpListState;
5205         break;
5206       }
5207       case KeyRelease:
5208       {
5209         static char
5210           command[MaxTextExtent];
5211
5212         static KeySym
5213           key_symbol;
5214
5215         /*
5216           Respond to a user key release.
5217         */
5218         if (event.xkey.window != windows->widget.id)
5219           break;
5220         (void) XLookupString((XKeyEvent *) &event.xkey,command,
5221           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5222         if (key_symbol == XK_Control_L)
5223           state&=(~ControlState);
5224         break;
5225       }
5226       case LeaveNotify:
5227       {
5228         if (event.xcrossing.window != windows->widget.id)
5229           break;
5230         state|=InactiveWidgetState;
5231         break;
5232       }
5233       case MapNotify:
5234       {
5235         mask&=(~CWX);
5236         mask&=(~CWY);
5237         break;
5238       }
5239       case MotionNotify:
5240       {
5241         /*
5242           Discard pending button motion events.
5243         */
5244         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
5245         if (slider_info.active)
5246           {
5247             /*
5248               Move slider matte.
5249             */
5250             slider_info.y=event.xmotion.y-
5251               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
5252             if (slider_info.y < slider_info.min_y)
5253               slider_info.y=slider_info.min_y;
5254             if (slider_info.y > slider_info.max_y)
5255               slider_info.y=slider_info.max_y;
5256             slider_info.id=0;
5257             if (slider_info.y != slider_info.min_y)
5258               slider_info.id=(int) ((files*(slider_info.y-slider_info.min_y+1))/
5259                 (slider_info.max_y-slider_info.min_y+1));
5260             state|=RedrawListState;
5261             break;
5262           }
5263         if (state & InactiveWidgetState)
5264           break;
5265         if (up_info.raised == MatteIsActive(up_info,event.xmotion))
5266           {
5267             /*
5268               Up button status changed.
5269             */
5270             up_info.raised=!up_info.raised;
5271             XDrawBeveledButton(display,&windows->widget,&up_info);
5272             break;
5273           }
5274         if (home_info.raised == MatteIsActive(home_info,event.xmotion))
5275           {
5276             /*
5277               Home button status changed.
5278             */
5279             home_info.raised=!home_info.raised;
5280             XDrawBeveledButton(display,&windows->widget,&home_info);
5281             break;
5282           }
5283         if (special_info.raised == MatteIsActive(special_info,event.xmotion))
5284           {
5285             /*
5286               Grab button status changed.
5287             */
5288             special_info.raised=!special_info.raised;
5289             XDrawBeveledButton(display,&windows->widget,&special_info);
5290             break;
5291           }
5292         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
5293           {
5294             /*
5295               Action button status changed.
5296             */
5297             action_info.raised=action_info.raised == MagickFalse ?
5298               MagickTrue : MagickFalse;
5299             XDrawBeveledButton(display,&windows->widget,&action_info);
5300             break;
5301           }
5302         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
5303           {
5304             /*
5305               Cancel button status changed.
5306             */
5307             cancel_info.raised=cancel_info.raised == MagickFalse ?
5308               MagickTrue : MagickFalse;
5309             XDrawBeveledButton(display,&windows->widget,&cancel_info);
5310             break;
5311           }
5312         break;
5313       }
5314       case SelectionClear:
5315       {
5316         reply_info.highlight=MagickFalse;
5317         XDrawMatteText(display,&windows->widget,&reply_info);
5318         break;
5319       }
5320       case SelectionNotify:
5321       {
5322         Atom
5323           type;
5324
5325         int
5326           format;
5327
5328         unsigned char
5329           *data;
5330
5331         unsigned long
5332           after,
5333           length;
5334
5335         /*
5336           Obtain response from primary selection.
5337         */
5338         if (event.xselection.property == (Atom) None)
5339           break;
5340         status=XGetWindowProperty(display,event.xselection.requestor,
5341           event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
5342           &format,&length,&after,&data);
5343         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
5344             (length == 0))
5345           break;
5346         if ((Extent(reply_info.text)+length) >= MaxTextExtent)
5347           (void) XBell(display,0);
5348         else
5349           {
5350             /*
5351               Insert primary selection in reply text.
5352             */
5353             *(data+length)='\0';
5354             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
5355               state);
5356             XDrawMatteText(display,&windows->widget,&reply_info);
5357             state|=JumpListState;
5358             state|=RedrawActionState;
5359           }
5360         (void) XFree((void *) data);
5361         break;
5362       }
5363       case SelectionRequest:
5364       {
5365         XSelectionEvent
5366           notify;
5367
5368         XSelectionRequestEvent
5369           *request;
5370
5371         if (reply_info.highlight == MagickFalse)
5372           break;
5373         /*
5374           Set primary selection.
5375         */
5376         request=(&(event.xselectionrequest));
5377         (void) XChangeProperty(request->display,request->requestor,
5378           request->property,request->target,8,PropModeReplace,
5379           (unsigned char *) primary_selection,Extent(primary_selection));
5380         notify.type=SelectionNotify;
5381         notify.display=request->display;
5382         notify.requestor=request->requestor;
5383         notify.selection=request->selection;
5384         notify.target=request->target;
5385         notify.time=request->time;
5386         if (request->property == None)
5387           notify.property=request->target;
5388         else
5389           notify.property=request->property;
5390         (void) XSendEvent(request->display,request->requestor,False,0,
5391           (XEvent *) &notify);
5392       }
5393       default:
5394         break;
5395     }
5396   } while ((state & ExitState) == 0);
5397   XSetCursorState(display,windows,MagickFalse);
5398   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
5399   XCheckRefreshWindows(display,windows);
5400   /*
5401     Free file list.
5402   */
5403   for (i=0; i < (ssize_t) files; i++)
5404     filelist[i]=DestroyString(filelist[i]);
5405   if (filelist != (char **) NULL)
5406     filelist=(char **) RelinquishMagickMemory(filelist);
5407   if (*reply != '\0')
5408     {
5409       (void) ConcatenateMagickString(working_path,DirectorySeparator,
5410         MaxTextExtent);
5411       (void) ConcatenateMagickString(working_path,reply,MaxTextExtent);
5412     }
5413   (void) CopyMagickString(reply,working_path,MaxTextExtent);
5414   if (*reply == '~')
5415     ExpandFilename(reply);
5416 }
5417 \f
5418 /*
5419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5420 %                                                                             %
5421 %                                                                             %
5422 %                                                                             %
5423 %   X F o n t B r o w s e r W i d g e t                                       %
5424 %                                                                             %
5425 %                                                                             %
5426 %                                                                             %
5427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5428 %
5429 %  XFontBrowserWidget() displays a Font Browser widget with a font query to the
5430 %  user.  The user keys a reply and presses the Action or Cancel button to
5431 %  exit.  The typed text is returned as the reply function parameter.
5432 %
5433 %  The format of the XFontBrowserWidget method is:
5434 %
5435 %      void XFontBrowserWidget(Display *display,XWindows *windows,
5436 %        const char *action,char *reply)
5437 %
5438 %  A description of each parameter follows:
5439 %
5440 %    o display: Specifies a connection to an X server;  returned from
5441 %      XOpenDisplay.
5442 %
5443 %    o window: Specifies a pointer to a XWindows structure.
5444 %
5445 %    o action: Specifies a pointer to the action of this widget.
5446 %
5447 %    o reply: the response from the user is returned in this parameter.
5448 %
5449 %
5450 */
5451
5452 #if defined(__cplusplus) || defined(c_plusplus)
5453 extern "C" {
5454 #endif
5455
5456 static int FontCompare(const void *x,const void *y)
5457 {
5458   register char
5459     *p,
5460     *q;
5461
5462   p=(char *) *((char **) x);
5463   q=(char *) *((char **) y);
5464   while ((*p != '\0') && (*q != '\0') && (*p == *q))
5465   {
5466     p++;
5467     q++;
5468   }
5469   return(*p-(*q));
5470 }
5471
5472 #if defined(__cplusplus) || defined(c_plusplus)
5473 }
5474 #endif
5475
5476 MagickExport void XFontBrowserWidget(Display *display,XWindows *windows,
5477   const char *action,char *reply)
5478 {
5479 #define BackButtonText  "Back"
5480 #define CancelButtonText  "Cancel"
5481 #define FontnameText  "Name:"
5482 #define FontPatternText  "Pattern:"
5483 #define ResetButtonText  "Reset"
5484
5485   char
5486     back_pattern[MaxTextExtent],
5487     **fontlist,
5488     **listhead,
5489     primary_selection[MaxTextExtent],
5490     reset_pattern[MaxTextExtent],
5491     text[MaxTextExtent];
5492
5493   int
5494     fonts,
5495     x,
5496     y;
5497
5498   register int
5499     i;
5500
5501   static char
5502     glob_pattern[MaxTextExtent] = "*";
5503
5504   static MagickStatusType
5505     mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
5506
5507   Status
5508     status;
5509
5510   unsigned int
5511     height,
5512     text_width,
5513     visible_fonts,
5514     width;
5515
5516   size_t
5517     delay,
5518     state;
5519
5520   XEvent
5521     event;
5522
5523   XFontStruct
5524     *font_info;
5525
5526   XTextProperty
5527     window_name;
5528
5529   XWidgetInfo
5530     action_info,
5531     back_info,
5532     cancel_info,
5533     expose_info,
5534     list_info,
5535     mode_info,
5536     north_info,
5537     reply_info,
5538     reset_info,
5539     scroll_info,
5540     selection_info,
5541     slider_info,
5542     south_info,
5543     text_info;
5544
5545   XWindowChanges
5546     window_changes;
5547
5548   /*
5549     Get font list and sort in ascending order.
5550   */
5551   assert(display != (Display *) NULL);
5552   assert(windows != (XWindows *) NULL);
5553   assert(action != (char *) NULL);
5554   assert(reply != (char *) NULL);
5555   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
5556   XSetCursorState(display,windows,MagickTrue);
5557   XCheckRefreshWindows(display,windows);
5558   (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
5559   (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
5560   fontlist=XListFonts(display,glob_pattern,32767,&fonts);
5561   if (fonts == 0)
5562     {
5563       /*
5564         Pattern failed, obtain all the fonts.
5565       */
5566       XNoticeWidget(display,windows,"Unable to obtain fonts names:",
5567         glob_pattern);
5568       (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
5569       fontlist=XListFonts(display,glob_pattern,32767,&fonts);
5570       if (fontlist == (char **) NULL)
5571         {
5572           XNoticeWidget(display,windows,"Unable to obtain fonts names:",
5573             glob_pattern);
5574           return;
5575         }
5576     }
5577   /*
5578     Sort font list in ascending order.
5579   */
5580   listhead=fontlist;
5581   fontlist=(char **) AcquireQuantumMemory((size_t) fonts,sizeof(*fontlist));
5582   if (fontlist == (char **) NULL)
5583     {
5584       XNoticeWidget(display,windows,"MemoryAllocationFailed",
5585         "UnableToViewFonts");
5586       return;
5587     }
5588   for (i=0; i < fonts; i++)
5589     fontlist[i]=listhead[i];
5590   qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
5591   /*
5592     Determine Font Browser widget attributes.
5593   */
5594   font_info=windows->widget.font_info;
5595   text_width=0;
5596   for (i=0; i < fonts; i++)
5597     if (WidgetTextWidth(font_info,fontlist[i]) > text_width)
5598       text_width=WidgetTextWidth(font_info,fontlist[i]);
5599   width=WidgetTextWidth(font_info,(char *) action);
5600   if (WidgetTextWidth(font_info,CancelButtonText) > width)
5601     width=WidgetTextWidth(font_info,CancelButtonText);
5602   if (WidgetTextWidth(font_info,ResetButtonText) > width)
5603     width=WidgetTextWidth(font_info,ResetButtonText);
5604   if (WidgetTextWidth(font_info,BackButtonText) > width)
5605     width=WidgetTextWidth(font_info,BackButtonText);
5606   width+=QuantumMargin;
5607   if (WidgetTextWidth(font_info,FontPatternText) > width)
5608     width=WidgetTextWidth(font_info,FontPatternText);
5609   if (WidgetTextWidth(font_info,FontnameText) > width)
5610     width=WidgetTextWidth(font_info,FontnameText);
5611   height=(unsigned int) (font_info->ascent+font_info->descent);
5612   /*
5613     Position Font Browser widget.
5614   */
5615   windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
5616     6*QuantumMargin;
5617   windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
5618   if (windows->widget.width < windows->widget.min_width)
5619     windows->widget.width=windows->widget.min_width;
5620   windows->widget.height=(unsigned int)
5621     (((85*height) >> 2)+((13*QuantumMargin) >> 1)+4);
5622   windows->widget.min_height=(unsigned int)
5623     (((27*height) >> 1)+((13*QuantumMargin) >> 1)+4);
5624   if (windows->widget.height < windows->widget.min_height)
5625     windows->widget.height=windows->widget.min_height;
5626   XConstrainWindowPosition(display,&windows->widget);
5627   /*
5628     Map Font Browser widget.
5629   */
5630   (void) CopyMagickString(windows->widget.name,"Browse and Select a Font",
5631     MaxTextExtent);
5632   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
5633   if (status != False)
5634     {
5635       XSetWMName(display,windows->widget.id,&window_name);
5636       XSetWMIconName(display,windows->widget.id,&window_name);
5637       (void) XFree((void *) window_name.value);
5638     }
5639   window_changes.width=(int) windows->widget.width;
5640   window_changes.height=(int) windows->widget.height;
5641   window_changes.x=windows->widget.x;
5642   window_changes.y=windows->widget.y;
5643   (void) XReconfigureWMWindow(display,windows->widget.id,
5644     windows->widget.screen,mask,&window_changes);
5645   (void) XMapRaised(display,windows->widget.id);
5646   windows->widget.mapped=MagickFalse;
5647   /*
5648     Respond to X events.
5649   */
5650   XGetWidgetInfo((char *) NULL,&slider_info);
5651   XGetWidgetInfo((char *) NULL,&north_info);
5652   XGetWidgetInfo((char *) NULL,&south_info);
5653   XGetWidgetInfo((char *) NULL,&expose_info);
5654   visible_fonts=0;
5655   delay=SuspendTime << 2;
5656   state=UpdateConfigurationState;
5657   do
5658   {
5659     if (state & UpdateConfigurationState)
5660       {
5661         int
5662           id;
5663
5664         /*
5665           Initialize button information.
5666         */
5667         XGetWidgetInfo(CancelButtonText,&cancel_info);
5668         cancel_info.width=width;
5669         cancel_info.height=(unsigned int) ((3*height) >> 1);
5670         cancel_info.x=(int)
5671           (windows->widget.width-cancel_info.width-QuantumMargin-2);
5672         cancel_info.y=(int)
5673           (windows->widget.height-cancel_info.height-QuantumMargin);
5674         XGetWidgetInfo(action,&action_info);
5675         action_info.width=width;
5676         action_info.height=(unsigned int) ((3*height) >> 1);
5677         action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
5678           (action_info.bevel_width << 1));
5679         action_info.y=cancel_info.y;
5680         XGetWidgetInfo(BackButtonText,&back_info);
5681         back_info.width=width;
5682         back_info.height=(unsigned int) ((3*height) >> 1);
5683         back_info.x=QuantumMargin;
5684         back_info.y=((5*QuantumMargin) >> 1)+height;
5685         XGetWidgetInfo(ResetButtonText,&reset_info);
5686         reset_info.width=width;
5687         reset_info.height=(unsigned int) ((3*height) >> 1);
5688         reset_info.x=QuantumMargin;
5689         reset_info.y=back_info.y+back_info.height+QuantumMargin;
5690         /*
5691           Initialize reply information.
5692         */
5693         XGetWidgetInfo(reply,&reply_info);
5694         reply_info.raised=MagickFalse;
5695         reply_info.bevel_width--;
5696         reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
5697         reply_info.height=height << 1;
5698         reply_info.x=(int) (width+(QuantumMargin << 1));
5699         reply_info.y=action_info.y-(action_info.height << 1)-QuantumMargin;
5700         /*
5701           Initialize mode information.
5702         */
5703         XGetWidgetInfo(reply,&mode_info);
5704         mode_info.bevel_width=0;
5705         mode_info.width=(unsigned int)
5706           (action_info.x-reply_info.x-QuantumMargin);
5707         mode_info.height=action_info.height << 1;
5708         mode_info.x=reply_info.x;
5709         mode_info.y=action_info.y-action_info.height+action_info.bevel_width;
5710         /*
5711           Initialize scroll information.
5712         */
5713         XGetWidgetInfo((char *) NULL,&scroll_info);
5714         scroll_info.bevel_width--;
5715         scroll_info.width=height;
5716         scroll_info.height=(unsigned int)
5717           (reply_info.y-back_info.y-(QuantumMargin >> 1));
5718         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
5719         scroll_info.y=back_info.y-reply_info.bevel_width;
5720         scroll_info.raised=MagickFalse;
5721         scroll_info.trough=MagickTrue;
5722         north_info=scroll_info;
5723         north_info.raised=MagickTrue;
5724         north_info.width-=(north_info.bevel_width << 1);
5725         north_info.height=north_info.width-1;
5726         north_info.x+=north_info.bevel_width;
5727         north_info.y+=north_info.bevel_width;
5728         south_info=north_info;
5729         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
5730           south_info.height;
5731         id=slider_info.id;
5732         slider_info=north_info;
5733         slider_info.id=id;
5734         slider_info.width-=2;
5735         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
5736           slider_info.bevel_width+2;
5737         slider_info.height=scroll_info.height-((slider_info.min_y-
5738           scroll_info.y+1) << 1)+4;
5739         visible_fonts=scroll_info.height/(height+(height >> 3));
5740         if (fonts > (int) visible_fonts)
5741           slider_info.height=(visible_fonts*slider_info.height)/fonts;
5742         slider_info.max_y=south_info.y-south_info.bevel_width-
5743           slider_info.bevel_width-2;
5744         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
5745         slider_info.y=slider_info.min_y;
5746         expose_info=scroll_info;
5747         expose_info.y=slider_info.y;
5748         /*
5749           Initialize list information.
5750         */
5751         XGetWidgetInfo((char *) NULL,&list_info);
5752         list_info.raised=MagickFalse;
5753         list_info.bevel_width--;
5754         list_info.width=(unsigned int)
5755           (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
5756         list_info.height=scroll_info.height;
5757         list_info.x=reply_info.x;
5758         list_info.y=scroll_info.y;
5759         if (windows->widget.mapped == MagickFalse)
5760           state|=JumpListState;
5761         /*
5762           Initialize text information.
5763         */
5764         *text='\0';
5765         XGetWidgetInfo(text,&text_info);
5766         text_info.center=MagickFalse;
5767         text_info.width=reply_info.width;
5768         text_info.height=height;
5769         text_info.x=list_info.x-(QuantumMargin >> 1);
5770         text_info.y=QuantumMargin;
5771         /*
5772           Initialize selection information.
5773         */
5774         XGetWidgetInfo((char *) NULL,&selection_info);
5775         selection_info.center=MagickFalse;
5776         selection_info.width=list_info.width;
5777         selection_info.height=(unsigned int) ((9*height) >> 3);
5778         selection_info.x=list_info.x;
5779         state&=(~UpdateConfigurationState);
5780       }
5781     if (state & RedrawWidgetState)
5782       {
5783         /*
5784           Redraw Font Browser window.
5785         */
5786         x=QuantumMargin;
5787         y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
5788         (void) XDrawString(display,windows->widget.id,
5789           windows->widget.annotate_context,x,y,FontPatternText,
5790           Extent(FontPatternText));
5791         (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
5792         XDrawWidgetText(display,&windows->widget,&text_info);
5793         XDrawBeveledButton(display,&windows->widget,&back_info);
5794         XDrawBeveledButton(display,&windows->widget,&reset_info);
5795         XDrawBeveledMatte(display,&windows->widget,&list_info);
5796         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
5797         XDrawTriangleNorth(display,&windows->widget,&north_info);
5798         XDrawBeveledButton(display,&windows->widget,&slider_info);
5799         XDrawTriangleSouth(display,&windows->widget,&south_info);
5800         x=QuantumMargin;
5801         y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
5802         (void) XDrawString(display,windows->widget.id,
5803           windows->widget.annotate_context,x,y,FontnameText,
5804           Extent(FontnameText));
5805         XDrawBeveledMatte(display,&windows->widget,&reply_info);
5806         XDrawMatteText(display,&windows->widget,&reply_info);
5807         XDrawBeveledButton(display,&windows->widget,&action_info);
5808         XDrawBeveledButton(display,&windows->widget,&cancel_info);
5809         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
5810         selection_info.id=(~0);
5811         state|=RedrawActionState;
5812         state|=RedrawListState;
5813         state&=(~RedrawWidgetState);
5814       }
5815     if (state & UpdateListState)
5816       {
5817         char
5818           **checklist;
5819
5820         int
5821           number_fonts;
5822
5823         /*
5824           Update font list.
5825         */
5826         checklist=XListFonts(display,glob_pattern,32767,&number_fonts);
5827         if (checklist == (char **) NULL)
5828           {
5829             if ((strchr(glob_pattern,'*') == (char *) NULL) &&
5830                 (strchr(glob_pattern,'?') == (char *) NULL))
5831               {
5832                 /*
5833                   Might be a scaleable font-- exit.
5834                 */
5835                 (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
5836                 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5837                 action_info.raised=MagickFalse;
5838                 XDrawBeveledButton(display,&windows->widget,&action_info);
5839                 break;
5840               }
5841             (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5842             (void) XBell(display,0);
5843           }
5844         else
5845           if (number_fonts == 1)
5846             {
5847               /*
5848                 Reply is a single font name-- exit.
5849               */
5850               (void) CopyMagickString(reply,checklist[0],MaxTextExtent);
5851               (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5852               (void) XFreeFontNames(checklist);
5853               action_info.raised=MagickFalse;
5854               XDrawBeveledButton(display,&windows->widget,&action_info);
5855               break;
5856             }
5857           else
5858             {
5859               (void) XFreeFontNames(listhead);
5860               fontlist=(char **) RelinquishMagickMemory(fontlist);
5861               fontlist=checklist;
5862               fonts=number_fonts;
5863             }
5864         /*
5865           Sort font list in ascending order.
5866         */
5867         listhead=fontlist;
5868         fontlist=(char **) AcquireQuantumMemory((size_t) fonts,
5869           sizeof(*fontlist));
5870         if (fontlist == (char **) NULL)
5871           {
5872             XNoticeWidget(display,windows,"MemoryAllocationFailed",
5873               "UnableToViewFonts");
5874             return;
5875           }
5876         for (i=0; i < fonts; i++)
5877           fontlist[i]=listhead[i];
5878         qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
5879         slider_info.height=
5880           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
5881         if (fonts > (int) visible_fonts)
5882           slider_info.height=(visible_fonts*slider_info.height)/fonts;
5883         slider_info.max_y=south_info.y-south_info.bevel_width-
5884           slider_info.bevel_width-2;
5885         slider_info.id=0;
5886         slider_info.y=slider_info.min_y;
5887         expose_info.y=slider_info.y;
5888         selection_info.id=(~0);
5889         list_info.id=(~0);
5890         state|=RedrawListState;
5891         /*
5892           Redraw font name & reply.
5893         */
5894         *reply_info.text='\0';
5895         reply_info.cursor=reply_info.text;
5896         (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
5897         XDrawWidgetText(display,&windows->widget,&text_info);
5898         XDrawMatteText(display,&windows->widget,&reply_info);
5899         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
5900         XDrawTriangleNorth(display,&windows->widget,&north_info);
5901         XDrawBeveledButton(display,&windows->widget,&slider_info);
5902         XDrawTriangleSouth(display,&windows->widget,&south_info);
5903         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
5904         state&=(~UpdateListState);
5905       }
5906     if (state & JumpListState)
5907       {
5908         /*
5909           Jump scroll to match user font.
5910         */
5911         list_info.id=(~0);
5912         for (i=0; i < fonts; i++)
5913           if (LocaleCompare(fontlist[i],reply) >= 0)
5914             {
5915               list_info.id=LocaleCompare(fontlist[i],reply) == 0 ? i : ~0;
5916               break;
5917             }
5918         if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_fonts)))
5919           slider_info.id=i-(visible_fonts >> 1);
5920         selection_info.id=(~0);
5921         state|=RedrawListState;
5922         state&=(~JumpListState);
5923       }
5924     if (state & RedrawListState)
5925       {
5926         /*
5927           Determine slider id and position.
5928         */
5929         if (slider_info.id >= (int) (fonts-visible_fonts))
5930           slider_info.id=fonts-visible_fonts;
5931         if ((slider_info.id < 0) || (fonts <= (int) visible_fonts))
5932           slider_info.id=0;
5933         slider_info.y=slider_info.min_y;
5934         if (fonts > 0)
5935           slider_info.y+=
5936             slider_info.id*(slider_info.max_y-slider_info.min_y+1)/fonts;
5937         if (slider_info.id != selection_info.id)
5938           {
5939             /*
5940               Redraw scroll bar and file names.
5941             */
5942             selection_info.id=slider_info.id;
5943             selection_info.y=list_info.y+(height >> 3)+2;
5944             for (i=0; i < (int) visible_fonts; i++)
5945             {
5946               selection_info.raised=(slider_info.id+i) != list_info.id ?
5947                 MagickTrue : MagickFalse;
5948               selection_info.text=(char *) NULL;
5949               if ((slider_info.id+i) < fonts)
5950                 selection_info.text=fontlist[slider_info.id+i];
5951               XDrawWidgetText(display,&windows->widget,&selection_info);
5952               selection_info.y+=(int) selection_info.height;
5953             }
5954             /*
5955               Update slider.
5956             */
5957             if (slider_info.y > expose_info.y)
5958               {
5959                 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
5960                 expose_info.y=slider_info.y-expose_info.height-
5961                   slider_info.bevel_width-1;
5962               }
5963             else
5964               {
5965                 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
5966                 expose_info.y=slider_info.y+slider_info.height+
5967                   slider_info.bevel_width+1;
5968               }
5969             XDrawTriangleNorth(display,&windows->widget,&north_info);
5970             XDrawMatte(display,&windows->widget,&expose_info);
5971             XDrawBeveledButton(display,&windows->widget,&slider_info);
5972             XDrawTriangleSouth(display,&windows->widget,&south_info);
5973             expose_info.y=slider_info.y;
5974           }
5975         state&=(~RedrawListState);
5976       }
5977     if (state & RedrawActionState)
5978       {
5979         XFontStruct
5980           *save_info;
5981
5982         /*
5983           Display the selected font in a drawing area.
5984         */
5985         save_info=windows->widget.font_info;
5986         font_info=XLoadQueryFont(display,reply_info.text);
5987         if (font_info != (XFontStruct *) NULL)
5988           {
5989             windows->widget.font_info=font_info;
5990             (void) XSetFont(display,windows->widget.widget_context,
5991               font_info->fid);
5992           }
5993         XDrawBeveledButton(display,&windows->widget,&mode_info);
5994         windows->widget.font_info=save_info;
5995         if (font_info != (XFontStruct *) NULL)
5996           {
5997             (void) XSetFont(display,windows->widget.widget_context,
5998               windows->widget.font_info->fid);
5999             (void) XFreeFont(display,font_info);
6000           }
6001         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
6002         XDrawMatteText(display,&windows->widget,&reply_info);
6003         state&=(~RedrawActionState);
6004       }
6005     /*
6006       Wait for next event.
6007     */
6008     if (north_info.raised && south_info.raised)
6009       (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
6010     else
6011       {
6012         /*
6013           Brief delay before advancing scroll bar.
6014         */
6015         XDelay(display,delay);
6016         delay=SuspendTime;
6017         (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
6018         if (north_info.raised == MagickFalse)
6019           if (slider_info.id > 0)
6020             {
6021               /*
6022                 Move slider up.
6023               */
6024               slider_info.id--;
6025               state|=RedrawListState;
6026             }
6027         if (south_info.raised == MagickFalse)
6028           if (slider_info.id < fonts)
6029             {
6030               /*
6031                 Move slider down.
6032               */
6033               slider_info.id++;
6034               state|=RedrawListState;
6035             }
6036         if (event.type != ButtonRelease)
6037           continue;
6038       }
6039     switch (event.type)
6040     {
6041       case ButtonPress:
6042       {
6043         if (MatteIsActive(slider_info,event.xbutton))
6044           {
6045             /*
6046               Track slider.
6047             */
6048             slider_info.active=MagickTrue;
6049             break;
6050           }
6051         if (MatteIsActive(north_info,event.xbutton))
6052           if (slider_info.id > 0)
6053             {
6054               /*
6055                 Move slider up.
6056               */
6057               north_info.raised=MagickFalse;
6058               slider_info.id--;
6059               state|=RedrawListState;
6060               break;
6061             }
6062         if (MatteIsActive(south_info,event.xbutton))
6063           if (slider_info.id < fonts)
6064             {
6065               /*
6066                 Move slider down.
6067               */
6068               south_info.raised=MagickFalse;
6069               slider_info.id++;
6070               state|=RedrawListState;
6071               break;
6072             }
6073         if (MatteIsActive(scroll_info,event.xbutton))
6074           {
6075             /*
6076               Move slider.
6077             */
6078             if (event.xbutton.y < slider_info.y)
6079               slider_info.id-=(visible_fonts-1);
6080             else
6081               slider_info.id+=(visible_fonts-1);
6082             state|=RedrawListState;
6083             break;
6084           }
6085         if (MatteIsActive(list_info,event.xbutton))
6086           {
6087             int
6088               id;
6089
6090             /*
6091               User pressed list matte.
6092             */
6093             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
6094               selection_info.height;
6095             if (id >= (int) fonts)
6096               break;
6097             (void) CopyMagickString(reply_info.text,fontlist[id],MaxTextExtent);
6098             reply_info.highlight=MagickFalse;
6099             reply_info.marker=reply_info.text;
6100             reply_info.cursor=reply_info.text+Extent(reply_info.text);
6101             XDrawMatteText(display,&windows->widget,&reply_info);
6102             state|=RedrawActionState;
6103             if (id == list_info.id)
6104               {
6105                 (void) CopyMagickString(glob_pattern,reply_info.text,
6106                   MaxTextExtent);
6107                 state|=UpdateListState;
6108               }
6109             selection_info.id=(~0);
6110             list_info.id=id;
6111             state|=RedrawListState;
6112             break;
6113           }
6114         if (MatteIsActive(back_info,event.xbutton))
6115           {
6116             /*
6117               User pressed Back button.
6118             */
6119             back_info.raised=MagickFalse;
6120             XDrawBeveledButton(display,&windows->widget,&back_info);
6121             break;
6122           }
6123         if (MatteIsActive(reset_info,event.xbutton))
6124           {
6125             /*
6126               User pressed Reset button.
6127             */
6128             reset_info.raised=MagickFalse;
6129             XDrawBeveledButton(display,&windows->widget,&reset_info);
6130             break;
6131           }
6132         if (MatteIsActive(action_info,event.xbutton))
6133           {
6134             /*
6135               User pressed action button.
6136             */
6137             action_info.raised=MagickFalse;
6138             XDrawBeveledButton(display,&windows->widget,&action_info);
6139             break;
6140           }
6141         if (MatteIsActive(cancel_info,event.xbutton))
6142           {
6143             /*
6144               User pressed Cancel button.
6145             */
6146             cancel_info.raised=MagickFalse;
6147             XDrawBeveledButton(display,&windows->widget,&cancel_info);
6148             break;
6149           }
6150         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
6151           break;
6152         if (event.xbutton.button != Button2)
6153           {
6154             static Time
6155               click_time;
6156
6157             /*
6158               Move text cursor to position of button press.
6159             */
6160             x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
6161             for (i=1; i <= Extent(reply_info.marker); i++)
6162               if (XTextWidth(font_info,reply_info.marker,i) > x)
6163                 break;
6164             reply_info.cursor=reply_info.marker+i-1;
6165             if (event.xbutton.time > (click_time+DoubleClick))
6166               reply_info.highlight=MagickFalse;
6167             else
6168               {
6169                 /*
6170                   Become the XA_PRIMARY selection owner.
6171                 */
6172                 (void) CopyMagickString(primary_selection,reply_info.text,
6173                   MaxTextExtent);
6174                 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
6175                   event.xbutton.time);
6176                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
6177                   windows->widget.id ? MagickTrue : MagickFalse;
6178               }
6179             XDrawMatteText(display,&windows->widget,&reply_info);
6180             click_time=event.xbutton.time;
6181             break;
6182           }
6183         /*
6184           Request primary selection.
6185         */
6186         (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
6187           windows->widget.id,event.xbutton.time);
6188         break;
6189       }
6190       case ButtonRelease:
6191       {
6192         if (windows->widget.mapped == MagickFalse)
6193           break;
6194         if (north_info.raised == MagickFalse)
6195           {
6196             /*
6197               User released up button.
6198             */
6199             delay=SuspendTime << 2;
6200             north_info.raised=MagickTrue;
6201             XDrawTriangleNorth(display,&windows->widget,&north_info);
6202           }
6203         if (south_info.raised == MagickFalse)
6204           {
6205             /*
6206               User released down button.
6207             */
6208             delay=SuspendTime << 2;
6209             south_info.raised=MagickTrue;
6210             XDrawTriangleSouth(display,&windows->widget,&south_info);
6211           }
6212         if (slider_info.active)
6213           {
6214             /*
6215               Stop tracking slider.
6216             */
6217             slider_info.active=MagickFalse;
6218             break;
6219           }
6220         if (back_info.raised == MagickFalse)
6221           {
6222             if (event.xbutton.window == windows->widget.id)
6223               if (MatteIsActive(back_info,event.xbutton))
6224                 {
6225                   (void) CopyMagickString(glob_pattern,back_pattern,
6226                     MaxTextExtent);
6227                   state|=UpdateListState;
6228                 }
6229             back_info.raised=MagickTrue;
6230             XDrawBeveledButton(display,&windows->widget,&back_info);
6231           }
6232         if (reset_info.raised == MagickFalse)
6233           {
6234             if (event.xbutton.window == windows->widget.id)
6235               if (MatteIsActive(reset_info,event.xbutton))
6236                 {
6237                   (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
6238                   (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
6239                   state|=UpdateListState;
6240                 }
6241             reset_info.raised=MagickTrue;
6242             XDrawBeveledButton(display,&windows->widget,&reset_info);
6243           }
6244         if (action_info.raised == MagickFalse)
6245           {
6246             if (event.xbutton.window == windows->widget.id)
6247               {
6248                 if (MatteIsActive(action_info,event.xbutton))
6249                   {
6250                     if (*reply_info.text == '\0')
6251                       (void) XBell(display,0);
6252                     else
6253                       state|=ExitState;
6254                   }
6255               }
6256             action_info.raised=MagickTrue;
6257             XDrawBeveledButton(display,&windows->widget,&action_info);
6258           }
6259         if (cancel_info.raised == MagickFalse)
6260           {
6261             if (event.xbutton.window == windows->widget.id)
6262               if (MatteIsActive(cancel_info,event.xbutton))
6263                 {
6264                   *reply_info.text='\0';
6265                   state|=ExitState;
6266                 }
6267             cancel_info.raised=MagickTrue;
6268             XDrawBeveledButton(display,&windows->widget,&cancel_info);
6269           }
6270         break;
6271       }
6272       case ClientMessage:
6273       {
6274         /*
6275           If client window delete message, exit.
6276         */
6277         if (event.xclient.message_type != windows->wm_protocols)
6278           break;
6279         if (*event.xclient.data.l == (int) windows->wm_take_focus)
6280           {
6281             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
6282               (Time) event.xclient.data.l[1]);
6283             break;
6284           }
6285         if (*event.xclient.data.l != (int) windows->wm_delete_window)
6286           break;
6287         if (event.xclient.window == windows->widget.id)
6288           {
6289             *reply_info.text='\0';
6290             state|=ExitState;
6291             break;
6292           }
6293         break;
6294       }
6295       case ConfigureNotify:
6296       {
6297         /*
6298           Update widget configuration.
6299         */
6300         if (event.xconfigure.window != windows->widget.id)
6301           break;
6302         if ((event.xconfigure.width == (int) windows->widget.width) &&
6303             (event.xconfigure.height == (int) windows->widget.height))
6304           break;
6305         windows->widget.width=(unsigned int)
6306           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
6307         windows->widget.height=(unsigned int)
6308           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
6309         state|=UpdateConfigurationState;
6310         break;
6311       }
6312       case EnterNotify:
6313       {
6314         if (event.xcrossing.window != windows->widget.id)
6315           break;
6316         state&=(~InactiveWidgetState);
6317         break;
6318       }
6319       case Expose:
6320       {
6321         if (event.xexpose.window != windows->widget.id)
6322           break;
6323         if (event.xexpose.count != 0)
6324           break;
6325         state|=RedrawWidgetState;
6326         break;
6327       }
6328       case KeyPress:
6329       {
6330         static char
6331           command[MaxTextExtent];
6332
6333         static int
6334           length;
6335
6336         static KeySym
6337           key_symbol;
6338
6339         /*
6340           Respond to a user key press.
6341         */
6342         if (event.xkey.window != windows->widget.id)
6343           break;
6344         length=XLookupString((XKeyEvent *) &event.xkey,command,
6345           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
6346         *(command+length)='\0';
6347         if (AreaIsActive(scroll_info,event.xkey))
6348           {
6349             /*
6350               Move slider.
6351             */
6352             switch ((int) key_symbol)
6353             {
6354               case XK_Home:
6355               case XK_KP_Home:
6356               {
6357                 slider_info.id=0;
6358                 break;
6359               }
6360               case XK_Up:
6361               case XK_KP_Up:
6362               {
6363                 slider_info.id--;
6364                 break;
6365               }
6366               case XK_Down:
6367               case XK_KP_Down:
6368               {
6369                 slider_info.id++;
6370                 break;
6371               }
6372               case XK_Prior:
6373               case XK_KP_Prior:
6374               {
6375                 slider_info.id-=visible_fonts;
6376                 break;
6377               }
6378               case XK_Next:
6379               case XK_KP_Next:
6380               {
6381                 slider_info.id+=visible_fonts;
6382                 break;
6383               }
6384               case XK_End:
6385               case XK_KP_End:
6386               {
6387                 slider_info.id=fonts;
6388                 break;
6389               }
6390             }
6391             state|=RedrawListState;
6392             break;
6393           }
6394         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
6395           {
6396             /*
6397               Read new font or glob patterm.
6398             */
6399             if (*reply_info.text == '\0')
6400               break;
6401             (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
6402             (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
6403             state|=UpdateListState;
6404             break;
6405           }
6406         if (key_symbol == XK_Control_L)
6407           {
6408             state|=ControlState;
6409             break;
6410           }
6411         if (state & ControlState)
6412           switch ((int) key_symbol)
6413           {
6414             case XK_u:
6415             case XK_U:
6416             {
6417               /*
6418                 Erase the entire line of text.
6419               */
6420               *reply_info.text='\0';
6421               reply_info.cursor=reply_info.text;
6422               reply_info.marker=reply_info.text;
6423               reply_info.highlight=MagickFalse;
6424               break;
6425             }
6426             default:
6427               break;
6428           }
6429         XEditText(display,&reply_info,key_symbol,command,state);
6430         XDrawMatteText(display,&windows->widget,&reply_info);
6431         state|=JumpListState;
6432         break;
6433       }
6434       case KeyRelease:
6435       {
6436         static char
6437           command[MaxTextExtent];
6438
6439         static KeySym
6440           key_symbol;
6441
6442         /*
6443           Respond to a user key release.
6444         */
6445         if (event.xkey.window != windows->widget.id)
6446           break;
6447         (void) XLookupString((XKeyEvent *) &event.xkey,command,
6448           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
6449         if (key_symbol == XK_Control_L)
6450           state&=(~ControlState);
6451         break;
6452       }
6453       case LeaveNotify:
6454       {
6455         if (event.xcrossing.window != windows->widget.id)
6456           break;
6457         state|=InactiveWidgetState;
6458         break;
6459       }
6460       case MapNotify:
6461       {
6462         mask&=(~CWX);
6463         mask&=(~CWY);
6464         break;
6465       }
6466       case MotionNotify:
6467       {
6468         /*
6469           Discard pending button motion events.
6470         */
6471         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
6472         if (slider_info.active)
6473           {
6474             /*
6475               Move slider matte.
6476             */
6477             slider_info.y=event.xmotion.y-
6478               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
6479             if (slider_info.y < slider_info.min_y)
6480               slider_info.y=slider_info.min_y;
6481             if (slider_info.y > slider_info.max_y)
6482               slider_info.y=slider_info.max_y;
6483             slider_info.id=0;
6484             if (slider_info.y != slider_info.min_y)
6485               slider_info.id=(fonts*(slider_info.y-slider_info.min_y+1))/
6486                 (slider_info.max_y-slider_info.min_y+1);
6487             state|=RedrawListState;
6488             break;
6489           }
6490         if (state & InactiveWidgetState)
6491           break;
6492         if (back_info.raised == MatteIsActive(back_info,event.xmotion))
6493           {
6494             /*
6495               Back button status changed.
6496             */
6497             back_info.raised=!back_info.raised;
6498             XDrawBeveledButton(display,&windows->widget,&back_info);
6499             break;
6500           }
6501         if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
6502           {
6503             /*
6504               Reset button status changed.
6505             */
6506             reset_info.raised=!reset_info.raised;
6507             XDrawBeveledButton(display,&windows->widget,&reset_info);
6508             break;
6509           }
6510         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
6511           {
6512             /*
6513               Action button status changed.
6514             */
6515             action_info.raised=action_info.raised == MagickFalse ?
6516               MagickTrue : MagickFalse;
6517             XDrawBeveledButton(display,&windows->widget,&action_info);
6518             break;
6519           }
6520         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
6521           {
6522             /*
6523               Cancel button status changed.
6524             */
6525             cancel_info.raised=cancel_info.raised == MagickFalse ?
6526               MagickTrue : MagickFalse;
6527             XDrawBeveledButton(display,&windows->widget,&cancel_info);
6528             break;
6529           }
6530         break;
6531       }
6532       case SelectionClear:
6533       {
6534         reply_info.highlight=MagickFalse;
6535         XDrawMatteText(display,&windows->widget,&reply_info);
6536         break;
6537       }
6538       case SelectionNotify:
6539       {
6540         Atom
6541           type;
6542
6543         int
6544           format;
6545
6546         unsigned char
6547           *data;
6548
6549         unsigned long
6550           after,
6551           length;
6552
6553         /*
6554           Obtain response from primary selection.
6555         */
6556         if (event.xselection.property == (Atom) None)
6557           break;
6558         status=XGetWindowProperty(display,event.xselection.requestor,
6559           event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
6560           &format,&length,&after,&data);
6561         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
6562             (length == 0))
6563           break;
6564         if ((Extent(reply_info.text)+length) >= MaxTextExtent)
6565           (void) XBell(display,0);
6566         else
6567           {
6568             /*
6569               Insert primary selection in reply text.
6570             */
6571             *(data+length)='\0';
6572             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
6573               state);
6574             XDrawMatteText(display,&windows->widget,&reply_info);
6575             state|=JumpListState;
6576             state|=RedrawActionState;
6577           }
6578         (void) XFree((void *) data);
6579         break;
6580       }
6581       case SelectionRequest:
6582       {
6583         XSelectionEvent
6584           notify;
6585
6586         XSelectionRequestEvent
6587           *request;
6588
6589         /*
6590           Set XA_PRIMARY selection.
6591         */
6592         request=(&(event.xselectionrequest));
6593         (void) XChangeProperty(request->display,request->requestor,
6594           request->property,request->target,8,PropModeReplace,
6595           (unsigned char *) primary_selection,Extent(primary_selection));
6596         notify.type=SelectionNotify;
6597         notify.display=request->display;
6598         notify.requestor=request->requestor;
6599         notify.selection=request->selection;
6600         notify.target=request->target;
6601         notify.time=request->time;
6602         if (request->property == None)
6603           notify.property=request->target;
6604         else
6605           notify.property=request->property;
6606         (void) XSendEvent(request->display,request->requestor,False,0,
6607           (XEvent *) &notify);
6608       }
6609       default:
6610         break;
6611     }
6612   } while ((state & ExitState) == 0);
6613   XSetCursorState(display,windows,MagickFalse);
6614   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
6615   XCheckRefreshWindows(display,windows);
6616   /*
6617     Free font list.
6618   */
6619   (void) XFreeFontNames(listhead);
6620   fontlist=(char **) RelinquishMagickMemory(fontlist);
6621 }
6622 \f
6623 /*
6624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6625 %                                                                             %
6626 %                                                                             %
6627 %                                                                             %
6628 %   X I n f o W i d g e t                                                     %
6629 %                                                                             %
6630 %                                                                             %
6631 %                                                                             %
6632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6633 %
6634 %  XInfoWidget() displays text in the Info widget.  The purpose is to inform
6635 %  the user that what activity is currently being performed (e.g. reading
6636 %  an image, rotating an image, etc.).
6637 %
6638 %  The format of the XInfoWidget method is:
6639 %
6640 %      void XInfoWidget(Display *display,XWindows *windows,const char *activity)
6641 %
6642 %  A description of each parameter follows:
6643 %
6644 %    o display: Specifies a connection to an X server;  returned from
6645 %      XOpenDisplay.
6646 %
6647 %    o window: Specifies a pointer to a XWindows structure.
6648 %
6649 %    o activity: This character string reflects the current activity and is
6650 %      displayed in the Info widget.
6651 %
6652 */
6653 MagickExport void XInfoWidget(Display *display,XWindows *windows,
6654   const char *activity)
6655 {
6656   unsigned int
6657     height,
6658     margin,
6659     width;
6660
6661   XFontStruct
6662     *font_info;
6663
6664   XWindowChanges
6665     window_changes;
6666
6667   /*
6668     Map Info widget.
6669   */
6670   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
6671   assert(display != (Display *) NULL);
6672   assert(windows != (XWindows *) NULL);
6673   assert(activity != (char *) NULL);
6674   font_info=windows->info.font_info;
6675   width=WidgetTextWidth(font_info,(char *) activity)+((3*QuantumMargin) >> 1)+4;
6676   height=(unsigned int) (((6*(font_info->ascent+font_info->descent)) >> 2)+4);
6677   if ((windows->info.width != width) || (windows->info.height != height))
6678     {
6679       /*
6680         Size Info widget to accommodate the activity text.
6681       */
6682       windows->info.width=width;
6683       windows->info.height=height;
6684       window_changes.width=(int) width;
6685       window_changes.height=(int) height;
6686       (void) XReconfigureWMWindow(display,windows->info.id,windows->info.screen,
6687         (unsigned int) (CWWidth | CWHeight),&window_changes);
6688     }
6689   if (windows->info.mapped == MagickFalse)
6690     {
6691       (void) XMapRaised(display,windows->info.id);
6692       windows->info.mapped=MagickTrue;
6693     }
6694   /*
6695     Initialize Info matte information.
6696   */
6697   height=(unsigned int) (font_info->ascent+font_info->descent);
6698   XGetWidgetInfo(activity,&monitor_info);
6699   monitor_info.bevel_width--;
6700   margin=monitor_info.bevel_width+((windows->info.height-height) >> 1)-2;
6701   monitor_info.center=MagickFalse;
6702   monitor_info.x=(int) margin;
6703   monitor_info.y=(int) margin;
6704   monitor_info.width=windows->info.width-(margin << 1);
6705   monitor_info.height=windows->info.height-(margin << 1)+1;
6706   /*
6707     Draw Info widget.
6708   */
6709   monitor_info.raised=MagickFalse;
6710   XDrawBeveledMatte(display,&windows->info,&monitor_info);
6711   monitor_info.raised=MagickTrue;
6712   XDrawWidgetText(display,&windows->info,&monitor_info);
6713 }
6714 \f
6715 /*
6716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6717 %                                                                             %
6718 %                                                                             %
6719 %                                                                             %
6720 %   X L i s t B r o w s e r W i d g e t                                       %
6721 %                                                                             %
6722 %                                                                             %
6723 %                                                                             %
6724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6725 %
6726 %  XListBrowserWidget() displays a List Browser widget with a query to the
6727 %  user.  The user keys a reply or select a reply from the list.  Finally, the
6728 %  user presses the Action or Cancel button to exit.  The typed text is
6729 %  returned as the reply function parameter.
6730 %
6731 %  The format of the XListBrowserWidget method is:
6732 %
6733 %      void XListBrowserWidget(Display *display,XWindows *windows,
6734 %        XWindowInfo *window_info,const char **list,const char *action,
6735 %        const char *query,char *reply)
6736 %
6737 %  A description of each parameter follows:
6738 %
6739 %    o display: Specifies a connection to an X server;  returned from
6740 %      XOpenDisplay.
6741 %
6742 %    o window: Specifies a pointer to a XWindows structure.
6743 %
6744 %    o list: Specifies a pointer to an array of strings.  The user can
6745 %      select from these strings as a possible reply value.
6746 %
6747 %    o action: Specifies a pointer to the action of this widget.
6748 %
6749 %    o query: Specifies a pointer to the query to present to the user.
6750 %
6751 %    o reply: the response from the user is returned in this parameter.
6752 %
6753 */
6754 MagickExport void XListBrowserWidget(Display *display,XWindows *windows,
6755   XWindowInfo *window_info,const char **list,const char *action,
6756   const char *query,char *reply)
6757 {
6758 #define CancelButtonText  "Cancel"
6759
6760   char
6761     primary_selection[MaxTextExtent];
6762
6763   int
6764     x;
6765
6766   register int
6767     i;
6768
6769   static MagickStatusType
6770     mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
6771
6772   Status
6773     status;
6774
6775   unsigned int
6776     entries,
6777     height,
6778     text_width,
6779     visible_entries,
6780     width;
6781
6782   size_t
6783     delay,
6784     state;
6785
6786   XEvent
6787     event;
6788
6789   XFontStruct
6790     *font_info;
6791
6792   XTextProperty
6793     window_name;
6794
6795   XWidgetInfo
6796     action_info,
6797     cancel_info,
6798     expose_info,
6799     list_info,
6800     north_info,
6801     reply_info,
6802     scroll_info,
6803     selection_info,
6804     slider_info,
6805     south_info,
6806     text_info;
6807
6808   XWindowChanges
6809     window_changes;
6810
6811   /*
6812     Count the number of entries in the list.
6813   */
6814   assert(display != (Display *) NULL);
6815   assert(windows != (XWindows *) NULL);
6816   assert(window_info != (XWindowInfo *) NULL);
6817   assert(list != (const char **) NULL);
6818   assert(action != (char *) NULL);
6819   assert(query != (char *) NULL);
6820   assert(reply != (char *) NULL);
6821   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
6822   XSetCursorState(display,windows,MagickTrue);
6823   XCheckRefreshWindows(display,windows);
6824   if (list == (const char **) NULL)
6825     {
6826       XNoticeWidget(display,windows,"No text to browse:",(char *) NULL);
6827       return;
6828     }
6829   for (entries=0; ; entries++)
6830     if (list[entries] == (char *) NULL)
6831       break;
6832   /*
6833     Determine Font Browser widget attributes.
6834   */
6835   font_info=window_info->font_info;
6836   text_width=WidgetTextWidth(font_info,(char *) query);
6837   for (i=0; i < (int) entries; i++)
6838     if (WidgetTextWidth(font_info,(char *) list[i]) > text_width)
6839       text_width=WidgetTextWidth(font_info,(char *) list[i]);
6840   width=WidgetTextWidth(font_info,(char *) action);
6841   if (WidgetTextWidth(font_info,CancelButtonText) > width)
6842     width=WidgetTextWidth(font_info,CancelButtonText);
6843   width+=QuantumMargin;
6844   height=(unsigned int) (font_info->ascent+font_info->descent);
6845   /*
6846     Position List Browser widget.
6847   */
6848   window_info->width=(unsigned int) MagickMin((int) text_width,(int)
6849     MaxTextWidth)+((9*QuantumMargin) >> 1);
6850   window_info->min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
6851   if (window_info->width < window_info->min_width)
6852     window_info->width=window_info->min_width;
6853   window_info->height=(unsigned int)
6854     (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
6855   window_info->min_height=(unsigned int)
6856     (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
6857   if (window_info->height < window_info->min_height)
6858     window_info->height=window_info->min_height;
6859   XConstrainWindowPosition(display,window_info);
6860   /*
6861     Map List Browser widget.
6862   */
6863   (void) CopyMagickString(window_info->name,"Browse",MaxTextExtent);
6864   status=XStringListToTextProperty(&window_info->name,1,&window_name);
6865   if (status != False)
6866     {
6867       XSetWMName(display,window_info->id,&window_name);
6868       XSetWMIconName(display,windows->widget.id,&window_name);
6869       (void) XFree((void *) window_name.value);
6870     }
6871   window_changes.width=(int) window_info->width;
6872   window_changes.height=(int) window_info->height;
6873   window_changes.x=window_info->x;
6874   window_changes.y=window_info->y;
6875   (void) XReconfigureWMWindow(display,window_info->id,window_info->screen,mask,
6876     &window_changes);
6877   (void) XMapRaised(display,window_info->id);
6878   window_info->mapped=MagickFalse;
6879   /*
6880     Respond to X events.
6881   */
6882   XGetWidgetInfo((char *) NULL,&slider_info);
6883   XGetWidgetInfo((char *) NULL,&north_info);
6884   XGetWidgetInfo((char *) NULL,&south_info);
6885   XGetWidgetInfo((char *) NULL,&expose_info);
6886   visible_entries=0;
6887   delay=SuspendTime << 2;
6888   state=UpdateConfigurationState;
6889   do
6890   {
6891     if (state & UpdateConfigurationState)
6892       {
6893         int
6894           id;
6895
6896         /*
6897           Initialize button information.
6898         */
6899         XGetWidgetInfo(CancelButtonText,&cancel_info);
6900         cancel_info.width=width;
6901         cancel_info.height=(unsigned int) ((3*height) >> 1);
6902         cancel_info.x=(int)
6903           (window_info->width-cancel_info.width-QuantumMargin-2);
6904         cancel_info.y=(int)
6905           (window_info->height-cancel_info.height-QuantumMargin);
6906         XGetWidgetInfo(action,&action_info);
6907         action_info.width=width;
6908         action_info.height=(unsigned int) ((3*height) >> 1);
6909         action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
6910           (action_info.bevel_width << 1));
6911         action_info.y=cancel_info.y;
6912         /*
6913           Initialize reply information.
6914         */
6915         XGetWidgetInfo(reply,&reply_info);
6916         reply_info.raised=MagickFalse;
6917         reply_info.bevel_width--;
6918         reply_info.width=window_info->width-((4*QuantumMargin) >> 1);
6919         reply_info.height=height << 1;
6920         reply_info.x=QuantumMargin;
6921         reply_info.y=action_info.y-reply_info.height-QuantumMargin;
6922         /*
6923           Initialize scroll information.
6924         */
6925         XGetWidgetInfo((char *) NULL,&scroll_info);
6926         scroll_info.bevel_width--;
6927         scroll_info.width=height;
6928         scroll_info.height=(unsigned int)
6929           (reply_info.y-((6*QuantumMargin) >> 1)-height);
6930         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
6931         scroll_info.y=((5*QuantumMargin) >> 1)+height-reply_info.bevel_width;
6932         scroll_info.raised=MagickFalse;
6933         scroll_info.trough=MagickTrue;
6934         north_info=scroll_info;
6935         north_info.raised=MagickTrue;
6936         north_info.width-=(north_info.bevel_width << 1);
6937         north_info.height=north_info.width-1;
6938         north_info.x+=north_info.bevel_width;
6939         north_info.y+=north_info.bevel_width;
6940         south_info=north_info;
6941         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
6942           south_info.height;
6943         id=slider_info.id;
6944         slider_info=north_info;
6945         slider_info.id=id;
6946         slider_info.width-=2;
6947         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
6948           slider_info.bevel_width+2;
6949         slider_info.height=scroll_info.height-((slider_info.min_y-
6950           scroll_info.y+1) << 1)+4;
6951         visible_entries=scroll_info.height/(height+(height >> 3));
6952         if (entries > visible_entries)
6953           slider_info.height=(visible_entries*slider_info.height)/entries;
6954         slider_info.max_y=south_info.y-south_info.bevel_width-
6955           slider_info.bevel_width-2;
6956         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
6957         slider_info.y=slider_info.min_y;
6958         expose_info=scroll_info;
6959         expose_info.y=slider_info.y;
6960         /*
6961           Initialize list information.
6962         */
6963         XGetWidgetInfo((char *) NULL,&list_info);
6964         list_info.raised=MagickFalse;
6965         list_info.bevel_width--;
6966         list_info.width=(unsigned int)
6967           (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
6968         list_info.height=scroll_info.height;
6969         list_info.x=reply_info.x;
6970         list_info.y=scroll_info.y;
6971         if (window_info->mapped == MagickFalse)
6972           for (i=0; i < (int) entries; i++)
6973             if (LocaleCompare(list[i],reply) == 0)
6974               {
6975                 list_info.id=i;
6976                 slider_info.id=i-(visible_entries >> 1);
6977                 if (slider_info.id < 0)
6978                   slider_info.id=0;
6979               }
6980         /*
6981           Initialize text information.
6982         */
6983         XGetWidgetInfo(query,&text_info);
6984         text_info.width=reply_info.width;
6985         text_info.height=height;
6986         text_info.x=list_info.x-(QuantumMargin >> 1);
6987         text_info.y=QuantumMargin;
6988         /*
6989           Initialize selection information.
6990         */
6991         XGetWidgetInfo((char *) NULL,&selection_info);
6992         selection_info.center=MagickFalse;
6993         selection_info.width=list_info.width;
6994         selection_info.height=(unsigned int) ((9*height) >> 3);
6995         selection_info.x=list_info.x;
6996         state&=(~UpdateConfigurationState);
6997       }
6998     if (state & RedrawWidgetState)
6999       {
7000         /*
7001           Redraw List Browser window.
7002         */
7003         XDrawWidgetText(display,window_info,&text_info);
7004         XDrawBeveledMatte(display,window_info,&list_info);
7005         XDrawBeveledMatte(display,window_info,&scroll_info);
7006         XDrawTriangleNorth(display,window_info,&north_info);
7007         XDrawBeveledButton(display,window_info,&slider_info);
7008         XDrawTriangleSouth(display,window_info,&south_info);
7009         XDrawBeveledMatte(display,window_info,&reply_info);
7010         XDrawMatteText(display,window_info,&reply_info);
7011         XDrawBeveledButton(display,window_info,&action_info);
7012         XDrawBeveledButton(display,window_info,&cancel_info);
7013         XHighlightWidget(display,window_info,BorderOffset,BorderOffset);
7014         selection_info.id=(~0);
7015         state|=RedrawActionState;
7016         state|=RedrawListState;
7017         state&=(~RedrawWidgetState);
7018       }
7019     if (state & RedrawListState)
7020       {
7021         /*
7022           Determine slider id and position.
7023         */
7024         if (slider_info.id >= (int) (entries-visible_entries))
7025           slider_info.id=(int) (entries-visible_entries);
7026         if ((slider_info.id < 0) || (entries <= visible_entries))
7027           slider_info.id=0;
7028         slider_info.y=slider_info.min_y;
7029         if (entries > 0)
7030           slider_info.y+=
7031             slider_info.id*(slider_info.max_y-slider_info.min_y+1)/entries;
7032         if (slider_info.id != selection_info.id)
7033           {
7034             /*
7035               Redraw scroll bar and file names.
7036             */
7037             selection_info.id=slider_info.id;
7038             selection_info.y=list_info.y+(height >> 3)+2;
7039             for (i=0; i < (int) visible_entries; i++)
7040             {
7041               selection_info.raised=(slider_info.id+i) != list_info.id ?
7042                 MagickTrue : MagickFalse;
7043               selection_info.text=(char *) NULL;
7044               if ((slider_info.id+i) < (int) entries)
7045                 selection_info.text=(char *) list[slider_info.id+i];
7046               XDrawWidgetText(display,window_info,&selection_info);
7047               selection_info.y+=(int) selection_info.height;
7048             }
7049             /*
7050               Update slider.
7051             */
7052             if (slider_info.y > expose_info.y)
7053               {
7054                 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
7055                 expose_info.y=slider_info.y-expose_info.height-
7056                   slider_info.bevel_width-1;
7057               }
7058             else
7059               {
7060                 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
7061                 expose_info.y=slider_info.y+slider_info.height+
7062                   slider_info.bevel_width+1;
7063               }
7064             XDrawTriangleNorth(display,window_info,&north_info);
7065             XDrawMatte(display,window_info,&expose_info);
7066             XDrawBeveledButton(display,window_info,&slider_info);
7067             XDrawTriangleSouth(display,window_info,&south_info);
7068             expose_info.y=slider_info.y;
7069           }
7070         state&=(~RedrawListState);
7071       }
7072     /*
7073       Wait for next event.
7074     */
7075     if (north_info.raised && south_info.raised)
7076       (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
7077     else
7078       {
7079         /*
7080           Brief delay before advancing scroll bar.
7081         */
7082         XDelay(display,delay);
7083         delay=SuspendTime;
7084         (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
7085         if (north_info.raised == MagickFalse)
7086           if (slider_info.id > 0)
7087             {
7088               /*
7089                 Move slider up.
7090               */
7091               slider_info.id--;
7092               state|=RedrawListState;
7093             }
7094         if (south_info.raised == MagickFalse)
7095           if (slider_info.id < (int) entries)
7096             {
7097               /*
7098                 Move slider down.
7099               */
7100               slider_info.id++;
7101               state|=RedrawListState;
7102             }
7103         if (event.type != ButtonRelease)
7104           continue;
7105       }
7106     switch (event.type)
7107     {
7108       case ButtonPress:
7109       {
7110         if (MatteIsActive(slider_info,event.xbutton))
7111           {
7112             /*
7113               Track slider.
7114             */
7115             slider_info.active=MagickTrue;
7116             break;
7117           }
7118         if (MatteIsActive(north_info,event.xbutton))
7119           if (slider_info.id > 0)
7120             {
7121               /*
7122                 Move slider up.
7123               */
7124               north_info.raised=MagickFalse;
7125               slider_info.id--;
7126               state|=RedrawListState;
7127               break;
7128             }
7129         if (MatteIsActive(south_info,event.xbutton))
7130           if (slider_info.id < (int) entries)
7131             {
7132               /*
7133                 Move slider down.
7134               */
7135               south_info.raised=MagickFalse;
7136               slider_info.id++;
7137               state|=RedrawListState;
7138               break;
7139             }
7140         if (MatteIsActive(scroll_info,event.xbutton))
7141           {
7142             /*
7143               Move slider.
7144             */
7145             if (event.xbutton.y < slider_info.y)
7146               slider_info.id-=(visible_entries-1);
7147             else
7148               slider_info.id+=(visible_entries-1);
7149             state|=RedrawListState;
7150             break;
7151           }
7152         if (MatteIsActive(list_info,event.xbutton))
7153           {
7154             int
7155               id;
7156
7157             /*
7158               User pressed list matte.
7159             */
7160             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
7161               selection_info.height;
7162             if (id >= (int) entries)
7163               break;
7164             (void) CopyMagickString(reply_info.text,list[id],MaxTextExtent);
7165             reply_info.highlight=MagickFalse;
7166             reply_info.marker=reply_info.text;
7167             reply_info.cursor=reply_info.text+Extent(reply_info.text);
7168             XDrawMatteText(display,window_info,&reply_info);
7169             selection_info.id=(~0);
7170             if (id == list_info.id)
7171               {
7172                 action_info.raised=MagickFalse;
7173                 XDrawBeveledButton(display,window_info,&action_info);
7174                 state|=ExitState;
7175               }
7176             list_info.id=id;
7177             state|=RedrawListState;
7178             break;
7179           }
7180         if (MatteIsActive(action_info,event.xbutton))
7181           {
7182             /*
7183               User pressed action button.
7184             */
7185             action_info.raised=MagickFalse;
7186             XDrawBeveledButton(display,window_info,&action_info);
7187             break;
7188           }
7189         if (MatteIsActive(cancel_info,event.xbutton))
7190           {
7191             /*
7192               User pressed Cancel button.
7193             */
7194             cancel_info.raised=MagickFalse;
7195             XDrawBeveledButton(display,window_info,&cancel_info);
7196             break;
7197           }
7198         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
7199           break;
7200         if (event.xbutton.button != Button2)
7201           {
7202             static Time
7203               click_time;
7204
7205             /*
7206               Move text cursor to position of button press.
7207             */
7208             x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
7209             for (i=1; i <= Extent(reply_info.marker); i++)
7210               if (XTextWidth(font_info,reply_info.marker,i) > x)
7211                 break;
7212             reply_info.cursor=reply_info.marker+i-1;
7213             if (event.xbutton.time > (click_time+DoubleClick))
7214               reply_info.highlight=MagickFalse;
7215             else
7216               {
7217                 /*
7218                   Become the XA_PRIMARY selection owner.
7219                 */
7220                 (void) CopyMagickString(primary_selection,reply_info.text,
7221                   MaxTextExtent);
7222                 (void) XSetSelectionOwner(display,XA_PRIMARY,window_info->id,
7223                   event.xbutton.time);
7224                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
7225                   window_info->id ? MagickTrue : MagickFalse;
7226               }
7227             XDrawMatteText(display,window_info,&reply_info);
7228             click_time=event.xbutton.time;
7229             break;
7230           }
7231         /*
7232           Request primary selection.
7233         */
7234         (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
7235           window_info->id,event.xbutton.time);
7236         break;
7237       }
7238       case ButtonRelease:
7239       {
7240         if (window_info->mapped == MagickFalse)
7241           break;
7242         if (north_info.raised == MagickFalse)
7243           {
7244             /*
7245               User released up button.
7246             */
7247             delay=SuspendTime << 2;
7248             north_info.raised=MagickTrue;
7249             XDrawTriangleNorth(display,window_info,&north_info);
7250           }
7251         if (south_info.raised == MagickFalse)
7252           {
7253             /*
7254               User released down button.
7255             */
7256             delay=SuspendTime << 2;
7257             south_info.raised=MagickTrue;
7258             XDrawTriangleSouth(display,window_info,&south_info);
7259           }
7260         if (slider_info.active)
7261           {
7262             /*
7263               Stop tracking slider.
7264             */
7265             slider_info.active=MagickFalse;
7266             break;
7267           }
7268         if (action_info.raised == MagickFalse)
7269           {
7270             if (event.xbutton.window == window_info->id)
7271               {
7272                 if (MatteIsActive(action_info,event.xbutton))
7273                   {
7274                     if (*reply_info.text == '\0')
7275                       (void) XBell(display,0);
7276                     else
7277                       state|=ExitState;
7278                   }
7279               }
7280             action_info.raised=MagickTrue;
7281             XDrawBeveledButton(display,window_info,&action_info);
7282           }
7283         if (cancel_info.raised == MagickFalse)
7284           {
7285             if (event.xbutton.window == window_info->id)
7286               if (MatteIsActive(cancel_info,event.xbutton))
7287                 {
7288                   *reply_info.text='\0';
7289                   state|=ExitState;
7290                 }
7291             cancel_info.raised=MagickTrue;
7292             XDrawBeveledButton(display,window_info,&cancel_info);
7293           }
7294         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
7295           break;
7296         break;
7297       }
7298       case ClientMessage:
7299       {
7300         /*
7301           If client window delete message, exit.
7302         */
7303         if (event.xclient.message_type != windows->wm_protocols)
7304           break;
7305         if (*event.xclient.data.l == (int) windows->wm_take_focus)
7306           {
7307             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
7308               (Time) event.xclient.data.l[1]);
7309             break;
7310           }
7311         if (*event.xclient.data.l != (int) windows->wm_delete_window)
7312           break;
7313         if (event.xclient.window == window_info->id)
7314           {
7315             *reply_info.text='\0';
7316             state|=ExitState;
7317             break;
7318           }
7319         break;
7320       }
7321       case ConfigureNotify:
7322       {
7323         /*
7324           Update widget configuration.
7325         */
7326         if (event.xconfigure.window != window_info->id)
7327           break;
7328         if ((event.xconfigure.width == (int) window_info->width) &&
7329             (event.xconfigure.height == (int) window_info->height))
7330           break;
7331         window_info->width=(unsigned int)
7332           MagickMax(event.xconfigure.width,(int) window_info->min_width);
7333         window_info->height=(unsigned int)
7334           MagickMax(event.xconfigure.height,(int) window_info->min_height);
7335         state|=UpdateConfigurationState;
7336         break;
7337       }
7338       case EnterNotify:
7339       {
7340         if (event.xcrossing.window != window_info->id)
7341           break;
7342         state&=(~InactiveWidgetState);
7343         break;
7344       }
7345       case Expose:
7346       {
7347         if (event.xexpose.window != window_info->id)
7348           break;
7349         if (event.xexpose.count != 0)
7350           break;
7351         state|=RedrawWidgetState;
7352         break;
7353       }
7354       case KeyPress:
7355       {
7356         static char
7357           command[MaxTextExtent];
7358
7359         static int
7360           length;
7361
7362         static KeySym
7363           key_symbol;
7364
7365         /*
7366           Respond to a user key press.
7367         */
7368         if (event.xkey.window != window_info->id)
7369           break;
7370         length=XLookupString((XKeyEvent *) &event.xkey,command,
7371           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
7372         *(command+length)='\0';
7373         if (AreaIsActive(scroll_info,event.xkey))
7374           {
7375             /*
7376               Move slider.
7377             */
7378             switch ((int) key_symbol)
7379             {
7380               case XK_Home:
7381               case XK_KP_Home:
7382               {
7383                 slider_info.id=0;
7384                 break;
7385               }
7386               case XK_Up:
7387               case XK_KP_Up:
7388               {
7389                 slider_info.id--;
7390                 break;
7391               }
7392               case XK_Down:
7393               case XK_KP_Down:
7394               {
7395                 slider_info.id++;
7396                 break;
7397               }
7398               case XK_Prior:
7399               case XK_KP_Prior:
7400               {
7401                 slider_info.id-=visible_entries;
7402                 break;
7403               }
7404               case XK_Next:
7405               case XK_KP_Next:
7406               {
7407                 slider_info.id+=visible_entries;
7408                 break;
7409               }
7410               case XK_End:
7411               case XK_KP_End:
7412               {
7413                 slider_info.id=(int) entries;
7414                 break;
7415               }
7416             }
7417             state|=RedrawListState;
7418             break;
7419           }
7420         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
7421           {
7422             /*
7423               Read new entry.
7424             */
7425             if (*reply_info.text == '\0')
7426               break;
7427             action_info.raised=MagickFalse;
7428             XDrawBeveledButton(display,window_info,&action_info);
7429             state|=ExitState;
7430             break;
7431           }
7432         if (key_symbol == XK_Control_L)
7433           {
7434             state|=ControlState;
7435             break;
7436           }
7437         if (state & ControlState)
7438           switch ((int) key_symbol)
7439           {
7440             case XK_u:
7441             case XK_U:
7442             {
7443               /*
7444                 Erase the entire line of text.
7445               */
7446               *reply_info.text='\0';
7447               reply_info.cursor=reply_info.text;
7448               reply_info.marker=reply_info.text;
7449               reply_info.highlight=MagickFalse;
7450               break;
7451             }
7452             default:
7453               break;
7454           }
7455         XEditText(display,&reply_info,key_symbol,command,state);
7456         XDrawMatteText(display,window_info,&reply_info);
7457         break;
7458       }
7459       case KeyRelease:
7460       {
7461         static char
7462           command[MaxTextExtent];
7463
7464         static KeySym
7465           key_symbol;
7466
7467         /*
7468           Respond to a user key release.
7469         */
7470         if (event.xkey.window != window_info->id)
7471           break;
7472         (void) XLookupString((XKeyEvent *) &event.xkey,command,
7473           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
7474         if (key_symbol == XK_Control_L)
7475           state&=(~ControlState);
7476         break;
7477       }
7478       case LeaveNotify:
7479       {
7480         if (event.xcrossing.window != window_info->id)
7481           break;
7482         state|=InactiveWidgetState;
7483         break;
7484       }
7485       case MapNotify:
7486       {
7487         mask&=(~CWX);
7488         mask&=(~CWY);
7489         break;
7490       }
7491       case MotionNotify:
7492       {
7493         /*
7494           Discard pending button motion events.
7495         */
7496         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
7497         if (slider_info.active)
7498           {
7499             /*
7500               Move slider matte.
7501             */
7502             slider_info.y=event.xmotion.y-
7503               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
7504             if (slider_info.y < slider_info.min_y)
7505               slider_info.y=slider_info.min_y;
7506             if (slider_info.y > slider_info.max_y)
7507               slider_info.y=slider_info.max_y;
7508             slider_info.id=0;
7509             if (slider_info.y != slider_info.min_y)
7510               slider_info.id=(int) ((entries*(slider_info.y-
7511                 slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
7512             state|=RedrawListState;
7513             break;
7514           }
7515         if (state & InactiveWidgetState)
7516           break;
7517         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
7518           {
7519             /*
7520               Action button status changed.
7521             */
7522             action_info.raised=action_info.raised == MagickFalse ?
7523               MagickTrue : MagickFalse;
7524             XDrawBeveledButton(display,window_info,&action_info);
7525             break;
7526           }
7527         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
7528           {
7529             /*
7530               Cancel button status changed.
7531             */
7532             cancel_info.raised=cancel_info.raised == MagickFalse ?
7533               MagickTrue : MagickFalse;
7534             XDrawBeveledButton(display,window_info,&cancel_info);
7535             break;
7536           }
7537         break;
7538       }
7539       case SelectionClear:
7540       {
7541         reply_info.highlight=MagickFalse;
7542         XDrawMatteText(display,window_info,&reply_info);
7543         break;
7544       }
7545       case SelectionNotify:
7546       {
7547         Atom
7548           type;
7549
7550         int
7551           format;
7552
7553         unsigned char
7554           *data;
7555
7556         unsigned long
7557           after,
7558           length;
7559
7560         /*
7561           Obtain response from primary selection.
7562         */
7563         if (event.xselection.property == (Atom) None)
7564           break;
7565         status=XGetWindowProperty(display,
7566           event.xselection.requestor,event.xselection.property,0L,2047L,
7567           MagickTrue,XA_STRING,&type,&format,&length,&after,&data);
7568         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
7569             (length == 0))
7570           break;
7571         if ((Extent(reply_info.text)+length) >= MaxTextExtent)
7572           (void) XBell(display,0);
7573         else
7574           {
7575             /*
7576               Insert primary selection in reply text.
7577             */
7578             *(data+length)='\0';
7579             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
7580               state);
7581             XDrawMatteText(display,window_info,&reply_info);
7582             state|=RedrawActionState;
7583           }
7584         (void) XFree((void *) data);
7585         break;
7586       }
7587       case SelectionRequest:
7588       {
7589         XSelectionEvent
7590           notify;
7591
7592         XSelectionRequestEvent
7593           *request;
7594
7595         if (reply_info.highlight == MagickFalse)
7596           break;
7597         /*
7598           Set primary selection.
7599         */
7600         request=(&(event.xselectionrequest));
7601         (void) XChangeProperty(request->display,request->requestor,
7602           request->property,request->target,8,PropModeReplace,
7603           (unsigned char *) primary_selection,Extent(primary_selection));
7604         notify.type=SelectionNotify;
7605         notify.send_event=MagickTrue;
7606         notify.display=request->display;
7607         notify.requestor=request->requestor;
7608         notify.selection=request->selection;
7609         notify.target=request->target;
7610         notify.time=request->time;
7611         if (request->property == None)
7612           notify.property=request->target;
7613         else
7614           notify.property=request->property;
7615         (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
7616           (XEvent *) &notify);
7617       }
7618       default:
7619         break;
7620     }
7621   } while ((state & ExitState) == 0);
7622   XSetCursorState(display,windows,MagickFalse);
7623   (void) XWithdrawWindow(display,window_info->id,window_info->screen);
7624   XCheckRefreshWindows(display,windows);
7625 }
7626 \f
7627 /*
7628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7629 %                                                                             %
7630 %                                                                             %
7631 %                                                                             %
7632 %   X M e n u W i d g e t                                                     %
7633 %                                                                             %
7634 %                                                                             %
7635 %                                                                             %
7636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7637 %
7638 %  XMenuWidget() maps a menu and returns the command pointed to by the user
7639 %  when the button is released.
7640 %
7641 %  The format of the XMenuWidget method is:
7642 %
7643 %      int XMenuWidget(Display *display,XWindows *windows,const char *title,
7644 %        const char **selections,char *item)
7645 %
7646 %  A description of each parameter follows:
7647 %
7648 %    o selection_number: Specifies the number of the selection that the
7649 %      user choose.
7650 %
7651 %    o display: Specifies a connection to an X server;  returned from
7652 %      XOpenDisplay.
7653 %
7654 %    o window: Specifies a pointer to a XWindows structure.
7655 %
7656 %    o title: Specifies a character string that describes the menu selections.
7657 %
7658 %    o selections: Specifies a pointer to one or more strings that comprise
7659 %      the choices in the menu.
7660 %
7661 %    o item: Specifies a character array.  The item selected from the menu
7662 %      is returned here.
7663 %
7664 */
7665 MagickExport int XMenuWidget(Display *display,XWindows *windows,
7666   const char *title,const char **selections,char *item)
7667 {
7668   Cursor
7669     cursor;
7670
7671   int
7672     id,
7673     x,
7674     y;
7675
7676   unsigned int
7677     height,
7678     number_selections,
7679     title_height,
7680     top_offset,
7681     width;
7682
7683   size_t
7684     state;
7685
7686   XEvent
7687     event;
7688
7689   XFontStruct
7690     *font_info;
7691
7692   XSetWindowAttributes
7693     window_attributes;
7694
7695   XWidgetInfo
7696     highlight_info,
7697     menu_info,
7698     selection_info;
7699
7700   XWindowChanges
7701     window_changes;
7702
7703   /*
7704     Determine Menu widget attributes.
7705   */
7706   assert(display != (Display *) NULL);
7707   assert(windows != (XWindows *) NULL);
7708   assert(title != (char *) NULL);
7709   assert(selections != (const char **) NULL);
7710   assert(item != (char *) NULL);
7711   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
7712   font_info=windows->widget.font_info;
7713   windows->widget.width=submenu_info.active == 0 ?
7714     WidgetTextWidth(font_info,(char *) title) : 0;
7715   for (id=0; selections[id] != (char *) NULL; id++)
7716   {
7717     width=WidgetTextWidth(font_info,(char *) selections[id]);
7718     if (width > windows->widget.width)
7719       windows->widget.width=width;
7720   }
7721   number_selections=(unsigned int) id;
7722   XGetWidgetInfo((char *) NULL,&menu_info);
7723   title_height=(unsigned int) (submenu_info.active == 0 ?
7724     (3*(font_info->descent+font_info->ascent) >> 1)+5 : 2);
7725   width=WidgetTextWidth(font_info,(char *) title);
7726   height=(unsigned int) ((3*(font_info->ascent+font_info->descent)) >> 1);
7727   /*
7728     Position Menu widget.
7729   */
7730   windows->widget.width+=QuantumMargin+(menu_info.bevel_width << 1);
7731   top_offset=title_height+menu_info.bevel_width-1;
7732   windows->widget.height=top_offset+number_selections*height+4;
7733   windows->widget.min_width=windows->widget.width;
7734   windows->widget.min_height=windows->widget.height;
7735   XQueryPosition(display,windows->widget.root,&x,&y);
7736   windows->widget.x=x-(QuantumMargin >> 1);
7737   if (submenu_info.active != 0)
7738     {
7739       windows->widget.x=
7740         windows->command.x+windows->command.width-QuantumMargin;
7741       toggle_info.raised=MagickTrue;
7742       XDrawTriangleEast(display,&windows->command,&toggle_info);
7743     }
7744   windows->widget.y=submenu_info.active == 0 ? y-(int)
7745     ((3*title_height) >> 2) : y;
7746   if (submenu_info.active != 0)
7747     windows->widget.y=windows->command.y+submenu_info.y;
7748   XConstrainWindowPosition(display,&windows->widget);
7749   /*
7750     Map Menu widget.
7751   */
7752   window_attributes.override_redirect=MagickTrue;
7753   (void) XChangeWindowAttributes(display,windows->widget.id,
7754     (size_t) CWOverrideRedirect,&window_attributes);
7755   window_changes.width=(int) windows->widget.width;
7756   window_changes.height=(int) windows->widget.height;
7757   window_changes.x=windows->widget.x;
7758   window_changes.y=windows->widget.y;
7759   (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
7760     (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
7761   (void) XMapRaised(display,windows->widget.id);
7762   windows->widget.mapped=MagickFalse;
7763   /*
7764     Respond to X events.
7765   */
7766   selection_info.height=height;
7767   cursor=XCreateFontCursor(display,XC_right_ptr);
7768   (void) XCheckDefineCursor(display,windows->image.id,cursor);
7769   (void) XCheckDefineCursor(display,windows->command.id,cursor);
7770   (void) XCheckDefineCursor(display,windows->widget.id,cursor);
7771   state=UpdateConfigurationState;
7772   do
7773   {
7774     if (state & UpdateConfigurationState)
7775       {
7776         /*
7777           Initialize selection information.
7778         */
7779         XGetWidgetInfo((char *) NULL,&menu_info);
7780         menu_info.bevel_width--;
7781         menu_info.width=windows->widget.width-((menu_info.bevel_width) << 1);
7782         menu_info.height=windows->widget.height-((menu_info.bevel_width) << 1);
7783         menu_info.x=(int) menu_info.bevel_width;
7784         menu_info.y=(int) menu_info.bevel_width;
7785         XGetWidgetInfo((char *) NULL,&selection_info);
7786         selection_info.center=MagickFalse;
7787         selection_info.width=menu_info.width;
7788         selection_info.height=height;
7789         selection_info.x=menu_info.x;
7790         highlight_info=selection_info;
7791         highlight_info.bevel_width--;
7792         highlight_info.width-=(highlight_info.bevel_width << 1);
7793         highlight_info.height-=(highlight_info.bevel_width << 1);
7794         highlight_info.x+=highlight_info.bevel_width;
7795         state&=(~UpdateConfigurationState);
7796       }
7797     if (state & RedrawWidgetState)
7798       {
7799         /*
7800           Redraw Menu widget.
7801         */
7802         if (submenu_info.active == 0)
7803           {
7804             y=(int) title_height;
7805             XSetBevelColor(display,&windows->widget,MagickFalse);
7806             (void) XDrawLine(display,windows->widget.id,
7807               windows->widget.widget_context,selection_info.x,y-1,
7808               (int) selection_info.width,y-1);
7809             XSetBevelColor(display,&windows->widget,MagickTrue);
7810             (void) XDrawLine(display,windows->widget.id,
7811               windows->widget.widget_context,selection_info.x,y,
7812               (int) selection_info.width,y);
7813             (void) XSetFillStyle(display,windows->widget.widget_context,
7814               FillSolid);
7815           }
7816         /*
7817           Draw menu selections.
7818         */
7819         selection_info.center=MagickTrue;
7820         selection_info.y=(int) menu_info.bevel_width;
7821         selection_info.text=(char *) title;
7822         if (submenu_info.active == 0)
7823           XDrawWidgetText(display,&windows->widget,&selection_info);
7824         selection_info.center=MagickFalse;
7825         selection_info.y=(int) top_offset;
7826         for (id=0; id < (int) number_selections; id++)
7827         {
7828           selection_info.text=(char *) selections[id];
7829           XDrawWidgetText(display,&windows->widget,&selection_info);
7830           highlight_info.y=selection_info.y+highlight_info.bevel_width;
7831           if (id == selection_info.id)
7832             XDrawBevel(display,&windows->widget,&highlight_info);
7833           selection_info.y+=(int) selection_info.height;
7834         }
7835         XDrawBevel(display,&windows->widget,&menu_info);
7836         state&=(~RedrawWidgetState);
7837       }
7838     if (number_selections > 2)
7839       {
7840         /*
7841           Redraw Menu line.
7842         */
7843         y=(int) (top_offset+selection_info.height*(number_selections-1));
7844         XSetBevelColor(display,&windows->widget,MagickFalse);
7845         (void) XDrawLine(display,windows->widget.id,
7846           windows->widget.widget_context,selection_info.x,y-1,
7847           (int) selection_info.width,y-1);
7848         XSetBevelColor(display,&windows->widget,MagickTrue);
7849         (void) XDrawLine(display,windows->widget.id,
7850           windows->widget.widget_context,selection_info.x,y,
7851           (int) selection_info.width,y);
7852         (void) XSetFillStyle(display,windows->widget.widget_context,FillSolid);
7853       }
7854     /*
7855       Wait for next event.
7856     */
7857     (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
7858     switch (event.type)
7859     {
7860       case ButtonPress:
7861       {
7862         if (event.xbutton.window != windows->widget.id)
7863           {
7864             /*
7865               exit menu.
7866             */
7867             if (event.xbutton.window == windows->command.id)
7868               (void) XPutBackEvent(display,&event);
7869             selection_info.id=(~0);
7870             *item='\0';
7871             state|=ExitState;
7872             break;
7873           }
7874         state&=(~InactiveWidgetState);
7875         id=(event.xbutton.y-top_offset)/(int) selection_info.height;
7876         selection_info.id=id;
7877         if ((id < 0) || (id >= (int) number_selections))
7878           break;
7879         /*
7880           Highlight this selection.
7881         */
7882         selection_info.y=(int) (top_offset+id*selection_info.height);
7883         selection_info.text=(char *) selections[id];
7884         XDrawWidgetText(display,&windows->widget,&selection_info);
7885         highlight_info.y=selection_info.y+highlight_info.bevel_width;
7886         XDrawBevel(display,&windows->widget,&highlight_info);
7887         break;
7888       }
7889       case ButtonRelease:
7890       {
7891         if (windows->widget.mapped == MagickFalse)
7892           break;
7893         if (event.xbutton.window == windows->command.id)
7894           if ((state & InactiveWidgetState) == 0)
7895             break;
7896         /*
7897           exit menu.
7898         */
7899         XSetCursorState(display,windows,MagickFalse);
7900         *item='\0';
7901         state|=ExitState;
7902         break;
7903       }
7904       case ConfigureNotify:
7905       {
7906         /*
7907           Update widget configuration.
7908         */
7909         if (event.xconfigure.window != windows->widget.id)
7910           break;
7911         if ((event.xconfigure.width == (int) windows->widget.width) &&
7912             (event.xconfigure.height == (int) windows->widget.height))
7913           break;
7914         windows->widget.width=(unsigned int)
7915           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
7916         windows->widget.height=(unsigned int)
7917           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
7918         state|=UpdateConfigurationState;
7919         break;
7920       }
7921       case EnterNotify:
7922       {
7923         if (event.xcrossing.window != windows->widget.id)
7924           break;
7925         if (event.xcrossing.state == 0)
7926           break;
7927         state&=(~InactiveWidgetState);
7928         id=((event.xcrossing.y-top_offset)/(int) selection_info.height);
7929         if ((selection_info.id >= 0) &&
7930             (selection_info.id < (int) number_selections))
7931           {
7932             /*
7933               Unhighlight last selection.
7934             */
7935             if (id == selection_info.id)
7936               break;
7937             selection_info.y=(int)
7938               (top_offset+selection_info.id*selection_info.height);
7939             selection_info.text=(char *) selections[selection_info.id];
7940             XDrawWidgetText(display,&windows->widget,&selection_info);
7941           }
7942         if ((id < 0) || (id >= (int) number_selections))
7943           break;
7944         /*
7945           Highlight this selection.
7946         */
7947         selection_info.id=id;
7948         selection_info.y=(int)
7949           (top_offset+selection_info.id*selection_info.height);
7950         selection_info.text=(char *) selections[selection_info.id];
7951         XDrawWidgetText(display,&windows->widget,&selection_info);
7952         highlight_info.y=selection_info.y+highlight_info.bevel_width;
7953         XDrawBevel(display,&windows->widget,&highlight_info);
7954         break;
7955       }
7956       case Expose:
7957       {
7958         if (event.xexpose.window != windows->widget.id)
7959           break;
7960         if (event.xexpose.count != 0)
7961           break;
7962         state|=RedrawWidgetState;
7963         break;
7964       }
7965       case LeaveNotify:
7966       {
7967         if (event.xcrossing.window != windows->widget.id)
7968           break;
7969         state|=InactiveWidgetState;
7970         id=selection_info.id;
7971         if ((id < 0) || (id >= (int) number_selections))
7972           break;
7973         /*
7974           Unhighlight last selection.
7975         */
7976         selection_info.y=(int) (top_offset+id*selection_info.height);
7977         selection_info.id=(~0);
7978         selection_info.text=(char *) selections[id];
7979         XDrawWidgetText(display,&windows->widget,&selection_info);
7980         break;
7981       }
7982       case MotionNotify:
7983       {
7984         /*
7985           Discard pending button motion events.
7986         */
7987         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
7988         if (submenu_info.active != 0)
7989           if (event.xmotion.window == windows->command.id)
7990             {
7991               if ((state & InactiveWidgetState) == 0)
7992                 {
7993                   if (MatteIsActive(submenu_info,event.xmotion) == MagickFalse)
7994                     {
7995                       selection_info.id=(~0);
7996                         *item='\0';
7997                       state|=ExitState;
7998                       break;
7999                     }
8000                 }
8001               else
8002                 if (WindowIsActive(windows->command,event.xmotion))
8003                   {
8004                     selection_info.id=(~0);
8005                     *item='\0';
8006                     state|=ExitState;
8007                     break;
8008                   }
8009             }
8010         if (event.xmotion.window != windows->widget.id)
8011           break;
8012         if (state & InactiveWidgetState)
8013           break;
8014         id=(event.xmotion.y-top_offset)/(int) selection_info.height;
8015         if ((selection_info.id >= 0) &&
8016             (selection_info.id < (int) number_selections))
8017           {
8018             /*
8019               Unhighlight last selection.
8020             */
8021             if (id == selection_info.id)
8022               break;
8023             selection_info.y=(int)
8024               (top_offset+selection_info.id*selection_info.height);
8025             selection_info.text=(char *) selections[selection_info.id];
8026             XDrawWidgetText(display,&windows->widget,&selection_info);
8027           }
8028         selection_info.id=id;
8029         if ((id < 0) || (id >= (int) number_selections))
8030           break;
8031         /*
8032           Highlight this selection.
8033         */
8034         selection_info.y=(int) (top_offset+id*selection_info.height);
8035         selection_info.text=(char *) selections[id];
8036         XDrawWidgetText(display,&windows->widget,&selection_info);
8037         highlight_info.y=selection_info.y+highlight_info.bevel_width;
8038         XDrawBevel(display,&windows->widget,&highlight_info);
8039         break;
8040       }
8041       default:
8042         break;
8043     }
8044   } while ((state & ExitState) == 0);
8045   (void) XFreeCursor(display,cursor);
8046   window_attributes.override_redirect=MagickFalse;
8047   (void) XChangeWindowAttributes(display,windows->widget.id,
8048     (size_t) CWOverrideRedirect,&window_attributes);
8049   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8050   XCheckRefreshWindows(display,windows);
8051   if (submenu_info.active != 0)
8052     {
8053       submenu_info.active=MagickFalse;
8054       toggle_info.raised=MagickFalse;
8055       XDrawTriangleEast(display,&windows->command,&toggle_info);
8056     }
8057   if ((selection_info.id < 0) || (selection_info.id >= (int) number_selections))
8058     return(~0);
8059   (void) CopyMagickString(item,selections[selection_info.id],MaxTextExtent);
8060   return(selection_info.id);
8061 }
8062 \f
8063 /*
8064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8065 %                                                                             %
8066 %                                                                             %
8067 %                                                                             %
8068 %   X N o t i c e W i d g e t                                                 %
8069 %                                                                             %
8070 %                                                                             %
8071 %                                                                             %
8072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8073 %
8074 %  XNoticeWidget() displays a Notice widget with a notice to the user.  The
8075 %  function returns when the user presses the "Dismiss" button.
8076 %
8077 %  The format of the XNoticeWidget method is:
8078 %
8079 %      void XNoticeWidget(Display *display,XWindows *windows,
8080 %        const char *reason,const char *description)
8081 %
8082 %  A description of each parameter follows:
8083 %
8084 %    o display: Specifies a connection to an X server;  returned from
8085 %      XOpenDisplay.
8086 %
8087 %    o window: Specifies a pointer to a XWindows structure.
8088 %
8089 %    o reason: Specifies the message to display before terminating the
8090 %      program.
8091 %
8092 %    o description: Specifies any description to the message.
8093 %
8094 */
8095 MagickExport void XNoticeWidget(Display *display,XWindows *windows,
8096   const char *reason,const char *description)
8097 {
8098 #define DismissButtonText  "Dismiss"
8099 #define Timeout  8
8100
8101   const char
8102     *text;
8103
8104   int
8105     x,
8106     y;
8107
8108   Status
8109     status;
8110
8111   time_t
8112     timer;
8113
8114   unsigned int
8115     height,
8116     width;
8117
8118   size_t
8119     state;
8120
8121   XEvent
8122     event;
8123
8124   XFontStruct
8125     *font_info;
8126
8127   XTextProperty
8128     window_name;
8129
8130   XWidgetInfo
8131     dismiss_info;
8132
8133   XWindowChanges
8134     window_changes;
8135
8136   /*
8137     Determine Notice widget attributes.
8138   */
8139   assert(display != (Display *) NULL);
8140   assert(windows != (XWindows *) NULL);
8141   assert(reason != (char *) NULL);
8142   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
8143   XDelay(display,SuspendTime << 3);  /* avoid surpise with delay */
8144   XSetCursorState(display,windows,MagickTrue);
8145   XCheckRefreshWindows(display,windows);
8146   font_info=windows->widget.font_info;
8147   width=WidgetTextWidth(font_info,DismissButtonText);
8148   text=GetLocaleExceptionMessage(XServerError,reason);
8149   if (text != (char *) NULL)
8150     if (WidgetTextWidth(font_info,(char *) text) > width)
8151       width=WidgetTextWidth(font_info,(char *) text);
8152   if (description != (char *) NULL)
8153     {
8154       text=GetLocaleExceptionMessage(XServerError,description);
8155       if (text != (char *) NULL)
8156         if (WidgetTextWidth(font_info,(char *) text) > width)
8157           width=WidgetTextWidth(font_info,(char *) text);
8158     }
8159   height=(unsigned int) (font_info->ascent+font_info->descent);
8160   /*
8161     Position Notice widget.
8162   */
8163   windows->widget.width=width+4*QuantumMargin;
8164   windows->widget.min_width=width+QuantumMargin;
8165   if (windows->widget.width < windows->widget.min_width)
8166     windows->widget.width=windows->widget.min_width;
8167   windows->widget.height=(unsigned int) (12*height);
8168   windows->widget.min_height=(unsigned int) (7*height);
8169   if (windows->widget.height < windows->widget.min_height)
8170     windows->widget.height=windows->widget.min_height;
8171   XConstrainWindowPosition(display,&windows->widget);
8172   /*
8173     Map Notice widget.
8174   */
8175   (void) CopyMagickString(windows->widget.name,"Notice",MaxTextExtent);
8176   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8177   if (status != False)
8178     {
8179       XSetWMName(display,windows->widget.id,&window_name);
8180       XSetWMIconName(display,windows->widget.id,&window_name);
8181       (void) XFree((void *) window_name.value);
8182     }
8183   window_changes.width=(int) windows->widget.width;
8184   window_changes.height=(int) windows->widget.height;
8185   window_changes.x=windows->widget.x;
8186   window_changes.y=windows->widget.y;
8187   (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8188     (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8189   (void) XMapRaised(display,windows->widget.id);
8190   windows->widget.mapped=MagickFalse;
8191   (void) XBell(display,0);
8192   /*
8193     Respond to X events.
8194   */
8195   timer=time((time_t *) NULL)+Timeout;
8196   state=UpdateConfigurationState;
8197   do
8198   {
8199     if (time((time_t *) NULL) > timer)
8200       break;
8201     if (state & UpdateConfigurationState)
8202       {
8203         /*
8204           Initialize Dismiss button information.
8205         */
8206         XGetWidgetInfo(DismissButtonText,&dismiss_info);
8207         dismiss_info.width=(unsigned int) QuantumMargin+
8208           WidgetTextWidth(font_info,DismissButtonText);
8209         dismiss_info.height=(unsigned int) ((3*height) >> 1);
8210         dismiss_info.x=(int)
8211           ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
8212         dismiss_info.y=(int)
8213           (windows->widget.height-(dismiss_info.height << 1));
8214         state&=(~UpdateConfigurationState);
8215       }
8216     if (state & RedrawWidgetState)
8217       {
8218         /*
8219           Redraw Notice widget.
8220         */
8221         width=WidgetTextWidth(font_info,(char *) reason);
8222         x=(int) ((windows->widget.width >> 1)-(width >> 1));
8223         y=(int) ((windows->widget.height >> 1)-(height << 1));
8224         (void) XDrawString(display,windows->widget.id,
8225           windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
8226         if (description != (char *) NULL)
8227           {
8228             width=WidgetTextWidth(font_info,(char *) description);
8229             x=(int) ((windows->widget.width >> 1)-(width >> 1));
8230             y+=height;
8231             (void) XDrawString(display,windows->widget.id,
8232               windows->widget.annotate_context,x,y,(char *) description,
8233               Extent(description));
8234           }
8235         XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8236         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8237         state&=(~RedrawWidgetState);
8238       }
8239     /*
8240       Wait for next event.
8241     */
8242     if (XCheckIfEvent(display,&event,XScreenEvent,(char *) windows) == MagickFalse)
8243       {
8244         /*
8245           Do not block if delay > 0.
8246         */
8247         XDelay(display,SuspendTime << 2);
8248         continue;
8249       }
8250     switch (event.type)
8251     {
8252       case ButtonPress:
8253       {
8254         if (MatteIsActive(dismiss_info,event.xbutton))
8255           {
8256             /*
8257               User pressed Dismiss button.
8258             */
8259             dismiss_info.raised=MagickFalse;
8260             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8261             break;
8262           }
8263         break;
8264       }
8265       case ButtonRelease:
8266       {
8267         if (windows->widget.mapped == MagickFalse)
8268           break;
8269         if (dismiss_info.raised == MagickFalse)
8270           {
8271             if (event.xbutton.window == windows->widget.id)
8272               if (MatteIsActive(dismiss_info,event.xbutton))
8273                 state|=ExitState;
8274             dismiss_info.raised=MagickTrue;
8275             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8276           }
8277         break;
8278       }
8279       case ClientMessage:
8280       {
8281         /*
8282           If client window delete message, exit.
8283         */
8284         if (event.xclient.message_type != windows->wm_protocols)
8285           break;
8286         if (*event.xclient.data.l == (int) windows->wm_take_focus)
8287           {
8288             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8289               (Time) event.xclient.data.l[1]);
8290             break;
8291           }
8292         if (*event.xclient.data.l != (int) windows->wm_delete_window)
8293           break;
8294         if (event.xclient.window == windows->widget.id)
8295           {
8296             state|=ExitState;
8297             break;
8298           }
8299         break;
8300       }
8301       case ConfigureNotify:
8302       {
8303         /*
8304           Update widget configuration.
8305         */
8306         if (event.xconfigure.window != windows->widget.id)
8307           break;
8308         if ((event.xconfigure.width == (int) windows->widget.width) &&
8309             (event.xconfigure.height == (int) windows->widget.height))
8310           break;
8311         windows->widget.width=(unsigned int)
8312           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8313         windows->widget.height=(unsigned int)
8314           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8315         state|=UpdateConfigurationState;
8316         break;
8317       }
8318       case EnterNotify:
8319       {
8320         if (event.xcrossing.window != windows->widget.id)
8321           break;
8322         state&=(~InactiveWidgetState);
8323         break;
8324       }
8325       case Expose:
8326       {
8327         if (event.xexpose.window != windows->widget.id)
8328           break;
8329         if (event.xexpose.count != 0)
8330           break;
8331         state|=RedrawWidgetState;
8332         break;
8333       }
8334       case KeyPress:
8335       {
8336         static char
8337           command[MaxTextExtent];
8338
8339         static KeySym
8340           key_symbol;
8341
8342         /*
8343           Respond to a user key press.
8344         */
8345         if (event.xkey.window != windows->widget.id)
8346           break;
8347         (void) XLookupString((XKeyEvent *) &event.xkey,command,
8348           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8349         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8350           {
8351             dismiss_info.raised=MagickFalse;
8352             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8353             state|=ExitState;
8354             break;
8355           }
8356         break;
8357       }
8358       case LeaveNotify:
8359       {
8360         if (event.xcrossing.window != windows->widget.id)
8361           break;
8362         state|=InactiveWidgetState;
8363         break;
8364       }
8365       case MotionNotify:
8366       {
8367         /*
8368           Discard pending button motion events.
8369         */
8370         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8371         if (state & InactiveWidgetState)
8372           break;
8373         if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
8374           {
8375             /*
8376               Dismiss button status changed.
8377             */
8378             dismiss_info.raised=
8379               dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8380             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8381             break;
8382           }
8383         break;
8384       }
8385       default:
8386         break;
8387     }
8388   } while ((state & ExitState) == 0);
8389   XSetCursorState(display,windows,MagickFalse);
8390   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8391   XCheckRefreshWindows(display,windows);
8392 }
8393 \f
8394 /*
8395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8396 %                                                                             %
8397 %                                                                             %
8398 %                                                                             %
8399 %   X P r e f e r e n c e s W i d g e t                                       %
8400 %                                                                             %
8401 %                                                                             %
8402 %                                                                             %
8403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8404 %
8405 %  XPreferencesWidget() displays a Preferences widget with program preferences.
8406 %  If the user presses the Apply button, the preferences are stored in a
8407 %  configuration file in the users' home directory.
8408 %
8409 %  The format of the XPreferencesWidget method is:
8410 %
8411 %      MagickBooleanType XPreferencesWidget(Display *display,
8412 %        XResourceInfo *resource_info,XWindows *windows)
8413 %
8414 %  A description of each parameter follows:
8415 %
8416 %    o display: Specifies a connection to an X server;  returned from
8417 %      XOpenDisplay.
8418 %
8419 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8420 %
8421 %    o window: Specifies a pointer to a XWindows structure.
8422 %
8423 */
8424 MagickExport MagickBooleanType XPreferencesWidget(Display *display,
8425   XResourceInfo *resource_info,XWindows *windows)
8426 {
8427 #define ApplyButtonText  "Apply"
8428 #define CacheButtonText  "%lu mega-bytes of memory in the undo edit cache   "
8429 #define CancelButtonText  "Cancel"
8430 #define NumberPreferences  8
8431
8432   static const char
8433     *Preferences[] =
8434     {
8435       "display image centered on a backdrop",
8436       "confirm on program exit",
8437       "confirm on image edits",
8438       "correct image for display gamma",
8439       "display warning messages",
8440       "apply Floyd/Steinberg error diffusion to image",
8441       "use a shared colormap for colormapped X visuals",
8442       "display images as an X server pixmap"
8443     };
8444
8445   char
8446     cache[MaxTextExtent];
8447
8448   int
8449     x,
8450     y;
8451
8452   register int
8453     i;
8454
8455   Status
8456     status;
8457
8458   unsigned int
8459     height,
8460     text_width,
8461     width;
8462
8463   size_t
8464     state;
8465
8466   XEvent
8467     event;
8468
8469   XFontStruct
8470     *font_info;
8471
8472   XTextProperty
8473     window_name;
8474
8475   XWidgetInfo
8476     apply_info,
8477     cache_info,
8478     cancel_info,
8479     preferences_info[NumberPreferences];
8480
8481   XWindowChanges
8482     window_changes;
8483
8484   /*
8485     Determine Preferences widget attributes.
8486   */
8487   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
8488   assert(display != (Display *) NULL);
8489   assert(resource_info != (XResourceInfo *) NULL);
8490   assert(windows != (XWindows *) NULL);
8491   XCheckRefreshWindows(display,windows);
8492   font_info=windows->widget.font_info;
8493   text_width=WidgetTextWidth(font_info,CacheButtonText);
8494   for (i=0; i < NumberPreferences; i++)
8495     if (WidgetTextWidth(font_info,(char *) Preferences[i]) > text_width)
8496       text_width=WidgetTextWidth(font_info,(char *) Preferences[i]);
8497   width=WidgetTextWidth(font_info,ApplyButtonText);
8498   if (WidgetTextWidth(font_info,CancelButtonText) > width)
8499     width=WidgetTextWidth(font_info,CancelButtonText);
8500   width+=(unsigned int) QuantumMargin;
8501   height=(unsigned int) (font_info->ascent+font_info->descent);
8502   /*
8503     Position Preferences widget.
8504   */
8505   windows->widget.width=(unsigned int) (MagickMax((int) (width << 1),
8506     (int) text_width)+6*QuantumMargin);
8507   windows->widget.min_width=(width << 1)+QuantumMargin;
8508   if (windows->widget.width < windows->widget.min_width)
8509     windows->widget.width=windows->widget.min_width;
8510   windows->widget.height=(unsigned int)
8511     (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
8512   windows->widget.min_height=(unsigned int)
8513     (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
8514   if (windows->widget.height < windows->widget.min_height)
8515     windows->widget.height=windows->widget.min_height;
8516   XConstrainWindowPosition(display,&windows->widget);
8517   /*
8518     Map Preferences widget.
8519   */
8520   (void) CopyMagickString(windows->widget.name,"Preferences",MaxTextExtent);
8521   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8522   if (status != False)
8523     {
8524       XSetWMName(display,windows->widget.id,&window_name);
8525       XSetWMIconName(display,windows->widget.id,&window_name);
8526       (void) XFree((void *) window_name.value);
8527     }
8528   window_changes.width=(int) windows->widget.width;
8529   window_changes.height=(int) windows->widget.height;
8530   window_changes.x=windows->widget.x;
8531   window_changes.y=windows->widget.y;
8532   (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8533     (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8534   (void) XMapRaised(display,windows->widget.id);
8535   windows->widget.mapped=MagickFalse;
8536   /*
8537     Respond to X events.
8538   */
8539   state=UpdateConfigurationState;
8540   XSetCursorState(display,windows,MagickTrue);
8541   do
8542   {
8543     if (state & UpdateConfigurationState)
8544       {
8545         /*
8546           Initialize button information.
8547         */
8548         XGetWidgetInfo(CancelButtonText,&cancel_info);
8549         cancel_info.width=width;
8550         cancel_info.height=(unsigned int) (3*height) >> 1;
8551         cancel_info.x=(int) windows->widget.width-cancel_info.width-
8552           (QuantumMargin << 1);
8553         cancel_info.y=(int) windows->widget.height-
8554           cancel_info.height-QuantumMargin;
8555         XGetWidgetInfo(ApplyButtonText,&apply_info);
8556         apply_info.width=width;
8557         apply_info.height=(unsigned int) (3*height) >> 1;
8558         apply_info.x=QuantumMargin << 1;
8559         apply_info.y=cancel_info.y;
8560         y=(int) (height << 1);
8561         for (i=0; i < NumberPreferences; i++)
8562         {
8563           XGetWidgetInfo(Preferences[i],&preferences_info[i]);
8564           preferences_info[i].bevel_width--;
8565           preferences_info[i].width=(unsigned int) QuantumMargin >> 1;
8566           preferences_info[i].height=(unsigned int) QuantumMargin >> 1;
8567           preferences_info[i].x=QuantumMargin << 1;
8568           preferences_info[i].y=y;
8569           y+=height+(QuantumMargin >> 1);
8570         }
8571         preferences_info[0].raised=resource_info->backdrop ==
8572           MagickFalse ? MagickTrue : MagickFalse;
8573         preferences_info[1].raised=resource_info->confirm_exit ==
8574           MagickFalse ? MagickTrue : MagickFalse;
8575         preferences_info[2].raised=resource_info->confirm_edit ==
8576           MagickFalse ? MagickTrue : MagickFalse;
8577         preferences_info[3].raised=resource_info->gamma_correct ==
8578           MagickFalse ? MagickTrue : MagickFalse;
8579         preferences_info[4].raised=resource_info->display_warnings ==
8580           MagickFalse ? MagickTrue : MagickFalse;
8581         preferences_info[5].raised=resource_info->quantize_info->dither ==
8582           MagickFalse ? MagickTrue : MagickFalse;
8583         preferences_info[6].raised=resource_info->colormap !=
8584           SharedColormap ? MagickTrue : MagickFalse;
8585         preferences_info[7].raised=resource_info->use_pixmap ==
8586           MagickFalse ? MagickTrue : MagickFalse;
8587         (void) FormatMagickString(cache,MaxTextExtent,CacheButtonText,
8588           (unsigned long) resource_info->undo_cache);
8589         XGetWidgetInfo(cache,&cache_info);
8590         cache_info.bevel_width--;
8591         cache_info.width=(unsigned int) QuantumMargin >> 1;
8592         cache_info.height=(unsigned int) QuantumMargin >> 1;
8593         cache_info.x=QuantumMargin << 1;
8594         cache_info.y=y;
8595         state&=(~UpdateConfigurationState);
8596       }
8597     if (state & RedrawWidgetState)
8598       {
8599         /*
8600           Redraw Preferences widget.
8601         */
8602         XDrawBeveledButton(display,&windows->widget,&apply_info);
8603         XDrawBeveledButton(display,&windows->widget,&cancel_info);
8604         for (i=0; i < NumberPreferences; i++)
8605           XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8606         XDrawTriangleEast(display,&windows->widget,&cache_info);
8607         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8608         state&=(~RedrawWidgetState);
8609       }
8610     /*
8611       Wait for next event.
8612     */
8613     (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
8614     switch (event.type)
8615     {
8616       case ButtonPress:
8617       {
8618         if (MatteIsActive(apply_info,event.xbutton))
8619           {
8620             /*
8621               User pressed Apply button.
8622             */
8623             apply_info.raised=MagickFalse;
8624             XDrawBeveledButton(display,&windows->widget,&apply_info);
8625             break;
8626           }
8627         if (MatteIsActive(cancel_info,event.xbutton))
8628           {
8629             /*
8630               User pressed Cancel button.
8631             */
8632             cancel_info.raised=MagickFalse;
8633             XDrawBeveledButton(display,&windows->widget,&cancel_info);
8634             break;
8635           }
8636         for (i=0; i < NumberPreferences; i++)
8637           if (MatteIsActive(preferences_info[i],event.xbutton))
8638             {
8639               /*
8640                 User pressed a Preferences button.
8641               */
8642               preferences_info[i].raised=preferences_info[i].raised ==
8643                 MagickFalse ? MagickTrue : MagickFalse;
8644               XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8645               break;
8646             }
8647         if (MatteIsActive(cache_info,event.xbutton))
8648           {
8649             /*
8650               User pressed Cache button.
8651             */
8652             x=cache_info.x+cache_info.width+cache_info.bevel_width+
8653               (QuantumMargin >> 1);
8654             y=cache_info.y+((cache_info.height-height) >> 1);
8655             width=WidgetTextWidth(font_info,cache);
8656             (void) XClearArea(display,windows->widget.id,x,y,width,height,
8657               False);
8658             resource_info->undo_cache<<=1;
8659             if (resource_info->undo_cache > 256)
8660               resource_info->undo_cache=1;
8661             (void) FormatMagickString(cache,MaxTextExtent,CacheButtonText,
8662               (unsigned long) resource_info->undo_cache);
8663             cache_info.raised=MagickFalse;
8664             XDrawTriangleEast(display,&windows->widget,&cache_info);
8665             break;
8666           }
8667         break;
8668       }
8669       case ButtonRelease:
8670       {
8671         if (windows->widget.mapped == MagickFalse)
8672           break;
8673         if (apply_info.raised == MagickFalse)
8674           {
8675             if (event.xbutton.window == windows->widget.id)
8676               if (MatteIsActive(apply_info,event.xbutton))
8677                 state|=ExitState;
8678             apply_info.raised=MagickTrue;
8679             XDrawBeveledButton(display,&windows->widget,&apply_info);
8680             apply_info.raised=MagickFalse;
8681           }
8682         if (cancel_info.raised == MagickFalse)
8683           {
8684             if (event.xbutton.window == windows->widget.id)
8685               if (MatteIsActive(cancel_info,event.xbutton))
8686                 state|=ExitState;
8687             cancel_info.raised=MagickTrue;
8688             XDrawBeveledButton(display,&windows->widget,&cancel_info);
8689           }
8690         if (cache_info.raised == MagickFalse)
8691           {
8692             cache_info.raised=MagickTrue;
8693             XDrawTriangleEast(display,&windows->widget,&cache_info);
8694           }
8695         break;
8696       }
8697       case ClientMessage:
8698       {
8699         /*
8700           If client window delete message, exit.
8701         */
8702         if (event.xclient.message_type != windows->wm_protocols)
8703           break;
8704         if (*event.xclient.data.l == (int) windows->wm_take_focus)
8705           {
8706             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8707               (Time) event.xclient.data.l[1]);
8708             break;
8709           }
8710         if (*event.xclient.data.l != (int) windows->wm_delete_window)
8711           break;
8712         if (event.xclient.window == windows->widget.id)
8713           {
8714             state|=ExitState;
8715             break;
8716           }
8717         break;
8718       }
8719       case ConfigureNotify:
8720       {
8721         /*
8722           Update widget configuration.
8723         */
8724         if (event.xconfigure.window != windows->widget.id)
8725           break;
8726         if ((event.xconfigure.width == (int) windows->widget.width) &&
8727             (event.xconfigure.height == (int) windows->widget.height))
8728           break;
8729         windows->widget.width=(unsigned int)
8730           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8731         windows->widget.height=(unsigned int)
8732           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8733         state|=UpdateConfigurationState;
8734         break;
8735       }
8736       case EnterNotify:
8737       {
8738         if (event.xcrossing.window != windows->widget.id)
8739           break;
8740         state&=(~InactiveWidgetState);
8741         break;
8742       }
8743       case Expose:
8744       {
8745         if (event.xexpose.window != windows->widget.id)
8746           break;
8747         if (event.xexpose.count != 0)
8748           break;
8749         state|=RedrawWidgetState;
8750         break;
8751       }
8752       case KeyPress:
8753       {
8754         static char
8755           command[MaxTextExtent];
8756
8757         static KeySym
8758           key_symbol;
8759
8760         /*
8761           Respond to a user key press.
8762         */
8763         if (event.xkey.window != windows->widget.id)
8764           break;
8765         (void) XLookupString((XKeyEvent *) &event.xkey,command,
8766           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8767         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8768           {
8769             apply_info.raised=MagickFalse;
8770             XDrawBeveledButton(display,&windows->widget,&apply_info);
8771             state|=ExitState;
8772             break;
8773           }
8774         break;
8775       }
8776       case LeaveNotify:
8777       {
8778         if (event.xcrossing.window != windows->widget.id)
8779           break;
8780         state|=InactiveWidgetState;
8781         break;
8782       }
8783       case MotionNotify:
8784       {
8785         /*
8786           Discard pending button motion events.
8787         */
8788         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8789         if (state & InactiveWidgetState)
8790           break;
8791         if (apply_info.raised == MatteIsActive(apply_info,event.xmotion))
8792           {
8793             /*
8794               Apply button status changed.
8795             */
8796             apply_info.raised=
8797               apply_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8798             XDrawBeveledButton(display,&windows->widget,&apply_info);
8799             break;
8800           }
8801         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
8802           {
8803             /*
8804               Cancel button status changed.
8805             */
8806             cancel_info.raised=
8807               cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8808             XDrawBeveledButton(display,&windows->widget,&cancel_info);
8809             break;
8810           }
8811         break;
8812       }
8813       default:
8814         break;
8815     }
8816   } while ((state & ExitState) == 0);
8817   XSetCursorState(display,windows,MagickFalse);
8818   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8819   XCheckRefreshWindows(display,windows);
8820   if (apply_info.raised)
8821     return(MagickFalse);
8822   /*
8823     Save user preferences to the client configuration file.
8824   */
8825   resource_info->backdrop=
8826     preferences_info[0].raised == MagickFalse ? MagickTrue : MagickFalse;
8827   resource_info->confirm_exit=
8828     preferences_info[1].raised == MagickFalse ? MagickTrue : MagickFalse;
8829   resource_info->confirm_edit=
8830     preferences_info[2].raised == MagickFalse ? MagickTrue : MagickFalse;
8831   resource_info->gamma_correct=
8832     preferences_info[3].raised == MagickFalse ? MagickTrue : MagickFalse;
8833   resource_info->display_warnings=
8834      preferences_info[4].raised == MagickFalse ? MagickTrue : MagickFalse;
8835   resource_info->quantize_info->dither=
8836     preferences_info[5].raised == MagickFalse ? MagickTrue : MagickFalse;
8837   resource_info->colormap=SharedColormap;
8838   if (preferences_info[6].raised)
8839     resource_info->colormap=PrivateColormap;
8840   resource_info->use_pixmap=
8841     preferences_info[7].raised == MagickFalse ? MagickTrue : MagickFalse;
8842   XUserPreferences(resource_info);
8843   return(MagickTrue);
8844 }
8845 \f
8846 /*
8847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8848 %                                                                             %
8849 %                                                                             %
8850 %                                                                             %
8851 %   X P r o g r e s s M o n i t o r W i d g e t                               %
8852 %                                                                             %
8853 %                                                                             %
8854 %                                                                             %
8855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8856 %
8857 %  XProgressMonitorWidget() displays the progress a task is making in
8858 %  completing a task.  A span of zero toggles the active status.  An inactive
8859 %  state disables the progress monitor.
8860 %
8861 %  The format of the XProgressMonitorWidget method is:
8862 %
8863 %      void XProgressMonitorWidget(Display *display,XWindows *windows,
8864 %        const char *task,const MagickOffsetType offset,
8865 %        const MagickSizeType span)
8866 %
8867 %  A description of each parameter follows:
8868 %
8869 %    o display: Specifies a connection to an X server;  returned from
8870 %      XOpenDisplay.
8871 %
8872 %    o window: Specifies a pointer to a XWindows structure.
8873 %
8874 %    o task: Identifies the task in progress.
8875 %
8876 %    o offset: Specifies the offset position within the span which represents
8877 %      how much progress has been made in completing a task.
8878 %
8879 %    o span: Specifies the span relative to completing a task.
8880 %
8881 */
8882 MagickExport void XProgressMonitorWidget(Display *display,XWindows *windows,
8883   const char *task,const MagickOffsetType offset,const MagickSizeType span)
8884 {
8885   unsigned int
8886     width;
8887
8888   XEvent
8889     event;
8890
8891   assert(display != (Display *) NULL);
8892   assert(windows != (XWindows *) NULL);
8893   assert(task != (const char *) NULL);
8894   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",task);
8895   if (span == 0)
8896     return;
8897   /*
8898     Update image windows if there is a pending expose event.
8899   */
8900   while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event))
8901     (void) XCommandWidget(display,windows,(const char **) NULL,&event);
8902   while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event))
8903     XRefreshWindow(display,&windows->image,&event);
8904   while (XCheckTypedWindowEvent(display,windows->info.id,Expose,&event))
8905     if (monitor_info.text != (char *) NULL)
8906       XInfoWidget(display,windows,monitor_info.text);
8907   /*
8908     Draw progress monitor bar to represent percent completion of a task.
8909   */
8910   if ((windows->info.mapped == MagickFalse) || (task != monitor_info.text))
8911     XInfoWidget(display,windows,task);
8912   width=(unsigned int) (((offset+1)*(windows->info.width-
8913     (2*monitor_info.x)))/span);
8914   if (width < monitor_info.width)
8915     {
8916       monitor_info.raised=MagickTrue;
8917       XDrawWidgetText(display,&windows->info,&monitor_info);
8918       monitor_info.raised=MagickFalse;
8919     }
8920   monitor_info.width=width;
8921   XDrawWidgetText(display,&windows->info,&monitor_info);
8922   (void) XFlush(display);
8923 }
8924 \f
8925 /*
8926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8927 %                                                                             %
8928 %                                                                             %
8929 %                                                                             %
8930 %   X T e x t V i e w W i d g e t                                             %
8931 %                                                                             %
8932 %                                                                             %
8933 %                                                                             %
8934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8935 %
8936 %  XTextViewWidget() displays text in a Text View widget.
8937 %
8938 %  The format of the XTextViewWidget method is:
8939 %
8940 %      void XTextViewWidget(Display *display,const XResourceInfo *resource_info,
8941 %        XWindows *windows,const MagickBooleanType mono,const char *title,
8942 %        const char **textlist)
8943 %
8944 %  A description of each parameter follows:
8945 %
8946 %    o display: Specifies a connection to an X server;  returned from
8947 %      XOpenDisplay.
8948 %
8949 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8950 %
8951 %    o window: Specifies a pointer to a XWindows structure.
8952 %
8953 %    o mono:  Use mono-spaced font when displaying text.
8954 %
8955 %    o title: This character string is displayed at the top of the widget
8956 %      window.
8957 %
8958 %    o textlist: This string list is displayed within the Text View widget.
8959 %
8960 */
8961 MagickExport void XTextViewWidget(Display *display,
8962   const XResourceInfo *resource_info,XWindows *windows,
8963   const MagickBooleanType mono,const char *title,const char **textlist)
8964 {
8965 #define DismissButtonText  "Dismiss"
8966
8967   char
8968     primary_selection[MaxTextExtent];
8969
8970   register int
8971     i;
8972
8973   static MagickStatusType
8974     mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
8975
8976   Status
8977     status;
8978
8979   unsigned int
8980     height,
8981     lines,
8982     text_width,
8983     visible_lines,
8984     width;
8985
8986   size_t
8987     delay,
8988     state;
8989
8990   XEvent
8991     event;
8992
8993   XFontStruct
8994     *font_info,
8995     *text_info;
8996
8997   XTextProperty
8998     window_name;
8999
9000   XWidgetInfo
9001     dismiss_info,
9002     expose_info,
9003     list_info,
9004     north_info,
9005     scroll_info,
9006     selection_info,
9007     slider_info,
9008     south_info;
9009
9010   XWindowChanges
9011     window_changes;
9012
9013   /*
9014     Convert text string to a text list.
9015   */
9016   assert(display != (Display *) NULL);
9017   assert(resource_info != (XResourceInfo *) NULL);
9018   assert(windows != (XWindows *) NULL);
9019   assert(title != (const char *) NULL);
9020   assert(textlist != (const char **) NULL);
9021   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
9022   XSetCursorState(display,windows,MagickTrue);
9023   XCheckRefreshWindows(display,windows);
9024   if (textlist == (const char **) NULL)
9025     {
9026       XNoticeWidget(display,windows,"No text to view:",(char *) NULL);
9027       return;
9028     }
9029   /*
9030     Determine Text View widget attributes.
9031   */
9032   font_info=windows->widget.font_info;
9033   text_info=(XFontStruct *) NULL;
9034   if (mono != MagickFalse)
9035     text_info=XBestFont(display,resource_info,MagickTrue);
9036   if (text_info == (XFontStruct *) NULL)
9037     text_info=windows->widget.font_info;
9038   text_width=0;
9039   for (i=0; textlist[i] != (char *) NULL; i++)
9040     if (WidgetTextWidth(text_info,(char *) textlist[i]) > text_width)
9041       text_width=(unsigned int) XTextWidth(text_info,(char *) textlist[i],
9042         MagickMin(Extent(textlist[i]),160));
9043   lines=(unsigned int) i;
9044   width=WidgetTextWidth(font_info,DismissButtonText);
9045   width+=QuantumMargin;
9046   height=(unsigned int) (text_info->ascent+text_info->descent);
9047   /*
9048     Position Text View widget.
9049   */
9050   windows->widget.width=(unsigned int) (MagickMin((int) text_width,
9051     (int) MaxTextWidth)+5*QuantumMargin);
9052   windows->widget.min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
9053   if (windows->widget.width < windows->widget.min_width)
9054     windows->widget.width=windows->widget.min_width;
9055   windows->widget.height=(unsigned int) (MagickMin(MagickMax((int) lines,3),32)*
9056     height+((13*height) >> 1)+((9*QuantumMargin) >> 1));
9057   windows->widget.min_height=(unsigned int) (3*height+((13*height) >> 1)+((9*
9058     QuantumMargin) >> 1));
9059   if (windows->widget.height < windows->widget.min_height)
9060     windows->widget.height=windows->widget.min_height;
9061   XConstrainWindowPosition(display,&windows->widget);
9062   /*
9063     Map Text View widget.
9064   */
9065   (void) CopyMagickString(windows->widget.name,title,MaxTextExtent);
9066   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
9067   if (status != False)
9068     {
9069       XSetWMName(display,windows->widget.id,&window_name);
9070       XSetWMIconName(display,windows->widget.id,&window_name);
9071       (void) XFree((void *) window_name.value);
9072     }
9073   window_changes.width=(int) windows->widget.width;
9074   window_changes.height=(int) windows->widget.height;
9075   window_changes.x=windows->widget.x;
9076   window_changes.y=windows->widget.y;
9077   (void) XReconfigureWMWindow(display,windows->widget.id,
9078     windows->widget.screen,(unsigned int) mask,&window_changes);
9079   (void) XMapRaised(display,windows->widget.id);
9080   windows->widget.mapped=MagickFalse;
9081   /*
9082     Respond to X events.
9083   */
9084   XGetWidgetInfo((char *) NULL,&slider_info);
9085   XGetWidgetInfo((char *) NULL,&north_info);
9086   XGetWidgetInfo((char *) NULL,&south_info);
9087   XGetWidgetInfo((char *) NULL,&expose_info);
9088   visible_lines=0;
9089   delay=SuspendTime << 2;
9090   height=(unsigned int) (font_info->ascent+font_info->descent);
9091   state=UpdateConfigurationState;
9092   do
9093   {
9094     if (state & UpdateConfigurationState)
9095       {
9096         int
9097           id;
9098
9099         /*
9100           Initialize button information.
9101         */
9102         XGetWidgetInfo(DismissButtonText,&dismiss_info);
9103         dismiss_info.width=width;
9104         dismiss_info.height=(unsigned int) ((3*height) >> 1);
9105         dismiss_info.x=(int) windows->widget.width-dismiss_info.width-
9106           QuantumMargin-2;
9107         dismiss_info.y=(int) windows->widget.height-dismiss_info.height-
9108           QuantumMargin;
9109         /*
9110           Initialize scroll information.
9111         */
9112         XGetWidgetInfo((char *) NULL,&scroll_info);
9113         scroll_info.bevel_width--;
9114         scroll_info.width=height;
9115         scroll_info.height=(unsigned int) (dismiss_info.y-((5*QuantumMargin) >>
9116           1));
9117         scroll_info.x=(int) windows->widget.width-QuantumMargin-
9118           scroll_info.width;
9119         scroll_info.y=(3*QuantumMargin) >> 1;
9120         scroll_info.raised=MagickFalse;
9121         scroll_info.trough=MagickTrue;
9122         north_info=scroll_info;
9123         north_info.raised=MagickTrue;
9124         north_info.width-=(north_info.bevel_width << 1);
9125         north_info.height=north_info.width-1;
9126         north_info.x+=north_info.bevel_width;
9127         north_info.y+=north_info.bevel_width;
9128         south_info=north_info;
9129         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
9130           south_info.height;
9131         id=slider_info.id;
9132         slider_info=north_info;
9133         slider_info.id=id;
9134         slider_info.width-=2;
9135         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
9136           slider_info.bevel_width+2;
9137         slider_info.height=scroll_info.height-((slider_info.min_y-
9138           scroll_info.y+1) << 1)+4;
9139         visible_lines=scroll_info.height/(text_info->ascent+text_info->descent+
9140           ((text_info->ascent+text_info->descent) >> 3));
9141         if (lines > visible_lines)
9142           slider_info.height=(unsigned int) (visible_lines*slider_info.height)/
9143             lines;
9144         slider_info.max_y=south_info.y-south_info.bevel_width-
9145           slider_info.bevel_width-2;
9146         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
9147         slider_info.y=slider_info.min_y;
9148         expose_info=scroll_info;
9149         expose_info.y=slider_info.y;
9150         /*
9151           Initialize list information.
9152         */
9153         XGetWidgetInfo((char *) NULL,&list_info);
9154         list_info.raised=MagickFalse;
9155         list_info.bevel_width--;
9156         list_info.width=(unsigned int) scroll_info.x-((3*QuantumMargin) >> 1);
9157         list_info.height=scroll_info.height;
9158         list_info.x=QuantumMargin;
9159         list_info.y=scroll_info.y;
9160         /*
9161           Initialize selection information.
9162         */
9163         XGetWidgetInfo((char *) NULL,&selection_info);
9164         selection_info.center=MagickFalse;
9165         selection_info.width=list_info.width;
9166         selection_info.height=(unsigned int)
9167           (9*(text_info->ascent+text_info->descent)) >> 3;
9168         selection_info.x=list_info.x;
9169         state&=(~UpdateConfigurationState);
9170       }
9171     if (state & RedrawWidgetState)
9172       {
9173         /*
9174           Redraw Text View window.
9175         */
9176         XDrawBeveledMatte(display,&windows->widget,&list_info);
9177         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
9178         XDrawTriangleNorth(display,&windows->widget,&north_info);
9179         XDrawBeveledButton(display,&windows->widget,&slider_info);
9180         XDrawTriangleSouth(display,&windows->widget,&south_info);
9181         XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9182         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
9183         selection_info.id=(~0);
9184         state|=RedrawListState;
9185         state&=(~RedrawWidgetState);
9186       }
9187     if (state & RedrawListState)
9188       {
9189         /*
9190           Determine slider id and position.
9191         */
9192         if (slider_info.id >= (int) (lines-visible_lines))
9193           slider_info.id=(int) lines-visible_lines;
9194         if ((slider_info.id < 0) || (lines <= visible_lines))
9195           slider_info.id=0;
9196         slider_info.y=slider_info.min_y;
9197         if (lines != 0)
9198           slider_info.y+=
9199             slider_info.id*(slider_info.max_y-slider_info.min_y+1)/lines;
9200         if (slider_info.id != selection_info.id)
9201           {
9202             /*
9203               Redraw scroll bar and text.
9204             */
9205             windows->widget.font_info=text_info;
9206             (void) XSetFont(display,windows->widget.annotate_context,
9207               text_info->fid);
9208             (void) XSetFont(display,windows->widget.highlight_context,
9209               text_info->fid);
9210             selection_info.id=slider_info.id;
9211             selection_info.y=list_info.y+(height >> 3)+2;
9212             for (i=0; i < (int) visible_lines; i++)
9213             {
9214               selection_info.raised=
9215                 (slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse;
9216               selection_info.text=(char *) NULL;
9217               if ((slider_info.id+i) < (int) lines)
9218                 selection_info.text=(char *) textlist[slider_info.id+i];
9219               XDrawWidgetText(display,&windows->widget,&selection_info);
9220               selection_info.y+=(int) selection_info.height;
9221             }
9222             windows->widget.font_info=font_info;
9223             (void) XSetFont(display,windows->widget.annotate_context,
9224               font_info->fid);
9225             (void) XSetFont(display,windows->widget.highlight_context,
9226               font_info->fid);
9227             /*
9228               Update slider.
9229             */
9230             if (slider_info.y > expose_info.y)
9231               {
9232                 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
9233                 expose_info.y=slider_info.y-expose_info.height-
9234                   slider_info.bevel_width-1;
9235               }
9236             else
9237               {
9238                 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
9239                 expose_info.y=slider_info.y+slider_info.height+
9240                   slider_info.bevel_width+1;
9241               }
9242             XDrawTriangleNorth(display,&windows->widget,&north_info);
9243             XDrawMatte(display,&windows->widget,&expose_info);
9244             XDrawBeveledButton(display,&windows->widget,&slider_info);
9245             XDrawTriangleSouth(display,&windows->widget,&south_info);
9246             expose_info.y=slider_info.y;
9247           }
9248         state&=(~RedrawListState);
9249       }
9250     /*
9251       Wait for next event.
9252     */
9253     if (north_info.raised && south_info.raised)
9254       (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
9255     else
9256       {
9257         /*
9258           Brief delay before advancing scroll bar.
9259         */
9260         XDelay(display,delay);
9261         delay=SuspendTime;
9262         (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
9263         if (north_info.raised == MagickFalse)
9264           if (slider_info.id > 0)
9265             {
9266               /*
9267                 Move slider up.
9268               */
9269               slider_info.id--;
9270               state|=RedrawListState;
9271             }
9272         if (south_info.raised == MagickFalse)
9273           if (slider_info.id < (int) lines)
9274             {
9275               /*
9276                 Move slider down.
9277               */
9278               slider_info.id++;
9279               state|=RedrawListState;
9280             }
9281         if (event.type != ButtonRelease)
9282           continue;
9283       }
9284     switch (event.type)
9285     {
9286       case ButtonPress:
9287       {
9288         if (MatteIsActive(slider_info,event.xbutton))
9289           {
9290             /*
9291               Track slider.
9292             */
9293             slider_info.active=MagickTrue;
9294             break;
9295           }
9296         if (MatteIsActive(north_info,event.xbutton))
9297           if (slider_info.id > 0)
9298             {
9299               /*
9300                 Move slider up.
9301               */
9302               north_info.raised=MagickFalse;
9303               slider_info.id--;
9304               state|=RedrawListState;
9305               break;
9306             }
9307         if (MatteIsActive(south_info,event.xbutton))
9308           if (slider_info.id < (int) lines)
9309             {
9310               /*
9311                 Move slider down.
9312               */
9313               south_info.raised=MagickFalse;
9314               slider_info.id++;
9315               state|=RedrawListState;
9316               break;
9317             }
9318         if (MatteIsActive(scroll_info,event.xbutton))
9319           {
9320             /*
9321               Move slider.
9322             */
9323             if (event.xbutton.y < slider_info.y)
9324               slider_info.id-=(visible_lines-1);
9325             else
9326               slider_info.id+=(visible_lines-1);
9327             state|=RedrawListState;
9328             break;
9329           }
9330         if (MatteIsActive(dismiss_info,event.xbutton))
9331           {
9332             /*
9333               User pressed Dismiss button.
9334             */
9335             dismiss_info.raised=MagickFalse;
9336             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9337             break;
9338           }
9339         if (MatteIsActive(list_info,event.xbutton))
9340           {
9341             int
9342               id;
9343
9344             static Time
9345               click_time;
9346
9347             /*
9348               User pressed list matte.
9349             */
9350             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
9351               selection_info.height;
9352             if (id >= (int) lines)
9353               break;
9354             if (id != list_info.id)
9355               {
9356                 list_info.id=id;
9357                 click_time=event.xbutton.time;
9358                 break;
9359               }
9360             list_info.id=id;
9361             if (event.xbutton.time >= (click_time+DoubleClick))
9362               {
9363                 click_time=event.xbutton.time;
9364                 break;
9365               }
9366             click_time=event.xbutton.time;
9367             /*
9368               Become the XA_PRIMARY selection owner.
9369             */
9370             (void) CopyMagickString(primary_selection,textlist[list_info.id],
9371               MaxTextExtent);
9372             (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
9373               event.xbutton.time);
9374             if (XGetSelectionOwner(display,XA_PRIMARY) != windows->widget.id)
9375               break;
9376             selection_info.id=(~0);
9377             list_info.id=id;
9378             state|=RedrawListState;
9379             break;
9380           }
9381         break;
9382       }
9383       case ButtonRelease:
9384       {
9385         if (windows->widget.mapped == MagickFalse)
9386           break;
9387         if (north_info.raised == MagickFalse)
9388           {
9389             /*
9390               User released up button.
9391             */
9392             delay=SuspendTime << 2;
9393             north_info.raised=MagickTrue;
9394             XDrawTriangleNorth(display,&windows->widget,&north_info);
9395           }
9396         if (south_info.raised == MagickFalse)
9397           {
9398             /*
9399               User released down button.
9400             */
9401             delay=SuspendTime << 2;
9402             south_info.raised=MagickTrue;
9403             XDrawTriangleSouth(display,&windows->widget,&south_info);
9404           }
9405         if (slider_info.active)
9406           {
9407             /*
9408               Stop tracking slider.
9409             */
9410             slider_info.active=MagickFalse;
9411             break;
9412           }
9413         if (dismiss_info.raised == MagickFalse)
9414           {
9415             if (event.xbutton.window == windows->widget.id)
9416               if (MatteIsActive(dismiss_info,event.xbutton))
9417                 state|=ExitState;
9418             dismiss_info.raised=MagickTrue;
9419             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9420           }
9421         break;
9422       }
9423       case ClientMessage:
9424       {
9425         /*
9426           If client window delete message, exit.
9427         */
9428         if (event.xclient.message_type != windows->wm_protocols)
9429           break;
9430         if (*event.xclient.data.l == (int) windows->wm_take_focus)
9431           {
9432             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
9433               (Time) event.xclient.data.l[1]);
9434             break;
9435           }
9436         if (*event.xclient.data.l != (int) windows->wm_delete_window)
9437           break;
9438         if (event.xclient.window == windows->widget.id)
9439           {
9440             state|=ExitState;
9441             break;
9442           }
9443         break;
9444       }
9445       case ConfigureNotify:
9446       {
9447         /*
9448           Update widget configuration.
9449         */
9450         if (event.xconfigure.window != windows->widget.id)
9451           break;
9452         if ((event.xconfigure.width == (int) windows->widget.width) &&
9453             (event.xconfigure.height == (int) windows->widget.height))
9454           break;
9455         windows->widget.width=(unsigned int)
9456           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
9457         windows->widget.height=(unsigned int)
9458           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
9459         state|=UpdateConfigurationState;
9460         break;
9461       }
9462       case EnterNotify:
9463       {
9464         if (event.xcrossing.window != windows->widget.id)
9465           break;
9466         state&=(~InactiveWidgetState);
9467         break;
9468       }
9469       case Expose:
9470       {
9471         if (event.xexpose.window != windows->widget.id)
9472           break;
9473         if (event.xexpose.count != 0)
9474           break;
9475         state|=RedrawWidgetState;
9476         break;
9477       }
9478       case KeyPress:
9479       {
9480         static char
9481           command[MaxTextExtent];
9482
9483         static int
9484           length;
9485
9486         static KeySym
9487           key_symbol;
9488
9489         /*
9490           Respond to a user key press.
9491         */
9492         if (event.xkey.window != windows->widget.id)
9493           break;
9494         length=XLookupString((XKeyEvent *) &event.xkey,command,
9495           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9496         *(command+length)='\0';
9497         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
9498           {
9499             dismiss_info.raised=MagickFalse;
9500             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9501             state|=ExitState;
9502             break;
9503           }
9504         if (AreaIsActive(scroll_info,event.xkey))
9505           {
9506             /*
9507               Move slider.
9508             */
9509             switch ((int) key_symbol)
9510             {
9511               case XK_Home:
9512               case XK_KP_Home:
9513               {
9514                 slider_info.id=0;
9515                 break;
9516               }
9517               case XK_Up:
9518               case XK_KP_Up:
9519               {
9520                 slider_info.id--;
9521                 break;
9522               }
9523               case XK_Down:
9524               case XK_KP_Down:
9525               {
9526                 slider_info.id++;
9527                 break;
9528               }
9529               case XK_Prior:
9530               case XK_KP_Prior:
9531               {
9532                 slider_info.id-=visible_lines;
9533                 break;
9534               }
9535               case XK_Next:
9536               case XK_KP_Next:
9537               {
9538                 slider_info.id+=visible_lines;
9539                 break;
9540               }
9541               case XK_End:
9542               case XK_KP_End:
9543               {
9544                 slider_info.id=(int) lines;
9545                 break;
9546               }
9547             }
9548             state|=RedrawListState;
9549             break;
9550           }
9551         break;
9552       }
9553       case KeyRelease:
9554         break;
9555       case LeaveNotify:
9556       {
9557         if (event.xcrossing.window != windows->widget.id)
9558           break;
9559         state|=InactiveWidgetState;
9560         break;
9561       }
9562       case MapNotify:
9563       {
9564         mask&=(~CWX);
9565         mask&=(~CWY);
9566         break;
9567       }
9568       case MotionNotify:
9569       {
9570         /*
9571           Discard pending button motion events.
9572         */
9573         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
9574         if (slider_info.active)
9575           {
9576             /*
9577               Move slider matte.
9578             */
9579             slider_info.y=event.xmotion.y-
9580               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
9581             if (slider_info.y < slider_info.min_y)
9582               slider_info.y=slider_info.min_y;
9583             if (slider_info.y > slider_info.max_y)
9584               slider_info.y=slider_info.max_y;
9585             slider_info.id=0;
9586             if (slider_info.y != slider_info.min_y)
9587               slider_info.id=(int) (lines*(slider_info.y-slider_info.min_y+1))/
9588                 (slider_info.max_y-slider_info.min_y+1);
9589             state|=RedrawListState;
9590             break;
9591           }
9592         if (state & InactiveWidgetState)
9593           break;
9594         if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
9595           {
9596             /*
9597               Dismiss button status changed.
9598             */
9599             dismiss_info.raised=
9600               dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
9601             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9602             break;
9603           }
9604         break;
9605       }
9606       case SelectionClear:
9607       {
9608         list_info.id=(~0);
9609         selection_info.id=(~0);
9610         state|=RedrawListState;
9611         break;
9612       }
9613       case SelectionRequest:
9614       {
9615         XSelectionEvent
9616           notify;
9617
9618         XSelectionRequestEvent
9619           *request;
9620
9621         if (list_info.id == (~0))
9622           break;
9623         /*
9624           Set primary selection.
9625         */
9626         request=(&(event.xselectionrequest));
9627         (void) XChangeProperty(request->display,request->requestor,
9628           request->property,request->target,8,PropModeReplace,
9629           (unsigned char *) primary_selection,Extent(primary_selection));
9630         notify.type=SelectionNotify;
9631         notify.send_event=MagickTrue;
9632         notify.display=request->display;
9633         notify.requestor=request->requestor;
9634         notify.selection=request->selection;
9635         notify.target=request->target;
9636         notify.time=request->time;
9637         if (request->property == None)
9638           notify.property=request->target;
9639         else
9640           notify.property=request->property;
9641         (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
9642           (XEvent *) &notify);
9643       }
9644       default:
9645         break;
9646     }
9647   } while ((state & ExitState) == 0);
9648   if (text_info != windows->widget.font_info)
9649     (void) XFreeFont(display,text_info);
9650   XSetCursorState(display,windows,MagickFalse);
9651   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
9652   XCheckRefreshWindows(display,windows);
9653 }
9654 #endif