/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % % % W W IIIII DDDD GGGG EEEEE TTTTT % % W W I D D G E T % % W W W I D D G GG EEE T % % WW WW I D D G G E T % % W W IIIII DDDD GGGG EEEEE T % % % % % % MagickCore X11 User Interface Methods % % % % Software Design % % Cristy % % September 1993 % % % % % % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % % obtain a copy of the License at % % % % https://imagemagick.org/script/license.php % % % % Unless required by applicable law or agreed to in writing, software % % distributed under the License is distributed on an "AS IS" BASIS, % % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % % See the License for the specific language governing permissions and % % limitations under the License. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % */ /* Include declarations. */ #include "MagickCore/studio.h" #include "MagickCore/color.h" #include "MagickCore/color-private.h" #include "MagickCore/exception.h" #include "MagickCore/exception-private.h" #include "MagickCore/image.h" #include "MagickCore/magick.h" #include "MagickCore/memory_.h" #include "MagickCore/string_.h" #include "MagickCore/token.h" #include "MagickCore/token-private.h" #include "MagickCore/utility.h" #include "MagickCore/utility-private.h" #include "MagickCore/xwindow-private.h" #include "MagickCore/widget.h" #include "MagickCore/widget-private.h" #if defined(MAGICKCORE_X11_DELEGATE) /* Define declarations. */ #define AreaIsActive(matte_info,position) ( \ ((position.y >= (int) (matte_info.y-matte_info.bevel_width)) && \ (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \ ? MagickTrue : MagickFalse) #define Extent(s) ((int) strlen(s)) #define MatteIsActive(matte_info,position) ( \ ((position.x >= (int) (matte_info.x-matte_info.bevel_width)) && \ (position.y >= (int) (matte_info.y-matte_info.bevel_width)) && \ (position.x < (int) (matte_info.x+matte_info.width+matte_info.bevel_width)) && \ (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \ ? MagickTrue : MagickFalse) #define MaxTextWidth ((unsigned int) (255*XTextWidth(font_info,"_",1))) #define MinTextWidth (26*XTextWidth(font_info,"_",1)) #define QuantumMargin MagickMax(font_info->max_bounds.width,12) #define WidgetTextWidth(font_info,text) \ ((unsigned int) XTextWidth(font_info,text,Extent(text))) #define WindowIsActive(window_info,position) ( \ ((position.x >= 0) && (position.y >= 0) && \ (position.x < (int) window_info.width) && \ (position.y < (int) window_info.height)) ? MagickTrue : MagickFalse) /* Enum declarations. */ typedef enum { ControlState = 0x0001, InactiveWidgetState = 0x0004, JumpListState = 0x0008, RedrawActionState = 0x0010, RedrawListState = 0x0020, RedrawWidgetState = 0x0040, UpdateListState = 0x0100 } WidgetState; /* Typedef declarations. */ typedef struct _XWidgetInfo { char *cursor, *text, *marker; int id; unsigned int bevel_width, width, height; int x, y, min_y, max_y; MagickStatusType raised, active, center, trough, highlight; } XWidgetInfo; /* Variable declarations. */ static XWidgetInfo monitor_info = { (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0, MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse }, submenu_info = { (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0, MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse }, *selection_info = (XWidgetInfo *) NULL, toggle_info = { (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0, MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse }; /* Constant declarations. */ static const int BorderOffset = 4, DoubleClick = 250; /* Method prototypes. */ static void XDrawMatte(Display *,const XWindowInfo *,const XWidgetInfo *), XSetBevelColor(Display *,const XWindowInfo *,const MagickStatusType), XSetMatteColor(Display *,const XWindowInfo *,const MagickStatusType), XSetTextColor(Display *,const XWindowInfo *,const MagickStatusType); /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % D e s t r o y X W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % DestroyXWidget() destroys resources associated with the X widget. % % The format of the DestroyXWidget method is: % % void DestroyXWidget() % % A description of each parameter follows: % */ MagickPrivate void DestroyXWidget(void) { if (selection_info != (XWidgetInfo *) NULL) selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X D r a w B e v e l % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDrawBevel() "sets off" an area with a highlighted upper and left bevel and % a shadowed lower and right bevel. The highlighted and shadowed bevels % create a 3-D effect. % % The format of the XDrawBevel function is: % % XDrawBevel(display,window_info,bevel_info) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o bevel_info: Specifies a pointer to a XWidgetInfo structure. It % contains the extents of the bevel. % */ static void XDrawBevel(Display *display,const XWindowInfo *window_info, const XWidgetInfo *bevel_info) { int x1, x2, y1, y2; unsigned int bevel_width; XPoint points[6]; /* Draw upper and left beveled border. */ x1=bevel_info->x; y1=bevel_info->y+bevel_info->height; x2=bevel_info->x+bevel_info->width; y2=bevel_info->y; bevel_width=bevel_info->bevel_width; points[0].x=x1; points[0].y=y1; points[1].x=x1; points[1].y=y2; points[2].x=x2; points[2].y=y2; points[3].x=x2+bevel_width; points[3].y=y2-bevel_width; points[4].x=x1-bevel_width; points[4].y=y2-bevel_width; points[5].x=x1-bevel_width; points[5].y=y1+bevel_width; XSetBevelColor(display,window_info,bevel_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,6,Complex,CoordModeOrigin); /* Draw lower and right beveled border. */ points[0].x=x1; points[0].y=y1; points[1].x=x2; points[1].y=y1; points[2].x=x2; points[2].y=y2; points[3].x=x2+bevel_width; points[3].y=y2-bevel_width; points[4].x=x2+bevel_width; points[4].y=y1+bevel_width; points[5].x=x1-bevel_width; points[5].y=y1+bevel_width; XSetBevelColor(display,window_info,!bevel_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,6,Complex,CoordModeOrigin); (void) XSetFillStyle(display,window_info->widget_context,FillSolid); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X D r a w B e v e l e d B u t t o n % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDrawBeveledButton() draws a button with a highlighted upper and left bevel % and a shadowed lower and right bevel. The highlighted and shadowed bevels % create a 3-D effect. % % The format of the XDrawBeveledButton function is: % % XDrawBeveledButton(display,window_info,button_info) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o button_info: Specifies a pointer to a XWidgetInfo structure. It % contains the extents of the button. % */ static void XDrawBeveledButton(Display *display,const XWindowInfo *window_info, const XWidgetInfo *button_info) { int x, y; unsigned int width; XFontStruct *font_info; XRectangle crop_info; /* Draw matte. */ XDrawBevel(display,window_info,button_info); XSetMatteColor(display,window_info,button_info->raised); (void) XFillRectangle(display,window_info->id,window_info->widget_context, button_info->x,button_info->y,button_info->width,button_info->height); x=button_info->x-button_info->bevel_width-1; y=button_info->y-button_info->bevel_width-1; (void) XSetForeground(display,window_info->widget_context, window_info->pixel_info->trough_color.pixel); if (button_info->raised || (window_info->depth == 1)) (void) XDrawRectangle(display,window_info->id,window_info->widget_context, x,y,button_info->width+(button_info->bevel_width << 1)+1, button_info->height+(button_info->bevel_width << 1)+1); if (button_info->text == (char *) NULL) return; /* Set cropping region. */ crop_info.width=(unsigned short) button_info->width; crop_info.height=(unsigned short) button_info->height; crop_info.x=button_info->x; crop_info.y=button_info->y; /* Draw text. */ font_info=window_info->font_info; width=WidgetTextWidth(font_info,button_info->text); x=button_info->x+(QuantumMargin >> 1); if (button_info->center) x=button_info->x+(button_info->width >> 1)-(width >> 1); y=button_info->y+((button_info->height- (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent; if ((int) button_info->width == (QuantumMargin >> 1)) { /* Option button-- write label to right of button. */ XSetTextColor(display,window_info,MagickTrue); x=button_info->x+button_info->width+button_info->bevel_width+ (QuantumMargin >> 1); (void) XDrawString(display,window_info->id,window_info->widget_context, x,y,button_info->text,Extent(button_info->text)); return; } (void) XSetClipRectangles(display,window_info->widget_context,0,0,&crop_info, 1,Unsorted); XSetTextColor(display,window_info,button_info->raised); (void) XDrawString(display,window_info->id,window_info->widget_context,x,y, button_info->text,Extent(button_info->text)); (void) XSetClipMask(display,window_info->widget_context,None); if (button_info->raised == MagickFalse) XDelay(display,SuspendTime << 2); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X D r a w B e v e l e d M a t t e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDrawBeveledMatte() draws a matte with a shadowed upper and left bevel and % a highlighted lower and right bevel. The highlighted and shadowed bevels % create a 3-D effect. % % The format of the XDrawBeveledMatte function is: % % XDrawBeveledMatte(display,window_info,matte_info) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o matte_info: Specifies a pointer to a XWidgetInfo structure. It % contains the extents of the matte. % */ static void XDrawBeveledMatte(Display *display,const XWindowInfo *window_info, const XWidgetInfo *matte_info) { /* Draw matte. */ XDrawBevel(display,window_info,matte_info); XDrawMatte(display,window_info,matte_info); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X D r a w M a t t e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDrawMatte() fills a rectangular area with the matte color. % % The format of the XDrawMatte function is: % % XDrawMatte(display,window_info,matte_info) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o matte_info: Specifies a pointer to a XWidgetInfo structure. It % contains the extents of the matte. % */ static void XDrawMatte(Display *display,const XWindowInfo *window_info, const XWidgetInfo *matte_info) { /* Draw matte. */ if ((matte_info->trough == MagickFalse) || (window_info->depth == 1)) (void) XFillRectangle(display,window_info->id, window_info->highlight_context,matte_info->x,matte_info->y, matte_info->width,matte_info->height); else { (void) XSetForeground(display,window_info->widget_context, window_info->pixel_info->trough_color.pixel); (void) XFillRectangle(display,window_info->id,window_info->widget_context, matte_info->x,matte_info->y,matte_info->width,matte_info->height); } } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X D r a w M a t t e T e x t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDrawMatteText() draws a matte with text. If the text exceeds the extents % of the text, a portion of the text relative to the cursor is displayed. % % The format of the XDrawMatteText function is: % % XDrawMatteText(display,window_info,text_info) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o text_info: Specifies a pointer to a XWidgetInfo structure. It % contains the extents of the text. % */ static void XDrawMatteText(Display *display,const XWindowInfo *window_info, XWidgetInfo *text_info) { const char *text; int n, x, y; register int i; unsigned int height, width; XFontStruct *font_info; XRectangle crop_info; /* Clear the text area. */ XSetMatteColor(display,window_info,MagickFalse); (void) XFillRectangle(display,window_info->id,window_info->widget_context, text_info->x,text_info->y,text_info->width,text_info->height); if (text_info->text == (char *) NULL) return; XSetTextColor(display,window_info,text_info->highlight); font_info=window_info->font_info; x=text_info->x+(QuantumMargin >> 2); y=text_info->y+font_info->ascent+(text_info->height >> 2); width=text_info->width-(QuantumMargin >> 1); height=(unsigned int) (font_info->ascent+font_info->descent); if (*text_info->text == '\0') { /* No text-- just draw cursor. */ (void) XDrawLine(display,window_info->id,window_info->annotate_context, x,y+3,x,y-height+3); return; } /* Set cropping region. */ crop_info.width=(unsigned short) text_info->width; crop_info.height=(unsigned short) text_info->height; crop_info.x=text_info->x; crop_info.y=text_info->y; /* Determine beginning of the visible text. */ if (text_info->cursor < text_info->marker) text_info->marker=text_info->cursor; else { text=text_info->marker; if (XTextWidth(font_info,(char *) text,(int) (text_info->cursor-text)) > (int) width) { text=text_info->text; for (i=0; i < Extent(text); i++) { n=XTextWidth(font_info,(char *) text+i,(int) (text_info->cursor-text-i)); if (n <= (int) width) break; } text_info->marker=(char *) text+i; } } /* Draw text and cursor. */ if (text_info->highlight == MagickFalse) { (void) XSetClipRectangles(display,window_info->widget_context,0,0, &crop_info,1,Unsorted); (void) XDrawString(display,window_info->id,window_info->widget_context, x,y,text_info->marker,Extent(text_info->marker)); (void) XSetClipMask(display,window_info->widget_context,None); } else { (void) XSetClipRectangles(display,window_info->annotate_context,0,0, &crop_info,1,Unsorted); width=WidgetTextWidth(font_info,text_info->marker); (void) XFillRectangle(display,window_info->id, window_info->annotate_context,x,y-font_info->ascent,width,height); (void) XSetClipMask(display,window_info->annotate_context,None); (void) XSetClipRectangles(display,window_info->highlight_context,0,0, &crop_info,1,Unsorted); (void) XDrawString(display,window_info->id, window_info->highlight_context,x,y,text_info->marker, Extent(text_info->marker)); (void) XSetClipMask(display,window_info->highlight_context,None); } x+=XTextWidth(font_info,text_info->marker,(int) (text_info->cursor-text_info->marker)); (void) XDrawLine(display,window_info->id,window_info->annotate_context,x,y+3, x,y-height+3); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X D r a w T r i a n g l e E a s t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDrawTriangleEast() draws a triangle with a highlighted left bevel and a % shadowed right and lower bevel. The highlighted and shadowed bevels create % a 3-D effect. % % The format of the XDrawTriangleEast function is: % % XDrawTriangleEast(display,window_info,triangle_info) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o triangle_info: Specifies a pointer to a XWidgetInfo structure. It % contains the extents of the triangle. % */ static void XDrawTriangleEast(Display *display,const XWindowInfo *window_info, const XWidgetInfo *triangle_info) { int x1, x2, x3, y1, y2, y3; unsigned int bevel_width; XFontStruct *font_info; XPoint points[4]; /* Draw triangle matte. */ x1=triangle_info->x; y1=triangle_info->y; x2=triangle_info->x+triangle_info->width; y2=triangle_info->y+(triangle_info->height >> 1); x3=triangle_info->x; y3=triangle_info->y+triangle_info->height; bevel_width=triangle_info->bevel_width; points[0].x=x1; points[0].y=y1; points[1].x=x2; points[1].y=y2; points[2].x=x3; points[2].y=y3; XSetMatteColor(display,window_info,triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,3,Complex,CoordModeOrigin); /* Draw bottom bevel. */ points[0].x=x2; points[0].y=y2; points[1].x=x3; points[1].y=y3; points[2].x=x3-bevel_width; points[2].y=y3+bevel_width; points[3].x=x2+bevel_width; points[3].y=y2; XSetBevelColor(display,window_info,!triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,4,Complex,CoordModeOrigin); /* Draw Left bevel. */ points[0].x=x3; points[0].y=y3; points[1].x=x1; points[1].y=y1; points[2].x=x1-bevel_width+1; points[2].y=y1-bevel_width; points[3].x=x3-bevel_width+1; points[3].y=y3+bevel_width; XSetBevelColor(display,window_info,triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,4,Complex,CoordModeOrigin); /* Draw top bevel. */ points[0].x=x1; points[0].y=y1; points[1].x=x2; points[1].y=y2; points[2].x=x2+bevel_width; points[2].y=y2; points[3].x=x1-bevel_width; points[3].y=y1-bevel_width; (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,4,Complex,CoordModeOrigin); (void) XSetFillStyle(display,window_info->widget_context,FillSolid); if (triangle_info->text == (char *) NULL) return; /* Write label to right of triangle. */ font_info=window_info->font_info; XSetTextColor(display,window_info,MagickTrue); x1=triangle_info->x+triangle_info->width+triangle_info->bevel_width+ (QuantumMargin >> 1); y1=triangle_info->y+((triangle_info->height- (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent; (void) XDrawString(display,window_info->id,window_info->widget_context,x1,y1, triangle_info->text,Extent(triangle_info->text)); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X D r a w T r i a n g l e N o r t h % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDrawTriangleNorth() draws a triangle with a highlighted left bevel and a % shadowed right and lower bevel. The highlighted and shadowed bevels create % a 3-D effect. % % The format of the XDrawTriangleNorth function is: % % XDrawTriangleNorth(display,window_info,triangle_info) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o triangle_info: Specifies a pointer to a XWidgetInfo structure. It % contains the extents of the triangle. % */ static void XDrawTriangleNorth(Display *display,const XWindowInfo *window_info, const XWidgetInfo *triangle_info) { int x1, x2, x3, y1, y2, y3; unsigned int bevel_width; XPoint points[4]; /* Draw triangle matte. */ x1=triangle_info->x; y1=triangle_info->y+triangle_info->height; x2=triangle_info->x+(triangle_info->width >> 1); y2=triangle_info->y; x3=triangle_info->x+triangle_info->width; y3=triangle_info->y+triangle_info->height; bevel_width=triangle_info->bevel_width; points[0].x=x1; points[0].y=y1; points[1].x=x2; points[1].y=y2; points[2].x=x3; points[2].y=y3; XSetMatteColor(display,window_info,triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,3,Complex,CoordModeOrigin); /* Draw left bevel. */ points[0].x=x1; points[0].y=y1; points[1].x=x2; points[1].y=y2; points[2].x=x2; points[2].y=y2-bevel_width-2; points[3].x=x1-bevel_width-1; points[3].y=y1+bevel_width; XSetBevelColor(display,window_info,triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,4,Complex,CoordModeOrigin); /* Draw right bevel. */ points[0].x=x2; points[0].y=y2; points[1].x=x3; points[1].y=y3; points[2].x=x3+bevel_width; points[2].y=y3+bevel_width; points[3].x=x2; points[3].y=y2-bevel_width; XSetBevelColor(display,window_info,!triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,4,Complex,CoordModeOrigin); /* Draw lower bevel. */ points[0].x=x3; points[0].y=y3; points[1].x=x1; points[1].y=y1; points[2].x=x1-bevel_width; points[2].y=y1+bevel_width; points[3].x=x3+bevel_width; points[3].y=y3+bevel_width; (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,4,Complex,CoordModeOrigin); (void) XSetFillStyle(display,window_info->widget_context,FillSolid); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X D r a w T r i a n g l e S o u t h % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDrawTriangleSouth() draws a border with a highlighted left and right bevel % and a shadowed lower bevel. The highlighted and shadowed bevels create a % 3-D effect. % % The format of the XDrawTriangleSouth function is: % % XDrawTriangleSouth(display,window_info,triangle_info) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o triangle_info: Specifies a pointer to a XWidgetInfo structure. It % contains the extents of the triangle. % */ static void XDrawTriangleSouth(Display *display,const XWindowInfo *window_info, const XWidgetInfo *triangle_info) { int x1, x2, x3, y1, y2, y3; unsigned int bevel_width; XPoint points[4]; /* Draw triangle matte. */ x1=triangle_info->x; y1=triangle_info->y; x2=triangle_info->x+(triangle_info->width >> 1); y2=triangle_info->y+triangle_info->height; x3=triangle_info->x+triangle_info->width; y3=triangle_info->y; bevel_width=triangle_info->bevel_width; points[0].x=x1; points[0].y=y1; points[1].x=x2; points[1].y=y2; points[2].x=x3; points[2].y=y3; XSetMatteColor(display,window_info,triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,3,Complex,CoordModeOrigin); /* Draw top bevel. */ points[0].x=x3; points[0].y=y3; points[1].x=x1; points[1].y=y1; points[2].x=x1-bevel_width; points[2].y=y1-bevel_width; points[3].x=x3+bevel_width; points[3].y=y3-bevel_width; XSetBevelColor(display,window_info,triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,4,Complex,CoordModeOrigin); /* Draw right bevel. */ points[0].x=x2; points[0].y=y2; points[1].x=x3+1; points[1].y=y3-bevel_width; points[2].x=x3+bevel_width; points[2].y=y3-bevel_width; points[3].x=x2; points[3].y=y2+bevel_width; XSetBevelColor(display,window_info,!triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,4,Complex,CoordModeOrigin); /* Draw left bevel. */ points[0].x=x1; points[0].y=y1; points[1].x=x2; points[1].y=y2; points[2].x=x2; points[2].y=y2+bevel_width; points[3].x=x1-bevel_width; points[3].y=y1-bevel_width; XSetBevelColor(display,window_info,triangle_info->raised); (void) XFillPolygon(display,window_info->id,window_info->widget_context, points,4,Complex,CoordModeOrigin); (void) XSetFillStyle(display,window_info->widget_context,FillSolid); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X D r a w W i d g e t T e x t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDrawWidgetText() first clears the widget and draws a text string justifed % left (or center) in the x-direction and centered within the y-direction. % % The format of the XDrawWidgetText function is: % % XDrawWidgetText(display,window_info,text_info) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a XWindowText structure. % % o text_info: Specifies a pointer to XWidgetInfo structure. % */ static void XDrawWidgetText(Display *display,const XWindowInfo *window_info, XWidgetInfo *text_info) { GC widget_context; int x, y; unsigned int height, width; XFontStruct *font_info; XRectangle crop_info; /* Clear the text area. */ widget_context=window_info->annotate_context; if (text_info->raised) (void) XClearArea(display,window_info->id,text_info->x,text_info->y, text_info->width,text_info->height,MagickFalse); else { (void) XFillRectangle(display,window_info->id,widget_context,text_info->x, text_info->y,text_info->width,text_info->height); widget_context=window_info->highlight_context; } if (text_info->text == (char *) NULL) return; if (*text_info->text == '\0') return; /* Set cropping region. */ font_info=window_info->font_info; crop_info.width=(unsigned short) text_info->width; crop_info.height=(unsigned short) text_info->height; crop_info.x=text_info->x; crop_info.y=text_info->y; /* Draw text. */ width=WidgetTextWidth(font_info,text_info->text); x=text_info->x+(QuantumMargin >> 1); if (text_info->center) x=text_info->x+(text_info->width >> 1)-(width >> 1); if (text_info->raised) if (width > (text_info->width-QuantumMargin)) x+=(text_info->width-QuantumMargin-width); height=(unsigned int) (font_info->ascent+font_info->descent); y=text_info->y+((text_info->height-height) >> 1)+font_info->ascent; (void) XSetClipRectangles(display,widget_context,0,0,&crop_info,1,Unsorted); (void) XDrawString(display,window_info->id,widget_context,x,y,text_info->text, Extent(text_info->text)); (void) XSetClipMask(display,widget_context,None); if (x < text_info->x) (void) XDrawLine(display,window_info->id,window_info->annotate_context, text_info->x,text_info->y,text_info->x,text_info->y+text_info->height-1); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X E d i t T e x t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XEditText() edits a text string as indicated by the key symbol. % % The format of the XEditText function is: % % XEditText(display,text_info,key_symbol,text,state) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o text_info: Specifies a pointer to a XWidgetInfo structure. It % contains the extents of the text. % % o key_symbol: A X11 KeySym that indicates what editing function to % perform to the text. % % o text: A character string to insert into the text. % % o state: An size_t that indicates whether the key symbol is a % control character or not. % */ static void XEditText(Display *display,XWidgetInfo *text_info, const KeySym key_symbol,char *text,const size_t state) { switch ((int) key_symbol) { case XK_BackSpace: case XK_Delete: { if (text_info->highlight) { /* Erase the entire line of text. */ *text_info->text='\0'; text_info->cursor=text_info->text; text_info->marker=text_info->text; text_info->highlight=MagickFalse; } /* Erase one character. */ if (text_info->cursor != text_info->text) { text_info->cursor--; (void) memmove(text_info->cursor,text_info->cursor+1, MagickPathExtent); text_info->highlight=MagickFalse; break; } } case XK_Left: case XK_KP_Left: { /* Move cursor one position left. */ if (text_info->cursor == text_info->text) break; text_info->cursor--; break; } case XK_Right: case XK_KP_Right: { /* Move cursor one position right. */ if (text_info->cursor == (text_info->text+Extent(text_info->text))) break; text_info->cursor++; break; } default: { register char *p, *q; register int i; if (state & ControlState) break; if (*text == '\0') break; if ((Extent(text_info->text)+1) >= (int) MagickPathExtent) (void) XBell(display,0); else { if (text_info->highlight) { /* Erase the entire line of text. */ *text_info->text='\0'; text_info->cursor=text_info->text; text_info->marker=text_info->text; text_info->highlight=MagickFalse; } /* Insert a string into the text. */ q=text_info->text+Extent(text_info->text)+strlen(text); for (i=0; i <= Extent(text_info->cursor); i++) { *q=(*(q-Extent(text))); q--; } p=text; for (i=0; i < Extent(text); i++) *text_info->cursor++=(*p++); } break; } } } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X G e t W i d g e t I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XGetWidgetInfo() initializes the XWidgetInfo structure. % % The format of the XGetWidgetInfo function is: % % XGetWidgetInfo(text,widget_info) % % A description of each parameter follows: % % o text: A string of characters associated with the widget. % % o widget_info: Specifies a pointer to a X11 XWidgetInfo structure. % */ static void XGetWidgetInfo(const char *text,XWidgetInfo *widget_info) { /* Initialize widget info. */ widget_info->id=(~0); widget_info->bevel_width=3; widget_info->width=1; widget_info->height=1; widget_info->x=0; widget_info->y=0; widget_info->min_y=0; widget_info->max_y=0; widget_info->raised=MagickTrue; widget_info->active=MagickFalse; widget_info->center=MagickTrue; widget_info->trough=MagickFalse; widget_info->highlight=MagickFalse; widget_info->text=(char *) text; widget_info->cursor=(char *) text; if (text != (char *) NULL) widget_info->cursor+=Extent(text); widget_info->marker=(char *) text; } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X H i g h l i g h t W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XHighlightWidget() draws a highlighted border around a window. % % The format of the XHighlightWidget function is: % % XHighlightWidget(display,window_info,x,y) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o x: Specifies an integer representing the rectangle offset in the % x-direction. % % o y: Specifies an integer representing the rectangle offset in the % y-direction. % */ static void XHighlightWidget(Display *display,const XWindowInfo *window_info, const int x,const int y) { /* Draw the widget highlighting rectangle. */ XSetBevelColor(display,window_info,MagickTrue); (void) XDrawRectangle(display,window_info->id,window_info->widget_context,x,y, window_info->width-(x << 1),window_info->height-(y << 1)); (void) XDrawRectangle(display,window_info->id,window_info->widget_context, x-1,y-1,window_info->width-(x << 1)+1,window_info->height-(y << 1)+1); XSetBevelColor(display,window_info,MagickFalse); (void) XDrawRectangle(display,window_info->id,window_info->widget_context, x-1,y-1,window_info->width-(x << 1),window_info->height-(y << 1)); (void) XSetFillStyle(display,window_info->widget_context,FillSolid); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X S c r e e n E v e n t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XScreenEvent() returns MagickTrue if the any event on the X server queue is % associated with the widget window. % % The format of the XScreenEvent function is: % % int XScreenEvent(Display *display,XEvent *event,char *data) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o event: Specifies a pointer to a X11 XEvent structure. % % o data: Specifies a pointer to a XWindows structure. % */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif static int XScreenEvent(Display *display,XEvent *event,char *data) { XWindows *windows; windows=(XWindows *) data; if (event->xany.window == windows->popup.id) { if (event->type == MapNotify) windows->popup.mapped=MagickTrue; if (event->type == UnmapNotify) windows->popup.mapped=MagickFalse; return(MagickTrue); } if (event->xany.window == windows->widget.id) { if (event->type == MapNotify) windows->widget.mapped=MagickTrue; if (event->type == UnmapNotify) windows->widget.mapped=MagickFalse; return(MagickTrue); } switch (event->type) { case ButtonPress: { if ((event->xbutton.button == Button3) && (event->xbutton.state & Mod1Mask)) { /* Convert Alt-Button3 to Button2. */ event->xbutton.button=Button2; event->xbutton.state&=(~Mod1Mask); } return(MagickTrue); } case Expose: { if (event->xexpose.window == windows->image.id) { XRefreshWindow(display,&windows->image,event); break; } if (event->xexpose.window == windows->magnify.id) if (event->xexpose.count == 0) if (windows->magnify.mapped) { ExceptionInfo *exception; exception=AcquireExceptionInfo(); XMakeMagnifyImage(display,windows,exception); exception=DestroyExceptionInfo(exception); break; } if (event->xexpose.window == windows->command.id) if (event->xexpose.count == 0) { (void) XCommandWidget(display,windows,(const char **) NULL,event); break; } break; } case FocusOut: { /* Set input focus for backdrop window. */ if (event->xfocus.window == windows->image.id) (void) XSetInputFocus(display,windows->image.id,RevertToNone, CurrentTime); return(MagickTrue); } case ButtonRelease: case KeyPress: case KeyRelease: case MotionNotify: case SelectionNotify: return(MagickTrue); default: break; } return(MagickFalse); } #if defined(__cplusplus) || defined(c_plusplus) } #endif /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X S e t B e v e l C o l o r % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XSetBevelColor() sets the graphic context for drawing a beveled border. % % The format of the XSetBevelColor function is: % % XSetBevelColor(display,window_info,raised) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o raised: A value other than zero indicates the color show be a % "highlight" color, otherwise the "shadow" color is set. % */ static void XSetBevelColor(Display *display,const XWindowInfo *window_info, const MagickStatusType raised) { if (window_info->depth == 1) { Pixmap stipple; /* Monochrome window. */ (void) XSetBackground(display,window_info->widget_context, XBlackPixel(display,window_info->screen)); (void) XSetForeground(display,window_info->widget_context, XWhitePixel(display,window_info->screen)); (void) XSetFillStyle(display,window_info->widget_context, FillOpaqueStippled); stipple=window_info->highlight_stipple; if (raised == MagickFalse) stipple=window_info->shadow_stipple; (void) XSetStipple(display,window_info->widget_context,stipple); } else if (raised) (void) XSetForeground(display,window_info->widget_context, window_info->pixel_info->highlight_color.pixel); else (void) XSetForeground(display,window_info->widget_context, window_info->pixel_info->shadow_color.pixel); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X S e t M a t t e C o l o r % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XSetMatteColor() sets the graphic context for drawing the matte. % % The format of the XSetMatteColor function is: % % XSetMatteColor(display,window_info,raised) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o raised: A value other than zero indicates the matte is active. % */ static void XSetMatteColor(Display *display,const XWindowInfo *window_info, const MagickStatusType raised) { if (window_info->depth == 1) { /* Monochrome window. */ if (raised) (void) XSetForeground(display,window_info->widget_context, XWhitePixel(display,window_info->screen)); else (void) XSetForeground(display,window_info->widget_context, XBlackPixel(display,window_info->screen)); } else if (raised) (void) XSetForeground(display,window_info->widget_context, window_info->pixel_info->matte_color.pixel); else (void) XSetForeground(display,window_info->widget_context, window_info->pixel_info->depth_color.pixel); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + X S e t T e x t C o l o r % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XSetTextColor() sets the graphic context for drawing text on a matte. % % The format of the XSetTextColor function is: % % XSetTextColor(display,window_info,raised) % % A description of each parameter follows: % % o display: Specifies a pointer to the Display structure; returned from % XOpenDisplay. % % o window_info: Specifies a pointer to a X11 XWindowInfo structure. % % o raised: A value other than zero indicates the color show be a % "highlight" color, otherwise the "shadow" color is set. % */ static void XSetTextColor(Display *display,const XWindowInfo *window_info, const MagickStatusType raised) { ssize_t foreground, matte; if (window_info->depth == 1) { /* Monochrome window. */ if (raised) (void) XSetForeground(display,window_info->widget_context, XBlackPixel(display,window_info->screen)); else (void) XSetForeground(display,window_info->widget_context, XWhitePixel(display,window_info->screen)); return; } foreground=(ssize_t) XPixelIntensity( &window_info->pixel_info->foreground_color); matte=(ssize_t) XPixelIntensity(&window_info->pixel_info->matte_color); if (MagickAbsoluteValue((int) (foreground-matte)) > (65535L >> 3)) (void) XSetForeground(display,window_info->widget_context, window_info->pixel_info->foreground_color.pixel); else (void) XSetForeground(display,window_info->widget_context, window_info->pixel_info->background_color.pixel); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X C o l o r B r o w s e r W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XColorBrowserWidget() displays a Color Browser widget with a color query % to the user. The user keys a reply and presses the Action or Cancel button % to exit. The typed text is returned as the reply function parameter. % % The format of the XColorBrowserWidget method is: % % void XColorBrowserWidget(Display *display,XWindows *windows, % const char *action,char *reply) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o action: Specifies a pointer to the action of this widget. % % o reply: the response from the user is returned in this parameter. % */ MagickPrivate void XColorBrowserWidget(Display *display,XWindows *windows, const char *action,char *reply) { #define CancelButtonText "Cancel" #define ColornameText "Name:" #define ColorPatternText "Pattern:" #define GrabButtonText "Grab" #define ResetButtonText "Reset" char **colorlist, primary_selection[MagickPathExtent], reset_pattern[MagickPathExtent], text[MagickPathExtent]; ExceptionInfo *exception; int x, y; register int i; static char glob_pattern[MagickPathExtent] = "*"; static MagickStatusType mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); Status status; unsigned int height, text_width, visible_colors, width; size_t colors, delay, state; XColor color; XEvent event; XFontStruct *font_info; XTextProperty window_name; XWidgetInfo action_info, cancel_info, expose_info, grab_info, list_info, mode_info, north_info, reply_info, reset_info, scroll_info, selection_info, slider_info, south_info, text_info; XWindowChanges window_changes; /* Get color list and sort in ascending order. */ assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(action != (char *) NULL); assert(reply != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); XSetCursorState(display,windows,MagickTrue); XCheckRefreshWindows(display,windows); (void) CopyMagickString(reset_pattern,"*",MagickPathExtent); exception=AcquireExceptionInfo(); colorlist=GetColorList(glob_pattern,&colors,exception); if (colorlist == (char **) NULL) { /* Pattern failed, obtain all the colors. */ (void) CopyMagickString(glob_pattern,"*",MagickPathExtent); colorlist=GetColorList(glob_pattern,&colors,exception); if (colorlist == (char **) NULL) { XNoticeWidget(display,windows,"Unable to obtain colors names:", glob_pattern); (void) XDialogWidget(display,windows,action,"Enter color name:", reply); return; } } /* Determine Color Browser widget attributes. */ font_info=windows->widget.font_info; text_width=0; for (i=0; i < (int) colors; i++) if (WidgetTextWidth(font_info,colorlist[i]) > text_width) text_width=WidgetTextWidth(font_info,colorlist[i]); width=WidgetTextWidth(font_info,(char *) action); if (WidgetTextWidth(font_info,CancelButtonText) > width) width=WidgetTextWidth(font_info,CancelButtonText); if (WidgetTextWidth(font_info,ResetButtonText) > width) width=WidgetTextWidth(font_info,ResetButtonText); if (WidgetTextWidth(font_info,GrabButtonText) > width) width=WidgetTextWidth(font_info,GrabButtonText); width+=QuantumMargin; if (WidgetTextWidth(font_info,ColorPatternText) > width) width=WidgetTextWidth(font_info,ColorPatternText); if (WidgetTextWidth(font_info,ColornameText) > width) width=WidgetTextWidth(font_info,ColornameText); height=(unsigned int) (font_info->ascent+font_info->descent); /* Position Color Browser widget. */ windows->widget.width=(unsigned int) (width+MagickMin((int) text_width,(int) MaxTextWidth)+6*QuantumMargin); windows->widget.min_width=(unsigned int) (width+MinTextWidth+4*QuantumMargin); if (windows->widget.width < windows->widget.min_width) windows->widget.width=windows->widget.min_width; windows->widget.height=(unsigned int) ((81*height) >> 2)+((13*QuantumMargin) >> 1)+4; windows->widget.min_height=(unsigned int) (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4); if (windows->widget.height < windows->widget.min_height) windows->widget.height=windows->widget.min_height; XConstrainWindowPosition(display,&windows->widget); /* Map Color Browser widget. */ (void) CopyMagickString(windows->widget.name,"Browse and Select a Color", MagickPathExtent); status=XStringListToTextProperty(&windows->widget.name,1,&window_name); if (status != False) { XSetWMName(display,windows->widget.id,&window_name); XSetWMIconName(display,windows->widget.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) windows->widget.width; window_changes.height=(int) windows->widget.height; window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, mask,&window_changes); (void) XMapRaised(display,windows->widget.id); windows->widget.mapped=MagickFalse; /* Respond to X events. */ XGetWidgetInfo((char *) NULL,&mode_info); XGetWidgetInfo((char *) NULL,&slider_info); XGetWidgetInfo((char *) NULL,&north_info); XGetWidgetInfo((char *) NULL,&south_info); XGetWidgetInfo((char *) NULL,&expose_info); XGetWidgetInfo((char *) NULL,&selection_info); visible_colors=0; delay=SuspendTime << 2; state=UpdateConfigurationState; do { if (state & UpdateConfigurationState) { int id; /* Initialize button information. */ XGetWidgetInfo(CancelButtonText,&cancel_info); cancel_info.width=width; cancel_info.height=(unsigned int) ((3*height) >> 1); cancel_info.x=(int) (windows->widget.width-cancel_info.width-QuantumMargin-2); cancel_info.y=(int) (windows->widget.height-cancel_info.height-QuantumMargin); XGetWidgetInfo(action,&action_info); action_info.width=width; action_info.height=(unsigned int) ((3*height) >> 1); action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+ (action_info.bevel_width << 1)); action_info.y=cancel_info.y; XGetWidgetInfo(GrabButtonText,&grab_info); grab_info.width=width; grab_info.height=(unsigned int) ((3*height) >> 1); grab_info.x=QuantumMargin; grab_info.y=((5*QuantumMargin) >> 1)+height; XGetWidgetInfo(ResetButtonText,&reset_info); reset_info.width=width; reset_info.height=(unsigned int) ((3*height) >> 1); reset_info.x=QuantumMargin; reset_info.y=grab_info.y+grab_info.height+QuantumMargin; /* Initialize reply information. */ XGetWidgetInfo(reply,&reply_info); reply_info.raised=MagickFalse; reply_info.bevel_width--; reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1); reply_info.height=height << 1; reply_info.x=(int) (width+(QuantumMargin << 1)); reply_info.y=action_info.y-reply_info.height-QuantumMargin; /* Initialize mode information. */ XGetWidgetInfo((char *) NULL,&mode_info); mode_info.active=MagickTrue; mode_info.bevel_width=0; mode_info.width=(unsigned int) (action_info.x-(QuantumMargin << 1)); mode_info.height=action_info.height; mode_info.x=QuantumMargin; mode_info.y=action_info.y; /* Initialize scroll information. */ XGetWidgetInfo((char *) NULL,&scroll_info); scroll_info.bevel_width--; scroll_info.width=height; scroll_info.height=(unsigned int) (reply_info.y-grab_info.y- (QuantumMargin >> 1)); scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width); scroll_info.y=grab_info.y-reply_info.bevel_width; scroll_info.raised=MagickFalse; scroll_info.trough=MagickTrue; north_info=scroll_info; north_info.raised=MagickTrue; north_info.width-=(north_info.bevel_width << 1); north_info.height=north_info.width-1; north_info.x+=north_info.bevel_width; north_info.y+=north_info.bevel_width; south_info=north_info; south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- south_info.height; id=slider_info.id; slider_info=north_info; slider_info.id=id; slider_info.width-=2; slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ slider_info.bevel_width+2; slider_info.height=scroll_info.height-((slider_info.min_y- scroll_info.y+1) << 1)+4; visible_colors=scroll_info.height/(height+(height >> 3)); if (colors > visible_colors) slider_info.height=(unsigned int) ((visible_colors*slider_info.height)/colors); slider_info.max_y=south_info.y-south_info.bevel_width- slider_info.bevel_width-2; slider_info.x=scroll_info.x+slider_info.bevel_width+1; slider_info.y=slider_info.min_y; expose_info=scroll_info; expose_info.y=slider_info.y; /* Initialize list information. */ XGetWidgetInfo((char *) NULL,&list_info); list_info.raised=MagickFalse; list_info.bevel_width--; list_info.width=(unsigned int) (scroll_info.x-reply_info.x-(QuantumMargin >> 1)); list_info.height=scroll_info.height; list_info.x=reply_info.x; list_info.y=scroll_info.y; if (windows->widget.mapped == MagickFalse) state|=JumpListState; /* Initialize text information. */ *text='\0'; XGetWidgetInfo(text,&text_info); text_info.center=MagickFalse; text_info.width=reply_info.width; text_info.height=height; text_info.x=list_info.x-(QuantumMargin >> 1); text_info.y=QuantumMargin; /* Initialize selection information. */ XGetWidgetInfo((char *) NULL,&selection_info); selection_info.center=MagickFalse; selection_info.width=list_info.width; selection_info.height=(unsigned int) ((9*height) >> 3); selection_info.x=list_info.x; state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw Color Browser window. */ x=QuantumMargin; y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent; (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,ColorPatternText, Extent(ColorPatternText)); (void) CopyMagickString(text_info.text,glob_pattern,MagickPathExtent); XDrawWidgetText(display,&windows->widget,&text_info); XDrawBeveledButton(display,&windows->widget,&grab_info); XDrawBeveledButton(display,&windows->widget,&reset_info); XDrawBeveledMatte(display,&windows->widget,&list_info); XDrawBeveledMatte(display,&windows->widget,&scroll_info); XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); x=QuantumMargin; y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent; (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,ColornameText, Extent(ColornameText)); XDrawBeveledMatte(display,&windows->widget,&reply_info); XDrawMatteText(display,&windows->widget,&reply_info); XDrawBeveledButton(display,&windows->widget,&action_info); XDrawBeveledButton(display,&windows->widget,&cancel_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); selection_info.id=(~0); state|=RedrawActionState; state|=RedrawListState; state&=(~RedrawWidgetState); } if (state & UpdateListState) { char **checklist; size_t number_colors; status=XParseColor(display,windows->widget.map_info->colormap, glob_pattern,&color); if ((status != False) || (strchr(glob_pattern,'-') != (char *) NULL)) { /* Reply is a single color name-- exit. */ (void) CopyMagickString(reply,glob_pattern,MagickPathExtent); (void) CopyMagickString(glob_pattern,reset_pattern,MagickPathExtent); action_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } /* Update color list. */ checklist=GetColorList(glob_pattern,&number_colors,exception); if (number_colors == 0) { (void) CopyMagickString(glob_pattern,reset_pattern,MagickPathExtent); (void) XBell(display,0); } else { for (i=0; i < (int) colors; i++) colorlist[i]=DestroyString(colorlist[i]); if (colorlist != (char **) NULL) colorlist=(char **) RelinquishMagickMemory(colorlist); colorlist=checklist; colors=number_colors; } /* Sort color list in ascending order. */ slider_info.height= scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1; if (colors > visible_colors) slider_info.height=(unsigned int) ((visible_colors*slider_info.height)/colors); slider_info.max_y=south_info.y-south_info.bevel_width- slider_info.bevel_width-2; slider_info.id=0; slider_info.y=slider_info.min_y; expose_info.y=slider_info.y; selection_info.id=(~0); list_info.id=(~0); state|=RedrawListState; /* Redraw color name & reply. */ *reply_info.text='\0'; reply_info.cursor=reply_info.text; (void) CopyMagickString(text_info.text,glob_pattern,MagickPathExtent); XDrawWidgetText(display,&windows->widget,&text_info); XDrawMatteText(display,&windows->widget,&reply_info); XDrawBeveledMatte(display,&windows->widget,&scroll_info); XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); state&=(~UpdateListState); } if (state & JumpListState) { /* Jump scroll to match user color. */ list_info.id=(~0); for (i=0; i < (int) colors; i++) if (LocaleCompare(colorlist[i],reply) >= 0) { list_info.id=LocaleCompare(colorlist[i],reply) == 0 ? i : ~0; break; } if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_colors))) slider_info.id=i-(visible_colors >> 1); selection_info.id=(~0); state|=RedrawListState; state&=(~JumpListState); } if (state & RedrawListState) { /* Determine slider id and position. */ if (slider_info.id >= (int) (colors-visible_colors)) slider_info.id=(int) (colors-visible_colors); if ((slider_info.id < 0) || (colors <= visible_colors)) slider_info.id=0; slider_info.y=slider_info.min_y; if (colors != 0) slider_info.y+=(int) (slider_info.id*(slider_info.max_y- slider_info.min_y+1)/colors); if (slider_info.id != selection_info.id) { /* Redraw scroll bar and file names. */ selection_info.id=slider_info.id; selection_info.y=list_info.y+(height >> 3)+2; for (i=0; i < (int) visible_colors; i++) { selection_info.raised=(slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse; selection_info.text=(char *) NULL; if ((slider_info.id+i) < (int) colors) selection_info.text=colorlist[slider_info.id+i]; XDrawWidgetText(display,&windows->widget,&selection_info); selection_info.y+=(int) selection_info.height; } /* Update slider. */ if (slider_info.y > expose_info.y) { expose_info.height=(unsigned int) slider_info.y-expose_info.y; expose_info.y=slider_info.y-expose_info.height- slider_info.bevel_width-1; } else { expose_info.height=(unsigned int) expose_info.y-slider_info.y; expose_info.y=slider_info.y+slider_info.height+ slider_info.bevel_width+1; } XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawMatte(display,&windows->widget,&expose_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); expose_info.y=slider_info.y; } state&=(~RedrawListState); } if (state & RedrawActionState) { static char colorname[MagickPathExtent]; /* Display the selected color in a drawing area. */ color=windows->widget.pixel_info->matte_color; (void) XParseColor(display,windows->widget.map_info->colormap, reply_info.text,&windows->widget.pixel_info->matte_color); XBestPixel(display,windows->widget.map_info->colormap,(XColor *) NULL, (unsigned int) windows->widget.visual_info->colormap_size, &windows->widget.pixel_info->matte_color); mode_info.text=colorname; (void) FormatLocaleString(mode_info.text,MagickPathExtent, "#%02x%02x%02x",windows->widget.pixel_info->matte_color.red, windows->widget.pixel_info->matte_color.green, windows->widget.pixel_info->matte_color.blue); XDrawBeveledButton(display,&windows->widget,&mode_info); windows->widget.pixel_info->matte_color=color; state&=(~RedrawActionState); } /* Wait for next event. */ if (north_info.raised && south_info.raised) (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); else { /* Brief delay before advancing scroll bar. */ XDelay(display,delay); delay=SuspendTime; (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); if (north_info.raised == MagickFalse) if (slider_info.id > 0) { /* Move slider up. */ slider_info.id--; state|=RedrawListState; } if (south_info.raised == MagickFalse) if (slider_info.id < (int) colors) { /* Move slider down. */ slider_info.id++; state|=RedrawListState; } if (event.type != ButtonRelease) continue; } switch (event.type) { case ButtonPress: { if (MatteIsActive(slider_info,event.xbutton)) { /* Track slider. */ slider_info.active=MagickTrue; break; } if (MatteIsActive(north_info,event.xbutton)) if (slider_info.id > 0) { /* Move slider up. */ north_info.raised=MagickFalse; slider_info.id--; state|=RedrawListState; break; } if (MatteIsActive(south_info,event.xbutton)) if (slider_info.id < (int) colors) { /* Move slider down. */ south_info.raised=MagickFalse; slider_info.id++; state|=RedrawListState; break; } if (MatteIsActive(scroll_info,event.xbutton)) { /* Move slider. */ if (event.xbutton.y < slider_info.y) slider_info.id-=(visible_colors-1); else slider_info.id+=(visible_colors-1); state|=RedrawListState; break; } if (MatteIsActive(list_info,event.xbutton)) { int id; /* User pressed list matte. */ id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ selection_info.height; if (id >= (int) colors) break; (void) CopyMagickString(reply_info.text,colorlist[id], MagickPathExtent); reply_info.highlight=MagickFalse; reply_info.marker=reply_info.text; reply_info.cursor=reply_info.text+Extent(reply_info.text); XDrawMatteText(display,&windows->widget,&reply_info); state|=RedrawActionState; if (id == list_info.id) { (void) CopyMagickString(glob_pattern,reply_info.text, MagickPathExtent); state|=UpdateListState; } selection_info.id=(~0); list_info.id=id; state|=RedrawListState; break; } if (MatteIsActive(grab_info,event.xbutton)) { /* User pressed Grab button. */ grab_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&grab_info); break; } if (MatteIsActive(reset_info,event.xbutton)) { /* User pressed Reset button. */ reset_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&reset_info); break; } if (MatteIsActive(mode_info,event.xbutton)) { /* User pressed mode button. */ if (mode_info.text != (char *) NULL) (void) CopyMagickString(reply_info.text,mode_info.text, MagickPathExtent); (void) CopyMagickString(primary_selection,reply_info.text, MagickPathExtent); (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, event.xbutton.time); reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == windows->widget.id ? MagickTrue : MagickFalse; reply_info.marker=reply_info.text; reply_info.cursor=reply_info.text+Extent(reply_info.text); XDrawMatteText(display,&windows->widget,&reply_info); break; } if (MatteIsActive(action_info,event.xbutton)) { /* User pressed action button. */ action_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } if (MatteIsActive(cancel_info,event.xbutton)) { /* User pressed Cancel button. */ cancel_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) break; if (event.xbutton.button != Button2) { static Time click_time; /* Move text cursor to position of button press. */ x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); for (i=1; i <= Extent(reply_info.marker); i++) if (XTextWidth(font_info,reply_info.marker,i) > x) break; reply_info.cursor=reply_info.marker+i-1; if (event.xbutton.time > (click_time+DoubleClick)) reply_info.highlight=MagickFalse; else { /* Become the XA_PRIMARY selection owner. */ (void) CopyMagickString(primary_selection,reply_info.text, MagickPathExtent); (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, event.xbutton.time); reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == windows->widget.id ? MagickTrue : MagickFalse; } XDrawMatteText(display,&windows->widget,&reply_info); click_time=event.xbutton.time; break; } /* Request primary selection. */ (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, windows->widget.id,event.xbutton.time); break; } case ButtonRelease: { if (windows->widget.mapped == MagickFalse) break; if (north_info.raised == MagickFalse) { /* User released up button. */ delay=SuspendTime << 2; north_info.raised=MagickTrue; XDrawTriangleNorth(display,&windows->widget,&north_info); } if (south_info.raised == MagickFalse) { /* User released down button. */ delay=SuspendTime << 2; south_info.raised=MagickTrue; XDrawTriangleSouth(display,&windows->widget,&south_info); } if (slider_info.active) { /* Stop tracking slider. */ slider_info.active=MagickFalse; break; } if (grab_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(grab_info,event.xbutton)) { /* Select a fill color from the X server. */ (void) XGetWindowColor(display,windows,reply_info.text, exception); reply_info.marker=reply_info.text; reply_info.cursor=reply_info.text+Extent(reply_info.text); XDrawMatteText(display,&windows->widget,&reply_info); state|=RedrawActionState; } grab_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&grab_info); } if (reset_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(reset_info,event.xbutton)) { (void) CopyMagickString(glob_pattern,reset_pattern, MagickPathExtent); state|=UpdateListState; } reset_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&reset_info); } if (action_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) { if (MatteIsActive(action_info,event.xbutton)) { if (*reply_info.text == '\0') (void) XBell(display,0); else state|=ExitState; } } action_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&action_info); } if (cancel_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(cancel_info,event.xbutton)) { *reply_info.text='\0'; state|=ExitState; } cancel_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&cancel_info); } if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) break; break; } case ClientMessage: { /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (int) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (int) windows->wm_delete_window) break; if (event.xclient.window == windows->widget.id) { *reply_info.text='\0'; state|=ExitState; break; } break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != windows->widget.id) break; if ((event.xconfigure.width == (int) windows->widget.width) && (event.xconfigure.height == (int) windows->widget.height)) break; windows->widget.width=(unsigned int) MagickMax(event.xconfigure.width,(int) windows->widget.min_width); windows->widget.height=(unsigned int) MagickMax(event.xconfigure.height,(int) windows->widget.min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != windows->widget.id) break; state&=(~InactiveWidgetState); break; } case Expose: { if (event.xexpose.window != windows->widget.id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case KeyPress: { static char command[MagickPathExtent]; static int length; static KeySym key_symbol; /* Respond to a user key press. */ if (event.xkey.window != windows->widget.id) break; length=XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); *(command+length)='\0'; if (AreaIsActive(scroll_info,event.xkey)) { /* Move slider. */ switch ((int) key_symbol) { case XK_Home: case XK_KP_Home: { slider_info.id=0; break; } case XK_Up: case XK_KP_Up: { slider_info.id--; break; } case XK_Down: case XK_KP_Down: { slider_info.id++; break; } case XK_Prior: case XK_KP_Prior: { slider_info.id-=visible_colors; break; } case XK_Next: case XK_KP_Next: { slider_info.id+=visible_colors; break; } case XK_End: case XK_KP_End: { slider_info.id=(int) colors; break; } } state|=RedrawListState; break; } if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) { /* Read new color or glob patterm. */ if (*reply_info.text == '\0') break; (void) CopyMagickString(glob_pattern,reply_info.text,MagickPathExtent); state|=UpdateListState; break; } if (key_symbol == XK_Control_L) { state|=ControlState; break; } if (state & ControlState) switch ((int) key_symbol) { case XK_u: case XK_U: { /* Erase the entire line of text. */ *reply_info.text='\0'; reply_info.cursor=reply_info.text; reply_info.marker=reply_info.text; reply_info.highlight=MagickFalse; break; } default: break; } XEditText(display,&reply_info,key_symbol,command,state); XDrawMatteText(display,&windows->widget,&reply_info); state|=JumpListState; status=XParseColor(display,windows->widget.map_info->colormap, reply_info.text,&color); if (status != False) state|=RedrawActionState; break; } case KeyRelease: { static char command[MagickPathExtent]; static KeySym key_symbol; /* Respond to a user key release. */ if (event.xkey.window != windows->widget.id) break; (void) XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); if (key_symbol == XK_Control_L) state&=(~ControlState); break; } case LeaveNotify: { if (event.xcrossing.window != windows->widget.id) break; state|=InactiveWidgetState; break; } case MapNotify: { mask&=(~CWX); mask&=(~CWY); break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (slider_info.active) { /* Move slider matte. */ slider_info.y=event.xmotion.y- ((slider_info.height+slider_info.bevel_width) >> 1)+1; if (slider_info.y < slider_info.min_y) slider_info.y=slider_info.min_y; if (slider_info.y > slider_info.max_y) slider_info.y=slider_info.max_y; slider_info.id=0; if (slider_info.y != slider_info.min_y) slider_info.id=(int) ((colors*(slider_info.y- slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1)); state|=RedrawListState; break; } if (state & InactiveWidgetState) break; if (grab_info.raised == MatteIsActive(grab_info,event.xmotion)) { /* Grab button status changed. */ grab_info.raised=!grab_info.raised; XDrawBeveledButton(display,&windows->widget,&grab_info); break; } if (reset_info.raised == MatteIsActive(reset_info,event.xmotion)) { /* Reset button status changed. */ reset_info.raised=!reset_info.raised; XDrawBeveledButton(display,&windows->widget,&reset_info); break; } if (action_info.raised == MatteIsActive(action_info,event.xmotion)) { /* Action button status changed. */ action_info.raised=action_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) { /* Cancel button status changed. */ cancel_info.raised=cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } break; } case SelectionClear: { reply_info.highlight=MagickFalse; XDrawMatteText(display,&windows->widget,&reply_info); break; } case SelectionNotify: { Atom type; int format; unsigned char *data; unsigned long after, length; /* Obtain response from primary selection. */ if (event.xselection.property == (Atom) None) break; status=XGetWindowProperty(display,event.xselection.requestor, event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type, &format,&length,&after,&data); if ((status != Success) || (type != XA_STRING) || (format == 32) || (length == 0)) break; if ((Extent(reply_info.text)+length) >= (MagickPathExtent-1)) (void) XBell(display,0); else { /* Insert primary selection in reply text. */ *(data+length)='\0'; XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, state); XDrawMatteText(display,&windows->widget,&reply_info); state|=JumpListState; state|=RedrawActionState; } (void) XFree((void *) data); break; } case SelectionRequest: { XSelectionEvent notify; XSelectionRequestEvent *request; if (reply_info.highlight == MagickFalse) break; /* Set primary selection. */ request=(&(event.xselectionrequest)); (void) XChangeProperty(request->display,request->requestor, request->property,request->target,8,PropModeReplace, (unsigned char *) primary_selection,Extent(primary_selection)); notify.type=SelectionNotify; notify.send_event=MagickTrue; notify.display=request->display; notify.requestor=request->requestor; notify.selection=request->selection; notify.target=request->target; notify.time=request->time; if (request->property == None) notify.property=request->target; else notify.property=request->property; (void) XSendEvent(request->display,request->requestor,False, NoEventMask,(XEvent *) ¬ify); } default: break; } } while ((state & ExitState) == 0); XSetCursorState(display,windows,MagickFalse); (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); XCheckRefreshWindows(display,windows); /* Free color list. */ for (i=0; i < (int) colors; i++) colorlist[i]=DestroyString(colorlist[i]); if (colorlist != (char **) NULL) colorlist=(char **) RelinquishMagickMemory(colorlist); exception=DestroyExceptionInfo(exception); if ((*reply == '\0') || (strchr(reply,'-') != (char *) NULL)) return; status=XParseColor(display,windows->widget.map_info->colormap,reply,&color); if (status != False) return; XNoticeWidget(display,windows,"Color is unknown to X server:",reply); (void) CopyMagickString(reply,"gray",MagickPathExtent); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X C o m m a n d W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XCommandWidget() maps a menu and returns the command pointed to by the user % when the button is released. % % The format of the XCommandWidget method is: % % int XCommandWidget(Display *display,XWindows *windows, % const char **selections,XEvent *event) % % A description of each parameter follows: % % o selection_number: Specifies the number of the selection that the % user choose. % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o selections: Specifies a pointer to one or more strings that comprise % the choices in the menu. % % o event: Specifies a pointer to a X11 XEvent structure. % */ MagickPrivate int XCommandWidget(Display *display,XWindows *windows, const char **selections,XEvent *event) { #define tile_width 112 #define tile_height 70 static const unsigned char tile_bits[]= { 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xbc, 0x9f, 0x03, 0x00, 0x3e, 0x00, 0xc0, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x0f, 0x80, 0x3f, 0x00, 0xf0, 0x1f, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x1f, 0xe0, 0x3f, 0x00, 0xfc, 0x1f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x1f, 0xf0, 0x3f, 0x00, 0xfe, 0x1f, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xfc, 0x3f, 0xf8, 0x3f, 0x00, 0xff, 0x1e, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x7c, 0xfc, 0x3e, 0xf8, 0x3c, 0x80, 0x1f, 0x1e, 0x7c, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, 0xc0, 0x0f, 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, 0xc0, 0x07, 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x7c, 0xc0, 0x0f, 0x1e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0xfc, 0x7c, 0x80, 0x7f, 0x1e, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf8, 0xff, 0x00, 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xfe, 0x1f, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xf8, 0x1f, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xc0, 0xef, 0x07, 0xe0, 0x1f, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0x70, 0x40, 0x78, 0x00, 0xc7, 0x07, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0x9f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0xdf, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x00, 0xe0, 0xdf, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0c, 0x78, 0x30, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0f, 0xf8, 0x70, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x1f, 0x00, 0xe0, 0x0f, 0x1e, 0x80, 0x0f, 0xf8, 0x78, 0xf0, 0xfd, 0xf9, 0x00, 0xc0, 0x1f, 0x00, 0xf8, 0x0f, 0x00, 0xe0, 0x1f, 0xf8, 0x7c, 0xf0, 0xfc, 0xf9, 0x00, 0xf0, 0x1f, 0x00, 0xfe, 0x0f, 0x00, 0xf0, 0x07, 0xf8, 0x3e, 0xf8, 0xfc, 0xf0, 0x01, 0xf8, 0x1f, 0x00, 0xff, 0x0f, 0x1e, 0xf0, 0x03, 0xf8, 0x3f, 0xf8, 0xf8, 0xf0, 0x01, 0xfc, 0x1f, 0x80, 0x7f, 0x0f, 0x1e, 0xf8, 0x00, 0xf8, 0x1f, 0x78, 0x18, 0xf0, 0x01, 0x7c, 0x1e, 0xc0, 0x0f, 0x0f, 0x1e, 0x7c, 0x00, 0xf0, 0x0f, 0x78, 0x00, 0xf0, 0x01, 0x3e, 0x1e, 0xe0, 0x07, 0x0f, 0x1e, 0x7c, 0x00, 0xf0, 0x07, 0x7c, 0x00, 0xe0, 0x01, 0x3e, 0x1e, 0xe0, 0x03, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x0f, 0x7c, 0x00, 0xe0, 0x03, 0x3e, 0x3e, 0xe0, 0x07, 0x0f, 0x1e, 0x1e, 0x00, 0xf0, 0x1f, 0x3c, 0x00, 0xe0, 0x03, 0x7e, 0x3e, 0xc0, 0x3f, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x1f, 0x3e, 0x00, 0xe0, 0x03, 0xfc, 0x7f, 0x80, 0xff, 0x0f, 0x1e, 0xfc, 0x00, 0xf0, 0x3e, 0x3e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xff, 0x0f, 0x1e, 0xfc, 0x07, 0xf0, 0x7c, 0x1e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xfc, 0x0f, 0x1e, 0xf8, 0x1f, 0xf0, 0xf8, 0x1e, 0x00, 0xc0, 0x03, 0xe0, 0xf7, 0x03, 0xf0, 0x0f, 0x1e, 0xe0, 0x3f, 0xf0, 0x78, 0x1c, 0x00, 0x80, 0x03, 0x80, 0xe3, 0x03, 0x00, 0x0f, 0x1e, 0xc0, 0x3f, 0xf0, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int id, y; register int i; static unsigned int number_selections; unsigned int height; size_t state; XFontStruct *font_info; (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); font_info=windows->command.font_info; height=(unsigned int) (font_info->ascent+font_info->descent); id=(~0); state=DefaultState; if (event == (XEvent *) NULL) { unsigned int width; XTextProperty window_name; XWindowChanges window_changes; /* Determine command window attributes. */ assert(selections != (const char **) NULL); windows->command.width=0; for (i=0; selections[i] != (char *) NULL; i++) { width=WidgetTextWidth(font_info,(char *) selections[i]); if (width > windows->command.width) windows->command.width=width; } number_selections=(unsigned int) i; windows->command.width+=3*QuantumMargin+10; if ((int) windows->command.width < (tile_width+QuantumMargin+10)) windows->command.width=(unsigned int) (tile_width+QuantumMargin+10); windows->command.height=(unsigned int) (number_selections* (((3*height) >> 1)+10)+tile_height+20); windows->command.min_width=windows->command.width; windows->command.min_height=windows->command.height; XConstrainWindowPosition(display,&windows->command); if (windows->command.id != (Window) NULL) { Status status; /* Reconfigure command window. */ status=XStringListToTextProperty(&windows->command.name,1, &window_name); if (status != False) { XSetWMName(display,windows->command.id,&window_name); XSetWMIconName(display,windows->command.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) windows->command.width; window_changes.height=(int) windows->command.height; (void) XReconfigureWMWindow(display,windows->command.id, windows->command.screen,(unsigned int) (CWWidth | CWHeight), &window_changes); } /* Allocate selection info memory. */ if (selection_info != (XWidgetInfo *) NULL) selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info); selection_info=(XWidgetInfo *) AcquireQuantumMemory(number_selections, sizeof(*selection_info)); if (selection_info == (XWidgetInfo *) NULL) { ThrowXWindowFatalException(ResourceLimitFatalError, "MemoryAllocationFailed","..."); return(id); } state|=UpdateConfigurationState | RedrawWidgetState; } /* Wait for next event. */ if (event != (XEvent *) NULL) switch (event->type) { case ButtonPress: { for (i=0; i < (int) number_selections; i++) { if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse) continue; if (i >= (int) windows->command.data) { selection_info[i].raised=MagickFalse; XDrawBeveledButton(display,&windows->command,&selection_info[i]); break; } submenu_info=selection_info[i]; submenu_info.active=MagickTrue; toggle_info.y=submenu_info.y+(submenu_info.height >> 1)- (toggle_info.height >> 1); id=i; (void) XCheckWindowEvent(display,windows->widget.id,LeaveWindowMask, event); break; } break; } case ButtonRelease: { for (i=0; i < (int) number_selections; i++) { if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse) continue; id=i; if (id >= (int) windows->command.data) { selection_info[id].raised=MagickTrue; XDrawBeveledButton(display,&windows->command,&selection_info[id]); break; } break; } break; } case ClientMessage: { /* If client window delete message, withdraw command widget. */ if (event->xclient.message_type != windows->wm_protocols) break; if (*event->xclient.data.l != (int) windows->wm_delete_window) break; (void) XWithdrawWindow(display,windows->command.id, windows->command.screen); break; } case ConfigureNotify: { /* Update widget configuration. */ if (event->xconfigure.window != windows->command.id) break; if (event->xconfigure.send_event != 0) { windows->command.x=event->xconfigure.x; windows->command.y=event->xconfigure.y; } if ((event->xconfigure.width == (int) windows->command.width) && (event->xconfigure.height == (int) windows->command.height)) break; windows->command.width=(unsigned int) MagickMax(event->xconfigure.width,(int) windows->command.min_width); windows->command.height=(unsigned int) MagickMax(event->xconfigure.height,(int) windows->command.min_height); state|=UpdateConfigurationState; break; } case Expose: { if (event->xexpose.window != windows->command.id) break; if (event->xexpose.count != 0) break; state|=RedrawWidgetState; break; } case MotionNotify: { /* Return the ID of the highlighted menu entry. */ for ( ; ; ) { for (i=0; i < (int) number_selections; i++) { if (i >= (int) windows->command.data) { if (selection_info[i].raised == MatteIsActive(selection_info[i],event->xmotion)) { /* Button status changed. */ selection_info[i].raised=!selection_info[i].raised; XDrawBeveledButton(display,&windows->command, &selection_info[i]); } continue; } if (MatteIsActive(selection_info[i],event->xmotion) == MagickFalse) continue; submenu_info=selection_info[i]; submenu_info.active=MagickTrue; toggle_info.raised=MagickTrue; toggle_info.y=submenu_info.y+(submenu_info.height >> 1)- (toggle_info.height >> 1); XDrawTriangleEast(display,&windows->command,&toggle_info); id=i; } XDelay(display,SuspendTime); if (XCheckMaskEvent(display,ButtonMotionMask,event) == MagickFalse) break; while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; toggle_info.raised=MagickFalse; if (windows->command.data != 0) XDrawTriangleEast(display,&windows->command,&toggle_info); } break; } case MapNotify: { windows->command.mapped=MagickTrue; break; } case UnmapNotify: { windows->command.mapped=MagickFalse; break; } default: break; } if (state & UpdateConfigurationState) { /* Initialize button information. */ assert(selections != (const char **) NULL); y=tile_height+20; for (i=0; i < (int) number_selections; i++) { XGetWidgetInfo(selections[i],&selection_info[i]); selection_info[i].center=MagickFalse; selection_info[i].bevel_width--; selection_info[i].height=(unsigned int) ((3*height) >> 1); selection_info[i].x=(QuantumMargin >> 1)+4; selection_info[i].width=(unsigned int) (windows->command.width- (selection_info[i].x << 1)); selection_info[i].y=y; y+=selection_info[i].height+(selection_info[i].bevel_width << 1)+6; } XGetWidgetInfo((char *) NULL,&toggle_info); toggle_info.bevel_width--; toggle_info.width=(unsigned int) (((5*height) >> 3)- (toggle_info.bevel_width << 1)); toggle_info.height=toggle_info.width; toggle_info.x=selection_info[0].x+selection_info[0].width- toggle_info.width-(QuantumMargin >> 1); if (windows->command.mapped) (void) XClearWindow(display,windows->command.id); } if (state & RedrawWidgetState) { Pixmap tile_pixmap; /* Draw command buttons. */ tile_pixmap=XCreatePixmapFromBitmapData(display,windows->command.id, (char *) tile_bits,tile_width,tile_height,1L,0L,1); if (tile_pixmap != (Pixmap) NULL) { (void) XCopyPlane(display,tile_pixmap,windows->command.id, windows->command.annotate_context,0,0,tile_width,tile_height, (int) ((windows->command.width-tile_width) >> 1),10,1L); (void) XFreePixmap(display,tile_pixmap); } for (i=0; i < (int) number_selections; i++) { XDrawBeveledButton(display,&windows->command,&selection_info[i]); if (i >= (int) windows->command.data) continue; toggle_info.raised=MagickFalse; toggle_info.y=selection_info[i].y+(selection_info[i].height >> 1)- (toggle_info.height >> 1); XDrawTriangleEast(display,&windows->command,&toggle_info); } XHighlightWidget(display,&windows->command,BorderOffset,BorderOffset); } return(id); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X C o n f i r m W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XConfirmWidget() displays a Confirm widget with a notice to the user. The % function returns -1 if Dismiss is pressed, 0 for Cancel, and 1 for Yes. % % The format of the XConfirmWidget method is: % % int XConfirmWidget(Display *display,XWindows *windows, % const char *reason,const char *description) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o reason: Specifies the message to display before terminating the % program. % % o description: Specifies any description to the message. % */ MagickPrivate int XConfirmWidget(Display *display,XWindows *windows, const char *reason,const char *description) { #define CancelButtonText "Cancel" #define DismissButtonText "Dismiss" #define YesButtonText "Yes" int confirm, x, y; Status status; unsigned int height, width; size_t state; XEvent event; XFontStruct *font_info; XTextProperty window_name; XWidgetInfo cancel_info, dismiss_info, yes_info; XWindowChanges window_changes; /* Determine Confirm widget attributes. */ assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(reason != (char *) NULL); assert(description != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason); XCheckRefreshWindows(display,windows); font_info=windows->widget.font_info; width=WidgetTextWidth(font_info,CancelButtonText); if (WidgetTextWidth(font_info,DismissButtonText) > width) width=WidgetTextWidth(font_info,DismissButtonText); if (WidgetTextWidth(font_info,YesButtonText) > width) width=WidgetTextWidth(font_info,YesButtonText); width<<=1; if (description != (char *) NULL) if (WidgetTextWidth(font_info,(char *) description) > width) width=WidgetTextWidth(font_info,(char *) description); height=(unsigned int) (font_info->ascent+font_info->descent); /* Position Confirm widget. */ windows->widget.width=(unsigned int) (width+9*QuantumMargin); windows->widget.min_width=(unsigned int) (9*QuantumMargin+ WidgetTextWidth(font_info,CancelButtonText)+ WidgetTextWidth(font_info,DismissButtonText)+ WidgetTextWidth(font_info,YesButtonText)); if (windows->widget.width < windows->widget.min_width) windows->widget.width=windows->widget.min_width; windows->widget.height=(unsigned int) (12*height); windows->widget.min_height=(unsigned int) (7*height); if (windows->widget.height < windows->widget.min_height) windows->widget.height=windows->widget.min_height; XConstrainWindowPosition(display,&windows->widget); /* Map Confirm widget. */ (void) CopyMagickString(windows->widget.name,"Confirm",MagickPathExtent); status=XStringListToTextProperty(&windows->widget.name,1,&window_name); if (status != False) { XSetWMName(display,windows->widget.id,&window_name); XSetWMIconName(display,windows->widget.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) windows->widget.width; window_changes.height=(int) windows->widget.height; window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); (void) XMapRaised(display,windows->widget.id); windows->widget.mapped=MagickFalse; /* Respond to X events. */ confirm=0; state=UpdateConfigurationState; XSetCursorState(display,windows,MagickTrue); do { if (state & UpdateConfigurationState) { /* Initialize button information. */ XGetWidgetInfo(CancelButtonText,&cancel_info); cancel_info.width=(unsigned int) QuantumMargin+ WidgetTextWidth(font_info,CancelButtonText); cancel_info.height=(unsigned int) ((3*height) >> 1); cancel_info.x=(int) (windows->widget.width-cancel_info.width- QuantumMargin); cancel_info.y=(int) (windows->widget.height-(cancel_info.height << 1)); dismiss_info=cancel_info; dismiss_info.text=(char *) DismissButtonText; if (LocaleCompare(description,"Do you want to save it") == 0) dismiss_info.text=(char *) "Don't Save"; dismiss_info.width=(unsigned int) QuantumMargin+ WidgetTextWidth(font_info,dismiss_info.text); dismiss_info.x=(int) ((windows->widget.width >> 1)-(dismiss_info.width >> 1)); yes_info=cancel_info; yes_info.text=(char *) YesButtonText; if (LocaleCompare(description,"Do you want to save it") == 0) yes_info.text=(char *) "Save"; yes_info.width=(unsigned int) QuantumMargin+ WidgetTextWidth(font_info,yes_info.text); if (yes_info.width < cancel_info.width) yes_info.width=cancel_info.width; yes_info.x=QuantumMargin; state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw Confirm widget. */ width=WidgetTextWidth(font_info,(char *) reason); x=(int) ((windows->widget.width >> 1)-(width >> 1)); y=(int) ((windows->widget.height >> 1)-(height << 1)); (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,(char *) reason,Extent(reason)); if (description != (char *) NULL) { char question[MagickPathExtent]; (void) CopyMagickString(question,description,MagickPathExtent); (void) ConcatenateMagickString(question,"?",MagickPathExtent); width=WidgetTextWidth(font_info,question); x=(int) ((windows->widget.width >> 1)-(width >> 1)); y+=height; (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,question,Extent(question)); } XDrawBeveledButton(display,&windows->widget,&cancel_info); XDrawBeveledButton(display,&windows->widget,&dismiss_info); XDrawBeveledButton(display,&windows->widget,&yes_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); state&=(~RedrawWidgetState); } /* Wait for next event. */ (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); switch (event.type) { case ButtonPress: { if (MatteIsActive(cancel_info,event.xbutton)) { /* User pressed No button. */ cancel_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } if (MatteIsActive(dismiss_info,event.xbutton)) { /* User pressed Dismiss button. */ dismiss_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&dismiss_info); break; } if (MatteIsActive(yes_info,event.xbutton)) { /* User pressed Yes button. */ yes_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&yes_info); break; } break; } case ButtonRelease: { if (windows->widget.mapped == MagickFalse) break; if (cancel_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(cancel_info,event.xbutton)) { confirm=0; state|=ExitState; } cancel_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&cancel_info); } if (dismiss_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(dismiss_info,event.xbutton)) { confirm=(-1); state|=ExitState; } dismiss_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&dismiss_info); } if (yes_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(yes_info,event.xbutton)) { confirm=1; state|=ExitState; } yes_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&yes_info); } break; } case ClientMessage: { /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (int) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (int) windows->wm_delete_window) break; if (event.xclient.window == windows->widget.id) { state|=ExitState; break; } break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != windows->widget.id) break; if ((event.xconfigure.width == (int) windows->widget.width) && (event.xconfigure.height == (int) windows->widget.height)) break; windows->widget.width=(unsigned int) MagickMax(event.xconfigure.width,(int) windows->widget.min_width); windows->widget.height=(unsigned int) MagickMax(event.xconfigure.height,(int) windows->widget.min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != windows->widget.id) break; state&=(~InactiveWidgetState); break; } case Expose: { if (event.xexpose.window != windows->widget.id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case KeyPress: { static char command[MagickPathExtent]; static KeySym key_symbol; /* Respond to a user key press. */ if (event.xkey.window != windows->widget.id) break; (void) XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) { yes_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&yes_info); confirm=1; state|=ExitState; break; } break; } case LeaveNotify: { if (event.xcrossing.window != windows->widget.id) break; state|=InactiveWidgetState; break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (state & InactiveWidgetState) break; if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) { /* Cancel button status changed. */ cancel_info.raised=cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion)) { /* Dismiss button status changed. */ dismiss_info.raised=dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&dismiss_info); break; } if (yes_info.raised == MatteIsActive(yes_info,event.xmotion)) { /* Yes button status changed. */ yes_info.raised=yes_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&yes_info); break; } break; } default: break; } } while ((state & ExitState) == 0); XSetCursorState(display,windows,MagickFalse); (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); XCheckRefreshWindows(display,windows); return(confirm); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X D i a l o g W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XDialogWidget() displays a Dialog widget with a query to the user. The user % keys a reply and presses the Ok or Cancel button to exit. The typed text is % returned as the reply function parameter. % % The format of the XDialogWidget method is: % % int XDialogWidget(Display *display,XWindows *windows,const char *action, % const char *query,char *reply) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o action: Specifies a pointer to the action of this widget. % % o query: Specifies a pointer to the query to present to the user. % % o reply: the response from the user is returned in this parameter. % */ MagickPrivate int XDialogWidget(Display *display,XWindows *windows, const char *action,const char *query,char *reply) { #define CancelButtonText "Cancel" char primary_selection[MagickPathExtent]; int x; register int i; static MagickBooleanType raised = MagickFalse; Status status; unsigned int anomaly, height, width; size_t state; XEvent event; XFontStruct *font_info; XTextProperty window_name; XWidgetInfo action_info, cancel_info, reply_info, special_info, text_info; XWindowChanges window_changes; /* Determine Dialog widget attributes. */ assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(action != (char *) NULL); assert(query != (char *) NULL); assert(reply != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); XCheckRefreshWindows(display,windows); font_info=windows->widget.font_info; width=WidgetTextWidth(font_info,(char *) action); if (WidgetTextWidth(font_info,CancelButtonText) > width) width=WidgetTextWidth(font_info,CancelButtonText); width+=(3*QuantumMargin) >> 1; height=(unsigned int) (font_info->ascent+font_info->descent); /* Position Dialog widget. */ windows->widget.width=(unsigned int) MagickMax((int) (2*width),(int) WidgetTextWidth(font_info,(char *) query)); if (windows->widget.width < WidgetTextWidth(font_info,reply)) windows->widget.width=WidgetTextWidth(font_info,reply); windows->widget.width+=6*QuantumMargin; windows->widget.min_width=(unsigned int) (width+28*XTextWidth(font_info,"#",1)+4*QuantumMargin); if (windows->widget.width < windows->widget.min_width) windows->widget.width=windows->widget.min_width; windows->widget.height=(unsigned int) (7*height+(QuantumMargin << 1)); windows->widget.min_height=windows->widget.height; if (windows->widget.height < windows->widget.min_height) windows->widget.height=windows->widget.min_height; XConstrainWindowPosition(display,&windows->widget); /* Map Dialog widget. */ (void) CopyMagickString(windows->widget.name,"Dialog",MagickPathExtent); status=XStringListToTextProperty(&windows->widget.name,1,&window_name); if (status != False) { XSetWMName(display,windows->widget.id,&window_name); XSetWMIconName(display,windows->widget.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) windows->widget.width; window_changes.height=(int) windows->widget.height; window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); (void) XMapRaised(display,windows->widget.id); windows->widget.mapped=MagickFalse; /* Respond to X events. */ anomaly=(LocaleCompare(action,"Background") == 0) || (LocaleCompare(action,"New") == 0) || (LocaleCompare(action,"Quantize") == 0) || (LocaleCompare(action,"Resize") == 0) || (LocaleCompare(action,"Save") == 0) || (LocaleCompare(action,"Shade") == 0); state=UpdateConfigurationState; XSetCursorState(display,windows,MagickTrue); do { if (state & UpdateConfigurationState) { /* Initialize button information. */ XGetWidgetInfo(CancelButtonText,&cancel_info); cancel_info.width=width; cancel_info.height=(unsigned int) ((3*height) >> 1); cancel_info.x=(int) (windows->widget.width-cancel_info.width-((3*QuantumMargin) >> 1)); cancel_info.y=(int) (windows->widget.height-cancel_info.height-((3*QuantumMargin) >> 1)); XGetWidgetInfo(action,&action_info); action_info.width=width; action_info.height=(unsigned int) ((3*height) >> 1); action_info.x=cancel_info.x-(cancel_info.width+QuantumMargin+ (action_info.bevel_width << 1)); action_info.y=cancel_info.y; /* Initialize reply information. */ XGetWidgetInfo(reply,&reply_info); reply_info.raised=MagickFalse; reply_info.bevel_width--; reply_info.width=windows->widget.width-(3*QuantumMargin); reply_info.height=height << 1; reply_info.x=(3*QuantumMargin) >> 1; reply_info.y=action_info.y-reply_info.height-QuantumMargin; /* Initialize option information. */ XGetWidgetInfo("Dither",&special_info); special_info.raised=raised; special_info.bevel_width--; special_info.width=(unsigned int) QuantumMargin >> 1; special_info.height=(unsigned int) QuantumMargin >> 1; special_info.x=reply_info.x; special_info.y=action_info.y+action_info.height-special_info.height; if (LocaleCompare(action,"Background") == 0) special_info.text=(char *) "Backdrop"; if (LocaleCompare(action,"New") == 0) special_info.text=(char *) "Gradation"; if (LocaleCompare(action,"Resize") == 0) special_info.text=(char *) "Constrain ratio"; if (LocaleCompare(action,"Save") == 0) special_info.text=(char *) "Non-progressive"; if (LocaleCompare(action,"Shade") == 0) special_info.text=(char *) "Color shading"; /* Initialize text information. */ XGetWidgetInfo(query,&text_info); text_info.width=reply_info.width; text_info.height=height; text_info.x=reply_info.x-(QuantumMargin >> 1); text_info.y=QuantumMargin; text_info.center=MagickFalse; state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw Dialog widget. */ XDrawWidgetText(display,&windows->widget,&text_info); XDrawBeveledMatte(display,&windows->widget,&reply_info); XDrawMatteText(display,&windows->widget,&reply_info); if (anomaly) XDrawBeveledButton(display,&windows->widget,&special_info); XDrawBeveledButton(display,&windows->widget,&action_info); XDrawBeveledButton(display,&windows->widget,&cancel_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); state&=(~RedrawWidgetState); } /* Wait for next event. */ (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); switch (event.type) { case ButtonPress: { if (anomaly) if (MatteIsActive(special_info,event.xbutton)) { /* Option button status changed. */ special_info.raised=!special_info.raised; XDrawBeveledButton(display,&windows->widget,&special_info); break; } if (MatteIsActive(action_info,event.xbutton)) { /* User pressed Action button. */ action_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } if (MatteIsActive(cancel_info,event.xbutton)) { /* User pressed Cancel button. */ cancel_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) break; if (event.xbutton.button != Button2) { static Time click_time; /* Move text cursor to position of button press. */ x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); for (i=1; i <= Extent(reply_info.marker); i++) if (XTextWidth(font_info,reply_info.marker,i) > x) break; reply_info.cursor=reply_info.marker+i-1; if (event.xbutton.time > (click_time+DoubleClick)) reply_info.highlight=MagickFalse; else { /* Become the XA_PRIMARY selection owner. */ (void) CopyMagickString(primary_selection,reply_info.text, MagickPathExtent); (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, event.xbutton.time); reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == windows->widget.id ? MagickTrue : MagickFalse; } XDrawMatteText(display,&windows->widget,&reply_info); click_time=event.xbutton.time; break; } /* Request primary selection. */ (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, windows->widget.id,event.xbutton.time); break; } case ButtonRelease: { if (windows->widget.mapped == MagickFalse) break; if (action_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(action_info,event.xbutton)) state|=ExitState; action_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&action_info); } if (cancel_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(cancel_info,event.xbutton)) { *reply_info.text='\0'; state|=ExitState; } cancel_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&cancel_info); } break; } case ClientMessage: { /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (int) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (int) windows->wm_delete_window) break; if (event.xclient.window == windows->widget.id) { *reply_info.text='\0'; state|=ExitState; break; } break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != windows->widget.id) break; if ((event.xconfigure.width == (int) windows->widget.width) && (event.xconfigure.height == (int) windows->widget.height)) break; windows->widget.width=(unsigned int) MagickMax(event.xconfigure.width,(int) windows->widget.min_width); windows->widget.height=(unsigned int) MagickMax(event.xconfigure.height,(int) windows->widget.min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != windows->widget.id) break; state&=(~InactiveWidgetState); break; } case Expose: { if (event.xexpose.window != windows->widget.id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case KeyPress: { static char command[MagickPathExtent]; static int length; static KeySym key_symbol; /* Respond to a user key press. */ if (event.xkey.window != windows->widget.id) break; length=XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); *(command+length)='\0'; if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) { action_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); state|=ExitState; break; } if (key_symbol == XK_Control_L) { state|=ControlState; break; } if (state & ControlState) switch ((int) key_symbol) { case XK_u: case XK_U: { /* Erase the entire line of text. */ *reply_info.text='\0'; reply_info.cursor=reply_info.text; reply_info.marker=reply_info.text; reply_info.highlight=MagickFalse; break; } default: break; } XEditText(display,&reply_info,key_symbol,command,state); XDrawMatteText(display,&windows->widget,&reply_info); break; } case KeyRelease: { static char command[MagickPathExtent]; static KeySym key_symbol; /* Respond to a user key release. */ if (event.xkey.window != windows->widget.id) break; (void) XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); if (key_symbol == XK_Control_L) state&=(~ControlState); break; } case LeaveNotify: { if (event.xcrossing.window != windows->widget.id) break; state|=InactiveWidgetState; break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (state & InactiveWidgetState) break; if (action_info.raised == MatteIsActive(action_info,event.xmotion)) { /* Action button status changed. */ action_info.raised=action_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) { /* Cancel button status changed. */ cancel_info.raised=cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } break; } case SelectionClear: { reply_info.highlight=MagickFalse; XDrawMatteText(display,&windows->widget,&reply_info); break; } case SelectionNotify: { Atom type; int format; unsigned char *data; unsigned long after, length; /* Obtain response from primary selection. */ if (event.xselection.property == (Atom) None) break; status=XGetWindowProperty(display,event.xselection.requestor, event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type, &format,&length,&after,&data); if ((status != Success) || (type != XA_STRING) || (format == 32) || (length == 0)) break; if ((Extent(reply_info.text)+length) >= (MagickPathExtent-1)) (void) XBell(display,0); else { /* Insert primary selection in reply text. */ *(data+length)='\0'; XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, state); XDrawMatteText(display,&windows->widget,&reply_info); } (void) XFree((void *) data); break; } case SelectionRequest: { XSelectionEvent notify; XSelectionRequestEvent *request; if (reply_info.highlight == MagickFalse) break; /* Set primary selection. */ request=(&(event.xselectionrequest)); (void) XChangeProperty(request->display,request->requestor, request->property,request->target,8,PropModeReplace, (unsigned char *) primary_selection,Extent(primary_selection)); notify.type=SelectionNotify; notify.display=request->display; notify.requestor=request->requestor; notify.selection=request->selection; notify.target=request->target; notify.time=request->time; if (request->property == None) notify.property=request->target; else notify.property=request->property; (void) XSendEvent(request->display,request->requestor,False,0, (XEvent *) ¬ify); } default: break; } } while ((state & ExitState) == 0); XSetCursorState(display,windows,MagickFalse); (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); XCheckRefreshWindows(display,windows); if (anomaly) if (special_info.raised) if (*reply != '\0') raised=MagickTrue; return(raised == MagickFalse); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X F i l e B r o w s e r W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XFileBrowserWidget() displays a File Browser widget with a file query to the % user. The user keys a reply and presses the Action or Cancel button to % exit. The typed text is returned as the reply function parameter. % % The format of the XFileBrowserWidget method is: % % void XFileBrowserWidget(Display *display,XWindows *windows, % const char *action,char *reply) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o action: Specifies a pointer to the action of this widget. % % o reply: the response from the user is returned in this parameter. % */ MagickPrivate void XFileBrowserWidget(Display *display,XWindows *windows, const char *action,char *reply) { #define CancelButtonText "Cancel" #define DirectoryText "Directory:" #define FilenameText "File name:" #define GrabButtonText "Grab" #define FormatButtonText "Format" #define HomeButtonText "Home" #define UpButtonText "Up" char *directory, **filelist, home_directory[MagickPathExtent], primary_selection[MagickPathExtent], text[MagickPathExtent], working_path[MagickPathExtent]; int x, y; register ssize_t i; static char glob_pattern[MagickPathExtent] = "*", format[MagickPathExtent] = "miff"; static MagickStatusType mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); Status status; unsigned int anomaly, height, text_width, visible_files, width; size_t delay, files, state; XEvent event; XFontStruct *font_info; XTextProperty window_name; XWidgetInfo action_info, cancel_info, expose_info, special_info, list_info, home_info, north_info, reply_info, scroll_info, selection_info, slider_info, south_info, text_info, up_info; XWindowChanges window_changes; /* Read filelist from current directory. */ assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(action != (char *) NULL); assert(reply != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); XSetCursorState(display,windows,MagickTrue); XCheckRefreshWindows(display,windows); directory=getcwd(home_directory,MagickPathExtent); (void) directory; (void) CopyMagickString(working_path,home_directory,MagickPathExtent); filelist=ListFiles(working_path,glob_pattern,&files); if (filelist == (char **) NULL) { /* Directory read failed. */ XNoticeWidget(display,windows,"Unable to read directory:",working_path); (void) XDialogWidget(display,windows,action,"Enter filename:",reply); return; } /* Determine File Browser widget attributes. */ font_info=windows->widget.font_info; text_width=0; for (i=0; i < (ssize_t) files; i++) if (WidgetTextWidth(font_info,filelist[i]) > text_width) text_width=WidgetTextWidth(font_info,filelist[i]); width=WidgetTextWidth(font_info,(char *) action); if (WidgetTextWidth(font_info,GrabButtonText) > width) width=WidgetTextWidth(font_info,GrabButtonText); if (WidgetTextWidth(font_info,FormatButtonText) > width) width=WidgetTextWidth(font_info,FormatButtonText); if (WidgetTextWidth(font_info,CancelButtonText) > width) width=WidgetTextWidth(font_info,CancelButtonText); if (WidgetTextWidth(font_info,HomeButtonText) > width) width=WidgetTextWidth(font_info,HomeButtonText); if (WidgetTextWidth(font_info,UpButtonText) > width) width=WidgetTextWidth(font_info,UpButtonText); width+=QuantumMargin; if (WidgetTextWidth(font_info,DirectoryText) > width) width=WidgetTextWidth(font_info,DirectoryText); if (WidgetTextWidth(font_info,FilenameText) > width) width=WidgetTextWidth(font_info,FilenameText); height=(unsigned int) (font_info->ascent+font_info->descent); /* Position File Browser widget. */ windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+ 6*QuantumMargin; windows->widget.min_width=width+MinTextWidth+4*QuantumMargin; if (windows->widget.width < windows->widget.min_width) windows->widget.width=windows->widget.min_width; windows->widget.height=(unsigned int) (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4); windows->widget.min_height=(unsigned int) (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4); if (windows->widget.height < windows->widget.min_height) windows->widget.height=windows->widget.min_height; XConstrainWindowPosition(display,&windows->widget); /* Map File Browser widget. */ (void) CopyMagickString(windows->widget.name,"Browse and Select a File", MagickPathExtent); status=XStringListToTextProperty(&windows->widget.name,1,&window_name); if (status != False) { XSetWMName(display,windows->widget.id,&window_name); XSetWMIconName(display,windows->widget.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) windows->widget.width; window_changes.height=(int) windows->widget.height; window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id, windows->widget.screen,mask,&window_changes); (void) XMapRaised(display,windows->widget.id); windows->widget.mapped=MagickFalse; /* Respond to X events. */ XGetWidgetInfo((char *) NULL,&slider_info); XGetWidgetInfo((char *) NULL,&north_info); XGetWidgetInfo((char *) NULL,&south_info); XGetWidgetInfo((char *) NULL,&expose_info); visible_files=0; anomaly=(LocaleCompare(action,"Composite") == 0) || (LocaleCompare(action,"Open") == 0) || (LocaleCompare(action,"Map") == 0); *reply='\0'; delay=SuspendTime << 2; state=UpdateConfigurationState; do { if (state & UpdateConfigurationState) { int id; /* Initialize button information. */ XGetWidgetInfo(CancelButtonText,&cancel_info); cancel_info.width=width; cancel_info.height=(unsigned int) ((3*height) >> 1); cancel_info.x=(int) (windows->widget.width-cancel_info.width-QuantumMargin-2); cancel_info.y=(int) (windows->widget.height-cancel_info.height-QuantumMargin); XGetWidgetInfo(action,&action_info); action_info.width=width; action_info.height=(unsigned int) ((3*height) >> 1); action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+ (action_info.bevel_width << 1)); action_info.y=cancel_info.y; XGetWidgetInfo(GrabButtonText,&special_info); special_info.width=width; special_info.height=(unsigned int) ((3*height) >> 1); special_info.x=action_info.x-(action_info.width+(QuantumMargin >> 1)+ (special_info.bevel_width << 1)); special_info.y=action_info.y; if (anomaly == MagickFalse) { register char *p; special_info.text=(char *) FormatButtonText; p=reply+Extent(reply)-1; while ((p > (reply+1)) && (*(p-1) != '.')) p--; if ((p > (reply+1)) && (*(p-1) == '.')) (void) CopyMagickString(format,p,MagickPathExtent); } XGetWidgetInfo(UpButtonText,&up_info); up_info.width=width; up_info.height=(unsigned int) ((3*height) >> 1); up_info.x=QuantumMargin; up_info.y=((5*QuantumMargin) >> 1)+height; XGetWidgetInfo(HomeButtonText,&home_info); home_info.width=width; home_info.height=(unsigned int) ((3*height) >> 1); home_info.x=QuantumMargin; home_info.y=up_info.y+up_info.height+QuantumMargin; /* Initialize reply information. */ XGetWidgetInfo(reply,&reply_info); reply_info.raised=MagickFalse; reply_info.bevel_width--; reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1); reply_info.height=height << 1; reply_info.x=(int) (width+(QuantumMargin << 1)); reply_info.y=action_info.y-reply_info.height-QuantumMargin; /* Initialize scroll information. */ XGetWidgetInfo((char *) NULL,&scroll_info); scroll_info.bevel_width--; scroll_info.width=height; scroll_info.height=(unsigned int) (reply_info.y-up_info.y-(QuantumMargin >> 1)); scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width); scroll_info.y=up_info.y-reply_info.bevel_width; scroll_info.raised=MagickFalse; scroll_info.trough=MagickTrue; north_info=scroll_info; north_info.raised=MagickTrue; north_info.width-=(north_info.bevel_width << 1); north_info.height=north_info.width-1; north_info.x+=north_info.bevel_width; north_info.y+=north_info.bevel_width; south_info=north_info; south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- south_info.height; id=slider_info.id; slider_info=north_info; slider_info.id=id; slider_info.width-=2; slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ slider_info.bevel_width+2; slider_info.height=scroll_info.height-((slider_info.min_y- scroll_info.y+1) << 1)+4; visible_files=scroll_info.height/(height+(height >> 3)); if (files > visible_files) slider_info.height=(unsigned int) ((visible_files*slider_info.height)/files); slider_info.max_y=south_info.y-south_info.bevel_width- slider_info.bevel_width-2; slider_info.x=scroll_info.x+slider_info.bevel_width+1; slider_info.y=slider_info.min_y; expose_info=scroll_info; expose_info.y=slider_info.y; /* Initialize list information. */ XGetWidgetInfo((char *) NULL,&list_info); list_info.raised=MagickFalse; list_info.bevel_width--; list_info.width=(unsigned int) (scroll_info.x-reply_info.x-(QuantumMargin >> 1)); list_info.height=scroll_info.height; list_info.x=reply_info.x; list_info.y=scroll_info.y; if (windows->widget.mapped == MagickFalse) state|=JumpListState; /* Initialize text information. */ *text='\0'; XGetWidgetInfo(text,&text_info); text_info.center=MagickFalse; text_info.width=reply_info.width; text_info.height=height; text_info.x=list_info.x-(QuantumMargin >> 1); text_info.y=QuantumMargin; /* Initialize selection information. */ XGetWidgetInfo((char *) NULL,&selection_info); selection_info.center=MagickFalse; selection_info.width=list_info.width; selection_info.height=(unsigned int) ((9*height) >> 3); selection_info.x=list_info.x; state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw File Browser window. */ x=QuantumMargin; y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent; (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,DirectoryText, Extent(DirectoryText)); (void) CopyMagickString(text_info.text,working_path,MagickPathExtent); (void) ConcatenateMagickString(text_info.text,DirectorySeparator, MagickPathExtent); (void) ConcatenateMagickString(text_info.text,glob_pattern, MagickPathExtent); XDrawWidgetText(display,&windows->widget,&text_info); XDrawBeveledButton(display,&windows->widget,&up_info); XDrawBeveledButton(display,&windows->widget,&home_info); XDrawBeveledMatte(display,&windows->widget,&list_info); XDrawBeveledMatte(display,&windows->widget,&scroll_info); XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); x=QuantumMargin; y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent; (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,FilenameText, Extent(FilenameText)); XDrawBeveledMatte(display,&windows->widget,&reply_info); XDrawMatteText(display,&windows->widget,&reply_info); XDrawBeveledButton(display,&windows->widget,&special_info); XDrawBeveledButton(display,&windows->widget,&action_info); XDrawBeveledButton(display,&windows->widget,&cancel_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); selection_info.id=(~0); state|=RedrawListState; state&=(~RedrawWidgetState); } if (state & UpdateListState) { char **checklist; size_t number_files; /* Update file list. */ checklist=ListFiles(working_path,glob_pattern,&number_files); if (checklist == (char **) NULL) { /* Reply is a filename, exit. */ action_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } for (i=0; i < (ssize_t) files; i++) filelist[i]=DestroyString(filelist[i]); if (filelist != (char **) NULL) filelist=(char **) RelinquishMagickMemory(filelist); filelist=checklist; files=number_files; /* Update file list. */ slider_info.height= scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1; if (files > visible_files) slider_info.height=(unsigned int) ((visible_files*slider_info.height)/files); slider_info.max_y=south_info.y-south_info.bevel_width- slider_info.bevel_width-2; slider_info.id=0; slider_info.y=slider_info.min_y; expose_info.y=slider_info.y; selection_info.id=(~0); list_info.id=(~0); state|=RedrawListState; /* Redraw directory name & reply. */ if (IsGlob(reply_info.text) == MagickFalse) { *reply_info.text='\0'; reply_info.cursor=reply_info.text; } (void) CopyMagickString(text_info.text,working_path,MagickPathExtent); (void) ConcatenateMagickString(text_info.text,DirectorySeparator, MagickPathExtent); (void) ConcatenateMagickString(text_info.text,glob_pattern, MagickPathExtent); XDrawWidgetText(display,&windows->widget,&text_info); XDrawMatteText(display,&windows->widget,&reply_info); XDrawBeveledMatte(display,&windows->widget,&scroll_info); XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); state&=(~UpdateListState); } if (state & JumpListState) { /* Jump scroll to match user filename. */ list_info.id=(~0); for (i=0; i < (ssize_t) files; i++) if (LocaleCompare(filelist[i],reply) >= 0) { list_info.id=(int) (LocaleCompare(filelist[i],reply) == 0 ? i : ~0); break; } if ((i < (ssize_t) slider_info.id) || (i >= (ssize_t) (slider_info.id+visible_files))) slider_info.id=(int) i-(visible_files >> 1); selection_info.id=(~0); state|=RedrawListState; state&=(~JumpListState); } if (state & RedrawListState) { /* Determine slider id and position. */ if (slider_info.id >= (int) (files-visible_files)) slider_info.id=(int) (files-visible_files); if ((slider_info.id < 0) || (files <= visible_files)) slider_info.id=0; slider_info.y=slider_info.min_y; if (files > 0) slider_info.y+=(int) (slider_info.id*(slider_info.max_y- slider_info.min_y+1)/files); if (slider_info.id != selection_info.id) { /* Redraw scroll bar and file names. */ selection_info.id=slider_info.id; selection_info.y=list_info.y+(height >> 3)+2; for (i=0; i < (ssize_t) visible_files; i++) { selection_info.raised=(int) (slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse; selection_info.text=(char *) NULL; if ((slider_info.id+i) < (ssize_t) files) selection_info.text=filelist[slider_info.id+i]; XDrawWidgetText(display,&windows->widget,&selection_info); selection_info.y+=(int) selection_info.height; } /* Update slider. */ if (slider_info.y > expose_info.y) { expose_info.height=(unsigned int) slider_info.y-expose_info.y; expose_info.y=slider_info.y-expose_info.height- slider_info.bevel_width-1; } else { expose_info.height=(unsigned int) expose_info.y-slider_info.y; expose_info.y=slider_info.y+slider_info.height+ slider_info.bevel_width+1; } XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawMatte(display,&windows->widget,&expose_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); expose_info.y=slider_info.y; } state&=(~RedrawListState); } /* Wait for next event. */ if (north_info.raised && south_info.raised) (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); else { /* Brief delay before advancing scroll bar. */ XDelay(display,delay); delay=SuspendTime; (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); if (north_info.raised == MagickFalse) if (slider_info.id > 0) { /* Move slider up. */ slider_info.id--; state|=RedrawListState; } if (south_info.raised == MagickFalse) if (slider_info.id < (int) files) { /* Move slider down. */ slider_info.id++; state|=RedrawListState; } if (event.type != ButtonRelease) continue; } switch (event.type) { case ButtonPress: { if (MatteIsActive(slider_info,event.xbutton)) { /* Track slider. */ slider_info.active=MagickTrue; break; } if (MatteIsActive(north_info,event.xbutton)) if (slider_info.id > 0) { /* Move slider up. */ north_info.raised=MagickFalse; slider_info.id--; state|=RedrawListState; break; } if (MatteIsActive(south_info,event.xbutton)) if (slider_info.id < (int) files) { /* Move slider down. */ south_info.raised=MagickFalse; slider_info.id++; state|=RedrawListState; break; } if (MatteIsActive(scroll_info,event.xbutton)) { /* Move slider. */ if (event.xbutton.y < slider_info.y) slider_info.id-=(visible_files-1); else slider_info.id+=(visible_files-1); state|=RedrawListState; break; } if (MatteIsActive(list_info,event.xbutton)) { int id; /* User pressed file matte. */ id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ selection_info.height; if (id >= (int) files) break; (void) CopyMagickString(reply_info.text,filelist[id],MagickPathExtent); reply_info.highlight=MagickFalse; reply_info.marker=reply_info.text; reply_info.cursor=reply_info.text+Extent(reply_info.text); XDrawMatteText(display,&windows->widget,&reply_info); if (id == list_info.id) { register char *p; p=reply_info.text+strlen(reply_info.text)-1; if (*p == *DirectorySeparator) ChopPathComponents(reply_info.text,1); (void) ConcatenateMagickString(working_path,DirectorySeparator, MagickPathExtent); (void) ConcatenateMagickString(working_path,reply_info.text, MagickPathExtent); *reply='\0'; state|=UpdateListState; } selection_info.id=(~0); list_info.id=id; state|=RedrawListState; break; } if (MatteIsActive(up_info,event.xbutton)) { /* User pressed Up button. */ up_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&up_info); break; } if (MatteIsActive(home_info,event.xbutton)) { /* User pressed Home button. */ home_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&home_info); break; } if (MatteIsActive(special_info,event.xbutton)) { /* User pressed Special button. */ special_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&special_info); break; } if (MatteIsActive(action_info,event.xbutton)) { /* User pressed action button. */ action_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } if (MatteIsActive(cancel_info,event.xbutton)) { /* User pressed Cancel button. */ cancel_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) break; if (event.xbutton.button != Button2) { static Time click_time; /* Move text cursor to position of button press. */ x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); for (i=1; i <= (ssize_t) Extent(reply_info.marker); i++) if (XTextWidth(font_info,reply_info.marker,(int) i) > x) break; reply_info.cursor=reply_info.marker+i-1; if (event.xbutton.time > (click_time+DoubleClick)) reply_info.highlight=MagickFalse; else { /* Become the XA_PRIMARY selection owner. */ (void) CopyMagickString(primary_selection,reply_info.text, MagickPathExtent); (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, event.xbutton.time); reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == windows->widget.id ? MagickTrue : MagickFalse; } XDrawMatteText(display,&windows->widget,&reply_info); click_time=event.xbutton.time; break; } /* Request primary selection. */ (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, windows->widget.id,event.xbutton.time); break; } case ButtonRelease: { if (windows->widget.mapped == MagickFalse) break; if (north_info.raised == MagickFalse) { /* User released up button. */ delay=SuspendTime << 2; north_info.raised=MagickTrue; XDrawTriangleNorth(display,&windows->widget,&north_info); } if (south_info.raised == MagickFalse) { /* User released down button. */ delay=SuspendTime << 2; south_info.raised=MagickTrue; XDrawTriangleSouth(display,&windows->widget,&south_info); } if (slider_info.active) { /* Stop tracking slider. */ slider_info.active=MagickFalse; break; } if (up_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(up_info,event.xbutton)) { ChopPathComponents(working_path,1); if (*working_path == '\0') (void) CopyMagickString(working_path,DirectorySeparator, MagickPathExtent); state|=UpdateListState; } up_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&up_info); } if (home_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(home_info,event.xbutton)) { (void) CopyMagickString(working_path,home_directory, MagickPathExtent); state|=UpdateListState; } home_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&home_info); } if (special_info.raised == MagickFalse) { if (anomaly == MagickFalse) { char **formats; ExceptionInfo *exception; size_t number_formats; /* Let user select image format. */ exception=AcquireExceptionInfo(); formats=GetMagickList("*",&number_formats,exception); exception=DestroyExceptionInfo(exception); if (formats == (char **) NULL) break; (void) XCheckDefineCursor(display,windows->widget.id, windows->widget.busy_cursor); windows->popup.x=windows->widget.x+60; windows->popup.y=windows->widget.y+60; XListBrowserWidget(display,windows,&windows->popup, (const char **) formats,"Select","Select image format type:", format); XSetCursorState(display,windows,MagickTrue); (void) XCheckDefineCursor(display,windows->widget.id, windows->widget.cursor); LocaleLower(format); AppendImageFormat(format,reply_info.text); reply_info.cursor=reply_info.text+Extent(reply_info.text); XDrawMatteText(display,&windows->widget,&reply_info); special_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&special_info); for (i=0; i < (ssize_t) number_formats; i++) formats[i]=DestroyString(formats[i]); formats=(char **) RelinquishMagickMemory(formats); break; } if (event.xbutton.window == windows->widget.id) if (MatteIsActive(special_info,event.xbutton)) { (void) CopyMagickString(working_path,"x:",MagickPathExtent); state|=ExitState; } special_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&special_info); } if (action_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) { if (MatteIsActive(action_info,event.xbutton)) { if (*reply_info.text == '\0') (void) XBell(display,0); else state|=ExitState; } } action_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&action_info); } if (cancel_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(cancel_info,event.xbutton)) { *reply_info.text='\0'; *reply='\0'; state|=ExitState; } cancel_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&cancel_info); } break; } case ClientMessage: { /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (int) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (int) windows->wm_delete_window) break; if (event.xclient.window == windows->widget.id) { *reply_info.text='\0'; state|=ExitState; break; } break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != windows->widget.id) break; if ((event.xconfigure.width == (int) windows->widget.width) && (event.xconfigure.height == (int) windows->widget.height)) break; windows->widget.width=(unsigned int) MagickMax(event.xconfigure.width,(int) windows->widget.min_width); windows->widget.height=(unsigned int) MagickMax(event.xconfigure.height,(int) windows->widget.min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != windows->widget.id) break; state&=(~InactiveWidgetState); break; } case Expose: { if (event.xexpose.window != windows->widget.id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case KeyPress: { static char command[MagickPathExtent]; static int length; static KeySym key_symbol; /* Respond to a user key press. */ if (event.xkey.window != windows->widget.id) break; length=XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); *(command+length)='\0'; if (AreaIsActive(scroll_info,event.xkey)) { /* Move slider. */ switch ((int) key_symbol) { case XK_Home: case XK_KP_Home: { slider_info.id=0; break; } case XK_Up: case XK_KP_Up: { slider_info.id--; break; } case XK_Down: case XK_KP_Down: { slider_info.id++; break; } case XK_Prior: case XK_KP_Prior: { slider_info.id-=visible_files; break; } case XK_Next: case XK_KP_Next: { slider_info.id+=visible_files; break; } case XK_End: case XK_KP_End: { slider_info.id=(int) files; break; } } state|=RedrawListState; break; } if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) { /* Read new directory or glob patterm. */ if (*reply_info.text == '\0') break; if (IsGlob(reply_info.text)) (void) CopyMagickString(glob_pattern,reply_info.text, MagickPathExtent); else { (void) ConcatenateMagickString(working_path,DirectorySeparator, MagickPathExtent); (void) ConcatenateMagickString(working_path,reply_info.text, MagickPathExtent); if (*working_path == '~') ExpandFilename(working_path); *reply='\0'; } state|=UpdateListState; break; } if (key_symbol == XK_Control_L) { state|=ControlState; break; } if (state & ControlState) switch ((int) key_symbol) { case XK_u: case XK_U: { /* Erase the entire line of text. */ *reply_info.text='\0'; reply_info.cursor=reply_info.text; reply_info.marker=reply_info.text; reply_info.highlight=MagickFalse; break; } default: break; } XEditText(display,&reply_info,key_symbol,command,state); XDrawMatteText(display,&windows->widget,&reply_info); state|=JumpListState; break; } case KeyRelease: { static char command[MagickPathExtent]; static KeySym key_symbol; /* Respond to a user key release. */ if (event.xkey.window != windows->widget.id) break; (void) XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); if (key_symbol == XK_Control_L) state&=(~ControlState); break; } case LeaveNotify: { if (event.xcrossing.window != windows->widget.id) break; state|=InactiveWidgetState; break; } case MapNotify: { mask&=(~CWX); mask&=(~CWY); break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (slider_info.active) { /* Move slider matte. */ slider_info.y=event.xmotion.y- ((slider_info.height+slider_info.bevel_width) >> 1)+1; if (slider_info.y < slider_info.min_y) slider_info.y=slider_info.min_y; if (slider_info.y > slider_info.max_y) slider_info.y=slider_info.max_y; slider_info.id=0; if (slider_info.y != slider_info.min_y) slider_info.id=(int) ((files*(slider_info.y-slider_info.min_y+1))/ (slider_info.max_y-slider_info.min_y+1)); state|=RedrawListState; break; } if (state & InactiveWidgetState) break; if (up_info.raised == MatteIsActive(up_info,event.xmotion)) { /* Up button status changed. */ up_info.raised=!up_info.raised; XDrawBeveledButton(display,&windows->widget,&up_info); break; } if (home_info.raised == MatteIsActive(home_info,event.xmotion)) { /* Home button status changed. */ home_info.raised=!home_info.raised; XDrawBeveledButton(display,&windows->widget,&home_info); break; } if (special_info.raised == MatteIsActive(special_info,event.xmotion)) { /* Grab button status changed. */ special_info.raised=!special_info.raised; XDrawBeveledButton(display,&windows->widget,&special_info); break; } if (action_info.raised == MatteIsActive(action_info,event.xmotion)) { /* Action button status changed. */ action_info.raised=action_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) { /* Cancel button status changed. */ cancel_info.raised=cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } break; } case SelectionClear: { reply_info.highlight=MagickFalse; XDrawMatteText(display,&windows->widget,&reply_info); break; } case SelectionNotify: { Atom type; int format; unsigned char *data; unsigned long after, length; /* Obtain response from primary selection. */ if (event.xselection.property == (Atom) None) break; status=XGetWindowProperty(display,event.xselection.requestor, event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type, &format,&length,&after,&data); if ((status != Success) || (type != XA_STRING) || (format == 32) || (length == 0)) break; if ((Extent(reply_info.text)+length) >= (MagickPathExtent-1)) (void) XBell(display,0); else { /* Insert primary selection in reply text. */ *(data+length)='\0'; XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, state); XDrawMatteText(display,&windows->widget,&reply_info); state|=JumpListState; state|=RedrawActionState; } (void) XFree((void *) data); break; } case SelectionRequest: { XSelectionEvent notify; XSelectionRequestEvent *request; if (reply_info.highlight == MagickFalse) break; /* Set primary selection. */ request=(&(event.xselectionrequest)); (void) XChangeProperty(request->display,request->requestor, request->property,request->target,8,PropModeReplace, (unsigned char *) primary_selection,Extent(primary_selection)); notify.type=SelectionNotify; notify.display=request->display; notify.requestor=request->requestor; notify.selection=request->selection; notify.target=request->target; notify.time=request->time; if (request->property == None) notify.property=request->target; else notify.property=request->property; (void) XSendEvent(request->display,request->requestor,False,0, (XEvent *) ¬ify); } default: break; } } while ((state & ExitState) == 0); XSetCursorState(display,windows,MagickFalse); (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); XCheckRefreshWindows(display,windows); /* Free file list. */ for (i=0; i < (ssize_t) files; i++) filelist[i]=DestroyString(filelist[i]); if (filelist != (char **) NULL) filelist=(char **) RelinquishMagickMemory(filelist); if (*reply != '\0') { (void) ConcatenateMagickString(working_path,DirectorySeparator, MagickPathExtent); (void) ConcatenateMagickString(working_path,reply,MagickPathExtent); } (void) CopyMagickString(reply,working_path,MagickPathExtent); if (*reply == '~') ExpandFilename(reply); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X F o n t B r o w s e r W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XFontBrowserWidget() displays a Font Browser widget with a font query to the % user. The user keys a reply and presses the Action or Cancel button to % exit. The typed text is returned as the reply function parameter. % % The format of the XFontBrowserWidget method is: % % void XFontBrowserWidget(Display *display,XWindows *windows, % const char *action,char *reply) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o action: Specifies a pointer to the action of this widget. % % o reply: the response from the user is returned in this parameter. % % */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif static int FontCompare(const void *x,const void *y) { register char *p, *q; p=(char *) *((char **) x); q=(char *) *((char **) y); while ((*p != '\0') && (*q != '\0') && (*p == *q)) { p++; q++; } return(*p-(*q)); } #if defined(__cplusplus) || defined(c_plusplus) } #endif MagickPrivate void XFontBrowserWidget(Display *display,XWindows *windows, const char *action,char *reply) { #define BackButtonText "Back" #define CancelButtonText "Cancel" #define FontnameText "Name:" #define FontPatternText "Pattern:" #define ResetButtonText "Reset" char back_pattern[MagickPathExtent], **fontlist, **listhead, primary_selection[MagickPathExtent], reset_pattern[MagickPathExtent], text[MagickPathExtent]; int fonts, x, y; register int i; static char glob_pattern[MagickPathExtent] = "*"; static MagickStatusType mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); Status status; unsigned int height, text_width, visible_fonts, width; size_t delay, state; XEvent event; XFontStruct *font_info; XTextProperty window_name; XWidgetInfo action_info, back_info, cancel_info, expose_info, list_info, mode_info, north_info, reply_info, reset_info, scroll_info, selection_info, slider_info, south_info, text_info; XWindowChanges window_changes; /* Get font list and sort in ascending order. */ assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(action != (char *) NULL); assert(reply != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); XSetCursorState(display,windows,MagickTrue); XCheckRefreshWindows(display,windows); (void) CopyMagickString(back_pattern,glob_pattern,MagickPathExtent); (void) CopyMagickString(reset_pattern,"*",MagickPathExtent); fontlist=XListFonts(display,glob_pattern,32767,&fonts); if (fonts == 0) { /* Pattern failed, obtain all the fonts. */ XNoticeWidget(display,windows,"Unable to obtain fonts names:", glob_pattern); (void) CopyMagickString(glob_pattern,"*",MagickPathExtent); fontlist=XListFonts(display,glob_pattern,32767,&fonts); if (fontlist == (char **) NULL) { XNoticeWidget(display,windows,"Unable to obtain fonts names:", glob_pattern); return; } } /* Sort font list in ascending order. */ listhead=fontlist; fontlist=(char **) AcquireQuantumMemory((size_t) fonts,sizeof(*fontlist)); if (fontlist == (char **) NULL) { XNoticeWidget(display,windows,"MemoryAllocationFailed", "UnableToViewFonts"); return; } for (i=0; i < fonts; i++) fontlist[i]=listhead[i]; qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare); /* Determine Font Browser widget attributes. */ font_info=windows->widget.font_info; text_width=0; for (i=0; i < fonts; i++) if (WidgetTextWidth(font_info,fontlist[i]) > text_width) text_width=WidgetTextWidth(font_info,fontlist[i]); width=WidgetTextWidth(font_info,(char *) action); if (WidgetTextWidth(font_info,CancelButtonText) > width) width=WidgetTextWidth(font_info,CancelButtonText); if (WidgetTextWidth(font_info,ResetButtonText) > width) width=WidgetTextWidth(font_info,ResetButtonText); if (WidgetTextWidth(font_info,BackButtonText) > width) width=WidgetTextWidth(font_info,BackButtonText); width+=QuantumMargin; if (WidgetTextWidth(font_info,FontPatternText) > width) width=WidgetTextWidth(font_info,FontPatternText); if (WidgetTextWidth(font_info,FontnameText) > width) width=WidgetTextWidth(font_info,FontnameText); height=(unsigned int) (font_info->ascent+font_info->descent); /* Position Font Browser widget. */ windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+ 6*QuantumMargin; windows->widget.min_width=width+MinTextWidth+4*QuantumMargin; if (windows->widget.width < windows->widget.min_width) windows->widget.width=windows->widget.min_width; windows->widget.height=(unsigned int) (((85*height) >> 2)+((13*QuantumMargin) >> 1)+4); windows->widget.min_height=(unsigned int) (((27*height) >> 1)+((13*QuantumMargin) >> 1)+4); if (windows->widget.height < windows->widget.min_height) windows->widget.height=windows->widget.min_height; XConstrainWindowPosition(display,&windows->widget); /* Map Font Browser widget. */ (void) CopyMagickString(windows->widget.name,"Browse and Select a Font", MagickPathExtent); status=XStringListToTextProperty(&windows->widget.name,1,&window_name); if (status != False) { XSetWMName(display,windows->widget.id,&window_name); XSetWMIconName(display,windows->widget.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) windows->widget.width; window_changes.height=(int) windows->widget.height; window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id, windows->widget.screen,mask,&window_changes); (void) XMapRaised(display,windows->widget.id); windows->widget.mapped=MagickFalse; /* Respond to X events. */ XGetWidgetInfo((char *) NULL,&slider_info); XGetWidgetInfo((char *) NULL,&north_info); XGetWidgetInfo((char *) NULL,&south_info); XGetWidgetInfo((char *) NULL,&expose_info); XGetWidgetInfo((char *) NULL,&selection_info); visible_fonts=0; delay=SuspendTime << 2; state=UpdateConfigurationState; do { if (state & UpdateConfigurationState) { int id; /* Initialize button information. */ XGetWidgetInfo(CancelButtonText,&cancel_info); cancel_info.width=width; cancel_info.height=(unsigned int) ((3*height) >> 1); cancel_info.x=(int) (windows->widget.width-cancel_info.width-QuantumMargin-2); cancel_info.y=(int) (windows->widget.height-cancel_info.height-QuantumMargin); XGetWidgetInfo(action,&action_info); action_info.width=width; action_info.height=(unsigned int) ((3*height) >> 1); action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+ (action_info.bevel_width << 1)); action_info.y=cancel_info.y; XGetWidgetInfo(BackButtonText,&back_info); back_info.width=width; back_info.height=(unsigned int) ((3*height) >> 1); back_info.x=QuantumMargin; back_info.y=((5*QuantumMargin) >> 1)+height; XGetWidgetInfo(ResetButtonText,&reset_info); reset_info.width=width; reset_info.height=(unsigned int) ((3*height) >> 1); reset_info.x=QuantumMargin; reset_info.y=back_info.y+back_info.height+QuantumMargin; /* Initialize reply information. */ XGetWidgetInfo(reply,&reply_info); reply_info.raised=MagickFalse; reply_info.bevel_width--; reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1); reply_info.height=height << 1; reply_info.x=(int) (width+(QuantumMargin << 1)); reply_info.y=action_info.y-(action_info.height << 1)-QuantumMargin; /* Initialize mode information. */ XGetWidgetInfo(reply,&mode_info); mode_info.bevel_width=0; mode_info.width=(unsigned int) (action_info.x-reply_info.x-QuantumMargin); mode_info.height=action_info.height << 1; mode_info.x=reply_info.x; mode_info.y=action_info.y-action_info.height+action_info.bevel_width; /* Initialize scroll information. */ XGetWidgetInfo((char *) NULL,&scroll_info); scroll_info.bevel_width--; scroll_info.width=height; scroll_info.height=(unsigned int) (reply_info.y-back_info.y-(QuantumMargin >> 1)); scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width); scroll_info.y=back_info.y-reply_info.bevel_width; scroll_info.raised=MagickFalse; scroll_info.trough=MagickTrue; north_info=scroll_info; north_info.raised=MagickTrue; north_info.width-=(north_info.bevel_width << 1); north_info.height=north_info.width-1; north_info.x+=north_info.bevel_width; north_info.y+=north_info.bevel_width; south_info=north_info; south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- south_info.height; id=slider_info.id; slider_info=north_info; slider_info.id=id; slider_info.width-=2; slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ slider_info.bevel_width+2; slider_info.height=scroll_info.height-((slider_info.min_y- scroll_info.y+1) << 1)+4; visible_fonts=scroll_info.height/(height+(height >> 3)); if (fonts > (int) visible_fonts) slider_info.height=(visible_fonts*slider_info.height)/fonts; slider_info.max_y=south_info.y-south_info.bevel_width- slider_info.bevel_width-2; slider_info.x=scroll_info.x+slider_info.bevel_width+1; slider_info.y=slider_info.min_y; expose_info=scroll_info; expose_info.y=slider_info.y; /* Initialize list information. */ XGetWidgetInfo((char *) NULL,&list_info); list_info.raised=MagickFalse; list_info.bevel_width--; list_info.width=(unsigned int) (scroll_info.x-reply_info.x-(QuantumMargin >> 1)); list_info.height=scroll_info.height; list_info.x=reply_info.x; list_info.y=scroll_info.y; if (windows->widget.mapped == MagickFalse) state|=JumpListState; /* Initialize text information. */ *text='\0'; XGetWidgetInfo(text,&text_info); text_info.center=MagickFalse; text_info.width=reply_info.width; text_info.height=height; text_info.x=list_info.x-(QuantumMargin >> 1); text_info.y=QuantumMargin; /* Initialize selection information. */ XGetWidgetInfo((char *) NULL,&selection_info); selection_info.center=MagickFalse; selection_info.width=list_info.width; selection_info.height=(unsigned int) ((9*height) >> 3); selection_info.x=list_info.x; state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw Font Browser window. */ x=QuantumMargin; y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent; (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,FontPatternText, Extent(FontPatternText)); (void) CopyMagickString(text_info.text,glob_pattern,MagickPathExtent); XDrawWidgetText(display,&windows->widget,&text_info); XDrawBeveledButton(display,&windows->widget,&back_info); XDrawBeveledButton(display,&windows->widget,&reset_info); XDrawBeveledMatte(display,&windows->widget,&list_info); XDrawBeveledMatte(display,&windows->widget,&scroll_info); XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); x=QuantumMargin; y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent; (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,FontnameText, Extent(FontnameText)); XDrawBeveledMatte(display,&windows->widget,&reply_info); XDrawMatteText(display,&windows->widget,&reply_info); XDrawBeveledButton(display,&windows->widget,&action_info); XDrawBeveledButton(display,&windows->widget,&cancel_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); selection_info.id=(~0); state|=RedrawActionState; state|=RedrawListState; state&=(~RedrawWidgetState); } if (state & UpdateListState) { char **checklist; int number_fonts; /* Update font list. */ checklist=XListFonts(display,glob_pattern,32767,&number_fonts); if (checklist == (char **) NULL) { if ((strchr(glob_pattern,'*') == (char *) NULL) && (strchr(glob_pattern,'?') == (char *) NULL)) { /* Might be a scaleable font-- exit. */ (void) CopyMagickString(reply,glob_pattern,MagickPathExtent); (void) CopyMagickString(glob_pattern,back_pattern,MagickPathExtent); action_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } (void) CopyMagickString(glob_pattern,back_pattern,MagickPathExtent); (void) XBell(display,0); } else if (number_fonts == 1) { /* Reply is a single font name-- exit. */ (void) CopyMagickString(reply,checklist[0],MagickPathExtent); (void) CopyMagickString(glob_pattern,back_pattern,MagickPathExtent); (void) XFreeFontNames(checklist); action_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } else { (void) XFreeFontNames(listhead); fontlist=(char **) RelinquishMagickMemory(fontlist); fontlist=checklist; fonts=number_fonts; } /* Sort font list in ascending order. */ listhead=fontlist; fontlist=(char **) AcquireQuantumMemory((size_t) fonts, sizeof(*fontlist)); if (fontlist == (char **) NULL) { XNoticeWidget(display,windows,"MemoryAllocationFailed", "UnableToViewFonts"); return; } for (i=0; i < fonts; i++) fontlist[i]=listhead[i]; qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare); slider_info.height= scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1; if (fonts > (int) visible_fonts) slider_info.height=(visible_fonts*slider_info.height)/fonts; slider_info.max_y=south_info.y-south_info.bevel_width- slider_info.bevel_width-2; slider_info.id=0; slider_info.y=slider_info.min_y; expose_info.y=slider_info.y; selection_info.id=(~0); list_info.id=(~0); state|=RedrawListState; /* Redraw font name & reply. */ *reply_info.text='\0'; reply_info.cursor=reply_info.text; (void) CopyMagickString(text_info.text,glob_pattern,MagickPathExtent); XDrawWidgetText(display,&windows->widget,&text_info); XDrawMatteText(display,&windows->widget,&reply_info); XDrawBeveledMatte(display,&windows->widget,&scroll_info); XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); state&=(~UpdateListState); } if (state & JumpListState) { /* Jump scroll to match user font. */ list_info.id=(~0); for (i=0; i < fonts; i++) if (LocaleCompare(fontlist[i],reply) >= 0) { list_info.id=LocaleCompare(fontlist[i],reply) == 0 ? i : ~0; break; } if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_fonts))) slider_info.id=i-(visible_fonts >> 1); selection_info.id=(~0); state|=RedrawListState; state&=(~JumpListState); } if (state & RedrawListState) { /* Determine slider id and position. */ if (slider_info.id >= (int) (fonts-visible_fonts)) slider_info.id=fonts-visible_fonts; if ((slider_info.id < 0) || (fonts <= (int) visible_fonts)) slider_info.id=0; slider_info.y=slider_info.min_y; if (fonts > 0) slider_info.y+= slider_info.id*(slider_info.max_y-slider_info.min_y+1)/fonts; if (slider_info.id != selection_info.id) { /* Redraw scroll bar and file names. */ selection_info.id=slider_info.id; selection_info.y=list_info.y+(height >> 3)+2; for (i=0; i < (int) visible_fonts; i++) { selection_info.raised=(slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse; selection_info.text=(char *) NULL; if ((slider_info.id+i) < fonts) selection_info.text=fontlist[slider_info.id+i]; XDrawWidgetText(display,&windows->widget,&selection_info); selection_info.y+=(int) selection_info.height; } /* Update slider. */ if (slider_info.y > expose_info.y) { expose_info.height=(unsigned int) slider_info.y-expose_info.y; expose_info.y=slider_info.y-expose_info.height- slider_info.bevel_width-1; } else { expose_info.height=(unsigned int) expose_info.y-slider_info.y; expose_info.y=slider_info.y+slider_info.height+ slider_info.bevel_width+1; } XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawMatte(display,&windows->widget,&expose_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); expose_info.y=slider_info.y; } state&=(~RedrawListState); } if (state & RedrawActionState) { XFontStruct *save_info; /* Display the selected font in a drawing area. */ save_info=windows->widget.font_info; font_info=XLoadQueryFont(display,reply_info.text); if (font_info != (XFontStruct *) NULL) { windows->widget.font_info=font_info; (void) XSetFont(display,windows->widget.widget_context, font_info->fid); } XDrawBeveledButton(display,&windows->widget,&mode_info); windows->widget.font_info=save_info; if (font_info != (XFontStruct *) NULL) { (void) XSetFont(display,windows->widget.widget_context, windows->widget.font_info->fid); (void) XFreeFont(display,font_info); } XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); XDrawMatteText(display,&windows->widget,&reply_info); state&=(~RedrawActionState); } /* Wait for next event. */ if (north_info.raised && south_info.raised) (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); else { /* Brief delay before advancing scroll bar. */ XDelay(display,delay); delay=SuspendTime; (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); if (north_info.raised == MagickFalse) if (slider_info.id > 0) { /* Move slider up. */ slider_info.id--; state|=RedrawListState; } if (south_info.raised == MagickFalse) if (slider_info.id < fonts) { /* Move slider down. */ slider_info.id++; state|=RedrawListState; } if (event.type != ButtonRelease) continue; } switch (event.type) { case ButtonPress: { if (MatteIsActive(slider_info,event.xbutton)) { /* Track slider. */ slider_info.active=MagickTrue; break; } if (MatteIsActive(north_info,event.xbutton)) if (slider_info.id > 0) { /* Move slider up. */ north_info.raised=MagickFalse; slider_info.id--; state|=RedrawListState; break; } if (MatteIsActive(south_info,event.xbutton)) if (slider_info.id < fonts) { /* Move slider down. */ south_info.raised=MagickFalse; slider_info.id++; state|=RedrawListState; break; } if (MatteIsActive(scroll_info,event.xbutton)) { /* Move slider. */ if (event.xbutton.y < slider_info.y) slider_info.id-=(visible_fonts-1); else slider_info.id+=(visible_fonts-1); state|=RedrawListState; break; } if (MatteIsActive(list_info,event.xbutton)) { int id; /* User pressed list matte. */ id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ selection_info.height; if (id >= (int) fonts) break; (void) CopyMagickString(reply_info.text,fontlist[id],MagickPathExtent); reply_info.highlight=MagickFalse; reply_info.marker=reply_info.text; reply_info.cursor=reply_info.text+Extent(reply_info.text); XDrawMatteText(display,&windows->widget,&reply_info); state|=RedrawActionState; if (id == list_info.id) { (void) CopyMagickString(glob_pattern,reply_info.text, MagickPathExtent); state|=UpdateListState; } selection_info.id=(~0); list_info.id=id; state|=RedrawListState; break; } if (MatteIsActive(back_info,event.xbutton)) { /* User pressed Back button. */ back_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&back_info); break; } if (MatteIsActive(reset_info,event.xbutton)) { /* User pressed Reset button. */ reset_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&reset_info); break; } if (MatteIsActive(action_info,event.xbutton)) { /* User pressed action button. */ action_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } if (MatteIsActive(cancel_info,event.xbutton)) { /* User pressed Cancel button. */ cancel_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) break; if (event.xbutton.button != Button2) { static Time click_time; /* Move text cursor to position of button press. */ x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); for (i=1; i <= Extent(reply_info.marker); i++) if (XTextWidth(font_info,reply_info.marker,i) > x) break; reply_info.cursor=reply_info.marker+i-1; if (event.xbutton.time > (click_time+DoubleClick)) reply_info.highlight=MagickFalse; else { /* Become the XA_PRIMARY selection owner. */ (void) CopyMagickString(primary_selection,reply_info.text, MagickPathExtent); (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, event.xbutton.time); reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == windows->widget.id ? MagickTrue : MagickFalse; } XDrawMatteText(display,&windows->widget,&reply_info); click_time=event.xbutton.time; break; } /* Request primary selection. */ (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, windows->widget.id,event.xbutton.time); break; } case ButtonRelease: { if (windows->widget.mapped == MagickFalse) break; if (north_info.raised == MagickFalse) { /* User released up button. */ delay=SuspendTime << 2; north_info.raised=MagickTrue; XDrawTriangleNorth(display,&windows->widget,&north_info); } if (south_info.raised == MagickFalse) { /* User released down button. */ delay=SuspendTime << 2; south_info.raised=MagickTrue; XDrawTriangleSouth(display,&windows->widget,&south_info); } if (slider_info.active) { /* Stop tracking slider. */ slider_info.active=MagickFalse; break; } if (back_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(back_info,event.xbutton)) { (void) CopyMagickString(glob_pattern,back_pattern, MagickPathExtent); state|=UpdateListState; } back_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&back_info); } if (reset_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(reset_info,event.xbutton)) { (void) CopyMagickString(back_pattern,glob_pattern,MagickPathExtent); (void) CopyMagickString(glob_pattern,reset_pattern,MagickPathExtent); state|=UpdateListState; } reset_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&reset_info); } if (action_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) { if (MatteIsActive(action_info,event.xbutton)) { if (*reply_info.text == '\0') (void) XBell(display,0); else state|=ExitState; } } action_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&action_info); } if (cancel_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(cancel_info,event.xbutton)) { *reply_info.text='\0'; state|=ExitState; } cancel_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&cancel_info); } break; } case ClientMessage: { /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (int) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (int) windows->wm_delete_window) break; if (event.xclient.window == windows->widget.id) { *reply_info.text='\0'; state|=ExitState; break; } break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != windows->widget.id) break; if ((event.xconfigure.width == (int) windows->widget.width) && (event.xconfigure.height == (int) windows->widget.height)) break; windows->widget.width=(unsigned int) MagickMax(event.xconfigure.width,(int) windows->widget.min_width); windows->widget.height=(unsigned int) MagickMax(event.xconfigure.height,(int) windows->widget.min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != windows->widget.id) break; state&=(~InactiveWidgetState); break; } case Expose: { if (event.xexpose.window != windows->widget.id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case KeyPress: { static char command[MagickPathExtent]; static int length; static KeySym key_symbol; /* Respond to a user key press. */ if (event.xkey.window != windows->widget.id) break; length=XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); *(command+length)='\0'; if (AreaIsActive(scroll_info,event.xkey)) { /* Move slider. */ switch ((int) key_symbol) { case XK_Home: case XK_KP_Home: { slider_info.id=0; break; } case XK_Up: case XK_KP_Up: { slider_info.id--; break; } case XK_Down: case XK_KP_Down: { slider_info.id++; break; } case XK_Prior: case XK_KP_Prior: { slider_info.id-=visible_fonts; break; } case XK_Next: case XK_KP_Next: { slider_info.id+=visible_fonts; break; } case XK_End: case XK_KP_End: { slider_info.id=fonts; break; } } state|=RedrawListState; break; } if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) { /* Read new font or glob patterm. */ if (*reply_info.text == '\0') break; (void) CopyMagickString(back_pattern,glob_pattern,MagickPathExtent); (void) CopyMagickString(glob_pattern,reply_info.text,MagickPathExtent); state|=UpdateListState; break; } if (key_symbol == XK_Control_L) { state|=ControlState; break; } if (state & ControlState) switch ((int) key_symbol) { case XK_u: case XK_U: { /* Erase the entire line of text. */ *reply_info.text='\0'; reply_info.cursor=reply_info.text; reply_info.marker=reply_info.text; reply_info.highlight=MagickFalse; break; } default: break; } XEditText(display,&reply_info,key_symbol,command,state); XDrawMatteText(display,&windows->widget,&reply_info); state|=JumpListState; break; } case KeyRelease: { static char command[MagickPathExtent]; static KeySym key_symbol; /* Respond to a user key release. */ if (event.xkey.window != windows->widget.id) break; (void) XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); if (key_symbol == XK_Control_L) state&=(~ControlState); break; } case LeaveNotify: { if (event.xcrossing.window != windows->widget.id) break; state|=InactiveWidgetState; break; } case MapNotify: { mask&=(~CWX); mask&=(~CWY); break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (slider_info.active) { /* Move slider matte. */ slider_info.y=event.xmotion.y- ((slider_info.height+slider_info.bevel_width) >> 1)+1; if (slider_info.y < slider_info.min_y) slider_info.y=slider_info.min_y; if (slider_info.y > slider_info.max_y) slider_info.y=slider_info.max_y; slider_info.id=0; if (slider_info.y != slider_info.min_y) slider_info.id=(fonts*(slider_info.y-slider_info.min_y+1))/ (slider_info.max_y-slider_info.min_y+1); state|=RedrawListState; break; } if (state & InactiveWidgetState) break; if (back_info.raised == MatteIsActive(back_info,event.xmotion)) { /* Back button status changed. */ back_info.raised=!back_info.raised; XDrawBeveledButton(display,&windows->widget,&back_info); break; } if (reset_info.raised == MatteIsActive(reset_info,event.xmotion)) { /* Reset button status changed. */ reset_info.raised=!reset_info.raised; XDrawBeveledButton(display,&windows->widget,&reset_info); break; } if (action_info.raised == MatteIsActive(action_info,event.xmotion)) { /* Action button status changed. */ action_info.raised=action_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&action_info); break; } if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) { /* Cancel button status changed. */ cancel_info.raised=cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } break; } case SelectionClear: { reply_info.highlight=MagickFalse; XDrawMatteText(display,&windows->widget,&reply_info); break; } case SelectionNotify: { Atom type; int format; unsigned char *data; unsigned long after, length; /* Obtain response from primary selection. */ if (event.xselection.property == (Atom) None) break; status=XGetWindowProperty(display,event.xselection.requestor, event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type, &format,&length,&after,&data); if ((status != Success) || (type != XA_STRING) || (format == 32) || (length == 0)) break; if ((Extent(reply_info.text)+length) >= (MagickPathExtent-1)) (void) XBell(display,0); else { /* Insert primary selection in reply text. */ *(data+length)='\0'; XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, state); XDrawMatteText(display,&windows->widget,&reply_info); state|=JumpListState; state|=RedrawActionState; } (void) XFree((void *) data); break; } case SelectionRequest: { XSelectionEvent notify; XSelectionRequestEvent *request; /* Set XA_PRIMARY selection. */ request=(&(event.xselectionrequest)); (void) XChangeProperty(request->display,request->requestor, request->property,request->target,8,PropModeReplace, (unsigned char *) primary_selection,Extent(primary_selection)); notify.type=SelectionNotify; notify.display=request->display; notify.requestor=request->requestor; notify.selection=request->selection; notify.target=request->target; notify.time=request->time; if (request->property == None) notify.property=request->target; else notify.property=request->property; (void) XSendEvent(request->display,request->requestor,False,0, (XEvent *) ¬ify); } default: break; } } while ((state & ExitState) == 0); XSetCursorState(display,windows,MagickFalse); (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); XCheckRefreshWindows(display,windows); /* Free font list. */ (void) XFreeFontNames(listhead); fontlist=(char **) RelinquishMagickMemory(fontlist); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X I n f o W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XInfoWidget() displays text in the Info widget. The purpose is to inform % the user that what activity is currently being performed (e.g. reading % an image, rotating an image, etc.). % % The format of the XInfoWidget method is: % % void XInfoWidget(Display *display,XWindows *windows,const char *activity) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o activity: This character string reflects the current activity and is % displayed in the Info widget. % */ MagickPrivate void XInfoWidget(Display *display,XWindows *windows, const char *activity) { unsigned int height, margin, width; XFontStruct *font_info; XWindowChanges window_changes; /* Map Info widget. */ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(activity != (char *) NULL); font_info=windows->info.font_info; width=WidgetTextWidth(font_info,(char *) activity)+((3*QuantumMargin) >> 1)+4; height=(unsigned int) (((6*(font_info->ascent+font_info->descent)) >> 2)+4); if ((windows->info.width != width) || (windows->info.height != height)) { /* Size Info widget to accommodate the activity text. */ windows->info.width=width; windows->info.height=height; window_changes.width=(int) width; window_changes.height=(int) height; (void) XReconfigureWMWindow(display,windows->info.id,windows->info.screen, (unsigned int) (CWWidth | CWHeight),&window_changes); } if (windows->info.mapped == MagickFalse) { (void) XMapRaised(display,windows->info.id); windows->info.mapped=MagickTrue; } /* Initialize Info matte information. */ height=(unsigned int) (font_info->ascent+font_info->descent); XGetWidgetInfo(activity,&monitor_info); monitor_info.bevel_width--; margin=monitor_info.bevel_width+((windows->info.height-height) >> 1)-2; monitor_info.center=MagickFalse; monitor_info.x=(int) margin; monitor_info.y=(int) margin; monitor_info.width=windows->info.width-(margin << 1); monitor_info.height=windows->info.height-(margin << 1)+1; /* Draw Info widget. */ monitor_info.raised=MagickFalse; XDrawBeveledMatte(display,&windows->info,&monitor_info); monitor_info.raised=MagickTrue; XDrawWidgetText(display,&windows->info,&monitor_info); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X L i s t B r o w s e r W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XListBrowserWidget() displays a List Browser widget with a query to the % user. The user keys a reply or select a reply from the list. Finally, the % user presses the Action or Cancel button to exit. The typed text is % returned as the reply function parameter. % % The format of the XListBrowserWidget method is: % % void XListBrowserWidget(Display *display,XWindows *windows, % XWindowInfo *window_info,const char **list,const char *action, % const char *query,char *reply) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o list: Specifies a pointer to an array of strings. The user can % select from these strings as a possible reply value. % % o action: Specifies a pointer to the action of this widget. % % o query: Specifies a pointer to the query to present to the user. % % o reply: the response from the user is returned in this parameter. % */ MagickPrivate void XListBrowserWidget(Display *display,XWindows *windows, XWindowInfo *window_info,const char **list,const char *action, const char *query,char *reply) { #define CancelButtonText "Cancel" char primary_selection[MagickPathExtent]; int x; register int i; static MagickStatusType mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); Status status; unsigned int entries, height, text_width, visible_entries, width; size_t delay, state; XEvent event; XFontStruct *font_info; XTextProperty window_name; XWidgetInfo action_info, cancel_info, expose_info, list_info, north_info, reply_info, scroll_info, selection_info, slider_info, south_info, text_info; XWindowChanges window_changes; /* Count the number of entries in the list. */ assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(window_info != (XWindowInfo *) NULL); assert(list != (const char **) NULL); assert(action != (char *) NULL); assert(query != (char *) NULL); assert(reply != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); XSetCursorState(display,windows,MagickTrue); XCheckRefreshWindows(display,windows); if (list == (const char **) NULL) { XNoticeWidget(display,windows,"No text to browse:",(char *) NULL); return; } for (entries=0; ; entries++) if (list[entries] == (char *) NULL) break; /* Determine Font Browser widget attributes. */ font_info=window_info->font_info; text_width=WidgetTextWidth(font_info,(char *) query); for (i=0; i < (int) entries; i++) if (WidgetTextWidth(font_info,(char *) list[i]) > text_width) text_width=WidgetTextWidth(font_info,(char *) list[i]); width=WidgetTextWidth(font_info,(char *) action); if (WidgetTextWidth(font_info,CancelButtonText) > width) width=WidgetTextWidth(font_info,CancelButtonText); width+=QuantumMargin; height=(unsigned int) (font_info->ascent+font_info->descent); /* Position List Browser widget. */ window_info->width=(unsigned int) MagickMin((int) text_width,(int) MaxTextWidth)+((9*QuantumMargin) >> 1); window_info->min_width=(unsigned int) (MinTextWidth+4*QuantumMargin); if (window_info->width < window_info->min_width) window_info->width=window_info->min_width; window_info->height=(unsigned int) (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4); window_info->min_height=(unsigned int) (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4); if (window_info->height < window_info->min_height) window_info->height=window_info->min_height; XConstrainWindowPosition(display,window_info); /* Map List Browser widget. */ (void) CopyMagickString(window_info->name,"Browse",MagickPathExtent); status=XStringListToTextProperty(&window_info->name,1,&window_name); if (status != False) { XSetWMName(display,window_info->id,&window_name); XSetWMIconName(display,windows->widget.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) window_info->width; window_changes.height=(int) window_info->height; window_changes.x=window_info->x; window_changes.y=window_info->y; (void) XReconfigureWMWindow(display,window_info->id,window_info->screen,mask, &window_changes); (void) XMapRaised(display,window_info->id); window_info->mapped=MagickFalse; /* Respond to X events. */ XGetWidgetInfo((char *) NULL,&slider_info); XGetWidgetInfo((char *) NULL,&north_info); XGetWidgetInfo((char *) NULL,&south_info); XGetWidgetInfo((char *) NULL,&expose_info); XGetWidgetInfo((char *) NULL,&selection_info); visible_entries=0; delay=SuspendTime << 2; state=UpdateConfigurationState; do { if (state & UpdateConfigurationState) { int id; /* Initialize button information. */ XGetWidgetInfo(CancelButtonText,&cancel_info); cancel_info.width=width; cancel_info.height=(unsigned int) ((3*height) >> 1); cancel_info.x=(int) (window_info->width-cancel_info.width-QuantumMargin-2); cancel_info.y=(int) (window_info->height-cancel_info.height-QuantumMargin); XGetWidgetInfo(action,&action_info); action_info.width=width; action_info.height=(unsigned int) ((3*height) >> 1); action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+ (action_info.bevel_width << 1)); action_info.y=cancel_info.y; /* Initialize reply information. */ XGetWidgetInfo(reply,&reply_info); reply_info.raised=MagickFalse; reply_info.bevel_width--; reply_info.width=window_info->width-((4*QuantumMargin) >> 1); reply_info.height=height << 1; reply_info.x=QuantumMargin; reply_info.y=action_info.y-reply_info.height-QuantumMargin; /* Initialize scroll information. */ XGetWidgetInfo((char *) NULL,&scroll_info); scroll_info.bevel_width--; scroll_info.width=height; scroll_info.height=(unsigned int) (reply_info.y-((6*QuantumMargin) >> 1)-height); scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width); scroll_info.y=((5*QuantumMargin) >> 1)+height-reply_info.bevel_width; scroll_info.raised=MagickFalse; scroll_info.trough=MagickTrue; north_info=scroll_info; north_info.raised=MagickTrue; north_info.width-=(north_info.bevel_width << 1); north_info.height=north_info.width-1; north_info.x+=north_info.bevel_width; north_info.y+=north_info.bevel_width; south_info=north_info; south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- south_info.height; id=slider_info.id; slider_info=north_info; slider_info.id=id; slider_info.width-=2; slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ slider_info.bevel_width+2; slider_info.height=scroll_info.height-((slider_info.min_y- scroll_info.y+1) << 1)+4; visible_entries=scroll_info.height/(height+(height >> 3)); if (entries > visible_entries) slider_info.height=(visible_entries*slider_info.height)/entries; slider_info.max_y=south_info.y-south_info.bevel_width- slider_info.bevel_width-2; slider_info.x=scroll_info.x+slider_info.bevel_width+1; slider_info.y=slider_info.min_y; expose_info=scroll_info; expose_info.y=slider_info.y; /* Initialize list information. */ XGetWidgetInfo((char *) NULL,&list_info); list_info.raised=MagickFalse; list_info.bevel_width--; list_info.width=(unsigned int) (scroll_info.x-reply_info.x-(QuantumMargin >> 1)); list_info.height=scroll_info.height; list_info.x=reply_info.x; list_info.y=scroll_info.y; if (window_info->mapped == MagickFalse) for (i=0; i < (int) entries; i++) if (LocaleCompare(list[i],reply) == 0) { list_info.id=i; slider_info.id=i-(visible_entries >> 1); if (slider_info.id < 0) slider_info.id=0; } /* Initialize text information. */ XGetWidgetInfo(query,&text_info); text_info.width=reply_info.width; text_info.height=height; text_info.x=list_info.x-(QuantumMargin >> 1); text_info.y=QuantumMargin; /* Initialize selection information. */ XGetWidgetInfo((char *) NULL,&selection_info); selection_info.center=MagickFalse; selection_info.width=list_info.width; selection_info.height=(unsigned int) ((9*height) >> 3); selection_info.x=list_info.x; state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw List Browser window. */ XDrawWidgetText(display,window_info,&text_info); XDrawBeveledMatte(display,window_info,&list_info); XDrawBeveledMatte(display,window_info,&scroll_info); XDrawTriangleNorth(display,window_info,&north_info); XDrawBeveledButton(display,window_info,&slider_info); XDrawTriangleSouth(display,window_info,&south_info); XDrawBeveledMatte(display,window_info,&reply_info); XDrawMatteText(display,window_info,&reply_info); XDrawBeveledButton(display,window_info,&action_info); XDrawBeveledButton(display,window_info,&cancel_info); XHighlightWidget(display,window_info,BorderOffset,BorderOffset); selection_info.id=(~0); state|=RedrawActionState; state|=RedrawListState; state&=(~RedrawWidgetState); } if (state & RedrawListState) { /* Determine slider id and position. */ if (slider_info.id >= (int) (entries-visible_entries)) slider_info.id=(int) (entries-visible_entries); if ((slider_info.id < 0) || (entries <= visible_entries)) slider_info.id=0; slider_info.y=slider_info.min_y; if (entries > 0) slider_info.y+= slider_info.id*(slider_info.max_y-slider_info.min_y+1)/entries; if (slider_info.id != selection_info.id) { /* Redraw scroll bar and file names. */ selection_info.id=slider_info.id; selection_info.y=list_info.y+(height >> 3)+2; for (i=0; i < (int) visible_entries; i++) { selection_info.raised=(slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse; selection_info.text=(char *) NULL; if ((slider_info.id+i) < (int) entries) selection_info.text=(char *) list[slider_info.id+i]; XDrawWidgetText(display,window_info,&selection_info); selection_info.y+=(int) selection_info.height; } /* Update slider. */ if (slider_info.y > expose_info.y) { expose_info.height=(unsigned int) slider_info.y-expose_info.y; expose_info.y=slider_info.y-expose_info.height- slider_info.bevel_width-1; } else { expose_info.height=(unsigned int) expose_info.y-slider_info.y; expose_info.y=slider_info.y+slider_info.height+ slider_info.bevel_width+1; } XDrawTriangleNorth(display,window_info,&north_info); XDrawMatte(display,window_info,&expose_info); XDrawBeveledButton(display,window_info,&slider_info); XDrawTriangleSouth(display,window_info,&south_info); expose_info.y=slider_info.y; } state&=(~RedrawListState); } /* Wait for next event. */ if (north_info.raised && south_info.raised) (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); else { /* Brief delay before advancing scroll bar. */ XDelay(display,delay); delay=SuspendTime; (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); if (north_info.raised == MagickFalse) if (slider_info.id > 0) { /* Move slider up. */ slider_info.id--; state|=RedrawListState; } if (south_info.raised == MagickFalse) if (slider_info.id < (int) entries) { /* Move slider down. */ slider_info.id++; state|=RedrawListState; } if (event.type != ButtonRelease) continue; } switch (event.type) { case ButtonPress: { if (MatteIsActive(slider_info,event.xbutton)) { /* Track slider. */ slider_info.active=MagickTrue; break; } if (MatteIsActive(north_info,event.xbutton)) if (slider_info.id > 0) { /* Move slider up. */ north_info.raised=MagickFalse; slider_info.id--; state|=RedrawListState; break; } if (MatteIsActive(south_info,event.xbutton)) if (slider_info.id < (int) entries) { /* Move slider down. */ south_info.raised=MagickFalse; slider_info.id++; state|=RedrawListState; break; } if (MatteIsActive(scroll_info,event.xbutton)) { /* Move slider. */ if (event.xbutton.y < slider_info.y) slider_info.id-=(visible_entries-1); else slider_info.id+=(visible_entries-1); state|=RedrawListState; break; } if (MatteIsActive(list_info,event.xbutton)) { int id; /* User pressed list matte. */ id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ selection_info.height; if (id >= (int) entries) break; (void) CopyMagickString(reply_info.text,list[id],MagickPathExtent); reply_info.highlight=MagickFalse; reply_info.marker=reply_info.text; reply_info.cursor=reply_info.text+Extent(reply_info.text); XDrawMatteText(display,window_info,&reply_info); selection_info.id=(~0); if (id == list_info.id) { action_info.raised=MagickFalse; XDrawBeveledButton(display,window_info,&action_info); state|=ExitState; } list_info.id=id; state|=RedrawListState; break; } if (MatteIsActive(action_info,event.xbutton)) { /* User pressed action button. */ action_info.raised=MagickFalse; XDrawBeveledButton(display,window_info,&action_info); break; } if (MatteIsActive(cancel_info,event.xbutton)) { /* User pressed Cancel button. */ cancel_info.raised=MagickFalse; XDrawBeveledButton(display,window_info,&cancel_info); break; } if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) break; if (event.xbutton.button != Button2) { static Time click_time; /* Move text cursor to position of button press. */ x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); for (i=1; i <= Extent(reply_info.marker); i++) if (XTextWidth(font_info,reply_info.marker,i) > x) break; reply_info.cursor=reply_info.marker+i-1; if (event.xbutton.time > (click_time+DoubleClick)) reply_info.highlight=MagickFalse; else { /* Become the XA_PRIMARY selection owner. */ (void) CopyMagickString(primary_selection,reply_info.text, MagickPathExtent); (void) XSetSelectionOwner(display,XA_PRIMARY,window_info->id, event.xbutton.time); reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == window_info->id ? MagickTrue : MagickFalse; } XDrawMatteText(display,window_info,&reply_info); click_time=event.xbutton.time; break; } /* Request primary selection. */ (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, window_info->id,event.xbutton.time); break; } case ButtonRelease: { if (window_info->mapped == MagickFalse) break; if (north_info.raised == MagickFalse) { /* User released up button. */ delay=SuspendTime << 2; north_info.raised=MagickTrue; XDrawTriangleNorth(display,window_info,&north_info); } if (south_info.raised == MagickFalse) { /* User released down button. */ delay=SuspendTime << 2; south_info.raised=MagickTrue; XDrawTriangleSouth(display,window_info,&south_info); } if (slider_info.active) { /* Stop tracking slider. */ slider_info.active=MagickFalse; break; } if (action_info.raised == MagickFalse) { if (event.xbutton.window == window_info->id) { if (MatteIsActive(action_info,event.xbutton)) { if (*reply_info.text == '\0') (void) XBell(display,0); else state|=ExitState; } } action_info.raised=MagickTrue; XDrawBeveledButton(display,window_info,&action_info); } if (cancel_info.raised == MagickFalse) { if (event.xbutton.window == window_info->id) if (MatteIsActive(cancel_info,event.xbutton)) { *reply_info.text='\0'; state|=ExitState; } cancel_info.raised=MagickTrue; XDrawBeveledButton(display,window_info,&cancel_info); } if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) break; break; } case ClientMessage: { /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (int) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (int) windows->wm_delete_window) break; if (event.xclient.window == window_info->id) { *reply_info.text='\0'; state|=ExitState; break; } break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != window_info->id) break; if ((event.xconfigure.width == (int) window_info->width) && (event.xconfigure.height == (int) window_info->height)) break; window_info->width=(unsigned int) MagickMax(event.xconfigure.width,(int) window_info->min_width); window_info->height=(unsigned int) MagickMax(event.xconfigure.height,(int) window_info->min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != window_info->id) break; state&=(~InactiveWidgetState); break; } case Expose: { if (event.xexpose.window != window_info->id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case KeyPress: { static char command[MagickPathExtent]; static int length; static KeySym key_symbol; /* Respond to a user key press. */ if (event.xkey.window != window_info->id) break; length=XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); *(command+length)='\0'; if (AreaIsActive(scroll_info,event.xkey)) { /* Move slider. */ switch ((int) key_symbol) { case XK_Home: case XK_KP_Home: { slider_info.id=0; break; } case XK_Up: case XK_KP_Up: { slider_info.id--; break; } case XK_Down: case XK_KP_Down: { slider_info.id++; break; } case XK_Prior: case XK_KP_Prior: { slider_info.id-=visible_entries; break; } case XK_Next: case XK_KP_Next: { slider_info.id+=visible_entries; break; } case XK_End: case XK_KP_End: { slider_info.id=(int) entries; break; } } state|=RedrawListState; break; } if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) { /* Read new entry. */ if (*reply_info.text == '\0') break; action_info.raised=MagickFalse; XDrawBeveledButton(display,window_info,&action_info); state|=ExitState; break; } if (key_symbol == XK_Control_L) { state|=ControlState; break; } if (state & ControlState) switch ((int) key_symbol) { case XK_u: case XK_U: { /* Erase the entire line of text. */ *reply_info.text='\0'; reply_info.cursor=reply_info.text; reply_info.marker=reply_info.text; reply_info.highlight=MagickFalse; break; } default: break; } XEditText(display,&reply_info,key_symbol,command,state); XDrawMatteText(display,window_info,&reply_info); break; } case KeyRelease: { static char command[MagickPathExtent]; static KeySym key_symbol; /* Respond to a user key release. */ if (event.xkey.window != window_info->id) break; (void) XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); if (key_symbol == XK_Control_L) state&=(~ControlState); break; } case LeaveNotify: { if (event.xcrossing.window != window_info->id) break; state|=InactiveWidgetState; break; } case MapNotify: { mask&=(~CWX); mask&=(~CWY); break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (slider_info.active) { /* Move slider matte. */ slider_info.y=event.xmotion.y- ((slider_info.height+slider_info.bevel_width) >> 1)+1; if (slider_info.y < slider_info.min_y) slider_info.y=slider_info.min_y; if (slider_info.y > slider_info.max_y) slider_info.y=slider_info.max_y; slider_info.id=0; if (slider_info.y != slider_info.min_y) slider_info.id=(int) ((entries*(slider_info.y- slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1)); state|=RedrawListState; break; } if (state & InactiveWidgetState) break; if (action_info.raised == MatteIsActive(action_info,event.xmotion)) { /* Action button status changed. */ action_info.raised=action_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,window_info,&action_info); break; } if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) { /* Cancel button status changed. */ cancel_info.raised=cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,window_info,&cancel_info); break; } break; } case SelectionClear: { reply_info.highlight=MagickFalse; XDrawMatteText(display,window_info,&reply_info); break; } case SelectionNotify: { Atom type; int format; unsigned char *data; unsigned long after, length; /* Obtain response from primary selection. */ if (event.xselection.property == (Atom) None) break; status=XGetWindowProperty(display, event.xselection.requestor,event.xselection.property,0L,2047L, MagickTrue,XA_STRING,&type,&format,&length,&after,&data); if ((status != Success) || (type != XA_STRING) || (format == 32) || (length == 0)) break; if ((Extent(reply_info.text)+length) >= (MagickPathExtent-1)) (void) XBell(display,0); else { /* Insert primary selection in reply text. */ *(data+length)='\0'; XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, state); XDrawMatteText(display,window_info,&reply_info); state|=RedrawActionState; } (void) XFree((void *) data); break; } case SelectionRequest: { XSelectionEvent notify; XSelectionRequestEvent *request; if (reply_info.highlight == MagickFalse) break; /* Set primary selection. */ request=(&(event.xselectionrequest)); (void) XChangeProperty(request->display,request->requestor, request->property,request->target,8,PropModeReplace, (unsigned char *) primary_selection,Extent(primary_selection)); notify.type=SelectionNotify; notify.send_event=MagickTrue; notify.display=request->display; notify.requestor=request->requestor; notify.selection=request->selection; notify.target=request->target; notify.time=request->time; if (request->property == None) notify.property=request->target; else notify.property=request->property; (void) XSendEvent(request->display,request->requestor,False,NoEventMask, (XEvent *) ¬ify); } default: break; } } while ((state & ExitState) == 0); XSetCursorState(display,windows,MagickFalse); (void) XWithdrawWindow(display,window_info->id,window_info->screen); XCheckRefreshWindows(display,windows); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X M e n u W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XMenuWidget() maps a menu and returns the command pointed to by the user % when the button is released. % % The format of the XMenuWidget method is: % % int XMenuWidget(Display *display,XWindows *windows,const char *title, % const char **selections,char *item) % % A description of each parameter follows: % % o selection_number: Specifies the number of the selection that the % user choose. % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o title: Specifies a character string that describes the menu selections. % % o selections: Specifies a pointer to one or more strings that comprise % the choices in the menu. % % o item: Specifies a character array. The item selected from the menu % is returned here. % */ MagickPrivate int XMenuWidget(Display *display,XWindows *windows, const char *title,const char **selections,char *item) { Cursor cursor; int id, x, y; unsigned int height, number_selections, title_height, top_offset, width; size_t state; XEvent event; XFontStruct *font_info; XSetWindowAttributes window_attributes; XWidgetInfo highlight_info, menu_info, selection_info; XWindowChanges window_changes; /* Determine Menu widget attributes. */ assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(title != (char *) NULL); assert(selections != (const char **) NULL); assert(item != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title); font_info=windows->widget.font_info; windows->widget.width=submenu_info.active == 0 ? WidgetTextWidth(font_info,(char *) title) : 0; for (id=0; selections[id] != (char *) NULL; id++) { width=WidgetTextWidth(font_info,(char *) selections[id]); if (width > windows->widget.width) windows->widget.width=width; } number_selections=(unsigned int) id; XGetWidgetInfo((char *) NULL,&menu_info); title_height=(unsigned int) (submenu_info.active == 0 ? (3*(font_info->descent+font_info->ascent) >> 1)+5 : 2); width=WidgetTextWidth(font_info,(char *) title); height=(unsigned int) ((3*(font_info->ascent+font_info->descent)) >> 1); /* Position Menu widget. */ windows->widget.width+=QuantumMargin+(menu_info.bevel_width << 1); top_offset=title_height+menu_info.bevel_width-1; windows->widget.height=top_offset+number_selections*height+4; windows->widget.min_width=windows->widget.width; windows->widget.min_height=windows->widget.height; XQueryPosition(display,windows->widget.root,&x,&y); windows->widget.x=x-(QuantumMargin >> 1); if (submenu_info.active != 0) { windows->widget.x= windows->command.x+windows->command.width-QuantumMargin; toggle_info.raised=MagickTrue; XDrawTriangleEast(display,&windows->command,&toggle_info); } windows->widget.y=submenu_info.active == 0 ? y-(int) ((3*title_height) >> 2) : y; if (submenu_info.active != 0) windows->widget.y=windows->command.y+submenu_info.y; XConstrainWindowPosition(display,&windows->widget); /* Map Menu widget. */ window_attributes.override_redirect=MagickTrue; (void) XChangeWindowAttributes(display,windows->widget.id, (size_t) CWOverrideRedirect,&window_attributes); window_changes.width=(int) windows->widget.width; window_changes.height=(int) windows->widget.height; window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); (void) XMapRaised(display,windows->widget.id); windows->widget.mapped=MagickFalse; /* Respond to X events. */ selection_info.height=height; cursor=XCreateFontCursor(display,XC_right_ptr); (void) XCheckDefineCursor(display,windows->image.id,cursor); (void) XCheckDefineCursor(display,windows->command.id,cursor); (void) XCheckDefineCursor(display,windows->widget.id,cursor); state=UpdateConfigurationState; do { if (state & UpdateConfigurationState) { /* Initialize selection information. */ XGetWidgetInfo((char *) NULL,&menu_info); menu_info.bevel_width--; menu_info.width=windows->widget.width-((menu_info.bevel_width) << 1); menu_info.height=windows->widget.height-((menu_info.bevel_width) << 1); menu_info.x=(int) menu_info.bevel_width; menu_info.y=(int) menu_info.bevel_width; XGetWidgetInfo((char *) NULL,&selection_info); selection_info.center=MagickFalse; selection_info.width=menu_info.width; selection_info.height=height; selection_info.x=menu_info.x; highlight_info=selection_info; highlight_info.bevel_width--; highlight_info.width-=(highlight_info.bevel_width << 1); highlight_info.height-=(highlight_info.bevel_width << 1); highlight_info.x+=highlight_info.bevel_width; state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw Menu widget. */ if (submenu_info.active == 0) { y=(int) title_height; XSetBevelColor(display,&windows->widget,MagickFalse); (void) XDrawLine(display,windows->widget.id, windows->widget.widget_context,selection_info.x,y-1, (int) selection_info.width,y-1); XSetBevelColor(display,&windows->widget,MagickTrue); (void) XDrawLine(display,windows->widget.id, windows->widget.widget_context,selection_info.x,y, (int) selection_info.width,y); (void) XSetFillStyle(display,windows->widget.widget_context, FillSolid); } /* Draw menu selections. */ selection_info.center=MagickTrue; selection_info.y=(int) menu_info.bevel_width; selection_info.text=(char *) title; if (submenu_info.active == 0) XDrawWidgetText(display,&windows->widget,&selection_info); selection_info.center=MagickFalse; selection_info.y=(int) top_offset; for (id=0; id < (int) number_selections; id++) { selection_info.text=(char *) selections[id]; XDrawWidgetText(display,&windows->widget,&selection_info); highlight_info.y=selection_info.y+highlight_info.bevel_width; if (id == selection_info.id) XDrawBevel(display,&windows->widget,&highlight_info); selection_info.y+=(int) selection_info.height; } XDrawBevel(display,&windows->widget,&menu_info); state&=(~RedrawWidgetState); } if (number_selections > 2) { /* Redraw Menu line. */ y=(int) (top_offset+selection_info.height*(number_selections-1)); XSetBevelColor(display,&windows->widget,MagickFalse); (void) XDrawLine(display,windows->widget.id, windows->widget.widget_context,selection_info.x,y-1, (int) selection_info.width,y-1); XSetBevelColor(display,&windows->widget,MagickTrue); (void) XDrawLine(display,windows->widget.id, windows->widget.widget_context,selection_info.x,y, (int) selection_info.width,y); (void) XSetFillStyle(display,windows->widget.widget_context,FillSolid); } /* Wait for next event. */ (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); switch (event.type) { case ButtonPress: { if (event.xbutton.window != windows->widget.id) { /* exit menu. */ if (event.xbutton.window == windows->command.id) (void) XPutBackEvent(display,&event); selection_info.id=(~0); *item='\0'; state|=ExitState; break; } state&=(~InactiveWidgetState); id=(event.xbutton.y-top_offset)/(int) selection_info.height; selection_info.id=id; if ((id < 0) || (id >= (int) number_selections)) break; /* Highlight this selection. */ selection_info.y=(int) (top_offset+id*selection_info.height); selection_info.text=(char *) selections[id]; XDrawWidgetText(display,&windows->widget,&selection_info); highlight_info.y=selection_info.y+highlight_info.bevel_width; XDrawBevel(display,&windows->widget,&highlight_info); break; } case ButtonRelease: { if (windows->widget.mapped == MagickFalse) break; if (event.xbutton.window == windows->command.id) if ((state & InactiveWidgetState) == 0) break; /* exit menu. */ XSetCursorState(display,windows,MagickFalse); *item='\0'; state|=ExitState; break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != windows->widget.id) break; if ((event.xconfigure.width == (int) windows->widget.width) && (event.xconfigure.height == (int) windows->widget.height)) break; windows->widget.width=(unsigned int) MagickMax(event.xconfigure.width,(int) windows->widget.min_width); windows->widget.height=(unsigned int) MagickMax(event.xconfigure.height,(int) windows->widget.min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != windows->widget.id) break; if (event.xcrossing.state == 0) break; state&=(~InactiveWidgetState); id=((event.xcrossing.y-top_offset)/(int) selection_info.height); if ((selection_info.id >= 0) && (selection_info.id < (int) number_selections)) { /* Unhighlight last selection. */ if (id == selection_info.id) break; selection_info.y=(int) (top_offset+selection_info.id*selection_info.height); selection_info.text=(char *) selections[selection_info.id]; XDrawWidgetText(display,&windows->widget,&selection_info); } if ((id < 0) || (id >= (int) number_selections)) break; /* Highlight this selection. */ selection_info.id=id; selection_info.y=(int) (top_offset+selection_info.id*selection_info.height); selection_info.text=(char *) selections[selection_info.id]; XDrawWidgetText(display,&windows->widget,&selection_info); highlight_info.y=selection_info.y+highlight_info.bevel_width; XDrawBevel(display,&windows->widget,&highlight_info); break; } case Expose: { if (event.xexpose.window != windows->widget.id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case LeaveNotify: { if (event.xcrossing.window != windows->widget.id) break; state|=InactiveWidgetState; id=selection_info.id; if ((id < 0) || (id >= (int) number_selections)) break; /* Unhighlight last selection. */ selection_info.y=(int) (top_offset+id*selection_info.height); selection_info.id=(~0); selection_info.text=(char *) selections[id]; XDrawWidgetText(display,&windows->widget,&selection_info); break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (submenu_info.active != 0) if (event.xmotion.window == windows->command.id) { if ((state & InactiveWidgetState) == 0) { if (MatteIsActive(submenu_info,event.xmotion) == MagickFalse) { selection_info.id=(~0); *item='\0'; state|=ExitState; break; } } else if (WindowIsActive(windows->command,event.xmotion)) { selection_info.id=(~0); *item='\0'; state|=ExitState; break; } } if (event.xmotion.window != windows->widget.id) break; if (state & InactiveWidgetState) break; id=(event.xmotion.y-top_offset)/(int) selection_info.height; if ((selection_info.id >= 0) && (selection_info.id < (int) number_selections)) { /* Unhighlight last selection. */ if (id == selection_info.id) break; selection_info.y=(int) (top_offset+selection_info.id*selection_info.height); selection_info.text=(char *) selections[selection_info.id]; XDrawWidgetText(display,&windows->widget,&selection_info); } selection_info.id=id; if ((id < 0) || (id >= (int) number_selections)) break; /* Highlight this selection. */ selection_info.y=(int) (top_offset+id*selection_info.height); selection_info.text=(char *) selections[id]; XDrawWidgetText(display,&windows->widget,&selection_info); highlight_info.y=selection_info.y+highlight_info.bevel_width; XDrawBevel(display,&windows->widget,&highlight_info); break; } default: break; } } while ((state & ExitState) == 0); (void) XFreeCursor(display,cursor); window_attributes.override_redirect=MagickFalse; (void) XChangeWindowAttributes(display,windows->widget.id, (size_t) CWOverrideRedirect,&window_attributes); (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); XCheckRefreshWindows(display,windows); if (submenu_info.active != 0) { submenu_info.active=MagickFalse; toggle_info.raised=MagickFalse; XDrawTriangleEast(display,&windows->command,&toggle_info); } if ((selection_info.id < 0) || (selection_info.id >= (int) number_selections)) return(~0); (void) CopyMagickString(item,selections[selection_info.id],MagickPathExtent); return(selection_info.id); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X N o t i c e W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XNoticeWidget() displays a Notice widget with a notice to the user. The % function returns when the user presses the "Dismiss" button. % % The format of the XNoticeWidget method is: % % void XNoticeWidget(Display *display,XWindows *windows, % const char *reason,const char *description) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o reason: Specifies the message to display before terminating the % program. % % o description: Specifies any description to the message. % */ MagickPrivate void XNoticeWidget(Display *display,XWindows *windows, const char *reason,const char *description) { #define DismissButtonText "Dismiss" #define Timeout 8 const char *text; int x, y; Status status; time_t timer; unsigned int height, width; size_t state; XEvent event; XFontStruct *font_info; XTextProperty window_name; XWidgetInfo dismiss_info; XWindowChanges window_changes; /* Determine Notice widget attributes. */ assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(reason != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason); XDelay(display,SuspendTime << 3); /* avoid surpise with delay */ XSetCursorState(display,windows,MagickTrue); XCheckRefreshWindows(display,windows); font_info=windows->widget.font_info; width=WidgetTextWidth(font_info,DismissButtonText); text=GetLocaleExceptionMessage(XServerError,reason); if (text != (char *) NULL) if (WidgetTextWidth(font_info,(char *) text) > width) width=WidgetTextWidth(font_info,(char *) text); if (description != (char *) NULL) { text=GetLocaleExceptionMessage(XServerError,description); if (text != (char *) NULL) if (WidgetTextWidth(font_info,(char *) text) > width) width=WidgetTextWidth(font_info,(char *) text); } height=(unsigned int) (font_info->ascent+font_info->descent); /* Position Notice widget. */ windows->widget.width=width+4*QuantumMargin; windows->widget.min_width=width+QuantumMargin; if (windows->widget.width < windows->widget.min_width) windows->widget.width=windows->widget.min_width; windows->widget.height=(unsigned int) (12*height); windows->widget.min_height=(unsigned int) (7*height); if (windows->widget.height < windows->widget.min_height) windows->widget.height=windows->widget.min_height; XConstrainWindowPosition(display,&windows->widget); /* Map Notice widget. */ (void) CopyMagickString(windows->widget.name,"Notice",MagickPathExtent); status=XStringListToTextProperty(&windows->widget.name,1,&window_name); if (status != False) { XSetWMName(display,windows->widget.id,&window_name); XSetWMIconName(display,windows->widget.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) windows->widget.width; window_changes.height=(int) windows->widget.height; window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); (void) XMapRaised(display,windows->widget.id); windows->widget.mapped=MagickFalse; (void) XBell(display,0); /* Respond to X events. */ timer=time((time_t *) NULL)+Timeout; state=UpdateConfigurationState; do { if (time((time_t *) NULL) > timer) break; if (state & UpdateConfigurationState) { /* Initialize Dismiss button information. */ XGetWidgetInfo(DismissButtonText,&dismiss_info); dismiss_info.width=(unsigned int) QuantumMargin+ WidgetTextWidth(font_info,DismissButtonText); dismiss_info.height=(unsigned int) ((3*height) >> 1); dismiss_info.x=(int) ((windows->widget.width >> 1)-(dismiss_info.width >> 1)); dismiss_info.y=(int) (windows->widget.height-(dismiss_info.height << 1)); state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw Notice widget. */ width=WidgetTextWidth(font_info,(char *) reason); x=(int) ((windows->widget.width >> 1)-(width >> 1)); y=(int) ((windows->widget.height >> 1)-(height << 1)); (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,(char *) reason,Extent(reason)); if (description != (char *) NULL) { width=WidgetTextWidth(font_info,(char *) description); x=(int) ((windows->widget.width >> 1)-(width >> 1)); y+=height; (void) XDrawString(display,windows->widget.id, windows->widget.annotate_context,x,y,(char *) description, Extent(description)); } XDrawBeveledButton(display,&windows->widget,&dismiss_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); state&=(~RedrawWidgetState); } /* Wait for next event. */ if (XCheckIfEvent(display,&event,XScreenEvent,(char *) windows) == MagickFalse) { /* Do not block if delay > 0. */ XDelay(display,SuspendTime << 2); continue; } switch (event.type) { case ButtonPress: { if (MatteIsActive(dismiss_info,event.xbutton)) { /* User pressed Dismiss button. */ dismiss_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&dismiss_info); break; } break; } case ButtonRelease: { if (windows->widget.mapped == MagickFalse) break; if (dismiss_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(dismiss_info,event.xbutton)) state|=ExitState; dismiss_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&dismiss_info); } break; } case ClientMessage: { /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (int) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (int) windows->wm_delete_window) break; if (event.xclient.window == windows->widget.id) { state|=ExitState; break; } break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != windows->widget.id) break; if ((event.xconfigure.width == (int) windows->widget.width) && (event.xconfigure.height == (int) windows->widget.height)) break; windows->widget.width=(unsigned int) MagickMax(event.xconfigure.width,(int) windows->widget.min_width); windows->widget.height=(unsigned int) MagickMax(event.xconfigure.height,(int) windows->widget.min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != windows->widget.id) break; state&=(~InactiveWidgetState); break; } case Expose: { if (event.xexpose.window != windows->widget.id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case KeyPress: { static char command[MagickPathExtent]; static KeySym key_symbol; /* Respond to a user key press. */ if (event.xkey.window != windows->widget.id) break; (void) XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) { dismiss_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&dismiss_info); state|=ExitState; break; } break; } case LeaveNotify: { if (event.xcrossing.window != windows->widget.id) break; state|=InactiveWidgetState; break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (state & InactiveWidgetState) break; if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion)) { /* Dismiss button status changed. */ dismiss_info.raised= dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&dismiss_info); break; } break; } default: break; } } while ((state & ExitState) == 0); XSetCursorState(display,windows,MagickFalse); (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); XCheckRefreshWindows(display,windows); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X P r e f e r e n c e s W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XPreferencesWidget() displays a Preferences widget with program preferences. % If the user presses the Apply button, the preferences are stored in a % configuration file in the users' home directory. % % The format of the XPreferencesWidget method is: % % MagickBooleanType XPreferencesWidget(Display *display, % XResourceInfo *resource_info,XWindows *windows) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. % % o window: Specifies a pointer to a XWindows structure. % */ MagickPrivate MagickBooleanType XPreferencesWidget(Display *display, XResourceInfo *resource_info,XWindows *windows) { #define ApplyButtonText "Apply" #define CacheButtonText "%lu mega-bytes of memory in the undo edit cache " #define CancelButtonText "Cancel" #define NumberPreferences 8 static const char *Preferences[] = { "display image centered on a backdrop", "confirm on program exit", "confirm on image edits", "correct image for display gamma", "display warning messages", "apply Floyd/Steinberg error diffusion to image", "use a shared colormap for colormapped X visuals", "display images as an X server pixmap" }; char cache[MagickPathExtent]; int x, y; register int i; Status status; unsigned int height, text_width, width; size_t state; XEvent event; XFontStruct *font_info; XTextProperty window_name; XWidgetInfo apply_info, cache_info, cancel_info, preferences_info[NumberPreferences]; XWindowChanges window_changes; /* Determine Preferences widget attributes. */ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); assert(display != (Display *) NULL); assert(resource_info != (XResourceInfo *) NULL); assert(windows != (XWindows *) NULL); XCheckRefreshWindows(display,windows); font_info=windows->widget.font_info; text_width=WidgetTextWidth(font_info,CacheButtonText); for (i=0; i < NumberPreferences; i++) if (WidgetTextWidth(font_info,(char *) Preferences[i]) > text_width) text_width=WidgetTextWidth(font_info,(char *) Preferences[i]); width=WidgetTextWidth(font_info,ApplyButtonText); if (WidgetTextWidth(font_info,CancelButtonText) > width) width=WidgetTextWidth(font_info,CancelButtonText); width+=(unsigned int) QuantumMargin; height=(unsigned int) (font_info->ascent+font_info->descent); /* Position Preferences widget. */ windows->widget.width=(unsigned int) (MagickMax((int) (width << 1), (int) text_width)+6*QuantumMargin); windows->widget.min_width=(width << 1)+QuantumMargin; if (windows->widget.width < windows->widget.min_width) windows->widget.width=windows->widget.min_width; windows->widget.height=(unsigned int) (7*height+NumberPreferences*(height+(QuantumMargin >> 1))); windows->widget.min_height=(unsigned int) (7*height+NumberPreferences*(height+(QuantumMargin >> 1))); if (windows->widget.height < windows->widget.min_height) windows->widget.height=windows->widget.min_height; XConstrainWindowPosition(display,&windows->widget); /* Map Preferences widget. */ (void) CopyMagickString(windows->widget.name,"Preferences",MagickPathExtent); status=XStringListToTextProperty(&windows->widget.name,1,&window_name); if (status != False) { XSetWMName(display,windows->widget.id,&window_name); XSetWMIconName(display,windows->widget.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) windows->widget.width; window_changes.height=(int) windows->widget.height; window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); (void) XMapRaised(display,windows->widget.id); windows->widget.mapped=MagickFalse; /* Respond to X events. */ state=UpdateConfigurationState; XSetCursorState(display,windows,MagickTrue); do { if (state & UpdateConfigurationState) { /* Initialize button information. */ XGetWidgetInfo(CancelButtonText,&cancel_info); cancel_info.width=width; cancel_info.height=(unsigned int) (3*height) >> 1; cancel_info.x=(int) windows->widget.width-cancel_info.width- (QuantumMargin << 1); cancel_info.y=(int) windows->widget.height- cancel_info.height-QuantumMargin; XGetWidgetInfo(ApplyButtonText,&apply_info); apply_info.width=width; apply_info.height=(unsigned int) (3*height) >> 1; apply_info.x=QuantumMargin << 1; apply_info.y=cancel_info.y; y=(int) (height << 1); for (i=0; i < NumberPreferences; i++) { XGetWidgetInfo(Preferences[i],&preferences_info[i]); preferences_info[i].bevel_width--; preferences_info[i].width=(unsigned int) QuantumMargin >> 1; preferences_info[i].height=(unsigned int) QuantumMargin >> 1; preferences_info[i].x=QuantumMargin << 1; preferences_info[i].y=y; y+=height+(QuantumMargin >> 1); } preferences_info[0].raised=resource_info->backdrop == MagickFalse ? MagickTrue : MagickFalse; preferences_info[1].raised=resource_info->confirm_exit == MagickFalse ? MagickTrue : MagickFalse; preferences_info[2].raised=resource_info->confirm_edit == MagickFalse ? MagickTrue : MagickFalse; preferences_info[3].raised=resource_info->gamma_correct == MagickFalse ? MagickTrue : MagickFalse; preferences_info[4].raised=resource_info->display_warnings == MagickFalse ? MagickTrue : MagickFalse; preferences_info[5].raised= resource_info->quantize_info->dither_method == NoDitherMethod ? MagickTrue : MagickFalse; preferences_info[6].raised=resource_info->colormap != SharedColormap ? MagickTrue : MagickFalse; preferences_info[7].raised=resource_info->use_pixmap == MagickFalse ? MagickTrue : MagickFalse; (void) FormatLocaleString(cache,MagickPathExtent,CacheButtonText, (unsigned long) resource_info->undo_cache); XGetWidgetInfo(cache,&cache_info); cache_info.bevel_width--; cache_info.width=(unsigned int) QuantumMargin >> 1; cache_info.height=(unsigned int) QuantumMargin >> 1; cache_info.x=QuantumMargin << 1; cache_info.y=y; state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw Preferences widget. */ XDrawBeveledButton(display,&windows->widget,&apply_info); XDrawBeveledButton(display,&windows->widget,&cancel_info); for (i=0; i < NumberPreferences; i++) XDrawBeveledButton(display,&windows->widget,&preferences_info[i]); XDrawTriangleEast(display,&windows->widget,&cache_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); state&=(~RedrawWidgetState); } /* Wait for next event. */ (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); switch (event.type) { case ButtonPress: { if (MatteIsActive(apply_info,event.xbutton)) { /* User pressed Apply button. */ apply_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&apply_info); break; } if (MatteIsActive(cancel_info,event.xbutton)) { /* User pressed Cancel button. */ cancel_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } for (i=0; i < NumberPreferences; i++) if (MatteIsActive(preferences_info[i],event.xbutton)) { /* User pressed a Preferences button. */ preferences_info[i].raised=preferences_info[i].raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&preferences_info[i]); break; } if (MatteIsActive(cache_info,event.xbutton)) { /* User pressed Cache button. */ x=cache_info.x+cache_info.width+cache_info.bevel_width+ (QuantumMargin >> 1); y=cache_info.y+((cache_info.height-height) >> 1); width=WidgetTextWidth(font_info,cache); (void) XClearArea(display,windows->widget.id,x,y,width,height, False); resource_info->undo_cache<<=1; if (resource_info->undo_cache > 256) resource_info->undo_cache=1; (void) FormatLocaleString(cache,MagickPathExtent,CacheButtonText, (unsigned long) resource_info->undo_cache); cache_info.raised=MagickFalse; XDrawTriangleEast(display,&windows->widget,&cache_info); break; } break; } case ButtonRelease: { if (windows->widget.mapped == MagickFalse) break; if (apply_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(apply_info,event.xbutton)) state|=ExitState; apply_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&apply_info); apply_info.raised=MagickFalse; } if (cancel_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(cancel_info,event.xbutton)) state|=ExitState; cancel_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&cancel_info); } if (cache_info.raised == MagickFalse) { cache_info.raised=MagickTrue; XDrawTriangleEast(display,&windows->widget,&cache_info); } break; } case ClientMessage: { /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (int) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (int) windows->wm_delete_window) break; if (event.xclient.window == windows->widget.id) { state|=ExitState; break; } break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != windows->widget.id) break; if ((event.xconfigure.width == (int) windows->widget.width) && (event.xconfigure.height == (int) windows->widget.height)) break; windows->widget.width=(unsigned int) MagickMax(event.xconfigure.width,(int) windows->widget.min_width); windows->widget.height=(unsigned int) MagickMax(event.xconfigure.height,(int) windows->widget.min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != windows->widget.id) break; state&=(~InactiveWidgetState); break; } case Expose: { if (event.xexpose.window != windows->widget.id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case KeyPress: { static char command[MagickPathExtent]; static KeySym key_symbol; /* Respond to a user key press. */ if (event.xkey.window != windows->widget.id) break; (void) XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) { apply_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&apply_info); state|=ExitState; break; } break; } case LeaveNotify: { if (event.xcrossing.window != windows->widget.id) break; state|=InactiveWidgetState; break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (state & InactiveWidgetState) break; if (apply_info.raised == MatteIsActive(apply_info,event.xmotion)) { /* Apply button status changed. */ apply_info.raised= apply_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&apply_info); break; } if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) { /* Cancel button status changed. */ cancel_info.raised= cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&cancel_info); break; } break; } default: break; } } while ((state & ExitState) == 0); XSetCursorState(display,windows,MagickFalse); (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); XCheckRefreshWindows(display,windows); if (apply_info.raised) return(MagickFalse); /* Save user preferences to the client configuration file. */ resource_info->backdrop= preferences_info[0].raised == MagickFalse ? MagickTrue : MagickFalse; resource_info->confirm_exit= preferences_info[1].raised == MagickFalse ? MagickTrue : MagickFalse; resource_info->confirm_edit= preferences_info[2].raised == MagickFalse ? MagickTrue : MagickFalse; resource_info->gamma_correct= preferences_info[3].raised == MagickFalse ? MagickTrue : MagickFalse; resource_info->display_warnings= preferences_info[4].raised == MagickFalse ? MagickTrue : MagickFalse; resource_info->quantize_info->dither_method= preferences_info[5].raised == MagickFalse ? RiemersmaDitherMethod : NoDitherMethod; resource_info->colormap=SharedColormap; if (preferences_info[6].raised) resource_info->colormap=PrivateColormap; resource_info->use_pixmap= preferences_info[7].raised == MagickFalse ? MagickTrue : MagickFalse; XUserPreferences(resource_info); return(MagickTrue); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X P r o g r e s s M o n i t o r W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XProgressMonitorWidget() displays the progress a task is making in % completing a task. A span of zero toggles the active status. An inactive % state disables the progress monitor. % % The format of the XProgressMonitorWidget method is: % % void XProgressMonitorWidget(Display *display,XWindows *windows, % const char *task,const MagickOffsetType offset, % const MagickSizeType span) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o window: Specifies a pointer to a XWindows structure. % % o task: Identifies the task in progress. % % o offset: Specifies the offset position within the span which represents % how much progress has been made in completing a task. % % o span: Specifies the span relative to completing a task. % */ MagickPrivate void XProgressMonitorWidget(Display *display,XWindows *windows, const char *task,const MagickOffsetType offset,const MagickSizeType span) { unsigned int width; XEvent event; assert(display != (Display *) NULL); assert(windows != (XWindows *) NULL); assert(task != (const char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",task); if (span == 0) return; /* Update image windows if there is a pending expose event. */ while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event)) (void) XCommandWidget(display,windows,(const char **) NULL,&event); while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event)) XRefreshWindow(display,&windows->image,&event); while (XCheckTypedWindowEvent(display,windows->info.id,Expose,&event)) if (monitor_info.text != (char *) NULL) XInfoWidget(display,windows,monitor_info.text); /* Draw progress monitor bar to represent percent completion of a task. */ if ((windows->info.mapped == MagickFalse) || (task != monitor_info.text)) XInfoWidget(display,windows,task); width=(unsigned int) (((offset+1)*(windows->info.width- (2*monitor_info.x)))/span); if (width < monitor_info.width) { monitor_info.raised=MagickTrue; XDrawWidgetText(display,&windows->info,&monitor_info); monitor_info.raised=MagickFalse; } monitor_info.width=width; XDrawWidgetText(display,&windows->info,&monitor_info); (void) XFlush(display); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X T e x t V i e w W i d g e t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % XTextViewWidget() displays text in a Text View widget. % % The format of the XTextViewWidget method is: % % void XTextViewWidget(Display *display,const XResourceInfo *resource_info, % XWindows *windows,const MagickBooleanType mono,const char *title, % const char **textlist) % % A description of each parameter follows: % % o display: Specifies a connection to an X server; returned from % XOpenDisplay. % % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. % % o window: Specifies a pointer to a XWindows structure. % % o mono: Use mono-spaced font when displaying text. % % o title: This character string is displayed at the top of the widget % window. % % o textlist: This string list is displayed within the Text View widget. % */ MagickPrivate void XTextViewWidget(Display *display, const XResourceInfo *resource_info,XWindows *windows, const MagickBooleanType mono,const char *title,const char **textlist) { #define DismissButtonText "Dismiss" char primary_selection[MagickPathExtent]; register int i; static MagickStatusType mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); Status status; unsigned int height, lines, text_width, visible_lines, width; size_t delay, state; XEvent event; XFontStruct *font_info, *text_info; XTextProperty window_name; XWidgetInfo dismiss_info, expose_info, list_info, north_info, scroll_info, selection_info, slider_info, south_info; XWindowChanges window_changes; /* Convert text string to a text list. */ assert(display != (Display *) NULL); assert(resource_info != (XResourceInfo *) NULL); assert(windows != (XWindows *) NULL); assert(title != (const char *) NULL); assert(textlist != (const char **) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title); XSetCursorState(display,windows,MagickTrue); XCheckRefreshWindows(display,windows); if (textlist == (const char **) NULL) { XNoticeWidget(display,windows,"No text to view:",(char *) NULL); return; } /* Determine Text View widget attributes. */ font_info=windows->widget.font_info; text_info=(XFontStruct *) NULL; if (mono != MagickFalse) text_info=XBestFont(display,resource_info,MagickTrue); if (text_info == (XFontStruct *) NULL) text_info=windows->widget.font_info; text_width=0; for (i=0; textlist[i] != (char *) NULL; i++) if (WidgetTextWidth(text_info,(char *) textlist[i]) > text_width) text_width=(unsigned int) XTextWidth(text_info,(char *) textlist[i], MagickMin(Extent(textlist[i]),160)); lines=(unsigned int) i; width=WidgetTextWidth(font_info,DismissButtonText); width+=QuantumMargin; height=(unsigned int) (text_info->ascent+text_info->descent); /* Position Text View widget. */ windows->widget.width=(unsigned int) (MagickMin((int) text_width, (int) MaxTextWidth)+5*QuantumMargin); windows->widget.min_width=(unsigned int) (MinTextWidth+4*QuantumMargin); if (windows->widget.width < windows->widget.min_width) windows->widget.width=windows->widget.min_width; windows->widget.height=(unsigned int) (MagickMin(MagickMax((int) lines,3),32)* height+((13*height) >> 1)+((9*QuantumMargin) >> 1)); windows->widget.min_height=(unsigned int) (3*height+((13*height) >> 1)+((9* QuantumMargin) >> 1)); if (windows->widget.height < windows->widget.min_height) windows->widget.height=windows->widget.min_height; XConstrainWindowPosition(display,&windows->widget); /* Map Text View widget. */ (void) CopyMagickString(windows->widget.name,title,MagickPathExtent); status=XStringListToTextProperty(&windows->widget.name,1,&window_name); if (status != False) { XSetWMName(display,windows->widget.id,&window_name); XSetWMIconName(display,windows->widget.id,&window_name); (void) XFree((void *) window_name.value); } window_changes.width=(int) windows->widget.width; window_changes.height=(int) windows->widget.height; window_changes.x=windows->widget.x; window_changes.y=windows->widget.y; (void) XReconfigureWMWindow(display,windows->widget.id, windows->widget.screen,(unsigned int) mask,&window_changes); (void) XMapRaised(display,windows->widget.id); windows->widget.mapped=MagickFalse; /* Respond to X events. */ XGetWidgetInfo((char *) NULL,&slider_info); XGetWidgetInfo((char *) NULL,&north_info); XGetWidgetInfo((char *) NULL,&south_info); XGetWidgetInfo((char *) NULL,&expose_info); XGetWidgetInfo((char *) NULL,&selection_info); visible_lines=0; delay=SuspendTime << 2; height=(unsigned int) (font_info->ascent+font_info->descent); state=UpdateConfigurationState; do { if (state & UpdateConfigurationState) { int id; /* Initialize button information. */ XGetWidgetInfo(DismissButtonText,&dismiss_info); dismiss_info.width=width; dismiss_info.height=(unsigned int) ((3*height) >> 1); dismiss_info.x=(int) windows->widget.width-dismiss_info.width- QuantumMargin-2; dismiss_info.y=(int) windows->widget.height-dismiss_info.height- QuantumMargin; /* Initialize scroll information. */ XGetWidgetInfo((char *) NULL,&scroll_info); scroll_info.bevel_width--; scroll_info.width=height; scroll_info.height=(unsigned int) (dismiss_info.y-((5*QuantumMargin) >> 1)); scroll_info.x=(int) windows->widget.width-QuantumMargin- scroll_info.width; scroll_info.y=(3*QuantumMargin) >> 1; scroll_info.raised=MagickFalse; scroll_info.trough=MagickTrue; north_info=scroll_info; north_info.raised=MagickTrue; north_info.width-=(north_info.bevel_width << 1); north_info.height=north_info.width-1; north_info.x+=north_info.bevel_width; north_info.y+=north_info.bevel_width; south_info=north_info; south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- south_info.height; id=slider_info.id; slider_info=north_info; slider_info.id=id; slider_info.width-=2; slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ slider_info.bevel_width+2; slider_info.height=scroll_info.height-((slider_info.min_y- scroll_info.y+1) << 1)+4; visible_lines=scroll_info.height/(text_info->ascent+text_info->descent+ ((text_info->ascent+text_info->descent) >> 3)); if (lines > visible_lines) slider_info.height=(unsigned int) (visible_lines*slider_info.height)/ lines; slider_info.max_y=south_info.y-south_info.bevel_width- slider_info.bevel_width-2; slider_info.x=scroll_info.x+slider_info.bevel_width+1; slider_info.y=slider_info.min_y; expose_info=scroll_info; expose_info.y=slider_info.y; /* Initialize list information. */ XGetWidgetInfo((char *) NULL,&list_info); list_info.raised=MagickFalse; list_info.bevel_width--; list_info.width=(unsigned int) scroll_info.x-((3*QuantumMargin) >> 1); list_info.height=scroll_info.height; list_info.x=QuantumMargin; list_info.y=scroll_info.y; /* Initialize selection information. */ XGetWidgetInfo((char *) NULL,&selection_info); selection_info.center=MagickFalse; selection_info.width=list_info.width; selection_info.height=(unsigned int) (9*(text_info->ascent+text_info->descent)) >> 3; selection_info.x=list_info.x; state&=(~UpdateConfigurationState); } if (state & RedrawWidgetState) { /* Redraw Text View window. */ XDrawBeveledMatte(display,&windows->widget,&list_info); XDrawBeveledMatte(display,&windows->widget,&scroll_info); XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); XDrawBeveledButton(display,&windows->widget,&dismiss_info); XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); selection_info.id=(~0); state|=RedrawListState; state&=(~RedrawWidgetState); } if (state & RedrawListState) { /* Determine slider id and position. */ if (slider_info.id >= (int) (lines-visible_lines)) slider_info.id=(int) lines-visible_lines; if ((slider_info.id < 0) || (lines <= visible_lines)) slider_info.id=0; slider_info.y=slider_info.min_y; if (lines != 0) slider_info.y+= slider_info.id*(slider_info.max_y-slider_info.min_y+1)/lines; if (slider_info.id != selection_info.id) { /* Redraw scroll bar and text. */ windows->widget.font_info=text_info; (void) XSetFont(display,windows->widget.annotate_context, text_info->fid); (void) XSetFont(display,windows->widget.highlight_context, text_info->fid); selection_info.id=slider_info.id; selection_info.y=list_info.y+(height >> 3)+2; for (i=0; i < (int) visible_lines; i++) { selection_info.raised= (slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse; selection_info.text=(char *) NULL; if ((slider_info.id+i) < (int) lines) selection_info.text=(char *) textlist[slider_info.id+i]; XDrawWidgetText(display,&windows->widget,&selection_info); selection_info.y+=(int) selection_info.height; } windows->widget.font_info=font_info; (void) XSetFont(display,windows->widget.annotate_context, font_info->fid); (void) XSetFont(display,windows->widget.highlight_context, font_info->fid); /* Update slider. */ if (slider_info.y > expose_info.y) { expose_info.height=(unsigned int) slider_info.y-expose_info.y; expose_info.y=slider_info.y-expose_info.height- slider_info.bevel_width-1; } else { expose_info.height=(unsigned int) expose_info.y-slider_info.y; expose_info.y=slider_info.y+slider_info.height+ slider_info.bevel_width+1; } XDrawTriangleNorth(display,&windows->widget,&north_info); XDrawMatte(display,&windows->widget,&expose_info); XDrawBeveledButton(display,&windows->widget,&slider_info); XDrawTriangleSouth(display,&windows->widget,&south_info); expose_info.y=slider_info.y; } state&=(~RedrawListState); } /* Wait for next event. */ if (north_info.raised && south_info.raised) (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); else { /* Brief delay before advancing scroll bar. */ XDelay(display,delay); delay=SuspendTime; (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); if (north_info.raised == MagickFalse) if (slider_info.id > 0) { /* Move slider up. */ slider_info.id--; state|=RedrawListState; } if (south_info.raised == MagickFalse) if (slider_info.id < (int) lines) { /* Move slider down. */ slider_info.id++; state|=RedrawListState; } if (event.type != ButtonRelease) continue; } switch (event.type) { case ButtonPress: { if (MatteIsActive(slider_info,event.xbutton)) { /* Track slider. */ slider_info.active=MagickTrue; break; } if (MatteIsActive(north_info,event.xbutton)) if (slider_info.id > 0) { /* Move slider up. */ north_info.raised=MagickFalse; slider_info.id--; state|=RedrawListState; break; } if (MatteIsActive(south_info,event.xbutton)) if (slider_info.id < (int) lines) { /* Move slider down. */ south_info.raised=MagickFalse; slider_info.id++; state|=RedrawListState; break; } if (MatteIsActive(scroll_info,event.xbutton)) { /* Move slider. */ if (event.xbutton.y < slider_info.y) slider_info.id-=(visible_lines-1); else slider_info.id+=(visible_lines-1); state|=RedrawListState; break; } if (MatteIsActive(dismiss_info,event.xbutton)) { /* User pressed Dismiss button. */ dismiss_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&dismiss_info); break; } if (MatteIsActive(list_info,event.xbutton)) { int id; static Time click_time; /* User pressed list matte. */ id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ selection_info.height; if (id >= (int) lines) break; if (id != list_info.id) { list_info.id=id; click_time=event.xbutton.time; break; } list_info.id=id; if (event.xbutton.time >= (click_time+DoubleClick)) { click_time=event.xbutton.time; break; } click_time=event.xbutton.time; /* Become the XA_PRIMARY selection owner. */ (void) CopyMagickString(primary_selection,textlist[list_info.id], MagickPathExtent); (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, event.xbutton.time); if (XGetSelectionOwner(display,XA_PRIMARY) != windows->widget.id) break; selection_info.id=(~0); list_info.id=id; state|=RedrawListState; break; } break; } case ButtonRelease: { if (windows->widget.mapped == MagickFalse) break; if (north_info.raised == MagickFalse) { /* User released up button. */ delay=SuspendTime << 2; north_info.raised=MagickTrue; XDrawTriangleNorth(display,&windows->widget,&north_info); } if (south_info.raised == MagickFalse) { /* User released down button. */ delay=SuspendTime << 2; south_info.raised=MagickTrue; XDrawTriangleSouth(display,&windows->widget,&south_info); } if (slider_info.active) { /* Stop tracking slider. */ slider_info.active=MagickFalse; break; } if (dismiss_info.raised == MagickFalse) { if (event.xbutton.window == windows->widget.id) if (MatteIsActive(dismiss_info,event.xbutton)) state|=ExitState; dismiss_info.raised=MagickTrue; XDrawBeveledButton(display,&windows->widget,&dismiss_info); } break; } case ClientMessage: { /* If client window delete message, exit. */ if (event.xclient.message_type != windows->wm_protocols) break; if (*event.xclient.data.l == (int) windows->wm_take_focus) { (void) XSetInputFocus(display,event.xclient.window,RevertToParent, (Time) event.xclient.data.l[1]); break; } if (*event.xclient.data.l != (int) windows->wm_delete_window) break; if (event.xclient.window == windows->widget.id) { state|=ExitState; break; } break; } case ConfigureNotify: { /* Update widget configuration. */ if (event.xconfigure.window != windows->widget.id) break; if ((event.xconfigure.width == (int) windows->widget.width) && (event.xconfigure.height == (int) windows->widget.height)) break; windows->widget.width=(unsigned int) MagickMax(event.xconfigure.width,(int) windows->widget.min_width); windows->widget.height=(unsigned int) MagickMax(event.xconfigure.height,(int) windows->widget.min_height); state|=UpdateConfigurationState; break; } case EnterNotify: { if (event.xcrossing.window != windows->widget.id) break; state&=(~InactiveWidgetState); break; } case Expose: { if (event.xexpose.window != windows->widget.id) break; if (event.xexpose.count != 0) break; state|=RedrawWidgetState; break; } case KeyPress: { static char command[MagickPathExtent]; static int length; static KeySym key_symbol; /* Respond to a user key press. */ if (event.xkey.window != windows->widget.id) break; length=XLookupString((XKeyEvent *) &event.xkey,command, (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); *(command+length)='\0'; if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) { dismiss_info.raised=MagickFalse; XDrawBeveledButton(display,&windows->widget,&dismiss_info); state|=ExitState; break; } if (AreaIsActive(scroll_info,event.xkey)) { /* Move slider. */ switch ((int) key_symbol) { case XK_Home: case XK_KP_Home: { slider_info.id=0; break; } case XK_Up: case XK_KP_Up: { slider_info.id--; break; } case XK_Down: case XK_KP_Down: { slider_info.id++; break; } case XK_Prior: case XK_KP_Prior: { slider_info.id-=visible_lines; break; } case XK_Next: case XK_KP_Next: { slider_info.id+=visible_lines; break; } case XK_End: case XK_KP_End: { slider_info.id=(int) lines; break; } } state|=RedrawListState; break; } break; } case KeyRelease: break; case LeaveNotify: { if (event.xcrossing.window != windows->widget.id) break; state|=InactiveWidgetState; break; } case MapNotify: { mask&=(~CWX); mask&=(~CWY); break; } case MotionNotify: { /* Discard pending button motion events. */ while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; if (slider_info.active) { /* Move slider matte. */ slider_info.y=event.xmotion.y- ((slider_info.height+slider_info.bevel_width) >> 1)+1; if (slider_info.y < slider_info.min_y) slider_info.y=slider_info.min_y; if (slider_info.y > slider_info.max_y) slider_info.y=slider_info.max_y; slider_info.id=0; if (slider_info.y != slider_info.min_y) slider_info.id=(int) (lines*(slider_info.y-slider_info.min_y+1))/ (slider_info.max_y-slider_info.min_y+1); state|=RedrawListState; break; } if (state & InactiveWidgetState) break; if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion)) { /* Dismiss button status changed. */ dismiss_info.raised= dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse; XDrawBeveledButton(display,&windows->widget,&dismiss_info); break; } break; } case SelectionClear: { list_info.id=(~0); selection_info.id=(~0); state|=RedrawListState; break; } case SelectionRequest: { XSelectionEvent notify; XSelectionRequestEvent *request; if (list_info.id == (~0)) break; /* Set primary selection. */ request=(&(event.xselectionrequest)); (void) XChangeProperty(request->display,request->requestor, request->property,request->target,8,PropModeReplace, (unsigned char *) primary_selection,Extent(primary_selection)); notify.type=SelectionNotify; notify.send_event=MagickTrue; notify.display=request->display; notify.requestor=request->requestor; notify.selection=request->selection; notify.target=request->target; notify.time=request->time; if (request->property == None) notify.property=request->target; else notify.property=request->property; (void) XSendEvent(request->display,request->requestor,False,NoEventMask, (XEvent *) ¬ify); } default: break; } } while ((state & ExitState) == 0); if (text_info != windows->widget.font_info) (void) XFreeFont(display,text_info); XSetCursorState(display,windows,MagickFalse); (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); XCheckRefreshWindows(display,windows); } #endif