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