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