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