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