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