1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/mdi.cpp
3 // Purpose: MDI classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
16 #define XtDisplay XTDISPLAY
17 #define XtWindow XTWINDOW
25 #include "wx/settings.h"
29 #pragma message disable nosimpint
32 #include <Xm/BulletinB.h>
35 #include <Xm/RowColumn.h>
36 #include <Xm/CascadeBG.h>
38 #include <Xm/PushBG.h>
39 #include <Xm/AtomMgr.h>
40 #include <Xm/Protocols.h>
42 #pragma message enable nosimpint
45 #include "wx/motif/private.h"
47 extern wxList wxModelessWindows
;
49 // Implemented in frame.cpp
50 extern void wxFrameFocusProc(Widget workArea
, XtPointer clientData
,
51 XmAnyCallbackStruct
*cbs
);
53 #define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
55 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
56 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
57 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxNotebook
)
59 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
60 EVT_SIZE(wxMDIParentFrame::OnSize
)
61 EVT_ACTIVATE(wxMDIParentFrame::OnActivate
)
62 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
63 EVT_MENU_HIGHLIGHT_ALL(wxMDIParentFrame::OnMenuHighlight
)
66 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxNotebook
)
67 EVT_SCROLL(wxMDIClientWindow::OnScroll
)
68 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA
, wxMDIClientWindow::OnPageChanged
)
74 wxMDIParentFrame::wxMDIParentFrame()
76 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
77 m_activeChild
= (wxMDIChildFrame
*) NULL
;
78 m_activeMenuBar
= (wxMenuBar
*) NULL
;
81 bool wxMDIParentFrame::Create(wxWindow
*parent
,
83 const wxString
& title
,
89 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
90 m_activeChild
= (wxMDIChildFrame
*) NULL
;
91 m_activeMenuBar
= (wxMenuBar
*) NULL
;
93 bool success
= wxFrame::Create(parent
, id
, title
, pos
, size
, style
, name
);
96 // TODO: app cannot override OnCreateClient since
97 // wxMDIParentFrame::OnCreateClient will still be called
98 // (we're in the constructor). How to resolve?
100 m_clientWindow
= OnCreateClient();
102 // Uses own style for client style
103 m_clientWindow
->CreateClient(this, GetWindowStyleFlag());
106 GetClientSize(& w
, & h
);
107 m_clientWindow
->SetSize(0, 0, w
, h
);
114 wxMDIParentFrame::~wxMDIParentFrame()
116 // Make sure we delete the client window last of all
117 RemoveChild(m_clientWindow
);
121 delete m_clientWindow
;
122 m_clientWindow
= NULL
;
125 void wxMDIParentFrame::SetMenuBar(wxMenuBar
*menu_bar
)
127 m_frameMenuBar
= menu_bar
;
129 SetChildMenuBar((wxMDIChildFrame
*) NULL
);
132 void wxMDIParentFrame::OnSize(wxSizeEvent
& WXUNUSED(event
))
134 #if wxUSE_CONSTRAINTS
141 GetClientSize(&width
, &height
);
143 if ( GetClientWindow() )
144 GetClientWindow()->SetSize(x
, y
, width
, height
);
147 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
149 wxFrame::DoGetClientSize(width
, height
);
152 void wxMDIParentFrame::OnActivate(wxActivateEvent
& WXUNUSED(event
))
157 // Returns the active MDI child window
158 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
160 return m_activeChild
;
163 // Create the client window class (don't Create the window,
164 // just return a new class)
165 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
167 return new wxMDIClientWindow
;
170 // Set the child's menu into the parent frame
171 void wxMDIParentFrame::SetChildMenuBar(wxMDIChildFrame
* child
)
173 wxMenuBar
* oldMenuBar
= m_activeMenuBar
;
175 if (child
== (wxMDIChildFrame
*) NULL
) // No child: use parent frame
177 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar
))
179 // if (m_activeMenuBar)
180 // m_activeMenuBar->DestroyMenuBar();
182 m_activeMenuBar
= GetMenuBar();
183 m_activeMenuBar
->CreateMenuBar(this);
185 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
186 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
188 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
189 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
193 else if (child
->GetMenuBar() == (wxMenuBar
*) NULL
) // No child menu bar: use parent frame
195 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar
))
197 // if (m_activeMenuBar)
198 // m_activeMenuBar->DestroyMenuBar();
199 m_activeMenuBar
= GetMenuBar();
200 m_activeMenuBar
->CreateMenuBar(this);
202 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
203 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
205 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
206 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
209 else // The child has a menubar
211 if (child
->GetMenuBar() != m_activeMenuBar
)
213 // if (m_activeMenuBar)
214 // m_activeMenuBar->DestroyMenuBar();
216 m_activeMenuBar
= child
->GetMenuBar();
217 m_activeMenuBar
->CreateMenuBar(this);
219 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
220 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
222 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
223 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
228 // Redirect events to active child first
229 bool wxMDIParentFrame::ProcessEvent(wxEvent
& event
)
231 // Stops the same event being processed repeatedly
232 static wxEventType inEvent
= wxEVT_NULL
;
233 if (inEvent
== event
.GetEventType())
236 inEvent
= event
.GetEventType();
239 if (m_activeChild
&& event
.IsKindOf(CLASSINFO(wxCommandEvent
)))
241 res
= m_activeChild
->HandleWindowEvent(event
);
245 res
= GetEventHandler()->wxEvtHandler::ProcessEvent(event
);
247 inEvent
= wxEVT_NULL
;
252 void wxMDIParentFrame::DoSetSize(int x
, int y
,
253 int width
, int height
,
256 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
259 void wxMDIParentFrame::DoSetClientSize(int width
, int height
)
261 wxWindow::DoSetClientSize(width
, height
);
264 // Responds to colour changes, and passes event on to children.
265 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
269 // Propagate the event to the non-top-level children
270 wxFrame::OnSysColourChanged(event
);
274 void wxMDIParentFrame::Cascade()
279 void wxMDIParentFrame::Tile(wxOrientation
WXUNUSED(orient
))
284 void wxMDIParentFrame::ArrangeIcons()
289 void wxMDIParentFrame::ActivateNext()
294 void wxMDIParentFrame::ActivatePrevious()
299 // Default menu selection behaviour - display a help string
300 void wxMDIParentFrame::OnMenuHighlight(wxMenuEvent
& event
)
304 if (event
.GetMenuId() == -1)
305 SetStatusText(wxEmptyString
);
308 wxMenuBar
*menuBar
= (wxMenuBar
*) NULL
;
309 if (GetActiveChild())
310 menuBar
= GetActiveChild()->GetMenuBar();
312 menuBar
= GetMenuBar();
315 wxString
helpString(menuBar
->GetHelpString(event
.GetMenuId()));
316 if (!helpString
.empty())
317 SetStatusText(helpString
);
325 wxMDIChildFrame::wxMDIChildFrame()
327 m_mdiParentFrame
= (wxMDIParentFrame
*) NULL
;
330 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
332 const wxString
& title
,
336 const wxString
& name
)
339 SetWindowStyleFlag(style
);
344 m_windowId
= (int)NewControlId();
346 wxMDIClientWindow
* clientWindow
= parent
->GetClientWindow();
348 wxCHECK_MSG( clientWindow
, false, "Missing MDI client window." );
350 clientWindow
->AddChild(this);
352 SetMDIParentFrame(parent
);
358 width
= 200; // TODO: give reasonable default
360 height
= 200; // TODO: give reasonable default
362 // We're deactivating the old child
363 wxMDIChildFrame
* oldActiveChild
= parent
->GetActiveChild();
366 wxActivateEvent
event(wxEVT_ACTIVATE
, false, oldActiveChild
->GetId());
367 event
.SetEventObject( oldActiveChild
);
368 oldActiveChild
->HandleWindowEvent(event
);
371 // This is the currently active child
372 parent
->SetActiveChild((wxMDIChildFrame
*) this);
374 // This time we'll try a bog-standard bulletin board for
375 // the 'frame'. A main window doesn't seem to work.
377 m_mainWidget
= (WXWidget
) XtVaCreateWidget("client",
378 xmBulletinBoardWidgetClass
, (Widget
) clientWindow
->GetTopWidget(),
382 XmNrightAttachment, XmATTACH_FORM,
383 XmNleftAttachment, XmATTACH_FORM,
384 XmNtopAttachment, XmATTACH_FORM,
385 XmNbottomAttachment, XmATTACH_FORM,
387 XmNresizePolicy
, XmRESIZE_NONE
,
390 XtAddEventHandler((Widget
) m_mainWidget
, ExposureMask
,False
,
391 wxUniversalRepaintProc
, (XtPointer
) this);
394 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
396 XtManageChild((Widget
) m_mainWidget
);
400 clientWindow
->AddPage(this, title
, true);
401 clientWindow
->Refresh();
403 // Positions the toolbar and status bar -- but we don't have any.
406 wxModelessWindows
.Append(this);
411 wxMDIChildFrame::~wxMDIChildFrame()
414 XtRemoveEventHandler((Widget
) m_mainWidget
, ExposureMask
,False
,
415 wxUniversalRepaintProc
, (XtPointer
) this);
417 if (GetMDIParentFrame())
419 wxMDIParentFrame
* parentFrame
= GetMDIParentFrame();
421 if (parentFrame
->GetActiveChild() == this)
422 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
423 wxMDIClientWindow
* clientWindow
= parentFrame
->GetClientWindow();
425 // Remove page if still there
427 int i
= clientWindow
->FindPage(this);
431 clientWindow
->RemovePage(i
);
432 clientWindow
->Refresh();
436 // Set the selection to the first remaining page
437 if (clientWindow
->GetPageCount() > 0)
439 wxMDIChildFrame
* child
= (wxMDIChildFrame
*) clientWindow
->GetPage(0);
440 parentFrame
->SetActiveChild(child
);
441 parentFrame
->SetChildMenuBar(child
);
445 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
446 parentFrame
->SetChildMenuBar((wxMDIChildFrame
*) NULL
);
452 // Implementation: intercept and act upon raise and lower commands.
453 void wxMDIChildFrame::OnRaise()
455 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
456 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
457 parentFrame
->SetActiveChild(this);
461 wxActivateEvent
event(wxEVT_ACTIVATE
, false, oldActiveChild
->GetId());
462 event
.SetEventObject( oldActiveChild
);
463 oldActiveChild
->HandleWindowEvent(event
);
466 wxActivateEvent
event(wxEVT_ACTIVATE
, true, this->GetId());
467 event
.SetEventObject( this );
468 this->HandleWindowEvent(event
);
471 void wxMDIChildFrame::OnLower()
473 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
474 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
476 if (oldActiveChild
== this)
478 wxActivateEvent
event(wxEVT_ACTIVATE
, false, oldActiveChild
->GetId());
479 event
.SetEventObject( oldActiveChild
);
480 oldActiveChild
->HandleWindowEvent(event
);
482 // TODO: unfortunately we don't now know which is the top-most child,
483 // so make the active child NULL.
484 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
488 // Set the client size (i.e. leave the calculation of borders etc.
490 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
492 wxWindow::DoSetClientSize(width
, height
);
495 void wxMDIChildFrame::DoGetClientSize(int* width
, int* height
) const
497 wxWindow::DoGetSize(width
, height
);
500 void wxMDIChildFrame::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
502 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
505 void wxMDIChildFrame::DoGetSize(int* width
, int* height
) const
507 wxWindow::DoGetSize(width
, height
);
510 void wxMDIChildFrame::DoGetPosition(int *x
, int *y
) const
512 wxWindow::DoGetPosition(x
, y
);
515 bool wxMDIChildFrame::Show(bool show
)
517 SetVisibleStatus( show
);
518 return wxWindow::Show(show
);
521 void wxMDIChildFrame::SetMenuBar(wxMenuBar
*menuBar
)
523 // Don't create the underlying menubar yet; need to recreate
524 // it every time the child is activated.
525 m_frameMenuBar
= menuBar
;
527 // We make the assumption that if you're setting the menubar,
528 // this is the currently active child.
529 GetMDIParentFrame()->SetChildMenuBar(this);
533 void wxMDIChildFrame::SetIcon(const wxIcon
& icon
)
535 m_icons
= wxIconBundle( icon
);
539 // Not appropriate since there are no icons in
544 void wxMDIChildFrame::SetIcons(const wxIconBundle
& icons
)
549 void wxMDIChildFrame::SetTitle(const wxString
& title
)
551 wxTopLevelWindow::SetTitle( title
);
552 wxMDIClientWindow
* clientWindow
= GetMDIParentFrame()->GetClientWindow();
554 // Remove page if still there
556 int i
= clientWindow
->FindPage(this);
559 clientWindow
->SetPageText(i
, title
);
564 void wxMDIChildFrame::Maximize()
569 void wxMDIChildFrame::Iconize(bool WXUNUSED(iconize
))
574 bool wxMDIChildFrame::IsIconized() const
579 // Is it maximized? Always maximized under Motif, using the
580 // tabbed MDI implementation.
581 bool wxMDIChildFrame::IsMaximized(void) const
586 void wxMDIChildFrame::Restore()
591 void wxMDIChildFrame::Activate()
596 void wxMDIChildFrame::CaptureMouse()
598 wxWindow::CaptureMouse();
601 void wxMDIChildFrame::ReleaseMouse()
603 wxWindow::ReleaseMouse();
606 void wxMDIChildFrame::Raise()
611 void wxMDIChildFrame::Lower(void)
616 void wxMDIChildFrame::DoSetSizeHints(int WXUNUSED(minW
), int WXUNUSED(minH
), int WXUNUSED(maxW
), int WXUNUSED(maxH
), int WXUNUSED(incW
), int WXUNUSED(incH
))
622 wxMDIClientWindow::wxMDIClientWindow()
626 wxMDIClientWindow::~wxMDIClientWindow()
628 // By the time this destructor is called, the child frames will have been
629 // deleted and removed from the notebook/client window.
632 m_mainWidget
= (WXWidget
) 0;
635 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
637 SetWindowStyleFlag(style
);
639 bool success
= wxNotebook::Create(parent
, wxID_NOTEBOOK_CLIENT_AREA
, wxPoint(0, 0), wxSize(100, 100), 0);
648 int wxMDIClientWindow::FindPage(const wxNotebookPage
* page
)
650 for (int i
= GetPageCount() - 1; i
>= 0; --i
)
652 if (GetPage(i
) == page
)
659 void wxMDIClientWindow::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
661 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
664 void wxMDIClientWindow::DoSetClientSize(int width
, int height
)
666 wxWindow::DoSetClientSize(width
, height
);
669 void wxMDIClientWindow::DoGetClientSize(int *width
, int *height
) const
671 wxWindow::DoGetClientSize(width
, height
);
674 void wxMDIClientWindow::DoGetSize(int *width
, int *height
) const
676 wxWindow::DoGetSize(width
, height
);
679 void wxMDIClientWindow::DoGetPosition(int *x
, int *y
) const
681 wxWindow::DoGetPosition(x
, y
);
684 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
)
686 // Default(); // Default processing: OBSOLETE FUNCTION
690 void wxMDIClientWindow::OnPageChanged(wxNotebookEvent
& event
)
692 // Notify child that it has been activated
693 if (event
.GetOldSelection() != -1)
695 wxMDIChildFrame
* oldChild
= (wxMDIChildFrame
*) GetPage(event
.GetOldSelection());
698 wxActivateEvent
event(wxEVT_ACTIVATE
, false, oldChild
->GetId());
699 event
.SetEventObject( oldChild
);
700 oldChild
->HandleWindowEvent(event
);
703 if (event
.GetSelection() != -1)
705 wxMDIChildFrame
* activeChild
= (wxMDIChildFrame
*) GetPage(event
.GetSelection());
708 wxActivateEvent
event(wxEVT_ACTIVATE
, true, activeChild
->GetId());
709 event
.SetEventObject( activeChild
);
710 activeChild
->HandleWindowEvent(event
);
712 if (activeChild
->GetMDIParentFrame())
714 activeChild
->GetMDIParentFrame()->SetActiveChild(activeChild
);
715 activeChild
->GetMDIParentFrame()->SetChildMenuBar(activeChild
);