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