1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: MDI classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "mdi.h"
18 #include "wx/settings.h"
21 #pragma message disable nosimpint
24 #include <Xm/BulletinB.h>
27 #include <Xm/RowColumn.h>
28 #include <Xm/CascadeBG.h>
30 #include <Xm/PushBG.h>
31 #include <Xm/AtomMgr.h>
32 #include <Xm/Protocols.h>
34 #pragma message enable nosimpint
37 #include "wx/motif/private.h"
39 extern wxList wxModelessWindows
;
41 // Implemented in frame.cpp
42 extern void wxFrameFocusProc(Widget workArea
, XtPointer clientData
,
43 XmAnyCallbackStruct
*cbs
);
45 #define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
47 #if !USE_SHARED_LIBRARY
48 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
49 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
50 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxNotebook
)
52 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
53 EVT_SIZE(wxMDIParentFrame::OnSize
)
54 EVT_ACTIVATE(wxMDIParentFrame::OnActivate
)
55 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
56 EVT_MENU_HIGHLIGHT_ALL(wxMDIParentFrame::OnMenuHighlight
)
59 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxNotebook
)
60 EVT_SCROLL(wxMDIClientWindow::OnScroll
)
61 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA
, wxMDIClientWindow::OnPageChanged
)
64 #endif // USE_SHARED_LIBRARY
68 wxMDIParentFrame::wxMDIParentFrame()
70 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
71 m_activeChild
= (wxMDIChildFrame
*) NULL
;
72 m_activeMenuBar
= (wxMenuBar
*) NULL
;
75 bool wxMDIParentFrame::Create(wxWindow
*parent
,
77 const wxString
& title
,
83 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
84 m_activeChild
= (wxMDIChildFrame
*) NULL
;
85 m_activeMenuBar
= (wxMenuBar
*) NULL
;
87 bool success
= wxFrame::Create(parent
, id
, title
, pos
, size
, style
, name
);
90 // TODO: app cannot override OnCreateClient since
91 // wxMDIParentFrame::OnCreateClient will still be called
92 // (we're in the constructor). How to resolve?
94 m_clientWindow
= OnCreateClient();
96 // Uses own style for client style
97 m_clientWindow
->CreateClient(this, GetWindowStyleFlag());
100 GetClientSize(& w
, & h
);
101 m_clientWindow
->SetSize(0, 0, w
, h
);
108 wxMDIParentFrame::~wxMDIParentFrame()
110 // Make sure we delete the client window last of all
111 RemoveChild(m_clientWindow
);
115 delete m_clientWindow
;
116 m_clientWindow
= NULL
;
119 void wxMDIParentFrame::SetMenuBar(wxMenuBar
*menu_bar
)
121 m_frameMenuBar
= menu_bar
;
123 SetChildMenuBar((wxMDIChildFrame
*) NULL
);
126 void wxMDIParentFrame::OnSize(wxSizeEvent
& WXUNUSED(event
))
128 #if wxUSE_CONSTRAINTS
135 GetClientSize(&width
, &height
);
137 if ( GetClientWindow() )
138 GetClientWindow()->SetSize(x
, y
, width
, height
);
141 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
143 wxFrame::DoGetClientSize(width
, height
);
146 void wxMDIParentFrame::OnActivate(wxActivateEvent
& WXUNUSED(event
))
151 // Returns the active MDI child window
152 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
154 return m_activeChild
;
157 // Create the client window class (don't Create the window,
158 // just return a new class)
159 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
161 return new wxMDIClientWindow
;
164 // Set the child's menu into the parent frame
165 void wxMDIParentFrame::SetChildMenuBar(wxMDIChildFrame
* child
)
167 wxMenuBar
* oldMenuBar
= m_activeMenuBar
;
169 if (child
== (wxMDIChildFrame
*) NULL
) // No child: use parent frame
171 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar
))
173 // if (m_activeMenuBar)
174 // m_activeMenuBar->DestroyMenuBar();
176 m_activeMenuBar
= GetMenuBar();
177 m_activeMenuBar
->CreateMenuBar(this);
179 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
180 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
182 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
183 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
187 else if (child
->GetMenuBar() == (wxMenuBar
*) NULL
) // No child menu bar: use parent frame
189 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar
))
191 // if (m_activeMenuBar)
192 // m_activeMenuBar->DestroyMenuBar();
193 m_activeMenuBar
= GetMenuBar();
194 m_activeMenuBar
->CreateMenuBar(this);
196 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
197 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
199 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
200 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
203 else // The child has a menubar
205 if (child
->GetMenuBar() != m_activeMenuBar
)
207 // if (m_activeMenuBar)
208 // m_activeMenuBar->DestroyMenuBar();
210 m_activeMenuBar
= child
->GetMenuBar();
211 m_activeMenuBar
->CreateMenuBar(this);
213 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
214 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
216 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
217 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
222 // Redirect events to active child first
223 bool wxMDIParentFrame::ProcessEvent(wxEvent
& event
)
225 // Stops the same event being processed repeatedly
226 static wxEventType inEvent
= wxEVT_NULL
;
227 if (inEvent
== event
.GetEventType())
230 inEvent
= event
.GetEventType();
233 if (m_activeChild
&& event
.IsKindOf(CLASSINFO(wxCommandEvent
)))
235 res
= m_activeChild
->GetEventHandler()->ProcessEvent(event
);
239 res
= GetEventHandler()->wxEvtHandler::ProcessEvent(event
);
241 inEvent
= wxEVT_NULL
;
246 void wxMDIParentFrame::DoSetSize(int x
, int y
,
247 int width
, int height
,
250 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
253 void wxMDIParentFrame::DoSetClientSize(int width
, int height
)
255 wxWindow::DoSetClientSize(width
, height
);
258 // Responds to colour changes, and passes event on to children.
259 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
263 // Propagate the event to the non-top-level children
264 wxFrame::OnSysColourChanged(event
);
268 void wxMDIParentFrame::Cascade()
273 void wxMDIParentFrame::Tile()
278 void wxMDIParentFrame::ArrangeIcons()
283 void wxMDIParentFrame::ActivateNext()
288 void wxMDIParentFrame::ActivatePrevious()
293 // Default menu selection behaviour - display a help string
294 void wxMDIParentFrame::OnMenuHighlight(wxMenuEvent
& event
)
298 if (event
.GetMenuId() == -1)
302 wxMenuBar
*menuBar
= (wxMenuBar
*) NULL
;
303 if (GetActiveChild())
304 menuBar
= GetActiveChild()->GetMenuBar();
306 menuBar
= GetMenuBar();
309 wxString
helpString(menuBar
->GetHelpString(event
.GetMenuId()));
310 if (helpString
!= "")
311 SetStatusText(helpString
);
319 wxMDIChildFrame::wxMDIChildFrame()
321 m_mdiParentFrame
= (wxMDIParentFrame
*) NULL
;
324 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
326 const wxString
& title
,
330 const wxString
& name
)
333 SetWindowStyleFlag(style
);
335 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
);
336 m_foregroundColour
= *wxBLACK
;
337 m_font
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
);
342 m_windowId
= (int)NewControlId();
344 wxMDIClientWindow
* clientWindow
= parent
->GetClientWindow();
346 wxASSERT_MSG( (clientWindow
!= (wxWindow
*) NULL
), "Missing MDI client window.");
348 if (clientWindow
) clientWindow
->AddChild(this);
350 SetMDIParentFrame(parent
);
355 width
= 200; // TODO: give reasonable default
357 height
= 200; // TODO: give reasonable default
359 // We're deactivating the old child
360 wxMDIChildFrame
* oldActiveChild
= parent
->GetActiveChild();
363 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldActiveChild
->GetId());
364 event
.SetEventObject( oldActiveChild
);
365 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
368 // This is the currently active child
369 parent
->SetActiveChild((wxMDIChildFrame
*) this);
371 // This time we'll try a bog-standard bulletin board for
372 // the 'frame'. A main window doesn't seem to work.
374 m_mainWidget
= (WXWidget
) XtVaCreateWidget("client",
375 xmBulletinBoardWidgetClass
, (Widget
) clientWindow
->GetTopWidget(),
379 XmNrightAttachment, XmATTACH_FORM,
380 XmNleftAttachment, XmATTACH_FORM,
381 XmNtopAttachment, XmATTACH_FORM,
382 XmNbottomAttachment, XmATTACH_FORM,
384 XmNresizePolicy
, XmRESIZE_NONE
,
387 XtAddEventHandler((Widget
) m_mainWidget
, ExposureMask
,FALSE
,
388 wxUniversalRepaintProc
, (XtPointer
) this);
390 SetCanAddEventHandler(TRUE
);
391 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
393 ChangeBackgroundColour();
395 XtManageChild((Widget
) m_mainWidget
);
399 clientWindow
->AddPage(this, title
, TRUE
);
400 clientWindow
->Refresh();
402 // Positions the toolbar and status bar -- but we don't have any.
405 wxModelessWindows
.Append(this);
410 wxMDIChildFrame::~wxMDIChildFrame()
413 XtRemoveEventHandler((Widget
) m_mainWidget
, ExposureMask
,FALSE
,
414 wxUniversalRepaintProc
, (XtPointer
) this);
416 if (GetMDIParentFrame())
418 wxMDIParentFrame
* parentFrame
= GetMDIParentFrame();
420 if (parentFrame
->GetActiveChild() == this)
421 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
422 wxMDIClientWindow
* clientWindow
= parentFrame
->GetClientWindow();
424 // Remove page if still there
425 if (clientWindow
->RemovePage(this))
426 clientWindow
->Refresh();
428 // Set the selection to the first remaining page
429 if (clientWindow
->GetPageCount() > 0)
431 wxMDIChildFrame
* child
= (wxMDIChildFrame
*) clientWindow
->GetPage(0);
432 parentFrame
->SetActiveChild(child
);
433 parentFrame
->SetChildMenuBar(child
);
437 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
438 parentFrame
->SetChildMenuBar((wxMDIChildFrame
*) NULL
);
444 // Implementation: intercept and act upon raise and lower commands.
445 void wxMDIChildFrame::OnRaise()
447 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
448 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
449 parentFrame
->SetActiveChild(this);
453 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldActiveChild
->GetId());
454 event
.SetEventObject( oldActiveChild
);
455 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
458 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, this->GetId());
459 event
.SetEventObject( this );
460 this->GetEventHandler()->ProcessEvent(event
);
463 void wxMDIChildFrame::OnLower()
465 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
466 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
468 if (oldActiveChild
== this)
470 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldActiveChild
->GetId());
471 event
.SetEventObject( oldActiveChild
);
472 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
474 // TODO: unfortunately we don't now know which is the top-most child,
475 // so make the active child NULL.
476 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
480 // Set the client size (i.e. leave the calculation of borders etc.
482 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
484 wxWindow::DoSetClientSize(width
, height
);
487 void wxMDIChildFrame::DoGetClientSize(int* width
, int* height
) const
489 wxWindow::DoGetSize(width
, height
);
492 void wxMDIChildFrame::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
494 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
497 void wxMDIChildFrame::DoGetSize(int* width
, int* height
) const
499 wxWindow::DoGetSize(width
, height
);
502 void wxMDIChildFrame::DoGetPosition(int *x
, int *y
) const
504 wxWindow::DoGetPosition(x
, y
);
507 bool wxMDIChildFrame::Show(bool show
)
509 m_visibleStatus
= show
; /* show-&-hide fix */
510 return wxWindow::Show(show
);
513 void wxMDIChildFrame::SetMenuBar(wxMenuBar
*menuBar
)
515 // Don't create the underlying menubar yet; need to recreate
516 // it every time the child is activated.
517 m_frameMenuBar
= menuBar
;
519 // We make the assumption that if you're setting the menubar,
520 // this is the currently active child.
521 GetMDIParentFrame()->SetChildMenuBar(this);
525 void wxMDIChildFrame::SetIcon(const wxIcon
& icon
)
530 // Not appropriate since there are no icons in
535 void wxMDIChildFrame::SetTitle(const wxString
& title
)
538 wxMDIClientWindow
* clientWindow
= GetMDIParentFrame()->GetClientWindow();
539 int pageNo
= clientWindow
->FindPagePosition(this);
541 clientWindow
->SetPageText(pageNo
, title
);
545 void wxMDIChildFrame::Maximize()
550 void wxMDIChildFrame::Iconize(bool WXUNUSED(iconize
))
555 bool wxMDIChildFrame::IsIconized() const
560 // Is it maximized? Always maximized under Motif, using the
561 // tabbed MDI implementation.
562 bool wxMDIChildFrame::IsMaximized(void) const
567 void wxMDIChildFrame::Restore()
572 void wxMDIChildFrame::Activate()
577 void wxMDIChildFrame::CaptureMouse()
579 wxWindow::CaptureMouse();
582 void wxMDIChildFrame::ReleaseMouse()
584 wxWindow::ReleaseMouse();
587 void wxMDIChildFrame::Raise()
592 void wxMDIChildFrame::Lower(void)
597 void wxMDIChildFrame::SetSizeHints(int WXUNUSED(minW
), int WXUNUSED(minH
), int WXUNUSED(maxW
), int WXUNUSED(maxH
), int WXUNUSED(incW
), int WXUNUSED(incH
))
603 wxMDIClientWindow::wxMDIClientWindow()
607 wxMDIClientWindow::~wxMDIClientWindow()
609 // By the time this destructor is called, the child frames will have been
610 // deleted and removed from the notebook/client window.
613 m_mainWidget
= (WXWidget
) 0;
616 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
618 SetWindowStyleFlag(style
);
620 // m_windowParent = parent;
621 // m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE);
623 bool success
= wxNotebook::Create(parent
, wxID_NOTEBOOK_CLIENT_AREA
, wxPoint(0, 0), wxSize(100, 100), 0);
626 wxFont
font(10, wxSWISS
, wxNORMAL
, wxNORMAL
);
627 wxFont
selFont(10, wxSWISS
, wxNORMAL
, wxBOLD
);
628 GetTabView()->SetTabFont(font
);
629 GetTabView()->SetSelectedTabFont(selFont
);
630 GetTabView()->SetTabSize(120, 18);
631 GetTabView()->SetTabSelectionHeight(20);
638 void wxMDIClientWindow::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
640 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
643 void wxMDIClientWindow::DoSetClientSize(int width
, int height
)
645 wxWindow::DoSetClientSize(width
, height
);
648 void wxMDIClientWindow::DoGetClientSize(int *width
, int *height
) const
650 wxWindow::DoGetClientSize(width
, height
);
653 void wxMDIClientWindow::DoGetSize(int *width
, int *height
) const
655 wxWindow::DoGetSize(width
, height
);
658 void wxMDIClientWindow::DoGetPosition(int *x
, int *y
) const
660 wxWindow::DoGetPosition(x
, y
);
663 // Explicitly call default scroll behaviour
664 void wxMDIClientWindow::OnScroll(wxScrollEvent
& WXUNUSED(event
))
666 Default(); // Default processing
669 void wxMDIClientWindow::OnPageChanged(wxNotebookEvent
& event
)
671 // Notify child that it has been activated
672 if (event
.GetOldSelection() != -1)
674 wxMDIChildFrame
* oldChild
= (wxMDIChildFrame
*) GetPage(event
.GetOldSelection());
677 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldChild
->GetId());
678 event
.SetEventObject( oldChild
);
679 oldChild
->GetEventHandler()->ProcessEvent(event
);
682 if (event
.GetSelection() != -1)
684 wxMDIChildFrame
* activeChild
= (wxMDIChildFrame
*) GetPage(event
.GetSelection());
687 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, activeChild
->GetId());
688 event
.SetEventObject( activeChild
);
689 activeChild
->GetEventHandler()->ProcessEvent(event
);
691 if (activeChild
->GetMDIParentFrame())
693 activeChild
->GetMDIParentFrame()->SetActiveChild(activeChild
);
694 activeChild
->GetMDIParentFrame()->SetChildMenuBar(activeChild
);