1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/mdi.cpp
3 // Purpose: MDI classes
4 // Author: Stefan Csomor
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
20 #include "wx/settings.h"
21 #include "wx/statusbr.h"
24 #include "wx/osx/private.h"
25 #include "wx/osx/uma.h"
27 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
28 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
29 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
)
31 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
32 EVT_ACTIVATE(wxMDIParentFrame::OnActivate
)
33 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
36 #define TRACE_MDI "mdi"
38 static const int IDM_WINDOWTILEHOR
= 4001;
39 static const int IDM_WINDOWCASCADE
= 4002;
40 static const int IDM_WINDOWICONS
= 4003;
41 static const int IDM_WINDOWNEXT
= 4004;
42 static const int IDM_WINDOWTILEVERT
= 4005;
46 void UMAHighlightAndActivateWindow( WindowRef inWindowRef
, bool inActivate
)
48 #if wxOSX_USE_CARBON // TODO REMOVE
51 // bool isHighlighted = IsWindowHighlited( inWindowRef ) ;
52 // if ( inActivate != isHighlighted )
56 SetPortWindowPort( inWindowRef
) ;
58 HiliteWindow( inWindowRef
, inActivate
) ;
59 ControlRef control
= NULL
;
60 ::GetRootControl( inWindowRef
, &control
) ;
64 ::ActivateControl( control
) ;
66 ::DeactivateControl( control
) ;
72 #elif defined(wxOSX_USE_COCOA)
73 wxUnusedVar(inActivate
);
74 wxUnusedVar(inWindowRef
);
75 // TODO: implement me!
79 // ----------------------------------------------------------------------------
81 // ----------------------------------------------------------------------------
83 void wxMDIParentFrame::Init()
85 m_parentFrameActive
= true;
86 m_shouldBeShown
= false;
89 bool wxMDIParentFrame::Create(wxWindow
*parent
,
91 const wxString
& title
,
97 // this style can be used to prevent a window from having the standard MDI
99 if ( style
& wxFRAME_NO_WINDOW_MENU
)
102 style
-= wxFRAME_NO_WINDOW_MENU
;
104 else // normal case: we have the window menu, so construct it
106 m_windowMenu
= new wxMenu
;
108 m_windowMenu
->Append(IDM_WINDOWCASCADE
, wxT("&Cascade"));
109 m_windowMenu
->Append(IDM_WINDOWTILEHOR
, wxT("Tile &Horizontally"));
110 m_windowMenu
->Append(IDM_WINDOWTILEVERT
, wxT("Tile &Vertically"));
111 m_windowMenu
->AppendSeparator();
112 m_windowMenu
->Append(IDM_WINDOWICONS
, wxT("&Arrange Icons"));
113 m_windowMenu
->Append(IDM_WINDOWNEXT
, wxT("&Next"));
116 if ( !wxFrame::Create( parent
, winid
, title
, pos
, size
, style
, name
) )
119 m_parentFrameActive
= true;
121 m_clientWindow
= OnCreateClient();
122 if ( !m_clientWindow
|| !m_clientWindow
->CreateClient(this, style
) )
128 wxMDIParentFrame::~wxMDIParentFrame()
132 // already deleted by DestroyChildren()
133 m_clientWindow
= NULL
;
136 void wxMDIParentFrame::SetMenuBar(wxMenuBar
*menu_bar
)
138 wxFrame::SetMenuBar( menu_bar
) ;
141 void wxMDIParentFrame::GetRectForTopLevelChildren(int *x
, int *y
, int *w
, int *h
)
151 void wxMDIParentFrame::AddChild(wxWindowBase
*child
)
153 // moved this to front, so that we don't run into unset m_parent problems later
154 wxFrame::AddChild(child
);
156 if ( !m_currentChild
)
158 m_currentChild
= wxDynamicCast(child
, wxMDIChildFrame
);
160 if ( m_currentChild
&& IsShown() && !ShouldBeVisible() )
162 // we shouldn't remain visible any more
163 wxFrame::Show(false);
164 m_shouldBeShown
= true;
169 void wxMDIParentFrame::RemoveChild(wxWindowBase
*child
)
171 if ( child
== m_currentChild
)
173 // the current child isn't active any more, try to find another one
174 m_currentChild
= NULL
;
176 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
178 node
= node
->GetNext() )
181 childCur
= wxDynamicCast(node
->GetData(), wxMDIChildFrame
);
182 if ( childCur
!= child
)
184 m_currentChild
= childCur
;
190 wxFrame::RemoveChild(child
);
192 // if there are no more children left we need to show the frame if we
193 // hadn't shown it before because there were active children and it was
194 // useless (note that we have to do it after fully removing the child, i.e.
195 // after calling the base class RemoveChild() as otherwise we risk to touch
196 // pointer to the child being deleted)
197 if ( !m_currentChild
&& m_shouldBeShown
&& !IsShown() )
199 // we have to show it, but at least move it out of sight and make it of
200 // smallest possible size (unfortunately (0, 0) doesn't work so that it
201 // doesn't appear in expose
202 SetSize(-10000, -10000, 1, 1);
207 void wxMDIParentFrame::MacActivate(long timestamp
, bool activating
)
209 wxLogTrace(TRACE_MDI
, wxT("MDI PARENT=%p MacActivate(0x%08lx,%s)"), this, timestamp
, activating
? wxT("ACTIV") : wxT("deact"));
213 if (s_macDeactivateWindow
&& s_macDeactivateWindow
->GetParent() == this)
215 wxLogTrace(TRACE_MDI
, wxT("child had been scheduled for deactivation, rehighlighting"));
217 UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->GetWXWindow(), true);
219 wxLogTrace(TRACE_MDI
, wxT("finished highliting child"));
221 s_macDeactivateWindow
= NULL
;
223 else if (s_macDeactivateWindow
== this)
225 wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"), this);
227 s_macDeactivateWindow
= NULL
;
229 else // window to deactivate is NULL or is not us or one of our kids
231 // activate kid instead
233 m_currentChild
->MacActivate(timestamp
, activating
);
235 wxFrame::MacActivate(timestamp
, activating
);
240 // We were scheduled for deactivation, and now we do it.
241 if (s_macDeactivateWindow
== this)
243 s_macDeactivateWindow
= NULL
;
245 m_currentChild
->MacActivate(timestamp
, activating
);
246 wxFrame::MacActivate(timestamp
, activating
);
248 else // schedule ourselves for deactivation
250 if (s_macDeactivateWindow
)
252 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow
);
254 wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed MDI Parent deactivation"));
256 s_macDeactivateWindow
= this;
261 void wxMDIParentFrame::OnActivate(wxActivateEvent
& event
)
266 // Responds to colour changes, and passes event on to children.
267 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
271 // Propagate the event to the non-top-level children
272 wxFrame::OnSysColourChanged(event
);
275 bool wxMDIParentFrame::ShouldBeVisible() const
277 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
279 node
= node
->GetNext() )
281 wxWindow
*win
= node
->GetData();
284 && !wxDynamicCast(win
, wxMDIChildFrame
)
286 && win
!= (wxWindow
*) GetStatusBar()
288 && win
!= GetClientWindow() )
290 // if we have a non-MDI child, do remain visible so that it could
299 bool wxMDIParentFrame::Show( bool show
)
301 m_shouldBeShown
= false;
303 // don't really show the MDI frame unless it has any children other than
304 // MDI children as it is pretty useless in this case
308 if ( !ShouldBeVisible() && m_currentChild
)
310 // don't make the window visible now but remember that we should
312 m_shouldBeShown
= true;
318 return wxFrame::Show(show
);
321 // ----------------------------------------------------------------------------
323 // ----------------------------------------------------------------------------
325 void wxMDIChildFrame::Init()
329 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
331 const wxString
& title
,
335 const wxString
& name
)
337 m_mdiParent
= parent
;
341 if ( winid
== wxID_ANY
)
342 winid
= (int)NewControlId();
344 wxNonOwnedWindow::Create( parent
, winid
, pos
, size
, MacRemoveBordersFromStyle(style
) , name
) ;
348 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
));
353 wxMDIChildFrame::~wxMDIChildFrame()
358 void wxMDIChildFrame::MacActivate(long timestamp
, bool activating
)
360 wxLogTrace(TRACE_MDI
, wxT("MDI child=%p MacActivate(0x%08lx,%s)"),this, timestamp
, activating
? wxT("ACTIV") : wxT("deact"));
362 wxMDIParentFrame
*mdiparent
= m_mdiParent
;
367 if (s_macDeactivateWindow
== m_parent
)
369 wxLogTrace(TRACE_MDI
, wxT("parent had been scheduled for deactivation, rehighlighting"));
371 UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->GetWXWindow(), true);
373 wxLogTrace(TRACE_MDI
, wxT("finished highliting parent"));
375 s_macDeactivateWindow
= NULL
;
377 else if ((mdiparent
->m_currentChild
== this) || !s_macDeactivateWindow
)
378 mdiparent
->wxFrame::MacActivate(timestamp
, activating
);
380 if (mdiparent
->m_currentChild
&& mdiparent
->m_currentChild
!= this)
381 mdiparent
->m_currentChild
->wxFrame::MacActivate(timestamp
, false);
382 mdiparent
->m_currentChild
= this;
384 if (s_macDeactivateWindow
== this)
386 wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"), this);
388 s_macDeactivateWindow
= NULL
;
391 wxFrame::MacActivate(timestamp
, activating
);
395 // We were scheduled for deactivation, and now we do it.
396 if (s_macDeactivateWindow
== this)
398 s_macDeactivateWindow
= NULL
;
399 wxFrame::MacActivate(timestamp
, activating
);
400 if (mdiparent
->m_currentChild
== this)
401 mdiparent
->wxFrame::MacActivate(timestamp
, activating
);
403 else // schedule ourselves for deactivation
405 if (s_macDeactivateWindow
)
407 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow
);
409 wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed deactivation"));
411 s_macDeactivateWindow
= this;
417 void wxMDIChildFrame::Activate()
419 // The base class method calls Activate() so skip it to avoid infinite
420 // recursion and go directly to the real Raise() implementation.
424 //-----------------------------------------------------------------------------
426 //-----------------------------------------------------------------------------
428 wxMDIClientWindow::~wxMDIClientWindow()
433 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
435 if ( !wxWindow::Create(parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
) )
441 void wxMDIClientWindow::DoGetClientSize(int *x
, int *y
) const
443 wxDisplaySize( x
, y
) ;