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