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