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