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 extern wxWindowList wxModelessWindows
; 
  30 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
) 
  31 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
) 
  32 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
) 
  34 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
) 
  35     EVT_ACTIVATE(wxMDIParentFrame::OnActivate
) 
  36     EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
) 
  39 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxWindow
) 
  40     EVT_SCROLL(wxMDIClientWindow::OnScroll
) 
  43 static const wxChar 
*TRACE_MDI 
= _T("mdi"); 
  45 static const int IDM_WINDOWTILEHOR  
= 4001; 
  46 static const int IDM_WINDOWCASCADE 
= 4002; 
  47 static const int IDM_WINDOWICONS 
= 4003; 
  48 static const int IDM_WINDOWNEXT 
= 4004; 
  49 static const int IDM_WINDOWTILEVERT 
= 4005; 
  51 // ---------------------------------------------------------------------------- 
  53 // ---------------------------------------------------------------------------- 
  55 void wxMDIParentFrame::Init() 
  57     m_clientWindow 
= NULL
; 
  58     m_currentChild 
= NULL
; 
  59     m_windowMenu 
= (wxMenu
*) NULL
; 
  60     m_parentFrameActive 
= true; 
  61     m_shouldBeShown 
= false; 
  64 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
  66     const wxString
& title
, 
  72     // this style can be used to prevent a window from having the standard MDI 
  74     if ( style 
& wxFRAME_NO_WINDOW_MENU 
) 
  76         m_windowMenu 
= (wxMenu 
*)NULL
; 
  77         style 
-= wxFRAME_NO_WINDOW_MENU 
; 
  79     else // normal case: we have the window menu, so construct it 
  81         m_windowMenu 
= new wxMenu
; 
  83         m_windowMenu
->Append(IDM_WINDOWCASCADE
, wxT("&Cascade")); 
  84         m_windowMenu
->Append(IDM_WINDOWTILEHOR
, wxT("Tile &Horizontally")); 
  85         m_windowMenu
->Append(IDM_WINDOWTILEVERT
, wxT("Tile &Vertically")); 
  86         m_windowMenu
->AppendSeparator(); 
  87         m_windowMenu
->Append(IDM_WINDOWICONS
, wxT("&Arrange Icons")); 
  88         m_windowMenu
->Append(IDM_WINDOWNEXT
, wxT("&Next")); 
  91     wxFrame::Create( parent 
, id 
, title 
, pos 
, size 
, style 
, name 
) ; 
  92     m_parentFrameActive 
= true; 
  99 wxMDIParentFrame::~wxMDIParentFrame() 
 103     // already deleted by DestroyChildren() 
 104     m_clientWindow 
= NULL 
; 
 109 void wxMDIParentFrame::SetMenuBar(wxMenuBar 
*menu_bar
) 
 111     wxFrame::SetMenuBar( menu_bar 
) ; 
 114 void wxMDIParentFrame::GetRectForTopLevelChildren(int *x
, int *y
, int *w
, int *h
) 
 124 void wxMDIParentFrame::AddChild(wxWindowBase 
*child
) 
 126     // moved this to front, so that we don't run into unset m_parent problems later 
 127     wxFrame::AddChild(child
); 
 129     if ( !m_currentChild 
) 
 131         m_currentChild 
= wxDynamicCast(child
, wxMDIChildFrame
); 
 133         if ( m_currentChild 
&& IsShown() && !ShouldBeVisible() ) 
 135             // we shouldn't remain visible any more 
 136             wxFrame::Show(false); 
 137             m_shouldBeShown 
= true; 
 142 void wxMDIParentFrame::RemoveChild(wxWindowBase 
*child
) 
 144     if ( child 
== m_currentChild 
) 
 146         // the current child isn't active any more, try to find another one 
 147         m_currentChild 
= NULL
; 
 149         for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 151               node 
= node
->GetNext() ) 
 154                 childCur 
= wxDynamicCast(node
->GetData(), wxMDIChildFrame
); 
 155             if ( childCur 
!= child 
) 
 157                 m_currentChild 
= childCur
; 
 163     wxFrame::RemoveChild(child
); 
 165     // if there are no more children left we need to show the frame if we 
 166     // hadn't shown it before because there were active children and it was 
 167     // useless (note that we have to do it after fully removing the child, i.e. 
 168     // after calling the base class RemoveChild() as otherwise we risk to touch 
 169     // pointer to the child being deleted) 
 170     if ( !m_currentChild 
&& m_shouldBeShown 
&& !IsShown() ) 
 172         // we have to show it, but at least move it out of sight and make it of 
 173         // smallest possible size (unfortunately (0, 0) doesn't work so that it 
 174         // doesn't appear in expose 
 175         SetSize(-10000, -10000, 1, 1); 
 180 void wxMDIParentFrame::MacActivate(long timestamp
, bool activating
) 
 182     wxLogTrace(TRACE_MDI
, wxT("MDI PARENT=%p MacActivate(0x%08lx,%s)"), this, timestamp
, activating 
? wxT("ACTIV") : wxT("deact")); 
 186         if (s_macDeactivateWindow 
&& s_macDeactivateWindow
->GetParent() == this) 
 188             wxLogTrace(TRACE_MDI
, wxT("child had been scheduled for deactivation, rehighlighting")); 
 190             UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->MacGetWindowRef(), true); 
 192             wxLogTrace(TRACE_MDI
, wxT("finished highliting child")); 
 194             s_macDeactivateWindow 
= NULL
; 
 196         else if (s_macDeactivateWindow 
== this) 
 198             wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"), this); 
 200             s_macDeactivateWindow 
= NULL
; 
 202         else // window to deactivate is NULL or is not us or one of our kids 
 204             // activate kid instead 
 206                 m_currentChild
->MacActivate(timestamp
, activating
); 
 208                 wxFrame::MacActivate(timestamp
, activating
); 
 213         // We were scheduled for deactivation, and now we do it. 
 214         if (s_macDeactivateWindow 
== this) 
 216             s_macDeactivateWindow 
= NULL
; 
 218                 m_currentChild
->MacActivate(timestamp
, activating
); 
 219             wxFrame::MacActivate(timestamp
, activating
); 
 221         else // schedule ourselves for deactivation 
 223             if (s_macDeactivateWindow
) 
 224                 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow
); 
 225             wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed MDI Parent deactivation")); 
 227             s_macDeactivateWindow 
= this; 
 232 void wxMDIParentFrame::OnActivate(wxActivateEvent
& event
) 
 237 // Returns the active MDI child window 
 238 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 240     return m_currentChild 
; 
 243 // Create the client window class (don't Create the window, 
 244 // just return a new class) 
 245 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 247     m_clientWindow 
= new wxMDIClientWindow( this ); 
 249     return m_clientWindow
; 
 252 // Responds to colour changes, and passes event on to children. 
 253 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
 257     // Propagate the event to the non-top-level children 
 258     wxFrame::OnSysColourChanged(event
); 
 262 void wxMDIParentFrame::Cascade() 
 267 void wxMDIParentFrame::Tile(wxOrientation 
WXUNUSED(orient
)) 
 272 void wxMDIParentFrame::ArrangeIcons() 
 277 void wxMDIParentFrame::ActivateNext() 
 282 void wxMDIParentFrame::ActivatePrevious() 
 287 bool wxMDIParentFrame::ShouldBeVisible() const 
 289     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 291           node 
= node
->GetNext() ) 
 293         wxWindow 
*win 
= node
->GetData(); 
 296                 && !wxDynamicCast(win
, wxMDIChildFrame
) 
 298                 && win 
!= (wxWindow
*) GetStatusBar() 
 300                 && win 
!= GetClientWindow() ) 
 302             // if we have a non-MDI child, do remain visible so that it could 
 311 bool wxMDIParentFrame::Show( bool show 
) 
 313     m_shouldBeShown 
= false; 
 315     // don't really show the MDI frame unless it has any children other than 
 316     // MDI children as it is pretty useless in this case 
 320         if ( !ShouldBeVisible() && m_currentChild 
) 
 322             // don't make the window visible now but remember that we should 
 324             m_shouldBeShown 
= true; 
 330     return wxFrame::Show(show
); 
 333 // ---------------------------------------------------------------------------- 
 335 // ---------------------------------------------------------------------------- 
 337 wxMDIChildFrame::wxMDIChildFrame() 
 341 void wxMDIChildFrame::Init() 
 345 bool wxMDIChildFrame::Create(wxMDIParentFrame 
*parent
, 
 347                              const wxString
& title
, 
 351                              const wxString
& name
) 
 355     if ( id 
== wxID_ANY 
) 
 356         m_windowId 
= (int)NewControlId(); 
 361         parent
->AddChild(this); 
 363     MacCreateRealWindow( title
, pos 
, size 
, MacRemoveBordersFromStyle(style
) , name 
) ; 
 365     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
)); 
 367     wxModelessWindows
.Append(this); 
 372 wxMDIChildFrame::~wxMDIChildFrame() 
 377 void wxMDIChildFrame::SetMenuBar(wxMenuBar 
*menu_bar
) 
 379     return wxFrame::SetMenuBar( menu_bar 
) ; 
 382 void wxMDIChildFrame::MacActivate(long timestamp
, bool activating
) 
 384     wxLogTrace(TRACE_MDI
, wxT("MDI child=%p  MacActivate(0x%08lx,%s)"),this, timestamp
, activating 
? wxT("ACTIV") : wxT("deact")); 
 386     wxMDIParentFrame 
*mdiparent 
= wxDynamicCast(m_parent
, wxMDIParentFrame
); 
 391         if (s_macDeactivateWindow 
== m_parent
) 
 393             wxLogTrace(TRACE_MDI
, wxT("parent had been scheduled for deactivation, rehighlighting")); 
 395             UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->MacGetWindowRef(), true); 
 397             wxLogTrace(TRACE_MDI
, wxT("finished highliting parent")); 
 399             s_macDeactivateWindow 
= NULL
; 
 401         else if ((mdiparent
->m_currentChild 
== this) || !s_macDeactivateWindow
) 
 402             mdiparent
->wxFrame::MacActivate(timestamp
, activating
); 
 404         if (mdiparent
->m_currentChild 
&& mdiparent
->m_currentChild 
!= this) 
 405             mdiparent
->m_currentChild
->wxFrame::MacActivate(timestamp
, false); 
 406         mdiparent
->m_currentChild 
= this; 
 408         if (s_macDeactivateWindow 
== this) 
 410             wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"), this); 
 412             s_macDeactivateWindow 
= NULL
; 
 415             wxFrame::MacActivate(timestamp
, activating
); 
 419         // We were scheduled for deactivation, and now we do it. 
 420         if (s_macDeactivateWindow 
== this) 
 422             s_macDeactivateWindow 
= NULL
; 
 423             wxFrame::MacActivate(timestamp
, activating
); 
 424             if (mdiparent
->m_currentChild 
== this) 
 425                 mdiparent
->wxFrame::MacActivate(timestamp
, activating
); 
 427         else // schedule ourselves for deactivation 
 429             if (s_macDeactivateWindow
) 
 430                 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow
); 
 431             wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed deactivation")); 
 433             s_macDeactivateWindow 
= this; 
 439 void wxMDIChildFrame::Maximize() 
 441     wxFrame::Maximize() ; 
 444 void wxMDIChildFrame::Restore() 
 449 void wxMDIChildFrame::Activate() 
 453 //----------------------------------------------------------------------------- 
 455 //----------------------------------------------------------------------------- 
 457 wxMDIClientWindow::wxMDIClientWindow() 
 461 wxMDIClientWindow::~wxMDIClientWindow() 
 466 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame 
*parent
, long style
) 
 468     if ( !wxWindow::Create(parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
) ) 
 471     wxModelessWindows
.Append(this); 
 476 // Get size *available for subwindows* i.e. excluding menu bar. 
 477 void wxMDIClientWindow::DoGetClientSize(int *x
, int *y
) const 
 479     wxDisplaySize( x 
, y 
) ; 
 482 // Explicitly call default scroll behaviour 
 483 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
)