X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e40298d54ecd5b109222a7c60aa2ef084a304d69..115563867dac8edf57b6d2c6ae95910c7f277d77:/src/mac/carbon/mdi.cpp diff --git a/src/mac/carbon/mdi.cpp b/src/mac/carbon/mdi.cpp index 1d9e43f170..324c8b22bb 100644 --- a/src/mac/carbon/mdi.cpp +++ b/src/mac/carbon/mdi.cpp @@ -1,79 +1,74 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: mdi.cpp +// Name: src/mac/carbon/mdi.cpp // Purpose: MDI classes // Author: Stefan Csomor // Modified by: // Created: 1998-01-01 // RCS-ID: $Id$ // Copyright: (c) Stefan Csomor -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "mdi.h" -#endif +#include "wx/wxprec.h" + +#if wxUSE_MDI #include "wx/mdi.h" -#include "wx/menu.h" -#include "wx/settings.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/menu.h" + #include "wx/settings.h" + #include "wx/statusbr.h" +#endif #include "wx/mac/private.h" +#include "wx/mac/uma.h" extern wxWindowList wxModelessWindows; -#if !USE_SHARED_LIBRARY IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame) IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame) IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow) BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame) - EVT_SIZE(wxMDIParentFrame::OnSize) - EVT_ACTIVATE(wxMDIParentFrame::OnActivate) - EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged) + EVT_ACTIVATE(wxMDIParentFrame::OnActivate) + EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged) END_EVENT_TABLE() BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow) - EVT_SCROLL(wxMDIClientWindow::OnScroll) + EVT_SCROLL(wxMDIClientWindow::OnScroll) END_EVENT_TABLE() -#endif +static const wxChar *TRACE_MDI = _T("mdi"); -static const int IDM_WINDOWTILE = 4001; static const int IDM_WINDOWTILEHOR = 4001; static const int IDM_WINDOWCASCADE = 4002; static const int IDM_WINDOWICONS = 4003; static const int IDM_WINDOWNEXT = 4004; static const int IDM_WINDOWTILEVERT = 4005; -static const int IDM_WINDOWPREV = 4006; - -// This range gives a maximum of 500 MDI children. Should be enough :-) -static const int wxFIRST_MDI_CHILD = 4100; -static const int wxLAST_MDI_CHILD = 4600; - -// Status border dimensions -static const int wxTHICK_LINE_BORDER = 3; +// ---------------------------------------------------------------------------- // Parent frame +// ---------------------------------------------------------------------------- -wxMDIParentFrame::wxMDIParentFrame() +void wxMDIParentFrame::Init() { m_clientWindow = NULL; m_currentChild = NULL; m_windowMenu = (wxMenu*) NULL; - m_parentFrameActive = TRUE; + m_parentFrameActive = true; + m_shouldBeShown = false; } bool wxMDIParentFrame::Create(wxWindow *parent, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) { - m_clientWindow = NULL; - m_currentChild = NULL; - // this style can be used to prevent a window from having the standard MDI // "Window" menu if ( style & wxFRAME_NO_WINDOW_MENU ) @@ -84,7 +79,7 @@ bool wxMDIParentFrame::Create(wxWindow *parent, else // normal case: we have the window menu, so construct it { m_windowMenu = new wxMenu; - + m_windowMenu->Append(IDM_WINDOWCASCADE, wxT("&Cascade")); m_windowMenu->Append(IDM_WINDOWTILEHOR, wxT("Tile &Horizontally")); m_windowMenu->Append(IDM_WINDOWTILEVERT, wxT("Tile &Vertically")); @@ -92,81 +87,153 @@ bool wxMDIParentFrame::Create(wxWindow *parent, m_windowMenu->Append(IDM_WINDOWICONS, wxT("&Arrange Icons")); m_windowMenu->Append(IDM_WINDOWNEXT, wxT("&Next")); } - - wxFrame::Create( parent , id , title , wxPoint( 2000 , 2000 ) , size , style , name ) ; - m_parentFrameActive = TRUE; - + + wxFrame::Create( parent , id , title , pos , size , style , name ) ; + m_parentFrameActive = true; + OnCreateClient(); - - return TRUE; + + return true; } wxMDIParentFrame::~wxMDIParentFrame() { DestroyChildren(); - // already delete by DestroyChildren() - m_frameToolBar = NULL; - m_frameStatusBar = NULL; + + // already deleted by DestroyChildren() m_clientWindow = NULL ; - - if (m_windowMenu) - { - delete m_windowMenu; - m_windowMenu = (wxMenu*) NULL; - } - - if ( m_clientWindow ) - { - delete m_clientWindow; - m_clientWindow = NULL ; - } + + delete m_windowMenu; } +void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar) +{ + wxFrame::SetMenuBar( menu_bar ) ; +} -// Get size *available for subwindows* i.e. excluding menu bar. -void wxMDIParentFrame::DoGetClientSize(int *x, int *y) const +void wxMDIParentFrame::GetRectForTopLevelChildren(int *x, int *y, int *w, int *h) { - wxDisplaySize( x , y ) ; + if (x) + *x = 0; + if (y) + *y = 0; + + wxDisplaySize(w, h); } -void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar) +void wxMDIParentFrame::AddChild(wxWindowBase *child) { - wxFrame::SetMenuBar( menu_bar ) ; + // moved this to front, so that we don't run into unset m_parent problems later + wxFrame::AddChild(child); + + if ( !m_currentChild ) + { + m_currentChild = wxDynamicCast(child, wxMDIChildFrame); + + if ( m_currentChild && IsShown() && !ShouldBeVisible() ) + { + // we shouldn't remain visible any more + wxFrame::Show(false); + m_shouldBeShown = true; + } + } } -void wxMDIParentFrame::OnSize(wxSizeEvent& event) +void wxMDIParentFrame::RemoveChild(wxWindowBase *child) { -#if wxUSE_CONSTRAINTS - if (GetAutoLayout()) - Layout(); -#endif - int x = 0; - int y = 0; - int width, height; - GetClientSize(&width, &height); - - if ( GetClientWindow() ) - GetClientWindow()->SetSize(x, y, width, height); + if ( child == m_currentChild ) + { + // the current child isn't active any more, try to find another one + m_currentChild = NULL; + + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxMDIChildFrame * + childCur = wxDynamicCast(node->GetData(), wxMDIChildFrame); + if ( childCur != child ) + { + m_currentChild = childCur; + break; + } + } + } + + wxFrame::RemoveChild(child); + + // if there are no more children left we need to show the frame if we + // hadn't shown it before because there were active children and it was + // useless (note that we have to do it after fully removing the child, i.e. + // after calling the base class RemoveChild() as otherwise we risk to touch + // pointer to the child being deleted) + if ( !m_currentChild && m_shouldBeShown && !IsShown() ) + { + // we have to show it, but at least move it out of sight and make it of + // smallest possible size (unfortunately (0, 0) doesn't work so that it + // doesn't appear in expose + SetSize(-10000, -10000, 1, 1); + Show(); + } } -void wxMDIParentFrame::OnActivate(wxActivateEvent& event) +void wxMDIParentFrame::MacActivate(long timestamp, bool activating) { - if ( m_currentChild && event.GetActive() ) + wxLogTrace(TRACE_MDI, wxT("MDI PARENT=%p MacActivate(0x%08lx,%s)"), this, timestamp, activating ? wxT("ACTIV") : wxT("deact")); + + if (activating) { - wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_currentChild->GetId()); - event.SetEventObject( m_currentChild ); - m_currentChild->GetEventHandler()->ProcessEvent(event) ; + if (s_macDeactivateWindow && s_macDeactivateWindow->GetParent() == this) + { + wxLogTrace(TRACE_MDI, wxT("child had been scheduled for deactivation, rehighlighting")); + + UMAHighlightAndActivateWindow((WindowRef)s_macDeactivateWindow->MacGetWindowRef(), true); + + wxLogTrace(TRACE_MDI, wxT("finished highliting child")); + + s_macDeactivateWindow = NULL; + } + else if (s_macDeactivateWindow == this) + { + wxLogTrace(TRACE_MDI, wxT("Avoided deactivation/activation of this=%p"), this); + + s_macDeactivateWindow = NULL; + } + else // window to deactivate is NULL or is not us or one of our kids + { + // activate kid instead + if (m_currentChild) + m_currentChild->MacActivate(timestamp, activating); + else + wxFrame::MacActivate(timestamp, activating); + } } - else if ( event.GetActive() ) + else { - if ( m_frameMenuBar != NULL ) + // We were scheduled for deactivation, and now we do it. + if (s_macDeactivateWindow == this) + { + s_macDeactivateWindow = NULL; + if (m_currentChild) + m_currentChild->MacActivate(timestamp, activating); + wxFrame::MacActivate(timestamp, activating); + } + else // schedule ourselves for deactivation { - m_frameMenuBar->MacInstallMenuBar() ; + if (s_macDeactivateWindow) + wxLogTrace(TRACE_MDI, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow); + wxLogTrace(TRACE_MDI, wxT("Scheduling delayed MDI Parent deactivation")); + + s_macDeactivateWindow = this; } - } } +void wxMDIParentFrame::OnActivate(wxActivateEvent& event) +{ + event.Skip(); +} + // Returns the active MDI child window wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const { @@ -178,6 +245,7 @@ wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const wxMDIClientWindow *wxMDIParentFrame::OnCreateClient() { m_clientWindow = new wxMDIClientWindow( this ); + return m_clientWindow; } @@ -185,7 +253,7 @@ wxMDIClientWindow *wxMDIParentFrame::OnCreateClient() void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event) { // TODO - + // Propagate the event to the non-top-level children wxFrame::OnSysColourChanged(event); } @@ -196,7 +264,7 @@ void wxMDIParentFrame::Cascade() // TODO } -void wxMDIParentFrame::Tile() +void wxMDIParentFrame::Tile(wxOrientation WXUNUSED(orient)) { // TODO } @@ -216,7 +284,55 @@ void wxMDIParentFrame::ActivatePrevious() // TODO } +bool wxMDIParentFrame::ShouldBeVisible() const +{ + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *win = node->GetData(); + + if ( win->IsShown() + && !wxDynamicCast(win, wxMDIChildFrame) +#if wxUSE_STATUSBAR + && win != (wxWindow*) GetStatusBar() +#endif + && win != GetClientWindow() ) + { + // if we have a non-MDI child, do remain visible so that it could + // be used + return true; + } + } + + return false; +} + +bool wxMDIParentFrame::Show( bool show ) +{ + m_shouldBeShown = false; + + // don't really show the MDI frame unless it has any children other than + // MDI children as it is pretty useless in this case + + if ( show ) + { + if ( !ShouldBeVisible() && m_currentChild ) + { + // don't make the window visible now but remember that we should + // have had done it + m_shouldBeShown = true; + + return false; + } + } + + return wxFrame::Show(show); +} + +// ---------------------------------------------------------------------------- // Child frame +// ---------------------------------------------------------------------------- wxMDIChildFrame::wxMDIChildFrame() { @@ -235,29 +351,27 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, const wxString& name) { SetName(name); - - if ( id > -1 ) - m_windowId = id; - else + + if ( id == wxID_ANY ) m_windowId = (int)NewControlId(); - - if (parent) parent->AddChild(this); - + else + m_windowId = id; + + if (parent) + parent->AddChild(this); + MacCreateRealWindow( title, pos , size , MacRemoveBordersFromStyle(style) , name ) ; - - m_macWindowBackgroundTheme = kThemeBrushDocumentWindowBackground ; - SetThemeWindowBackground( (WindowRef) m_macWindow , m_macWindowBackgroundTheme , false ) ; - + + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE)); + wxModelessWindows.Append(this); - return FALSE; + + return true; } wxMDIChildFrame::~wxMDIChildFrame() { DestroyChildren(); - // already delete by DestroyChildren() - m_frameToolBar = NULL; - m_frameStatusBar = NULL; } void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar) @@ -265,6 +379,62 @@ void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar) return wxFrame::SetMenuBar( menu_bar ) ; } +void wxMDIChildFrame::MacActivate(long timestamp, bool activating) +{ + wxLogTrace(TRACE_MDI, wxT("MDI child=%p MacActivate(0x%08lx,%s)"),this, timestamp, activating ? wxT("ACTIV") : wxT("deact")); + + wxMDIParentFrame *mdiparent = wxDynamicCast(m_parent, wxMDIParentFrame); + wxASSERT(mdiparent); + + if (activating) + { + if (s_macDeactivateWindow == m_parent) + { + wxLogTrace(TRACE_MDI, wxT("parent had been scheduled for deactivation, rehighlighting")); + + UMAHighlightAndActivateWindow((WindowRef)s_macDeactivateWindow->MacGetWindowRef(), true); + + wxLogTrace(TRACE_MDI, wxT("finished highliting parent")); + + s_macDeactivateWindow = NULL; + } + else if ((mdiparent->m_currentChild == this) || !s_macDeactivateWindow) + mdiparent->wxFrame::MacActivate(timestamp, activating); + + if (mdiparent->m_currentChild && mdiparent->m_currentChild != this) + mdiparent->m_currentChild->wxFrame::MacActivate(timestamp, false); + mdiparent->m_currentChild = this; + + if (s_macDeactivateWindow == this) + { + wxLogTrace(TRACE_MDI, wxT("Avoided deactivation/activation of this=%p"), this); + + s_macDeactivateWindow = NULL; + } + else + wxFrame::MacActivate(timestamp, activating); + } + else + { + // We were scheduled for deactivation, and now we do it. + if (s_macDeactivateWindow == this) + { + s_macDeactivateWindow = NULL; + wxFrame::MacActivate(timestamp, activating); + if (mdiparent->m_currentChild == this) + mdiparent->wxFrame::MacActivate(timestamp, activating); + } + else // schedule ourselves for deactivation + { + if (s_macDeactivateWindow) + wxLogTrace(TRACE_MDI, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow); + wxLogTrace(TRACE_MDI, wxT("Scheduling delayed deactivation")); + + s_macDeactivateWindow = this; + } + } +} + // MDI operations void wxMDIChildFrame::Maximize() { @@ -295,21 +465,23 @@ wxMDIClientWindow::~wxMDIClientWindow() bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style) { - - m_windowId = (int)NewControlId(); - - if ( parent ) - { - parent->AddChild(this); - } - m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE); - + if ( !wxWindow::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style) ) + return false; + wxModelessWindows.Append(this); - return TRUE; + + return true; +} + +// Get size *available for subwindows* i.e. excluding menu bar. +void wxMDIClientWindow::DoGetClientSize(int *x, int *y) const +{ + wxDisplaySize( x , y ) ; } // Explicitly call default scroll behaviour -void wxMDIClientWindow::OnScroll(wxScrollEvent& event) +void wxMDIClientWindow::OnScroll(wxScrollEvent& WXUNUSED(event)) { } +#endif // wxUSE_MDI