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