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