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