1///////////////////////////////////////////////////////////////////////////// 2// Name: src/motif/toolbar.cpp 3// Purpose: wxToolBar 4// Author: Julian Smart 5// Modified by: 13.12.99 by VZ during toolbar classes reorganization 6// Created: 04/01/98 7// RCS-ID: $Id: toolbar.cpp 50982 2008-01-01 20:38:33Z VZ $ 8// Copyright: (c) Julian Smart 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#include "wx/toolbar.h" 24 25#ifndef WX_PRECOMP 26 #include "wx/app.h" 27 #include "wx/frame.h" 28 #include "wx/timer.h" 29 #include "wx/settings.h" 30#endif 31 32#ifdef __VMS__ 33#pragma message disable nosimpint 34#endif 35#include <Xm/Xm.h> 36#include <Xm/PushBG.h> 37#include <Xm/PushB.h> 38#include <Xm/Label.h> 39#include <Xm/ToggleB.h> 40#include <Xm/ToggleBG.h> 41#include <Xm/Form.h> 42#ifdef __VMS__ 43#pragma message enable nosimpint 44#endif 45 46#include "wx/motif/private.h" 47#include "wx/motif/bmpmotif.h" 48 49// ---------------------------------------------------------------------------- 50// wxWin macros 51// ---------------------------------------------------------------------------- 52 53IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl) 54 55// ---------------------------------------------------------------------------- 56// private functions 57// ---------------------------------------------------------------------------- 58 59static void wxToolButtonCallback (Widget w, XtPointer clientData, 60 XtPointer ptr); 61static void wxToolButtonPopupCallback (Widget w, XtPointer client_data, 62 XEvent *event, Boolean *continue_to_dispatch); 63 64// ---------------------------------------------------------------------------- 65// private classes 66// ---------------------------------------------------------------------------- 67 68class wxToolBarTimer : public wxTimer 69{ 70public: 71 virtual void Notify(); 72 73 static Widget help_popup; 74 static Widget buttonWidget; 75 static wxString helpString; 76}; 77 78class wxToolBarTool : public wxToolBarToolBase 79{ 80public: 81 wxToolBarTool(wxToolBar *tbar, 82 int id, 83 const wxString& label, 84 const wxBitmap& bmpNormal, 85 const wxBitmap& bmpToggled, 86 wxItemKind kind, 87 wxObject *clientData, 88 const wxString& shortHelp, 89 const wxString& longHelp) 90 : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpToggled, kind, 91 clientData, shortHelp, longHelp) 92 { 93 Init(); 94 } 95 96 wxToolBarTool(wxToolBar *tbar, wxControl *control) 97 : wxToolBarToolBase(tbar, control) 98 { 99 Init(); 100 } 101 102 virtual ~wxToolBarTool(); 103 104 // accessors 105 void SetWidget(Widget widget) { m_widget = widget; } 106 Widget GetButtonWidget() const { return m_widget; } 107 108 Pixmap GetArmPixmap() 109 { 110 m_bitmapCache.SetBitmap( GetNormalBitmap() ); 111 return (Pixmap)m_bitmapCache.GetArmPixmap( (WXWidget)m_widget ); 112 } 113 114 Pixmap GetInsensPixmap() 115 { 116 m_bitmapCache.SetBitmap( GetNormalBitmap() ); 117 return (Pixmap)m_bitmapCache.GetInsensPixmap( (WXWidget)m_widget ); 118 } 119protected: 120 void Init(); 121 122 Widget m_widget; 123 wxBitmapCache m_bitmapCache; 124}; 125 126// ---------------------------------------------------------------------------- 127// globals 128// ---------------------------------------------------------------------------- 129 130static wxToolBarTimer* wxTheToolBarTimer = (wxToolBarTimer*) NULL; 131 132Widget wxToolBarTimer::help_popup = (Widget) 0; 133Widget wxToolBarTimer::buttonWidget = (Widget) 0; 134wxString wxToolBarTimer::helpString; 135 136// ============================================================================ 137// implementation 138// ============================================================================ 139 140// ---------------------------------------------------------------------------- 141// wxToolBarTool 142// ---------------------------------------------------------------------------- 143 144wxToolBarToolBase *wxToolBar::CreateTool(int id, 145 const wxString& label, 146 const wxBitmap& bmpNormal, 147 const wxBitmap& bmpToggled, 148 wxItemKind kind, 149 wxObject *clientData, 150 const wxString& shortHelp, 151 const wxString& longHelp) 152{ 153 return new wxToolBarTool(this, id, label, bmpNormal, bmpToggled, kind, 154 clientData, shortHelp, longHelp); 155} 156 157 158wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control) 159{ 160 return new wxToolBarTool(this, control); 161} 162 163void wxToolBarTool::Init() 164{ 165 m_widget = (Widget)0; 166} 167 168wxToolBarTool::~wxToolBarTool() 169{ 170 if ( m_widget ) 171 XtDestroyWidget(m_widget); 172} 173 174// ---------------------------------------------------------------------------- 175// wxToolBar construction 176// ---------------------------------------------------------------------------- 177 178void wxToolBar::Init() 179{ 180 m_maxWidth = -1; 181 m_maxHeight = -1; 182 m_defaultWidth = 24; 183 m_defaultHeight = 22; 184 m_toolPacking = 2; 185 m_toolSeparation = 8; 186 m_xMargin = 2; 187 m_yMargin = 2; 188 m_maxRows = 100; 189 m_maxCols = 100; 190} 191 192bool wxToolBar::Create(wxWindow *parent, 193 wxWindowID id, 194 const wxPoint& pos, 195 const wxSize& size, 196 long style, 197 const wxString& name) 198{ 199 if( !wxControl::CreateControl( parent, id, pos, size, style, 200 wxDefaultValidator, name ) ) 201 return false; 202 203 FixupStyle(); 204 205 m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); 206 207 Widget parentWidget = (Widget) parent->GetClientWidget(); 208 209 Widget toolbar = XtVaCreateManagedWidget("toolbar", 210 xmBulletinBoardWidgetClass, (Widget) parentWidget, 211 XmNmarginWidth, 0, 212 XmNmarginHeight, 0, 213 XmNresizePolicy, XmRESIZE_NONE, 214 NULL); 215/* 216 Widget toolbar = XtVaCreateManagedWidget("toolbar", 217 xmFormWidgetClass, (Widget) m_clientWidget, 218 XmNtraversalOn, False, 219 XmNhorizontalSpacing, 0, 220 XmNverticalSpacing, 0, 221 XmNleftOffset, 0, 222 XmNrightOffset, 0, 223 XmNmarginWidth, 0, 224 XmNmarginHeight, 0, 225 NULL); 226*/ 227 228 m_mainWidget = (WXWidget) toolbar; 229 230 ChangeFont(false); 231 232 wxPoint rPos = pos; 233 wxSize rSize = size; 234 235 if( rPos.x == -1 ) rPos.x = 0; 236 if( rPos.y == -1 ) rPos.y = 0; 237 if( rSize.x == -1 && GetParent() ) 238 rSize.x = GetParent()->GetSize().x; 239 240 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, 241 rPos.x, rPos.y, rSize.x, rSize.y); 242 243 ChangeBackgroundColour(); 244 245 return true; 246} 247 248wxToolBar::~wxToolBar() 249{ 250 delete wxTheToolBarTimer; 251 wxTheToolBarTimer = NULL; 252} 253 254bool wxToolBar::Realize() 255{ 256 if ( m_tools.GetCount() == 0 ) 257 { 258 // nothing to do 259 return true; 260 } 261 262 bool isVertical = GetWindowStyle() & wxTB_VERTICAL; 263 264 // Separator spacing 265 const int separatorSize = GetToolSeparation(); // 8; 266 wxSize margins = GetToolMargins(); 267 int packing = GetToolPacking(); 268 int marginX = margins.x; 269 int marginY = margins.y; 270 271 int currentX = marginX; 272 int currentY = marginY; 273 274 int buttonHeight = 0, buttonWidth = 0; 275 276 Widget button; 277 Pixmap pixmap, insensPixmap; 278 wxBitmap bmp, insensBmp; 279 280 wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); 281 while ( node ) 282 { 283 wxToolBarTool *tool = (wxToolBarTool *)node->GetData(); 284 285 switch ( tool->GetStyle() ) 286 { 287 case wxTOOL_STYLE_CONTROL: 288 { 289 wxControl* control = tool->GetControl(); 290 wxSize sz = control->GetSize(); 291 wxPoint pos = control->GetPosition(); 292 // Allow a control to specify a y[x]-offset by setting 293 // its initial position, but still don't allow it to 294 // position itself above the top[left] margin. 295 int controlY = (pos.y > 0) ? pos.y : currentY; 296 int controlX = (pos.x > 0) ? pos.x : currentX; 297 control->Move( isVertical ? controlX : currentX, 298 isVertical ? currentY : controlY ); 299 if ( isVertical ) 300 currentY += sz.y + packing; 301 else 302 currentX += sz.x + packing; 303 304 break; 305 } 306 case wxTOOL_STYLE_SEPARATOR: 307 // skip separators for vertical toolbars 308 if( !isVertical ) 309 { 310 currentX += separatorSize; 311 } 312 break; 313 314 case wxTOOL_STYLE_BUTTON: 315 button = (Widget) 0; 316 317 if ( tool->CanBeToggled() && !tool->GetButtonWidget() ) 318 { 319 button = XtVaCreateWidget("toggleButton", 320 xmToggleButtonWidgetClass, (Widget) m_mainWidget, 321 XmNx, currentX, XmNy, currentY, 322 XmNindicatorOn, False, 323 XmNshadowThickness, 2, 324 XmNborderWidth, 0, 325 XmNspacing, 0, 326 XmNmarginWidth, 0, 327 XmNmarginHeight, 0, 328 XmNmultiClick, XmMULTICLICK_KEEP, 329 XmNlabelType, XmPIXMAP, 330 NULL); 331 XtAddCallback ((Widget) button, 332 XmNvalueChangedCallback, 333 (XtCallbackProc) wxToolButtonCallback, 334 (XtPointer) this); 335 336 XtVaSetValues ((Widget) button, 337 XmNselectColor, 338 m_backgroundColour.AllocColour 339 (XtDisplay((Widget) button)), 340 NULL); 341 } 342 else if( !tool->GetButtonWidget() ) 343 { 344 button = XtVaCreateWidget("button", 345 xmPushButtonWidgetClass, (Widget) m_mainWidget, 346 XmNx, currentX, XmNy, currentY, 347 XmNpushButtonEnabled, True, 348 XmNmultiClick, XmMULTICLICK_KEEP, 349 XmNlabelType, XmPIXMAP, 350 NULL); 351 XtAddCallback (button, 352 XmNactivateCallback, 353 (XtCallbackProc) wxToolButtonCallback, 354 (XtPointer) this); 355 } 356 357 if( !tool->GetButtonWidget() ) 358 { 359 wxDoChangeBackgroundColour((WXWidget) button, 360 m_backgroundColour, true); 361 362 tool->SetWidget(button); 363 } 364 else 365 { 366 button = (Widget)tool->GetButtonWidget(); 367 XtVaSetValues( button, 368 XmNx, currentX, XmNy, currentY, 369 NULL ); 370 } 371 372 // For each button, if there is a mask, we must create 373 // a new wxBitmap that has the correct background colour 374 // for the button. Otherwise the background will just be 375 // e.g. black if a transparent XPM has been loaded. 376 bmp = tool->GetNormalBitmap(); 377 insensBmp = tool->GetDisabledBitmap(); 378 if ( bmp.GetMask() || insensBmp.GetMask() ) 379 { 380 WXPixel backgroundPixel; 381 XtVaGetValues(button, XmNbackground, &backgroundPixel, 382 NULL); 383 384 wxColour col; 385 col.SetPixel(backgroundPixel); 386 387 if( bmp.Ok() && bmp.GetMask() ) 388 { 389 bmp = wxCreateMaskedBitmap(bmp, col); 390 tool->SetNormalBitmap(bmp); 391 } 392 393 if( insensBmp.Ok() && insensBmp.GetMask() ) 394 { 395 insensBmp = wxCreateMaskedBitmap(insensBmp, col); 396 tool->SetDisabledBitmap(insensBmp); 397 } 398 } 399 400 // Create a selected/toggled bitmap. If there isn't a 2nd 401 // bitmap, we need to create it (with a darker, selected 402 // background) 403 WXPixel backgroundPixel; 404 if ( tool->CanBeToggled() ) 405 XtVaGetValues(button, XmNselectColor, &backgroundPixel, 406 NULL); 407 else 408 XtVaGetValues(button, XmNarmColor, &backgroundPixel, 409 NULL); 410 wxColour col; 411 col.SetPixel(backgroundPixel); 412 413 pixmap = (Pixmap) bmp.GetDrawable(); 414 { 415 wxBitmap tmp = tool->GetDisabledBitmap(); 416 417 insensPixmap = tmp.Ok() ? 418 (Pixmap)tmp.GetDrawable() : 419 tool->GetInsensPixmap(); 420 } 421 422 if (tool->CanBeToggled()) 423 { 424 // Toggle button 425 Pixmap pixmap2 = tool->GetArmPixmap(); 426 Pixmap insensPixmap2 = tool->GetInsensPixmap(); 427 428 XtVaSetValues (button, 429 XmNfillOnSelect, True, 430 XmNlabelPixmap, pixmap, 431 XmNselectPixmap, pixmap2, 432 XmNlabelInsensitivePixmap, insensPixmap, 433 XmNselectInsensitivePixmap, insensPixmap2, 434 XmNlabelType, XmPIXMAP, 435 NULL); 436 } 437 else 438 { 439 Pixmap pixmap2 = tool->GetArmPixmap(); 440 441 // Normal button 442 XtVaSetValues(button, 443 XmNlabelPixmap, pixmap, 444 XmNlabelInsensitivePixmap, insensPixmap, 445 XmNarmPixmap, pixmap2, 446 NULL); 447 } 448 449 XtManageChild(button); 450 451 { 452 Dimension width, height; 453 XtVaGetValues(button, 454 XmNwidth, &width, 455 XmNheight, & height, 456 NULL); 457 if ( isVertical ) 458 currentY += height + packing; 459 else 460 currentX += width + packing; 461 buttonHeight = wxMax(buttonHeight, height); 462 buttonWidth = wxMax(buttonWidth, width); 463 } 464 465 XtAddEventHandler (button, EnterWindowMask | LeaveWindowMask, 466 False, wxToolButtonPopupCallback, (XtPointer) this); 467 468 break; 469 } 470 471 node = node->GetNext(); 472 } 473 474 SetSize( -1, -1, 475 isVertical ? buttonWidth + 2 * marginX : -1, 476 isVertical ? -1 : buttonHeight + 2*marginY ); 477 478 return true; 479} 480 481wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord WXUNUSED(x), 482 wxCoord WXUNUSED(y)) const 483{ 484 wxFAIL_MSG( _T("TODO") ); 485 486 return (wxToolBarToolBase *)NULL; 487} 488 489bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool) 490{ 491 tool->Attach(this); 492 493 return true; 494} 495 496bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool) 497{ 498 tool->Detach(); 499 500 bool isVertical = GetWindowStyle() & wxTB_VERTICAL; 501 const int separatorSize = GetToolSeparation(); // 8; 502 int packing = GetToolPacking(); 503 int offset = 0; 504 505 for( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); 506 node; node = node->GetNext() ) 507 { 508 wxToolBarTool *t = (wxToolBarTool*)node->GetData(); 509 510 if( t == tool ) 511 { 512 switch ( t->GetStyle() ) 513 { 514 case wxTOOL_STYLE_CONTROL: 515 { 516 wxSize size = t->GetControl()->GetSize(); 517 offset = isVertical ? size.y : size.x; 518 offset += packing; 519 break; 520 } 521 case wxTOOL_STYLE_SEPARATOR: 522 offset = isVertical ? 0 : separatorSize; 523 break; 524 case wxTOOL_STYLE_BUTTON: 525 { 526 Widget w = t->GetButtonWidget(); 527 Dimension width, height; 528 529 XtVaGetValues( w, 530 XmNwidth, &width, 531 XmNheight, &height, 532 NULL ); 533 534 offset = isVertical ? height : width; 535 offset += packing; 536 break; 537 } 538 } 539 } 540 else if( offset ) 541 { 542 switch ( t->GetStyle() ) 543 { 544 case wxTOOL_STYLE_CONTROL: 545 { 546 wxPoint location = t->GetControl()->GetPosition(); 547 548 if( isVertical ) 549 location.y -= offset; 550 else 551 location.x -= offset; 552 553 t->GetControl()->Move( location ); 554 break; 555 } 556 case wxTOOL_STYLE_SEPARATOR: 557 break; 558 case wxTOOL_STYLE_BUTTON: 559 { 560 Dimension x, y; 561 XtVaGetValues( t->GetButtonWidget(), 562 XmNx, &x, 563 XmNy, &y, 564 NULL ); 565 566 if( isVertical ) 567 y = (Dimension)(y - offset); 568 else 569 x = (Dimension)(x - offset); 570 571 XtVaSetValues( t->GetButtonWidget(), 572 XmNx, x, 573 XmNy, y, 574 NULL ); 575 break; 576 } 577 } 578 } 579 } 580 581 return true; 582} 583 584void wxToolBar::DoEnableTool(wxToolBarToolBase *toolBase, bool enable) 585{ 586 wxToolBarTool *tool = (wxToolBarTool *)toolBase; 587 if (tool->GetButtonWidget()){ 588 XtSetSensitive(tool->GetButtonWidget(), (Boolean) enable); 589 } else if (wxTOOL_STYLE_CONTROL == tool->GetStyle()){ 590 // Controls (such as wxChoice) do not have button widgets 591 tool->GetControl()->Enable(enable); 592 } 593} 594 595void wxToolBar::DoToggleTool(wxToolBarToolBase *toolBase, bool toggle) 596{ 597 wxToolBarTool *tool = (wxToolBarTool *)toolBase; 598 599 XmToggleButtonSetState(tool->GetButtonWidget(), (Boolean) toggle, False); 600} 601 602void wxToolBar::DoSetToggle(wxToolBarToolBase * WXUNUSED(tool), 603 bool WXUNUSED(toggle)) 604{ 605 // nothing to do 606} 607 608void wxToolBar::DoSetSize(int x, int y, int width, int height, int sizeFlags) 609{ 610 int old_width, old_height; 611 GetSize(&old_width, &old_height); 612 613 // Correct width and height if needed. 614 if ( width == -1 || height == -1 ) 615 { 616 wxSize defaultSize = GetSize(); 617 618 if ( width == -1 ) 619 width = defaultSize.x; 620 if ( height == -1 ) 621 height = defaultSize.y; 622 } 623 624 wxToolBarBase::DoSetSize(x, y, width, height, sizeFlags); 625 626 // We must refresh the frame size when the toolbar changes size 627 // otherwise the toolbar can be shown incorrectly 628 if ( old_width != width || old_height != height ) 629 { 630 // But before we send the size event check it 631 // we have a frame that is not being deleted. 632 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); 633 if ( frame && !frame->IsBeingDeleted() ) 634 { 635 frame->SendSizeEvent(); 636 } 637 } 638} 639 640// ---------------------------------------------------------------------------- 641// Motif callbacks 642// ---------------------------------------------------------------------------- 643 644wxToolBarToolBase *wxToolBar::FindToolByWidget(WXWidget w) const 645{ 646 wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); 647 while ( node ) 648 { 649 wxToolBarTool *tool = (wxToolBarTool *)node->GetData(); 650 if ( tool->GetButtonWidget() == w) 651 { 652 return tool; 653 } 654 655 node = node->GetNext(); 656 } 657 658 return (wxToolBarToolBase *)NULL; 659} 660 661static void wxToolButtonCallback(Widget w, 662 XtPointer clientData, 663 XtPointer WXUNUSED(ptr)) 664{ 665 wxToolBar *toolBar = (wxToolBar *) clientData; 666 wxToolBarToolBase *tool = toolBar->FindToolByWidget((WXWidget) w); 667 if ( !tool ) 668 return; 669 670 if ( tool->CanBeToggled() ) 671 tool->Toggle(); 672 673 if ( !toolBar->OnLeftClick(tool->GetId(), tool->IsToggled()) ) 674 { 675 // revert 676 tool->Toggle(); 677 } 678} 679 680 681static void wxToolButtonPopupCallback(Widget w, 682 XtPointer client_data, 683 XEvent *event, 684 Boolean *WXUNUSED(continue_to_dispatch)) 685{ 686 // TODO: retrieve delay before popping up tooltip from wxSystemSettings. 687 static const int delayMilli = 800; 688 689 wxToolBar* toolBar = (wxToolBar*) client_data; 690 wxToolBarToolBase *tool = toolBar->FindToolByWidget((WXWidget) w); 691 692 if ( !tool ) 693 return; 694 695 wxString tooltip = tool->GetShortHelp(); 696 if ( !tooltip ) 697 return; 698 699 if (!wxTheToolBarTimer) 700 wxTheToolBarTimer = new wxToolBarTimer; 701 702 wxToolBarTimer::buttonWidget = w; 703 wxToolBarTimer::helpString = tooltip; 704 705 /************************************************************/ 706 /* Popup help label */ 707 /************************************************************/ 708 if (event->type == EnterNotify) 709 { 710 if (wxToolBarTimer::help_popup != (Widget) 0) 711 { 712 XtDestroyWidget (wxToolBarTimer::help_popup); 713 XtPopdown (wxToolBarTimer::help_popup); 714 } 715 wxToolBarTimer::help_popup = (Widget) 0; 716 717 // One shot 718 wxTheToolBarTimer->Start(delayMilli, true); 719 720 } 721 /************************************************************/ 722 /* Popdown help label */ 723 /************************************************************/ 724 else if (event->type == LeaveNotify) 725 { 726 if (wxTheToolBarTimer) 727 wxTheToolBarTimer->Stop(); 728 if (wxToolBarTimer::help_popup != (Widget) 0) 729 { 730 XtDestroyWidget (wxToolBarTimer::help_popup); 731 XtPopdown (wxToolBarTimer::help_popup); 732 } 733 wxToolBarTimer::help_popup = (Widget) 0; 734 } 735} 736 737void wxToolBarTimer::Notify() 738{ 739 Position x, y; 740 741 /************************************************************/ 742 /* Create shell without window decorations */ 743 /************************************************************/ 744 help_popup = XtVaCreatePopupShell ("shell", 745 overrideShellWidgetClass, (Widget) wxTheApp->GetTopLevelWidget(), 746 NULL); 747 748 /************************************************************/ 749 /* Get absolute position on display of toolbar button */ 750 /************************************************************/ 751 XtTranslateCoords (buttonWidget, 752 (Position) 0, 753 (Position) 0, 754 &x, &y); 755 756 // Move the tooltip more or less above the button 757 int yOffset = 20; // TODO: What should be really? 758 y = (Position)(y - yOffset); 759 if (y < yOffset) y = 0; 760 761 /************************************************************/ 762 /* Set the position of the help popup */ 763 /************************************************************/ 764 XtVaSetValues (help_popup, 765 XmNx, (Position) x, 766 XmNy, (Position) y, 767 NULL); 768 769 /************************************************************/ 770 /* Create help label */ 771 /************************************************************/ 772 XmString text = XmStringCreateSimple ((char*) (const char*) helpString); 773 XtVaCreateManagedWidget ("help_label", 774 xmLabelWidgetClass, help_popup, 775 XmNlabelString, text, 776 XtVaTypedArg, 777 XmNforeground, XtRString, "black", 778 strlen("black")+1, 779 XtVaTypedArg, 780 XmNbackground, XtRString, "LightGoldenrod", 781 strlen("LightGoldenrod")+1, 782 NULL); 783 XmStringFree (text); 784 785 /************************************************************/ 786 /* Popup help label */ 787 /************************************************************/ 788 XtPopup (help_popup, XtGrabNone); 789} 790