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