1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/mdi.cpp
3 // Purpose: MDI classes
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
21 #include "wx/settings.h"
22 #include "wx/statusbr.h"
25 #include "wx/mac/private.h"
26 #include "wx/mac/uma.h"
28 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
29 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
30 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
)
32 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
33 EVT_ACTIVATE(wxMDIParentFrame::OnActivate
)
34 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
37 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxWindow
)
38 EVT_SCROLL(wxMDIClientWindow::OnScroll
)
41 #define TRACE_MDI "mdi"
43 static const int IDM_WINDOWTILEHOR
= 4001;
44 static const int IDM_WINDOWCASCADE
= 4002;
45 static const int IDM_WINDOWICONS
= 4003;
46 static const int IDM_WINDOWNEXT
= 4004;
47 static const int IDM_WINDOWTILEVERT
= 4005;
51 void UMAHighlightAndActivateWindow( WindowRef inWindowRef
, bool inActivate
)
56 // bool isHighlighted = IsWindowHighlited( inWindowRef ) ;
57 // if ( inActivate != isHighlighted )
61 SetPortWindowPort( inWindowRef
) ;
63 HiliteWindow( inWindowRef
, inActivate
) ;
64 ControlRef control
= NULL
;
65 ::GetRootControl( inWindowRef
, &control
) ;
69 ::ActivateControl( control
) ;
71 ::DeactivateControl( control
) ;
80 // ----------------------------------------------------------------------------
82 // ----------------------------------------------------------------------------
84 void wxMDIParentFrame::Init()
86 m_clientWindow
= NULL
;
87 m_currentChild
= NULL
;
88 m_windowMenu
= (wxMenu
*) NULL
;
89 m_parentFrameActive
= true;
90 m_shouldBeShown
= false;
93 bool wxMDIParentFrame::Create(wxWindow
*parent
,
95 const wxString
& title
,
101 // this style can be used to prevent a window from having the standard MDI
103 if ( style
& wxFRAME_NO_WINDOW_MENU
)
105 m_windowMenu
= (wxMenu
*)NULL
;
106 style
-= wxFRAME_NO_WINDOW_MENU
;
108 else // normal case: we have the window menu, so construct it
110 m_windowMenu
= new wxMenu
;
112 m_windowMenu
->Append(IDM_WINDOWCASCADE
, wxT("&Cascade"));
113 m_windowMenu
->Append(IDM_WINDOWTILEHOR
, wxT("Tile &Horizontally"));
114 m_windowMenu
->Append(IDM_WINDOWTILEVERT
, wxT("Tile &Vertically"));
115 m_windowMenu
->AppendSeparator();
116 m_windowMenu
->Append(IDM_WINDOWICONS
, wxT("&Arrange Icons"));
117 m_windowMenu
->Append(IDM_WINDOWNEXT
, wxT("&Next"));
120 if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) )
123 m_parentFrameActive
= true;
125 m_clientWindow
= OnCreateClient();
127 return m_clientWindow
!= NULL
;
130 wxMDIParentFrame::~wxMDIParentFrame()
134 // already deleted by DestroyChildren()
135 m_clientWindow
= NULL
;
140 void wxMDIParentFrame::SetMenuBar(wxMenuBar
*menu_bar
)
142 wxFrame::SetMenuBar( menu_bar
) ;
145 void wxMDIParentFrame::GetRectForTopLevelChildren(int *x
, int *y
, int *w
, int *h
)
155 void wxMDIParentFrame::AddChild(wxWindowBase
*child
)
157 // moved this to front, so that we don't run into unset m_parent problems later
158 wxFrame::AddChild(child
);
160 if ( !m_currentChild
)
162 m_currentChild
= wxDynamicCast(child
, wxMDIChildFrame
);
164 if ( m_currentChild
&& IsShown() && !ShouldBeVisible() )
166 // we shouldn't remain visible any more
167 wxFrame::Show(false);
168 m_shouldBeShown
= true;
173 void wxMDIParentFrame::RemoveChild(wxWindowBase
*child
)
175 if ( child
== m_currentChild
)
177 // the current child isn't active any more, try to find another one
178 m_currentChild
= NULL
;
180 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
182 node
= node
->GetNext() )
185 childCur
= wxDynamicCast(node
->GetData(), wxMDIChildFrame
);
186 if ( childCur
!= child
)
188 m_currentChild
= childCur
;
194 wxFrame::RemoveChild(child
);
196 // if there are no more children left we need to show the frame if we
197 // hadn't shown it before because there were active children and it was
198 // useless (note that we have to do it after fully removing the child, i.e.
199 // after calling the base class RemoveChild() as otherwise we risk to touch
200 // pointer to the child being deleted)
201 if ( !m_currentChild
&& m_shouldBeShown
&& !IsShown() )
203 // we have to show it, but at least move it out of sight and make it of
204 // smallest possible size (unfortunately (0, 0) doesn't work so that it
205 // doesn't appear in expose
206 SetSize(-10000, -10000, 1, 1);
211 void wxMDIParentFrame::MacActivate(long timestamp
, bool activating
)
213 wxLogTrace(TRACE_MDI
, wxT("MDI PARENT=%p MacActivate(0x%08lx,%s)"), this, timestamp
, activating
? wxT("ACTIV") : wxT("deact"));
217 if (s_macDeactivateWindow
&& s_macDeactivateWindow
->GetParent() == this)
219 wxLogTrace(TRACE_MDI
, wxT("child had been scheduled for deactivation, rehighlighting"));
221 UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->MacGetWindowRef(), true);
223 wxLogTrace(TRACE_MDI
, wxT("finished highliting child"));
225 s_macDeactivateWindow
= NULL
;
227 else if (s_macDeactivateWindow
== this)
229 wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"), this);
231 s_macDeactivateWindow
= NULL
;
233 else // window to deactivate is NULL or is not us or one of our kids
235 // activate kid instead
237 m_currentChild
->MacActivate(timestamp
, activating
);
239 wxFrame::MacActivate(timestamp
, activating
);
244 // We were scheduled for deactivation, and now we do it.
245 if (s_macDeactivateWindow
== this)
247 s_macDeactivateWindow
= NULL
;
249 m_currentChild
->MacActivate(timestamp
, activating
);
250 wxFrame::MacActivate(timestamp
, activating
);
252 else // schedule ourselves for deactivation
254 if (s_macDeactivateWindow
)
255 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow
);
256 wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed MDI Parent deactivation"));
258 s_macDeactivateWindow
= this;
263 void wxMDIParentFrame::OnActivate(wxActivateEvent
& event
)
268 // Returns the active MDI child window
269 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
271 return m_currentChild
;
274 // Create the client window class (don't Create the window,
275 // just return a new class)
276 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
278 return new wxMDIClientWindow( this );
281 // Responds to colour changes, and passes event on to children.
282 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
286 // Propagate the event to the non-top-level children
287 wxFrame::OnSysColourChanged(event
);
291 void wxMDIParentFrame::Cascade()
296 void wxMDIParentFrame::Tile(wxOrientation
WXUNUSED(orient
))
301 void wxMDIParentFrame::ArrangeIcons()
306 void wxMDIParentFrame::ActivateNext()
311 void wxMDIParentFrame::ActivatePrevious()
316 bool wxMDIParentFrame::ShouldBeVisible() const
318 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
320 node
= node
->GetNext() )
322 wxWindow
*win
= node
->GetData();
325 && !wxDynamicCast(win
, wxMDIChildFrame
)
327 && win
!= (wxWindow
*) GetStatusBar()
329 && win
!= GetClientWindow() )
331 // if we have a non-MDI child, do remain visible so that it could
340 bool wxMDIParentFrame::Show( bool show
)
342 m_shouldBeShown
= false;
344 // don't really show the MDI frame unless it has any children other than
345 // MDI children as it is pretty useless in this case
349 if ( !ShouldBeVisible() && m_currentChild
)
351 // don't make the window visible now but remember that we should
353 m_shouldBeShown
= true;
359 return wxFrame::Show(show
);
362 // ----------------------------------------------------------------------------
364 // ----------------------------------------------------------------------------
366 wxMDIChildFrame::wxMDIChildFrame()
370 void wxMDIChildFrame::Init()
374 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
376 const wxString
& title
,
380 const wxString
& name
)
384 if ( id
== wxID_ANY
)
385 m_windowId
= (int)NewControlId();
390 parent
->AddChild(this);
392 MacCreateRealWindow( pos
, size
, MacRemoveBordersFromStyle(style
) , name
) ;
395 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
));
400 wxMDIChildFrame::~wxMDIChildFrame()
405 void wxMDIChildFrame::SetMenuBar(wxMenuBar
*menu_bar
)
407 return wxFrame::SetMenuBar( menu_bar
) ;
410 void wxMDIChildFrame::MacActivate(long timestamp
, bool activating
)
412 wxLogTrace(TRACE_MDI
, wxT("MDI child=%p MacActivate(0x%08lx,%s)"),this, timestamp
, activating
? wxT("ACTIV") : wxT("deact"));
414 wxMDIParentFrame
*mdiparent
= wxDynamicCast(m_parent
, wxMDIParentFrame
);
419 if (s_macDeactivateWindow
== m_parent
)
421 wxLogTrace(TRACE_MDI
, wxT("parent had been scheduled for deactivation, rehighlighting"));
423 UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->MacGetWindowRef(), true);
425 wxLogTrace(TRACE_MDI
, wxT("finished highliting parent"));
427 s_macDeactivateWindow
= NULL
;
429 else if ((mdiparent
->m_currentChild
== this) || !s_macDeactivateWindow
)
430 mdiparent
->wxFrame::MacActivate(timestamp
, activating
);
432 if (mdiparent
->m_currentChild
&& mdiparent
->m_currentChild
!= this)
433 mdiparent
->m_currentChild
->wxFrame::MacActivate(timestamp
, false);
434 mdiparent
->m_currentChild
= this;
436 if (s_macDeactivateWindow
== this)
438 wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"), this);
440 s_macDeactivateWindow
= NULL
;
443 wxFrame::MacActivate(timestamp
, activating
);
447 // We were scheduled for deactivation, and now we do it.
448 if (s_macDeactivateWindow
== this)
450 s_macDeactivateWindow
= NULL
;
451 wxFrame::MacActivate(timestamp
, activating
);
452 if (mdiparent
->m_currentChild
== this)
453 mdiparent
->wxFrame::MacActivate(timestamp
, activating
);
455 else // schedule ourselves for deactivation
457 if (s_macDeactivateWindow
)
458 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow
);
459 wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed deactivation"));
461 s_macDeactivateWindow
= this;
467 void wxMDIChildFrame::Maximize()
469 wxFrame::Maximize() ;
472 void wxMDIChildFrame::Restore()
477 void wxMDIChildFrame::Activate()
481 //-----------------------------------------------------------------------------
483 //-----------------------------------------------------------------------------
485 wxMDIClientWindow::wxMDIClientWindow()
489 wxMDIClientWindow::~wxMDIClientWindow()
494 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
496 if ( !wxWindow::Create(parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
) )
502 // Get size *available for subwindows* i.e. excluding menu bar.
503 void wxMDIClientWindow::DoGetClientSize(int *x
, int *y
) const
505 wxDisplaySize( x
, y
) ;
508 // Explicitly call default scroll behaviour
509 void wxMDIClientWindow::OnScroll(wxScrollEvent
& WXUNUSED(event
))