MagickCore  6.7.5
widget.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                                                                             %
00007 %                  W   W  IIIII  DDDD    GGGG  EEEEE  TTTTT                   %
00008 %                  W   W    I    D   D  G      E        T                     %
00009 %                  W W W    I    D   D  G  GG  EEE      T                     %
00010 %                  WW WW    I    D   D  G   G  E        T                     %
00011 %                  W   W  IIIII  DDDD    GGGG  EEEEE    T                     %
00012 %                                                                             %
00013 %                                                                             %
00014 %                   MagickCore X11 User Interface Methods                     %
00015 %                                                                             %
00016 %                              Software Design                                %
00017 %                                John Cristy                                  %
00018 %                              September 1993                                 %
00019 %                                                                             %
00020 %                                                                             %
00021 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00022 %  dedicated to making software imaging solutions freely available.           %
00023 %                                                                             %
00024 %  You may not use this file except in compliance with the License.  You may  %
00025 %  obtain a copy of the License at                                            %
00026 %                                                                             %
00027 %    http://www.imagemagick.org/script/license.php                            %
00028 %                                                                             %
00029 %  Unless required by applicable law or agreed to in writing, software        %
00030 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00031 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00032 %  See the License for the specific language governing permissions and        %
00033 %  limitations under the License.                                             %
00034 %                                                                             %
00035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
00042 */
00043 #include "MagickCore/studio.h"
00044 #include "MagickCore/color.h"
00045 #include "MagickCore/color-private.h"
00046 #include "MagickCore/exception.h"
00047 #include "MagickCore/exception-private.h"
00048 #include "MagickCore/image.h"
00049 #include "MagickCore/magick.h"
00050 #include "MagickCore/memory_.h"
00051 #include "MagickCore/PreRvIcccm.h"
00052 #include "MagickCore/string_.h"
00053 #include "MagickCore/token.h"
00054 #include "MagickCore/token-private.h"
00055 #include "MagickCore/utility.h"
00056 #include "MagickCore/utility-private.h"
00057 #include "MagickCore/xwindow-private.h"
00058 #include "MagickCore/widget.h"
00059 #include "MagickCore/widget-private.h"
00060 
00061 #if defined(MAGICKCORE_X11_DELEGATE)
00062 
00063 /*
00064   Define declarations.
00065 */
00066 #define AreaIsActive(matte_info,position)  ( \
00067   ((position.y >= (int) (matte_info.y-matte_info.bevel_width)) &&  \
00068    (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
00069    ? MagickTrue : MagickFalse)
00070 #define Extent(s)  ((int) strlen(s))
00071 #define MatteIsActive(matte_info,position)  ( \
00072   ((position.x >= (int) (matte_info.x-matte_info.bevel_width)) && \
00073    (position.y >= (int) (matte_info.y-matte_info.bevel_width)) &&  \
00074    (position.x < (int) (matte_info.x+matte_info.width+matte_info.bevel_width)) &&  \
00075    (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
00076    ? MagickTrue : MagickFalse)
00077 #define MaxTextWidth  ((unsigned int) (255*XTextWidth(font_info,"_",1)))
00078 #define MinTextWidth  (26*XTextWidth(font_info,"_",1))
00079 #define QuantumMargin   MagickMax(font_info->max_bounds.width,12)
00080 #define WidgetTextWidth(font_info,text)  \
00081   ((unsigned int) XTextWidth(font_info,text,Extent(text)))
00082 #define WindowIsActive(window_info,position)  ( \
00083   ((position.x >= 0) && (position.y >= 0) &&  \
00084    (position.x < (int) window_info.width) &&  \
00085    (position.y < (int) window_info.height)) ? MagickTrue : MagickFalse)
00086 
00087 /*
00088   Enum declarations.
00089 */
00090 typedef enum
00091 {
00092   ControlState = 0x0001,
00093   InactiveWidgetState = 0x0004,
00094   JumpListState = 0x0008,
00095   RedrawActionState = 0x0010,
00096   RedrawListState = 0x0020,
00097   RedrawWidgetState = 0x0040,
00098   UpdateListState = 0x0100
00099 } WidgetState;
00100 
00101 /*
00102   Typedef declarations.
00103 */
00104 typedef struct _XWidgetInfo
00105 {
00106   char
00107     *cursor,
00108     *text,
00109     *marker;
00110 
00111   int
00112     id;
00113 
00114   unsigned int
00115     bevel_width,
00116     width,
00117     height;
00118 
00119   int
00120     x,
00121     y,
00122     min_y,
00123     max_y;
00124 
00125   MagickStatusType
00126     raised,
00127     active,
00128     center,
00129     trough,
00130     highlight;
00131 } XWidgetInfo;
00132 
00133 /*
00134   Variable declarations.
00135 */
00136 static XWidgetInfo
00137   monitor_info =
00138   {
00139     (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
00140     MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
00141   },
00142   submenu_info =
00143   {
00144     (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
00145     MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
00146   },
00147   *selection_info = (XWidgetInfo *) NULL,
00148   toggle_info =
00149   {
00150     (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
00151     MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
00152   };
00153 
00154 /*
00155   Constant declarations.
00156 */
00157 static const int
00158   BorderOffset = 4,
00159   DoubleClick = 250;
00160 
00161 /*
00162   Method prototypes.
00163 */
00164 static void
00165   XDrawMatte(Display *,const XWindowInfo *,const XWidgetInfo *),
00166   XSetBevelColor(Display *,const XWindowInfo *,const MagickStatusType),
00167   XSetMatteColor(Display *,const XWindowInfo *,const MagickStatusType),
00168   XSetTextColor(Display *,const XWindowInfo *,const MagickStatusType);
00169 
00170 /*
00171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00172 %                                                                             %
00173 %                                                                             %
00174 %                                                                             %
00175 %   D e s t r o y X W i d g e t                                               %
00176 %                                                                             %
00177 %                                                                             %
00178 %                                                                             %
00179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00180 %
00181 %  DestroyXWidget() destroys resources associated with the X widget.
00182 %
00183 %  The format of the DestroyXWidget method is:
00184 %
00185 %      void DestroyXWidget()
00186 %
00187 %  A description of each parameter follows:
00188 %
00189 */
00190 MagickPrivate void DestroyXWidget(void)
00191 {
00192   if (selection_info != (XWidgetInfo *) NULL)
00193     selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
00194 }
00195 
00196 /*
00197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00198 %                                                                             %
00199 %                                                                             %
00200 %                                                                             %
00201 +   X D r a w B e v e l                                                       %
00202 %                                                                             %
00203 %                                                                             %
00204 %                                                                             %
00205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00206 %
00207 %  XDrawBevel() "sets off" an area with a highlighted upper and left bevel and
00208 %  a shadowed lower and right bevel.  The highlighted and shadowed bevels
00209 %  create a 3-D effect.
00210 %
00211 %  The format of the XDrawBevel function is:
00212 %
00213 %      XDrawBevel(display,window_info,bevel_info)
00214 %
00215 %  A description of each parameter follows:
00216 %
00217 %    o display: Specifies a pointer to the Display structure;  returned from
00218 %      XOpenDisplay.
00219 %
00220 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
00221 %
00222 %    o bevel_info: Specifies a pointer to a XWidgetInfo structure.  It
00223 %      contains the extents of the bevel.
00224 %
00225 */
00226 static void XDrawBevel(Display *display,const XWindowInfo *window_info,
00227   const XWidgetInfo *bevel_info)
00228 {
00229   int
00230     x1,
00231     x2,
00232     y1,
00233     y2;
00234 
00235   unsigned int
00236     bevel_width;
00237 
00238   XPoint
00239     points[6];
00240 
00241   /*
00242     Draw upper and left beveled border.
00243   */
00244   x1=bevel_info->x;
00245   y1=bevel_info->y+bevel_info->height;
00246   x2=bevel_info->x+bevel_info->width;
00247   y2=bevel_info->y;
00248   bevel_width=bevel_info->bevel_width;
00249   points[0].x=x1;
00250   points[0].y=y1;
00251   points[1].x=x1;
00252   points[1].y=y2;
00253   points[2].x=x2;
00254   points[2].y=y2;
00255   points[3].x=x2+bevel_width;
00256   points[3].y=y2-bevel_width;
00257   points[4].x=x1-bevel_width;
00258   points[4].y=y2-bevel_width;
00259   points[5].x=x1-bevel_width;
00260   points[5].y=y1+bevel_width;
00261   XSetBevelColor(display,window_info,bevel_info->raised);
00262   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00263     points,6,Complex,CoordModeOrigin);
00264   /*
00265     Draw lower and right beveled border.
00266   */
00267   points[0].x=x1;
00268   points[0].y=y1;
00269   points[1].x=x2;
00270   points[1].y=y1;
00271   points[2].x=x2;
00272   points[2].y=y2;
00273   points[3].x=x2+bevel_width;
00274   points[3].y=y2-bevel_width;
00275   points[4].x=x2+bevel_width;
00276   points[4].y=y1+bevel_width;
00277   points[5].x=x1-bevel_width;
00278   points[5].y=y1+bevel_width;
00279   XSetBevelColor(display,window_info,!bevel_info->raised);
00280   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00281     points,6,Complex,CoordModeOrigin);
00282   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
00283 }
00284 
00285 /*
00286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00287 %                                                                             %
00288 %                                                                             %
00289 %                                                                             %
00290 +   X D r a w B e v e l e d B u t t o n                                       %
00291 %                                                                             %
00292 %                                                                             %
00293 %                                                                             %
00294 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00295 %
00296 %  XDrawBeveledButton() draws a button with a highlighted upper and left bevel
00297 %  and a shadowed lower and right bevel.  The highlighted and shadowed bevels
00298 %  create a 3-D effect.
00299 %
00300 %  The format of the XDrawBeveledButton function is:
00301 %
00302 %      XDrawBeveledButton(display,window_info,button_info)
00303 %
00304 %  A description of each parameter follows:
00305 %
00306 %    o display: Specifies a pointer to the Display structure;  returned from
00307 %      XOpenDisplay.
00308 %
00309 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
00310 %
00311 %    o button_info: Specifies a pointer to a XWidgetInfo structure.  It
00312 %      contains the extents of the button.
00313 %
00314 */
00315 
00316 static inline int MagickAbsoluteValue(const int x)
00317 {
00318   if (x < 0)
00319     return(-x);
00320   return(x);
00321 }
00322 
00323 static inline int MagickMax(const int x,const int y)
00324 {
00325   if (x > y)
00326     return(x);
00327   return(y);
00328 }
00329 
00330 static inline int MagickMin(const int x,const int y)
00331 {
00332   if (x < y)
00333     return(x);
00334   return(y);
00335 }
00336 
00337 static void XDrawBeveledButton(Display *display,const XWindowInfo *window_info,
00338   const XWidgetInfo *button_info)
00339 {
00340   int
00341     x,
00342     y;
00343 
00344   unsigned int
00345     width;
00346 
00347   XFontStruct
00348     *font_info;
00349 
00350   XRectangle
00351     crop_info;
00352 
00353   /*
00354     Draw matte.
00355   */
00356   XDrawBevel(display,window_info,button_info);
00357   XSetMatteColor(display,window_info,button_info->raised);
00358   (void) XFillRectangle(display,window_info->id,window_info->widget_context,
00359     button_info->x,button_info->y,button_info->width,button_info->height);
00360   x=button_info->x-button_info->bevel_width-1;
00361   y=button_info->y-button_info->bevel_width-1;
00362   (void) XSetForeground(display,window_info->widget_context,
00363     window_info->pixel_info->trough_color.pixel);
00364   if (button_info->raised || (window_info->depth == 1))
00365     (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
00366       x,y,button_info->width+(button_info->bevel_width << 1)+1,
00367       button_info->height+(button_info->bevel_width << 1)+1);
00368   if (button_info->text == (char *) NULL)
00369     return;
00370   /*
00371     Set cropping region.
00372   */
00373   crop_info.width=(unsigned short) button_info->width;
00374   crop_info.height=(unsigned short) button_info->height;
00375   crop_info.x=button_info->x;
00376   crop_info.y=button_info->y;
00377   /*
00378     Draw text.
00379   */
00380   font_info=window_info->font_info;
00381   width=WidgetTextWidth(font_info,button_info->text);
00382   x=button_info->x+(QuantumMargin >> 1);
00383   if (button_info->center)
00384     x=button_info->x+(button_info->width >> 1)-(width >> 1);
00385   y=button_info->y+((button_info->height-
00386     (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
00387   if ((int) button_info->width == (QuantumMargin >> 1))
00388     {
00389       /*
00390         Option button-- write label to right of button.
00391       */
00392       XSetTextColor(display,window_info,MagickTrue);
00393       x=button_info->x+button_info->width+button_info->bevel_width+
00394         (QuantumMargin >> 1);
00395       (void) XDrawString(display,window_info->id,window_info->widget_context,
00396         x,y,button_info->text,Extent(button_info->text));
00397       return;
00398     }
00399   (void) XSetClipRectangles(display,window_info->widget_context,0,0,&crop_info,
00400     1,Unsorted);
00401   XSetTextColor(display,window_info,button_info->raised);
00402   (void) XDrawString(display,window_info->id,window_info->widget_context,x,y,
00403     button_info->text,Extent(button_info->text));
00404   (void) XSetClipMask(display,window_info->widget_context,None);
00405   if (button_info->raised == MagickFalse)
00406     XDelay(display,SuspendTime << 2);
00407 }
00408 
00409 /*
00410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00411 %                                                                             %
00412 %                                                                             %
00413 %                                                                             %
00414 +   X D r a w B e v e l e d M a t t e                                         %
00415 %                                                                             %
00416 %                                                                             %
00417 %                                                                             %
00418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00419 %
00420 %  XDrawBeveledMatte() draws a matte with a shadowed upper and left bevel and
00421 %  a highlighted lower and right bevel.  The highlighted and shadowed bevels
00422 %  create a 3-D effect.
00423 %
00424 %  The format of the XDrawBeveledMatte function is:
00425 %
00426 %      XDrawBeveledMatte(display,window_info,matte_info)
00427 %
00428 %  A description of each parameter follows:
00429 %
00430 %    o display: Specifies a pointer to the Display structure;  returned from
00431 %      XOpenDisplay.
00432 %
00433 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
00434 %
00435 %    o matte_info: Specifies a pointer to a XWidgetInfo structure.  It
00436 %      contains the extents of the matte.
00437 %
00438 */
00439 static void XDrawBeveledMatte(Display *display,const XWindowInfo *window_info,
00440   const XWidgetInfo *matte_info)
00441 {
00442   /*
00443     Draw matte.
00444   */
00445   XDrawBevel(display,window_info,matte_info);
00446   XDrawMatte(display,window_info,matte_info);
00447 }
00448 
00449 /*
00450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00451 %                                                                             %
00452 %                                                                             %
00453 %                                                                             %
00454 +   X D r a w M a t t e                                                       %
00455 %                                                                             %
00456 %                                                                             %
00457 %                                                                             %
00458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00459 %
00460 %  XDrawMatte() fills a rectangular area with the matte color.
00461 %
00462 %  The format of the XDrawMatte function is:
00463 %
00464 %      XDrawMatte(display,window_info,matte_info)
00465 %
00466 %  A description of each parameter follows:
00467 %
00468 %    o display: Specifies a pointer to the Display structure;  returned from
00469 %      XOpenDisplay.
00470 %
00471 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
00472 %
00473 %    o matte_info: Specifies a pointer to a XWidgetInfo structure.  It
00474 %      contains the extents of the matte.
00475 %
00476 */
00477 static void XDrawMatte(Display *display,const XWindowInfo *window_info,
00478   const XWidgetInfo *matte_info)
00479 {
00480   /*
00481     Draw matte.
00482   */
00483   if ((matte_info->trough == MagickFalse) || (window_info->depth == 1))
00484     (void) XFillRectangle(display,window_info->id,
00485       window_info->highlight_context,matte_info->x,matte_info->y,
00486       matte_info->width,matte_info->height);
00487   else
00488     {
00489       (void) XSetForeground(display,window_info->widget_context,
00490         window_info->pixel_info->trough_color.pixel);
00491       (void) XFillRectangle(display,window_info->id,window_info->widget_context,
00492         matte_info->x,matte_info->y,matte_info->width,matte_info->height);
00493     }
00494 }
00495 
00496 /*
00497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00498 %                                                                             %
00499 %                                                                             %
00500 %                                                                             %
00501 +   X D r a w M a t t e T e x t                                               %
00502 %                                                                             %
00503 %                                                                             %
00504 %                                                                             %
00505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00506 %
00507 %  XDrawMatteText() draws a matte with text.  If the text exceeds the extents
00508 %  of the text, a portion of the text relative to the cursor is displayed.
00509 %
00510 %  The format of the XDrawMatteText function is:
00511 %
00512 %      XDrawMatteText(display,window_info,text_info)
00513 %
00514 %  A description of each parameter follows:
00515 %
00516 %    o display: Specifies a pointer to the Display structure;  returned from
00517 %      XOpenDisplay.
00518 %
00519 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
00520 %
00521 %    o text_info: Specifies a pointer to a XWidgetInfo structure.  It
00522 %      contains the extents of the text.
00523 %
00524 */
00525 static void XDrawMatteText(Display *display,const XWindowInfo *window_info,
00526   XWidgetInfo *text_info)
00527 {
00528   const char
00529     *text;
00530 
00531   int
00532     n,
00533     x,
00534     y;
00535 
00536   register int
00537     i;
00538 
00539   unsigned int
00540     height,
00541     width;
00542 
00543   XFontStruct
00544     *font_info;
00545 
00546   XRectangle
00547     crop_info;
00548 
00549   /*
00550     Clear the text area.
00551   */
00552   XSetMatteColor(display,window_info,MagickFalse);
00553   (void) XFillRectangle(display,window_info->id,window_info->widget_context,
00554     text_info->x,text_info->y,text_info->width,text_info->height);
00555   if (text_info->text == (char *) NULL)
00556     return;
00557   XSetTextColor(display,window_info,text_info->highlight);
00558   font_info=window_info->font_info;
00559   x=text_info->x+(QuantumMargin >> 2);
00560   y=text_info->y+font_info->ascent+(text_info->height >> 2);
00561   width=text_info->width-(QuantumMargin >> 1);
00562   height=(unsigned int) (font_info->ascent+font_info->descent);
00563   if (*text_info->text == '\0')
00564     {
00565       /*
00566         No text-- just draw cursor.
00567       */
00568       (void) XDrawLine(display,window_info->id,window_info->annotate_context,
00569         x,y+3,x,y-height+3);
00570       return;
00571     }
00572   /*
00573     Set cropping region.
00574   */
00575   crop_info.width=(unsigned short) text_info->width;
00576   crop_info.height=(unsigned short) text_info->height;
00577   crop_info.x=text_info->x;
00578   crop_info.y=text_info->y;
00579   /*
00580     Determine beginning of the visible text.
00581   */
00582   if (text_info->cursor < text_info->marker)
00583     text_info->marker=text_info->cursor;
00584   else
00585     {
00586       text=text_info->marker;
00587       if (XTextWidth(font_info,(char *) text,(int) (text_info->cursor-text)) >
00588           (int) width)
00589         {
00590           text=text_info->text;
00591           for (i=0; i < Extent(text); i++)
00592           {
00593             n=XTextWidth(font_info,(char *) text+i,(int)
00594               (text_info->cursor-text-i));
00595             if (n <= (int) width)
00596               break;
00597           }
00598           text_info->marker=(char *) text+i;
00599         }
00600     }
00601   /*
00602     Draw text and cursor.
00603   */
00604   if (text_info->highlight == MagickFalse)
00605     {
00606       (void) XSetClipRectangles(display,window_info->widget_context,0,0,
00607         &crop_info,1,Unsorted);
00608       (void) XDrawString(display,window_info->id,window_info->widget_context,
00609         x,y,text_info->marker,Extent(text_info->marker));
00610       (void) XSetClipMask(display,window_info->widget_context,None);
00611     }
00612   else
00613     {
00614       (void) XSetClipRectangles(display,window_info->annotate_context,0,0,
00615         &crop_info,1,Unsorted);
00616       width=WidgetTextWidth(font_info,text_info->marker);
00617       (void) XFillRectangle(display,window_info->id,
00618         window_info->annotate_context,x,y-font_info->ascent,width,height);
00619       (void) XSetClipMask(display,window_info->annotate_context,None);
00620       (void) XSetClipRectangles(display,window_info->highlight_context,0,0,
00621         &crop_info,1,Unsorted);
00622       (void) XDrawString(display,window_info->id,
00623         window_info->highlight_context,x,y,text_info->marker,
00624         Extent(text_info->marker));
00625       (void) XSetClipMask(display,window_info->highlight_context,None);
00626     }
00627   x+=XTextWidth(font_info,text_info->marker,(int)
00628     (text_info->cursor-text_info->marker));
00629   (void) XDrawLine(display,window_info->id,window_info->annotate_context,x,y+3,
00630     x,y-height+3);
00631 }
00632 
00633 /*
00634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00635 %                                                                             %
00636 %                                                                             %
00637 %                                                                             %
00638 +   X D r a w T r i a n g l e E a s t                                         %
00639 %                                                                             %
00640 %                                                                             %
00641 %                                                                             %
00642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00643 %
00644 %  XDrawTriangleEast() draws a triangle with a highlighted left bevel and a
00645 %  shadowed right and lower bevel.  The highlighted and shadowed bevels create
00646 %  a 3-D effect.
00647 %
00648 %  The format of the XDrawTriangleEast function is:
00649 %
00650 %      XDrawTriangleEast(display,window_info,triangle_info)
00651 %
00652 %  A description of each parameter follows:
00653 %
00654 %    o display: Specifies a pointer to the Display structure;  returned from
00655 %      XOpenDisplay.
00656 %
00657 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
00658 %
00659 %    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
00660 %      contains the extents of the triangle.
00661 %
00662 */
00663 static void XDrawTriangleEast(Display *display,const XWindowInfo *window_info,
00664   const XWidgetInfo *triangle_info)
00665 {
00666   int
00667     x1,
00668     x2,
00669     x3,
00670     y1,
00671     y2,
00672     y3;
00673 
00674   unsigned int
00675     bevel_width;
00676 
00677   XFontStruct
00678     *font_info;
00679 
00680   XPoint
00681     points[4];
00682 
00683   /*
00684     Draw triangle matte.
00685   */
00686   x1=triangle_info->x;
00687   y1=triangle_info->y;
00688   x2=triangle_info->x+triangle_info->width;
00689   y2=triangle_info->y+(triangle_info->height >> 1);
00690   x3=triangle_info->x;
00691   y3=triangle_info->y+triangle_info->height;
00692   bevel_width=triangle_info->bevel_width;
00693   points[0].x=x1;
00694   points[0].y=y1;
00695   points[1].x=x2;
00696   points[1].y=y2;
00697   points[2].x=x3;
00698   points[2].y=y3;
00699   XSetMatteColor(display,window_info,triangle_info->raised);
00700   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00701     points,3,Complex,CoordModeOrigin);
00702   /*
00703     Draw bottom bevel.
00704   */
00705   points[0].x=x2;
00706   points[0].y=y2;
00707   points[1].x=x3;
00708   points[1].y=y3;
00709   points[2].x=x3-bevel_width;
00710   points[2].y=y3+bevel_width;
00711   points[3].x=x2+bevel_width;
00712   points[3].y=y2;
00713   XSetBevelColor(display,window_info,!triangle_info->raised);
00714   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00715     points,4,Complex,CoordModeOrigin);
00716   /*
00717     Draw Left bevel.
00718   */
00719   points[0].x=x3;
00720   points[0].y=y3;
00721   points[1].x=x1;
00722   points[1].y=y1;
00723   points[2].x=x1-bevel_width+1;
00724   points[2].y=y1-bevel_width;
00725   points[3].x=x3-bevel_width+1;
00726   points[3].y=y3+bevel_width;
00727   XSetBevelColor(display,window_info,triangle_info->raised);
00728   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00729     points,4,Complex,CoordModeOrigin);
00730   /*
00731     Draw top bevel.
00732   */
00733   points[0].x=x1;
00734   points[0].y=y1;
00735   points[1].x=x2;
00736   points[1].y=y2;
00737   points[2].x=x2+bevel_width;
00738   points[2].y=y2;
00739   points[3].x=x1-bevel_width;
00740   points[3].y=y1-bevel_width;
00741   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00742     points,4,Complex,CoordModeOrigin);
00743   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
00744   if (triangle_info->text == (char *) NULL)
00745     return;
00746   /*
00747     Write label to right of triangle.
00748   */
00749   font_info=window_info->font_info;
00750   XSetTextColor(display,window_info,MagickTrue);
00751   x1=triangle_info->x+triangle_info->width+triangle_info->bevel_width+
00752     (QuantumMargin >> 1);
00753   y1=triangle_info->y+((triangle_info->height-
00754     (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
00755   (void) XDrawString(display,window_info->id,window_info->widget_context,x1,y1,
00756     triangle_info->text,Extent(triangle_info->text));
00757 }
00758 
00759 /*
00760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00761 %                                                                             %
00762 %                                                                             %
00763 %                                                                             %
00764 +   X D r a w T r i a n g l e N o r t h                                       %
00765 %                                                                             %
00766 %                                                                             %
00767 %                                                                             %
00768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00769 %
00770 %  XDrawTriangleNorth() draws a triangle with a highlighted left bevel and a
00771 %  shadowed right and lower bevel.  The highlighted and shadowed bevels create
00772 %  a 3-D effect.
00773 %
00774 %  The format of the XDrawTriangleNorth function is:
00775 %
00776 %      XDrawTriangleNorth(display,window_info,triangle_info)
00777 %
00778 %  A description of each parameter follows:
00779 %
00780 %    o display: Specifies a pointer to the Display structure;  returned from
00781 %      XOpenDisplay.
00782 %
00783 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
00784 %
00785 %    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
00786 %      contains the extents of the triangle.
00787 %
00788 */
00789 static void XDrawTriangleNorth(Display *display,const XWindowInfo *window_info,
00790   const XWidgetInfo *triangle_info)
00791 {
00792   int
00793     x1,
00794     x2,
00795     x3,
00796     y1,
00797     y2,
00798     y3;
00799 
00800   unsigned int
00801     bevel_width;
00802 
00803   XPoint
00804     points[4];
00805 
00806   /*
00807     Draw triangle matte.
00808   */
00809   x1=triangle_info->x;
00810   y1=triangle_info->y+triangle_info->height;
00811   x2=triangle_info->x+(triangle_info->width >> 1);
00812   y2=triangle_info->y;
00813   x3=triangle_info->x+triangle_info->width;
00814   y3=triangle_info->y+triangle_info->height;
00815   bevel_width=triangle_info->bevel_width;
00816   points[0].x=x1;
00817   points[0].y=y1;
00818   points[1].x=x2;
00819   points[1].y=y2;
00820   points[2].x=x3;
00821   points[2].y=y3;
00822   XSetMatteColor(display,window_info,triangle_info->raised);
00823   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00824     points,3,Complex,CoordModeOrigin);
00825   /*
00826     Draw left bevel.
00827   */
00828   points[0].x=x1;
00829   points[0].y=y1;
00830   points[1].x=x2;
00831   points[1].y=y2;
00832   points[2].x=x2;
00833   points[2].y=y2-bevel_width-2;
00834   points[3].x=x1-bevel_width-1;
00835   points[3].y=y1+bevel_width;
00836   XSetBevelColor(display,window_info,triangle_info->raised);
00837   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00838     points,4,Complex,CoordModeOrigin);
00839   /*
00840     Draw right bevel.
00841   */
00842   points[0].x=x2;
00843   points[0].y=y2;
00844   points[1].x=x3;
00845   points[1].y=y3;
00846   points[2].x=x3+bevel_width;
00847   points[2].y=y3+bevel_width;
00848   points[3].x=x2;
00849   points[3].y=y2-bevel_width;
00850   XSetBevelColor(display,window_info,!triangle_info->raised);
00851   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00852     points,4,Complex,CoordModeOrigin);
00853   /*
00854     Draw lower bevel.
00855   */
00856   points[0].x=x3;
00857   points[0].y=y3;
00858   points[1].x=x1;
00859   points[1].y=y1;
00860   points[2].x=x1-bevel_width;
00861   points[2].y=y1+bevel_width;
00862   points[3].x=x3+bevel_width;
00863   points[3].y=y3+bevel_width;
00864   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00865     points,4,Complex,CoordModeOrigin);
00866   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
00867 }
00868 
00869 /*
00870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00871 %                                                                             %
00872 %                                                                             %
00873 %                                                                             %
00874 +   X D r a w T r i a n g l e S o u t h                                       %
00875 %                                                                             %
00876 %                                                                             %
00877 %                                                                             %
00878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00879 %
00880 %  XDrawTriangleSouth() draws a border with a highlighted left and right bevel
00881 %  and a shadowed lower bevel.  The highlighted and shadowed bevels create a
00882 %  3-D effect.
00883 %
00884 %  The format of the XDrawTriangleSouth function is:
00885 %
00886 %      XDrawTriangleSouth(display,window_info,triangle_info)
00887 %
00888 %  A description of each parameter follows:
00889 %
00890 %    o display: Specifies a pointer to the Display structure;  returned from
00891 %      XOpenDisplay.
00892 %
00893 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
00894 %
00895 %    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
00896 %      contains the extents of the triangle.
00897 %
00898 */
00899 static void XDrawTriangleSouth(Display *display,const XWindowInfo *window_info,
00900   const XWidgetInfo *triangle_info)
00901 {
00902   int
00903     x1,
00904     x2,
00905     x3,
00906     y1,
00907     y2,
00908     y3;
00909 
00910   unsigned int
00911     bevel_width;
00912 
00913   XPoint
00914     points[4];
00915 
00916   /*
00917     Draw triangle matte.
00918   */
00919   x1=triangle_info->x;
00920   y1=triangle_info->y;
00921   x2=triangle_info->x+(triangle_info->width >> 1);
00922   y2=triangle_info->y+triangle_info->height;
00923   x3=triangle_info->x+triangle_info->width;
00924   y3=triangle_info->y;
00925   bevel_width=triangle_info->bevel_width;
00926   points[0].x=x1;
00927   points[0].y=y1;
00928   points[1].x=x2;
00929   points[1].y=y2;
00930   points[2].x=x3;
00931   points[2].y=y3;
00932   XSetMatteColor(display,window_info,triangle_info->raised);
00933   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00934     points,3,Complex,CoordModeOrigin);
00935   /*
00936     Draw top bevel.
00937   */
00938   points[0].x=x3;
00939   points[0].y=y3;
00940   points[1].x=x1;
00941   points[1].y=y1;
00942   points[2].x=x1-bevel_width;
00943   points[2].y=y1-bevel_width;
00944   points[3].x=x3+bevel_width;
00945   points[3].y=y3-bevel_width;
00946   XSetBevelColor(display,window_info,triangle_info->raised);
00947   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00948     points,4,Complex,CoordModeOrigin);
00949   /*
00950     Draw right bevel.
00951   */
00952   points[0].x=x2;
00953   points[0].y=y2;
00954   points[1].x=x3+1;
00955   points[1].y=y3-bevel_width;
00956   points[2].x=x3+bevel_width;
00957   points[2].y=y3-bevel_width;
00958   points[3].x=x2;
00959   points[3].y=y2+bevel_width;
00960   XSetBevelColor(display,window_info,!triangle_info->raised);
00961   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00962     points,4,Complex,CoordModeOrigin);
00963   /*
00964     Draw left bevel.
00965   */
00966   points[0].x=x1;
00967   points[0].y=y1;
00968   points[1].x=x2;
00969   points[1].y=y2;
00970   points[2].x=x2;
00971   points[2].y=y2+bevel_width;
00972   points[3].x=x1-bevel_width;
00973   points[3].y=y1-bevel_width;
00974   XSetBevelColor(display,window_info,triangle_info->raised);
00975   (void) XFillPolygon(display,window_info->id,window_info->widget_context,
00976     points,4,Complex,CoordModeOrigin);
00977   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
00978 }
00979 
00980 /*
00981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00982 %                                                                             %
00983 %                                                                             %
00984 %                                                                             %
00985 +   X D r a w W i d g e t T e x t                                             %
00986 %                                                                             %
00987 %                                                                             %
00988 %                                                                             %
00989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00990 %
00991 %  XDrawWidgetText() first clears the widget and draws a text string justifed
00992 %  left (or center) in the x-direction and centered within the y-direction.
00993 %
00994 %  The format of the XDrawWidgetText function is:
00995 %
00996 %      XDrawWidgetText(display,window_info,text_info)
00997 %
00998 %  A description of each parameter follows:
00999 %
01000 %    o display: Specifies a pointer to the Display structure;  returned from
01001 %      XOpenDisplay.
01002 %
01003 %    o window_info: Specifies a pointer to a XWindowText structure.
01004 %
01005 %    o text_info: Specifies a pointer to XWidgetInfo structure.
01006 %
01007 */
01008 static void XDrawWidgetText(Display *display,const XWindowInfo *window_info,
01009   XWidgetInfo *text_info)
01010 {
01011   GC
01012     widget_context;
01013 
01014   int
01015     x,
01016     y;
01017 
01018   unsigned int
01019     height,
01020     width;
01021 
01022   XFontStruct
01023     *font_info;
01024 
01025   XRectangle
01026     crop_info;
01027 
01028   /*
01029     Clear the text area.
01030   */
01031   widget_context=window_info->annotate_context;
01032   if (text_info->raised)
01033     (void) XClearArea(display,window_info->id,text_info->x,text_info->y,
01034       text_info->width,text_info->height,MagickFalse);
01035   else
01036     {
01037       (void) XFillRectangle(display,window_info->id,widget_context,text_info->x,
01038         text_info->y,text_info->width,text_info->height);
01039       widget_context=window_info->highlight_context;
01040     }
01041   if (text_info->text == (char *) NULL)
01042     return;
01043   if (*text_info->text == '\0')
01044     return;
01045   /*
01046     Set cropping region.
01047   */
01048   font_info=window_info->font_info;
01049   crop_info.width=(unsigned short) text_info->width;
01050   crop_info.height=(unsigned short) text_info->height;
01051   crop_info.x=text_info->x;
01052   crop_info.y=text_info->y;
01053   /*
01054     Draw text.
01055   */
01056   width=WidgetTextWidth(font_info,text_info->text);
01057   x=text_info->x+(QuantumMargin >> 1);
01058   if (text_info->center)
01059     x=text_info->x+(text_info->width >> 1)-(width >> 1);
01060   if (text_info->raised)
01061     if (width > (text_info->width-QuantumMargin))
01062       x+=(text_info->width-QuantumMargin-width);
01063   height=(unsigned int) (font_info->ascent+font_info->descent);
01064   y=text_info->y+((text_info->height-height) >> 1)+font_info->ascent;
01065   (void) XSetClipRectangles(display,widget_context,0,0,&crop_info,1,Unsorted);
01066   (void) XDrawString(display,window_info->id,widget_context,x,y,text_info->text,
01067     Extent(text_info->text));
01068   (void) XSetClipMask(display,widget_context,None);
01069   if (x < text_info->x)
01070     (void) XDrawLine(display,window_info->id,window_info->annotate_context,
01071       text_info->x,text_info->y,text_info->x,text_info->y+text_info->height-1);
01072 }
01073 
01074 /*
01075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01076 %                                                                             %
01077 %                                                                             %
01078 %                                                                             %
01079 +   X E d i t T e x t                                                         %
01080 %                                                                             %
01081 %                                                                             %
01082 %                                                                             %
01083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01084 %
01085 %  XEditText() edits a text string as indicated by the key symbol.
01086 %
01087 %  The format of the XEditText function is:
01088 %
01089 %      XEditText(display,text_info,key_symbol,text,state)
01090 %
01091 %  A description of each parameter follows:
01092 %
01093 %    o display: Specifies a connection to an X server;  returned from
01094 %      XOpenDisplay.
01095 %
01096 %    o text_info: Specifies a pointer to a XWidgetInfo structure.  It
01097 %      contains the extents of the text.
01098 %
01099 %    o key_symbol:  A X11 KeySym that indicates what editing function to
01100 %      perform to the text.
01101 %
01102 %    o text: A character string to insert into the text.
01103 %
01104 %    o state:  An size_t that indicates whether the key symbol is a
01105 %      control character or not.
01106 %
01107 */
01108 static void XEditText(Display *display,XWidgetInfo *text_info,
01109   const KeySym key_symbol,char *text,const size_t state)
01110 {
01111   switch ((int) key_symbol)
01112   {
01113     case XK_BackSpace:
01114     case XK_Delete:
01115     {
01116       if (text_info->highlight)
01117         {
01118           /*
01119             Erase the entire line of text.
01120           */
01121           *text_info->text='\0';
01122           text_info->cursor=text_info->text;
01123           text_info->marker=text_info->text;
01124           text_info->highlight=MagickFalse;
01125         }
01126       /*
01127         Erase one character.
01128       */
01129       if (text_info->cursor != text_info->text)
01130         {
01131           text_info->cursor--;
01132           (void) CopyMagickString(text_info->cursor,text_info->cursor+1,
01133             MaxTextExtent);
01134           text_info->highlight=MagickFalse;
01135           break;
01136         }
01137     }
01138     case XK_Left:
01139     case XK_KP_Left:
01140     {
01141       /*
01142         Move cursor one position left.
01143       */
01144       if (text_info->cursor == text_info->text)
01145         break;
01146       text_info->cursor--;
01147       break;
01148     }
01149     case XK_Right:
01150     case XK_KP_Right:
01151     {
01152       /*
01153         Move cursor one position right.
01154       */
01155       if (text_info->cursor == (text_info->text+Extent(text_info->text)))
01156         break;
01157       text_info->cursor++;
01158       break;
01159     }
01160     default:
01161     {
01162       register char
01163         *p,
01164         *q;
01165 
01166       register int
01167         i;
01168 
01169       if (state & ControlState)
01170         break;
01171       if (*text == '\0')
01172         break;
01173       if ((Extent(text_info->text)+1) >= (int) MaxTextExtent)
01174         (void) XBell(display,0);
01175       else
01176         {
01177           if (text_info->highlight)
01178             {
01179               /*
01180                 Erase the entire line of text.
01181               */
01182               *text_info->text='\0';
01183               text_info->cursor=text_info->text;
01184               text_info->marker=text_info->text;
01185               text_info->highlight=MagickFalse;
01186             }
01187           /*
01188             Insert a string into the text.
01189           */
01190           q=text_info->text+Extent(text_info->text)+strlen(text);
01191           for (i=0; i <= Extent(text_info->cursor); i++)
01192           {
01193             *q=(*(q-Extent(text)));
01194             q--;
01195           }
01196           p=text;
01197           for (i=0; i < Extent(text); i++)
01198             *text_info->cursor++=(*p++);
01199         }
01200       break;
01201     }
01202   }
01203 }
01204 
01205 /*
01206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01207 %                                                                             %
01208 %                                                                             %
01209 %                                                                             %
01210 +   X G e t W i d g e t I n f o                                               %
01211 %                                                                             %
01212 %                                                                             %
01213 %                                                                             %
01214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01215 %
01216 %  XGetWidgetInfo() initializes the XWidgetInfo structure.
01217 %
01218 %  The format of the XGetWidgetInfo function is:
01219 %
01220 %      XGetWidgetInfo(text,widget_info)
01221 %
01222 %  A description of each parameter follows:
01223 %
01224 %    o text: A string of characters associated with the widget.
01225 %
01226 %    o widget_info: Specifies a pointer to a X11 XWidgetInfo structure.
01227 %
01228 */
01229 static void XGetWidgetInfo(const char *text,XWidgetInfo *widget_info)
01230 {
01231   /*
01232     Initialize widget info.
01233   */
01234   widget_info->id=(~0);
01235   widget_info->bevel_width=3;
01236   widget_info->width=1;
01237   widget_info->height=1;
01238   widget_info->x=0;
01239   widget_info->y=0;
01240   widget_info->min_y=0;
01241   widget_info->max_y=0;
01242   widget_info->raised=MagickTrue;
01243   widget_info->active=MagickFalse;
01244   widget_info->center=MagickTrue;
01245   widget_info->trough=MagickFalse;
01246   widget_info->highlight=MagickFalse;
01247   widget_info->text=(char *) text;
01248   widget_info->cursor=(char *) text;
01249   if (text != (char *) NULL)
01250     widget_info->cursor+=Extent(text);
01251   widget_info->marker=(char *) text;
01252 }
01253 
01254 /*
01255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01256 %                                                                             %
01257 %                                                                             %
01258 %                                                                             %
01259 +   X H i g h l i g h t W i d g e t                                           %
01260 %                                                                             %
01261 %                                                                             %
01262 %                                                                             %
01263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01264 %
01265 %  XHighlightWidget() draws a highlighted border around a window.
01266 %
01267 %  The format of the XHighlightWidget function is:
01268 %
01269 %      XHighlightWidget(display,window_info,x,y)
01270 %
01271 %  A description of each parameter follows:
01272 %
01273 %    o display: Specifies a pointer to the Display structure;  returned from
01274 %      XOpenDisplay.
01275 %
01276 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
01277 %
01278 %    o x: Specifies an integer representing the rectangle offset in the
01279 %      x-direction.
01280 %
01281 %    o y: Specifies an integer representing the rectangle offset in the
01282 %      y-direction.
01283 %
01284 */
01285 static void XHighlightWidget(Display *display,const XWindowInfo *window_info,
01286   const int x,const int y)
01287 {
01288   /*
01289     Draw the widget highlighting rectangle.
01290   */
01291   XSetBevelColor(display,window_info,MagickTrue);
01292   (void) XDrawRectangle(display,window_info->id,window_info->widget_context,x,y,
01293     window_info->width-(x << 1),window_info->height-(y << 1));
01294   (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
01295     x-1,y-1,window_info->width-(x << 1)+1,window_info->height-(y << 1)+1);
01296   XSetBevelColor(display,window_info,MagickFalse);
01297   (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
01298     x-1,y-1,window_info->width-(x << 1),window_info->height-(y << 1));
01299   (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
01300 }
01301 
01302 /*
01303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01304 %                                                                             %
01305 %                                                                             %
01306 %                                                                             %
01307 +   X S c r e e n E v e n t                                                   %
01308 %                                                                             %
01309 %                                                                             %
01310 %                                                                             %
01311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01312 %
01313 %  XScreenEvent() returns MagickTrue if the any event on the X server queue is
01314 %  associated with the widget window.
01315 %
01316 %  The format of the XScreenEvent function is:
01317 %
01318 %      int XScreenEvent(Display *display,XEvent *event,char *data)
01319 %
01320 %  A description of each parameter follows:
01321 %
01322 %    o display: Specifies a pointer to the Display structure;  returned from
01323 %      XOpenDisplay.
01324 %
01325 %    o event: Specifies a pointer to a X11 XEvent structure.
01326 %
01327 %    o data: Specifies a pointer to a XWindows structure.
01328 %
01329 */
01330 
01331 #if defined(__cplusplus) || defined(c_plusplus)
01332 extern "C" {
01333 #endif
01334 
01335 static int XScreenEvent(Display *display,XEvent *event,char *data)
01336 {
01337   XWindows
01338     *windows;
01339 
01340   windows=(XWindows *) data;
01341   if (event->xany.window == windows->popup.id)
01342     {
01343       if (event->type == MapNotify)
01344         windows->popup.mapped=MagickTrue;
01345       if (event->type == UnmapNotify)
01346         windows->popup.mapped=MagickFalse;
01347       return(MagickTrue);
01348     }
01349   if (event->xany.window == windows->widget.id)
01350     {
01351       if (event->type == MapNotify)
01352         windows->widget.mapped=MagickTrue;
01353       if (event->type == UnmapNotify)
01354         windows->widget.mapped=MagickFalse;
01355       return(MagickTrue);
01356     }
01357   switch (event->type)
01358   {
01359     case ButtonPress:
01360     {
01361       if ((event->xbutton.button == Button3) &&
01362           (event->xbutton.state & Mod1Mask))
01363         {
01364           /*
01365             Convert Alt-Button3 to Button2.
01366           */
01367           event->xbutton.button=Button2;
01368           event->xbutton.state&=(~Mod1Mask);
01369         }
01370       return(MagickTrue);
01371     }
01372     case Expose:
01373     {
01374       if (event->xexpose.window == windows->image.id)
01375         {
01376           XRefreshWindow(display,&windows->image,event);
01377           break;
01378         }
01379       if (event->xexpose.window == windows->magnify.id)
01380         if (event->xexpose.count == 0)
01381           if (windows->magnify.mapped)
01382             {
01383               ExceptionInfo
01384                 *exception;
01385 
01386               exception=AcquireExceptionInfo();
01387               XMakeMagnifyImage(display,windows,exception);
01388               exception=DestroyExceptionInfo(exception);
01389               break;
01390             }
01391       if (event->xexpose.window == windows->command.id)
01392         if (event->xexpose.count == 0)
01393           {
01394             (void) XCommandWidget(display,windows,(const char **) NULL,event);
01395             break;
01396           }
01397       break;
01398     }
01399     case FocusOut:
01400     {
01401       /*
01402         Set input focus for backdrop window.
01403       */
01404       if (event->xfocus.window == windows->image.id)
01405         (void) XSetInputFocus(display,windows->image.id,RevertToNone,
01406           CurrentTime);
01407       return(MagickTrue);
01408     }
01409     case ButtonRelease:
01410     case KeyPress:
01411     case KeyRelease:
01412     case MotionNotify:
01413     case SelectionNotify:
01414       return(MagickTrue);
01415     default:
01416       break;
01417   }
01418   return(MagickFalse);
01419 }
01420 
01421 #if defined(__cplusplus) || defined(c_plusplus)
01422 }
01423 #endif
01424 
01425 /*
01426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01427 %                                                                             %
01428 %                                                                             %
01429 %                                                                             %
01430 +   X S e t B e v e l C o l o r                                               %
01431 %                                                                             %
01432 %                                                                             %
01433 %                                                                             %
01434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01435 %
01436 %  XSetBevelColor() sets the graphic context for drawing a beveled border.
01437 %
01438 %  The format of the XSetBevelColor function is:
01439 %
01440 %      XSetBevelColor(display,window_info,raised)
01441 %
01442 %  A description of each parameter follows:
01443 %
01444 %    o display: Specifies a pointer to the Display structure;  returned from
01445 %      XOpenDisplay.
01446 %
01447 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
01448 %
01449 %    o raised: A value other than zero indicates the color show be a
01450 %      "highlight" color, otherwise the "shadow" color is set.
01451 %
01452 */
01453 static void XSetBevelColor(Display *display,const XWindowInfo *window_info,
01454   const MagickStatusType raised)
01455 {
01456   if (window_info->depth == 1)
01457     {
01458       Pixmap
01459         stipple;
01460 
01461       /*
01462         Monochrome window.
01463       */
01464       (void) XSetBackground(display,window_info->widget_context,
01465         XBlackPixel(display,window_info->screen));
01466       (void) XSetForeground(display,window_info->widget_context,
01467         XWhitePixel(display,window_info->screen));
01468       (void) XSetFillStyle(display,window_info->widget_context,
01469         FillOpaqueStippled);
01470       stipple=window_info->highlight_stipple;
01471       if (raised == MagickFalse)
01472         stipple=window_info->shadow_stipple;
01473       (void) XSetStipple(display,window_info->widget_context,stipple);
01474     }
01475   else
01476     if (raised)
01477       (void) XSetForeground(display,window_info->widget_context,
01478         window_info->pixel_info->highlight_color.pixel);
01479     else
01480       (void) XSetForeground(display,window_info->widget_context,
01481         window_info->pixel_info->shadow_color.pixel);
01482 }
01483 
01484 /*
01485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01486 %                                                                             %
01487 %                                                                             %
01488 %                                                                             %
01489 +   X S e t M a t t e C o l o r                                               %
01490 %                                                                             %
01491 %                                                                             %
01492 %                                                                             %
01493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01494 %
01495 %  XSetMatteColor() sets the graphic context for drawing the matte.
01496 %
01497 %  The format of the XSetMatteColor function is:
01498 %
01499 %      XSetMatteColor(display,window_info,raised)
01500 %
01501 %  A description of each parameter follows:
01502 %
01503 %    o display: Specifies a pointer to the Display structure;  returned from
01504 %      XOpenDisplay.
01505 %
01506 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
01507 %
01508 %    o raised: A value other than zero indicates the matte is active.
01509 %
01510 */
01511 static void XSetMatteColor(Display *display,const XWindowInfo *window_info,
01512   const MagickStatusType raised)
01513 {
01514   if (window_info->depth == 1)
01515     {
01516       /*
01517         Monochrome window.
01518       */
01519       if (raised)
01520         (void) XSetForeground(display,window_info->widget_context,
01521           XWhitePixel(display,window_info->screen));
01522       else
01523         (void) XSetForeground(display,window_info->widget_context,
01524           XBlackPixel(display,window_info->screen));
01525     }
01526   else
01527     if (raised)
01528       (void) XSetForeground(display,window_info->widget_context,
01529         window_info->pixel_info->matte_color.pixel);
01530     else
01531       (void) XSetForeground(display,window_info->widget_context,
01532         window_info->pixel_info->depth_color.pixel);
01533 }
01534 
01535 /*
01536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01537 %                                                                             %
01538 %                                                                             %
01539 %                                                                             %
01540 +   X S e t T e x t C o l o r                                                 %
01541 %                                                                             %
01542 %                                                                             %
01543 %                                                                             %
01544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01545 %
01546 %  XSetTextColor() sets the graphic context for drawing text on a matte.
01547 %
01548 %  The format of the XSetTextColor function is:
01549 %
01550 %      XSetTextColor(display,window_info,raised)
01551 %
01552 %  A description of each parameter follows:
01553 %
01554 %    o display: Specifies a pointer to the Display structure;  returned from
01555 %      XOpenDisplay.
01556 %
01557 %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
01558 %
01559 %    o raised: A value other than zero indicates the color show be a
01560 %      "highlight" color, otherwise the "shadow" color is set.
01561 %
01562 */
01563 static void XSetTextColor(Display *display,const XWindowInfo *window_info,
01564   const MagickStatusType raised)
01565 {
01566   ssize_t
01567     foreground,
01568     matte;
01569 
01570   if (window_info->depth == 1)
01571     {
01572       /*
01573         Monochrome window.
01574       */
01575       if (raised)
01576         (void) XSetForeground(display,window_info->widget_context,
01577           XBlackPixel(display,window_info->screen));
01578       else
01579         (void) XSetForeground(display,window_info->widget_context,
01580           XWhitePixel(display,window_info->screen));
01581       return;
01582     }
01583   foreground=(ssize_t) XPixelIntensity(
01584     &window_info->pixel_info->foreground_color);
01585   matte=(ssize_t) XPixelIntensity(&window_info->pixel_info->matte_color);
01586   if (MagickAbsoluteValue((int) (foreground-matte)) > (65535L >> 3))
01587     (void) XSetForeground(display,window_info->widget_context,
01588       window_info->pixel_info->foreground_color.pixel);
01589   else
01590     (void) XSetForeground(display,window_info->widget_context,
01591       window_info->pixel_info->background_color.pixel);
01592 }
01593 
01594 /*
01595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01596 %                                                                             %
01597 %                                                                             %
01598 %                                                                             %
01599 %   X C o l o r B r o w s e r W i d g e t                                     %
01600 %                                                                             %
01601 %                                                                             %
01602 %                                                                             %
01603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01604 %
01605 %  XColorBrowserWidget() displays a Color Browser widget with a color query
01606 %  to the user.  The user keys a reply and presses the Action or Cancel button
01607 %  to exit.  The typed text is returned as the reply function parameter.
01608 %
01609 %  The format of the XColorBrowserWidget method is:
01610 %
01611 %      void XColorBrowserWidget(Display *display,XWindows *windows,
01612 %        const char *action,char *reply)
01613 %
01614 %  A description of each parameter follows:
01615 %
01616 %    o display: Specifies a connection to an X server;  returned from
01617 %      XOpenDisplay.
01618 %
01619 %    o window: Specifies a pointer to a XWindows structure.
01620 %
01621 %    o action: Specifies a pointer to the action of this widget.
01622 %
01623 %    o reply: the response from the user is returned in this parameter.
01624 %
01625 */
01626 MagickPrivate void XColorBrowserWidget(Display *display,XWindows *windows,
01627   const char *action,char *reply)
01628 {
01629 #define CancelButtonText  "Cancel"
01630 #define ColornameText  "Name:"
01631 #define ColorPatternText  "Pattern:"
01632 #define GrabButtonText  "Grab"
01633 #define ResetButtonText  "Reset"
01634 
01635   char
01636     **colorlist,
01637     primary_selection[MaxTextExtent],
01638     reset_pattern[MaxTextExtent],
01639     text[MaxTextExtent];
01640 
01641   ExceptionInfo
01642     *exception;
01643 
01644   int
01645     x,
01646     y;
01647 
01648   register int
01649     i;
01650 
01651   static char
01652     glob_pattern[MaxTextExtent] = "*";
01653 
01654   static MagickStatusType
01655     mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
01656 
01657   Status
01658     status;
01659 
01660   unsigned int
01661     height,
01662     text_width,
01663     visible_colors,
01664     width;
01665 
01666   size_t
01667     colors,
01668     delay,
01669     state;
01670 
01671   XColor
01672     color;
01673 
01674   XEvent
01675     event;
01676 
01677   XFontStruct
01678     *font_info;
01679 
01680   XTextProperty
01681     window_name;
01682 
01683   XWidgetInfo
01684     action_info,
01685     cancel_info,
01686     expose_info,
01687     grab_info,
01688     list_info,
01689     mode_info,
01690     north_info,
01691     reply_info,
01692     reset_info,
01693     scroll_info,
01694     selection_info,
01695     slider_info,
01696     south_info,
01697     text_info;
01698 
01699   XWindowChanges
01700     window_changes;
01701 
01702   /*
01703     Get color list and sort in ascending order.
01704   */
01705   assert(display != (Display *) NULL);
01706   assert(windows != (XWindows *) NULL);
01707   assert(action != (char *) NULL);
01708   assert(reply != (char *) NULL);
01709   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
01710   XSetCursorState(display,windows,MagickTrue);
01711   XCheckRefreshWindows(display,windows);
01712   (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
01713   exception=AcquireExceptionInfo();
01714   colorlist=GetColorList(glob_pattern,&colors,exception);
01715   if (colorlist == (char **) NULL)
01716     {
01717       /*
01718         Pattern failed, obtain all the colors.
01719       */
01720       (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
01721       colorlist=GetColorList(glob_pattern,&colors,exception);
01722       if (colorlist == (char **) NULL)
01723         {
01724           XNoticeWidget(display,windows,"Unable to obtain colors names:",
01725             glob_pattern);
01726           (void) XDialogWidget(display,windows,action,"Enter color name:",
01727             reply);
01728           return;
01729         }
01730     }
01731   /*
01732     Determine Color Browser widget attributes.
01733   */
01734   font_info=windows->widget.font_info;
01735   text_width=0;
01736   for (i=0; i < (int) colors; i++)
01737     if (WidgetTextWidth(font_info,colorlist[i]) > text_width)
01738       text_width=WidgetTextWidth(font_info,colorlist[i]);
01739   width=WidgetTextWidth(font_info,(char *) action);
01740   if (WidgetTextWidth(font_info,CancelButtonText) > width)
01741     width=WidgetTextWidth(font_info,CancelButtonText);
01742   if (WidgetTextWidth(font_info,ResetButtonText) > width)
01743     width=WidgetTextWidth(font_info,ResetButtonText);
01744   if (WidgetTextWidth(font_info,GrabButtonText) > width)
01745     width=WidgetTextWidth(font_info,GrabButtonText);
01746   width+=QuantumMargin;
01747   if (WidgetTextWidth(font_info,ColorPatternText) > width)
01748     width=WidgetTextWidth(font_info,ColorPatternText);
01749   if (WidgetTextWidth(font_info,ColornameText) > width)
01750     width=WidgetTextWidth(font_info,ColornameText);
01751   height=(unsigned int) (font_info->ascent+font_info->descent);
01752   /*
01753     Position Color Browser widget.
01754   */
01755   windows->widget.width=(unsigned int)
01756     (width+MagickMin((int) text_width,(int) MaxTextWidth)+6*QuantumMargin);
01757   windows->widget.min_width=(unsigned int)
01758     (width+MinTextWidth+4*QuantumMargin);
01759   if (windows->widget.width < windows->widget.min_width)
01760     windows->widget.width=windows->widget.min_width;
01761   windows->widget.height=(unsigned int)
01762     ((81*height) >> 2)+((13*QuantumMargin) >> 1)+4;
01763   windows->widget.min_height=(unsigned int)
01764     (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
01765   if (windows->widget.height < windows->widget.min_height)
01766     windows->widget.height=windows->widget.min_height;
01767   XConstrainWindowPosition(display,&windows->widget);
01768   /*
01769     Map Color Browser widget.
01770   */
01771   (void) CopyMagickString(windows->widget.name,"Browse and Select a Color",
01772     MaxTextExtent);
01773   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
01774   if (status != False)
01775     {
01776       XSetWMName(display,windows->widget.id,&window_name);
01777       XSetWMIconName(display,windows->widget.id,&window_name);
01778       (void) XFree((void *) window_name.value);
01779     }
01780   window_changes.width=(int) windows->widget.width;
01781   window_changes.height=(int) windows->widget.height;
01782   window_changes.x=windows->widget.x;
01783   window_changes.y=windows->widget.y;
01784   (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
01785     mask,&window_changes);
01786   (void) XMapRaised(display,windows->widget.id);
01787   windows->widget.mapped=MagickFalse;
01788   /*
01789     Respond to X events.
01790   */
01791   XGetWidgetInfo((char *) NULL,&slider_info);
01792   XGetWidgetInfo((char *) NULL,&north_info);
01793   XGetWidgetInfo((char *) NULL,&south_info);
01794   XGetWidgetInfo((char *) NULL,&expose_info);
01795   visible_colors=0;
01796   delay=SuspendTime << 2;
01797   state=UpdateConfigurationState;
01798   do
01799   {
01800     if (state & UpdateConfigurationState)
01801       {
01802         int
01803           id;
01804 
01805         /*
01806           Initialize button information.
01807         */
01808         XGetWidgetInfo(CancelButtonText,&cancel_info);
01809         cancel_info.width=width;
01810         cancel_info.height=(unsigned int) ((3*height) >> 1);
01811         cancel_info.x=(int)
01812           (windows->widget.width-cancel_info.width-QuantumMargin-2);
01813         cancel_info.y=(int)
01814           (windows->widget.height-cancel_info.height-QuantumMargin);
01815         XGetWidgetInfo(action,&action_info);
01816         action_info.width=width;
01817         action_info.height=(unsigned int) ((3*height) >> 1);
01818         action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
01819           (action_info.bevel_width << 1));
01820         action_info.y=cancel_info.y;
01821         XGetWidgetInfo(GrabButtonText,&grab_info);
01822         grab_info.width=width;
01823         grab_info.height=(unsigned int) ((3*height) >> 1);
01824         grab_info.x=QuantumMargin;
01825         grab_info.y=((5*QuantumMargin) >> 1)+height;
01826         XGetWidgetInfo(ResetButtonText,&reset_info);
01827         reset_info.width=width;
01828         reset_info.height=(unsigned int) ((3*height) >> 1);
01829         reset_info.x=QuantumMargin;
01830         reset_info.y=grab_info.y+grab_info.height+QuantumMargin;
01831         /*
01832           Initialize reply information.
01833         */
01834         XGetWidgetInfo(reply,&reply_info);
01835         reply_info.raised=MagickFalse;
01836         reply_info.bevel_width--;
01837         reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
01838         reply_info.height=height << 1;
01839         reply_info.x=(int) (width+(QuantumMargin << 1));
01840         reply_info.y=action_info.y-reply_info.height-QuantumMargin;
01841         /*
01842           Initialize mode information.
01843         */
01844         XGetWidgetInfo((char *) NULL,&mode_info);
01845         mode_info.active=MagickTrue;
01846         mode_info.bevel_width=0;
01847         mode_info.width=(unsigned int) (action_info.x-(QuantumMargin << 1));
01848         mode_info.height=action_info.height;
01849         mode_info.x=QuantumMargin;
01850         mode_info.y=action_info.y;
01851         /*
01852           Initialize scroll information.
01853         */
01854         XGetWidgetInfo((char *) NULL,&scroll_info);
01855         scroll_info.bevel_width--;
01856         scroll_info.width=height;
01857         scroll_info.height=(unsigned int) (reply_info.y-grab_info.y-
01858           (QuantumMargin >> 1));
01859         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
01860         scroll_info.y=grab_info.y-reply_info.bevel_width;
01861         scroll_info.raised=MagickFalse;
01862         scroll_info.trough=MagickTrue;
01863         north_info=scroll_info;
01864         north_info.raised=MagickTrue;
01865         north_info.width-=(north_info.bevel_width << 1);
01866         north_info.height=north_info.width-1;
01867         north_info.x+=north_info.bevel_width;
01868         north_info.y+=north_info.bevel_width;
01869         south_info=north_info;
01870         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
01871           south_info.height;
01872         id=slider_info.id;
01873         slider_info=north_info;
01874         slider_info.id=id;
01875         slider_info.width-=2;
01876         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
01877           slider_info.bevel_width+2;
01878         slider_info.height=scroll_info.height-((slider_info.min_y-
01879           scroll_info.y+1) << 1)+4;
01880         visible_colors=scroll_info.height/(height+(height >> 3));
01881         if (colors > visible_colors)
01882           slider_info.height=(unsigned int)
01883             ((visible_colors*slider_info.height)/colors);
01884         slider_info.max_y=south_info.y-south_info.bevel_width-
01885           slider_info.bevel_width-2;
01886         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
01887         slider_info.y=slider_info.min_y;
01888         expose_info=scroll_info;
01889         expose_info.y=slider_info.y;
01890         /*
01891           Initialize list information.
01892         */
01893         XGetWidgetInfo((char *) NULL,&list_info);
01894         list_info.raised=MagickFalse;
01895         list_info.bevel_width--;
01896         list_info.width=(unsigned int)
01897           (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
01898         list_info.height=scroll_info.height;
01899         list_info.x=reply_info.x;
01900         list_info.y=scroll_info.y;
01901         if (windows->widget.mapped == MagickFalse)
01902           state|=JumpListState;
01903         /*
01904           Initialize text information.
01905         */
01906         *text='\0';
01907         XGetWidgetInfo(text,&text_info);
01908         text_info.center=MagickFalse;
01909         text_info.width=reply_info.width;
01910         text_info.height=height;
01911         text_info.x=list_info.x-(QuantumMargin >> 1);
01912         text_info.y=QuantumMargin;
01913         /*
01914           Initialize selection information.
01915         */
01916         XGetWidgetInfo((char *) NULL,&selection_info);
01917         selection_info.center=MagickFalse;
01918         selection_info.width=list_info.width;
01919         selection_info.height=(unsigned int) ((9*height) >> 3);
01920         selection_info.x=list_info.x;
01921         state&=(~UpdateConfigurationState);
01922       }
01923     if (state & RedrawWidgetState)
01924       {
01925         /*
01926           Redraw Color Browser window.
01927         */
01928         x=QuantumMargin;
01929         y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
01930         (void) XDrawString(display,windows->widget.id,
01931           windows->widget.annotate_context,x,y,ColorPatternText,
01932           Extent(ColorPatternText));
01933         (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
01934         XDrawWidgetText(display,&windows->widget,&text_info);
01935         XDrawBeveledButton(display,&windows->widget,&grab_info);
01936         XDrawBeveledButton(display,&windows->widget,&reset_info);
01937         XDrawBeveledMatte(display,&windows->widget,&list_info);
01938         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
01939         XDrawTriangleNorth(display,&windows->widget,&north_info);
01940         XDrawBeveledButton(display,&windows->widget,&slider_info);
01941         XDrawTriangleSouth(display,&windows->widget,&south_info);
01942         x=QuantumMargin;
01943         y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
01944         (void) XDrawString(display,windows->widget.id,
01945           windows->widget.annotate_context,x,y,ColornameText,
01946           Extent(ColornameText));
01947         XDrawBeveledMatte(display,&windows->widget,&reply_info);
01948         XDrawMatteText(display,&windows->widget,&reply_info);
01949         XDrawBeveledButton(display,&windows->widget,&action_info);
01950         XDrawBeveledButton(display,&windows->widget,&cancel_info);
01951         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
01952         selection_info.id=(~0);
01953         state|=RedrawActionState;
01954         state|=RedrawListState;
01955         state&=(~RedrawWidgetState);
01956       }
01957     if (state & UpdateListState)
01958       {
01959         char
01960           **checklist;
01961 
01962         size_t
01963           number_colors;
01964 
01965         status=XParseColor(display,windows->widget.map_info->colormap,
01966           glob_pattern,&color);
01967         if ((status != False) || (strchr(glob_pattern,'-') != (char *) NULL))
01968           {
01969             /*
01970               Reply is a single color name-- exit.
01971             */
01972             (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
01973             (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
01974             action_info.raised=MagickFalse;
01975             XDrawBeveledButton(display,&windows->widget,&action_info);
01976             break;
01977           }
01978         /*
01979           Update color list.
01980         */
01981         checklist=GetColorList(glob_pattern,&number_colors,exception);
01982         if (number_colors == 0)
01983           {
01984             (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
01985             (void) XBell(display,0);
01986           }
01987         else
01988           {
01989             for (i=0; i < (int) colors; i++)
01990               colorlist[i]=DestroyString(colorlist[i]);
01991             if (colorlist != (char **) NULL)
01992               colorlist=(char **) RelinquishMagickMemory(colorlist);
01993             colorlist=checklist;
01994             colors=number_colors;
01995           }
01996         /*
01997           Sort color list in ascending order.
01998         */
01999         slider_info.height=
02000           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
02001         if (colors > visible_colors)
02002           slider_info.height=(unsigned int)
02003             ((visible_colors*slider_info.height)/colors);
02004         slider_info.max_y=south_info.y-south_info.bevel_width-
02005           slider_info.bevel_width-2;
02006         slider_info.id=0;
02007         slider_info.y=slider_info.min_y;
02008         expose_info.y=slider_info.y;
02009         selection_info.id=(~0);
02010         list_info.id=(~0);
02011         state|=RedrawListState;
02012         /*
02013           Redraw color name & reply.
02014         */
02015         *reply_info.text='\0';
02016         reply_info.cursor=reply_info.text;
02017         (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
02018         XDrawWidgetText(display,&windows->widget,&text_info);
02019         XDrawMatteText(display,&windows->widget,&reply_info);
02020         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
02021         XDrawTriangleNorth(display,&windows->widget,&north_info);
02022         XDrawBeveledButton(display,&windows->widget,&slider_info);
02023         XDrawTriangleSouth(display,&windows->widget,&south_info);
02024         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
02025         state&=(~UpdateListState);
02026       }
02027     if (state & JumpListState)
02028       {
02029         /*
02030           Jump scroll to match user color.
02031         */
02032         list_info.id=(~0);
02033         for (i=0; i < (int) colors; i++)
02034           if (LocaleCompare(colorlist[i],reply) >= 0)
02035             {
02036               list_info.id=LocaleCompare(colorlist[i],reply) == 0 ? i : ~0;
02037               break;
02038             }
02039         if ((i < slider_info.id) ||
02040             (i >= (int) (slider_info.id+visible_colors)))
02041           slider_info.id=i-(visible_colors >> 1);
02042         selection_info.id=(~0);
02043         state|=RedrawListState;
02044         state&=(~JumpListState);
02045       }
02046     if (state & RedrawListState)
02047       {
02048         /*
02049           Determine slider id and position.
02050         */
02051         if (slider_info.id >= (int) (colors-visible_colors))
02052           slider_info.id=(int) (colors-visible_colors);
02053         if ((slider_info.id < 0) || (colors <= visible_colors))
02054           slider_info.id=0;
02055         slider_info.y=slider_info.min_y;
02056         if (colors != 0)
02057           slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
02058             slider_info.min_y+1)/colors);
02059         if (slider_info.id != selection_info.id)
02060           {
02061             /*
02062               Redraw scroll bar and file names.
02063             */
02064             selection_info.id=slider_info.id;
02065             selection_info.y=list_info.y+(height >> 3)+2;
02066             for (i=0; i < (int) visible_colors; i++)
02067             {
02068               selection_info.raised=(slider_info.id+i) != list_info.id ?
02069                 MagickTrue : MagickFalse;
02070               selection_info.text=(char *) NULL;
02071               if ((slider_info.id+i) < (int) colors)
02072                 selection_info.text=colorlist[slider_info.id+i];
02073               XDrawWidgetText(display,&windows->widget,&selection_info);
02074               selection_info.y+=(int) selection_info.height;
02075             }
02076             /*
02077               Update slider.
02078             */
02079             if (slider_info.y > expose_info.y)
02080               {
02081                 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
02082                 expose_info.y=slider_info.y-expose_info.height-
02083                   slider_info.bevel_width-1;
02084               }
02085             else
02086               {
02087                 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
02088                 expose_info.y=slider_info.y+slider_info.height+
02089                   slider_info.bevel_width+1;
02090               }
02091             XDrawTriangleNorth(display,&windows->widget,&north_info);
02092             XDrawMatte(display,&windows->widget,&expose_info);
02093             XDrawBeveledButton(display,&windows->widget,&slider_info);
02094             XDrawTriangleSouth(display,&windows->widget,&south_info);
02095             expose_info.y=slider_info.y;
02096           }
02097         state&=(~RedrawListState);
02098       }
02099     if (state & RedrawActionState)
02100       {
02101         static char
02102           colorname[MaxTextExtent];
02103 
02104         /*
02105           Display the selected color in a drawing area.
02106         */
02107         color=windows->widget.pixel_info->matte_color;
02108         (void) XParseColor(display,windows->widget.map_info->colormap,
02109           reply_info.text,&windows->widget.pixel_info->matte_color);
02110         XBestPixel(display,windows->widget.map_info->colormap,(XColor *) NULL,
02111           (unsigned int) windows->widget.visual_info->colormap_size,
02112           &windows->widget.pixel_info->matte_color);
02113         mode_info.text=colorname;
02114         (void) FormatLocaleString(mode_info.text,MaxTextExtent,"#%02x%02x%02x",
02115           windows->widget.pixel_info->matte_color.red,
02116           windows->widget.pixel_info->matte_color.green,
02117           windows->widget.pixel_info->matte_color.blue);
02118         XDrawBeveledButton(display,&windows->widget,&mode_info);
02119         windows->widget.pixel_info->matte_color=color;
02120         state&=(~RedrawActionState);
02121       }
02122     /*
02123       Wait for next event.
02124     */
02125     if (north_info.raised && south_info.raised)
02126       (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
02127     else
02128       {
02129         /*
02130           Brief delay before advancing scroll bar.
02131         */
02132         XDelay(display,delay);
02133         delay=SuspendTime;
02134         (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
02135         if (north_info.raised == MagickFalse)
02136           if (slider_info.id > 0)
02137             {
02138               /*
02139                 Move slider up.
02140               */
02141               slider_info.id--;
02142               state|=RedrawListState;
02143             }
02144         if (south_info.raised == MagickFalse)
02145           if (slider_info.id < (int) colors)
02146             {
02147               /*
02148                 Move slider down.
02149               */
02150               slider_info.id++;
02151               state|=RedrawListState;
02152             }
02153         if (event.type != ButtonRelease)
02154           continue;
02155       }
02156     switch (event.type)
02157     {
02158       case ButtonPress:
02159       {
02160         if (MatteIsActive(slider_info,event.xbutton))
02161           {
02162             /*
02163               Track slider.
02164             */
02165             slider_info.active=MagickTrue;
02166             break;
02167           }
02168         if (MatteIsActive(north_info,event.xbutton))
02169           if (slider_info.id > 0)
02170             {
02171               /*
02172                 Move slider up.
02173               */
02174               north_info.raised=MagickFalse;
02175               slider_info.id--;
02176               state|=RedrawListState;
02177               break;
02178             }
02179         if (MatteIsActive(south_info,event.xbutton))
02180           if (slider_info.id < (int) colors)
02181             {
02182               /*
02183                 Move slider down.
02184               */
02185               south_info.raised=MagickFalse;
02186               slider_info.id++;
02187               state|=RedrawListState;
02188               break;
02189             }
02190         if (MatteIsActive(scroll_info,event.xbutton))
02191           {
02192             /*
02193               Move slider.
02194             */
02195             if (event.xbutton.y < slider_info.y)
02196               slider_info.id-=(visible_colors-1);
02197             else
02198               slider_info.id+=(visible_colors-1);
02199             state|=RedrawListState;
02200             break;
02201           }
02202         if (MatteIsActive(list_info,event.xbutton))
02203           {
02204             int
02205               id;
02206 
02207             /*
02208               User pressed list matte.
02209             */
02210             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
02211               selection_info.height;
02212             if (id >= (int) colors)
02213               break;
02214             (void) CopyMagickString(reply_info.text,colorlist[id],
02215               MaxTextExtent);
02216             reply_info.highlight=MagickFalse;
02217             reply_info.marker=reply_info.text;
02218             reply_info.cursor=reply_info.text+Extent(reply_info.text);
02219             XDrawMatteText(display,&windows->widget,&reply_info);
02220             state|=RedrawActionState;
02221             if (id == list_info.id)
02222               {
02223                 (void) CopyMagickString(glob_pattern,reply_info.text,
02224                   MaxTextExtent);
02225                 state|=UpdateListState;
02226               }
02227             selection_info.id=(~0);
02228             list_info.id=id;
02229             state|=RedrawListState;
02230             break;
02231           }
02232         if (MatteIsActive(grab_info,event.xbutton))
02233           {
02234             /*
02235               User pressed Grab button.
02236             */
02237             grab_info.raised=MagickFalse;
02238             XDrawBeveledButton(display,&windows->widget,&grab_info);
02239             break;
02240           }
02241         if (MatteIsActive(reset_info,event.xbutton))
02242           {
02243             /*
02244               User pressed Reset button.
02245             */
02246             reset_info.raised=MagickFalse;
02247             XDrawBeveledButton(display,&windows->widget,&reset_info);
02248             break;
02249           }
02250         if (MatteIsActive(mode_info,event.xbutton))
02251           {
02252             /*
02253               User pressed mode button.
02254             */
02255             (void) CopyMagickString(reply_info.text,mode_info.text,
02256               MaxTextExtent);
02257             (void) CopyMagickString(primary_selection,reply_info.text,
02258               MaxTextExtent);
02259             (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
02260               event.xbutton.time);
02261             reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
02262               windows->widget.id ? MagickTrue : MagickFalse;
02263             reply_info.marker=reply_info.text;
02264             reply_info.cursor=reply_info.text+Extent(reply_info.text);
02265             XDrawMatteText(display,&windows->widget,&reply_info);
02266             break;
02267           }
02268         if (MatteIsActive(action_info,event.xbutton))
02269           {
02270             /*
02271               User pressed action button.
02272             */
02273             action_info.raised=MagickFalse;
02274             XDrawBeveledButton(display,&windows->widget,&action_info);
02275             break;
02276           }
02277         if (MatteIsActive(cancel_info,event.xbutton))
02278           {
02279             /*
02280               User pressed Cancel button.
02281             */
02282             cancel_info.raised=MagickFalse;
02283             XDrawBeveledButton(display,&windows->widget,&cancel_info);
02284             break;
02285           }
02286         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
02287           break;
02288         if (event.xbutton.button != Button2)
02289           {
02290             static Time
02291               click_time;
02292 
02293             /*
02294               Move text cursor to position of button press.
02295             */
02296             x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
02297             for (i=1; i <= Extent(reply_info.marker); i++)
02298               if (XTextWidth(font_info,reply_info.marker,i) > x)
02299                 break;
02300             reply_info.cursor=reply_info.marker+i-1;
02301             if (event.xbutton.time > (click_time+DoubleClick))
02302               reply_info.highlight=MagickFalse;
02303             else
02304               {
02305                 /*
02306                   Become the XA_PRIMARY selection owner.
02307                 */
02308                 (void) CopyMagickString(primary_selection,reply_info.text,
02309                   MaxTextExtent);
02310                 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
02311                   event.xbutton.time);
02312                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
02313                   windows->widget.id ? MagickTrue : MagickFalse;
02314               }
02315             XDrawMatteText(display,&windows->widget,&reply_info);
02316             click_time=event.xbutton.time;
02317             break;
02318           }
02319         /*
02320           Request primary selection.
02321         */
02322         (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
02323           windows->widget.id,event.xbutton.time);
02324         break;
02325       }
02326       case ButtonRelease:
02327       {
02328         if (windows->widget.mapped == MagickFalse)
02329           break;
02330         if (north_info.raised == MagickFalse)
02331           {
02332             /*
02333               User released up button.
02334             */
02335             delay=SuspendTime << 2;
02336             north_info.raised=MagickTrue;
02337             XDrawTriangleNorth(display,&windows->widget,&north_info);
02338           }
02339         if (south_info.raised == MagickFalse)
02340           {
02341             /*
02342               User released down button.
02343             */
02344             delay=SuspendTime << 2;
02345             south_info.raised=MagickTrue;
02346             XDrawTriangleSouth(display,&windows->widget,&south_info);
02347           }
02348         if (slider_info.active)
02349           {
02350             /*
02351               Stop tracking slider.
02352             */
02353             slider_info.active=MagickFalse;
02354             break;
02355           }
02356         if (grab_info.raised == MagickFalse)
02357           {
02358             if (event.xbutton.window == windows->widget.id)
02359               if (MatteIsActive(grab_info,event.xbutton))
02360                 {
02361                   /*
02362                     Select a fill color from the X server.
02363                   */
02364                   (void) XGetWindowColor(display,windows,reply_info.text,
02365                     exception);
02366                   reply_info.marker=reply_info.text;
02367                   reply_info.cursor=reply_info.text+Extent(reply_info.text);
02368                   XDrawMatteText(display,&windows->widget,&reply_info);
02369                   state|=RedrawActionState;
02370                 }
02371             grab_info.raised=MagickTrue;
02372             XDrawBeveledButton(display,&windows->widget,&grab_info);
02373           }
02374         if (reset_info.raised == MagickFalse)
02375           {
02376             if (event.xbutton.window == windows->widget.id)
02377               if (MatteIsActive(reset_info,event.xbutton))
02378                 {
02379                   (void) CopyMagickString(glob_pattern,reset_pattern,
02380                     MaxTextExtent);
02381                   state|=UpdateListState;
02382                 }
02383             reset_info.raised=MagickTrue;
02384             XDrawBeveledButton(display,&windows->widget,&reset_info);
02385           }
02386         if (action_info.raised == MagickFalse)
02387           {
02388             if (event.xbutton.window == windows->widget.id)
02389               {
02390                 if (MatteIsActive(action_info,event.xbutton))
02391                   {
02392                     if (*reply_info.text == '\0')
02393                       (void) XBell(display,0);
02394                     else
02395                       state|=ExitState;
02396                   }
02397               }
02398             action_info.raised=MagickTrue;
02399             XDrawBeveledButton(display,&windows->widget,&action_info);
02400           }
02401         if (cancel_info.raised == MagickFalse)
02402           {
02403             if (event.xbutton.window == windows->widget.id)
02404               if (MatteIsActive(cancel_info,event.xbutton))
02405                 {
02406                   *reply_info.text='\0';
02407                   state|=ExitState;
02408                 }
02409             cancel_info.raised=MagickTrue;
02410             XDrawBeveledButton(display,&windows->widget,&cancel_info);
02411           }
02412         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
02413           break;
02414         break;
02415       }
02416       case ClientMessage:
02417       {
02418         /*
02419           If client window delete message, exit.
02420         */
02421         if (event.xclient.message_type != windows->wm_protocols)
02422           break;
02423         if (*event.xclient.data.l == (int) windows->wm_take_focus)
02424           {
02425             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
02426               (Time) event.xclient.data.l[1]);
02427             break;
02428           }
02429         if (*event.xclient.data.l != (int) windows->wm_delete_window)
02430           break;
02431         if (event.xclient.window == windows->widget.id)
02432           {
02433             *reply_info.text='\0';
02434             state|=ExitState;
02435             break;
02436           }
02437         break;
02438       }
02439       case ConfigureNotify:
02440       {
02441         /*
02442           Update widget configuration.
02443         */
02444         if (event.xconfigure.window != windows->widget.id)
02445           break;
02446         if ((event.xconfigure.width == (int) windows->widget.width) &&
02447             (event.xconfigure.height == (int) windows->widget.height))
02448           break;
02449         windows->widget.width=(unsigned int)
02450           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
02451         windows->widget.height=(unsigned int)
02452           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
02453         state|=UpdateConfigurationState;
02454         break;
02455       }
02456       case EnterNotify:
02457       {
02458         if (event.xcrossing.window != windows->widget.id)
02459           break;
02460         state&=(~InactiveWidgetState);
02461         break;
02462       }
02463       case Expose:
02464       {
02465         if (event.xexpose.window != windows->widget.id)
02466           break;
02467         if (event.xexpose.count != 0)
02468           break;
02469         state|=RedrawWidgetState;
02470         break;
02471       }
02472       case KeyPress:
02473       {
02474         static char
02475           command[MaxTextExtent];
02476 
02477         static int
02478           length;
02479 
02480         static KeySym
02481           key_symbol;
02482 
02483         /*
02484           Respond to a user key press.
02485         */
02486         if (event.xkey.window != windows->widget.id)
02487           break;
02488         length=XLookupString((XKeyEvent *) &event.xkey,command,
02489           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
02490         *(command+length)='\0';
02491         if (AreaIsActive(scroll_info,event.xkey))
02492           {
02493             /*
02494               Move slider.
02495             */
02496             switch ((int) key_symbol)
02497             {
02498               case XK_Home:
02499               case XK_KP_Home:
02500               {
02501                 slider_info.id=0;
02502                 break;
02503               }
02504               case XK_Up:
02505               case XK_KP_Up:
02506               {
02507                 slider_info.id--;
02508                 break;
02509               }
02510               case XK_Down:
02511               case XK_KP_Down:
02512               {
02513                 slider_info.id++;
02514                 break;
02515               }
02516               case XK_Prior:
02517               case XK_KP_Prior:
02518               {
02519                 slider_info.id-=visible_colors;
02520                 break;
02521               }
02522               case XK_Next:
02523               case XK_KP_Next:
02524               {
02525                 slider_info.id+=visible_colors;
02526                 break;
02527               }
02528               case XK_End:
02529               case XK_KP_End:
02530               {
02531                 slider_info.id=(int) colors;
02532                 break;
02533               }
02534             }
02535             state|=RedrawListState;
02536             break;
02537           }
02538         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
02539           {
02540             /*
02541               Read new color or glob patterm.
02542             */
02543             if (*reply_info.text == '\0')
02544               break;
02545             (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
02546             state|=UpdateListState;
02547             break;
02548           }
02549         if (key_symbol == XK_Control_L)
02550           {
02551             state|=ControlState;
02552             break;
02553           }
02554         if (state & ControlState)
02555           switch ((int) key_symbol)
02556           {
02557             case XK_u:
02558             case XK_U:
02559             {
02560               /*
02561                 Erase the entire line of text.
02562               */
02563               *reply_info.text='\0';
02564               reply_info.cursor=reply_info.text;
02565               reply_info.marker=reply_info.text;
02566               reply_info.highlight=MagickFalse;
02567               break;
02568             }
02569             default:
02570               break;
02571           }
02572         XEditText(display,&reply_info,key_symbol,command,state);
02573         XDrawMatteText(display,&windows->widget,&reply_info);
02574         state|=JumpListState;
02575         status=XParseColor(display,windows->widget.map_info->colormap,
02576           reply_info.text,&color);
02577         if (status != False)
02578           state|=RedrawActionState;
02579         break;
02580       }
02581       case KeyRelease:
02582       {
02583         static char
02584           command[MaxTextExtent];
02585 
02586         static KeySym
02587           key_symbol;
02588 
02589         /*
02590           Respond to a user key release.
02591         */
02592         if (event.xkey.window != windows->widget.id)
02593           break;
02594         (void) XLookupString((XKeyEvent *) &event.xkey,command,
02595           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
02596         if (key_symbol == XK_Control_L)
02597           state&=(~ControlState);
02598         break;
02599       }
02600       case LeaveNotify:
02601       {
02602         if (event.xcrossing.window != windows->widget.id)
02603           break;
02604         state|=InactiveWidgetState;
02605         break;
02606       }
02607       case MapNotify:
02608       {
02609         mask&=(~CWX);
02610         mask&=(~CWY);
02611         break;
02612       }
02613       case MotionNotify:
02614       {
02615         /*
02616           Discard pending button motion events.
02617         */
02618         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
02619         if (slider_info.active)
02620           {
02621             /*
02622               Move slider matte.
02623             */
02624             slider_info.y=event.xmotion.y-
02625               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
02626             if (slider_info.y < slider_info.min_y)
02627               slider_info.y=slider_info.min_y;
02628             if (slider_info.y > slider_info.max_y)
02629               slider_info.y=slider_info.max_y;
02630             slider_info.id=0;
02631             if (slider_info.y != slider_info.min_y)
02632               slider_info.id=(int) ((colors*(slider_info.y-
02633                 slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
02634             state|=RedrawListState;
02635             break;
02636           }
02637         if (state & InactiveWidgetState)
02638           break;
02639         if (grab_info.raised == MatteIsActive(grab_info,event.xmotion))
02640           {
02641             /*
02642               Grab button status changed.
02643             */
02644             grab_info.raised=!grab_info.raised;
02645             XDrawBeveledButton(display,&windows->widget,&grab_info);
02646             break;
02647           }
02648         if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
02649           {
02650             /*
02651               Reset button status changed.
02652             */
02653             reset_info.raised=!reset_info.raised;
02654             XDrawBeveledButton(display,&windows->widget,&reset_info);
02655             break;
02656           }
02657         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
02658           {
02659             /*
02660               Action button status changed.
02661             */
02662             action_info.raised=action_info.raised == MagickFalse ?
02663               MagickTrue : MagickFalse;
02664             XDrawBeveledButton(display,&windows->widget,&action_info);
02665             break;
02666           }
02667         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
02668           {
02669             /*
02670               Cancel button status changed.
02671             */
02672             cancel_info.raised=cancel_info.raised == MagickFalse ?
02673               MagickTrue : MagickFalse;
02674             XDrawBeveledButton(display,&windows->widget,&cancel_info);
02675             break;
02676           }
02677         break;
02678       }
02679       case SelectionClear:
02680       {
02681         reply_info.highlight=MagickFalse;
02682         XDrawMatteText(display,&windows->widget,&reply_info);
02683         break;
02684       }
02685       case SelectionNotify:
02686       {
02687         Atom
02688           type;
02689 
02690         int
02691           format;
02692 
02693         unsigned char
02694           *data;
02695 
02696         unsigned long
02697           after,
02698           length;
02699 
02700         /*
02701           Obtain response from primary selection.
02702         */
02703         if (event.xselection.property == (Atom) None)
02704           break;
02705         status=XGetWindowProperty(display,event.xselection.requestor,
02706           event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
02707           &format,&length,&after,&data);
02708         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
02709             (length == 0))
02710           break;
02711         if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
02712           (void) XBell(display,0);
02713         else
02714           {
02715             /*
02716               Insert primary selection in reply text.
02717             */
02718             *(data+length)='\0';
02719             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
02720               state);
02721             XDrawMatteText(display,&windows->widget,&reply_info);
02722             state|=JumpListState;
02723             state|=RedrawActionState;
02724           }
02725         (void) XFree((void *) data);
02726         break;
02727       }
02728       case SelectionRequest:
02729       {
02730         XSelectionEvent
02731           notify;
02732 
02733         XSelectionRequestEvent
02734           *request;
02735 
02736         if (reply_info.highlight == MagickFalse)
02737           break;
02738         /*
02739           Set primary selection.
02740         */
02741         request=(&(event.xselectionrequest));
02742         (void) XChangeProperty(request->display,request->requestor,
02743           request->property,request->target,8,PropModeReplace,
02744           (unsigned char *) primary_selection,Extent(primary_selection));
02745         notify.type=SelectionNotify;
02746         notify.send_event=MagickTrue;
02747         notify.display=request->display;
02748         notify.requestor=request->requestor;
02749         notify.selection=request->selection;
02750         notify.target=request->target;
02751         notify.time=request->time;
02752         if (request->property == None)
02753           notify.property=request->target;
02754         else
02755           notify.property=request->property;
02756         (void) XSendEvent(request->display,request->requestor,False,
02757           NoEventMask,(XEvent *) &notify);
02758       }
02759       default:
02760         break;
02761     }
02762   } while ((state & ExitState) == 0);
02763   XSetCursorState(display,windows,MagickFalse);
02764   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
02765   XCheckRefreshWindows(display,windows);
02766   /*
02767     Free color list.
02768   */
02769   for (i=0; i < (int) colors; i++)
02770     colorlist[i]=DestroyString(colorlist[i]);
02771   if (colorlist != (char **) NULL)
02772     colorlist=(char **) RelinquishMagickMemory(colorlist);
02773   exception=DestroyExceptionInfo(exception);
02774   if ((*reply == '\0') || (strchr(reply,'-') != (char *) NULL))
02775     return;
02776   status=XParseColor(display,windows->widget.map_info->colormap,reply,&color);
02777   if (status != False)
02778     return;
02779   XNoticeWidget(display,windows,"Color is unknown to X server:",reply);
02780   (void) CopyMagickString(reply,"gray",MaxTextExtent);
02781 }
02782 
02783 /*
02784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02785 %                                                                             %
02786 %                                                                             %
02787 %                                                                             %
02788 %   X C o m m a n d W i d g e t                                               %
02789 %                                                                             %
02790 %                                                                             %
02791 %                                                                             %
02792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02793 %
02794 %  XCommandWidget() maps a menu and returns the command pointed to by the user
02795 %  when the button is released.
02796 %
02797 %  The format of the XCommandWidget method is:
02798 %
02799 %      int XCommandWidget(Display *display,XWindows *windows,
02800 %        const char **selections,XEvent *event)
02801 %
02802 %  A description of each parameter follows:
02803 %
02804 %    o selection_number: Specifies the number of the selection that the
02805 %      user choose.
02806 %
02807 %    o display: Specifies a connection to an X server;  returned from
02808 %      XOpenDisplay.
02809 %
02810 %    o window: Specifies a pointer to a XWindows structure.
02811 %
02812 %    o selections: Specifies a pointer to one or more strings that comprise
02813 %      the choices in the menu.
02814 %
02815 %    o event: Specifies a pointer to a X11 XEvent structure.
02816 %
02817 */
02818 MagickPrivate int XCommandWidget(Display *display,XWindows *windows,
02819   const char **selections,XEvent *event)
02820 {
02821 #define tile_width 112
02822 #define tile_height 70
02823 
02824   static const unsigned char
02825     tile_bits[]=
02826     {
02827       0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02828       0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02829       0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02830       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
02831       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
02832       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
02833       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02834       0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02835       0x00, 0x00, 0x1e, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02836       0x00, 0x00, 0x00, 0x00, 0x1e, 0xbc, 0x9f, 0x03, 0x00, 0x3e, 0x00, 0xc0,
02837       0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x0f, 0x80, 0x3f,
02838       0x00, 0xf0, 0x1f, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x1f,
02839       0xe0, 0x3f, 0x00, 0xfc, 0x1f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc,
02840       0xff, 0x1f, 0xf0, 0x3f, 0x00, 0xfe, 0x1f, 0xf8, 0x0f, 0x00, 0x00, 0x00,
02841       0x1e, 0xfc, 0xfc, 0x3f, 0xf8, 0x3f, 0x00, 0xff, 0x1e, 0xfc, 0x0f, 0x00,
02842       0x00, 0x00, 0x1e, 0x7c, 0xfc, 0x3e, 0xf8, 0x3c, 0x80, 0x1f, 0x1e, 0x7c,
02843       0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, 0xc0, 0x0f,
02844       0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c,
02845       0xc0, 0x07, 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c,
02846       0x7c, 0x7c, 0xc0, 0x0f, 0x1e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x78,
02847       0x78, 0x3c, 0xfc, 0x7c, 0x80, 0x7f, 0x1e, 0x7c, 0x00, 0x00, 0x00, 0x00,
02848       0x1e, 0xf8, 0x78, 0x7c, 0xf8, 0xff, 0x00, 0xff, 0x1f, 0xf8, 0xff, 0x00,
02849       0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xfe, 0x1f, 0xf8,
02850       0xff, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xf8,
02851       0x1f, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xc0, 0xef,
02852       0x07, 0xe0, 0x1f, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0x70, 0x40, 0x78,
02853       0x00, 0xc7, 0x07, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00,
02854       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
02855       0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
02856       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
02857       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
02858       0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02859       0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02860       0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02861       0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
02862       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00,
02863       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
02864       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
02865       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02866       0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x02, 0x00,
02867       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
02868       0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02869       0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02870       0x60, 0x00, 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02871       0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
02872       0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00,
02873       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0x9f, 0x7f, 0x00,
02874       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0xdf,
02875       0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x00,
02876       0xe0, 0xdf, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0c,
02877       0x78, 0x30, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
02878       0x00, 0x0f, 0xf8, 0x70, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x1f, 0x00, 0xe0,
02879       0x0f, 0x1e, 0x80, 0x0f, 0xf8, 0x78, 0xf0, 0xfd, 0xf9, 0x00, 0xc0, 0x1f,
02880       0x00, 0xf8, 0x0f, 0x00, 0xe0, 0x1f, 0xf8, 0x7c, 0xf0, 0xfc, 0xf9, 0x00,
02881       0xf0, 0x1f, 0x00, 0xfe, 0x0f, 0x00, 0xf0, 0x07, 0xf8, 0x3e, 0xf8, 0xfc,
02882       0xf0, 0x01, 0xf8, 0x1f, 0x00, 0xff, 0x0f, 0x1e, 0xf0, 0x03, 0xf8, 0x3f,
02883       0xf8, 0xf8, 0xf0, 0x01, 0xfc, 0x1f, 0x80, 0x7f, 0x0f, 0x1e, 0xf8, 0x00,
02884       0xf8, 0x1f, 0x78, 0x18, 0xf0, 0x01, 0x7c, 0x1e, 0xc0, 0x0f, 0x0f, 0x1e,
02885       0x7c, 0x00, 0xf0, 0x0f, 0x78, 0x00, 0xf0, 0x01, 0x3e, 0x1e, 0xe0, 0x07,
02886       0x0f, 0x1e, 0x7c, 0x00, 0xf0, 0x07, 0x7c, 0x00, 0xe0, 0x01, 0x3e, 0x1e,
02887       0xe0, 0x03, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x0f, 0x7c, 0x00, 0xe0, 0x03,
02888       0x3e, 0x3e, 0xe0, 0x07, 0x0f, 0x1e, 0x1e, 0x00, 0xf0, 0x1f, 0x3c, 0x00,
02889       0xe0, 0x03, 0x7e, 0x3e, 0xc0, 0x3f, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x1f,
02890       0x3e, 0x00, 0xe0, 0x03, 0xfc, 0x7f, 0x80, 0xff, 0x0f, 0x1e, 0xfc, 0x00,
02891       0xf0, 0x3e, 0x3e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xff, 0x0f, 0x1e,
02892       0xfc, 0x07, 0xf0, 0x7c, 0x1e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xfc,
02893       0x0f, 0x1e, 0xf8, 0x1f, 0xf0, 0xf8, 0x1e, 0x00, 0xc0, 0x03, 0xe0, 0xf7,
02894       0x03, 0xf0, 0x0f, 0x1e, 0xe0, 0x3f, 0xf0, 0x78, 0x1c, 0x00, 0x80, 0x03,
02895       0x80, 0xe3, 0x03, 0x00, 0x0f, 0x1e, 0xc0, 0x3f, 0xf0, 0x30, 0x00, 0x00,
02896       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0x3e, 0x00, 0x00,
02897       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x10,
02898       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
02899       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
02900       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02901       0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02902       0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02903       0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
02904       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
02905       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
02906       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
02907       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
02908       0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
02909     };
02910 
02911   int
02912     id,
02913     y;
02914 
02915   register int
02916     i;
02917 
02918   static unsigned int
02919     number_selections;
02920 
02921   unsigned int
02922     height;
02923 
02924   size_t
02925     state;
02926 
02927   XFontStruct
02928     *font_info;
02929 
02930   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
02931   assert(display != (Display *) NULL);
02932   assert(windows != (XWindows *) NULL);
02933   font_info=windows->command.font_info;
02934   height=(unsigned int) (font_info->ascent+font_info->descent);
02935   id=(~0);
02936   state=DefaultState;
02937   if (event == (XEvent *) NULL)
02938     {
02939       unsigned int
02940         width;
02941 
02942       XTextProperty
02943         window_name;
02944 
02945       XWindowChanges
02946         window_changes;
02947 
02948       /*
02949         Determine command window attributes.
02950       */
02951       assert(selections != (const char **) NULL);
02952       windows->command.width=0;
02953       for (i=0; selections[i] != (char *) NULL; i++)
02954       {
02955         width=WidgetTextWidth(font_info,(char *) selections[i]);
02956         if (width > windows->command.width)
02957           windows->command.width=width;
02958       }
02959       number_selections=(unsigned int) i;
02960       windows->command.width+=3*QuantumMargin+10;
02961       if ((int) windows->command.width < (tile_width+QuantumMargin+10))
02962         windows->command.width=(unsigned  int) (tile_width+QuantumMargin+10);
02963       windows->command.height=(unsigned  int) (number_selections*
02964         (((3*height) >> 1)+10)+tile_height+20);
02965       windows->command.min_width=windows->command.width;
02966       windows->command.min_height=windows->command.height;
02967       XConstrainWindowPosition(display,&windows->command);
02968       if (windows->command.id != (Window) NULL)
02969         {
02970           Status
02971             status;
02972 
02973           /*
02974             Reconfigure command window.
02975           */
02976           status=XStringListToTextProperty(&windows->command.name,1,
02977             &window_name);
02978           if (status != False)
02979             {
02980               XSetWMName(display,windows->command.id,&window_name);
02981               XSetWMIconName(display,windows->command.id,&window_name);
02982               (void) XFree((void *) window_name.value);
02983             }
02984           window_changes.width=(int) windows->command.width;
02985           window_changes.height=(int) windows->command.height;
02986           (void) XReconfigureWMWindow(display,windows->command.id,
02987             windows->command.screen,(unsigned int) (CWWidth | CWHeight),
02988             &window_changes);
02989         }
02990       /*
02991         Allocate selection info memory.
02992       */
02993       if (selection_info != (XWidgetInfo *) NULL)
02994         selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
02995       selection_info=(XWidgetInfo *) AcquireQuantumMemory(number_selections,
02996         sizeof(*selection_info));
02997       if (selection_info == (XWidgetInfo *) NULL)
02998         {
02999           ThrowXWindowFatalException(ResourceLimitError,
03000             "MemoryAllocationFailed","...");
03001           return(id);
03002         }
03003       state|=UpdateConfigurationState | RedrawWidgetState;
03004     }
03005   /*
03006     Wait for next event.
03007   */
03008   if (event != (XEvent *) NULL)
03009     switch (event->type)
03010     {
03011       case ButtonPress:
03012       {
03013         for (i=0; i < (int) number_selections; i++)
03014         {
03015           if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
03016             continue;
03017           if (i >= (int) windows->command.data)
03018             {
03019               selection_info[i].raised=MagickFalse;
03020               XDrawBeveledButton(display,&windows->command,&selection_info[i]);
03021               break;
03022             }
03023           submenu_info=selection_info[i];
03024           submenu_info.active=MagickTrue;
03025           toggle_info.y=
03026             submenu_info.y+(submenu_info.height >> 1)-(toggle_info.height >> 1);
03027           id=i;
03028           (void) XCheckWindowEvent(display,windows->widget.id,LeaveWindowMask,
03029             event);
03030           break;
03031         }
03032         break;
03033       }
03034       case ButtonRelease:
03035       {
03036         for (i=0; i < (int) number_selections; i++)
03037         {
03038           if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
03039             continue;
03040           id=i;
03041           if (id >= (int) windows->command.data)
03042             {
03043               selection_info[id].raised=MagickTrue;
03044               XDrawBeveledButton(display,&windows->command,&selection_info[id]);
03045               break;
03046             }
03047           break;
03048         }
03049         break;
03050       }
03051       case ClientMessage:
03052       {
03053         /*
03054           If client window delete message, withdraw command widget.
03055         */
03056         if (event->xclient.message_type != windows->wm_protocols)
03057           break;
03058         if (*event->xclient.data.l != (int) windows->wm_delete_window)
03059           break;
03060         (void) XWithdrawWindow(display,windows->command.id,
03061           windows->command.screen);
03062         break;
03063       }
03064       case ConfigureNotify:
03065       {
03066         /*
03067           Update widget configuration.
03068         */
03069         if (event->xconfigure.window != windows->command.id)
03070           break;
03071         if (event->xconfigure.send_event != 0)
03072           {
03073             windows->command.x=event->xconfigure.x;
03074             windows->command.y=event->xconfigure.y;
03075           }
03076         if ((event->xconfigure.width == (int) windows->command.width) &&
03077             (event->xconfigure.height == (int) windows->command.height))
03078           break;
03079         windows->command.width=(unsigned int)
03080           MagickMax(event->xconfigure.width,(int) windows->command.min_width);
03081         windows->command.height=(unsigned int)
03082           MagickMax(event->xconfigure.height,(int) windows->command.min_height);
03083         state|=UpdateConfigurationState;
03084         break;
03085       }
03086       case Expose:
03087       {
03088         if (event->xexpose.window != windows->command.id)
03089           break;
03090         if (event->xexpose.count != 0)
03091           break;
03092         state|=RedrawWidgetState;
03093         break;
03094       }
03095       case MotionNotify:
03096       {
03097         /*
03098           Return the ID of the highlighted menu entry.
03099         */
03100         for ( ; ; )
03101         {
03102           for (i=0; i < (int) number_selections; i++)
03103           {
03104             if (i >= (int) windows->command.data)
03105               {
03106                 if (selection_info[i].raised ==
03107                     MatteIsActive(selection_info[i],event->xmotion))
03108                   {
03109                     /*
03110                       Button status changed.
03111                     */
03112                     selection_info[i].raised=!selection_info[i].raised;
03113                     XDrawBeveledButton(display,&windows->command,
03114                       &selection_info[i]);
03115                   }
03116                 continue;
03117               }
03118             if (MatteIsActive(selection_info[i],event->xmotion) == MagickFalse)
03119               continue;
03120             submenu_info=selection_info[i];
03121             submenu_info.active=MagickTrue;
03122             toggle_info.raised=MagickTrue;
03123             toggle_info.y=submenu_info.y+(submenu_info.height >> 1)-
03124               (toggle_info.height >> 1);
03125             XDrawTriangleEast(display,&windows->command,&toggle_info);
03126             id=i;
03127           }
03128           XDelay(display,SuspendTime);
03129           if (XCheckMaskEvent(display,ButtonMotionMask,event) == MagickFalse)
03130             break;
03131           while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
03132           toggle_info.raised=MagickFalse;
03133           if (windows->command.data != 0)
03134             XDrawTriangleEast(display,&windows->command,&toggle_info);
03135         }
03136         break;
03137       }
03138       case MapNotify:
03139       {
03140         windows->command.mapped=MagickTrue;
03141         break;
03142       }
03143       case UnmapNotify:
03144       {
03145         windows->command.mapped=MagickFalse;
03146         break;
03147       }
03148       default:
03149         break;
03150     }
03151   if (state & UpdateConfigurationState)
03152     {
03153       /*
03154         Initialize button information.
03155       */
03156       assert(selections != (const char **) NULL);
03157       y=tile_height+20;
03158       for (i=0; i < (int) number_selections; i++)
03159       {
03160         XGetWidgetInfo(selections[i],&selection_info[i]);
03161         selection_info[i].center=MagickFalse;
03162         selection_info[i].bevel_width--;
03163         selection_info[i].height=(unsigned int) ((3*height) >> 1);
03164         selection_info[i].x=(QuantumMargin >> 1)+4;
03165         selection_info[i].width=(unsigned int)
03166           (windows->command.width-(selection_info[i].x << 1));
03167         selection_info[i].y=y;
03168         y+=selection_info[i].height+(selection_info[i].bevel_width << 1)+6;
03169       }
03170       XGetWidgetInfo((char *) NULL,&toggle_info);
03171       toggle_info.bevel_width--;
03172       toggle_info.width=(unsigned int)
03173         (((5*height) >> 3)-(toggle_info.bevel_width << 1));
03174       toggle_info.height=toggle_info.width;
03175       toggle_info.x=selection_info[0].x+selection_info[0].width-
03176         toggle_info.width-(QuantumMargin >> 1);
03177       if (windows->command.mapped)
03178         (void) XClearWindow(display,windows->command.id);
03179     }
03180   if (state & RedrawWidgetState)
03181     {
03182       Pixmap
03183         tile_pixmap;
03184 
03185       /*
03186         Draw command buttons.
03187       */
03188       tile_pixmap=XCreatePixmapFromBitmapData(display,windows->command.id,
03189         (char *) tile_bits,tile_width,tile_height,1L,0L,1);
03190       if (tile_pixmap != (Pixmap) NULL)
03191         {
03192           (void) XCopyPlane(display,tile_pixmap,windows->command.id,
03193             windows->command.annotate_context,0,0,tile_width,tile_height,
03194             (int) ((windows->command.width-tile_width) >> 1),10,1L);
03195           (void) XFreePixmap(display,tile_pixmap);
03196         }
03197       for (i=0; i < (int) number_selections; i++)
03198       {
03199         XDrawBeveledButton(display,&windows->command,&selection_info[i]);
03200         if (i >= (int) windows->command.data)
03201           continue;
03202         toggle_info.raised=i == id ? MagickTrue : MagickFalse;
03203         toggle_info.y=selection_info[i].y+
03204           (selection_info[i].height >> 1)-(toggle_info.height >> 1);
03205         XDrawTriangleEast(display,&windows->command,&toggle_info);
03206       }
03207       XHighlightWidget(display,&windows->command,BorderOffset,BorderOffset);
03208     }
03209   return(id);
03210 }
03211 
03212 /*
03213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03214 %                                                                             %
03215 %                                                                             %
03216 %                                                                             %
03217 %   X C o n f i r m W i d g e t                                               %
03218 %                                                                             %
03219 %                                                                             %
03220 %                                                                             %
03221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03222 %
03223 %  XConfirmWidget() displays a Confirm widget with a notice to the user. The
03224 %  function returns -1 if Dismiss is pressed, 0 for Cancel, and 1 for Yes.
03225 %
03226 %  The format of the XConfirmWidget method is:
03227 %
03228 %      int XConfirmWidget(Display *display,XWindows *windows,
03229 %        const char *reason,const char *description)
03230 %
03231 %  A description of each parameter follows:
03232 %
03233 %    o display: Specifies a connection to an X server;  returned from
03234 %      XOpenDisplay.
03235 %
03236 %    o window: Specifies a pointer to a XWindows structure.
03237 %
03238 %    o reason: Specifies the message to display before terminating the
03239 %      program.
03240 %
03241 %    o description: Specifies any description to the message.
03242 %
03243 */
03244 MagickPrivate int XConfirmWidget(Display *display,XWindows *windows,
03245   const char *reason,const char *description)
03246 {
03247 #define CancelButtonText  "Cancel"
03248 #define DismissButtonText  "Dismiss"
03249 #define YesButtonText  "Yes"
03250 
03251   int
03252     confirm,
03253     x,
03254     y;
03255 
03256   Status
03257     status;
03258 
03259   unsigned int
03260     height,
03261     width;
03262 
03263   size_t
03264     state;
03265 
03266   XEvent
03267     event;
03268 
03269   XFontStruct
03270     *font_info;
03271 
03272   XTextProperty
03273     window_name;
03274 
03275   XWidgetInfo
03276     cancel_info,
03277     dismiss_info,
03278     yes_info;
03279 
03280   XWindowChanges
03281     window_changes;
03282 
03283   /*
03284     Determine Confirm widget attributes.
03285   */
03286   assert(display != (Display *) NULL);
03287   assert(windows != (XWindows *) NULL);
03288   assert(reason != (char *) NULL);
03289   assert(description != (char *) NULL);
03290   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
03291   XCheckRefreshWindows(display,windows);
03292   font_info=windows->widget.font_info;
03293   width=WidgetTextWidth(font_info,CancelButtonText);
03294   if (WidgetTextWidth(font_info,DismissButtonText) > width)
03295     width=WidgetTextWidth(font_info,DismissButtonText);
03296   if (WidgetTextWidth(font_info,YesButtonText) > width)
03297     width=WidgetTextWidth(font_info,YesButtonText);
03298   width<<=1;
03299   if (description != (char *) NULL)
03300     if (WidgetTextWidth(font_info,(char *) description) > width)
03301       width=WidgetTextWidth(font_info,(char *) description);
03302   height=(unsigned int) (font_info->ascent+font_info->descent);
03303   /*
03304     Position Confirm widget.
03305   */
03306   windows->widget.width=(unsigned int) (width+9*QuantumMargin);
03307   windows->widget.min_width=(unsigned int) (9*QuantumMargin+
03308     WidgetTextWidth(font_info,CancelButtonText)+
03309     WidgetTextWidth(font_info,DismissButtonText)+
03310     WidgetTextWidth(font_info,YesButtonText));
03311   if (windows->widget.width < windows->widget.min_width)
03312     windows->widget.width=windows->widget.min_width;
03313   windows->widget.height=(unsigned int) (12*height);
03314   windows->widget.min_height=(unsigned int) (7*height);
03315   if (windows->widget.height < windows->widget.min_height)
03316     windows->widget.height=windows->widget.min_height;
03317   XConstrainWindowPosition(display,&windows->widget);
03318   /*
03319     Map Confirm widget.
03320   */
03321   (void) CopyMagickString(windows->widget.name,"Confirm",MaxTextExtent);
03322   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
03323   if (status != False)
03324     {
03325       XSetWMName(display,windows->widget.id,&window_name);
03326       XSetWMIconName(display,windows->widget.id,&window_name);
03327       (void) XFree((void *) window_name.value);
03328     }
03329   window_changes.width=(int) windows->widget.width;
03330   window_changes.height=(int) windows->widget.height;
03331   window_changes.x=windows->widget.x;
03332   window_changes.y=windows->widget.y;
03333   (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
03334     (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
03335   (void) XMapRaised(display,windows->widget.id);
03336   windows->widget.mapped=MagickFalse;
03337   /*
03338     Respond to X events.
03339   */
03340   confirm=0;
03341   state=UpdateConfigurationState;
03342   XSetCursorState(display,windows,MagickTrue);
03343   do
03344   {
03345     if (state & UpdateConfigurationState)
03346       {
03347         /*
03348           Initialize button information.
03349         */
03350         XGetWidgetInfo(CancelButtonText,&cancel_info);
03351         cancel_info.width=(unsigned int) QuantumMargin+
03352           WidgetTextWidth(font_info,CancelButtonText);
03353         cancel_info.height=(unsigned int) ((3*height) >> 1);
03354         cancel_info.x=(int) (windows->widget.width-cancel_info.width-
03355           QuantumMargin);
03356         cancel_info.y=(int) (windows->widget.height-(cancel_info.height << 1));
03357         dismiss_info=cancel_info;
03358         dismiss_info.text=(char *) DismissButtonText;
03359         if (LocaleCompare(description,"Do you want to save it") == 0)
03360           dismiss_info.text=(char *) "Don't Save";
03361         dismiss_info.width=(unsigned int) QuantumMargin+
03362           WidgetTextWidth(font_info,dismiss_info.text);
03363         dismiss_info.x=(int)
03364           ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
03365         yes_info=cancel_info;
03366         yes_info.text=(char *) YesButtonText;
03367         if (LocaleCompare(description,"Do you want to save it") == 0)
03368           yes_info.text=(char *) "Save";
03369         yes_info.width=(unsigned int) QuantumMargin+
03370           WidgetTextWidth(font_info,yes_info.text);
03371         if (yes_info.width < cancel_info.width)
03372           yes_info.width=cancel_info.width;
03373         yes_info.x=QuantumMargin;
03374         state&=(~UpdateConfigurationState);
03375       }
03376     if (state & RedrawWidgetState)
03377       {
03378         /*
03379           Redraw Confirm widget.
03380         */
03381         width=WidgetTextWidth(font_info,(char *) reason);
03382         x=(int) ((windows->widget.width >> 1)-(width >> 1));
03383         y=(int) ((windows->widget.height >> 1)-(height << 1));
03384         (void) XDrawString(display,windows->widget.id,
03385           windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
03386         if (description != (char *) NULL)
03387           {
03388             char
03389               question[MaxTextExtent];
03390 
03391             (void) CopyMagickString(question,description,MaxTextExtent);
03392             (void) ConcatenateMagickString(question,"?",MaxTextExtent);
03393             width=WidgetTextWidth(font_info,question);
03394             x=(int) ((windows->widget.width >> 1)-(width >> 1));
03395             y+=height;
03396             (void) XDrawString(display,windows->widget.id,
03397               windows->widget.annotate_context,x,y,question,Extent(question));
03398           }
03399         XDrawBeveledButton(display,&windows->widget,&cancel_info);
03400         XDrawBeveledButton(display,&windows->widget,&dismiss_info);
03401         XDrawBeveledButton(display,&windows->widget,&yes_info);
03402         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
03403         state&=(~RedrawWidgetState);
03404       }
03405     /*
03406       Wait for next event.
03407     */
03408     (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
03409     switch (event.type)
03410     {
03411       case ButtonPress:
03412       {
03413         if (MatteIsActive(cancel_info,event.xbutton))
03414           {
03415             /*
03416               User pressed No button.
03417             */
03418             cancel_info.raised=MagickFalse;
03419             XDrawBeveledButton(display,&windows->widget,&cancel_info);
03420             break;
03421           }
03422         if (MatteIsActive(dismiss_info,event.xbutton))
03423           {
03424             /*
03425               User pressed Dismiss button.
03426             */
03427             dismiss_info.raised=MagickFalse;
03428             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
03429             break;
03430           }
03431         if (MatteIsActive(yes_info,event.xbutton))
03432           {
03433             /*
03434               User pressed Yes button.
03435             */
03436             yes_info.raised=MagickFalse;
03437             XDrawBeveledButton(display,&windows->widget,&yes_info);
03438             break;
03439           }
03440         break;
03441       }
03442       case ButtonRelease:
03443       {
03444         if (windows->widget.mapped == MagickFalse)
03445           break;
03446         if (cancel_info.raised == MagickFalse)
03447           {
03448             if (event.xbutton.window == windows->widget.id)
03449               if (MatteIsActive(cancel_info,event.xbutton))
03450                 {
03451                   confirm=0;
03452                   state|=ExitState;
03453                 }
03454             cancel_info.raised=MagickTrue;
03455             XDrawBeveledButton(display,&windows->widget,&cancel_info);
03456           }
03457         if (dismiss_info.raised == MagickFalse)
03458           {
03459             if (event.xbutton.window == windows->widget.id)
03460               if (MatteIsActive(dismiss_info,event.xbutton))
03461                 {
03462                   confirm=(-1);
03463                   state|=ExitState;
03464                 }
03465             dismiss_info.raised=MagickTrue;
03466             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
03467           }
03468         if (yes_info.raised == MagickFalse)
03469           {
03470             if (event.xbutton.window == windows->widget.id)
03471               if (MatteIsActive(yes_info,event.xbutton))
03472                 {
03473                   confirm=1;
03474                   state|=ExitState;
03475                 }
03476             yes_info.raised=MagickTrue;
03477             XDrawBeveledButton(display,&windows->widget,&yes_info);
03478           }
03479         break;
03480       }
03481       case ClientMessage:
03482       {
03483         /*
03484           If client window delete message, exit.
03485         */
03486         if (event.xclient.message_type != windows->wm_protocols)
03487           break;
03488         if (*event.xclient.data.l == (int) windows->wm_take_focus)
03489           {
03490             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
03491               (Time) event.xclient.data.l[1]);
03492             break;
03493           }
03494         if (*event.xclient.data.l != (int) windows->wm_delete_window)
03495           break;
03496         if (event.xclient.window == windows->widget.id)
03497           {
03498             state|=ExitState;
03499             break;
03500           }
03501         break;
03502       }
03503       case ConfigureNotify:
03504       {
03505         /*
03506           Update widget configuration.
03507         */
03508         if (event.xconfigure.window != windows->widget.id)
03509           break;
03510         if ((event.xconfigure.width == (int) windows->widget.width) &&
03511             (event.xconfigure.height == (int) windows->widget.height))
03512           break;
03513         windows->widget.width=(unsigned int)
03514           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
03515         windows->widget.height=(unsigned int)
03516           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
03517         state|=UpdateConfigurationState;
03518         break;
03519       }
03520       case EnterNotify:
03521       {
03522         if (event.xcrossing.window != windows->widget.id)
03523           break;
03524         state&=(~InactiveWidgetState);
03525         break;
03526       }
03527       case Expose:
03528       {
03529         if (event.xexpose.window != windows->widget.id)
03530           break;
03531         if (event.xexpose.count != 0)
03532           break;
03533         state|=RedrawWidgetState;
03534         break;
03535       }
03536       case KeyPress:
03537       {
03538         static char
03539           command[MaxTextExtent];
03540 
03541         static KeySym
03542           key_symbol;
03543 
03544         /*
03545           Respond to a user key press.
03546         */
03547         if (event.xkey.window != windows->widget.id)
03548           break;
03549         (void) XLookupString((XKeyEvent *) &event.xkey,command,
03550           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
03551         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
03552           {
03553             yes_info.raised=MagickFalse;
03554             XDrawBeveledButton(display,&windows->widget,&yes_info);
03555             confirm=1;
03556             state|=ExitState;
03557             break;
03558           }
03559         break;
03560       }
03561       case LeaveNotify:
03562       {
03563         if (event.xcrossing.window != windows->widget.id)
03564           break;
03565         state|=InactiveWidgetState;
03566         break;
03567       }
03568       case MotionNotify:
03569       {
03570         /*
03571           Discard pending button motion events.
03572         */
03573         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
03574         if (state & InactiveWidgetState)
03575           break;
03576         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
03577           {
03578             /*
03579               Cancel button status changed.
03580             */
03581             cancel_info.raised=cancel_info.raised == MagickFalse ?
03582               MagickTrue : MagickFalse;
03583             XDrawBeveledButton(display,&windows->widget,&cancel_info);
03584             break;
03585           }
03586         if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
03587           {
03588             /*
03589               Dismiss button status changed.
03590             */
03591             dismiss_info.raised=cancel_info.raised == MagickFalse ?
03592               MagickTrue : MagickFalse;
03593             XDrawBeveledButton(display,&windows->widget,&dismiss_info);
03594             break;
03595           }
03596         if (yes_info.raised == MatteIsActive(yes_info,event.xmotion))
03597           {
03598             /*
03599               Yes button status changed.
03600             */
03601             yes_info.raised=yes_info.raised == MagickFalse ?
03602               MagickTrue : MagickFalse;
03603             XDrawBeveledButton(display,&windows->widget,&yes_info);
03604             break;
03605           }
03606         break;
03607       }
03608       default:
03609         break;
03610     }
03611   } while ((state & ExitState) == 0);
03612   XSetCursorState(display,windows,MagickFalse);
03613   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
03614   XCheckRefreshWindows(display,windows);
03615   return(confirm);
03616 }
03617 
03618 /*
03619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03620 %                                                                             %
03621 %                                                                             %
03622 %                                                                             %
03623 %   X D i a l o g W i d g e t                                                 %
03624 %                                                                             %
03625 %                                                                             %
03626 %                                                                             %
03627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03628 %
03629 %  XDialogWidget() displays a Dialog widget with a query to the user.  The user
03630 %  keys a reply and presses the Ok or Cancel button to exit.  The typed text is
03631 %  returned as the reply function parameter.
03632 %
03633 %  The format of the XDialogWidget method is:
03634 %
03635 %      int XDialogWidget(Display *display,XWindows *windows,const char *action,
03636 %        const char *query,char *reply)
03637 %
03638 %  A description of each parameter follows:
03639 %
03640 %    o display: Specifies a connection to an X server;  returned from
03641 %      XOpenDisplay.
03642 %
03643 %    o window: Specifies a pointer to a XWindows structure.
03644 %
03645 %    o action: Specifies a pointer to the action of this widget.
03646 %
03647 %    o query: Specifies a pointer to the query to present to the user.
03648 %
03649 %    o reply: the response from the user is returned in this parameter.
03650 %
03651 */
03652 MagickPrivate int XDialogWidget(Display *display,XWindows *windows,
03653   const char *action,const char *query,char *reply)
03654 {
03655 #define CancelButtonText  "Cancel"
03656 
03657   char
03658     primary_selection[MaxTextExtent];
03659 
03660   int
03661     x;
03662 
03663   register int
03664     i;
03665 
03666   static MagickBooleanType
03667     raised = MagickFalse;
03668 
03669   Status
03670     status;
03671 
03672   unsigned int
03673     anomaly,
03674     height,
03675     width;
03676 
03677   size_t
03678     state;
03679 
03680   XEvent
03681     event;
03682 
03683   XFontStruct
03684     *font_info;
03685 
03686   XTextProperty
03687     window_name;
03688 
03689   XWidgetInfo
03690     action_info,
03691     cancel_info,
03692     reply_info,
03693     special_info,
03694     text_info;
03695 
03696   XWindowChanges
03697     window_changes;
03698 
03699   /*
03700     Determine Dialog widget attributes.
03701   */
03702   assert(display != (Display *) NULL);
03703   assert(windows != (XWindows *) NULL);
03704   assert(action != (char *) NULL);
03705   assert(query != (char *) NULL);
03706   assert(reply != (char *) NULL);
03707   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
03708   XCheckRefreshWindows(display,windows);
03709   font_info=windows->widget.font_info;
03710   width=WidgetTextWidth(font_info,(char *) action);
03711   if (WidgetTextWidth(font_info,CancelButtonText) > width)
03712     width=WidgetTextWidth(font_info,CancelButtonText);
03713   width+=(3*QuantumMargin) >> 1;
03714   height=(unsigned int) (font_info->ascent+font_info->descent);
03715   /*
03716     Position Dialog widget.
03717   */
03718   windows->widget.width=(unsigned int) MagickMax((int) (2*width),(int)
03719     WidgetTextWidth(font_info,(char *) query));
03720   if (windows->widget.width < WidgetTextWidth(font_info,reply))
03721     windows->widget.width=WidgetTextWidth(font_info,reply);
03722   windows->widget.width+=6*QuantumMargin;
03723   windows->widget.min_width=(unsigned int)
03724     (width+28*XTextWidth(font_info,"#",1)+4*QuantumMargin);
03725   if (windows->widget.width < windows->widget.min_width)
03726     windows->widget.width=windows->widget.min_width;
03727   windows->widget.height=(unsigned int) (7*height+(QuantumMargin << 1));
03728   windows->widget.min_height=windows->widget.height;
03729   if (windows->widget.height < windows->widget.min_height)
03730     windows->widget.height=windows->widget.min_height;
03731   XConstrainWindowPosition(display,&windows->widget);
03732   /*
03733     Map Dialog widget.
03734   */
03735   (void) CopyMagickString(windows->widget.name,"Dialog",MaxTextExtent);
03736   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
03737   if (status != False)
03738     {
03739       XSetWMName(display,windows->widget.id,&window_name);
03740       XSetWMIconName(display,windows->widget.id,&window_name);
03741       (void) XFree((void *) window_name.value);
03742     }
03743   window_changes.width=(int) windows->widget.width;
03744   window_changes.height=(int) windows->widget.height;
03745   window_changes.x=windows->widget.x;
03746   window_changes.y=windows->widget.y;
03747   (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
03748     (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
03749   (void) XMapRaised(display,windows->widget.id);
03750   windows->widget.mapped=MagickFalse;
03751   /*
03752     Respond to X events.
03753   */
03754   anomaly=(LocaleCompare(action,"Background") == 0) ||
03755     (LocaleCompare(action,"New") == 0) ||
03756     (LocaleCompare(action,"Quantize") == 0) ||
03757     (LocaleCompare(action,"Resize") == 0) ||
03758     (LocaleCompare(action,"Save") == 0) ||
03759     (LocaleCompare(action,"Shade") == 0);
03760   state=UpdateConfigurationState;
03761   XSetCursorState(display,windows,MagickTrue);
03762   do
03763   {
03764     if (state & UpdateConfigurationState)
03765       {
03766         /*
03767           Initialize button information.
03768         */
03769         XGetWidgetInfo(CancelButtonText,&cancel_info);
03770         cancel_info.width=width;
03771         cancel_info.height=(unsigned int) ((3*height) >> 1);
03772         cancel_info.x=(int)
03773           (windows->widget.width-cancel_info.width-((3*QuantumMargin) >> 1));
03774         cancel_info.y=(int)
03775           (windows->widget.height-cancel_info.height-((3*QuantumMargin) >> 1));
03776         XGetWidgetInfo(action,&action_info);
03777         action_info.width=width;
03778         action_info.height=(unsigned int) ((3*height) >> 1);
03779         action_info.x=cancel_info.x-(cancel_info.width+QuantumMargin+
03780           (action_info.bevel_width << 1));
03781         action_info.y=cancel_info.y;
03782         /*
03783           Initialize reply information.
03784         */
03785         XGetWidgetInfo(reply,&reply_info);
03786         reply_info.raised=MagickFalse;
03787         reply_info.bevel_width--;
03788         reply_info.width=windows->widget.width-(3*QuantumMargin);
03789         reply_info.height=height << 1;
03790         reply_info.x=(3*QuantumMargin) >> 1;
03791         reply_info.y=action_info.y-reply_info.height-QuantumMargin;
03792         /*
03793           Initialize option information.
03794         */
03795         XGetWidgetInfo("Dither",&special_info);
03796         special_info.raised=raised;
03797         special_info.bevel_width--;
03798         special_info.width=(unsigned int) QuantumMargin >> 1;
03799         special_info.height=(unsigned int) QuantumMargin >> 1;
03800         special_info.x=reply_info.x;
03801         special_info.y=action_info.y+action_info.height-special_info.height;
03802         if (LocaleCompare(action,"Background") == 0)
03803           special_info.text=(char *) "Backdrop";
03804         if (LocaleCompare(action,"New") == 0)
03805           special_info.text=(char *) "Gradation";
03806         if (LocaleCompare(action,"Resize") == 0)
03807           special_info.text=(char *) "Constrain ratio";
03808         if (LocaleCompare(action,"Save") == 0)
03809           special_info.text=(char *) "Non-progressive";
03810         if (LocaleCompare(action,"Shade") == 0)
03811           special_info.text=(char *) "Color shading";
03812         /*
03813           Initialize text information.
03814         */
03815         XGetWidgetInfo(query,&text_info);
03816         text_info.width=reply_info.width;
03817         text_info.height=height;
03818         text_info.x=reply_info.x-(QuantumMargin >> 1);
03819         text_info.y=QuantumMargin;
03820         text_info.center=MagickFalse;
03821         state&=(~UpdateConfigurationState);
03822       }
03823     if (state & RedrawWidgetState)
03824       {
03825         /*
03826           Redraw Dialog widget.
03827         */
03828         XDrawWidgetText(display,&windows->widget,&text_info);
03829         XDrawBeveledMatte(display,&windows->widget,&reply_info);
03830         XDrawMatteText(display,&windows->widget,&reply_info);
03831         if (anomaly)
03832           XDrawBeveledButton(display,&windows->widget,&special_info);
03833         XDrawBeveledButton(display,&windows->widget,&action_info);
03834         XDrawBeveledButton(display,&windows->widget,&cancel_info);
03835         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
03836         state&=(~RedrawWidgetState);
03837       }
03838     /*
03839       Wait for next event.
03840     */
03841     (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
03842     switch (event.type)
03843     {
03844       case ButtonPress:
03845       {
03846         if (anomaly)
03847           if (MatteIsActive(special_info,event.xbutton))
03848             {
03849               /*
03850                 Option button status changed.
03851               */
03852               special_info.raised=!special_info.raised;
03853               XDrawBeveledButton(display,&windows->widget,&special_info);
03854               break;
03855             }
03856         if (MatteIsActive(action_info,event.xbutton))
03857           {
03858             /*
03859               User pressed Action button.
03860             */
03861             action_info.raised=MagickFalse;
03862             XDrawBeveledButton(display,&windows->widget,&action_info);
03863             break;
03864           }
03865         if (MatteIsActive(cancel_info,event.xbutton))
03866           {
03867             /*
03868               User pressed Cancel button.
03869             */
03870             cancel_info.raised=MagickFalse;
03871             XDrawBeveledButton(display,&windows->widget,&cancel_info);
03872             break;
03873           }
03874         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
03875           break;
03876         if (event.xbutton.button != Button2)
03877           {
03878             static Time
03879               click_time;
03880 
03881             /*
03882               Move text cursor to position of button press.
03883             */
03884             x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
03885             for (i=1; i <= Extent(reply_info.marker); i++)
03886               if (XTextWidth(font_info,reply_info.marker,i) > x)
03887                 break;
03888             reply_info.cursor=reply_info.marker+i-1;
03889             if (event.xbutton.time > (click_time+DoubleClick))
03890               reply_info.highlight=MagickFalse;
03891             else
03892               {
03893                 /*
03894                   Become the XA_PRIMARY selection owner.
03895                 */
03896                 (void) CopyMagickString(primary_selection,reply_info.text,
03897                   MaxTextExtent);
03898                 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
03899                   event.xbutton.time);
03900                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
03901                   windows->widget.id ? MagickTrue : MagickFalse;
03902               }
03903             XDrawMatteText(display,&windows->widget,&reply_info);
03904             click_time=event.xbutton.time;
03905             break;
03906           }
03907         /*
03908           Request primary selection.
03909         */
03910         (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
03911           windows->widget.id,event.xbutton.time);
03912         break;
03913       }
03914       case ButtonRelease:
03915       {
03916         if (windows->widget.mapped == MagickFalse)
03917           break;
03918         if (action_info.raised == MagickFalse)
03919           {
03920             if (event.xbutton.window == windows->widget.id)
03921               if (MatteIsActive(action_info,event.xbutton))
03922                 state|=ExitState;
03923             action_info.raised=MagickTrue;
03924             XDrawBeveledButton(display,&windows->widget,&action_info);
03925           }
03926         if (cancel_info.raised == MagickFalse)
03927           {
03928             if (event.xbutton.window == windows->widget.id)
03929               if (MatteIsActive(cancel_info,event.xbutton))
03930                 {
03931                   *reply_info.text='\0';
03932                   state|=ExitState;
03933                 }
03934             cancel_info.raised=MagickTrue;
03935             XDrawBeveledButton(display,&windows->widget,&cancel_info);
03936           }
03937         break;
03938       }
03939       case ClientMessage:
03940       {
03941         /*
03942           If client window delete message, exit.
03943         */
03944         if (event.xclient.message_type != windows->wm_protocols)
03945           break;
03946         if (*event.xclient.data.l == (int) windows->wm_take_focus)
03947           {
03948             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
03949               (Time) event.xclient.data.l[1]);
03950             break;
03951           }
03952         if (*event.xclient.data.l != (int) windows->wm_delete_window)
03953           break;
03954         if (event.xclient.window == windows->widget.id)
03955           {
03956             *reply_info.text='\0';
03957             state|=ExitState;
03958             break;
03959           }
03960         break;
03961       }
03962       case ConfigureNotify:
03963       {
03964         /*
03965           Update widget configuration.
03966         */
03967         if (event.xconfigure.window != windows->widget.id)
03968           break;
03969         if ((event.xconfigure.width == (int) windows->widget.width) &&
03970             (event.xconfigure.height == (int) windows->widget.height))
03971           break;
03972         windows->widget.width=(unsigned int)
03973           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
03974         windows->widget.height=(unsigned int)
03975           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
03976         state|=UpdateConfigurationState;
03977         break;
03978       }
03979       case EnterNotify:
03980       {
03981         if (event.xcrossing.window != windows->widget.id)
03982           break;
03983         state&=(~InactiveWidgetState);
03984         break;
03985       }
03986       case Expose:
03987       {
03988         if (event.xexpose.window != windows->widget.id)
03989           break;
03990         if (event.xexpose.count != 0)
03991           break;
03992         state|=RedrawWidgetState;
03993         break;
03994       }
03995       case KeyPress:
03996       {
03997         static char
03998           command[MaxTextExtent];
03999 
04000         static int
04001           length;
04002 
04003         static KeySym
04004           key_symbol;
04005 
04006         /*
04007           Respond to a user key press.
04008         */
04009         if (event.xkey.window != windows->widget.id)
04010           break;
04011         length=XLookupString((XKeyEvent *) &event.xkey,command,
04012           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
04013         *(command+length)='\0';
04014         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
04015           {
04016             action_info.raised=MagickFalse;
04017             XDrawBeveledButton(display,&windows->widget,&action_info);
04018             state|=ExitState;
04019             break;
04020           }
04021         if (key_symbol == XK_Control_L)
04022           {
04023             state|=ControlState;
04024             break;
04025           }
04026         if (state & ControlState)
04027           switch ((int) key_symbol)
04028           {
04029             case XK_u:
04030             case XK_U:
04031             {
04032               /*
04033                 Erase the entire line of text.
04034               */
04035               *reply_info.text='\0';
04036               reply_info.cursor=reply_info.text;
04037               reply_info.marker=reply_info.text;
04038               reply_info.highlight=MagickFalse;
04039               break;
04040             }
04041             default:
04042               break;
04043           }
04044         XEditText(display,&reply_info,key_symbol,command,state);
04045         XDrawMatteText(display,&windows->widget,&reply_info);
04046         break;
04047       }
04048       case KeyRelease:
04049       {
04050         static char
04051           command[MaxTextExtent];
04052 
04053         static KeySym
04054           key_symbol;
04055 
04056         /*
04057           Respond to a user key release.
04058         */
04059         if (event.xkey.window != windows->widget.id)
04060           break;
04061         (void) XLookupString((XKeyEvent *) &event.xkey,command,
04062           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
04063         if (key_symbol == XK_Control_L)
04064           state&=(~ControlState);
04065         break;
04066       }
04067       case LeaveNotify:
04068       {
04069         if (event.xcrossing.window != windows->widget.id)
04070           break;
04071         state|=InactiveWidgetState;
04072         break;
04073       }
04074       case MotionNotify:
04075       {
04076         /*
04077           Discard pending button motion events.
04078         */
04079         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
04080         if (state & InactiveWidgetState)
04081           break;
04082         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
04083           {
04084             /*
04085               Action button status changed.
04086             */
04087             action_info.raised=action_info.raised == MagickFalse ?
04088               MagickTrue : MagickFalse;
04089             XDrawBeveledButton(display,&windows->widget,&action_info);
04090             break;
04091           }
04092         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
04093           {
04094             /*
04095               Cancel button status changed.
04096             */
04097             cancel_info.raised=cancel_info.raised == MagickFalse ?
04098               MagickTrue : MagickFalse;
04099             XDrawBeveledButton(display,&windows->widget,&cancel_info);
04100             break;
04101           }
04102         break;
04103       }
04104       case SelectionClear:
04105       {
04106         reply_info.highlight=MagickFalse;
04107         XDrawMatteText(display,&windows->widget,&reply_info);
04108         break;
04109       }
04110       case SelectionNotify:
04111       {
04112         Atom
04113           type;
04114 
04115         int
04116           format;
04117 
04118         unsigned char
04119           *data;
04120 
04121         unsigned long
04122           after,
04123           length;
04124 
04125         /*
04126           Obtain response from primary selection.
04127         */
04128         if (event.xselection.property == (Atom) None)
04129           break;
04130         status=XGetWindowProperty(display,event.xselection.requestor,
04131           event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
04132           &format,&length,&after,&data);
04133         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
04134             (length == 0))
04135           break;
04136         if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
04137           (void) XBell(display,0);
04138         else
04139           {
04140             /*
04141               Insert primary selection in reply text.
04142             */
04143             *(data+length)='\0';
04144             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
04145               state);
04146             XDrawMatteText(display,&windows->widget,&reply_info);
04147           }
04148         (void) XFree((void *) data);
04149         break;
04150       }
04151       case SelectionRequest:
04152       {
04153         XSelectionEvent
04154           notify;
04155 
04156         XSelectionRequestEvent
04157           *request;
04158 
04159         if (reply_info.highlight == MagickFalse)
04160           break;
04161         /*
04162           Set primary selection.
04163         */
04164         request=(&(event.xselectionrequest));
04165         (void) XChangeProperty(request->display,request->requestor,
04166           request->property,request->target,8,PropModeReplace,
04167           (unsigned char *) primary_selection,Extent(primary_selection));
04168         notify.type=SelectionNotify;
04169         notify.display=request->display;
04170         notify.requestor=request->requestor;
04171         notify.selection=request->selection;
04172         notify.target=request->target;
04173         notify.time=request->time;
04174         if (request->property == None)
04175           notify.property=request->target;
04176         else
04177           notify.property=request->property;
04178         (void) XSendEvent(request->display,request->requestor,False,0,
04179           (XEvent *) &notify);
04180       }
04181       default:
04182         break;
04183     }
04184   } while ((state & ExitState) == 0);
04185   XSetCursorState(display,windows,MagickFalse);
04186   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
04187   XCheckRefreshWindows(display,windows);
04188   if (anomaly)
04189     if (special_info.raised)
04190       if (*reply != '\0')
04191         raised=MagickTrue;
04192   return(raised == MagickFalse);
04193 }
04194 
04195 /*
04196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04197 %                                                                             %
04198 %                                                                             %
04199 %                                                                             %
04200 %   X F i l e B r o w s e r W i d g e t                                       %
04201 %                                                                             %
04202 %                                                                             %
04203 %                                                                             %
04204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04205 %
04206 %  XFileBrowserWidget() displays a File Browser widget with a file query to the
04207 %  user.  The user keys a reply and presses the Action or Cancel button to
04208 %  exit.  The typed text is returned as the reply function parameter.
04209 %
04210 %  The format of the XFileBrowserWidget method is:
04211 %
04212 %      void XFileBrowserWidget(Display *display,XWindows *windows,
04213 %        const char *action,char *reply)
04214 %
04215 %  A description of each parameter follows:
04216 %
04217 %    o display: Specifies a connection to an X server;  returned from
04218 %      XOpenDisplay.
04219 %
04220 %    o window: Specifies a pointer to a XWindows structure.
04221 %
04222 %    o action: Specifies a pointer to the action of this widget.
04223 %
04224 %    o reply: the response from the user is returned in this parameter.
04225 %
04226 */
04227 MagickPrivate void XFileBrowserWidget(Display *display,XWindows *windows,
04228   const char *action,char *reply)
04229 {
04230 #define CancelButtonText  "Cancel"
04231 #define DirectoryText  "Directory:"
04232 #define FilenameText  "File name:"
04233 #define GrabButtonText  "Grab"
04234 #define FormatButtonText  "Format"
04235 #define HomeButtonText  "Home"
04236 #define UpButtonText  "Up"
04237 
04238   char
04239     *directory,
04240     **filelist,
04241     home_directory[MaxTextExtent],
04242     primary_selection[MaxTextExtent],
04243     text[MaxTextExtent],
04244     working_path[MaxTextExtent];
04245 
04246   int
04247     x,
04248     y;
04249 
04250   register ssize_t
04251     i;
04252 
04253   static char
04254     glob_pattern[MaxTextExtent] = "*",
04255     format[MaxTextExtent] = "miff";
04256 
04257   static MagickStatusType
04258     mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
04259 
04260   Status
04261     status;
04262 
04263   unsigned int
04264     anomaly,
04265     height,
04266     text_width,
04267     visible_files,
04268     width;
04269 
04270   size_t
04271     delay,
04272     files,
04273     state;
04274 
04275   XEvent
04276     event;
04277 
04278   XFontStruct
04279     *font_info;
04280 
04281   XTextProperty
04282     window_name;
04283 
04284   XWidgetInfo
04285     action_info,
04286     cancel_info,
04287     expose_info,
04288     special_info,
04289     list_info,
04290     home_info,
04291     north_info,
04292     reply_info,
04293     scroll_info,
04294     selection_info,
04295     slider_info,
04296     south_info,
04297     text_info,
04298     up_info;
04299 
04300   XWindowChanges
04301     window_changes;
04302 
04303   /*
04304     Read filelist from current directory.
04305   */
04306   assert(display != (Display *) NULL);
04307   assert(windows != (XWindows *) NULL);
04308   assert(action != (char *) NULL);
04309   assert(reply != (char *) NULL);
04310   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
04311   XSetCursorState(display,windows,MagickTrue);
04312   XCheckRefreshWindows(display,windows);
04313   directory=getcwd(home_directory,MaxTextExtent);
04314   (void) directory;
04315   (void) CopyMagickString(working_path,home_directory,MaxTextExtent);
04316   filelist=ListFiles(working_path,glob_pattern,&files);
04317   if (filelist == (char **) NULL)
04318     {
04319       /*
04320         Directory read failed.
04321       */
04322       XNoticeWidget(display,windows,"Unable to read directory:",working_path);
04323       (void) XDialogWidget(display,windows,action,"Enter filename:",reply);
04324       return;
04325     }
04326   /*
04327     Determine File Browser widget attributes.
04328   */
04329   font_info=windows->widget.font_info;
04330   text_width=0;
04331   for (i=0; i < (ssize_t) files; i++)
04332     if (WidgetTextWidth(font_info,filelist[i]) > text_width)
04333       text_width=WidgetTextWidth(font_info,filelist[i]);
04334   width=WidgetTextWidth(font_info,(char *) action);
04335   if (WidgetTextWidth(font_info,GrabButtonText) > width)
04336     width=WidgetTextWidth(font_info,GrabButtonText);
04337   if (WidgetTextWidth(font_info,FormatButtonText) > width)
04338     width=WidgetTextWidth(font_info,FormatButtonText);
04339   if (WidgetTextWidth(font_info,CancelButtonText) > width)
04340     width=WidgetTextWidth(font_info,CancelButtonText);
04341   if (WidgetTextWidth(font_info,HomeButtonText) > width)
04342     width=WidgetTextWidth(font_info,HomeButtonText);
04343   if (WidgetTextWidth(font_info,UpButtonText) > width)
04344     width=WidgetTextWidth(font_info,UpButtonText);
04345   width+=QuantumMargin;
04346   if (WidgetTextWidth(font_info,DirectoryText) > width)
04347     width=WidgetTextWidth(font_info,DirectoryText);
04348   if (WidgetTextWidth(font_info,FilenameText) > width)
04349     width=WidgetTextWidth(font_info,FilenameText);
04350   height=(unsigned int) (font_info->ascent+font_info->descent);
04351   /*
04352     Position File Browser widget.
04353   */
04354   windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
04355     6*QuantumMargin;
04356   windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
04357   if (windows->widget.width < windows->widget.min_width)
04358     windows->widget.width=windows->widget.min_width;
04359   windows->widget.height=(unsigned int)
04360     (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
04361   windows->widget.min_height=(unsigned int)
04362     (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
04363   if (windows->widget.height < windows->widget.min_height)
04364     windows->widget.height=windows->widget.min_height;
04365   XConstrainWindowPosition(display,&windows->widget);
04366   /*
04367     Map File Browser widget.
04368   */
04369   (void) CopyMagickString(windows->widget.name,"Browse and Select a File",
04370     MaxTextExtent);
04371   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
04372   if (status != False)
04373     {
04374       XSetWMName(display,windows->widget.id,&window_name);
04375       XSetWMIconName(display,windows->widget.id,&window_name);
04376       (void) XFree((void *) window_name.value);
04377     }
04378   window_changes.width=(int) windows->widget.width;
04379   window_changes.height=(int) windows->widget.height;
04380   window_changes.x=windows->widget.x;
04381   window_changes.y=windows->widget.y;
04382   (void) XReconfigureWMWindow(display,windows->widget.id,
04383     windows->widget.screen,mask,&window_changes);
04384   (void) XMapRaised(display,windows->widget.id);
04385   windows->widget.mapped=MagickFalse;
04386   /*
04387     Respond to X events.
04388   */
04389   XGetWidgetInfo((char *) NULL,&slider_info);
04390   XGetWidgetInfo((char *) NULL,&north_info);
04391   XGetWidgetInfo((char *) NULL,&south_info);
04392   XGetWidgetInfo((char *) NULL,&expose_info);
04393   visible_files=0;
04394   anomaly=(LocaleCompare(action,"Composite") == 0) ||
04395     (LocaleCompare(action,"Open") == 0) || (LocaleCompare(action,"Map") == 0);
04396   *reply='\0';
04397   delay=SuspendTime << 2;
04398   state=UpdateConfigurationState;
04399   do
04400   {
04401     if (state & UpdateConfigurationState)
04402       {
04403         int
04404           id;
04405 
04406         /*
04407           Initialize button information.
04408         */
04409         XGetWidgetInfo(CancelButtonText,&cancel_info);
04410         cancel_info.width=width;
04411         cancel_info.height=(unsigned int) ((3*height) >> 1);
04412         cancel_info.x=(int)
04413           (windows->widget.width-cancel_info.width-QuantumMargin-2);
04414         cancel_info.y=(int)
04415           (windows->widget.height-cancel_info.height-QuantumMargin);
04416         XGetWidgetInfo(action,&action_info);
04417         action_info.width=width;
04418         action_info.height=(unsigned int) ((3*height) >> 1);
04419         action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
04420           (action_info.bevel_width << 1));
04421         action_info.y=cancel_info.y;
04422         XGetWidgetInfo(GrabButtonText,&special_info);
04423         special_info.width=width;
04424         special_info.height=(unsigned int) ((3*height) >> 1);
04425         special_info.x=action_info.x-(action_info.width+(QuantumMargin >> 1)+
04426           (special_info.bevel_width << 1));
04427         special_info.y=action_info.y;
04428         if (anomaly == MagickFalse)
04429           {
04430             register char
04431               *p;
04432 
04433             special_info.text=(char *) FormatButtonText;
04434             p=reply+Extent(reply)-1;
04435             while ((p > (reply+1)) && (*(p-1) != '.'))
04436               p--;
04437             if ((p > (reply+1)) && (*(p-1) == '.'))
04438               (void) CopyMagickString(format,p,MaxTextExtent);
04439           }
04440         XGetWidgetInfo(UpButtonText,&up_info);
04441         up_info.width=width;
04442         up_info.height=(unsigned int) ((3*height) >> 1);
04443         up_info.x=QuantumMargin;
04444         up_info.y=((5*QuantumMargin) >> 1)+height;
04445         XGetWidgetInfo(HomeButtonText,&home_info);
04446         home_info.width=width;
04447         home_info.height=(unsigned int) ((3*height) >> 1);
04448         home_info.x=QuantumMargin;
04449         home_info.y=up_info.y+up_info.height+QuantumMargin;
04450         /*
04451           Initialize reply information.
04452         */
04453         XGetWidgetInfo(reply,&reply_info);
04454         reply_info.raised=MagickFalse;
04455         reply_info.bevel_width--;
04456         reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
04457         reply_info.height=height << 1;
04458         reply_info.x=(int) (width+(QuantumMargin << 1));
04459         reply_info.y=action_info.y-reply_info.height-QuantumMargin;
04460         /*
04461           Initialize scroll information.
04462         */
04463         XGetWidgetInfo((char *) NULL,&scroll_info);
04464         scroll_info.bevel_width--;
04465         scroll_info.width=height;
04466         scroll_info.height=(unsigned int)
04467           (reply_info.y-up_info.y-(QuantumMargin >> 1));
04468         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
04469         scroll_info.y=up_info.y-reply_info.bevel_width;
04470         scroll_info.raised=MagickFalse;
04471         scroll_info.trough=MagickTrue;
04472         north_info=scroll_info;
04473         north_info.raised=MagickTrue;
04474         north_info.width-=(north_info.bevel_width << 1);
04475         north_info.height=north_info.width-1;
04476         north_info.x+=north_info.bevel_width;
04477         north_info.y+=north_info.bevel_width;
04478         south_info=north_info;
04479         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
04480           south_info.height;
04481         id=slider_info.id;
04482         slider_info=north_info;
04483         slider_info.id=id;
04484         slider_info.width-=2;
04485         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
04486           slider_info.bevel_width+2;
04487         slider_info.height=scroll_info.height-((slider_info.min_y-
04488           scroll_info.y+1) << 1)+4;
04489         visible_files=scroll_info.height/(height+(height >> 3));
04490         if (files > visible_files)
04491           slider_info.height=(unsigned int)
04492             ((visible_files*slider_info.height)/files);
04493         slider_info.max_y=south_info.y-south_info.bevel_width-
04494           slider_info.bevel_width-2;
04495         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
04496         slider_info.y=slider_info.min_y;
04497         expose_info=scroll_info;
04498         expose_info.y=slider_info.y;
04499         /*
04500           Initialize list information.
04501         */
04502         XGetWidgetInfo((char *) NULL,&list_info);
04503         list_info.raised=MagickFalse;
04504         list_info.bevel_width--;
04505         list_info.width=(unsigned int)
04506           (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
04507         list_info.height=scroll_info.height;
04508         list_info.x=reply_info.x;
04509         list_info.y=scroll_info.y;
04510         if (windows->widget.mapped == MagickFalse)
04511           state|=JumpListState;
04512         /*
04513           Initialize text information.
04514         */
04515         *text='\0';
04516         XGetWidgetInfo(text,&text_info);
04517         text_info.center=MagickFalse;
04518         text_info.width=reply_info.width;
04519         text_info.height=height;
04520         text_info.x=list_info.x-(QuantumMargin >> 1);
04521         text_info.y=QuantumMargin;
04522         /*
04523           Initialize selection information.
04524         */
04525         XGetWidgetInfo((char *) NULL,&selection_info);
04526         selection_info.center=MagickFalse;
04527         selection_info.width=list_info.width;
04528         selection_info.height=(unsigned int) ((9*height) >> 3);
04529         selection_info.x=list_info.x;
04530         state&=(~UpdateConfigurationState);
04531       }
04532     if (state & RedrawWidgetState)
04533       {
04534         /*
04535           Redraw File Browser window.
04536         */
04537         x=QuantumMargin;
04538         y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
04539         (void) XDrawString(display,windows->widget.id,
04540           windows->widget.annotate_context,x,y,DirectoryText,
04541           Extent(DirectoryText));
04542         (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
04543         (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
04544           MaxTextExtent);
04545         (void) ConcatenateMagickString(text_info.text,glob_pattern,
04546           MaxTextExtent);
04547         XDrawWidgetText(display,&windows->widget,&text_info);
04548         XDrawBeveledButton(display,&windows->widget,&up_info);
04549         XDrawBeveledButton(display,&windows->widget,&home_info);
04550         XDrawBeveledMatte(display,&windows->widget,&list_info);
04551         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
04552         XDrawTriangleNorth(display,&windows->widget,&north_info);
04553         XDrawBeveledButton(display,&windows->widget,&slider_info);
04554         XDrawTriangleSouth(display,&windows->widget,&south_info);
04555         x=QuantumMargin;
04556         y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
04557         (void) XDrawString(display,windows->widget.id,
04558           windows->widget.annotate_context,x,y,FilenameText,
04559           Extent(FilenameText));
04560         XDrawBeveledMatte(display,&windows->widget,&reply_info);
04561         XDrawMatteText(display,&windows->widget,&reply_info);
04562         XDrawBeveledButton(display,&windows->widget,&special_info);
04563         XDrawBeveledButton(display,&windows->widget,&action_info);
04564         XDrawBeveledButton(display,&windows->widget,&cancel_info);
04565         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
04566         selection_info.id=(~0);
04567         state|=RedrawListState;
04568         state&=(~RedrawWidgetState);
04569       }
04570     if (state & UpdateListState)
04571       {
04572         char
04573           **checklist;
04574 
04575         size_t
04576           number_files;
04577 
04578         /*
04579           Update file list.
04580         */
04581         checklist=ListFiles(working_path,glob_pattern,&number_files);
04582         if (checklist == (char **) NULL)
04583           {
04584             /*
04585               Reply is a filename, exit.
04586             */
04587             action_info.raised=MagickFalse;
04588             XDrawBeveledButton(display,&windows->widget,&action_info);
04589             break;
04590           }
04591         for (i=0; i < (ssize_t) files; i++)
04592           filelist[i]=DestroyString(filelist[i]);
04593         if (filelist != (char **) NULL)
04594           filelist=(char **) RelinquishMagickMemory(filelist);
04595         filelist=checklist;
04596         files=number_files;
04597         /*
04598           Update file list.
04599         */
04600         slider_info.height=
04601           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
04602         if (files > visible_files)
04603           slider_info.height=(unsigned int)
04604             ((visible_files*slider_info.height)/files);
04605         slider_info.max_y=south_info.y-south_info.bevel_width-
04606           slider_info.bevel_width-2;
04607         slider_info.id=0;
04608         slider_info.y=slider_info.min_y;
04609         expose_info.y=slider_info.y;
04610         selection_info.id=(~0);
04611         list_info.id=(~0);
04612         state|=RedrawListState;
04613         /*
04614           Redraw directory name & reply.
04615         */
04616         if (IsGlob(reply_info.text) == MagickFalse)
04617           {
04618             *reply_info.text='\0';
04619             reply_info.cursor=reply_info.text;
04620           }
04621         (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
04622         (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
04623           MaxTextExtent);
04624         (void) ConcatenateMagickString(text_info.text,glob_pattern,
04625           MaxTextExtent);
04626         XDrawWidgetText(display,&windows->widget,&text_info);
04627         XDrawMatteText(display,&windows->widget,&reply_info);
04628         XDrawBeveledMatte(display,&windows->widget,&scroll_info);
04629         XDrawTriangleNorth(display,&windows->widget,&north_info);
04630         XDrawBeveledButton(display,&windows->widget,&slider_info);
04631         XDrawTriangleSouth(display,&windows->widget,&south_info);
04632         XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
04633         state&=(~UpdateListState);
04634       }
04635     if (state & JumpListState)
04636       {
04637         /*
04638           Jump scroll to match user filename.
04639         */
04640         list_info.id=(~0);
04641         for (i=0; i < (ssize_t) files; i++)
04642           if (LocaleCompare(filelist[i],reply) >= 0)
04643             {
04644               list_info.id=(int)
04645                 (LocaleCompare(filelist[i],reply) == 0 ? i : ~0);
04646               break;
04647             }
04648         if ((i < (ssize_t) slider_info.id) ||
04649             (i >= (ssize_t) (slider_info.id+visible_files)))
04650           slider_info.id=(int) i-(visible_files >> 1);
04651         selection_info.id=(~0);
04652         state|=RedrawListState;
04653         state&=(~JumpListState);
04654       }
04655     if (state & RedrawListState)
04656       {
04657         /*
04658           Determine slider id and position.
04659         */
04660         if (slider_info.id >= (int) (files-visible_files))
04661           slider_info.id=(int) (files-visible_files);
04662         if ((slider_info.id < 0) || (files <= visible_files))
04663           slider_info.id=0;
04664         slider_info.y=slider_info.min_y;
04665         if (files > 0)
04666           slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
04667             slider_info.min_y+1)/files);
04668         if (slider_info.id != selection_info.id)
04669           {
04670             /*
04671               Redraw scroll bar and file names.
04672             */
04673             selection_info.id=slider_info.id;
04674             selection_info.y=list_info.y+(height >> 3)+2;
04675             for (i=0; i < (ssize_t) visible_files; i++)
04676             {
04677               selection_info.raised=(int) (slider_info.id+i) != list_info.id ?
04678                 MagickTrue : MagickFalse;
04679               selection_info.text=(char *) NULL;
04680               if ((slider_info.id+i) < (ssize_t) files)
04681                 selection_info.text=filelist[slider_info.id+i];
04682               XDrawWidgetText(display,&windows->widget,&selection_info);
04683               selection_info.y+=(int) selection_info.height;
04684             }
04685             /*
04686               Update slider.
04687             */
04688             if (slider_info.y > expose_info.y)
04689               {
04690                 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
04691                 expose_info.y=slider_info.y-expose_info.height-
04692                   slider_info.bevel_width-1;
04693               }
04694             else
04695               {
04696                 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
04697                 expose_info.y=slider_info.y+slider_info.height+
04698                   slider_info.bevel_width+1;
04699               }
04700             XDrawTriangleNorth(display,&windows->widget,&north_info);
04701             XDrawMatte(display,&windows->widget,&expose_info);
04702             XDrawBeveledButton(display,&windows->widget,&slider_info);
04703             XDrawTriangleSouth(display,&windows->widget,&south_info);
04704             expose_info.y=slider_info.y;
04705           }
04706         state&=(~RedrawListState);
04707       }
04708     /*
04709       Wait for next event.
04710     */
04711     if (north_info.raised && south_info.raised)
04712       (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
04713     else
04714       {
04715         /*
04716           Brief delay before advancing scroll bar.
04717         */
04718         XDelay(display,delay);
04719         delay=SuspendTime;
04720         (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
04721         if (north_info.raised == MagickFalse)
04722           if (slider_info.id > 0)
04723             {
04724               /*
04725                 Move slider up.
04726               */
04727               slider_info.id--;
04728               state|=RedrawListState;
04729             }
04730         if (south_info.raised == MagickFalse)
04731           if (slider_info.id < (int) files)
04732             {
04733               /*
04734                 Move slider down.
04735               */
04736               slider_info.id++;
04737               state|=RedrawListState;
04738             }
04739         if (event.type != ButtonRelease)
04740           continue;
04741       }
04742     switch (event.type)
04743     {
04744       case ButtonPress:
04745       {
04746         if (MatteIsActive(slider_info,event.xbutton))
04747           {
04748             /*
04749               Track slider.
04750             */
04751             slider_info.active=MagickTrue;
04752             break;
04753           }
04754         if (MatteIsActive(north_info,event.xbutton))
04755           if (slider_info.id > 0)
04756             {
04757               /*
04758                 Move slider up.
04759               */
04760               north_info.raised=MagickFalse;
04761               slider_info.id--;
04762               state|=RedrawListState;
04763               break;
04764             }
04765         if (MatteIsActive(south_info,event.xbutton))
04766           if (slider_info.id < (int) files)
04767             {
04768               /*
04769                 Move slider down.
04770               */
04771               south_info.raised=MagickFalse;
04772               slider_info.id++;
04773               state|=RedrawListState;
04774               break;
04775             }
04776         if (MatteIsActive(scroll_info,event.xbutton))
04777           {
04778             /*
04779               Move slider.
04780             */
04781             if (event.xbutton.y < slider_info.y)
04782               slider_info.id-=(visible_files-1);
04783             else
04784               slider_info.id+=(visible_files-1);
04785             state|=RedrawListState;
04786             break;
04787           }
04788         if (MatteIsActive(list_info,event.xbutton))
04789           {
04790             int
04791               id;
04792 
04793             /*
04794               User pressed file matte.
04795             */
04796             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
04797               selection_info.height;
04798             if (id >= (int) files)
04799               break;
04800             (void) CopyMagickString(reply_info.text,filelist[id],MaxTextExtent);
04801             reply_info.highlight=MagickFalse;
04802             reply_info.marker=reply_info.text;
04803             reply_info.cursor=reply_info.text+Extent(reply_info.text);
04804             XDrawMatteText(display,&windows->widget,&reply_info);
04805             if (id == list_info.id)
04806               {
04807                 register char
04808                   *p;
04809 
04810                 p=reply_info.text+strlen(reply_info.text)-1;
04811                 if (*p == *DirectorySeparator)
04812                   ChopPathComponents(reply_info.text,1);
04813                 (void) ConcatenateMagickString(working_path,DirectorySeparator,
04814                   MaxTextExtent);
04815                 (void) ConcatenateMagickString(working_path,reply_info.text,
04816                   MaxTextExtent);
04817                 *reply='\0';
04818                 state|=UpdateListState;
04819               }
04820             selection_info.id=(~0);
04821             list_info.id=id;
04822             state|=RedrawListState;
04823             break;
04824           }
04825         if (MatteIsActive(up_info,event.xbutton))
04826           {
04827             /*
04828               User pressed Up button.
04829             */
04830             up_info.raised=MagickFalse;
04831             XDrawBeveledButton(display,&windows->widget,&up_info);
04832             break;
04833           }
04834         if (MatteIsActive(home_info,event.xbutton))
04835           {
04836             /*
04837               User pressed Home button.
04838             */
04839             home_info.raised=MagickFalse;
04840             XDrawBeveledButton(display,&windows->widget,&home_info);
04841             break;
04842           }
04843         if (MatteIsActive(special_info,event.xbutton))
04844           {
04845             /*
04846               User pressed Special button.
04847             */
04848             special_info.raised=MagickFalse;
04849             XDrawBeveledButton(display,&windows->widget,&special_info);
04850             break;
04851           }
04852         if (MatteIsActive(action_info,event.xbutton))
04853           {
04854             /*
04855               User pressed action button.
04856             */
04857             action_info.raised=MagickFalse;
04858             XDrawBeveledButton(display,&windows->widget,&action_info);
04859             break;
04860           }
04861         if (MatteIsActive(cancel_info,event.xbutton))
04862           {
04863             /*
04864               User pressed Cancel button.
04865             */
04866             cancel_info.raised=MagickFalse;
04867             XDrawBeveledButton(display,&windows->widget,&cancel_info);
04868             break;
04869           }
04870         if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
04871           break;
04872         if (event.xbutton.button != Button2)
04873           {
04874             static Time
04875               click_time;
04876 
04877             /*
04878               Move text cursor to position of button press.
04879             */
04880             x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
04881             for (i=1; i <= (ssize_t) Extent(reply_info.marker); i++)
04882               if (XTextWidth(font_info,reply_info.marker,(int) i) > x)
04883                 break;
04884             reply_info.cursor=reply_info.marker+i-1;
04885             if (event.xbutton.time > (click_time+DoubleClick))
04886               reply_info.highlight=MagickFalse;
04887             else
04888               {
04889                 /*
04890                   Become the XA_PRIMARY selection owner.
04891                 */
04892                 (void) CopyMagickString(primary_selection,reply_info.text,
04893                   MaxTextExtent);
04894                 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
04895                   event.xbutton.time);
04896                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
04897                   windows->widget.id ? MagickTrue : MagickFalse;
04898               }
04899             XDrawMatteText(display,&windows->widget,&reply_info);
04900             click_time=event.xbutton.time;
04901             break;
04902           }
04903         /*
04904           Request primary selection.
04905         */
04906         (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
04907           windows->widget.id,event.xbutton.time);
04908         break;
04909       }
04910       case ButtonRelease:
04911       {
04912         if (windows->widget.mapped == MagickFalse)
04913           break;
04914         if (north_info.raised == MagickFalse)
04915           {
04916             /*
04917               User released up button.
04918             */
04919             delay=SuspendTime << 2;
04920             north_info.raised=MagickTrue;
04921             XDrawTriangleNorth(display,&windows->widget,&north_info);
04922           }
04923         if (south_info.raised == MagickFalse)
04924           {
04925             /*
04926               User released down button.
04927             */
04928             delay=SuspendTime << 2;
04929             south_info.raised=MagickTrue;
04930             XDrawTriangleSouth(display,&windows->widget,&south_info);
04931           }
04932         if (slider_info.active)
04933           {
04934             /*
04935               Stop tracking slider.
04936             */
04937             slider_info.active=MagickFalse;
04938             break;
04939           }
04940         if (up_info.raised == MagickFalse)
04941           {
04942             if (event.xbutton.window == windows->widget.id)
04943               if (MatteIsActive(up_info,event.xbutton))
04944                 {
04945                   ChopPathComponents(working_path,1);
04946                   if (*working_path == '\0')
04947                     (void) CopyMagickString(working_path,DirectorySeparator,
04948                       MaxTextExtent);
04949                   state|=UpdateListState;
04950                 }
04951             up_info.raised=MagickTrue;
04952             XDrawBeveledButton(display,&windows->widget,&up_info);
04953           }
04954         if (home_info.raised == MagickFalse)
04955           {
04956             if (event.xbutton.window == windows->widget.id)
04957               if (MatteIsActive(home_info,event.xbutton))
04958                 {
04959                   (void) CopyMagickString(working_path,home_directory,
04960                     MaxTextExtent);
04961                   state|=UpdateListState;
04962                 }
04963             home_info.raised=MagickTrue;
04964             XDrawBeveledButton(display,&windows->widget,&home_info);
04965           }
04966         if (special_info.raised == MagickFalse)
04967           {
04968             if (anomaly == MagickFalse)
04969               {
04970                 char
04971                   **formats;
04972 
04973                 ExceptionInfo
04974                   *exception;
04975 
04976                 size_t
04977                   number_formats;
04978 
04979                 /*
04980                   Let user select image format.
04981                 */
04982                 exception=AcquireExceptionInfo();
04983                 formats=GetMagickList("*",&number_formats,exception);
04984                 exception=DestroyExceptionInfo(exception);
04985                 (void) XCheckDefineCursor(display,windows->widget.id,
04986                   windows->widget.busy_cursor);
04987                 windows->popup.x=windows->widget.x+60;
04988                 windows->popup.y=windows->widget.y+60;
04989                 XListBrowserWidget(display,windows,&windows->popup,
04990                   (const char **) formats,"Select","Select image format type:",
04991                   format);
04992                 XSetCursorState(display,windows,MagickTrue);
04993                 (void) XCheckDefineCursor(display,windows->widget.id,
04994                   windows->widget.cursor);
04995                 LocaleLower(format);
04996                 AppendImageFormat(format,reply_info.text);
04997                 reply_info.cursor=reply_info.text+Extent(reply_info.text);
04998                 XDrawMatteText(display,&windows->widget,&reply_info);
04999                 special_info.raised=MagickTrue;
05000                 XDrawBeveledButton(display,&windows->widget,&special_info);
05001                 for (i=0; i < (ssize_t) number_formats; i++)
05002                   formats[i]=DestroyString(formats[i]);
05003                 formats=(char **) RelinquishMagickMemory(formats);
05004                 break;
05005               }
05006             if (event.xbutton.window == windows->widget.id)
05007               if (MatteIsActive(special_info,event.xbutton))
05008                 {
05009                   (void) CopyMagickString(working_path,"x:",MaxTextExtent);
05010                   state|=ExitState;
05011                 }
05012             special_info.raised=MagickTrue;
05013             XDrawBeveledButton(display,&windows->widget,&special_info);
05014           }
05015         if (action_info.raised == MagickFalse)
05016           {
05017             if (event.xbutton.window == windows->widget.id)
05018               {
05019                 if (MatteIsActive(action_info,event.xbutton))
05020                   {
05021                     if (*reply_info.text == '\0')
05022                       (void) XBell(display,0);
05023                     else
05024                       state|=ExitState;
05025                   }
05026               }
05027             action_info.raised=MagickTrue;
05028             XDrawBeveledButton(display,&windows->widget,&action_info);
05029           }
05030         if (cancel_info.raised == MagickFalse)
05031           {
05032             if (event.xbutton.window == windows->widget.id)
05033               if (MatteIsActive(cancel_info,event.xbutton))
05034                 {
05035                   *reply_info.text='\0';
05036                   *reply='\0';
05037                   state|=ExitState;
05038                 }
05039             cancel_info.raised=MagickTrue;
05040             XDrawBeveledButton(display,&windows->widget,&cancel_info);
05041           }
05042         break;
05043       }
05044       case ClientMessage:
05045       {
05046         /*
05047           If client window delete message, exit.
05048         */
05049         if (event.xclient.message_type != windows->wm_protocols)
05050           break;
05051         if (*event.xclient.data.l == (int) windows->wm_take_focus)
05052           {
05053             (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
05054               (Time) event.xclient.data.l[1]);
05055             break;
05056           }
05057         if (*event.xclient.data.l != (int) windows->wm_delete_window)
05058           break;
05059         if (event.xclient.window == windows->widget.id)
05060           {
05061             *reply_info.text='\0';
05062             state|=ExitState;
05063             break;
05064           }
05065         break;
05066       }
05067       case ConfigureNotify:
05068       {
05069         /*
05070           Update widget configuration.
05071         */
05072         if (event.xconfigure.window != windows->widget.id)
05073           break;
05074         if ((event.xconfigure.width == (int) windows->widget.width) &&
05075             (event.xconfigure.height == (int) windows->widget.height))
05076           break;
05077         windows->widget.width=(unsigned int)
05078           MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
05079         windows->widget.height=(unsigned int)
05080           MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
05081         state|=UpdateConfigurationState;
05082         break;
05083       }
05084       case EnterNotify:
05085       {
05086         if (event.xcrossing.window != windows->widget.id)
05087           break;
05088         state&=(~InactiveWidgetState);
05089         break;
05090       }
05091       case Expose:
05092       {
05093         if (event.xexpose.window != windows->widget.id)
05094           break;
05095         if (event.xexpose.count != 0)
05096           break;
05097         state|=RedrawWidgetState;
05098         break;
05099       }
05100       case KeyPress:
05101       {
05102         static char
05103           command[MaxTextExtent];
05104 
05105         static int
05106           length;
05107 
05108         static KeySym
05109           key_symbol;
05110 
05111         /*
05112           Respond to a user key press.
05113         */
05114         if (event.xkey.window != windows->widget.id)
05115           break;
05116         length=XLookupString((XKeyEvent *) &event.xkey,command,
05117           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
05118         *(command+length)='\0';
05119         if (AreaIsActive(scroll_info,event.xkey))
05120           {
05121             /*
05122               Move slider.
05123             */
05124             switch ((int) key_symbol)
05125             {
05126               case XK_Home:
05127               case XK_KP_Home:
05128               {
05129                 slider_info.id=0;
05130                 break;
05131               }
05132               case XK_Up:
05133               case XK_KP_Up:
05134               {
05135                 slider_info.id--;
05136                 break;
05137               }
05138               case XK_Down:
05139               case XK_KP_Down:
05140               {
05141                 slider_info.id++;
05142                 break;
05143               }
05144               case XK_Prior:
05145               case XK_KP_Prior:
05146               {
05147                 slider_info.id-=visible_files;
05148                 break;
05149               }
05150               case XK_Next:
05151               case XK_KP_Next:
05152               {
05153                 slider_info.id+=visible_files;
05154                 break;
05155               }
05156               case XK_End:
05157               case XK_KP_End:
05158               {
05159                 slider_info.id=(int) files;
05160                 break;
05161               }
05162             }
05163             state|=RedrawListState;
05164             break;
05165           }
05166         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
05167           {
05168             /*
05169               Read new directory or glob patterm.
05170             */
05171             if (*reply_info.text == '\0')
05172               break;
05173             if (IsGlob(reply_info.text))
05174               (void) CopyMagickString(glob_pattern,reply_info.text,
05175                 MaxTextExtent);
05176             else
05177               {
05178                 (void) ConcatenateMagickString(working_path,DirectorySeparator,
05179                   MaxTextExtent);
05180                 (void) ConcatenateMagickString(working_path,reply_info.text,
05181                   MaxTextExtent);
05182                 if (*working_path == '~')
05183                   ExpandFilename(working_path);
05184                 *reply='\0';
05185               }
05186             state|=UpdateListState;
05187             break;
05188           }
05189         if (key_symbol == XK_Control_L)
05190           {
05191             state|=ControlState;
05192             break;
05193           }
05194         if (state & ControlState)
05195           switch ((int) key_symbol)
05196           {
05197             case XK_u:
05198             case XK_U:
05199             {
05200               /*
05201                 Erase the entire line of text.
05202               */
05203               *reply_info.text='\0';
05204               reply_info.cursor=reply_info.text;
05205               reply_info.marker=reply_info.text;
05206               reply_info.highlight=MagickFalse;
05207               break;
05208             }
05209             default:
05210               break;
05211           }
05212         XEditText(display,&reply_info,key_symbol,command,state);
05213         XDrawMatteText(display,&windows->widget,&reply_info);
05214         state|=JumpListState;
05215         break;
05216       }
05217       case KeyRelease:
05218       {
05219         static char
05220           command[MaxTextExtent];
05221 
05222         static KeySym
05223           key_symbol;
05224 
05225         /*
05226           Respond to a user key release.
05227         */
05228         if (event.xkey.window != windows->widget.id)
05229           break;
05230         (void) XLookupString((XKeyEvent *) &event.xkey,command,
05231           (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
05232         if (key_symbol == XK_Control_L)
05233           state&=(~ControlState);
05234         break;
05235       }
05236       case LeaveNotify:
05237       {
05238         if (event.xcrossing.window != windows->widget.id)
05239           break;
05240         state|=InactiveWidgetState;
05241         break;
05242       }
05243       case MapNotify:
05244       {
05245         mask&=(~CWX);
05246         mask&=(~CWY);
05247         break;
05248       }
05249       case MotionNotify:
05250       {
05251         /*
05252           Discard pending button motion events.
05253         */
05254         while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
05255         if (slider_info.active)
05256           {
05257             /*
05258               Move slider matte.
05259             */
05260             slider_info.y=event.xmotion.y-
05261               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
05262             if (slider_info.y < slider_info.min_y)
05263               slider_info.y=slider_info.min_y;
05264             if (slider_info.y > slider_info.max_y)
05265               slider_info.y=slider_info.max_y;
05266             slider_info.id=0;
05267             if (slider_info.y != slider_info.min_y)
05268               slider_info.id=(int) ((files*(slider_info.y-slider_info.min_y+1))/
05269                 (slider_info.max_y-slider_info.min_y+1));
05270             state|=RedrawListState;
05271             break;
05272           }
05273         if (state & InactiveWidgetState)
05274           break;
05275         if (up_info.raised == MatteIsActive(up_info,event.xmotion))
05276           {
05277             /*
05278               Up button status changed.
05279             */
05280             up_info.raised=!up_info.raised;
05281             XDrawBeveledButton(display,&windows->widget,&up_info);
05282             break;
05283           }
05284         if (home_info.raised == MatteIsActive(home_info,event.xmotion))
05285           {
05286             /*
05287               Home button status changed.
05288             */
05289             home_info.raised=!home_info.raised;
05290             XDrawBeveledButton(display,&windows->widget,&home_info);
05291             break;
05292           }
05293         if (special_info.raised == MatteIsActive(special_info,event.xmotion))
05294           {
05295             /*
05296               Grab button status changed.
05297             */
05298             special_info.raised=!special_info.raised;
05299             XDrawBeveledButton(display,&windows->widget,&special_info);
05300             break;
05301           }
05302         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
05303           {
05304             /*
05305               Action button status changed.
05306             */
05307             action_info.raised=action_info.raised == MagickFalse ?
05308               MagickTrue : MagickFalse;
05309             XDrawBeveledButton(display,&windows->widget,&action_info);
05310             break;
05311           }
05312         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
05313           {
05314             /*
05315               Cancel button status changed.
05316             */
05317             cancel_info.raised=cancel_info.raised == MagickFalse ?
05318               MagickTrue : MagickFalse;
05319             XDrawBeveledButton(display,&windows->widget,&cancel_info);
05320             break;
05321           }
05322         break;
05323       }
05324       case SelectionClear:
05325       {
05326         reply_info.highlight=MagickFalse;
05327         XDrawMatteText(display,&windows->widget,&reply_info);
05328         break;
05329       }
05330       case SelectionNotify:
05331       {
05332         Atom
05333           type;
05334 
05335         int
05336           format;
05337 
05338         unsigned char
05339           *data;
05340 
05341         unsigned long
05342           after,
05343           length;
05344 
05345         /*
05346           Obtain response from primary selection.
05347         */
05348         if (event.xselection.property == (Atom) None)
05349           break;
05350         status=XGetWindowProperty(display,event.xselection.requestor,
05351           event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
05352           &format,&length,&after,&data);
05353         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
05354             (length == 0))
05355           break;
05356         if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
05357           (void) XBell(display,0);
05358         else
05359           {
05360             /*
05361               Insert primary selection in reply text.
05362             */
05363             *(data+length)='\0';
05364             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
05365               state);
05366             XDrawMatteText(display,&windows->widget,&reply_info);
05367             state|=JumpListState;
05368             state|=RedrawActionState;
05369           }
05370         (void) XFree((void *) data);
05371         break;
05372       }
05373       case SelectionRequest:
05374       {
05375         XSelectionEvent
05376           notify;
05377 
05378         XSelectionRequestEvent
05379           *request;
05380 
05381         if (reply_info.highlight == MagickFalse)
05382           break;
05383         /*
05384           Set primary selection.
05385         */
05386         request=(&(event.xselectionrequest));
05387         (void) XChangeProperty(request->display,request->requestor,
05388           request->property,request->target,8,PropModeReplace,
05389           (unsigned char *) primary_selection,Extent(primary_selection));
05390         notify.type=SelectionNotify;
05391         notify.display=request->display;
05392         notify.requestor=request->requestor;
05393         notify.selection=request->selection;
05394         notify.target=request->target;
05395         notify.time=request->time;
05396         if (request->property == None)
05397           notify.property=request->target;
05398         else
05399           notify.property=request->property;
05400         (void) XSendEvent(request->display,request->requestor,False,0,
05401           (XEvent *) &notify);
05402       }
05403       default:
05404         break;
05405     }
05406   } while ((state & ExitState) == 0);
05407   XSetCursorState(display,windows,MagickFalse);
05408   (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
05409   XCheckRefreshWindows(display,windows);
05410   /*
05411     Free file list.
05412   */
05413   for (i=0; i < (ssize_t) files; i++)
05414     filelist[i]=DestroyString(filelist[i]);
05415   if (filelist != (char **) NULL)
05416     filelist=(char **) RelinquishMagickMemory(filelist);
05417   if (*reply != '\0')
05418     {
05419       (void) ConcatenateMagickString(working_path,DirectorySeparator,
05420         MaxTextExtent);
05421       (void) ConcatenateMagickString(working_path,reply,MaxTextExtent);
05422     }
05423   (void) CopyMagickString(reply,working_path,MaxTextExtent);
05424   if (*reply == '~')
05425     ExpandFilename(reply);
05426 }
05427 
05428 /*
05429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
05430 %                                                                             %
05431 %                                                                             %
05432 %                                                                             %
05433 %   X F o n t B r o w s e r W i d g e t                                       %
05434 %                                                                             %
05435 %                                                                             %
05436 %                                                                             %
05437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
05438 %
05439 %  XFontBrowserWidget() displays a Font Browser widget with a font query to the
05440 %  user.  The user keys a reply and presses the Action or Cancel button to
05441 %  exit.  The typed text is returned as the reply function parameter.
05442 %
05443 %  The format of the XFontBrowserWidget method is:
05444 %
05445 %      void XFontBrowserWidget(Display *display,XWindows *windows,
05446 %        const char *action,char *reply)
05447 %
05448 %  A description of each parameter follows:
05449 %
05450 %    o display: Specifies a connection to an X server;  returned from
05451 %      XOpenDisplay.
05452 %
05453 %    o window: Specifies a pointer to a XWindows structure.
05454 %
05455 %    o action: Specifies a pointer to the action of this widget.
05456 %
05457 %    o reply: the response from the user is returned in this parameter.
05458 %
05459 %
05460 */
05461 
05462 #if defined(__cplusplus) || defined(c_plusplus)
05463 extern "C" {
05464 #endif
05465 
05466 static int FontCompare(const void *x,const void *y)
05467 {
05468   register char
05469     *p,
05470     *q;
05471 
05472   p=(char *) *((char **) x);
05473   q=(char *) *((char **) y);
05474   while ((*p != '\0') && (*q != '\0') && (*p == *q))
05475   {
05476     p++;
05477     q++;
05478   }
05479   return(*p-(*q));
05480 }
05481 
05482 #if defined(__cplusplus) || defined(c_plusplus)
05483 }
05484 #endif
05485 
05486 MagickPrivate void XFontBrowserWidget(Display *display,XWindows *windows,
05487   const char *action,char *reply)
05488 {
05489 #define BackButtonText  "Back"
05490 #define CancelButtonText  "Cancel"
05491 #define FontnameText  "Name:"
05492 #define FontPatternText  "Pattern:"
05493 #define ResetButtonText  "Reset"
05494 
05495   char
05496     back_pattern[MaxTextExtent],
05497     **fontlist,
05498     **listhead,
05499     primary_selection[MaxTextExtent],
05500     reset_pattern[MaxTextExtent],
05501     text[MaxTextExtent];
05502 
05503   int
05504     fonts,
05505     x,
05506     y;
05507 
05508   register int
05509     i;
05510 
05511   static char
05512     glob_pattern[MaxTextExtent] = "*";
05513 
05514   static MagickStatusType
05515     mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
05516 
05517   Status
05518     status;
05519 
05520   unsigned int
05521     height,
05522     text_width,
05523     visible_fonts,
05524     width;
05525 
05526   size_t
05527     delay,
05528     state;
05529 
05530   XEvent
05531     event;
05532 
05533   XFontStruct
05534     *font_info;
05535 
05536   XTextProperty
05537     window_name;
05538 
05539   XWidgetInfo
05540     action_info,
05541     back_info,
05542     cancel_info,
05543     expose_info,
05544     list_info,
05545     mode_info,
05546     north_info,
05547     reply_info,
05548     reset_info,
05549     scroll_info,
05550     selection_info,
05551     slider_info,
05552     south_info,
05553     text_info;
05554 
05555   XWindowChanges
05556     window_changes;
05557 
05558   /*
05559     Get font list and sort in ascending order.
05560   */
05561   assert(display != (Display *) NULL);
05562   assert(windows != (XWindows *) NULL);
05563   assert(action != (char *) NULL);
05564   assert(reply != (char *) NULL);
05565   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
05566   XSetCursorState(display,windows,MagickTrue);
05567   XCheckRefreshWindows(display,windows);
05568   (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
05569   (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
05570   fontlist=XListFonts(display,glob_pattern,32767,&fonts);
05571   if (fonts == 0)
05572     {
05573       /*
05574         Pattern failed, obtain all the fonts.
05575       */
05576       XNoticeWidget(display,windows,"Unable to obtain fonts names:",
05577         glob_pattern);
05578       (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
05579       fontlist=XListFonts(display,glob_pattern,32767,&fonts);
05580       if (fontlist == (char **) NULL)
05581         {
05582           XNoticeWidget(display,windows,"Unable to obtain fonts names:",
05583             glob_pattern);
05584           return;
05585         }
05586     }
05587   /*
05588     Sort font list in ascending order.
05589   */
05590   listhead=fontlist;
05591   fontlist=(char **) AcquireQuantumMemory((size_t) fonts,sizeof(*fontlist));
05592   if (fontlist == (char **) NULL)
05593     {
05594       XNoticeWidget(display,windows,"MemoryAllocationFailed",
05595         "UnableToViewFonts");
05596       return;
05597     }
05598   for (i=0; i < fonts; i++)
05599     fontlist[i]=listhead[i];
05600   qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
05601   /*
05602     Determine Font Browser widget attributes.
05603   */
05604   font_info=windows->widget.font_info;
05605   text_width=0;
05606   for (i=0; i < fonts; i++)
05607     if (WidgetTextWidth(font_info,fontlist[i]) > text_width)
05608       text_width=WidgetTextWidth(font_info,fontlist[i]);
05609   width=WidgetTextWidth(font_info,(char *) action);
05610   if (WidgetTextWidth(font_info,CancelButtonText) > width)
05611     width=WidgetTextWidth(font_info,CancelButtonText);
05612   if (WidgetTextWidth(font_info,ResetButtonText) > width)
05613     width=WidgetTextWidth(font_info,ResetButtonText);
05614   if (WidgetTextWidth(font_info,BackButtonText) > width)
05615     width=WidgetTextWidth(font_info,BackButtonText);
05616   width+=QuantumMargin;
05617   if (WidgetTextWidth(font_info,FontPatternText) > width)
05618     width=WidgetTextWidth(font_info,FontPatternText);
05619   if (WidgetTextWidth(font_info,FontnameText) > width)
05620     width=WidgetTextWidth(font_info,FontnameText);
05621   height=(unsigned int) (font_info->ascent+font_info->descent);
05622   /*
05623     Position Font Browser widget.
05624   */
05625   windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
05626     6*QuantumMargin;
05627   windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
05628   if (windows->widget.width < windows->widget.min_width)
05629     windows->widget.width=windows->widget.min_width;
05630   windows->widget.height=(unsigned int)
05631     (((85*height) >> 2)+((13*QuantumMargin) >> 1)+4);
05632   windows->widget.min_height=(unsigned int)
05633     (((27*height) >> 1)+((13*QuantumMargin) >> 1)+4);
05634   if (windows->widget.height < windows->widget.min_height)
05635     windows->widget.height=windows->widget.min_height;
05636   XConstrainWindowPosition(display,&windows->widget);
05637   /*
05638     Map Font Browser widget.
05639   */
05640   (void) CopyMagickString(windows->widget.name,"Browse and Select a Font",
05641     MaxTextExtent);
05642   status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
05643   if (status != False)
05644     {
05645       XSetWMName(display,windows->widget.id,&window_name);
05646       XSetWMIconName(display,windows->widget.id,&window_name);
05647       (void) XFree((void *) window_name.value);
05648     }
05649   window_changes.width=(int) windows->widget.width;
05650   window_changes.height=(int) windows->widget.height;
05651   window_changes.x=windows->widget.x;
05652   window_changes.y=windows->widget.y;
05653   (void) XReconfigureWMWindow(display,windows->widget.id,
05654     windows->widget.screen,mask,&window_changes);
05655   (void) XMapRaised(display,windows->widget.id);
05656   windows->widget.mapped=MagickFalse;
05657   /*
05658     Respond to X events.
05659   */
05660   XGetWidgetInfo((char *) NULL,&slider_info);
05661   XGetWidgetInfo((char *) NULL,&north_info);
05662   XGetWidgetInfo((char *) NULL,&south_info);
05663   XGetWidgetInfo((char *) NULL,&expose_info);
05664   visible_fonts=0;
05665   delay=SuspendTime << 2;
05666   state=UpdateConfigurationState;
05667   do
05668   {
05669     if (state & UpdateConfigurationState)
05670       {
05671         int
05672           id;
05673 
05674         /*
05675           Initialize button information.
05676         */
05677         XGetWidgetInfo(CancelButtonText,&cancel_info);
05678         cancel_info.width=width;
05679         cancel_info.height=(unsigned int) ((3*height) >> 1);
05680         cancel_info.x=(int)
05681           (windows->widget.width-cancel_info.width-QuantumMargin-2);
05682         cancel_info.y=(int)
05683           (windows->widget.height-cancel_info.height-QuantumMargin);
05684         XGetWidgetInfo(action,&action_info);
05685         action_info.width=width;
05686         action_info.height=(unsigned int) ((3*height) >> 1);
05687         action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
05688           (action_info.bevel_width << 1));
05689         action_info.y=cancel_info.y;
05690         XGetWidgetInfo(BackButtonText,&back_info);
05691         back_info.width=width;
05692         back_info.height=(unsigned int) ((3*height) >> 1);
05693         back_info.x=QuantumMargin;
05694         back_info.y=((5*QuantumMargin) >> 1)+height;
05695         XGetWidgetInfo(ResetButtonText,&reset_info);
05696         reset_info.width=width;
05697         reset_info.height=(unsigned int) ((3*height) >> 1);
05698         reset_info.x=QuantumMargin;
05699         reset_info.y=back_info.y+back_info.height+QuantumMargin;
05700         /*
05701           Initialize reply information.
05702         */
05703         XGetWidgetInfo(reply,&reply_info);
05704         reply_info.raised=MagickFalse;
05705         reply_info.bevel_width--;
05706         reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
05707         reply_info.height=height << 1;
05708         reply_info.x=(int) (width+(QuantumMargin << 1));
05709         reply_info.y=action_info.y-(action_info.height << 1)-QuantumMargin;
05710         /*
05711           Initialize mode information.
05712         */
05713         XGetWidgetInfo(reply,&mode_info);
05714         mode_info.bevel_width=0;
05715         mode_info.width=(unsigned int)
05716           (action_info.x-reply_info.x-QuantumMargin);
05717         mode_info.height=action_info.height << 1;
05718         mode_info.x=reply_info.x;
05719         mode_info.y=action_info.y-action_info.height+action_info.bevel_width;
05720         /*
05721           Initialize scroll information.
05722         */
05723         XGetWidgetInfo((char *) NULL,&scroll_info);
05724         scroll_info.bevel_width--;
05725         scroll_info.width=height;
05726         scroll_info.height=(unsigned int)
05727           (reply_info.y-back_info.y-(QuantumMargin >> 1));
05728         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
05729         scroll_info.y=back_info.y-reply_info.bevel_width;
05730         scroll_info.raised=MagickFalse;
05731         scroll_info.trough=MagickTrue;
05732         north_info=scroll_info;
05733         north_info.raised=MagickTrue;
05734         north_info.width-=(north_info.bevel_width << 1);
05735         north_info.height=north_info.width-1;
05736         north_info.x+=north_info.bevel_width;
05737         north_info.y+=north_info.bevel_width;
05738         south_info=north_info;
05739         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
05740           south_info.height;
05741         id=slider_info.id;
05742         slider_info=north_info;
05743         slider_info.id=id;
05744         slider_info.width-=2;
05745         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
05746           slider_info.bevel_width+2;
05747         slider_info.height=scroll_info.height-((slider_info.min_y-
05748           scroll_info.y+1) << 1)+4;
05749         visible_fonts=scroll_info.height/(height+(height >> 3));
05750         if (fonts > (int) visible_fonts)
05751           slider_info.height=(visible_fonts*slider_info.height)/fonts;
05752         slider_info.max_y=south_info.y-south_info.bevel_width-
05753           slider_info.bevel_width-2;
05754         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
05755         slider_info.y=slider_info.min_y;
05756         expose_info=scroll_info;
05757         expose_info.y=slider_info.y;
05758         /*
05759           Initialize list information.
05760         */
05761         XGetWidgetInfo((char *) NULL,&list_info);
05762         list_info.raised=MagickFalse;
05763         list_info.bevel_width--;
05764         list_info.width=(unsigned int)
05765           (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
05766         list_info.height=scroll_info.height;
05767         list_info.x=reply_info.x;
05768         list_info.y=scroll_info.y;
05769         if (windows->widget.mapped == MagickFalse)
05770           state|=JumpListState;
05771         /*
05772