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