]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/mdig.cpp
new file added
[wxWidgets.git] / src / generic / mdig.cpp
index be8d84b8ba869069340afa74d99ae41edf560059..0c139b94702fc619581f2d9a1ec0d667ac310f49 100644 (file)
@@ -2,10 +2,11 @@
 // Name:        src/generic/mdig.cpp
 // Purpose:     Generic MDI (Multiple Document Interface) classes
 // Author:      Hans Van Leemputten
-// Modified by:
+// Modified by: 2008-10-31 Vadim Zeitlin: derive from the base classes
 // Created:     29/07/2002
 // RCS-ID:      $Id$
-// Copyright:   (c) Hans Van Leemputten
+// Copyright:   (c) 2002 Hans Van Leemputten
+//              (c) 2008 Vadim Zeitlin
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // headers
 // ---------------------------------------------------------------------------
 
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-    #pragma implementation "mdig.h"
-#endif
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
     #pragma hdrstop
 #endif
 
+#if wxUSE_MDI
+
 #ifndef WX_PRECOMP
-    #include "wx/panel.h"
     #include "wx/menu.h"
     #include "wx/intl.h"
+    #include "wx/log.h"
 #endif //WX_PRECOMP
 
+#include "wx/mdi.h"
 #include "wx/generic/mdig.h"
+#include "wx/notebook.h"
+#include "wx/scopeguard.h"
+
 #include "wx/stockitem.h"
 
 enum MDI_MENU_ID
@@ -52,48 +55,28 @@ enum MDI_MENU_ID
 IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIParentFrame, wxFrame)
 
 BEGIN_EVENT_TABLE(wxGenericMDIParentFrame, wxFrame)
+    EVT_CLOSE(wxGenericMDIParentFrame::OnClose)
 #if wxUSE_MENUS
-    EVT_MENU (wxID_ANY, wxGenericMDIParentFrame::DoHandleMenu)
+    EVT_MENU(wxID_ANY, wxGenericMDIParentFrame::OnWindowMenu)
 #endif
 END_EVENT_TABLE()
 
-wxGenericMDIParentFrame::wxGenericMDIParentFrame()
-{
-    Init();
-}
-
-wxGenericMDIParentFrame::wxGenericMDIParentFrame(wxWindow *parent,
-                                   wxWindowID id,
-                                   const wxString& title,
-                                   const wxPoint& pos,
-                                   const wxSize& size,
-                                   long style,
-                                   const wxString& name)
+void wxGenericMDIParentFrame::Init()
 {
-    Init();
-
-    (void)Create(parent, id, title, pos, size, style, name);
+#if wxUSE_MENUS
+    m_pMyMenuBar = NULL;
+#endif // wxUSE_MENUS
 }
 
 wxGenericMDIParentFrame::~wxGenericMDIParentFrame()
 {
     // Make sure the client window is destructed before the menu bars are!
-    wxDELETE(m_pClientWindow);
+    wxDELETE(m_clientWindow);
 
 #if wxUSE_MENUS
-    if (m_pMyMenuBar)
-    {
-        delete m_pMyMenuBar;
-        m_pMyMenuBar = (wxMenuBar *) NULL;
-    }
+    wxDELETE(m_pMyMenuBar);
 
     RemoveWindowMenu(GetMenuBar());
-
-    if (m_pWindowMenu)
-    {
-        delete m_pWindowMenu;
-        m_pWindowMenu = (wxMenu*) NULL;
-    }
 #endif // wxUSE_MENUS
 }
 
@@ -105,26 +88,60 @@ bool wxGenericMDIParentFrame::Create(wxWindow *parent,
                               long style,
                               const wxString& name)
 {
-  // this style can be used to prevent a window from having the standard MDI
-  // "Window" menu
-  if ( !(style & wxFRAME_NO_WINDOW_MENU) )
-  {
+    // this style can be used to prevent a window from having the standard MDI
+    // "Window" menu
+    if ( !(style & wxFRAME_NO_WINDOW_MENU) )
+    {
 #if wxUSE_MENUS
-      m_pWindowMenu = new wxMenu;
+        m_windowMenu = new wxMenu;
 
-      m_pWindowMenu->Append(wxWINDOWCLOSE,    _("Cl&ose"));
-      m_pWindowMenu->Append(wxWINDOWCLOSEALL, _("Close All"));
-      m_pWindowMenu->AppendSeparator();
-      m_pWindowMenu->Append(wxWINDOWNEXT,     _("&Next"));
-      m_pWindowMenu->Append(wxWINDOWPREV,     _("&Previous"));
+        m_windowMenu->Append(wxWINDOWCLOSE,    _("Cl&ose"));
+        m_windowMenu->Append(wxWINDOWCLOSEALL, _("Close All"));
+        m_windowMenu->AppendSeparator();
+        m_windowMenu->Append(wxWINDOWNEXT,     _("&Next"));
+        m_windowMenu->Append(wxWINDOWPREV,     _("&Previous"));
 #endif // wxUSE_MENUS
-  }
+    }
 
-  wxFrame::Create( parent, id, title, pos, size, style, name );
+    // the scrolling styles don't make sense neither for us nor for our client
+    // window (to which they're supposed to apply)
+    style &= ~(wxHSCROLL | wxVSCROLL);
 
-  OnCreateClient();
+    if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
+        return false;
+
+    wxGenericMDIClientWindow * const client = OnCreateGenericClient();
+    if ( !client->CreateGenericClient(this) )
+        return false;
 
-  return true;
+    m_clientWindow = client;
+
+    return true;
+}
+
+wxGenericMDIClientWindow *wxGenericMDIParentFrame::OnCreateGenericClient()
+{
+    return new wxGenericMDIClientWindow;
+}
+
+bool wxGenericMDIParentFrame::CloseAll()
+{
+    wxGenericMDIClientWindow * const client = GetGenericClientWindow();
+    if ( !client )
+        return true; // none of the windows left
+
+    wxBookCtrlBase * const book = client->GetBookCtrl();
+    while ( book->GetPageCount() )
+    {
+        wxGenericMDIChildFrame * const child = client->GetChild(0);
+        if ( !child->Close() )
+        {
+            // it refused to close, don't close the remaining ones neither
+            return false;
+        }
+    }
+
+    return true;
 }
 
 #if wxUSE_MENUS
@@ -133,16 +150,16 @@ void wxGenericMDIParentFrame::SetWindowMenu(wxMenu* pMenu)
     // Replace the window menu from the currently loaded menu bar.
     wxMenuBar *pMenuBar = GetMenuBar();
 
-    if (m_pWindowMenu)
+    if (m_windowMenu)
     {
         RemoveWindowMenu(pMenuBar);
 
-        wxDELETE(m_pWindowMenu);
+        wxDELETE(m_windowMenu);
     }
 
     if (pMenu)
     {
-        m_pWindowMenu = pMenu;
+        m_windowMenu = pMenu;
 
         AddWindowMenu(pMenuBar);
     }
@@ -159,20 +176,20 @@ void wxGenericMDIParentFrame::SetMenuBar(wxMenuBar *pMenuBar)
 }
 #endif // wxUSE_MENUS
 
-void wxGenericMDIParentFrame::SetChildMenuBar(wxGenericMDIChildFrame *pChild)
+void wxGenericMDIParentFrame::WXSetChildMenuBar(wxGenericMDIChildFrame *pChild)
 {
 #if wxUSE_MENUS
-    if (pChild  == (wxGenericMDIChildFrame *) NULL)
+    if (pChild  == NULL)
     {
         // No Child, set Our menu bar back.
         SetMenuBar(m_pMyMenuBar);
 
         // Make sure we know our menu bar is in use
-        m_pMyMenuBar = (wxMenuBar*) NULL;
+        m_pMyMenuBar = NULL;
     }
     else
     {
-        if (pChild->GetMenuBar() == (wxMenuBar*) NULL)
+        if (pChild->GetMenuBar() == NULL)
             return;
 
         // Do we need to save the current bar?
@@ -184,121 +201,101 @@ void wxGenericMDIParentFrame::SetChildMenuBar(wxGenericMDIChildFrame *pChild)
 #endif // wxUSE_MENUS
 }
 
-bool wxGenericMDIParentFrame::ProcessEvent(wxEvent& event)
+wxGenericMDIClientWindow *
+wxGenericMDIParentFrame::GetGenericClientWindow() const
 {
-    /*
-     * Redirect events to active child first.
-     */
-
-    // Stops the same event being processed repeatedly
-    static wxEventType inEvent = wxEVT_NULL;
-    if (inEvent == event.GetEventType())
-        return false;
-
-    inEvent = event.GetEventType();
-
-    // Let the active child (if any) process the event first.
-    bool res = false;
-    if (m_pActiveChild && event.IsKindOf(CLASSINFO(wxCommandEvent))
-#if 0
-        /* This is sure to not give problems... */
-        && (event.GetEventType() == wxEVT_COMMAND_MENU_SELECTED ||
-            event.GetEventType() == wxEVT_UPDATE_UI )
-#else
-        /* This was tested on wxMSW and worked... */
-        && event.GetEventObject() != m_pClientWindow
-        && !(event.GetEventType() == wxEVT_ACTIVATE ||
-             event.GetEventType() == wxEVT_SET_FOCUS ||
-             event.GetEventType() == wxEVT_KILL_FOCUS ||
-             event.GetEventType() == wxEVT_CHILD_FOCUS ||
-             event.GetEventType() == wxEVT_COMMAND_SET_FOCUS ||
-             event.GetEventType() == wxEVT_COMMAND_KILL_FOCUS )
-#endif
-       )
-    {
-        res = m_pActiveChild->GetEventHandler()->ProcessEvent(event);
-    }
-
-    // If the event was not handled this frame will handle it!
-    if (!res)
-    {
-        res = GetEventHandler()->wxEvtHandler::ProcessEvent(event);
-    }
-
-    inEvent = wxEVT_NULL;
-
-    return res;
+    return static_cast<wxGenericMDIClientWindow *>(m_clientWindow);
 }
 
-wxGenericMDIChildFrame *wxGenericMDIParentFrame::GetActiveChild() const
+wxBookCtrlBase *wxGenericMDIParentFrame::GetBookCtrl() const
 {
-    return m_pActiveChild;
+    wxGenericMDIClientWindow * const client = GetGenericClientWindow();
+    return client ? client->GetBookCtrl() : NULL;
 }
 
-void wxGenericMDIParentFrame::SetActiveChild(wxGenericMDIChildFrame* pChildFrame)
+void wxGenericMDIParentFrame::AdvanceActive(bool forward)
 {
-    m_pActiveChild = pChildFrame;
+    wxBookCtrlBase * const book = GetBookCtrl();
+    if ( book )
+        book->AdvanceSelection(forward);
 }
 
-wxGenericMDIClientWindow *wxGenericMDIParentFrame::GetClientWindow() const
+void wxGenericMDIParentFrame::WXUpdateChildTitle(wxGenericMDIChildFrame *child)
 {
-    return m_pClientWindow;
+    wxGenericMDIClientWindow * const client = GetGenericClientWindow();
+
+    const int pos = client->FindChild(child);
+    if ( pos == wxNOT_FOUND )
+        return;
+
+    client->GetBookCtrl()->SetPageText(pos, child->GetTitle());
 }
 
-wxGenericMDIClientWindow *wxGenericMDIParentFrame::OnCreateClient()
+void wxGenericMDIParentFrame::WXActivateChild(wxGenericMDIChildFrame *child)
 {
-#if wxUSE_GENERIC_MDI_AS_NATIVE
-    m_pClientWindow = new wxMDIClientWindow( this );
-#else
-    m_pClientWindow = new wxGenericMDIClientWindow( this );
-#endif
-    return m_pClientWindow;
+    wxGenericMDIClientWindow * const client = GetGenericClientWindow();
+
+    const int pos = client->FindChild(child);
+    if ( pos == wxNOT_FOUND )
+        return;
+
+    client->GetBookCtrl()->SetSelection(pos);
 }
 
-void wxGenericMDIParentFrame::ActivateNext()
+void wxGenericMDIParentFrame::WXRemoveChild(wxGenericMDIChildFrame *child)
 {
-    if (m_pClientWindow && m_pClientWindow->GetSelection() != -1)
+    const bool removingActive = WXIsActiveChild(child);
+    if ( removingActive )
     {
-        size_t active = m_pClientWindow->GetSelection() + 1;
-        if (active >= m_pClientWindow->GetPageCount())
-            active = 0;
-
-        m_pClientWindow->SetSelection(active);
+        SetActiveChild(NULL);
+        WXSetChildMenuBar(NULL);
     }
-}
 
-void wxGenericMDIParentFrame::ActivatePrevious()
-{
-    if (m_pClientWindow && m_pClientWindow->GetSelection() != -1)
+    wxGenericMDIClientWindow * const client = GetGenericClientWindow();
+    wxCHECK_RET( client, "should have client window" );
+
+    wxBookCtrlBase * const book = client->GetBookCtrl();
+
+    // Remove page if still there
+    int pos = client->FindChild(child);
+    if ( pos != wxNOT_FOUND )
     {
-        int active = m_pClientWindow->GetSelection() - 1;
-        if (active < 0)
-            active = m_pClientWindow->GetPageCount() - 1;
+        if ( book->RemovePage(pos) )
+            book->Refresh();
+    }
 
-        m_pClientWindow->SetSelection(active);
+    if ( removingActive )
+    {
+        // Set the new selection to a remaining page
+        const size_t count = book->GetPageCount();
+        if ( count > (size_t)pos )
+        {
+            book->SetSelection(pos);
+        }
+        else
+        {
+            if ( count > 0 )
+                book->SetSelection(count - 1);
+        }
     }
 }
 
-void wxGenericMDIParentFrame::Init()
+bool
+wxGenericMDIParentFrame::WXIsActiveChild(wxGenericMDIChildFrame *child) const
 {
-    m_pClientWindow = (wxGenericMDIClientWindow *) NULL;
-    m_pActiveChild = (wxGenericMDIChildFrame *) NULL;
-#if wxUSE_MENUS
-    m_pWindowMenu = (wxMenu *) NULL;
-    m_pMyMenuBar = (wxMenuBar*) NULL;
-#endif // wxUSE_MENUS
+    return static_cast<wxMDIChildFrameBase *>(GetActiveChild()) == child;
 }
 
 #if wxUSE_MENUS
 void wxGenericMDIParentFrame::RemoveWindowMenu(wxMenuBar *pMenuBar)
 {
-    if (pMenuBar && m_pWindowMenu)
+    if (pMenuBar && m_windowMenu)
     {
         // Remove old window menu
         int pos = pMenuBar->FindMenu(_("&Window"));
         if (pos != wxNOT_FOUND)
         {
-            wxASSERT(m_pWindowMenu == pMenuBar->GetMenu(pos)); // DBG:: We're going to delete the wrong menu!!!
+            wxASSERT(m_windowMenu == pMenuBar->GetMenu(pos)); // DBG:: We're going to delete the wrong menu!!!
             pMenuBar->Remove(pos);
         }
     }
@@ -306,173 +303,144 @@ void wxGenericMDIParentFrame::RemoveWindowMenu(wxMenuBar *pMenuBar)
 
 void wxGenericMDIParentFrame::AddWindowMenu(wxMenuBar *pMenuBar)
 {
-    if (pMenuBar && m_pWindowMenu)
+    if (pMenuBar && m_windowMenu)
     {
         int pos = pMenuBar->FindMenu(wxGetStockLabel(wxID_HELP,false));
         if (pos == wxNOT_FOUND)
         {
-            pMenuBar->Append(m_pWindowMenu, _("&Window"));
+            pMenuBar->Append(m_windowMenu, _("&Window"));
         }
         else
         {
-            pMenuBar->Insert(pos, m_pWindowMenu, _("&Window"));
+            pMenuBar->Insert(pos, m_windowMenu, _("&Window"));
         }
     }
 }
 
-void wxGenericMDIParentFrame::DoHandleMenu(wxCommandEvent &event)
+void wxGenericMDIParentFrame::OnWindowMenu(wxCommandEvent &event)
 {
-    switch (event.GetId())
+    switch ( event.GetId() )
     {
-    case wxWINDOWCLOSE:
-        if (m_pActiveChild)
-        {
-            m_pActiveChild->Close();
-        }
-        break;
-    case wxWINDOWCLOSEALL:
-        {
-#if 0   // code is only needed if next #if is set to 0!
-            wxGenericMDIChildFrame *pFirstActiveChild = m_pActiveChild;
-#endif
-            while (m_pActiveChild)
-            {
-                if (!m_pActiveChild->Close())
-                {
-                    return; // We failed...
-                }
-                else
-                {
-#if 1   // What's best? Delayed deleting or immediate deleting?
-                    delete m_pActiveChild;
-                    m_pActiveChild = NULL;
-#else
-                    ActivateNext();
-
-                    if (pFirstActiveChild == m_pActiveChild)
-                        return; // We've called Close on all items, no need to continue.
-#endif
-                }
-            }
-        }
-        break;
-    case wxWINDOWNEXT:
-        ActivateNext();
-        break;
-    case wxWINDOWPREV:
-        ActivatePrevious();
-        break;
-    default :
-        event.Skip();
+        case wxWINDOWCLOSE:
+            if ( m_currentChild )
+                m_currentChild->Close();
+            break;
+
+        case wxWINDOWCLOSEALL:
+            CloseAll();
+            break;
+
+        case wxWINDOWNEXT:
+            ActivateNext();
+            break;
+
+        case wxWINDOWPREV:
+            ActivatePrevious();
+            break;
+
+        default:
+            event.Skip();
     }
 }
 #endif // wxUSE_MENUS
 
-void wxGenericMDIParentFrame::DoGetClientSize(int *width, int *height) const
+void wxGenericMDIParentFrame::OnClose(wxCloseEvent& event)
 {
-    wxFrame::DoGetClientSize( width, height );
+    if ( !CloseAll() )
+        event.Veto();
+    else
+        event.Skip();
 }
 
+bool wxGenericMDIParentFrame::ProcessEvent(wxEvent& event)
+{
+    if ( m_currentChild )
+    {
+        // the menu events should be given to the child as we show its menu bar
+        // as our own
+        const wxEventType eventType = event.GetEventType();
+        if ( eventType == wxEVT_COMMAND_MENU_SELECTED ||
+             eventType == wxEVT_UPDATE_UI )
+        {
+            // set the flag indicating that this event was forwarded to the
+            // child from the parent and so shouldn't be propagated upwards if
+            // not processed to avoid infinite loop
+            m_childHandler = m_currentChild;
+            wxON_BLOCK_EXIT_NULL(m_childHandler);
+
+            if ( m_currentChild->ProcessWindowEvent(event) )
+                return true;
+        }
+    }
 
-//-----------------------------------------------------------------------------
+    return wxMDIParentFrameBase::ProcessEvent(event);
+}
+
+// ----------------------------------------------------------------------------
 // wxGenericMDIChildFrame
-//-----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIChildFrame, wxPanel)
+IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIChildFrame, wxFrame)
 
-BEGIN_EVENT_TABLE(wxGenericMDIChildFrame, wxPanel)
+BEGIN_EVENT_TABLE(wxGenericMDIChildFrame, wxFrame)
     EVT_MENU_HIGHLIGHT_ALL(wxGenericMDIChildFrame::OnMenuHighlight)
-    EVT_ACTIVATE(wxGenericMDIChildFrame::OnActivate)
 
-    EVT_CLOSE(wxGenericMDIChildFrame::OnCloseWindow)
-    EVT_SIZE(wxGenericMDIChildFrame::OnSize)
+    EVT_CLOSE(wxGenericMDIChildFrame::OnClose)
 END_EVENT_TABLE()
 
-wxGenericMDIChildFrame::wxGenericMDIChildFrame()
-{
-    Init();
-}
-
-wxGenericMDIChildFrame::wxGenericMDIChildFrame( wxGenericMDIParentFrame *parent,
-      wxWindowID id, const wxString& title,
-      const wxPoint& WXUNUSED(pos), const wxSize& size,
-      long style, const wxString& name )
+void wxGenericMDIChildFrame::Init()
 {
-    Init();
+#if wxUSE_MENUS
+    m_pMenuBar = NULL;
+#endif // wxUSE_MENUS
 
-    Create( parent, id, title, wxDefaultPosition, size, style, name );
+#if !wxUSE_GENERIC_MDI_AS_NATIVE
+    m_mdiParentGeneric = NULL;
+#endif
 }
 
-#include "wx/log.h"
 wxGenericMDIChildFrame::~wxGenericMDIChildFrame()
 {
-    wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame();
+    wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
 
-    if (pParentFrame != NULL)
-    {
-        bool bActive = false;
-        if (pParentFrame->GetActiveChild() == this)
-        {
-            pParentFrame->SetActiveChild((wxGenericMDIChildFrame*) NULL);
-            pParentFrame->SetChildMenuBar((wxGenericMDIChildFrame*) NULL);
-            bActive = true;
-        }
-
-        wxGenericMDIClientWindow *pClientWindow = pParentFrame->GetClientWindow();
-
-        // Remove page if still there
-        size_t pos;
-        for (pos = 0; pos < pClientWindow->GetPageCount(); pos++)
-        {
-            if (pClientWindow->GetPage(pos) == this)
-            {
-                if (pClientWindow->RemovePage(pos))
-                    pClientWindow->Refresh();
-                break;
-            }
-        }
-
-        if (bActive)
-        {
-            // Set the new selection to the a remaining page
-            if (pClientWindow->GetPageCount() > pos)
-            {
-                pClientWindow->SetSelection(pos);
-            }
-            else
-            {
-                if ((int)pClientWindow->GetPageCount() - 1 >= 0)
-                    pClientWindow->SetSelection(pClientWindow->GetPageCount() - 1);
-            }
-        }
-    }
+    // it could happen that we don't have a valid parent if we hadn't been ever
+    // really created -- but in this case there is nothing else to do neither
+    if ( parent )
+        parent->WXRemoveChild(this);
 
 #if wxUSE_MENUS
-    wxDELETE(m_pMenuBar);
+    delete m_pMenuBar;
 #endif // wxUSE_MENUS
 }
 
-bool wxGenericMDIChildFrame::Create( wxGenericMDIParentFrame *parent,
-      wxWindowID id, const wxString& title,
-      const wxPoint& WXUNUSED(pos), const wxSize& size,
-      long style, const wxString& name )
+bool wxGenericMDIChildFrame::Create(wxGenericMDIParentFrame *parent,
+                                    wxWindowID id,
+                                    const wxString& title,
+                                    const wxPoint& WXUNUSED(pos),
+                                    const wxSize& size,
+                                    long WXUNUSED(style),
+                                    const wxString& name)
 {
-    wxGenericMDIClientWindow* pClientWindow = parent->GetClientWindow();
-
-    wxASSERT_MSG((pClientWindow != (wxWindow*) NULL), wxT("Missing MDI client window.") );
-
-    wxPanel::Create(pClientWindow, id, wxDefaultPosition, size, style, name);
+    // unfortunately we can't use the base class m_mdiParent field unless
+    // wxGenericMDIParentFrame is wxMDIParentFrame
+#if wxUSE_GENERIC_MDI_AS_NATIVE
+    m_mdiParent = parent;
+#else // generic != native
+    // leave m_mdiParent NULL, we don't have it
+    m_mdiParentGeneric = parent;
+#endif
 
-    SetMDIParentFrame(parent);
+    wxBookCtrlBase * const book = parent->GetBookCtrl();
 
-    // This is the currently active child
-    parent->SetActiveChild(this);
+    wxASSERT_MSG( book, "Missing MDI client window." );
 
-    m_Title = title;
+    // note that we ignore the styles, none of the usual TLW styles apply to
+    // this (child) window
+    if ( !wxWindow::Create(book, id, wxDefaultPosition, size, 0, name) )
+        return false;
 
-    pClientWindow->AddPage(this, title, true);
-    ApplyMDIChildFrameRect();   // Ok confirme the size change!
-    pClientWindow->Refresh();
+    m_title = title;
+    book->AddPage(this, title, true);
 
     return true;
 }
@@ -485,18 +453,18 @@ void wxGenericMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
 
     if (m_pMenuBar)
     {
-        wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame();
+        wxGenericMDIParentFrame *parent = GetGenericMDIParent();
 
-        if (pParentFrame != NULL)
+        if ( parent )
         {
-            m_pMenuBar->SetParent(pParentFrame);
+            m_pMenuBar->SetParent(parent);
 
-            if (pParentFrame->GetActiveChild() == this)
+            if ( parent->WXIsActiveChild(this) )
             {
                 // Replace current menu bars
                 if (pOldMenuBar)
-                    pParentFrame->SetChildMenuBar((wxGenericMDIChildFrame*) NULL);
-                pParentFrame->SetChildMenuBar((wxGenericMDIChildFrame*) this);
+                    parent->WXSetChildMenuBar(NULL);
+                parent->WXSetChildMenuBar(this);
             }
         }
     }
@@ -510,245 +478,120 @@ wxMenuBar *wxGenericMDIChildFrame::GetMenuBar() const
 
 void wxGenericMDIChildFrame::SetTitle(const wxString& title)
 {
-    m_Title = title;
-
-    wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame();
+    m_title = title;
 
-    if (pParentFrame != NULL)
-    {
-        wxGenericMDIClientWindow * pClientWindow = pParentFrame->GetClientWindow();
-
-        if (pClientWindow != NULL)
-        {
-            size_t pos;
-            for (pos = 0; pos < pClientWindow->GetPageCount(); pos++)
-            {
-                if (pClientWindow->GetPage(pos) == this)
-                {
-                    pClientWindow->SetPageText(pos, m_Title);
-                    break;
-                }
-            }
-        }
-    }
-}
-
-wxString wxGenericMDIChildFrame::GetTitle() const
-{
-    return m_Title;
+    wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
+    if ( parent )
+        parent->WXUpdateChildTitle(this);
+    //else: it's ok, we might be not created yet
 }
 
 void wxGenericMDIChildFrame::Activate()
 {
-    wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame();
+    wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
 
-    if (pParentFrame != NULL)
-    {
-        wxGenericMDIClientWindow * pClientWindow = pParentFrame->GetClientWindow();
-
-        if (pClientWindow != NULL)
-        {
-            size_t pos;
-            for (pos = 0; pos < pClientWindow->GetPageCount(); pos++)
-            {
-                if (pClientWindow->GetPage(pos) == this)
-                {
-                    pClientWindow->SetSelection(pos);
-                    break;
-                }
-            }
-        }
-    }
+    wxCHECK_RET( parent, "can't activate MDI child without parent" );
+    parent->WXActivateChild(this);
 }
 
 void wxGenericMDIChildFrame::OnMenuHighlight(wxMenuEvent& event)
 {
-#if wxUSE_STATUSBAR
-    if ( m_pMDIParentFrame)
+    wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
+    if ( parent)
     {
         // we don't have any help text for this item,
         // but may be the MDI frame does?
-        m_pMDIParentFrame->OnMenuHighlight(event);
+        parent->OnMenuHighlight(event);
     }
-#else
-    wxUnusedVar(event);
-#endif // wxUSE_STATUSBAR
 }
 
-void wxGenericMDIChildFrame::OnActivate(wxActivateEvent& WXUNUSED(event))
+void wxGenericMDIChildFrame::OnClose(wxCloseEvent& WXUNUSED(event))
 {
-    // Do mothing.
+    // we're not a TLW so don't delay the destruction of this window
+    delete this;
 }
 
-/*** Copied from top level..! ***/
-// default resizing behaviour - if only ONE subwindow, resize to fill the
-// whole client area
-void wxGenericMDIChildFrame::OnSize(wxSizeEvent& WXUNUSED(event))
+bool wxGenericMDIChildFrame::TryAfter(wxEvent& event)
 {
-    // if we're using constraints or sizers - do use them
-    if ( GetAutoLayout() )
-    {
-        Layout();
-    }
-    else
-    {
-        // do we have _exactly_ one child?
-        wxWindow *child = (wxWindow *)NULL;
-        for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-              node;
-              node = node->GetNext() )
-        {
-            wxWindow *win = node->GetData();
-
-            // exclude top level and managed windows (status bar isn't
-            // currently in the children list except under wxMac anyhow, but
-            // it makes no harm to test for it)
-            if ( !win->IsTopLevel() /*&& !IsOneOfBars(win)*/ )
-            {
-                if ( child )
-                {
-                    return;     // it's our second subwindow - nothing to do
-                }
-
-                child = win;
-            }
-        }
-
-        // do we have any children at all?
-        if ( child )
-        {
-            // exactly one child - set it's size to fill the whole frame
-            int clientW, clientH;
-            DoGetClientSize(&clientW, &clientH);
-
-            // for whatever reasons, wxGTK wants to have a small offset - it
-            // probably looks better with it?
-#ifdef __WXGTK__
-            static const int ofs = 1;
-#else
-            static const int ofs = 0;
-#endif
-
-            child->SetSize(ofs, ofs, clientW - 2*ofs, clientH - 2*ofs);
-        }
-    }
-}
-
-/*** Copied from top level..! ***/
-// The default implementation for the close window event.
-void wxGenericMDIChildFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
-{
-    Destroy();
-}
-
-void wxGenericMDIChildFrame::SetMDIParentFrame(wxGenericMDIParentFrame* parentFrame)
-{
-    m_pMDIParentFrame = parentFrame;
-}
-
-wxGenericMDIParentFrame* wxGenericMDIChildFrame::GetMDIParentFrame() const
-{
-    return m_pMDIParentFrame;
-}
-
-void wxGenericMDIChildFrame::Init()
-{
-    m_pMDIParentFrame = (wxGenericMDIParentFrame *) NULL;
-#if wxUSE_MENUS
-    m_pMenuBar = (wxMenuBar *) NULL;
-#endif // wxUSE_MENUS
-}
+    // we shouldn't propagate the event to the parent if we received it from it
+    // in the first place
+    wxGenericMDIParentFrame * const parent = GetGenericMDIParent();
+    if ( parent && parent->WXIsInsideChildHandler(this) )
+        return false;
 
-void wxGenericMDIChildFrame::DoMoveWindow(int x, int y, int width, int height)
-{
-    m_MDIRect = wxRect(x, y, width, height);
+    return wxTDIChildFrame::TryAfter(event);
 }
 
-void wxGenericMDIChildFrame::ApplyMDIChildFrameRect()
-{
-    wxPanel::DoMoveWindow(m_MDIRect.x, m_MDIRect.y, m_MDIRect.width, m_MDIRect.height);
-}
-
-//-----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
 // wxGenericMDIClientWindow
-//-----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
 
-#define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
+IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIClientWindow, wxWindow)
 
-IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIClientWindow, wxNotebook)
+bool
+wxGenericMDIClientWindow::CreateGenericClient(wxWindow *parent)
+{
+    if ( !wxWindow::Create(parent, wxID_ANY) )
+        return false;
 
-BEGIN_EVENT_TABLE(wxGenericMDIClientWindow, wxNotebook)
-    EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA, wxGenericMDIClientWindow::OnPageChanged)
-    EVT_SIZE(wxGenericMDIClientWindow::OnSize)
-END_EVENT_TABLE()
+    m_notebook = new wxNotebook(this, wxID_ANY);
+    m_notebook->Connect
+                (
+                    wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
+                    wxNotebookEventHandler(
+                        wxGenericMDIClientWindow::OnPageChanged),
+                    NULL,
+                    this
+                );
 
+    // now that we have a notebook to resize, hook up OnSize() too
+    Connect(wxEVT_SIZE, wxSizeEventHandler(wxGenericMDIClientWindow::OnSize));
 
-wxGenericMDIClientWindow::wxGenericMDIClientWindow()
-{
+    return true;
 }
 
-wxGenericMDIClientWindow::wxGenericMDIClientWindow( wxGenericMDIParentFrame *parent, long style )
+wxBookCtrlBase *wxGenericMDIClientWindow::GetBookCtrl() const
 {
-    CreateClient( parent, style );
+    return m_notebook;
 }
 
-wxGenericMDIClientWindow::~wxGenericMDIClientWindow()
+wxGenericMDIChildFrame *wxGenericMDIClientWindow::GetChild(size_t pos) const
 {
-    DestroyChildren();
+    return static_cast<wxGenericMDIChildFrame *>(GetBookCtrl()->GetPage(pos));
 }
 
-bool wxGenericMDIClientWindow::CreateClient( wxGenericMDIParentFrame *parent, long style )
+int wxGenericMDIClientWindow::FindChild(wxGenericMDIChildFrame *child) const
 {
-    SetWindowStyleFlag(style);
-
-    bool success = wxNotebook::Create(parent, wxID_NOTEBOOK_CLIENT_AREA, wxPoint(0,0), wxSize(100, 100), 0);
-    if (success)
+    wxBookCtrlBase * const book = GetBookCtrl();
+    const size_t count = book->GetPageCount();
+    for ( size_t pos = 0; pos < count; pos++ )
     {
-        /*
-        wxFont font(10, wxSWISS, wxNORMAL, wxNORMAL);
-        wxFont selFont(10, wxSWISS, wxNORMAL, wxBOLD);
-        GetTabView()->SetTabFont(font);
-        GetTabView()->SetSelectedTabFont(selFont);
-        GetTabView()->SetTabSize(120, 18);
-        GetTabView()->SetTabSelectionHeight(20);
-        */
-        return true;
+        if ( book->GetPage(pos) == child )
+            return pos;
     }
-    else
-        return false;
-}
 
-int wxGenericMDIClientWindow::SetSelection(size_t nPage)
-{
-    int oldSelection = wxNotebook::SetSelection(nPage);
-
-#if !defined(__WXMSW__) // No need to do this for wxMSW as wxNotebook::SetSelection()
-                        // will already cause this to be done!
-    // Handle the page change.
-    PageChanged(oldSelection, nPage);
-#endif
-
-    return oldSelection;
+    return wxNOT_FOUND;
 }
 
-void wxGenericMDIClientWindow::PageChanged(int OldSelection, int newSelection)
+void wxGenericMDIClientWindow::PageChanged(int oldSelection, int newSelection)
 {
-    // Don't do to much work, only when something realy should change!
-    if (OldSelection == newSelection)
+    // Don't do anything if nothing changed
+    if (oldSelection == newSelection)
         return;
-    // Again check if we realy need to do this...
+
+    // Again check if we really need to do this...
     if (newSelection != -1)
     {
-        wxGenericMDIChildFrame* child = (wxGenericMDIChildFrame *)GetPage(newSelection);
+        wxGenericMDIChildFrame * const child = GetChild(newSelection);
 
-        if (child->GetMDIParentFrame()->GetActiveChild() == child)
+        if ( child->GetGenericMDIParent()->WXIsActiveChild(child) )
             return;
     }
 
     // Notify old active child that it has been deactivated
-    if (OldSelection != -1)
+    if (oldSelection != -1)
     {
-        wxGenericMDIChildFrame* oldChild = (wxGenericMDIChildFrame *)GetPage(OldSelection);
+        wxGenericMDIChildFrame * const oldChild = GetChild(oldSelection);
         if (oldChild)
         {
             wxActivateEvent event(wxEVT_ACTIVATE, false, oldChild->GetId());
@@ -760,60 +603,41 @@ void wxGenericMDIClientWindow::PageChanged(int OldSelection, int newSelection)
     // Notify new active child that it has been activated
     if (newSelection != -1)
     {
-        wxGenericMDIChildFrame* activeChild = (wxGenericMDIChildFrame *)GetPage(newSelection);
-        if (activeChild)
+        wxGenericMDIChildFrame * const activeChild = GetChild(newSelection);
+        if ( activeChild )
         {
             wxActivateEvent event(wxEVT_ACTIVATE, true, activeChild->GetId());
             event.SetEventObject( activeChild );
             activeChild->GetEventHandler()->ProcessEvent(event);
 
-            if (activeChild->GetMDIParentFrame())
+            wxGenericMDIParentFrame * const
+                parent = activeChild->GetGenericMDIParent();
+
+            if ( parent )
             {
-                activeChild->GetMDIParentFrame()->SetActiveChild(activeChild);
-                activeChild->GetMDIParentFrame()->SetChildMenuBar(activeChild);
+                // this is a dirty hack as activeChild is not really a
+                // wxMDIChildFrame at all but we still want to store it in the
+                // base class m_currentChild field and this will work as long
+                // as we only use as wxMDIChildFrameBase pointer (which it is)
+                parent->SetActiveChild(
+                    reinterpret_cast<wxMDIChildFrame *>(activeChild));
+                parent->WXSetChildMenuBar(activeChild);
             }
         }
     }
 }
 
-void wxGenericMDIClientWindow::OnPageChanged(wxNotebookEvent& event)
+void wxGenericMDIClientWindow::OnPageChanged(wxBookCtrlEvent& event)
 {
     PageChanged(event.GetOldSelection(), event.GetSelection());
 
     event.Skip();
 }
 
-void wxGenericMDIClientWindow::OnSize(wxSizeEvent& event)
+void wxGenericMDIClientWindow::OnSize(wxSizeEvent& WXUNUSED(event))
 {
-    wxNotebook::OnSize(event);
-
-    size_t pos;
-    for (pos = 0; pos < GetPageCount(); pos++)
-    {
-        ((wxGenericMDIChildFrame *)GetPage(pos))->ApplyMDIChildFrameRect();
-    }
+    m_notebook->SetSize(GetClientSize());
 }
 
-
-/*
- * Define normal wxMDI classes based on wxGenericMDI
- */
-
-#if wxUSE_GENERIC_MDI_AS_NATIVE
-
-wxMDIChildFrame * wxMDIParentFrame::GetActiveChild() const
-    {
-        wxGenericMDIChildFrame *pGFrame = wxGenericMDIParentFrame::GetActiveChild();
-        wxMDIChildFrame *pFrame = wxDynamicCast(pGFrame, wxMDIChildFrame);
-
-        wxASSERT_MSG(!(pFrame == NULL && pGFrame != NULL), wxT("Active frame is class not derived from wxMDIChildFrame!"));
-
-        return pFrame;
-    }
-
-IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxGenericMDIParentFrame)
-IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxGenericMDIChildFrame)
-IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxGenericMDIClientWindow)
-
-#endif
+#endif // wxUSE_MDI