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