SimpleMenu.c revision 7a84e134
1/* $Xorg: SimpleMenu.c,v 1.4 2001/02/09 02:03:45 xorgcvs Exp $ */ 2 3/* 4Copyright 1989, 1994, 1998 The Open Group 5 6Permission to use, copy, modify, distribute, and sell this software and its 7documentation for any purpose is hereby granted without fee, provided that 8the above copyright notice appear in all copies and that both that 9copyright notice and this permission notice appear in supporting 10documentation. 11 12The above copyright notice and this permission notice shall be included in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall not be 23used in advertising or otherwise to promote the sale, use or other dealings 24in this Software without prior written authorization from The Open Group. 25 */ 26 27/* $XFree86: xc/lib/Xaw/SimpleMenu.c,v 3.21 2001/03/23 23:59:15 paulo Exp $ */ 28 29/* 30 * SimpleMenu.c - Source code file for SimpleMenu widget. 31 * 32 * Date: April 3, 1989 33 * 34 * By: Chris D. Peterson 35 * MIT X Consortium 36 * kit@expo.lcs.mit.edu 37 */ 38 39#ifdef HAVE_CONFIG_H 40#include <config.h> 41#endif 42#include <stdio.h> 43#include <X11/IntrinsicP.h> 44#include <X11/StringDefs.h> 45#include <X11/Xmu/Initer.h> 46#include <X11/Xmu/SysUtil.h> 47#include <X11/Xaw/Cardinals.h> 48#include <X11/Xaw/SimpleMenP.h> 49#include <X11/Xaw/SmeBSBP.h> 50#include <X11/Xaw/XawInit.h> 51#include "Private.h" 52 53#define streq(a, b) (strcmp((a), (b)) == 0) 54 55#define ForAllChildren(smw, childP) \ 56for ((childP) = (SmeObject *)(smw)->composite.children; \ 57 (childP) < (SmeObject *)((smw)->composite.children \ 58 + (smw)->composite.num_children); \ 59 (childP)++) 60 61#ifndef OLDXAW 62#define SMW_UNMAPPING 0x01 63#define SMW_POPLEFT 0x02 64#endif 65 66/* 67 * Class Methods 68 */ 69static void XawSimpleMenuChangeManaged(Widget); 70static void XawSimpleMenuClassInitialize(void); 71static void XawSimpleMenuClassPartInitialize(WidgetClass); 72static XtGeometryResult XawSimpleMenuGeometryManager(Widget, XtWidgetGeometry*, 73 XtWidgetGeometry*); 74static void XawSimpleMenuInitialize(Widget, Widget, ArgList, Cardinal*); 75static void XawSimpleMenuRealize(Widget, XtValueMask*, XSetWindowAttributes*); 76static void XawSimpleMenuRedisplay(Widget, XEvent*, Region); 77static void XawSimpleMenuResize(Widget); 78static Boolean XawSimpleMenuSetValues(Widget, Widget, Widget, 79 ArgList, Cardinal*); 80static Boolean XawSimpleMenuSetValuesHook(Widget, ArgList, Cardinal*); 81#ifndef OLDXAW 82static void PopupSubMenu(SimpleMenuWidget); 83static void PopdownSubMenu(SimpleMenuWidget); 84static void PopupCB(Widget, XtPointer, XtPointer); 85#endif 86 87/* 88 * Prototypes 89 */ 90static void AddPositionAction(XtAppContext, XPointer); 91static void CalculateNewSize(Widget, Dimension*, Dimension*); 92static void ChangeCursorOnGrab(Widget, XtPointer, XtPointer); 93static void CreateLabel(Widget); 94static SmeObject DoGetEventEntry(Widget, int, int); 95static Widget FindMenu(Widget, String); 96static SmeObject GetEventEntry(Widget, XEvent*); 97static void Layout(Widget, Dimension*, Dimension*); 98static void MakeResizeRequest(Widget); 99static void MakeSetValuesRequest(Widget, unsigned int, unsigned int); 100static void MoveMenu(Widget, int, int); 101static void PositionMenu(Widget, XPoint*); 102 103/* 104 * Actions 105 */ 106static void Highlight(Widget, XEvent*, String*, Cardinal*); 107static void Notify(Widget, XEvent*, String*, Cardinal*); 108#ifndef OLDXAW 109static void Popdown(Widget, XEvent*, String*, Cardinal*); 110#endif 111static void PositionMenuAction(Widget, XEvent*, String*, Cardinal*); 112static void Unhighlight(Widget, XEvent*, String*, Cardinal*); 113 114/* 115 * Initialization 116 */ 117#define offset(field) XtOffsetOf(SimpleMenuRec, simple_menu.field) 118 119static XtResource resources[] = { 120 /* label */ 121 { 122 XtNlabel, 123 XtCLabel, 124 XtRString, 125 sizeof(String), 126 offset(label_string), 127 XtRString, 128 NULL 129 }, 130 { 131 XtNlabelClass, 132 XtCLabelClass, 133 XtRPointer, 134 sizeof(WidgetClass), 135 offset(label_class), 136 XtRImmediate, 137 NULL 138 }, 139 140 /* layout */ 141 { 142 XtNrowHeight, 143 XtCRowHeight, 144 XtRDimension, 145 sizeof(Dimension), 146 offset(row_height), 147 XtRImmediate, 148 (XtPointer)0 149 }, 150 { 151 XtNtopMargin, 152 XtCVerticalMargins, 153 XtRDimension, 154 sizeof(Dimension), 155 offset(top_margin), 156 XtRImmediate, 157 (XtPointer)0 158 }, 159 { 160 XtNbottomMargin, 161 XtCVerticalMargins, 162 XtRDimension, 163 sizeof(Dimension), 164 offset(bottom_margin), 165 XtRImmediate, 166 (XtPointer)0 167 }, 168#ifndef OLDXAW 169 { 170 XtNleftMargin, 171 XtCHorizontalMargins, 172 XtRDimension, 173 sizeof(Dimension), 174 offset(left_margin), 175 XtRImmediate, 176 (XtPointer)0 177 }, 178 { 179 XtNrightMargin, 180 XtCHorizontalMargins, 181 XtRDimension, 182 sizeof(Dimension), 183 offset(right_margin), 184 XtRImmediate, 185 (XtPointer)0 186 }, 187#endif 188 189 /* misc */ 190 { 191 XtNallowShellResize, 192 XtCAllowShellResize, 193 XtRBoolean, 194 sizeof(Boolean), 195 XtOffsetOf(SimpleMenuRec, shell.allow_shell_resize), 196 XtRImmediate, 197 (XtPointer)True 198 }, 199 { 200 XtNcursor, 201 XtCCursor, 202 XtRCursor, 203 sizeof(Cursor), 204 offset(cursor), 205 XtRImmediate, 206 (XtPointer)None 207 }, 208 { 209 XtNmenuOnScreen, 210 XtCMenuOnScreen, 211 XtRBoolean, 212 sizeof(Boolean), 213 offset(menu_on_screen), 214 XtRImmediate, 215 (XtPointer)True 216 }, 217 { 218 XtNpopupOnEntry, 219 XtCPopupOnEntry, 220 XtRWidget, 221 sizeof(Widget), 222 offset(popup_entry), 223 XtRWidget, 224 NULL 225 }, 226 { 227 XtNbackingStore, 228 XtCBackingStore, 229 XtRBackingStore, 230 sizeof(int), 231 offset(backing_store), 232 XtRImmediate, 233 (XtPointer)(Always + WhenMapped + NotUseful) 234 }, 235#ifndef OLDXAW 236 { 237 XawNdisplayList, 238 XawCDisplayList, 239 XawRDisplayList, 240 sizeof(XawDisplayList*), 241 offset(display_list), 242 XtRImmediate, 243 NULL 244 }, 245#endif 246}; 247#undef offset 248 249static char defaultTranslations[] = 250"<Enter>:" "highlight()\n" 251"<Leave>:" "unhighlight()\n" 252"<BtnMotion>:" "highlight()\n" 253#ifndef OLDXAW 254"<BtnUp>:" "popdown() notify() unhighlight()\n" 255#else 256"<BtnUp>:" "MenuPopdown() notify() unhighlight()\n" 257#endif 258; 259 260static XtActionsRec actionsList[] = 261{ 262 {"notify", Notify}, 263 {"highlight", Highlight}, 264 {"unhighlight", Unhighlight}, 265#ifndef OLDXAW 266 {"popdown", Popdown}, 267 {"set-values", XawSetValuesAction}, 268 {"get-values", XawGetValuesAction}, 269 {"declare", XawDeclareAction}, 270 {"call-proc", XawCallProcAction}, 271#endif 272}; 273 274static CompositeClassExtensionRec extension_rec = { 275 NULL, /* next_extension */ 276 NULLQUARK, /* record_type */ 277 XtCompositeExtensionVersion, /* version */ 278 sizeof(CompositeClassExtensionRec), /* record_size */ 279 True, /* accepts_objects */ 280}; 281 282#define Superclass (&overrideShellClassRec) 283SimpleMenuClassRec simpleMenuClassRec = { 284 /* core */ 285 { 286 (WidgetClass)Superclass, /* superclass */ 287 "SimpleMenu", /* class_name */ 288 sizeof(SimpleMenuRec), /* size */ 289 XawSimpleMenuClassInitialize, /* class_initialize */ 290 XawSimpleMenuClassPartInitialize, /* class_part_initialize */ 291 False, /* class_inited */ 292 XawSimpleMenuInitialize, /* initialize */ 293 NULL, /* initialize_hook */ 294 XawSimpleMenuRealize, /* realize */ 295 actionsList, /* actions */ 296 XtNumber(actionsList), /* num_actions */ 297 resources, /* resources */ 298 XtNumber(resources), /* num_resources */ 299 NULLQUARK, /* xrm_class */ 300 True, /* compress_motion */ 301 True, /* compress_exposure */ 302 True, /* compress_enterleave */ 303 False, /* visible_interest */ 304 NULL, /* destroy */ 305 XawSimpleMenuResize, /* resize */ 306 XawSimpleMenuRedisplay, /* expose */ 307 XawSimpleMenuSetValues, /* set_values */ 308 XawSimpleMenuSetValuesHook, /* set_values_hook */ 309 XtInheritSetValuesAlmost, /* set_values_almost */ 310 NULL, /* get_values_hook */ 311 NULL, /* accept_focus */ 312 XtVersion, /* intrinsics version */ 313 NULL, /* callback offsets */ 314 defaultTranslations, /* tm_table */ 315 NULL, /* query_geometry */ 316 NULL, /* display_accelerator */ 317 NULL, /* extension */ 318 }, 319 /* composite */ 320 { 321 XawSimpleMenuGeometryManager, /* geometry_manager */ 322 XawSimpleMenuChangeManaged, /* change_managed */ 323 XtInheritInsertChild, /* insert_child */ 324 XtInheritDeleteChild, /* delete_child */ 325 NULL, /* extension */ 326 }, 327 /* shell */ 328 { 329 NULL, /* extension */ 330 }, 331 /* override */ 332 { 333 NULL, /* extension */ 334 }, 335 /* simple_menu */ 336 { 337 NULL, /* extension */ 338 }, 339}; 340 341WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec; 342 343/* 344 * Implementation 345 */ 346/* 347 * Function: 348 * XawSimpleMenuClassInitialize 349 * 350 * Description: 351 * Class Initialize routine, called only once. 352 */ 353static void 354XawSimpleMenuClassInitialize(void) 355{ 356 XawInitializeWidgetSet(); 357 XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore, 358 NULL, 0); 359 XtSetTypeConverter(XtRBackingStore, XtRString, XmuCvtBackingStoreToString, 360 NULL, 0, XtCacheNone, NULL); 361 XmuAddInitializer(AddPositionAction, NULL); 362} 363 364/* 365 * Function: 366 * XawSimpleMenuClassPartInitialize 367 * Arguments: wc - the widget class of the subclass. 368 * 369 * Description: 370 * Class Part Initialize routine, called for every subclass. Makes 371 * sure that the subclasses pick up the extension record. 372 */ 373static void 374XawSimpleMenuClassPartInitialize(WidgetClass wc) 375{ 376 SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass)wc; 377 378 /* 379 * Make sure that our subclass gets the extension rec too 380 */ 381 extension_rec.next_extension = smwc->composite_class.extension; 382 smwc->composite_class.extension = (XtPointer) &extension_rec; 383} 384 385/* 386 * Function: 387 * XawSimpleMenuInitialize 388 * 389 * Parameters: 390 * request - widget requested by the argument list 391 * cnew - new widget with both resource and non resource values 392 * 393 * Description: 394 * Initializes the simple menu widget. 395 */ 396/*ARGSUSED*/ 397static void 398XawSimpleMenuInitialize(Widget request, Widget cnew, 399 ArgList args, Cardinal *num_args) 400{ 401 SimpleMenuWidget smw = (SimpleMenuWidget)cnew; 402 Dimension width, height; 403 404 XmuCallInitializers(XtWidgetToApplicationContext(cnew)); 405 406 if (smw->simple_menu.label_class == NULL) 407 smw->simple_menu.label_class = smeBSBObjectClass; 408 409 smw->simple_menu.label = NULL; 410 smw->simple_menu.entry_set = NULL; 411 smw->simple_menu.recursive_set_values = False; 412#ifndef OLDXAW 413 smw->simple_menu.sub_menu = NULL; 414 smw->simple_menu.state = 0; 415 416 XtAddCallback(cnew, XtNpopupCallback, PopupCB, NULL); 417#endif 418 419 if (smw->simple_menu.label_string != NULL) 420 CreateLabel(cnew); 421 422 width = height = 0; 423 CalculateNewSize(cnew, &width, &height); 424 425 smw->simple_menu.menu_width = True; 426 427 if (XtWidth(smw) == 0) { 428 smw->simple_menu.menu_width = False; 429 XtWidth(smw) = width; 430 } 431 432 smw->simple_menu.menu_height = True; 433 434 if (XtHeight(smw) == 0) { 435 smw->simple_menu.menu_height = False; 436 XtHeight(smw) = height; 437 } 438 439 /* 440 * Add a popup_callback routine for changing the cursor 441 */ 442 XtAddCallback(cnew, XtNpopupCallback, ChangeCursorOnGrab, NULL); 443} 444 445/* 446 * Function: 447 * XawSimpleMenuRedisplay 448 * 449 * Parameters: 450 * w - simple menu widget 451 * event - X event that caused this redisplay 452 * region - region the needs to be repainted 453 * 454 * Description: 455 * Redisplays the contents of the widget. 456 */ 457/*ARGSUSED*/ 458static void 459XawSimpleMenuRedisplay(Widget w, XEvent *event, Region region) 460{ 461 SimpleMenuWidget smw = (SimpleMenuWidget)w; 462 SmeObject *entry; 463 SmeObjectClass cclass; 464 465 if (region == NULL) 466 XClearWindow(XtDisplay(w), XtWindow(w)); 467 468#ifndef OLDXAW 469 if (smw->simple_menu.display_list) 470 XawRunDisplayList(w, smw->simple_menu.display_list, event, region); 471#endif 472 473 /* 474 * Check and Paint each of the entries - including the label 475 */ 476 ForAllChildren(smw, entry) { 477 if (!XtIsManaged((Widget)*entry)) 478 continue; 479 480 if (region != NULL) 481 switch(XRectInRegion(region, XtX(*entry),XtY(*entry), 482 XtWidth(*entry), XtHeight(*entry))) { 483 case RectangleIn: 484 case RectanglePart: 485 break; 486 default: 487 continue; 488 } 489 490 cclass = (SmeObjectClass)(*entry)->object.widget_class; 491 492 if (cclass->rect_class.expose != NULL) 493 (cclass->rect_class.expose)((Widget)*entry, NULL, NULL); 494 } 495} 496 497/* 498 * Function: 499 * XawSimpleMenuRealize 500 * 501 * Parameters: 502 * w - simple menu widget 503 * mask - value mask for the window to create 504 * attrs - attributes for the window to create 505 * 506 * Description: 507 * Realizes the widget. 508 */ 509static void 510XawSimpleMenuRealize(Widget w, XtValueMask *mask, XSetWindowAttributes *attrs) 511{ 512 SimpleMenuWidget smw = (SimpleMenuWidget)w; 513#ifndef OLDXAW 514 XawPixmap *pixmap; 515#endif 516 517 attrs->cursor = smw->simple_menu.cursor; 518 *mask |= CWCursor; 519 if (smw->simple_menu.backing_store == Always || 520 smw->simple_menu.backing_store == NotUseful || 521 smw->simple_menu.backing_store == WhenMapped) { 522 *mask |= CWBackingStore; 523 attrs->backing_store = smw->simple_menu.backing_store; 524 } 525 else 526 *mask &= ~CWBackingStore; 527 528 (*Superclass->core_class.realize)(w, mask, attrs); 529 530#ifndef OLDXAW 531 if (w->core.background_pixmap > XtUnspecifiedPixmap) { 532 pixmap = XawPixmapFromXPixmap(w->core.background_pixmap, XtScreen(w), 533 w->core.colormap, w->core.depth); 534 if (pixmap && pixmap->mask) 535 XawReshapeWidget(w, pixmap); 536 } 537#endif 538} 539 540/* 541 * Function: 542 * XawSimpleMenuResize 543 * 544 * Parameters: 545 * w - simple menu widget 546 * 547 * Description: 548 * Handle the menu being resized. 549 */ 550static void 551XawSimpleMenuResize(Widget w) 552{ 553 if (!XtIsRealized(w)) 554 return; 555 556 Layout(w, NULL, NULL); 557 558 XawSimpleMenuRedisplay(w, NULL, NULL); 559} 560 561/* 562 * Function: 563 * XawSimpleMenuSetValues 564 * 565 * Parameters: 566 * current - current state of the widget 567 * request - what was requested 568 * cnew - what the widget will become 569 * 570 * Description: 571 * Relayout the menu when one of the resources is changed. 572 */ 573/*ARGSUSED*/ 574static Boolean 575XawSimpleMenuSetValues(Widget current, Widget request, Widget cnew, 576 ArgList args, Cardinal *num_args) 577{ 578 SimpleMenuWidget smw_old = (SimpleMenuWidget)current; 579 SimpleMenuWidget smw_new = (SimpleMenuWidget)cnew; 580 Boolean ret_val = False, layout = False; 581 582 if (!XtIsRealized(current)) 583 return (False); 584 585 if (!smw_new->simple_menu.recursive_set_values) { 586 if (XtWidth(smw_new) != XtWidth(smw_old)) { 587 smw_new->simple_menu.menu_width = XtWidth(smw_new) != 0; 588 layout = True; 589 } 590 if (XtHeight(smw_new) != XtHeight(smw_old)) { 591 smw_new->simple_menu.menu_height = XtHeight(smw_new) != 0; 592 layout = True; 593 } 594 } 595 596 if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor) 597 XDefineCursor(XtDisplay(cnew), XtWindow(cnew), 598 smw_new->simple_menu.cursor); 599 600 if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string) { 601 if (smw_new->simple_menu.label_string == NULL) /* Destroy */ 602 XtDestroyWidget((Widget)smw_old->simple_menu.label); 603 else if (smw_old->simple_menu.label_string == NULL) /* Create */ 604 CreateLabel(cnew); 605 else { /* Change */ 606 Arg arglist[1]; 607 608 XtSetArg(arglist[0], XtNlabel, smw_new->simple_menu.label_string); 609 XtSetValues((Widget)smw_new->simple_menu.label, arglist, ONE); 610 } 611 } 612 613 if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class) 614 XtAppWarning(XtWidgetToApplicationContext(cnew), 615 "No Dynamic class change of the SimpleMenu Label."); 616 617 if (smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin 618 || smw_old->simple_menu.bottom_margin 619 != smw_new->simple_menu.bottom_margin) { 620 layout = True; 621 ret_val = True; 622 } 623 624#ifndef OLDXAW 625 if (smw_old->core.background_pixmap != smw_new->core.background_pixmap) { 626 XawPixmap *opix, *npix; 627 628 opix = XawPixmapFromXPixmap(smw_old->core.background_pixmap, 629 XtScreen(smw_old), smw_old->core.colormap, 630 smw_old->core.depth); 631 npix = XawPixmapFromXPixmap(smw_new->core.background_pixmap, 632 XtScreen(smw_new), smw_new->core.colormap, 633 smw_new->core.depth); 634 if ((npix && npix->mask) || (opix && opix->mask)) 635 XawReshapeWidget(cnew, npix); 636 } 637#endif 638 639 if (layout) 640 Layout(cnew, NULL, NULL); 641 642 return (ret_val); 643} 644 645/* 646 * Function: 647 * XawSimpleMenuSetValuesHook 648 * 649 * Parameters: 650 * w - menu widget 651 * arglist - argument list passed to XtSetValues 652 * num_args - number of args 653 * 654 * Description: 655 * To handle a special case, this is passed the actual arguments. 656 */ 657static Boolean 658XawSimpleMenuSetValuesHook(Widget w, ArgList arglist, Cardinal *num_args) 659{ 660 Cardinal i; 661 Dimension width, height; 662 663 width = XtWidth(w); 664 height = XtHeight(w); 665 666 for (i = 0 ; i < *num_args ; i++) { 667 if (streq(arglist[i].name, XtNwidth)) 668 width = (Dimension)arglist[i].value; 669 if (streq(arglist[i].name, XtNheight)) 670 height = (Dimension) arglist[i].value; 671 } 672 673 if (width != XtWidth(w) || height != XtHeight(w)) 674 MakeSetValuesRequest(w, width, height); 675 676 return (False); 677} 678 679/* 680 * Geometry Management routines 681 */ 682/* 683 * Function: 684 * XawSimpleMenuGeometryManager 685 * 686 * Parameters: 687 * w - Menu Entry making the request 688 * request - requested new geometry 689 * reply - the allowed geometry. 690 * 691 * Description: 692 * This is the SimpleMenu Widget's Geometry Manager. 693 * 694 * Returns: 695 * XtGeometry{Yes, No, Almost} 696 */ 697static XtGeometryResult 698XawSimpleMenuGeometryManager(Widget w, XtWidgetGeometry *request, 699 XtWidgetGeometry *reply) 700{ 701 SimpleMenuWidget smw = (SimpleMenuWidget)XtParent(w); 702 SmeObject entry = (SmeObject)w; 703 XtGeometryMask mode = request->request_mode; 704 XtGeometryResult answer; 705 Dimension old_height, old_width; 706 707 if (!(mode & CWWidth) && !(mode & CWHeight)) 708 return (XtGeometryNo); 709 710 reply->width = request->width; 711 reply->height = request->height; 712 713 old_width = XtWidth(entry); 714 old_height = XtHeight(entry); 715 716 Layout(w, &reply->width, &reply->height); 717 718 /* 719 * Since we are an override shell and have no parent there is no one to 720 * ask to see if this geom change is okay, so I am just going to assume 721 * we can do whatever we want. If you subclass be very careful with this 722 * assumption, it could bite you. 723 * 724 * Chris D. Peterson - Sept. 1989. 725 */ 726 if ((!(mode & CWWidth) || reply->width == request->width) 727 && (!(mode & CWHeight) || reply->height == request->height)) { 728 if (mode & XtCWQueryOnly) { /* Actually perform the layout */ 729 XtWidth(entry) = old_width; 730 XtHeight(entry) = old_height; 731 } 732 else 733 Layout((Widget)smw, NULL, NULL); 734 answer = XtGeometryDone; 735 } 736 else { 737 XtWidth(entry) = old_width; 738 XtHeight(entry) = old_height; 739 740 if ((reply->width == request->width && !(mode & CWHeight)) 741 || (reply->height == request->height && !(mode & CWWidth)) 742 || (reply->width == request->width 743 && reply->height == request->height)) 744 answer = XtGeometryNo; 745 else { 746 answer = XtGeometryAlmost; 747 reply->request_mode = 0; 748 if (reply->width != request->width) 749 reply->request_mode |= CWWidth; 750 if (reply->height != request->height) 751 reply->request_mode |= CWHeight; 752 } 753 } 754 755 return (answer); 756} 757 758/* 759 * Function: 760 * XawSimpleMenuChangeManaged 761 * 762 * Parameters: 763 * w - simple menu widget 764 * 765 * Description: 766 * Called whenever a new child is managed. 767 */ 768static void 769XawSimpleMenuChangeManaged(Widget w) 770{ 771 Layout(w, NULL, NULL); 772} 773 774/* 775 * Global Action Routines 776 * 777 * These actions routines will be added to the application's 778 * global action list 779 */ 780/* 781 * Function: 782 * PositionMenuAction 783 * 784 * Parameters: 785 * w - a widget (no the simple menu widget) 786 * event - the event that caused this action 787 * params - parameters passed to the routine. 788 * we expect the name of the menu here. 789 * num_params - "" 790 * 791 * Description: 792 * Positions the simple menu widget. 793 */ 794/*ARGSUSED*/ 795static void 796PositionMenuAction(Widget w, XEvent *event, 797 String *params, Cardinal *num_params) 798{ 799 Widget menu; 800 XPoint loc; 801 802 if (*num_params != 1) { 803 XtAppWarning(XtWidgetToApplicationContext(w), 804 "SimpleMenuWidget: position menu action expects " 805 "only one parameter which is the name of the menu."); 806 return; 807 } 808 809 if ((menu = FindMenu(w, params[0])) == NULL) { 810 char error_buf[BUFSIZ]; 811 812 (void)XmuSnprintf(error_buf, sizeof(error_buf), 813 "SimpleMenuWidget: could not find menu named %s.", 814 params[0]); 815 XtAppWarning(XtWidgetToApplicationContext(w), error_buf); 816 return; 817 } 818 819 switch (event->type) { 820 case ButtonPress: 821 case ButtonRelease: 822 loc.x = event->xbutton.x_root; 823 loc.y = event->xbutton.y_root; 824 PositionMenu(menu, &loc); 825 break; 826 case EnterNotify: 827 case LeaveNotify: 828 loc.x = event->xcrossing.x_root; 829 loc.y = event->xcrossing.y_root; 830 PositionMenu(menu, &loc); 831 break; 832 case MotionNotify: 833 loc.x = event->xmotion.x_root; 834 loc.y = event->xmotion.y_root; 835 PositionMenu(menu, &loc); 836 break; 837 default: 838 PositionMenu(menu, NULL); 839 break; 840 } 841} 842 843/* 844 * Widget Action Routines 845 */ 846/* 847 * Function: 848 * Unhighlight 849 * 850 * Parameters: 851 * w - simple menu widget 852 * event - event that caused this action 853 * params - not used 854 * num_params - "" 855 * 856 * Description: 857 * Unhighlights current entry. 858 */ 859/*ARGSUSED*/ 860static void 861Unhighlight(Widget w, XEvent *event, String *params, Cardinal *num_params) 862{ 863 SimpleMenuWidget smw = (SimpleMenuWidget)w; 864 SmeObject entry = smw->simple_menu.entry_set; 865 866 if (entry == NULL) 867 return; 868 869#ifndef OLDXAW 870 if (!smw->simple_menu.sub_menu) 871#endif 872 { 873 SmeObjectClass cclass; 874 875 smw->simple_menu.entry_set = NULL; 876 cclass = (SmeObjectClass)entry->object.widget_class; 877 (cclass->sme_class.unhighlight)((Widget)entry); 878 } 879} 880 881/* 882 * Function: 883 * Highlight 884 * 885 * Parameters: 886 * w - simple menu widget 887 * event - event that caused this action 888 * params - not used 889 * num_params - "" 890 * 891 * Description: 892 * Highlights current entry. 893 */ 894/*ARGSUSED*/ 895static void 896Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params) 897{ 898 SimpleMenuWidget smw = (SimpleMenuWidget)w; 899 SmeObject entry; 900 901 if (!XtIsSensitive(w)) 902 return; 903 904 entry = GetEventEntry(w, event); 905 906 if (entry == smw->simple_menu.entry_set) 907 return; 908 909#ifndef OLDXAW 910 if (!smw->simple_menu.sub_menu) 911#endif 912 Unhighlight(w, event, params, num_params); 913 914 if (entry == NULL) 915 return; 916 917 if (!XtIsSensitive((Widget)entry)) 918 return; 919 920#ifndef OLDXAW 921 if (smw->simple_menu.sub_menu) 922 PopdownSubMenu(smw); 923#endif 924 925 Unhighlight(w, event, params, num_params); 926 927#ifndef OLDXAW 928 if (!(smw->simple_menu.state & SMW_UNMAPPING)) 929#endif 930 { 931 SmeObjectClass cclass; 932 933 smw->simple_menu.entry_set = entry; 934 cclass = (SmeObjectClass)entry->object.widget_class; 935 936 (cclass->sme_class.highlight)((Widget)entry); 937 938#ifndef OLDXAW 939 if (XtIsSubclass((Widget)entry, smeBSBObjectClass)) 940 PopupSubMenu(smw); 941#endif 942 } 943} 944 945/* 946 * Function: 947 * Notify 948 * 949 * Parameters: 950 * w - simple menu widget 951 * event - event that caused this action 952 * params - not used 953 * num_params - "" 954 * 955 * Description: 956 * Notify user of current entry. 957 */ 958/*ARGSUSED*/ 959static void 960Notify(Widget w, XEvent *event, String *params, Cardinal *num_params) 961{ 962 SmeObject entry; 963 SmeObjectClass cclass; 964 965 /* may be a propagated event from a sub menu, need to check it */ 966 if (XtWindow(w) != event->xany.window) 967 return; 968 entry = GetEventEntry(w, event); 969 if (entry == NULL || !XtIsSensitive((Widget)entry)) 970 return; 971 972 cclass = (SmeObjectClass) entry->object.widget_class; 973 (cclass->sme_class.notify)((Widget)entry); 974} 975 976/* 977 * Public Functions 978 */ 979/* 980 * Function: 981 * XawSimpleMenuAddGlobalActions 982 * 983 * Arguments: 984 * app_con - appcontext 985 * 986 * Description: 987 * Adds the global actions to the simple menu widget. 988 */ 989void 990XawSimpleMenuAddGlobalActions(XtAppContext app_con) 991{ 992 XtInitializeWidgetClass(simpleMenuWidgetClass); 993 XmuCallInitializers(app_con); 994} 995 996/* 997 * Function: 998 * XawSimpleMenuGetActiveEntry 999 * 1000 * Parameters: 1001 * w - smw widget 1002 * 1003 * Description: 1004 * Gets the currently active (set) entry. 1005 * 1006 * Returns: 1007 * The currently set entry or NULL if none is set 1008 */ 1009Widget 1010XawSimpleMenuGetActiveEntry(Widget w) 1011{ 1012 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1013 1014 return ((Widget)smw->simple_menu.entry_set); 1015} 1016 1017/* 1018 * Function: 1019 * XawSimpleMenuClearActiveEntry 1020 * 1021 * Parameters: 1022 * w - smw widget 1023 * 1024 * Description: 1025 * Unsets the currently active (set) entry. 1026 */ 1027void 1028XawSimpleMenuClearActiveEntry(Widget w) 1029{ 1030 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1031 1032 smw->simple_menu.entry_set = NULL; 1033} 1034 1035/* 1036 * Private Functions 1037 */ 1038/* 1039 * Function: 1040 * CreateLabel 1041 * 1042 * Parameters: 1043 * w - smw widget 1044 * 1045 * Description: 1046 * Creates the label object and makes sure it is the first child in 1047 * in the list. 1048 */ 1049static void 1050CreateLabel(Widget w) 1051{ 1052 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1053 Widget *child, *next_child; 1054 int i; 1055 Arg args[2]; 1056 1057 if (smw->simple_menu.label_string == NULL || 1058 smw->simple_menu.label != NULL) { 1059 XtAppWarning(XtWidgetToApplicationContext(w), 1060 "Xaw Simple Menu Widget: label string is NULL or " 1061 "label already exists, no label is being created."); 1062 return; 1063 } 1064 1065 XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string); 1066 XtSetArg(args[1], XtNjustify, XtJustifyCenter); 1067 smw->simple_menu.label = (SmeObject) 1068 XtCreateManagedWidget("menuLabel", 1069 smw->simple_menu.label_class, w, args, TWO); 1070 1071 next_child = NULL; 1072 for (child = smw->composite.children + smw->composite.num_children, 1073 i = smw->composite.num_children; i > 0; i--, child--) { 1074 if (next_child != NULL) 1075 *next_child = *child; 1076 next_child = child; 1077 } 1078 *child = (Widget)smw->simple_menu.label; 1079} 1080 1081/* 1082 * Function: 1083 * Layout 1084 * 1085 * Arguments: 1086 * w - See below 1087 * width_ret - returned width 1088 * height_ret - returned height 1089 * 1090 * Note: 1091 * if width == NULL || height == NULL then it assumes the you do not care 1092 * about the return values, and just want a relayout. 1093 * 1094 * if this is not the case then it will set width_ret and height_ret 1095 * to be width and height that the child would get if it were layed out 1096 * at this time. 1097 * 1098 * "w" can be the simple menu widget or any of its object children. 1099 */ 1100static void 1101Layout(Widget w, Dimension *width_ret, Dimension *height_ret) 1102{ 1103 SmeObject current_entry; 1104 SimpleMenuWidget smw; 1105 Dimension width, height; 1106 Boolean allow_change_size; 1107 Widget kid; 1108 Cardinal i, count, n; 1109 int width_kid, height_kid, tmp_w, tmp_h; 1110 short vadd, hadd, x_ins, y_ins; 1111 Dimension *widths; 1112 1113 height = 0; 1114 1115 if (XtIsSubclass(w, simpleMenuWidgetClass)) { 1116 smw = (SimpleMenuWidget)w; 1117 current_entry = NULL; 1118 } 1119 else { 1120 smw = (SimpleMenuWidget)XtParent(w); 1121 current_entry = (SmeObject)w; 1122 } 1123 1124 allow_change_size = (!XtIsRealized((Widget)smw) 1125 || smw->shell.allow_shell_resize); 1126 1127 for (i = smw->simple_menu.label ? 1 : 0; 1128 i < smw->composite.num_children; 1129 i++) { 1130 XtWidgetGeometry preferred; 1131 1132 kid = smw->composite.children[i]; 1133 if (!XtIsManaged(kid)) 1134 continue; 1135 if (smw->simple_menu.row_height != 0) 1136 XtHeight(kid) = smw->simple_menu.row_height; 1137 XtQueryGeometry(kid, NULL, &preferred); 1138 if (preferred.request_mode & CWWidth) 1139 XtWidth(kid) = preferred.width; 1140 } 1141 1142 if (smw->simple_menu.label 1143 && XtIsManaged((Widget)smw->simple_menu.label)) { 1144 XtWidgetGeometry preferred; 1145 1146 kid = (Widget)smw->simple_menu.label; 1147 XtQueryGeometry(kid, NULL, &preferred); 1148 if (preferred.request_mode & CWWidth) 1149 XtWidth(kid) = preferred.width; 1150 if (preferred.request_mode & CWHeight) 1151 XtHeight(kid) = preferred.height; 1152 } 1153 1154 /* reset */ 1155 if (!smw->simple_menu.menu_width) 1156 XtWidth(smw) = 0; 1157 if (!smw->simple_menu.menu_height) 1158 XtHeight(smw) = 0; 1159 if (!XtWidth(smw) || !XtHeight(smw)) 1160 MakeResizeRequest((Widget)smw); 1161 1162 widths = (Dimension *)XtMalloc(sizeof(Dimension)); 1163#ifndef OLDXAW 1164 hadd = smw->simple_menu.left_margin; 1165#else 1166 hadd = 0; 1167#endif 1168 vadd = smw->simple_menu.top_margin; 1169 if (smw->simple_menu.label) 1170 vadd += XtHeight(smw->simple_menu.label); 1171 1172 count = 1; 1173 width = tmp_w = tmp_h = n = 0; 1174 height = vadd; 1175 1176 for (i = smw->simple_menu.label ? 1 : 0; 1177 i < smw->composite.num_children; 1178 i++) { 1179 kid = smw->composite.children[i]; 1180 if (!XtIsManaged(kid)) 1181 continue; 1182 width_kid = XtWidth(kid); 1183 height_kid = XtHeight(kid); 1184 1185 if (n && (height + height_kid + smw->simple_menu.bottom_margin 1186 > XtHeight(smw))) { 1187 ++count; 1188 widths = (Dimension *)XtRealloc((char *)widths, 1189 sizeof(Dimension) * count); 1190 widths[count - 1] = width_kid; 1191 width += tmp_w; 1192 tmp_w = width_kid; 1193 height = height_kid + vadd; 1194 } 1195 else 1196 height += height_kid; 1197 if (height > tmp_h) 1198 tmp_h = height; 1199 if (width_kid > tmp_w) 1200 widths[count - 1] = tmp_w = width_kid; 1201 ++n; 1202 } 1203 1204 height = tmp_h + smw->simple_menu.bottom_margin; 1205 width += tmp_w; 1206 1207 if (smw->simple_menu.label && width < XtWidth(smw->simple_menu.label)) { 1208 float inc; 1209 1210 inc = (XtWidth(smw->simple_menu.label) - width) / (float)count; 1211 width = XtWidth(smw->simple_menu.label); 1212 for (n = 0; n < count; n++) 1213 widths[n] += inc; 1214 } 1215 1216#ifndef OLDXAW 1217 width += hadd + smw->simple_menu.right_margin; 1218#endif 1219 1220 x_ins = n = count = 0; 1221 tmp_w = widths[0]; 1222 tmp_h = vadd; 1223 1224 for (i = smw->simple_menu.label ? 1 : 0; 1225 i < smw->composite.num_children; 1226 i++) { 1227 kid = smw->composite.children[i]; 1228 if (!XtIsManaged(kid)) 1229 continue; 1230 1231 height_kid = XtHeight(kid); 1232 1233 if (n && (tmp_h + height_kid + smw->simple_menu.bottom_margin 1234 > XtHeight(smw))) { 1235 x_ins = tmp_w; 1236 y_ins = vadd; 1237 ++count; 1238 tmp_w += widths[count]; 1239 tmp_h = height_kid + vadd; 1240 } 1241 else { 1242 y_ins = tmp_h; 1243 tmp_h += height_kid; 1244 } 1245 ++n; 1246 1247 XtX(kid) = x_ins + hadd; 1248 XtY(kid) = y_ins; 1249 XtWidth(kid) = widths[count]; 1250 } 1251 1252 XtFree((char *)widths); 1253 1254 if (allow_change_size) 1255 MakeSetValuesRequest((Widget) smw, width, height); 1256 1257 if (smw->simple_menu.label) { 1258 XtX(smw->simple_menu.label) = 0; 1259 XtY(smw->simple_menu.label) = smw->simple_menu.top_margin; 1260 XtWidth(smw->simple_menu.label) = XtWidth(smw) 1261#ifndef OLDXAW 1262 - (smw->simple_menu.left_margin + smw->simple_menu.right_margin) 1263#endif 1264 ; 1265 } 1266 if (current_entry) { 1267 if (width_ret) 1268 *width_ret = XtWidth(current_entry); 1269 if (height_ret) 1270 *height_ret = XtHeight(current_entry); 1271 } 1272} 1273 1274/* 1275 * Function: 1276 * AddPositionAction 1277 * 1278 * Parameters: 1279 * app_con - application context 1280 * data - (not used) 1281 * 1282 * Description: 1283 * Adds the XawPositionSimpleMenu action to the global 1284 * action list for this appcon. 1285 */ 1286/*ARGSUSED*/ 1287static void 1288AddPositionAction(XtAppContext app_con, XPointer data) 1289{ 1290 static XtActionsRec pos_action[] = { 1291 {"XawPositionSimpleMenu", PositionMenuAction}, 1292 }; 1293 1294 XtAppAddActions(app_con, pos_action, XtNumber(pos_action)); 1295} 1296 1297/* 1298 * Function: 1299 * FindMenu 1300 * 1301 * Parameters: 1302 * widget - reference widget 1303 * name - menu widget's name 1304 * 1305 * Description: 1306 * Find the menu give a name and reference widget 1307 * 1308 * Returns: 1309 * The menu widget or NULL. 1310 */ 1311static Widget 1312FindMenu(Widget widget, String name) 1313{ 1314 Widget w, menu; 1315 1316 for (w = widget; w != NULL; w = XtParent(w)) 1317 if ((menu = XtNameToWidget(w, name)) != NULL) 1318 return (menu); 1319 1320 return (NULL); 1321} 1322 1323/* 1324 * Function: 1325 * PositionMenu 1326 * 1327 * Parameters: 1328 * w - simple menu widget 1329 * location - pointer the the position or NULL 1330 * 1331 * Description: 1332 * Places the menu 1333 */ 1334static void 1335PositionMenu(Widget w, XPoint *location) 1336{ 1337 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1338 SmeObject entry; 1339 XPoint t_point; 1340 1341 if (location == NULL) { 1342 Window temp1, temp2; 1343 int root_x, root_y, tempX, tempY; 1344 unsigned int tempM; 1345 1346 location = &t_point; 1347 if (XQueryPointer(XtDisplay(w), XtWindow(w), &temp1, &temp2, 1348 &root_x, &root_y, &tempX, &tempY, &tempM) == False) { 1349 XtAppWarning(XtWidgetToApplicationContext(w), 1350 "Xaw Simple Menu Widget: " 1351 "Could not find location of mouse pointer"); 1352 return; 1353 } 1354 location->x = (short) root_x; 1355 location->y = (short) root_y; 1356 } 1357 1358 /* 1359 * The width will not be correct unless it is realized 1360 */ 1361 XtRealizeWidget(w); 1362 1363 location->x -= XtWidth(w) >> 1; 1364 1365 if (smw->simple_menu.popup_entry == NULL) 1366 entry = smw->simple_menu.label; 1367 else 1368 entry = smw->simple_menu.popup_entry; 1369 1370 if (entry != NULL) 1371 location->y -= XtY(entry) + (XtHeight(entry) >> 1); 1372 1373 MoveMenu(w, location->x, location->y); 1374} 1375 1376/* 1377 * Function: 1378 * MoveMenu 1379 * 1380 * Parameters: 1381 * w - simple menu widget 1382 * x - current location of the widget 1383 * y - "" 1384 * 1385 * Description: 1386 * Actually moves the menu, may force it to 1387 * to be fully visable if menu_on_screen is True. 1388 */ 1389static void 1390MoveMenu(Widget w, int x, int y) 1391{ 1392 Arg arglist[2]; 1393 Cardinal num_args = 0; 1394 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1395 1396 if (smw->simple_menu.menu_on_screen) { 1397 int width = XtWidth(w) + (XtBorderWidth(w) << 1); 1398 int height = XtHeight(w) + (XtBorderWidth(w) << 1); 1399 1400 if (x >= 0) { 1401 int scr_width = WidthOfScreen(XtScreen(w)); 1402 1403 if (x + width > scr_width) 1404 x = scr_width - width; 1405 } 1406 if (x < 0) 1407 x = 0; 1408 1409 if (y >= 0) { 1410 int scr_height = HeightOfScreen(XtScreen(w)); 1411 1412 if (y + height > scr_height) 1413 y = scr_height - height; 1414 } 1415 if (y < 0) 1416 y = 0; 1417 } 1418 1419 XtSetArg(arglist[num_args], XtNx, x); num_args++; 1420 XtSetArg(arglist[num_args], XtNy, y); num_args++; 1421 XtSetValues(w, arglist, num_args); 1422} 1423 1424/* 1425 * Function: 1426 * ChangeCursorOnGrab 1427 * 1428 * Parameters: 1429 * w - menu widget 1430 * temp1 - not used 1431 * temp2 - "" 1432 * 1433 * Description: 1434 * Changes the cursor on the active grab to the one 1435 * specified in out resource list. 1436 */ 1437/*ARGSUSED*/ 1438static void 1439ChangeCursorOnGrab(Widget w, XtPointer temp1, XtPointer temp2) 1440{ 1441 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1442 1443 /* 1444 * The event mask here is what is currently in the MIT implementation. 1445 * There really needs to be a way to get the value of the mask out 1446 * of the toolkit (CDP 5/26/89). 1447 */ 1448 XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask | ButtonReleaseMask, 1449 smw->simple_menu.cursor, 1450 XtLastTimestampProcessed(XtDisplay(w))); 1451} 1452 1453/* 1454 * Function: 1455 * MakeSetValuesRequest 1456 * 1457 * Parameters: 1458 * w - simple menu widget 1459 * width - size requested 1460 * height - "" 1461 */ 1462static void 1463MakeSetValuesRequest(Widget w, unsigned int width, unsigned int height) 1464{ 1465 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1466 Arg arglist[2]; 1467 Cardinal num_args = 0; 1468 1469 if (!smw->simple_menu.recursive_set_values) { 1470 if (XtWidth(smw) != width || XtHeight(smw) != height) { 1471 smw->simple_menu.recursive_set_values = True; 1472 XtSetArg(arglist[num_args], XtNwidth, width); num_args++; 1473 XtSetArg(arglist[num_args], XtNheight, height); num_args++; 1474 XtSetValues(w, arglist, num_args); 1475 } 1476 else if (XtIsRealized((Widget)smw)) 1477 XawSimpleMenuRedisplay((Widget)smw, NULL, NULL); 1478 } 1479 smw->simple_menu.recursive_set_values = False; 1480} 1481 1482static SmeObject 1483DoGetEventEntry(Widget w, int x_loc, int y_loc) 1484{ 1485 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1486 SmeObject *entry; 1487 1488 ForAllChildren(smw, entry) { 1489 if (!XtIsManaged((Widget)*entry)) 1490 continue; 1491 1492 if (x_loc > XtX(*entry) 1493 && x_loc <= XtX(*entry) + XtWidth(*entry) 1494 && y_loc > XtY(*entry) 1495 && y_loc <= XtY(*entry) + XtHeight(*entry)) { 1496 if (*entry == smw->simple_menu.label) 1497 return (NULL); /* cannot select the label */ 1498 else 1499 return (*entry); 1500 } 1501 } 1502 1503 return (NULL); 1504} 1505 1506/* 1507 * Function: 1508 * GetEventEntry 1509 * 1510 * Parameters: 1511 * w - simple menu widget 1512 * event - X event 1513 * 1514 * Description: 1515 * Gets an entry given an event that has X and Y coords. 1516 * 1517 * Returns: 1518 * The entry that this point is in 1519 */ 1520static SmeObject 1521GetEventEntry(Widget w, XEvent *event) 1522{ 1523 int x_loc, y_loc, x_root; 1524 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1525 SmeObject entry; 1526 int warp, move; 1527 1528 switch (event->type) { 1529 case MotionNotify: 1530 x_loc = event->xmotion.x; 1531 y_loc = event->xmotion.y; 1532 x_root = event->xmotion.x_root; 1533 break; 1534 case EnterNotify: 1535 case LeaveNotify: 1536 x_loc = event->xcrossing.x; 1537 y_loc = event->xcrossing.y; 1538 x_root = event->xcrossing.x_root; 1539 break; 1540 case ButtonPress: 1541 case ButtonRelease: 1542 x_loc = event->xbutton.x; 1543 y_loc = event->xbutton.y; 1544 x_root = event->xbutton.x_root; 1545 break; 1546 default: 1547 XtAppError(XtWidgetToApplicationContext(w), 1548 "Unknown event type in GetEventEntry()."); 1549 return (NULL); 1550 } 1551 1552 if (x_loc < 0 || x_loc >= XtWidth(smw) || 1553 y_loc < 0 || y_loc >= XtHeight(smw)) 1554 return (NULL); 1555 1556 /* Move the menu if it's outside the screen, does not check 1557 * smw->simple_menu.menu_on_screen because menus is bigger than screen 1558 */ 1559 if (x_root == WidthOfScreen(XtScreen(w)) - 1 && 1560 XtX(w) + XtWidth(w) + (XtBorderWidth(w)) > x_root) { 1561 warp = -8; 1562 if (smw->simple_menu.entry_set) { 1563 entry = DoGetEventEntry(w, 1564 XtX(smw->simple_menu.entry_set) 1565 + XtWidth(smw->simple_menu.entry_set) + 1, 1566 y_loc); 1567 Unhighlight(w, event, NULL, NULL); 1568 if (entry) { 1569 warp = -(int)XtWidth(entry) >> 1; 1570 move = x_loc - XtWidth(entry) - XtX(entry) + XtBorderWidth(w); 1571 } 1572 else { 1573 warp = 0; 1574 move = WidthOfScreen(XtScreen(w)) - 1575 (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1)); 1576 } 1577 } 1578 else { 1579 warp = 0; 1580 move = WidthOfScreen(XtScreen(w)) - 1581 (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1)); 1582 } 1583 } 1584 else if (x_root == 0 && XtX(w) < 0) { 1585 warp = 8; 1586 if (smw->simple_menu.entry_set) { 1587 entry = DoGetEventEntry(w, XtX(smw->simple_menu.entry_set) - 1, 1588 y_loc); 1589 Unhighlight(w, event, NULL, NULL); 1590 if (entry) { 1591 warp = XtWidth(entry) >> 1; 1592 move = x_loc - XtX(entry); 1593 } 1594 else 1595 move = x_loc + XtBorderWidth(w); 1596 } 1597 else 1598 move = x_loc + XtBorderWidth(w); 1599 } 1600 else 1601 move = warp = 0; 1602 1603 if (move) 1604 XtMoveWidget(w, XtX(w) + move, XtY(w)); 1605 if (warp) 1606 XWarpPointer(XtDisplay(w), None, None, 0, 0, 0, 0, warp, 0); 1607 1608 return (DoGetEventEntry(w, x_loc, y_loc)); 1609} 1610 1611static void 1612CalculateNewSize(Widget w, Dimension *width_return, Dimension *height_return) 1613{ 1614 SimpleMenuWidget xaw = (SimpleMenuWidget)w; 1615 Widget kid; 1616 Cardinal i; 1617 int width_kid, height_kid; 1618 int width, height, tmp_w, tmp_h, max_dim; 1619 short vadd, hadd; 1620 int n, columns, test_h, num_children = 0; 1621 Boolean try_layout = False; 1622 1623#ifndef OLDXAW 1624 hadd = xaw->simple_menu.left_margin + xaw->simple_menu.right_margin; 1625#else 1626 hadd = 0; 1627#endif 1628 vadd = xaw->simple_menu.top_margin + xaw->simple_menu.bottom_margin; 1629 if (xaw->simple_menu.label) 1630 vadd += XtHeight(xaw->simple_menu.label); 1631 1632 if (*height_return) 1633 max_dim = *height_return; 1634 else if (!XtHeight(w)) { 1635 max_dim = HeightOfScreen(XtScreen(w)); 1636 try_layout = True; 1637 } 1638 else 1639 max_dim = XtHeight(w); 1640 max_dim -= vadd; 1641 1642 width = height = tmp_w = tmp_h = n = test_h = 0; 1643 columns = 1; 1644 for (i = xaw->simple_menu.label ? 1 : 0; 1645 i < xaw->composite.num_children; 1646 i++) { 1647 kid = xaw->composite.children[i]; 1648 if (!XtIsManaged(kid)) 1649 continue; 1650 ++num_children; 1651 width_kid = XtWidth(kid); 1652 height_kid = XtHeight(kid); 1653 1654 if (try_layout) { 1655 if (!test_h) 1656 test_h = height_kid; 1657 else if (test_h != height_kid) 1658 try_layout = False; 1659 } 1660 1661 if (n && (height + height_kid > max_dim)) { 1662 ++columns; 1663 width += tmp_w; 1664 tmp_w = width_kid; 1665 height = height_kid; 1666 } 1667 else 1668 height += height_kid; 1669 if (height > tmp_h) 1670 tmp_h = height; 1671 if (width_kid > tmp_w) 1672 tmp_w = width_kid; 1673 ++n; 1674 } 1675 1676 height = tmp_h + vadd; 1677 width += tmp_w + hadd; 1678 1679 if (xaw->simple_menu.label) 1680 width = XawMax(width, XtWidth(xaw->simple_menu.label) + hadd); 1681 1682 *width_return = width; 1683 *height_return = height; 1684 1685 if (try_layout && columns > 1 && num_children > 2) { 1686 int space; 1687 1688 height = test_h * (xaw->simple_menu.label ? 1689 num_children - 1 : 1690 num_children); 1691 1692 max_dim -= max_dim % test_h; 1693 space = max_dim - (height % max_dim); 1694 if (space >= test_h * columns) { 1695 height = max_dim - space / columns; 1696 if (height % test_h) 1697 height += test_h - (height % test_h); 1698 *height_return = height + vadd; 1699 CalculateNewSize(w, width_return, height_return); 1700 } 1701 } 1702} 1703 1704static void 1705MakeResizeRequest(Widget w) 1706{ 1707 int tries; 1708 Dimension width, height; 1709 1710 width = XtWidth(w); 1711 height = XtHeight(w); 1712 1713 for (tries = 0; tries < 100; tries++) { 1714 CalculateNewSize(w, &width, &height); 1715 if (width == XtWidth(w) && height == XtHeight(w)) 1716 break; 1717 if (XtMakeResizeRequest(w, width, height, &width, &height) == 1718 XtGeometryNo) 1719 break; 1720 } 1721} 1722 1723#ifndef OLDXAW 1724static void 1725Popdown(Widget w, XEvent *event, String *params, Cardinal *num_params) 1726{ 1727 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1728 1729 while (XtParent(w) && 1730 XtIsSubclass(XtParent(w), simpleMenuWidgetClass)) { 1731 if (((SimpleMenuWidget)XtParent(w))->simple_menu.sub_menu == (Widget)w) { 1732 w = XtParent(w); 1733 smw = (SimpleMenuWidget)w; 1734 smw->simple_menu.entry_set = NULL; 1735 } 1736 else 1737 break; 1738 } 1739 1740 smw->simple_menu.state |= SMW_UNMAPPING; 1741 if (smw->simple_menu.sub_menu) 1742 PopdownSubMenu(smw); 1743 XtCallActionProc(w, "XtMenuPopdown", event, params, *num_params); 1744} 1745 1746static void 1747PopupSubMenu(SimpleMenuWidget smw) 1748{ 1749 Arg args[2]; 1750 Cardinal num_args; 1751 Widget menu; 1752 SmeBSBObject entry = (SmeBSBObject)smw->simple_menu.entry_set; 1753 Position menu_x, menu_y; 1754 Bool popleft; 1755 1756 if (entry->sme_bsb.menu_name == NULL) 1757 return; 1758 1759 if ((menu = FindMenu((Widget)smw, entry->sme_bsb.menu_name)) == NULL) 1760 return; 1761 1762 smw->simple_menu.sub_menu = menu; 1763 1764 if (!XtIsRealized(menu)) 1765 XtRealizeWidget(menu); 1766 1767 popleft = (smw->simple_menu.state & SMW_POPLEFT) != 0; 1768 1769 if (popleft) 1770 XtTranslateCoords((Widget)smw, -(int)XtWidth(menu), 1771 XtY(entry) - XtBorderWidth(menu), &menu_x, &menu_y); 1772 else 1773 XtTranslateCoords((Widget)smw, XtWidth(smw), XtY(entry) 1774 - XtBorderWidth(menu), &menu_x, &menu_y); 1775 1776 if (!popleft && menu_x >= 0) { 1777 int scr_width = WidthOfScreen(XtScreen(menu)); 1778 1779 if (menu_x + XtWidth(menu) > scr_width) { 1780 menu_x -= XtWidth(menu) + XtWidth(smw); 1781 popleft = True; 1782 } 1783 } 1784 else if (popleft && menu_x < 0) { 1785 menu_x = 0; 1786 popleft = False; 1787 } 1788 if (menu_y >= 0) { 1789 int scr_height = HeightOfScreen(XtScreen(menu)); 1790 1791 if (menu_y + XtHeight(menu) > scr_height) 1792 menu_y = scr_height - XtHeight(menu) - XtBorderWidth(menu); 1793 } 1794 if (menu_y < 0) 1795 menu_y = 0; 1796 1797 num_args = 0; 1798 XtSetArg(args[num_args], XtNx, menu_x); num_args++; 1799 XtSetArg(args[num_args], XtNy, menu_y); num_args++; 1800 XtSetValues(menu, args, num_args); 1801 1802 if (popleft) 1803 ((SimpleMenuWidget)menu)->simple_menu.state |= SMW_POPLEFT; 1804 else 1805 ((SimpleMenuWidget)menu)->simple_menu.state &= ~SMW_POPLEFT; 1806 1807 XtPopup(menu, XtGrabNone); 1808} 1809 1810static void 1811PopdownSubMenu(SimpleMenuWidget smw) 1812{ 1813 SimpleMenuWidget menu = (SimpleMenuWidget)smw->simple_menu.sub_menu; 1814 1815 if (!menu) 1816 return; 1817 1818 menu->simple_menu.state |= SMW_UNMAPPING; 1819 PopdownSubMenu(menu); 1820 1821 XtPopdown((Widget)menu); 1822 1823 smw->simple_menu.sub_menu = NULL; 1824} 1825 1826/*ARGSUSED*/ 1827static void 1828PopupCB(Widget w, XtPointer client_data, XtPointer call_data) 1829{ 1830 SimpleMenuWidget smw = (SimpleMenuWidget)w; 1831 1832 smw->simple_menu.state &= ~(SMW_UNMAPPING | SMW_POPLEFT); 1833} 1834#endif /* OLDXAW */ 1835