MagickCore 7.1.2
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 {
1368 ExceptionInfo
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
1627 ExceptionInfo
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 MagickSafeReciprocal((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 MagickSafeReciprocal((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
4974 ExceptionInfo
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 MagickSafeReciprocal((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 MagickSafeReciprocal((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) (title_height >> 2) : y;
7777 if (submenu_info.active != 0)
7778 windows->widget.y=windows->command.y+submenu_info.y;
7779 XConstrainWindowPosition(display,&windows->widget);
7780 /*
7781 Map Menu widget.
7782 */
7783 window_attributes.override_redirect=MagickTrue;
7784 (void) XChangeWindowAttributes(display,windows->widget.id,
7785 (size_t) CWOverrideRedirect,&window_attributes);
7786 window_changes.width=(int) windows->widget.width;
7787 window_changes.height=(int) windows->widget.height;
7788 window_changes.x=windows->widget.x;
7789 window_changes.y=windows->widget.y;
7790 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
7791 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
7792 (void) XMapRaised(display,windows->widget.id);
7793 windows->widget.mapped=MagickFalse;
7794 /*
7795 Respond to X events.
7796 */
7797 selection_info.height=height;
7798 cursor=XCreateFontCursor(display,XC_right_ptr);
7799 (void) XCheckDefineCursor(display,windows->image.id,cursor);
7800 (void) XCheckDefineCursor(display,windows->command.id,cursor);
7801 (void) XCheckDefineCursor(display,windows->widget.id,cursor);
7802 state=UpdateConfigurationState;
7803 do
7804 {
7805 if (state & UpdateConfigurationState)
7806 {
7807 /*
7808 Initialize selection information.
7809 */
7810 XGetWidgetInfo((char *) NULL,&menu_info);
7811 menu_info.bevel_width--;
7812 menu_info.width=windows->widget.width-((menu_info.bevel_width) << 1);
7813 menu_info.height=windows->widget.height-((menu_info.bevel_width) << 1);
7814 menu_info.x=(int) menu_info.bevel_width;
7815 menu_info.y=(int) menu_info.bevel_width;
7816 XGetWidgetInfo((char *) NULL,&selection_info);
7817 selection_info.center=MagickFalse;
7818 selection_info.width=menu_info.width;
7819 selection_info.height=height;
7820 selection_info.x=menu_info.x;
7821 highlight_info=selection_info;
7822 highlight_info.bevel_width--;
7823 highlight_info.width-=(highlight_info.bevel_width << 1);
7824 highlight_info.height-=(highlight_info.bevel_width << 1);
7825 highlight_info.x+=(int) highlight_info.bevel_width;
7826 state&=(unsigned int) (~UpdateConfigurationState);
7827 }
7828 if (state & RedrawWidgetState)
7829 {
7830 /*
7831 Redraw Menu widget.
7832 */
7833 if (submenu_info.active == 0)
7834 {
7835 y=(int) title_height;
7836 XSetBevelColor(display,&windows->widget,MagickFalse);
7837 (void) XDrawLine(display,windows->widget.id,
7838 windows->widget.widget_context,selection_info.x,y-1,
7839 (int) selection_info.width,y-1);
7840 XSetBevelColor(display,&windows->widget,MagickTrue);
7841 (void) XDrawLine(display,windows->widget.id,
7842 windows->widget.widget_context,selection_info.x,y,
7843 (int) selection_info.width,y);
7844 (void) XSetFillStyle(display,windows->widget.widget_context,
7845 FillSolid);
7846 }
7847 /*
7848 Draw menu selections.
7849 */
7850 selection_info.center=MagickTrue;
7851 selection_info.y=(int) menu_info.bevel_width;
7852 selection_info.text=(char *) title;
7853 if (submenu_info.active == 0)
7854 XDrawWidgetText(display,&windows->widget,&selection_info);
7855 selection_info.center=MagickFalse;
7856 selection_info.y=(int) top_offset;
7857 for (id=0; id < (int) number_selections; id++)
7858 {
7859 selection_info.text=(char *) selections[id];
7860 XDrawWidgetText(display,&windows->widget,&selection_info);
7861 highlight_info.y=selection_info.y+(int) highlight_info.bevel_width;
7862 if (id == selection_info.id)
7863 XDrawBevel(display,&windows->widget,&highlight_info);
7864 selection_info.y+=(int) selection_info.height;
7865 }
7866 XDrawBevel(display,&windows->widget,&menu_info);
7867 state&=(unsigned int) (~RedrawWidgetState);
7868 }
7869 if (number_selections > 2)
7870 {
7871 /*
7872 Redraw Menu line.
7873 */
7874 y=((int) top_offset+(int) selection_info.height*(int)
7875 (number_selections-1));
7876 XSetBevelColor(display,&windows->widget,MagickFalse);
7877 (void) XDrawLine(display,windows->widget.id,
7878 windows->widget.widget_context,selection_info.x,y-1,
7879 (int) selection_info.width,y-1);
7880 XSetBevelColor(display,&windows->widget,MagickTrue);
7881 (void) XDrawLine(display,windows->widget.id,
7882 windows->widget.widget_context,selection_info.x,y,
7883 (int) selection_info.width,y);
7884 (void) XSetFillStyle(display,windows->widget.widget_context,FillSolid);
7885 }
7886 /*
7887 Wait for next event.
7888 */
7889 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
7890 switch (event.type)
7891 {
7892 case ButtonPress:
7893 {
7894 if (event.xbutton.window != windows->widget.id)
7895 {
7896 /*
7897 exit menu.
7898 */
7899 if (event.xbutton.window == windows->command.id)
7900 (void) XPutBackEvent(display,&event);
7901 selection_info.id=(~0);
7902 *item='\0';
7903 state|=ExitState;
7904 break;
7905 }
7906 state&=(unsigned int) (~InactiveWidgetState);
7907 if (selection_info.height == 0)
7908 break;
7909 id=(event.xbutton.y-(int) top_offset)/(int) selection_info.height;
7910 selection_info.id=id;
7911 if ((id < 0) || (id >= (int) number_selections))
7912 break;
7913 /*
7914 Highlight this selection.
7915 */
7916 selection_info.y=((int) top_offset+id*(int) selection_info.height);
7917 selection_info.text=(char *) selections[id];
7918 XDrawWidgetText(display,&windows->widget,&selection_info);
7919 highlight_info.y=selection_info.y+(int) highlight_info.bevel_width;
7920 XDrawBevel(display,&windows->widget,&highlight_info);
7921 break;
7922 }
7923 case ButtonRelease:
7924 {
7925 if (windows->widget.mapped == MagickFalse)
7926 break;
7927 if (event.xbutton.window == windows->command.id)
7928 if ((state & InactiveWidgetState) == 0)
7929 break;
7930 /*
7931 exit menu.
7932 */
7933 XSetCursorState(display,windows,MagickFalse);
7934 *item='\0';
7935 state|=ExitState;
7936 break;
7937 }
7938 case ConfigureNotify:
7939 {
7940 /*
7941 Update widget configuration.
7942 */
7943 if (event.xconfigure.window != windows->widget.id)
7944 break;
7945 if ((event.xconfigure.width == (int) windows->widget.width) &&
7946 (event.xconfigure.height == (int) windows->widget.height))
7947 break;
7948 windows->widget.width=(unsigned int)
7949 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
7950 windows->widget.height=(unsigned int)
7951 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
7952 state|=UpdateConfigurationState;
7953 break;
7954 }
7955 case EnterNotify:
7956 {
7957 if (event.xcrossing.window != windows->widget.id)
7958 break;
7959 if (event.xcrossing.state == 0)
7960 break;
7961 state&=(unsigned int) (~InactiveWidgetState);
7962 if (selection_info.height == 0)
7963 break;
7964 id=((event.xcrossing.y-(int) top_offset)/(int) selection_info.height);
7965 if ((selection_info.id >= 0) &&
7966 (selection_info.id < (int) number_selections))
7967 {
7968 /*
7969 Unhighlight last selection.
7970 */
7971 if (id == selection_info.id)
7972 break;
7973 selection_info.y=((int) top_offset+selection_info.id*(int)
7974 selection_info.height);
7975 selection_info.text=(char *) selections[selection_info.id];
7976 XDrawWidgetText(display,&windows->widget,&selection_info);
7977 }
7978 if ((id < 0) || (id >= (int) number_selections))
7979 break;
7980 /*
7981 Highlight this selection.
7982 */
7983 selection_info.id=id;
7984 selection_info.y=((int) top_offset+selection_info.id*(int)
7985 selection_info.height);
7986 selection_info.text=(char *) selections[selection_info.id];
7987 XDrawWidgetText(display,&windows->widget,&selection_info);
7988 highlight_info.y=selection_info.y+(int) highlight_info.bevel_width;
7989 XDrawBevel(display,&windows->widget,&highlight_info);
7990 break;
7991 }
7992 case Expose:
7993 {
7994 if (event.xexpose.window != windows->widget.id)
7995 break;
7996 if (event.xexpose.count != 0)
7997 break;
7998 state|=RedrawWidgetState;
7999 break;
8000 }
8001 case LeaveNotify:
8002 {
8003 if (event.xcrossing.window != windows->widget.id)
8004 break;
8005 state|=InactiveWidgetState;
8006 id=selection_info.id;
8007 if ((id < 0) || (id >= (int) number_selections))
8008 break;
8009 /*
8010 Unhighlight last selection.
8011 */
8012 selection_info.y=((int) top_offset+id*(int) selection_info.height);
8013 selection_info.id=(~0);
8014 selection_info.text=(char *) selections[id];
8015 XDrawWidgetText(display,&windows->widget,&selection_info);
8016 break;
8017 }
8018 case MotionNotify:
8019 {
8020 /*
8021 Discard pending button motion events.
8022 */
8023 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8024 if (submenu_info.active != 0)
8025 if (event.xmotion.window == windows->command.id)
8026 {
8027 if ((state & InactiveWidgetState) == 0)
8028 {
8029 if (MatteIsActive(submenu_info,event.xmotion) == MagickFalse)
8030 {
8031 selection_info.id=(~0);
8032 *item='\0';
8033 state|=ExitState;
8034 break;
8035 }
8036 }
8037 else
8038 if (WindowIsActive(windows->command,event.xmotion))
8039 {
8040 selection_info.id=(~0);
8041 *item='\0';
8042 state|=ExitState;
8043 break;
8044 }
8045 }
8046 if (event.xmotion.window != windows->widget.id)
8047 break;
8048 if (state & InactiveWidgetState)
8049 break;
8050 if (selection_info.height == 0)
8051 break;
8052 id=(event.xmotion.y-(int) top_offset)/(int) selection_info.height;
8053 if ((selection_info.id >= 0) &&
8054 (selection_info.id < (int) number_selections))
8055 {
8056 /*
8057 Unhighlight last selection.
8058 */
8059 if (id == selection_info.id)
8060 break;
8061 selection_info.y=((int) top_offset+selection_info.id*(int)
8062 selection_info.height);
8063 selection_info.text=(char *) selections[selection_info.id];
8064 XDrawWidgetText(display,&windows->widget,&selection_info);
8065 }
8066 selection_info.id=id;
8067 if ((id < 0) || (id >= (int) number_selections))
8068 break;
8069 /*
8070 Highlight this selection.
8071 */
8072 selection_info.y=((int) top_offset+id*(int) selection_info.height);
8073 selection_info.text=(char *) selections[id];
8074 XDrawWidgetText(display,&windows->widget,&selection_info);
8075 highlight_info.y=selection_info.y+(int) highlight_info.bevel_width;
8076 XDrawBevel(display,&windows->widget,&highlight_info);
8077 break;
8078 }
8079 default:
8080 break;
8081 }
8082 } while ((state & ExitState) == 0);
8083 (void) XFreeCursor(display,cursor);
8084 window_attributes.override_redirect=MagickFalse;
8085 (void) XChangeWindowAttributes(display,windows->widget.id,
8086 (size_t) CWOverrideRedirect,&window_attributes);
8087 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8088 XCheckRefreshWindows(display,windows);
8089 if (submenu_info.active != 0)
8090 {
8091 submenu_info.active=MagickFalse;
8092 toggle_info.raised=MagickFalse;
8093 XDrawTriangleEast(display,&windows->command,&toggle_info);
8094 }
8095 if ((selection_info.id < 0) || (selection_info.id >= (int) number_selections))
8096 return(~0);
8097 (void) CopyMagickString(item,selections[selection_info.id],MagickPathExtent);
8098 return(selection_info.id);
8099}
8100
8101/*
8102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8103% %
8104% %
8105% %
8106% X N o t i c e W i d g e t %
8107% %
8108% %
8109% %
8110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8111%
8112% XNoticeWidget() displays a Notice widget with a notice to the user. The
8113% function returns when the user presses the "Dismiss" button.
8114%
8115% The format of the XNoticeWidget method is:
8116%
8117% void XNoticeWidget(Display *display,XWindows *windows,
8118% const char *reason,const char *description)
8119%
8120% A description of each parameter follows:
8121%
8122% o display: Specifies a connection to an X server; returned from
8123% XOpenDisplay.
8124%
8125% o window: Specifies a pointer to a XWindows structure.
8126%
8127% o reason: Specifies the message to display before terminating the
8128% program.
8129%
8130% o description: Specifies any description to the message.
8131%
8132*/
8133MagickPrivate void XNoticeWidget(Display *display,XWindows *windows,
8134 const char *reason,const char *description)
8135{
8136#define DismissButtonText "Dismiss"
8137#define Timeout 8
8138
8139 const char
8140 *text;
8141
8142 int
8143 x,
8144 y;
8145
8146 Status
8147 status;
8148
8149 time_t
8150 timer;
8151
8152 unsigned int
8153 height,
8154 width;
8155
8156 size_t
8157 state;
8158
8159 XEvent
8160 event;
8161
8162 XFontStruct
8163 *font_info;
8164
8165 XTextProperty
8166 window_name;
8167
8168 XWidgetInfo
8169 dismiss_info;
8170
8171 XWindowChanges
8172 window_changes;
8173
8174 /*
8175 Determine Notice widget attributes.
8176 */
8177 assert(display != (Display *) NULL);
8178 assert(windows != (XWindows *) NULL);
8179 assert(reason != (char *) NULL);
8180 if (IsEventLogging() != MagickFalse)
8181 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
8182 XDelay(display,SuspendTime << 3); /* avoid surprise with delay */
8183 XSetCursorState(display,windows,MagickTrue);
8184 XCheckRefreshWindows(display,windows);
8185 font_info=windows->widget.font_info;
8186 width=WidgetTextWidth(font_info,DismissButtonText);
8187 text=GetLocaleExceptionMessage(XServerError,reason);
8188 if (text != (char *) NULL)
8189 if (WidgetTextWidth(font_info,(char *) text) > width)
8190 width=WidgetTextWidth(font_info,(char *) text);
8191 if (description != (char *) NULL)
8192 {
8193 text=GetLocaleExceptionMessage(XServerError,description);
8194 if (text != (char *) NULL)
8195 if (WidgetTextWidth(font_info,(char *) text) > width)
8196 width=WidgetTextWidth(font_info,(char *) text);
8197 }
8198 height=(unsigned int) (font_info->ascent+font_info->descent);
8199 /*
8200 Position Notice widget.
8201 */
8202 windows->widget.width=width+(unsigned int) (4*QuantumMargin);
8203 windows->widget.min_width=width+(unsigned int) QuantumMargin;
8204 if (windows->widget.width < windows->widget.min_width)
8205 windows->widget.width=windows->widget.min_width;
8206 windows->widget.height=(unsigned int) (12*height);
8207 windows->widget.min_height=(unsigned int) (7*height);
8208 if (windows->widget.height < windows->widget.min_height)
8209 windows->widget.height=windows->widget.min_height;
8210 XConstrainWindowPosition(display,&windows->widget);
8211 /*
8212 Map Notice widget.
8213 */
8214 (void) CopyMagickString(windows->widget.name,"Notice",MagickPathExtent);
8215 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8216 if (status != False)
8217 {
8218 XSetWMName(display,windows->widget.id,&window_name);
8219 XSetWMIconName(display,windows->widget.id,&window_name);
8220 (void) XFree((void *) window_name.value);
8221 }
8222 window_changes.width=(int) windows->widget.width;
8223 window_changes.height=(int) windows->widget.height;
8224 window_changes.x=windows->widget.x;
8225 window_changes.y=windows->widget.y;
8226 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8227 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8228 (void) XMapRaised(display,windows->widget.id);
8229 windows->widget.mapped=MagickFalse;
8230 (void) XBell(display,0);
8231 /*
8232 Respond to X events.
8233 */
8234 timer=GetMagickTime()+Timeout;
8235 state=UpdateConfigurationState;
8236 do
8237 {
8238 if (GetMagickTime() > timer)
8239 break;
8240 if (state & UpdateConfigurationState)
8241 {
8242 /*
8243 Initialize Dismiss button information.
8244 */
8245 XGetWidgetInfo(DismissButtonText,&dismiss_info);
8246 dismiss_info.width=(unsigned int) QuantumMargin+
8247 WidgetTextWidth(font_info,DismissButtonText);
8248 dismiss_info.height=(unsigned int) ((3*height) >> 1);
8249 dismiss_info.x=(int)
8250 ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
8251 dismiss_info.y=(int)
8252 (windows->widget.height-(dismiss_info.height << 1));
8253 state&=(unsigned int) (~UpdateConfigurationState);
8254 }
8255 if (state & RedrawWidgetState)
8256 {
8257 /*
8258 Redraw Notice widget.
8259 */
8260 width=WidgetTextWidth(font_info,(char *) reason);
8261 x=(int) ((windows->widget.width >> 1)-(width >> 1));
8262 y=(int) ((windows->widget.height >> 1)-(height << 1));
8263 (void) XDrawString(display,windows->widget.id,
8264 windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
8265 if (description != (char *) NULL)
8266 {
8267 width=WidgetTextWidth(font_info,(char *) description);
8268 x=(int) ((windows->widget.width >> 1)-(width >> 1));
8269 y+=(int) height;
8270 (void) XDrawString(display,windows->widget.id,
8271 windows->widget.annotate_context,x,y,(char *) description,
8272 Extent(description));
8273 }
8274 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8275 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8276 state&=(unsigned int) (~RedrawWidgetState);
8277 }
8278 /*
8279 Wait for next event.
8280 */
8281 if (XCheckIfEvent(display,&event,XScreenEvent,(char *) windows) == MagickFalse)
8282 {
8283 /*
8284 Do not block if delay > 0.
8285 */
8286 XDelay(display,SuspendTime << 2);
8287 continue;
8288 }
8289 switch (event.type)
8290 {
8291 case ButtonPress:
8292 {
8293 if (MatteIsActive(dismiss_info,event.xbutton))
8294 {
8295 /*
8296 User pressed Dismiss button.
8297 */
8298 dismiss_info.raised=MagickFalse;
8299 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8300 break;
8301 }
8302 break;
8303 }
8304 case ButtonRelease:
8305 {
8306 if (windows->widget.mapped == MagickFalse)
8307 break;
8308 if (dismiss_info.raised == MagickFalse)
8309 {
8310 if (event.xbutton.window == windows->widget.id)
8311 if (MatteIsActive(dismiss_info,event.xbutton))
8312 state|=ExitState;
8313 dismiss_info.raised=MagickTrue;
8314 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8315 }
8316 break;
8317 }
8318 case ClientMessage:
8319 {
8320 /*
8321 If client window delete message, exit.
8322 */
8323 if (event.xclient.message_type != windows->wm_protocols)
8324 break;
8325 if (*event.xclient.data.l == (int) windows->wm_take_focus)
8326 {
8327 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8328 (Time) event.xclient.data.l[1]);
8329 break;
8330 }
8331 if (*event.xclient.data.l != (int) windows->wm_delete_window)
8332 break;
8333 if (event.xclient.window == windows->widget.id)
8334 {
8335 state|=ExitState;
8336 break;
8337 }
8338 break;
8339 }
8340 case ConfigureNotify:
8341 {
8342 /*
8343 Update widget configuration.
8344 */
8345 if (event.xconfigure.window != windows->widget.id)
8346 break;
8347 if ((event.xconfigure.width == (int) windows->widget.width) &&
8348 (event.xconfigure.height == (int) windows->widget.height))
8349 break;
8350 windows->widget.width=(unsigned int)
8351 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8352 windows->widget.height=(unsigned int)
8353 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8354 state|=UpdateConfigurationState;
8355 break;
8356 }
8357 case EnterNotify:
8358 {
8359 if (event.xcrossing.window != windows->widget.id)
8360 break;
8361 state&=(unsigned int) (~InactiveWidgetState);
8362 break;
8363 }
8364 case Expose:
8365 {
8366 if (event.xexpose.window != windows->widget.id)
8367 break;
8368 if (event.xexpose.count != 0)
8369 break;
8370 state|=RedrawWidgetState;
8371 break;
8372 }
8373 case KeyPress:
8374 {
8375 static char
8376 command[MagickPathExtent];
8377
8378 static KeySym
8379 key_symbol;
8380
8381 /*
8382 Respond to a user key press.
8383 */
8384 if (event.xkey.window != windows->widget.id)
8385 break;
8386 (void) XLookupString((XKeyEvent *) &event.xkey,command,
8387 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8388 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8389 {
8390 dismiss_info.raised=MagickFalse;
8391 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8392 state|=ExitState;
8393 break;
8394 }
8395 break;
8396 }
8397 case LeaveNotify:
8398 {
8399 if (event.xcrossing.window != windows->widget.id)
8400 break;
8401 state|=InactiveWidgetState;
8402 break;
8403 }
8404 case MotionNotify:
8405 {
8406 /*
8407 Discard pending button motion events.
8408 */
8409 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8410 if (state & InactiveWidgetState)
8411 break;
8412 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
8413 {
8414 /*
8415 Dismiss button status changed.
8416 */
8417 dismiss_info.raised=
8418 dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8419 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8420 break;
8421 }
8422 break;
8423 }
8424 default:
8425 break;
8426 }
8427 } while ((state & ExitState) == 0);
8428 XSetCursorState(display,windows,MagickFalse);
8429 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8430 XCheckRefreshWindows(display,windows);
8431}
8432
8433/*
8434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8435% %
8436% %
8437% %
8438% X P r e f e r e n c e s W i d g e t %
8439% %
8440% %
8441% %
8442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8443%
8444% XPreferencesWidget() displays a Preferences widget with program preferences.
8445% If the user presses the Apply button, the preferences are stored in a
8446% configuration file in the users' home directory.
8447%
8448% The format of the XPreferencesWidget method is:
8449%
8450% MagickBooleanType XPreferencesWidget(Display *display,
8451% XResourceInfo *resource_info,XWindows *windows)
8452%
8453% A description of each parameter follows:
8454%
8455% o display: Specifies a connection to an X server; returned from
8456% XOpenDisplay.
8457%
8458% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8459%
8460% o window: Specifies a pointer to a XWindows structure.
8461%
8462*/
8463MagickPrivate MagickBooleanType XPreferencesWidget(Display *display,
8464 XResourceInfo *resource_info,XWindows *windows)
8465{
8466#define ApplyButtonText "Apply"
8467#define CacheButtonText "%lu mega-bytes of memory in the undo edit cache "
8468#define CancelButtonText "Cancel"
8469#define NumberPreferences 8
8470
8471 static const char
8472 *Preferences[] =
8473 {
8474 "display image centered on a backdrop",
8475 "confirm on program exit",
8476 "confirm on image edits",
8477 "correct image for display gamma",
8478 "display warning messages",
8479 "apply Floyd/Steinberg error diffusion to image",
8480 "use a shared colormap for colormapped X visuals",
8481 "display images as an X server pixmap"
8482 };
8483
8484 char
8485 cache[MagickPathExtent];
8486
8487 int
8488 x,
8489 y;
8490
8491 int
8492 i;
8493
8494 Status
8495 status;
8496
8497 unsigned int
8498 height,
8499 text_width,
8500 width;
8501
8502 size_t
8503 state;
8504
8505 XEvent
8506 event;
8507
8508 XFontStruct
8509 *font_info;
8510
8511 XTextProperty
8512 window_name;
8513
8514 XWidgetInfo
8515 apply_info,
8516 cache_info,
8517 cancel_info,
8518 preferences_info[NumberPreferences];
8519
8520 XWindowChanges
8521 window_changes;
8522
8523 /*
8524 Determine Preferences widget attributes.
8525 */
8526 if (IsEventLogging() != MagickFalse)
8527 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
8528 assert(display != (Display *) NULL);
8529 assert(resource_info != (XResourceInfo *) NULL);
8530 assert(windows != (XWindows *) NULL);
8531 XCheckRefreshWindows(display,windows);
8532 font_info=windows->widget.font_info;
8533 text_width=WidgetTextWidth(font_info,CacheButtonText);
8534 for (i=0; i < NumberPreferences; i++)
8535 if (WidgetTextWidth(font_info,(char *) Preferences[i]) > text_width)
8536 text_width=WidgetTextWidth(font_info,(char *) Preferences[i]);
8537 width=WidgetTextWidth(font_info,ApplyButtonText);
8538 if (WidgetTextWidth(font_info,CancelButtonText) > width)
8539 width=WidgetTextWidth(font_info,CancelButtonText);
8540 width+=(unsigned int) QuantumMargin;
8541 height=(unsigned int) (font_info->ascent+font_info->descent);
8542 /*
8543 Position Preferences widget.
8544 */
8545 windows->widget.width=(unsigned int) (MagickMax((int) (width << 1),
8546 (int) text_width)+6*QuantumMargin);
8547 windows->widget.min_width=(width << 1)+(unsigned int) QuantumMargin;
8548 if (windows->widget.width < windows->widget.min_width)
8549 windows->widget.width=windows->widget.min_width;
8550 windows->widget.height=(unsigned int) (7*(int) height+NumberPreferences*
8551 ((int) height+(QuantumMargin >> 1)));
8552 windows->widget.min_height=(unsigned int) (7*(int) height+NumberPreferences*
8553 ((int) height+(QuantumMargin >> 1)));
8554 if (windows->widget.height < windows->widget.min_height)
8555 windows->widget.height=windows->widget.min_height;
8556 XConstrainWindowPosition(display,&windows->widget);
8557 /*
8558 Map Preferences widget.
8559 */
8560 (void) CopyMagickString(windows->widget.name,"Preferences",MagickPathExtent);
8561 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8562 if (status != False)
8563 {
8564 XSetWMName(display,windows->widget.id,&window_name);
8565 XSetWMIconName(display,windows->widget.id,&window_name);
8566 (void) XFree((void *) window_name.value);
8567 }
8568 window_changes.width=(int) windows->widget.width;
8569 window_changes.height=(int) windows->widget.height;
8570 window_changes.x=windows->widget.x;
8571 window_changes.y=windows->widget.y;
8572 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8573 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8574 (void) XMapRaised(display,windows->widget.id);
8575 windows->widget.mapped=MagickFalse;
8576 /*
8577 Respond to X events.
8578 */
8579 state=UpdateConfigurationState;
8580 XSetCursorState(display,windows,MagickTrue);
8581 do
8582 {
8583 if (state & UpdateConfigurationState)
8584 {
8585 /*
8586 Initialize button information.
8587 */
8588 XGetWidgetInfo(CancelButtonText,&cancel_info);
8589 cancel_info.width=width;
8590 cancel_info.height=(unsigned int) (3*height) >> 1;
8591 cancel_info.x=(int) windows->widget.width-(int) cancel_info.width-
8592 (QuantumMargin << 1);
8593 cancel_info.y=(int) windows->widget.height-(int) cancel_info.height-
8594 QuantumMargin;
8595 XGetWidgetInfo(ApplyButtonText,&apply_info);
8596 apply_info.width=width;
8597 apply_info.height=(unsigned int) (3*height) >> 1;
8598 apply_info.x=QuantumMargin << 1;
8599 apply_info.y=cancel_info.y;
8600 y=(int) (height << 1);
8601 for (i=0; i < NumberPreferences; i++)
8602 {
8603 XGetWidgetInfo(Preferences[i],&preferences_info[i]);
8604 preferences_info[i].bevel_width--;
8605 preferences_info[i].width=(unsigned int) QuantumMargin >> 1;
8606 preferences_info[i].height=(unsigned int) QuantumMargin >> 1;
8607 preferences_info[i].x=QuantumMargin << 1;
8608 preferences_info[i].y=y;
8609 y+=(int) height+(QuantumMargin >> 1);
8610 }
8611 preferences_info[0].raised=resource_info->backdrop ==
8612 MagickFalse ? MagickTrue : MagickFalse;
8613 preferences_info[1].raised=resource_info->confirm_exit ==
8614 MagickFalse ? MagickTrue : MagickFalse;
8615 preferences_info[2].raised=resource_info->confirm_edit ==
8616 MagickFalse ? MagickTrue : MagickFalse;
8617 preferences_info[3].raised=resource_info->gamma_correct ==
8618 MagickFalse ? MagickTrue : MagickFalse;
8619 preferences_info[4].raised=resource_info->display_warnings ==
8620 MagickFalse ? MagickTrue : MagickFalse;
8621 preferences_info[5].raised=
8622 resource_info->quantize_info->dither_method == NoDitherMethod ?
8623 MagickTrue : MagickFalse;
8624 preferences_info[6].raised=resource_info->colormap !=
8625 SharedColormap ? MagickTrue : MagickFalse;
8626 preferences_info[7].raised=resource_info->use_pixmap ==
8627 MagickFalse ? MagickTrue : MagickFalse;
8628 (void) FormatLocaleString(cache,MagickPathExtent,CacheButtonText,
8629 (unsigned long) resource_info->undo_cache);
8630 XGetWidgetInfo(cache,&cache_info);
8631 cache_info.bevel_width--;
8632 cache_info.width=(unsigned int) QuantumMargin >> 1;
8633 cache_info.height=(unsigned int) QuantumMargin >> 1;
8634 cache_info.x=QuantumMargin << 1;
8635 cache_info.y=y;
8636 state&=(unsigned int) (~UpdateConfigurationState);
8637 }
8638 if (state & RedrawWidgetState)
8639 {
8640 /*
8641 Redraw Preferences widget.
8642 */
8643 XDrawBeveledButton(display,&windows->widget,&apply_info);
8644 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8645 for (i=0; i < NumberPreferences; i++)
8646 XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8647 XDrawTriangleEast(display,&windows->widget,&cache_info);
8648 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8649 state&=(unsigned int) (~RedrawWidgetState);
8650 }
8651 /*
8652 Wait for next event.
8653 */
8654 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
8655 switch (event.type)
8656 {
8657 case ButtonPress:
8658 {
8659 if (MatteIsActive(apply_info,event.xbutton))
8660 {
8661 /*
8662 User pressed Apply button.
8663 */
8664 apply_info.raised=MagickFalse;
8665 XDrawBeveledButton(display,&windows->widget,&apply_info);
8666 break;
8667 }
8668 if (MatteIsActive(cancel_info,event.xbutton))
8669 {
8670 /*
8671 User pressed Cancel button.
8672 */
8673 cancel_info.raised=MagickFalse;
8674 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8675 break;
8676 }
8677 for (i=0; i < NumberPreferences; i++)
8678 if (MatteIsActive(preferences_info[i],event.xbutton))
8679 {
8680 /*
8681 User pressed a Preferences button.
8682 */
8683 preferences_info[i].raised=preferences_info[i].raised ==
8684 MagickFalse ? MagickTrue : MagickFalse;
8685 XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8686 break;
8687 }
8688 if (MatteIsActive(cache_info,event.xbutton))
8689 {
8690 /*
8691 User pressed Cache button.
8692 */
8693 x=cache_info.x+(int) cache_info.width+(int) cache_info.bevel_width+
8694 (QuantumMargin >> 1);
8695 y=cache_info.y+(int) ((cache_info.height-height) >> 1);
8696 width=WidgetTextWidth(font_info,cache);
8697 (void) XClearArea(display,windows->widget.id,x,y,width,height,
8698 False);
8699 resource_info->undo_cache<<=1;
8700 if (resource_info->undo_cache > 256)
8701 resource_info->undo_cache=1;
8702 (void) FormatLocaleString(cache,MagickPathExtent,CacheButtonText,
8703 (unsigned long) resource_info->undo_cache);
8704 cache_info.raised=MagickFalse;
8705 XDrawTriangleEast(display,&windows->widget,&cache_info);
8706 break;
8707 }
8708 break;
8709 }
8710 case ButtonRelease:
8711 {
8712 if (windows->widget.mapped == MagickFalse)
8713 break;
8714 if (apply_info.raised == MagickFalse)
8715 {
8716 if (event.xbutton.window == windows->widget.id)
8717 if (MatteIsActive(apply_info,event.xbutton))
8718 state|=ExitState;
8719 apply_info.raised=MagickTrue;
8720 XDrawBeveledButton(display,&windows->widget,&apply_info);
8721 apply_info.raised=MagickFalse;
8722 }
8723 if (cancel_info.raised == MagickFalse)
8724 {
8725 if (event.xbutton.window == windows->widget.id)
8726 if (MatteIsActive(cancel_info,event.xbutton))
8727 state|=ExitState;
8728 cancel_info.raised=MagickTrue;
8729 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8730 }
8731 if (cache_info.raised == MagickFalse)
8732 {
8733 cache_info.raised=MagickTrue;
8734 XDrawTriangleEast(display,&windows->widget,&cache_info);
8735 }
8736 break;
8737 }
8738 case ClientMessage:
8739 {
8740 /*
8741 If client window delete message, exit.
8742 */
8743 if (event.xclient.message_type != windows->wm_protocols)
8744 break;
8745 if (*event.xclient.data.l == (int) windows->wm_take_focus)
8746 {
8747 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8748 (Time) event.xclient.data.l[1]);
8749 break;
8750 }
8751 if (*event.xclient.data.l != (int) windows->wm_delete_window)
8752 break;
8753 if (event.xclient.window == windows->widget.id)
8754 {
8755 state|=ExitState;
8756 break;
8757 }
8758 break;
8759 }
8760 case ConfigureNotify:
8761 {
8762 /*
8763 Update widget configuration.
8764 */
8765 if (event.xconfigure.window != windows->widget.id)
8766 break;
8767 if ((event.xconfigure.width == (int) windows->widget.width) &&
8768 (event.xconfigure.height == (int) windows->widget.height))
8769 break;
8770 windows->widget.width=(unsigned int)
8771 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8772 windows->widget.height=(unsigned int)
8773 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8774 state|=UpdateConfigurationState;
8775 break;
8776 }
8777 case EnterNotify:
8778 {
8779 if (event.xcrossing.window != windows->widget.id)
8780 break;
8781 state&=(unsigned int) (~InactiveWidgetState);
8782 break;
8783 }
8784 case Expose:
8785 {
8786 if (event.xexpose.window != windows->widget.id)
8787 break;
8788 if (event.xexpose.count != 0)
8789 break;
8790 state|=RedrawWidgetState;
8791 break;
8792 }
8793 case KeyPress:
8794 {
8795 static char
8796 command[MagickPathExtent];
8797
8798 static KeySym
8799 key_symbol;
8800
8801 /*
8802 Respond to a user key press.
8803 */
8804 if (event.xkey.window != windows->widget.id)
8805 break;
8806 (void) XLookupString((XKeyEvent *) &event.xkey,command,
8807 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8808 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8809 {
8810 apply_info.raised=MagickFalse;
8811 XDrawBeveledButton(display,&windows->widget,&apply_info);
8812 state|=ExitState;
8813 break;
8814 }
8815 break;
8816 }
8817 case LeaveNotify:
8818 {
8819 if (event.xcrossing.window != windows->widget.id)
8820 break;
8821 state|=InactiveWidgetState;
8822 break;
8823 }
8824 case MotionNotify:
8825 {
8826 /*
8827 Discard pending button motion events.
8828 */
8829 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8830 if (state & InactiveWidgetState)
8831 break;
8832 if (apply_info.raised == MatteIsActive(apply_info,event.xmotion))
8833 {
8834 /*
8835 Apply button status changed.
8836 */
8837 apply_info.raised=
8838 apply_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8839 XDrawBeveledButton(display,&windows->widget,&apply_info);
8840 break;
8841 }
8842 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
8843 {
8844 /*
8845 Cancel button status changed.
8846 */
8847 cancel_info.raised=
8848 cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8849 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8850 break;
8851 }
8852 break;
8853 }
8854 default:
8855 break;
8856 }
8857 } while ((state & ExitState) == 0);
8858 XSetCursorState(display,windows,MagickFalse);
8859 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8860 XCheckRefreshWindows(display,windows);
8861 if (apply_info.raised)
8862 return(MagickFalse);
8863 /*
8864 Save user preferences to the client configuration file.
8865 */
8866 resource_info->backdrop=
8867 preferences_info[0].raised == MagickFalse ? MagickTrue : MagickFalse;
8868 resource_info->confirm_exit=
8869 preferences_info[1].raised == MagickFalse ? MagickTrue : MagickFalse;
8870 resource_info->confirm_edit=
8871 preferences_info[2].raised == MagickFalse ? MagickTrue : MagickFalse;
8872 resource_info->gamma_correct=
8873 preferences_info[3].raised == MagickFalse ? MagickTrue : MagickFalse;
8874 resource_info->display_warnings=
8875 preferences_info[4].raised == MagickFalse ? MagickTrue : MagickFalse;
8876 resource_info->quantize_info->dither_method=
8877 preferences_info[5].raised == MagickFalse ?
8878 RiemersmaDitherMethod : NoDitherMethod;
8879 resource_info->colormap=SharedColormap;
8880 if (preferences_info[6].raised)
8881 resource_info->colormap=PrivateColormap;
8882 resource_info->use_pixmap=
8883 preferences_info[7].raised == MagickFalse ? MagickTrue : MagickFalse;
8884 XUserPreferences(resource_info);
8885 return(MagickTrue);
8886}
8887
8888/*
8889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8890% %
8891% %
8892% %
8893% X P r o g r e s s M o n i t o r W i d g e t %
8894% %
8895% %
8896% %
8897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8898%
8899% XProgressMonitorWidget() displays the progress a task is making in
8900% completing a task. A span of zero toggles the active status. An inactive
8901% state disables the progress monitor.
8902%
8903% The format of the XProgressMonitorWidget method is:
8904%
8905% void XProgressMonitorWidget(Display *display,XWindows *windows,
8906% const char *task,const MagickOffsetType offset,
8907% const MagickSizeType span)
8908%
8909% A description of each parameter follows:
8910%
8911% o display: Specifies a connection to an X server; returned from
8912% XOpenDisplay.
8913%
8914% o window: Specifies a pointer to a XWindows structure.
8915%
8916% o task: Identifies the task in progress.
8917%
8918% o offset: Specifies the offset position within the span which represents
8919% how much progress has been made in completing a task.
8920%
8921% o span: Specifies the span relative to completing a task.
8922%
8923*/
8924MagickPrivate void XProgressMonitorWidget(Display *display,XWindows *windows,
8925 const char *task,const MagickOffsetType offset,const MagickSizeType span)
8926{
8927 unsigned int
8928 width;
8929
8930 XEvent
8931 event;
8932
8933 assert(display != (Display *) NULL);
8934 assert(windows != (XWindows *) NULL);
8935 assert(task != (const char *) NULL);
8936 if (IsEventLogging() != MagickFalse)
8937 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",task);
8938 if (span == 0)
8939 return;
8940 /*
8941 Update image windows if there is a pending expose event.
8942 */
8943 while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event))
8944 (void) XCommandWidget(display,windows,(const char *const *) NULL,&event);
8945 while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event))
8946 XRefreshWindow(display,&windows->image,&event);
8947 while (XCheckTypedWindowEvent(display,windows->info.id,Expose,&event))
8948 if (monitor_info.text != (char *) NULL)
8949 XInfoWidget(display,windows,monitor_info.text);
8950 /*
8951 Draw progress monitor bar to represent percent completion of a task.
8952 */
8953 if ((windows->info.mapped == MagickFalse) || (task != monitor_info.text))
8954 XInfoWidget(display,windows,task);
8955 width=(unsigned int) (((offset+1)*((int) windows->info.width-
8956 (2*monitor_info.x)))/(int) span);
8957 if (width < monitor_info.width)
8958 {
8959 monitor_info.raised=MagickTrue;
8960 XDrawWidgetText(display,&windows->info,&monitor_info);
8961 monitor_info.raised=MagickFalse;
8962 }
8963 monitor_info.width=width;
8964 XDrawWidgetText(display,&windows->info,&monitor_info);
8965 (void) XFlush(display);
8966}
8967
8968/*
8969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8970% %
8971% %
8972% %
8973% X T e x t V i e w W i d g e t %
8974% %
8975% %
8976% %
8977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8978%
8979% XTextViewWidget() displays text in a Text View widget.
8980%
8981% The format of the XTextViewWidget method is:
8982%
8983% void XTextViewWidget(Display *display,const XResourceInfo *resource_info,
8984% XWindows *windows,const MagickBooleanType mono,const char *title,
8985% const char **textlist)
8986%
8987% A description of each parameter follows:
8988%
8989% o display: Specifies a connection to an X server; returned from
8990% XOpenDisplay.
8991%
8992% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8993%
8994% o window: Specifies a pointer to a XWindows structure.
8995%
8996% o mono: Use mono-spaced font when displaying text.
8997%
8998% o title: This character string is displayed at the top of the widget
8999% window.
9000%
9001% o textlist: This string list is displayed within the Text View widget.
9002%
9003*/
9004MagickPrivate void XTextViewWidget(Display *display,
9005 const XResourceInfo *resource_info,XWindows *windows,
9006 const MagickBooleanType mono,const char *title,const char **textlist)
9007{
9008#define DismissButtonText "Dismiss"
9009
9010 char
9011 primary_selection[MagickPathExtent];
9012
9013 int
9014 i;
9015
9016 static MagickStatusType
9017 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
9018
9019 Status
9020 status;
9021
9022 unsigned int
9023 height,
9024 lines,
9025 text_width,
9026 visible_lines,
9027 width;
9028
9029 size_t
9030 delay,
9031 state;
9032
9033 XEvent
9034 event;
9035
9036 XFontStruct
9037 *font_info,
9038 *text_info;
9039
9040 XTextProperty
9041 window_name;
9042
9043 XWidgetInfo
9044 dismiss_info,
9045 expose_info,
9046 list_info,
9047 north_info,
9048 scroll_info,
9049 selection_info,
9050 slider_info,
9051 south_info;
9052
9053 XWindowChanges
9054 window_changes;
9055
9056 /*
9057 Convert text string to a text list.
9058 */
9059 assert(display != (Display *) NULL);
9060 assert(resource_info != (XResourceInfo *) NULL);
9061 assert(windows != (XWindows *) NULL);
9062 assert(title != (const char *) NULL);
9063 assert(textlist != (const char **) NULL);
9064 if (IsEventLogging() != MagickFalse)
9065 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
9066 XSetCursorState(display,windows,MagickTrue);
9067 XCheckRefreshWindows(display,windows);
9068 if (textlist == (const char **) NULL)
9069 {
9070 XNoticeWidget(display,windows,"No text to view:",(char *) NULL);
9071 return;
9072 }
9073 /*
9074 Determine Text View widget attributes.
9075 */
9076 font_info=windows->widget.font_info;
9077 text_info=(XFontStruct *) NULL;
9078 if (mono != MagickFalse)
9079 text_info=XBestFont(display,resource_info,MagickTrue);
9080 if (text_info == (XFontStruct *) NULL)
9081 text_info=windows->widget.font_info;
9082 text_width=0;
9083 for (i=0; textlist[i] != (char *) NULL; i++)
9084 if (WidgetTextWidth(text_info,(char *) textlist[i]) > text_width)
9085 text_width=(unsigned int) XTextWidth(text_info,(char *) textlist[i],
9086 MagickMin(Extent(textlist[i]),160));
9087 lines=(unsigned int) i;
9088 width=WidgetTextWidth(font_info,DismissButtonText);
9089 width+=(unsigned int) QuantumMargin;
9090 height=(unsigned int) (text_info->ascent+text_info->descent);
9091 /*
9092 Position Text View widget.
9093 */
9094 windows->widget.width=(unsigned int) (MagickMin((int) text_width,
9095 (int) MaxTextWidth)+5*QuantumMargin);
9096 windows->widget.min_width=(unsigned int) ((int) MinTextWidth+4*QuantumMargin);
9097 if (windows->widget.width < windows->widget.min_width)
9098 windows->widget.width=windows->widget.min_width;
9099 windows->widget.height=(unsigned int) (MagickMin(MagickMax((int) lines,3),32)*
9100 (int) height+(int) ((13*height) >> 1)+((9*QuantumMargin) >> 1));
9101 windows->widget.min_height=(3*height+((13*height) >> 1)+(unsigned int) ((9*
9102 QuantumMargin) >> 1));
9103 if (windows->widget.height < windows->widget.min_height)
9104 windows->widget.height=windows->widget.min_height;
9105 XConstrainWindowPosition(display,&windows->widget);
9106 /*
9107 Map Text View widget.
9108 */
9109 (void) CopyMagickString(windows->widget.name,title,MagickPathExtent);
9110 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
9111 if (status != False)
9112 {
9113 XSetWMName(display,windows->widget.id,&window_name);
9114 XSetWMIconName(display,windows->widget.id,&window_name);
9115 (void) XFree((void *) window_name.value);
9116 }
9117 window_changes.width=(int) windows->widget.width;
9118 window_changes.height=(int) windows->widget.height;
9119 window_changes.x=windows->widget.x;
9120 window_changes.y=windows->widget.y;
9121 (void) XReconfigureWMWindow(display,windows->widget.id,
9122 windows->widget.screen,(unsigned int) mask,&window_changes);
9123 (void) XMapRaised(display,windows->widget.id);
9124 windows->widget.mapped=MagickFalse;
9125 /*
9126 Respond to X events.
9127 */
9128 XGetWidgetInfo((char *) NULL,&slider_info);
9129 XGetWidgetInfo((char *) NULL,&north_info);
9130 XGetWidgetInfo((char *) NULL,&south_info);
9131 XGetWidgetInfo((char *) NULL,&expose_info);
9132 XGetWidgetInfo((char *) NULL,&selection_info);
9133 visible_lines=0;
9134 delay=SuspendTime << 2;
9135 height=(unsigned int) (font_info->ascent+font_info->descent);
9136 state=UpdateConfigurationState;
9137 do
9138 {
9139 if (state & UpdateConfigurationState)
9140 {
9141 int
9142 id;
9143
9144 /*
9145 Initialize button information.
9146 */
9147 XGetWidgetInfo(DismissButtonText,&dismiss_info);
9148 dismiss_info.width=width;
9149 dismiss_info.height=(unsigned int) ((3*height) >> 1);
9150 dismiss_info.x=(int) windows->widget.width-(int) dismiss_info.width-
9151 QuantumMargin-2;
9152 dismiss_info.y=(int) windows->widget.height-(int) dismiss_info.height-
9153 QuantumMargin;
9154 /*
9155 Initialize scroll information.
9156 */
9157 XGetWidgetInfo((char *) NULL,&scroll_info);
9158 scroll_info.bevel_width--;
9159 scroll_info.width=height;
9160 scroll_info.height=(unsigned int) (dismiss_info.y-((5*QuantumMargin) >>
9161 1));
9162 scroll_info.x=(int) windows->widget.width-QuantumMargin-(int)
9163 scroll_info.width;
9164 scroll_info.y=(3*QuantumMargin) >> 1;
9165 scroll_info.raised=MagickFalse;
9166 scroll_info.trough=MagickTrue;
9167 north_info=scroll_info;
9168 north_info.raised=MagickTrue;
9169 north_info.width-=(north_info.bevel_width << 1);
9170 north_info.height=north_info.width-1;
9171 north_info.x+=(int) north_info.bevel_width;
9172 north_info.y+=(int) north_info.bevel_width;
9173 south_info=north_info;
9174 south_info.y=scroll_info.y+(int) scroll_info.height-(int)
9175 scroll_info.bevel_width-(int) south_info.height;
9176 id=slider_info.id;
9177 slider_info=north_info;
9178 slider_info.id=id;
9179 slider_info.width-=2;
9180 slider_info.min_y=north_info.y+(int) north_info.height+(int)
9181 north_info.bevel_width+(int) slider_info.bevel_width+2;
9182 slider_info.height=(unsigned int) ((int) scroll_info.height-
9183 ((slider_info.min_y-scroll_info.y+1) << 1)+4);
9184 visible_lines=(unsigned int) (scroll_info.height*MagickSafeReciprocal(
9185 (double) text_info->ascent+text_info->descent+((text_info->ascent+
9186 text_info->descent) >> 3)));
9187 if (lines > visible_lines)
9188 slider_info.height=(unsigned int) (visible_lines*slider_info.height)/
9189 lines;
9190 slider_info.max_y=south_info.y-(int) south_info.bevel_width-(int)
9191 slider_info.bevel_width-2;
9192 slider_info.x=scroll_info.x+(int) slider_info.bevel_width+1;
9193 slider_info.y=slider_info.min_y;
9194 expose_info=scroll_info;
9195 expose_info.y=slider_info.y;
9196 /*
9197 Initialize list information.
9198 */
9199 XGetWidgetInfo((char *) NULL,&list_info);
9200 list_info.raised=MagickFalse;
9201 list_info.bevel_width--;
9202 list_info.width=(unsigned int) (scroll_info.x-((3*QuantumMargin) >> 1));
9203 list_info.height=scroll_info.height;
9204 list_info.x=QuantumMargin;
9205 list_info.y=scroll_info.y;
9206 /*
9207 Initialize selection information.
9208 */
9209 XGetWidgetInfo((char *) NULL,&selection_info);
9210 selection_info.center=MagickFalse;
9211 selection_info.width=list_info.width;
9212 selection_info.height=(unsigned int)
9213 (9*(text_info->ascent+text_info->descent)) >> 3;
9214 selection_info.x=list_info.x;
9215 state&=(unsigned int) (~UpdateConfigurationState);
9216 }
9217 if (state & RedrawWidgetState)
9218 {
9219 /*
9220 Redraw Text View window.
9221 */
9222 XDrawBeveledMatte(display,&windows->widget,&list_info);
9223 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
9224 XDrawTriangleNorth(display,&windows->widget,&north_info);
9225 XDrawBeveledButton(display,&windows->widget,&slider_info);
9226 XDrawTriangleSouth(display,&windows->widget,&south_info);
9227 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9228 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
9229 selection_info.id=(~0);
9230 state|=RedrawListState;
9231 state&=(unsigned int) (~RedrawWidgetState);
9232 }
9233 if (state & RedrawListState)
9234 {
9235 /*
9236 Determine slider id and position.
9237 */
9238 if (slider_info.id >= (int) (lines-visible_lines))
9239 slider_info.id=(int) (lines-visible_lines);
9240 if ((slider_info.id < 0) || (lines <= visible_lines))
9241 slider_info.id=0;
9242 slider_info.y=slider_info.min_y;
9243 if (lines != 0)
9244 slider_info.y+=slider_info.id*(slider_info.max_y-
9245 slider_info.min_y+1)/(int) lines;
9246 if (slider_info.id != selection_info.id)
9247 {
9248 /*
9249 Redraw scroll bar and text.
9250 */
9251 windows->widget.font_info=text_info;
9252 (void) XSetFont(display,windows->widget.annotate_context,
9253 text_info->fid);
9254 (void) XSetFont(display,windows->widget.highlight_context,
9255 text_info->fid);
9256 selection_info.id=slider_info.id;
9257 selection_info.y=list_info.y+(int) (height >> 3)+2;
9258 for (i=0; i < (int) visible_lines; i++)
9259 {
9260 selection_info.raised=
9261 (slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse;
9262 selection_info.text=(char *) NULL;
9263 if ((slider_info.id+i) < (int) lines)
9264 selection_info.text=(char *) textlist[slider_info.id+i];
9265 XDrawWidgetText(display,&windows->widget,&selection_info);
9266 selection_info.y+=(int) selection_info.height;
9267 }
9268 windows->widget.font_info=font_info;
9269 (void) XSetFont(display,windows->widget.annotate_context,
9270 font_info->fid);
9271 (void) XSetFont(display,windows->widget.highlight_context,
9272 font_info->fid);
9273 /*
9274 Update slider.
9275 */
9276 if (slider_info.y > expose_info.y)
9277 {
9278 expose_info.height=(unsigned int) (slider_info.y-expose_info.y);
9279 expose_info.y=slider_info.y-(int) expose_info.height-(int)
9280 slider_info.bevel_width-1;
9281 }
9282 else
9283 {
9284 expose_info.height=(unsigned int) (expose_info.y-slider_info.y);
9285 expose_info.y=slider_info.y+(int) slider_info.height+(int)
9286 slider_info.bevel_width+1;
9287 }
9288 XDrawTriangleNorth(display,&windows->widget,&north_info);
9289 XDrawMatte(display,&windows->widget,&expose_info);
9290 XDrawBeveledButton(display,&windows->widget,&slider_info);
9291 XDrawTriangleSouth(display,&windows->widget,&south_info);
9292 expose_info.y=slider_info.y;
9293 }
9294 state&=(unsigned int) (~RedrawListState);
9295 }
9296 /*
9297 Wait for next event.
9298 */
9299 if (north_info.raised && south_info.raised)
9300 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
9301 else
9302 {
9303 /*
9304 Brief delay before advancing scroll bar.
9305 */
9306 XDelay(display,delay);
9307 delay=SuspendTime;
9308 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
9309 if (north_info.raised == MagickFalse)
9310 if (slider_info.id > 0)
9311 {
9312 /*
9313 Move slider up.
9314 */
9315 slider_info.id--;
9316 state|=RedrawListState;
9317 }
9318 if (south_info.raised == MagickFalse)
9319 if (slider_info.id < (int) lines)
9320 {
9321 /*
9322 Move slider down.
9323 */
9324 slider_info.id++;
9325 state|=RedrawListState;
9326 }
9327 if (event.type != ButtonRelease)
9328 continue;
9329 }
9330 switch (event.type)
9331 {
9332 case ButtonPress:
9333 {
9334 if (MatteIsActive(slider_info,event.xbutton))
9335 {
9336 /*
9337 Track slider.
9338 */
9339 slider_info.active=MagickTrue;
9340 break;
9341 }
9342 if (MatteIsActive(north_info,event.xbutton))
9343 if (slider_info.id > 0)
9344 {
9345 /*
9346 Move slider up.
9347 */
9348 north_info.raised=MagickFalse;
9349 slider_info.id--;
9350 state|=RedrawListState;
9351 break;
9352 }
9353 if (MatteIsActive(south_info,event.xbutton))
9354 if (slider_info.id < (int) lines)
9355 {
9356 /*
9357 Move slider down.
9358 */
9359 south_info.raised=MagickFalse;
9360 slider_info.id++;
9361 state|=RedrawListState;
9362 break;
9363 }
9364 if (MatteIsActive(scroll_info,event.xbutton))
9365 {
9366 /*
9367 Move slider.
9368 */
9369 if (event.xbutton.y < slider_info.y)
9370 slider_info.id-=(int) (visible_lines-1);
9371 else
9372 slider_info.id+=(int) (visible_lines-1);
9373 state|=RedrawListState;
9374 break;
9375 }
9376 if (MatteIsActive(dismiss_info,event.xbutton))
9377 {
9378 /*
9379 User pressed Dismiss button.
9380 */
9381 dismiss_info.raised=MagickFalse;
9382 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9383 break;
9384 }
9385 if (MatteIsActive(list_info,event.xbutton))
9386 {
9387 int
9388 id;
9389
9390 static Time
9391 click_time;
9392
9393 /*
9394 User pressed list matte.
9395 */
9396 id=slider_info.id+(event.xbutton.y-(list_info.y+(int)
9397 (height >> 1))+1)/(int) selection_info.height;
9398 if (id >= (int) lines)
9399 break;
9400 if (id != list_info.id)
9401 {
9402 list_info.id=id;
9403 click_time=event.xbutton.time;
9404 break;
9405 }
9406 list_info.id=id;
9407 if (event.xbutton.time >= (click_time+(unsigned long) DoubleClick))
9408 {
9409 click_time=event.xbutton.time;
9410 break;
9411 }
9412 click_time=event.xbutton.time;
9413 /*
9414 Become the XA_PRIMARY selection owner.
9415 */
9416 (void) CopyMagickString(primary_selection,textlist[list_info.id],
9417 MagickPathExtent);
9418 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
9419 event.xbutton.time);
9420 if (XGetSelectionOwner(display,XA_PRIMARY) != windows->widget.id)
9421 break;
9422 selection_info.id=(~0);
9423 list_info.id=id;
9424 state|=RedrawListState;
9425 break;
9426 }
9427 break;
9428 }
9429 case ButtonRelease:
9430 {
9431 if (windows->widget.mapped == MagickFalse)
9432 break;
9433 if (north_info.raised == MagickFalse)
9434 {
9435 /*
9436 User released up button.
9437 */
9438 delay=SuspendTime << 2;
9439 north_info.raised=MagickTrue;
9440 XDrawTriangleNorth(display,&windows->widget,&north_info);
9441 }
9442 if (south_info.raised == MagickFalse)
9443 {
9444 /*
9445 User released down button.
9446 */
9447 delay=SuspendTime << 2;
9448 south_info.raised=MagickTrue;
9449 XDrawTriangleSouth(display,&windows->widget,&south_info);
9450 }
9451 if (slider_info.active)
9452 {
9453 /*
9454 Stop tracking slider.
9455 */
9456 slider_info.active=MagickFalse;
9457 break;
9458 }
9459 if (dismiss_info.raised == MagickFalse)
9460 {
9461 if (event.xbutton.window == windows->widget.id)
9462 if (MatteIsActive(dismiss_info,event.xbutton))
9463 state|=ExitState;
9464 dismiss_info.raised=MagickTrue;
9465 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9466 }
9467 break;
9468 }
9469 case ClientMessage:
9470 {
9471 /*
9472 If client window delete message, exit.
9473 */
9474 if (event.xclient.message_type != windows->wm_protocols)
9475 break;
9476 if (*event.xclient.data.l == (int) windows->wm_take_focus)
9477 {
9478 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
9479 (Time) event.xclient.data.l[1]);
9480 break;
9481 }
9482 if (*event.xclient.data.l != (int) windows->wm_delete_window)
9483 break;
9484 if (event.xclient.window == windows->widget.id)
9485 {
9486 state|=ExitState;
9487 break;
9488 }
9489 break;
9490 }
9491 case ConfigureNotify:
9492 {
9493 /*
9494 Update widget configuration.
9495 */
9496 if (event.xconfigure.window != windows->widget.id)
9497 break;
9498 if ((event.xconfigure.width == (int) windows->widget.width) &&
9499 (event.xconfigure.height == (int) windows->widget.height))
9500 break;
9501 windows->widget.width=(unsigned int)
9502 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
9503 windows->widget.height=(unsigned int)
9504 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
9505 state|=UpdateConfigurationState;
9506 break;
9507 }
9508 case EnterNotify:
9509 {
9510 if (event.xcrossing.window != windows->widget.id)
9511 break;
9512 state&=(unsigned int) (~InactiveWidgetState);
9513 break;
9514 }
9515 case Expose:
9516 {
9517 if (event.xexpose.window != windows->widget.id)
9518 break;
9519 if (event.xexpose.count != 0)
9520 break;
9521 state|=RedrawWidgetState;
9522 break;
9523 }
9524 case KeyPress:
9525 {
9526 static char
9527 command[MagickPathExtent];
9528
9529 static int
9530 length;
9531
9532 static KeySym
9533 key_symbol;
9534
9535 /*
9536 Respond to a user key press.
9537 */
9538 if (event.xkey.window != windows->widget.id)
9539 break;
9540 length=XLookupString((XKeyEvent *) &event.xkey,command,
9541 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9542 *(command+length)='\0';
9543 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
9544 {
9545 dismiss_info.raised=MagickFalse;
9546 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9547 state|=ExitState;
9548 break;
9549 }
9550 if (AreaIsActive(scroll_info,event.xkey))
9551 {
9552 /*
9553 Move slider.
9554 */
9555 switch ((int) key_symbol)
9556 {
9557 case XK_Home:
9558 case XK_KP_Home:
9559 {
9560 slider_info.id=0;
9561 break;
9562 }
9563 case XK_Up:
9564 case XK_KP_Up:
9565 {
9566 slider_info.id--;
9567 break;
9568 }
9569 case XK_Down:
9570 case XK_KP_Down:
9571 {
9572 slider_info.id++;
9573 break;
9574 }
9575 case XK_Prior:
9576 case XK_KP_Prior:
9577 {
9578 slider_info.id-=(int) visible_lines;
9579 break;
9580 }
9581 case XK_Next:
9582 case XK_KP_Next:
9583 {
9584 slider_info.id+=(int) visible_lines;
9585 break;
9586 }
9587 case XK_End:
9588 case XK_KP_End:
9589 {
9590 slider_info.id=(int) lines;
9591 break;
9592 }
9593 }
9594 state|=RedrawListState;
9595 break;
9596 }
9597 break;
9598 }
9599 case KeyRelease:
9600 break;
9601 case LeaveNotify:
9602 {
9603 if (event.xcrossing.window != windows->widget.id)
9604 break;
9605 state|=InactiveWidgetState;
9606 break;
9607 }
9608 case MapNotify:
9609 {
9610 mask&=(unsigned int) (~CWX);
9611 mask&=(unsigned int) (~CWY);
9612 break;
9613 }
9614 case MotionNotify:
9615 {
9616 /*
9617 Discard pending button motion events.
9618 */
9619 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
9620 if (slider_info.active)
9621 {
9622 /*
9623 Move slider matte.
9624 */
9625 slider_info.y=event.xmotion.y-(int)
9626 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
9627 if (slider_info.y < slider_info.min_y)
9628 slider_info.y=slider_info.min_y;
9629 if (slider_info.y > slider_info.max_y)
9630 slider_info.y=slider_info.max_y;
9631 slider_info.id=0;
9632 if (slider_info.y != slider_info.min_y)
9633 slider_info.id=((int) lines*(slider_info.y-slider_info.min_y+1))/
9634 (slider_info.max_y-slider_info.min_y+1);
9635 state|=RedrawListState;
9636 break;
9637 }
9638 if (state & InactiveWidgetState)
9639 break;
9640 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
9641 {
9642 /*
9643 Dismiss button status changed.
9644 */
9645 dismiss_info.raised=
9646 dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
9647 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9648 break;
9649 }
9650 break;
9651 }
9652 case SelectionClear:
9653 {
9654 list_info.id=(~0);
9655 selection_info.id=(~0);
9656 state|=RedrawListState;
9657 break;
9658 }
9659 case SelectionRequest:
9660 {
9661 XSelectionEvent
9662 notify;
9663
9664 XSelectionRequestEvent
9665 *request;
9666
9667 if (list_info.id == (~0))
9668 break;
9669 /*
9670 Set primary selection.
9671 */
9672 request=(&(event.xselectionrequest));
9673 (void) XChangeProperty(request->display,request->requestor,
9674 request->property,request->target,8,PropModeReplace,
9675 (unsigned char *) primary_selection,Extent(primary_selection));
9676 notify.type=SelectionNotify;
9677 notify.send_event=MagickTrue;
9678 notify.display=request->display;
9679 notify.requestor=request->requestor;
9680 notify.selection=request->selection;
9681 notify.target=request->target;
9682 notify.time=request->time;
9683 if (request->property == None)
9684 notify.property=request->target;
9685 else
9686 notify.property=request->property;
9687 (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
9688 (XEvent *) &notify);
9689 }
9690 default:
9691 break;
9692 }
9693 } while ((state & ExitState) == 0);
9694 if (text_info != windows->widget.font_info)
9695 (void) XFreeFont(display,text_info);
9696 XSetCursorState(display,windows,MagickFalse);
9697 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
9698 XCheckRefreshWindows(display,windows);
9699}
9700#endif