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