Only give capture to wxPopupTransientWindow child if it's the only one.
[wxWidgets.git] / src / motif / frame.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/frame.cpp
3 // Purpose: wxFrame
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #include "wx/frame.h"
23
24 #ifndef WX_PRECOMP
25 #include "wx/log.h"
26 #include "wx/app.h"
27 #include "wx/utils.h"
28 #include "wx/menu.h"
29 #include "wx/icon.h"
30 #include "wx/settings.h"
31 #include "wx/toolbar.h"
32 #include "wx/statusbr.h"
33 #endif
34
35 #ifdef __VMS__
36 #pragma message disable nosimpint
37 #endif
38
39 #if defined(__ultrix) || defined(__sgi)
40 #include <Xm/Frame.h>
41 #endif
42
43 #include <Xm/Xm.h>
44 #include <X11/Shell.h>
45 #include <X11/Core.h>
46 #if XmVersion >= 1002
47 #include <Xm/XmAll.h>
48 #else
49 #include <Xm/Frame.h>
50 #endif
51 #include <Xm/MwmUtil.h>
52 #include <Xm/BulletinB.h>
53 #include <Xm/Form.h>
54 #include <Xm/MainW.h>
55 #include <Xm/RowColumn.h>
56 #include <Xm/Label.h>
57 #include <Xm/AtomMgr.h>
58 #include <Xm/LabelG.h>
59 #include <Xm/Frame.h>
60 #if XmVersion > 1000
61 #include <Xm/Protocols.h>
62 #endif
63
64 #ifdef __VMS__
65 #pragma message enable nosimpint
66 #endif
67
68 #include "wx/motif/private.h"
69 #include "wx/unix/utilsx11.h"
70
71 // ----------------------------------------------------------------------------
72 // private functions
73 // ----------------------------------------------------------------------------
74
75 static void wxFrameMapProc(Widget frameShell, XtPointer clientData,
76 XCrossingEvent* event);
77
78 // ----------------------------------------------------------------------------
79 // globals
80 // ----------------------------------------------------------------------------
81
82 extern wxList wxModelessWindows;
83
84 // ----------------------------------------------------------------------------
85 // wxWin macros
86 // ----------------------------------------------------------------------------
87
88 BEGIN_EVENT_TABLE(wxFrame, wxFrameBase)
89 EVT_ACTIVATE(wxFrame::OnActivate)
90 EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged)
91 END_EVENT_TABLE()
92
93 // ============================================================================
94 // implementation
95 // ============================================================================
96
97 // ----------------------------------------------------------------------------
98 // frame construction
99 // ----------------------------------------------------------------------------
100
101 void wxFrame::Init()
102 {
103 m_iconized = false;
104
105 //// Motif-specific
106 m_frameShell = (WXWidget) NULL;
107 m_mainWidget = (WXWidget) NULL;
108 m_workArea = (WXWidget) NULL;
109 m_clientArea = (WXWidget) NULL;
110 }
111
112 bool wxFrame::Create(wxWindow *parent,
113 wxWindowID id,
114 const wxString& title,
115 const wxPoint& pos,
116 const wxSize& size,
117 long style,
118 const wxString& name)
119 {
120 if( !wxTopLevelWindow::Create( parent, id, title, pos, size, style,
121 name ) )
122 return false;
123
124 int x = pos.x, y = pos.y;
125 int width = size.x, height = size.y;
126
127 // Set reasonable values for position and size if defaults have been
128 // requested
129 //
130 // MB TODO: something better than these arbitrary values ?
131 // VZ should use X resources for this...
132 if ( width == -1 )
133 width = 400;
134 if ( height == -1 )
135 height = 400;
136
137 int displayW, displayH;
138 wxDisplaySize( &displayW, &displayH );
139
140 if ( x == -1 )
141 {
142 x = (displayW - width) / 2;
143 if (x < 10) x = 10;
144 }
145 if ( y == -1 )
146 {
147 y = (displayH - height) / 2;
148 if (y < 10) y = 10;
149 }
150
151 SetTitle( title );
152
153 wxLogTrace(wxTRACE_Messages,
154 "Created frame (0x%p) with work area 0x%p and client "
155 "area 0x%p", m_mainWidget, m_workArea, m_clientArea);
156
157 XtAddEventHandler((Widget) m_clientArea, ExposureMask,False,
158 wxUniversalRepaintProc, (XtPointer) this);
159
160 if (x > -1)
161 XtVaSetValues((Widget) m_frameShell, XmNx, x, NULL);
162 if (y > -1)
163 XtVaSetValues((Widget) m_frameShell, XmNy, y, NULL);
164 if (width > -1)
165 XtVaSetValues((Widget) m_frameShell, XmNwidth, width, NULL);
166 if (height > -1)
167 XtVaSetValues((Widget) m_frameShell, XmNheight, height, NULL);
168
169 PostCreation();
170 PreResize();
171
172 wxSize newSize(width, height);
173 wxSizeEvent sizeEvent(newSize, GetId());
174 sizeEvent.SetEventObject(this);
175
176 HandleWindowEvent(sizeEvent);
177
178 return true;
179 }
180
181 bool wxFrame::XmDoCreateTLW(wxWindow* WXUNUSED(parent),
182 wxWindowID WXUNUSED(id),
183 const wxString& WXUNUSED(title),
184 const wxPoint& WXUNUSED(pos),
185 const wxSize& WXUNUSED(size),
186 long style,
187 const wxString& name)
188 {
189 Widget frameShell;
190
191 frameShell = XtCreatePopupShell( name, topLevelShellWidgetClass,
192 (Widget)wxTheApp->GetTopLevelWidget(),
193 NULL, 0 );
194
195 XtVaSetValues(frameShell,
196 // Allows menu to resize
197 XmNallowShellResize, True,
198 XmNdeleteResponse, XmDO_NOTHING,
199 XmNmappedWhenManaged, False,
200 XmNiconic, (style & wxICONIZE) ? True : False,
201 NULL);
202
203 m_frameShell = (WXWidget)frameShell;
204
205 m_mainWidget = (WXWidget) XtVaCreateManagedWidget("main_window",
206 xmMainWindowWidgetClass, frameShell,
207 XmNresizePolicy, XmRESIZE_NONE,
208 NULL);
209
210 m_workArea = (WXWidget) XtVaCreateWidget("form",
211 xmFormWidgetClass, (Widget) m_mainWidget,
212 XmNresizePolicy, XmRESIZE_NONE,
213 NULL);
214
215 m_clientArea = (WXWidget) XtVaCreateWidget("client",
216 xmBulletinBoardWidgetClass, (Widget) m_workArea,
217 XmNmarginWidth, 0,
218 XmNmarginHeight, 0,
219 XmNrightAttachment, XmATTACH_FORM,
220 XmNleftAttachment, XmATTACH_FORM,
221 XmNtopAttachment, XmATTACH_FORM,
222 XmNbottomAttachment, XmATTACH_FORM,
223 NULL);
224
225 XtVaSetValues((Widget) m_mainWidget,
226 XmNworkWindow, (Widget) m_workArea,
227 NULL);
228
229 XtManageChild((Widget) m_clientArea);
230 XtManageChild((Widget) m_workArea);
231
232 XtTranslations ptr = XtParseTranslationTable( "<Configure>: resize()" );
233 XtOverrideTranslations( (Widget) m_workArea, ptr );
234 XtFree( (char *)ptr );
235
236 /* Part of show-&-hide fix */
237 XtAddEventHandler( frameShell, StructureNotifyMask,
238 False, (XtEventHandler)wxFrameMapProc,
239 (XtPointer)this );
240
241 XtRealizeWidget(frameShell);
242
243 wxAddWindowToTable( (Widget)m_workArea, this);
244 wxAddWindowToTable( (Widget)m_clientArea, this);
245
246 wxModelessWindows.Append( this );
247
248 return true;
249 }
250
251 wxFrame::~wxFrame()
252 {
253 SendDestroyEvent();
254
255 if (m_clientArea)
256 {
257 XtRemoveEventHandler((Widget) m_clientArea, ExposureMask, False,
258 wxUniversalRepaintProc, (XtPointer) this);
259 }
260
261 if (GetMainWidget())
262 Show(false);
263
264 if (m_frameMenuBar)
265 {
266 m_frameMenuBar->DestroyMenuBar();
267 wxDELETE(m_frameMenuBar);
268 }
269
270 wxDELETE(m_frameStatusBar);
271
272 PreDestroy();
273
274 Widget frameShell = (Widget)GetShellWidget();
275
276 if( frameShell )
277 XtRemoveEventHandler( frameShell, StructureNotifyMask,
278 False, (XtEventHandler)wxFrameMapProc,
279 (XtPointer)this );
280
281 if( m_clientArea )
282 {
283 wxDeleteWindowFromTable( (Widget)m_clientArea );
284 XtDestroyWidget( (Widget)m_clientArea );
285 }
286
287 if( m_workArea )
288 {
289 XtVaSetValues( (Widget)m_mainWidget,
290 XmNworkWindow, (Widget)NULL,
291 NULL );
292
293 wxDeleteWindowFromTable( (Widget)m_workArea );
294 XtDestroyWidget( (Widget)m_workArea );
295 }
296
297 if( m_mainWidget )
298 XtDestroyWidget( (Widget)m_mainWidget );
299
300 if( frameShell )
301 XtDestroyWidget( frameShell );
302 }
303
304 // Get size *available for subwindows* i.e. excluding menu bar, toolbar etc.
305 void wxFrame::DoGetClientSize(int *x, int *y) const
306 {
307 Dimension xx, yy;
308 XtVaGetValues((Widget) m_workArea, XmNwidth, &xx, XmNheight, &yy, NULL);
309
310 if (m_frameStatusBar)
311 {
312 int sbw, sbh;
313 m_frameStatusBar->GetSize(& sbw, & sbh);
314 yy = (Dimension)(yy - sbh);
315 }
316 #if wxUSE_TOOLBAR
317 if (m_frameToolBar)
318 {
319 int tbw, tbh;
320 m_frameToolBar->GetSize(& tbw, & tbh);
321 if (m_frameToolBar->GetWindowStyleFlag() & wxTB_VERTICAL)
322 xx = (Dimension)(xx - tbw);
323 else
324 yy = (Dimension)(yy - tbh);
325 }
326 #endif // wxUSE_TOOLBAR
327
328 //CE found a call here with NULL y pointer
329 if (x)
330 *x = xx;
331 if (y)
332 *y = yy;
333 }
334
335 // Set the client size (i.e. leave the calculation of borders etc.
336 // to wxWidgets)
337 void wxFrame::DoSetClientSize(int width, int height)
338 {
339 // Calculate how large the new main window should be
340 // by finding the difference between the client area and the
341 // main window area, and adding on to the new client area
342 if (width > -1)
343 XtVaSetValues((Widget) m_workArea, XmNwidth, width, NULL);
344
345 if (height > -1)
346 {
347 if (m_frameStatusBar)
348 {
349 int sbw, sbh;
350 m_frameStatusBar->GetSize(& sbw, & sbh);
351 height += sbh;
352 }
353 #if wxUSE_TOOLBAR
354 if (m_frameToolBar)
355 {
356 int tbw, tbh;
357 m_frameToolBar->GetSize(& tbw, & tbh);
358 if (m_frameToolBar->GetWindowStyleFlag() & wxTB_VERTICAL)
359 width += tbw;
360 else
361 height += tbh;
362 }
363 #endif // wxUSE_TOOLBAR
364
365 XtVaSetValues((Widget) m_workArea, XmNheight, height, NULL);
366 }
367 PreResize();
368
369 wxSize newSize(width, height);
370 wxSizeEvent sizeEvent(newSize, GetId());
371 sizeEvent.SetEventObject(this);
372
373 HandleWindowEvent(sizeEvent);
374
375 }
376
377 void wxFrame::DoGetSize(int *width, int *height) const
378 {
379 if (!m_frameShell)
380 {
381 *width = -1; *height = -1;
382 return;
383 }
384
385 Dimension xx, yy;
386 XtVaGetValues((Widget) m_frameShell, XmNwidth, &xx, XmNheight, &yy, NULL);
387 *width = xx; *height = yy;
388 }
389
390 void wxFrame::DoSetSize(int x, int y, int width, int height, int WXUNUSED(sizeFlags))
391 {
392 if (x > -1)
393 XtVaSetValues((Widget) m_frameShell, XmNx, x, NULL);
394 if (y > -1)
395 XtVaSetValues((Widget) m_frameShell, XmNy, y, NULL);
396 if (width > -1)
397 XtVaSetValues((Widget) m_mainWidget, XmNwidth, width, NULL);
398 if (height > -1)
399 XtVaSetValues((Widget) m_mainWidget, XmNheight, height, NULL);
400
401 if (!(height == -1 && width == -1))
402 {
403 PreResize();
404 }
405 }
406
407 bool wxFrame::Show( bool show )
408 {
409 if( !wxWindowBase::Show( show ) )
410 return false;
411
412 m_isShown = show;
413
414 Widget shell = (Widget)GetShellWidget();
415 if (!shell)
416 return wxWindow::Show(show);
417
418 SetVisibleStatus(show);
419 if (show)
420 {
421 XtPopup(shell, XtGrabNone);
422 }
423 else
424 {
425 XtPopdown(shell);
426 }
427
428 return true;
429 }
430
431 void wxFrame::SetTitle(const wxString& title)
432 {
433 wxString oldTitle = GetTitle();
434 if( title == oldTitle )
435 return;
436
437 wxTopLevelWindow::SetTitle( title );
438
439 if( !title.empty() )
440 XtVaSetValues( (Widget)m_frameShell,
441 XmNtitle, (const char*)title.mb_str(),
442 XmNiconName, (const char*)title.mb_str(),
443 NULL );
444 }
445
446 void wxFrame::DoSetIcon(const wxIcon& icon)
447 {
448 if (!m_frameShell)
449 return;
450
451 if (!icon.IsOk() || !icon.GetDrawable())
452 return;
453
454 XtVaSetValues((Widget) m_frameShell,
455 XtNiconPixmap, icon.GetDrawable(),
456 NULL);
457 }
458
459 void wxFrame::SetIcons(const wxIconBundle& icons)
460 {
461 wxFrameBase::SetIcons( icons );
462
463 if (!m_frameShell)
464 return;
465
466 DoSetIcon( m_icons.GetIcon( -1 ) );
467 wxSetIconsX11(GetXDisplay(),
468 (WXWindow) XtWindow( (Widget) m_frameShell ), icons);
469 }
470
471 void wxFrame::PositionStatusBar()
472 {
473 if (!m_frameStatusBar)
474 return;
475
476 int w, h;
477 GetClientSize(&w, &h);
478 int sw, sh;
479 m_frameStatusBar->GetSize(&sw, &sh);
480
481 // Since we wish the status bar to be directly under the client area,
482 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
483 m_frameStatusBar->SetSize(0, h, w, sh);
484 }
485
486 WXWidget wxFrame::GetMenuBarWidget() const
487 {
488 if (GetMenuBar())
489 return GetMenuBar()->GetMainWidget();
490 else
491 return (WXWidget) NULL;
492 }
493
494 void wxFrame::SetMenuBar(wxMenuBar *menuBar)
495 {
496 if (!menuBar)
497 {
498 m_frameMenuBar = NULL;
499 return;
500 }
501
502 // Currently can't set it twice
503 // wxASSERT_MSG( (m_frameMenuBar == NULL), "Cannot set the menubar more than once");
504
505 if (m_frameMenuBar)
506 {
507 m_frameMenuBar->DestroyMenuBar();
508 delete m_frameMenuBar;
509 }
510
511 m_frameMenuBar = menuBar;
512 m_frameMenuBar->CreateMenuBar(this);
513 }
514
515 // Responds to colour changes, and passes event on to children.
516 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
517 {
518 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
519 Refresh();
520
521 if ( m_frameStatusBar )
522 {
523 wxSysColourChangedEvent event2;
524 event2.SetEventObject( m_frameStatusBar );
525 m_frameStatusBar->HandleWindowEvent(event2);
526 }
527
528 // Propagate the event to the non-top-level children
529 wxWindow::OnSysColourChanged(event);
530 }
531
532 // Default activation behaviour - set the focus for the first child
533 // subwindow found.
534 void wxFrame::OnActivate(wxActivateEvent& event)
535 {
536 if (!event.GetActive())
537 return;
538
539 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node;
540 node = node->GetNext())
541 {
542 // Find a child that's a subwindow, but not a dialog box.
543 wxWindow *child = node->GetData();
544 if (!child->IsTopLevel())
545 {
546 child->SetFocus();
547 return;
548 }
549 }
550 }
551
552 #if wxUSE_TOOLBAR
553
554 wxToolBar* wxFrame::CreateToolBar(long style,
555 wxWindowID id,
556 const wxString& name)
557 {
558 if ( wxFrameBase::CreateToolBar(style, id, name) )
559 {
560 PositionToolBar();
561 }
562
563 return m_frameToolBar;
564 }
565
566 void wxFrame::SetToolBar(wxToolBar *toolbar)
567 {
568 wxFrameBase::SetToolBar(toolbar);
569 SendSizeEvent();
570 }
571
572 void wxFrame::PositionToolBar()
573 {
574 wxToolBar* tb = GetToolBar();
575 if (tb)
576 {
577 int cw, ch;
578 GetClientSize(& cw, &ch);
579
580 int tw, th;
581 tb->GetSize(& tw, & th);
582
583 if (tb->GetWindowStyleFlag() & wxTB_VERTICAL)
584 {
585 // Use the 'real' position. wxSIZE_NO_ADJUSTMENTS
586 // means, pretend we don't have toolbar/status bar, so we
587 // have the original client size.
588 th = ch + th;
589 }
590 else
591 {
592 // Use the 'real' position
593 tw = cw;
594 }
595
596 tb->SetSize(0, 0, -1, -1, wxSIZE_NO_ADJUSTMENTS);
597 }
598 }
599 #endif // wxUSE_TOOLBAR
600
601 //// Motif-specific
602 bool wxFrame::PreResize()
603 {
604 #if wxUSE_TOOLBAR
605 PositionToolBar();
606 #endif // wxUSE_TOOLBAR
607
608 #if wxUSE_STATUSBAR
609 PositionStatusBar();
610 #endif // wxUSE_STATUSBAR
611
612 return true;
613 }
614
615 WXWidget wxFrame::GetClientWidget() const
616 {
617 return m_clientArea;
618 }
619
620 void wxFrame::ChangeFont(bool WXUNUSED(keepOriginalSize))
621 {
622 // TODO
623 }
624
625 void wxFrame::ChangeBackgroundColour()
626 {
627 if (GetClientWidget())
628 wxDoChangeBackgroundColour(GetClientWidget(), m_backgroundColour);
629 }
630
631 void wxFrame::ChangeForegroundColour()
632 {
633 if (GetClientWidget())
634 wxDoChangeForegroundColour(GetClientWidget(), m_foregroundColour);
635 }
636
637 /* MATTEW: Used to insure that hide-&-show within an event cycle works */
638 static void wxFrameMapProc( Widget frameShell, XtPointer clientData,
639 XCrossingEvent* event )
640 {
641 wxFrame *tli = (wxFrame*)clientData;
642
643 XEvent *e = (XEvent *)event;
644
645 if( e->xany.type == MapNotify )
646 {
647 // Iconize fix
648 XtVaSetValues( frameShell, XmNiconic, (Boolean)False, NULL );
649 if( !tli->GetVisibleStatus() )
650 {
651 /* We really wanted this to be hidden! */
652 XtUnmapWidget( frameShell );
653 }
654 }
655 else if( e->xany.type == UnmapNotify )
656 // Iconize fix
657 XtVaSetValues( frameShell, XmNiconic, (Boolean)True, NULL );
658 }