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