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