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