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