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