1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: MDI classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "mdi.h"
17 #define XtDisplay XTDISPLAY
18 #define XtWindow XTWINDOW
24 #include "wx/settings.h"
28 #pragma message disable nosimpint
31 #include <Xm/BulletinB.h>
34 #include <Xm/RowColumn.h>
35 #include <Xm/CascadeBG.h>
37 #include <Xm/PushBG.h>
38 #include <Xm/AtomMgr.h>
39 #include <Xm/Protocols.h>
41 #pragma message enable nosimpint
44 #include "wx/motif/private.h"
46 extern wxList wxModelessWindows
;
48 // Implemented in frame.cpp
49 extern void wxFrameFocusProc(Widget workArea
, XtPointer clientData
,
50 XmAnyCallbackStruct
*cbs
);
52 #define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
54 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
55 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
56 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxNotebook
)
58 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
59 EVT_SIZE(wxMDIParentFrame::OnSize
)
60 EVT_ACTIVATE(wxMDIParentFrame::OnActivate
)
61 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
62 EVT_MENU_HIGHLIGHT_ALL(wxMDIParentFrame::OnMenuHighlight
)
65 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxNotebook
)
66 EVT_SCROLL(wxMDIClientWindow::OnScroll
)
67 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA
, wxMDIClientWindow::OnPageChanged
)
73 wxMDIParentFrame::wxMDIParentFrame()
75 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
76 m_activeChild
= (wxMDIChildFrame
*) NULL
;
77 m_activeMenuBar
= (wxMenuBar
*) NULL
;
80 bool wxMDIParentFrame::Create(wxWindow
*parent
,
82 const wxString
& title
,
88 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
89 m_activeChild
= (wxMDIChildFrame
*) NULL
;
90 m_activeMenuBar
= (wxMenuBar
*) NULL
;
92 bool success
= wxFrame::Create(parent
, id
, title
, pos
, size
, style
, name
);
95 // TODO: app cannot override OnCreateClient since
96 // wxMDIParentFrame::OnCreateClient will still be called
97 // (we're in the constructor). How to resolve?
99 m_clientWindow
= OnCreateClient();
101 // Uses own style for client style
102 m_clientWindow
->CreateClient(this, GetWindowStyleFlag());
105 GetClientSize(& w
, & h
);
106 m_clientWindow
->SetSize(0, 0, w
, h
);
113 wxMDIParentFrame::~wxMDIParentFrame()
115 // Make sure we delete the client window last of all
116 RemoveChild(m_clientWindow
);
120 delete m_clientWindow
;
121 m_clientWindow
= NULL
;
124 void wxMDIParentFrame::SetMenuBar(wxMenuBar
*menu_bar
)
126 m_frameMenuBar
= menu_bar
;
128 SetChildMenuBar((wxMDIChildFrame
*) NULL
);
131 void wxMDIParentFrame::OnSize(wxSizeEvent
& WXUNUSED(event
))
133 #if wxUSE_CONSTRAINTS
140 GetClientSize(&width
, &height
);
142 if ( GetClientWindow() )
143 GetClientWindow()->SetSize(x
, y
, width
, height
);
146 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
148 wxFrame::DoGetClientSize(width
, height
);
151 void wxMDIParentFrame::OnActivate(wxActivateEvent
& WXUNUSED(event
))
156 // Returns the active MDI child window
157 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
159 return m_activeChild
;
162 // Create the client window class (don't Create the window,
163 // just return a new class)
164 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
166 return new wxMDIClientWindow
;
169 // Set the child's menu into the parent frame
170 void wxMDIParentFrame::SetChildMenuBar(wxMDIChildFrame
* child
)
172 wxMenuBar
* oldMenuBar
= m_activeMenuBar
;
174 if (child
== (wxMDIChildFrame
*) NULL
) // No child: use parent frame
176 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar
))
178 // if (m_activeMenuBar)
179 // m_activeMenuBar->DestroyMenuBar();
181 m_activeMenuBar
= GetMenuBar();
182 m_activeMenuBar
->CreateMenuBar(this);
184 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
185 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
187 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
188 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
192 else if (child
->GetMenuBar() == (wxMenuBar
*) NULL
) // No child menu bar: use parent frame
194 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar
))
196 // if (m_activeMenuBar)
197 // m_activeMenuBar->DestroyMenuBar();
198 m_activeMenuBar
= GetMenuBar();
199 m_activeMenuBar
->CreateMenuBar(this);
201 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
202 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
204 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
205 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
208 else // The child has a menubar
210 if (child
->GetMenuBar() != m_activeMenuBar
)
212 // if (m_activeMenuBar)
213 // m_activeMenuBar->DestroyMenuBar();
215 m_activeMenuBar
= child
->GetMenuBar();
216 m_activeMenuBar
->CreateMenuBar(this);
218 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
219 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
221 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
222 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
227 // Redirect events to active child first
228 bool wxMDIParentFrame::ProcessEvent(wxEvent
& event
)
230 // Stops the same event being processed repeatedly
231 static wxEventType inEvent
= wxEVT_NULL
;
232 if (inEvent
== event
.GetEventType())
235 inEvent
= event
.GetEventType();
238 if (m_activeChild
&& event
.IsKindOf(CLASSINFO(wxCommandEvent
)))
240 res
= m_activeChild
->GetEventHandler()->ProcessEvent(event
);
244 res
= GetEventHandler()->wxEvtHandler::ProcessEvent(event
);
246 inEvent
= wxEVT_NULL
;
251 void wxMDIParentFrame::DoSetSize(int x
, int y
,
252 int width
, int height
,
255 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
258 void wxMDIParentFrame::DoSetClientSize(int width
, int height
)
260 wxWindow::DoSetClientSize(width
, height
);
263 // Responds to colour changes, and passes event on to children.
264 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
268 // Propagate the event to the non-top-level children
269 wxFrame::OnSysColourChanged(event
);
273 void wxMDIParentFrame::Cascade()
278 void wxMDIParentFrame::Tile()
283 void wxMDIParentFrame::ArrangeIcons()
288 void wxMDIParentFrame::ActivateNext()
293 void wxMDIParentFrame::ActivatePrevious()
298 // Default menu selection behaviour - display a help string
299 void wxMDIParentFrame::OnMenuHighlight(wxMenuEvent
& event
)
303 if (event
.GetMenuId() == -1)
307 wxMenuBar
*menuBar
= (wxMenuBar
*) NULL
;
308 if (GetActiveChild())
309 menuBar
= GetActiveChild()->GetMenuBar();
311 menuBar
= GetMenuBar();
314 wxString
helpString(menuBar
->GetHelpString(event
.GetMenuId()));
315 if (helpString
!= "")
316 SetStatusText(helpString
);
324 wxMDIChildFrame::wxMDIChildFrame()
326 m_mdiParentFrame
= (wxMDIParentFrame
*) NULL
;
329 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
331 const wxString
& title
,
335 const wxString
& name
)
338 SetWindowStyleFlag(style
);
340 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
);
341 m_foregroundColour
= *wxBLACK
;
342 m_font
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
347 m_windowId
= (int)NewControlId();
349 wxMDIClientWindow
* clientWindow
= parent
->GetClientWindow();
351 wxASSERT_MSG( (clientWindow
!= (wxWindow
*) NULL
), "Missing MDI client window.");
353 if (clientWindow
) clientWindow
->AddChild(this);
355 SetMDIParentFrame(parent
);
360 width
= 200; // TODO: give reasonable default
362 height
= 200; // TODO: give reasonable default
364 // We're deactivating the old child
365 wxMDIChildFrame
* oldActiveChild
= parent
->GetActiveChild();
368 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldActiveChild
->GetId());
369 event
.SetEventObject( oldActiveChild
);
370 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
373 // This is the currently active child
374 parent
->SetActiveChild((wxMDIChildFrame
*) this);
376 // This time we'll try a bog-standard bulletin board for
377 // the 'frame'. A main window doesn't seem to work.
379 m_mainWidget
= (WXWidget
) XtVaCreateWidget("client",
380 xmBulletinBoardWidgetClass
, (Widget
) clientWindow
->GetTopWidget(),
384 XmNrightAttachment, XmATTACH_FORM,
385 XmNleftAttachment, XmATTACH_FORM,
386 XmNtopAttachment, XmATTACH_FORM,
387 XmNbottomAttachment, XmATTACH_FORM,
389 XmNresizePolicy
, XmRESIZE_NONE
,
392 XtAddEventHandler((Widget
) m_mainWidget
, ExposureMask
,FALSE
,
393 wxUniversalRepaintProc
, (XtPointer
) this);
395 SetCanAddEventHandler(TRUE
);
396 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
398 ChangeBackgroundColour();
400 XtManageChild((Widget
) m_mainWidget
);
404 clientWindow
->AddPage(this, title
, TRUE
);
405 clientWindow
->Refresh();
407 // Positions the toolbar and status bar -- but we don't have any.
410 wxModelessWindows
.Append(this);
415 wxMDIChildFrame::~wxMDIChildFrame()
418 XtRemoveEventHandler((Widget
) m_mainWidget
, ExposureMask
,FALSE
,
419 wxUniversalRepaintProc
, (XtPointer
) this);
421 if (GetMDIParentFrame())
423 wxMDIParentFrame
* parentFrame
= GetMDIParentFrame();
425 if (parentFrame
->GetActiveChild() == this)
426 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
427 wxMDIClientWindow
* clientWindow
= parentFrame
->GetClientWindow();
429 // Remove page if still there
430 if (clientWindow
->RemovePage(this))
431 clientWindow
->Refresh();
433 // Set the selection to the first remaining page
434 if (clientWindow
->GetPageCount() > 0)
436 wxMDIChildFrame
* child
= (wxMDIChildFrame
*) clientWindow
->GetPage(0);
437 parentFrame
->SetActiveChild(child
);
438 parentFrame
->SetChildMenuBar(child
);
442 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
443 parentFrame
->SetChildMenuBar((wxMDIChildFrame
*) NULL
);
449 // Implementation: intercept and act upon raise and lower commands.
450 void wxMDIChildFrame::OnRaise()
452 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
453 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
454 parentFrame
->SetActiveChild(this);
458 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldActiveChild
->GetId());
459 event
.SetEventObject( oldActiveChild
);
460 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
463 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, this->GetId());
464 event
.SetEventObject( this );
465 this->GetEventHandler()->ProcessEvent(event
);
468 void wxMDIChildFrame::OnLower()
470 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
471 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
473 if (oldActiveChild
== this)
475 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldActiveChild
->GetId());
476 event
.SetEventObject( oldActiveChild
);
477 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
479 // TODO: unfortunately we don't now know which is the top-most child,
480 // so make the active child NULL.
481 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
485 // Set the client size (i.e. leave the calculation of borders etc.
487 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
489 wxWindow::DoSetClientSize(width
, height
);
492 void wxMDIChildFrame::DoGetClientSize(int* width
, int* height
) const
494 wxWindow::DoGetSize(width
, height
);
497 void wxMDIChildFrame::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
499 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
502 void wxMDIChildFrame::DoGetSize(int* width
, int* height
) const
504 wxWindow::DoGetSize(width
, height
);
507 void wxMDIChildFrame::DoGetPosition(int *x
, int *y
) const
509 wxWindow::DoGetPosition(x
, y
);
512 bool wxMDIChildFrame::Show(bool show
)
514 SetVisibleStatus( show
);
515 return wxWindow::Show(show
);
518 void wxMDIChildFrame::SetMenuBar(wxMenuBar
*menuBar
)
520 // Don't create the underlying menubar yet; need to recreate
521 // it every time the child is activated.
522 m_frameMenuBar
= menuBar
;
524 // We make the assumption that if you're setting the menubar,
525 // this is the currently active child.
526 GetMDIParentFrame()->SetChildMenuBar(this);
530 void wxMDIChildFrame::SetIcon(const wxIcon
& icon
)
532 m_icons
= wxIconBundle( icon
);
536 // Not appropriate since there are no icons in
541 void wxMDIChildFrame::SetIcons(const wxIconBundle
& icons
)
546 void wxMDIChildFrame::SetTitle(const wxString
& title
)
548 wxTopLevelWindow::SetTitle( title
);
549 wxMDIClientWindow
* clientWindow
= GetMDIParentFrame()->GetClientWindow();
550 int pageNo
= clientWindow
->FindPagePosition(this);
552 clientWindow
->SetPageText(pageNo
, title
);
556 void wxMDIChildFrame::Maximize()
561 void wxMDIChildFrame::Iconize(bool WXUNUSED(iconize
))
566 bool wxMDIChildFrame::IsIconized() const
571 // Is it maximized? Always maximized under Motif, using the
572 // tabbed MDI implementation.
573 bool wxMDIChildFrame::IsMaximized(void) const
578 void wxMDIChildFrame::Restore()
583 void wxMDIChildFrame::Activate()
588 void wxMDIChildFrame::CaptureMouse()
590 wxWindow::CaptureMouse();
593 void wxMDIChildFrame::ReleaseMouse()
595 wxWindow::ReleaseMouse();
598 void wxMDIChildFrame::Raise()
603 void wxMDIChildFrame::Lower(void)
608 void wxMDIChildFrame::SetSizeHints(int WXUNUSED(minW
), int WXUNUSED(minH
), int WXUNUSED(maxW
), int WXUNUSED(maxH
), int WXUNUSED(incW
), int WXUNUSED(incH
))
614 wxMDIClientWindow::wxMDIClientWindow()
618 wxMDIClientWindow::~wxMDIClientWindow()
620 // By the time this destructor is called, the child frames will have been
621 // deleted and removed from the notebook/client window.
624 m_mainWidget
= (WXWidget
) 0;
627 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
629 SetWindowStyleFlag(style
);
631 // m_windowParent = parent;
632 // m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
634 bool success
= wxNotebook::Create(parent
, wxID_NOTEBOOK_CLIENT_AREA
, wxPoint(0, 0), wxSize(100, 100), 0);
637 wxFont
font(10, wxSWISS
, wxNORMAL
, wxNORMAL
);
638 wxFont
selFont(10, wxSWISS
, wxNORMAL
, wxBOLD
);
639 GetTabView()->SetTabFont(font
);
640 GetTabView()->SetSelectedTabFont(selFont
);
641 GetTabView()->SetTabSize(120, 18);
642 GetTabView()->SetTabSelectionHeight(20);
649 void wxMDIClientWindow::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
651 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
654 void wxMDIClientWindow::DoSetClientSize(int width
, int height
)
656 wxWindow::DoSetClientSize(width
, height
);
659 void wxMDIClientWindow::DoGetClientSize(int *width
, int *height
) const
661 wxWindow::DoGetClientSize(width
, height
);
664 void wxMDIClientWindow::DoGetSize(int *width
, int *height
) const
666 wxWindow::DoGetSize(width
, height
);
669 void wxMDIClientWindow::DoGetPosition(int *x
, int *y
) const
671 wxWindow::DoGetPosition(x
, y
);
674 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
)
676 // Default(); // Default processing: OBSOLETE FUNCTION
680 void wxMDIClientWindow::OnPageChanged(wxNotebookEvent
& event
)
682 // Notify child that it has been activated
683 if (event
.GetOldSelection() != -1)
685 wxMDIChildFrame
* oldChild
= (wxMDIChildFrame
*) GetPage(event
.GetOldSelection());
688 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldChild
->GetId());
689 event
.SetEventObject( oldChild
);
690 oldChild
->GetEventHandler()->ProcessEvent(event
);
693 if (event
.GetSelection() != -1)
695 wxMDIChildFrame
* activeChild
= (wxMDIChildFrame
*) GetPage(event
.GetSelection());
698 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, activeChild
->GetId());
699 event
.SetEventObject( activeChild
);
700 activeChild
->GetEventHandler()->ProcessEvent(event
);
702 if (activeChild
->GetMDIParentFrame())
704 activeChild
->GetMDIParentFrame()->SetActiveChild(activeChild
);
705 activeChild
->GetMDIParentFrame()->SetChildMenuBar(activeChild
);