]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/mdi.cpp
handle correctly never/always shown scrollbars in GetClientSize()
[wxWidgets.git] / src / msw / mdi.cpp
index c854040c0529e03b1b964ca324e65a56cf6575fe..6b9cdbcc9a139cfab1d987421525fc7426e237c4 100644 (file)
@@ -52,9 +52,6 @@
 
 extern wxMenu *wxCurrentPopupMenu;
 
-extern const wxChar *wxMDIFrameClassName;   // from app.cpp
-extern const wxChar *wxMDIChildFrameClassName;
-extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
 extern void wxRemoveHandleAssociation(wxWindow *win);
 
 // ---------------------------------------------------------------------------
@@ -82,10 +79,10 @@ static void MDISetMenu(wxWindow *win, HMENU hmenuFrame, HMENU hmenuWindow);
 
 // insert the window menu (subMenu) into menu just before "Help" submenu or at
 // the very end if not found
-static void InsertWindowMenu(wxWindow *win, WXHMENU menu, HMENU subMenu);
+static void MDIInsertWindowMenu(wxWindow *win, WXHMENU menu, HMENU subMenu);
 
 // Remove the window menu
-static void RemoveWindowMenu(wxWindow *win, WXHMENU menu);
+static void MDIRemoveWindowMenu(wxWindow *win, WXHMENU menu);
 
 // is this an id of an MDI child?
 inline bool IsMdiCommandId(int id)
@@ -98,6 +95,9 @@ static void UnpackMDIActivate(WXWPARAM wParam, WXLPARAM lParam,
                               WXWORD *activate, WXHWND *hwndAct, WXHWND *hwndDeact);
 
 // return the HMENU of the MDI menu
+//
+// this function works correctly even when we don't have a window menu and just
+// returns 0 then
 static inline HMENU GetMDIWindowMenu(wxMDIParentFrame *frame)
 {
     wxMenu *menu = frame->GetWindowMenu();
@@ -137,9 +137,6 @@ END_EVENT_TABLE()
 
 wxMDIParentFrame::wxMDIParentFrame()
 {
-    m_clientWindow = NULL;
-    m_currentChild = NULL;
-    m_windowMenu = (wxMenu*) NULL;
     m_parentFrameActive = true;
 }
 
@@ -151,17 +148,11 @@ bool wxMDIParentFrame::Create(wxWindow *parent,
                               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 )
-  {
-      m_windowMenu = (wxMenu *)NULL;
-  }
-  else // normal case: we have the window menu, so construct it
+  if ( !(style & wxFRAME_NO_WINDOW_MENU) )
   {
+      // normal case: we have the window menu, so construct it
       m_windowMenu = new wxMenu;
 
       m_windowMenu->Append(IDM_WINDOWCASCADE, _("&Cascade"));
@@ -194,7 +185,7 @@ bool wxMDIParentFrame::Create(wxWindow *parent,
   msflags &= ~WS_VSCROLL;
   msflags &= ~WS_HSCROLL;
 
-  if ( !wxWindow::MSWCreate(wxMDIFrameClassName,
+  if ( !wxWindow::MSWCreate(wxApp::GetRegisteredClassName(_T("wxMDIFrame")),
                             title.wx_str(),
                             pos, size,
                             msflags,
@@ -223,19 +214,10 @@ wxMDIParentFrame::~wxMDIParentFrame()
 
     DestroyChildren();
 
-    if (m_windowMenu)
-    {
-        delete m_windowMenu;
-        m_windowMenu = (wxMenu*) NULL;
-    }
-
     // the MDI frame menubar is not automatically deleted by Windows unlike for
     // the normal frames
     if ( m_hMenu )
-    {
         ::DestroyMenu((HMENU)m_hMenu);
-        m_hMenu = (WXHMENU)NULL;
-    }
 
     if ( m_clientWindow )
     {
@@ -247,40 +229,91 @@ wxMDIParentFrame::~wxMDIParentFrame()
     }
 }
 
+// ----------------------------------------------------------------------------
+// wxMDIParentFrame child management
+// ----------------------------------------------------------------------------
+
+int wxMDIParentFrame::GetChildFramesCount() const
+{
+    int count = 0;
+    for ( wxWindowList::const_iterator i = GetChildren().begin();
+          i != GetChildren().end();
+          ++i )
+    {
+        if ( wxDynamicCast(*i, wxMDIChildFrame) )
+            count++;
+    }
+
+    return count;
+}
+
+void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame * WXUNUSED(child))
+{
+    if ( GetChildFramesCount() == 1 )
+    {
+        // first MDI child added, we need to insert the window menu now if we
+        // have it
+        AddWindowMenu();
+    }
+}
+
+void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame * WXUNUSED(child))
+{
+    if ( GetChildFramesCount() == 1 )
+    {
+        // last MDI child is being removed, remove the now unnecessary window
+        // menu too
+        RemoveWindowMenu();
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxMDIParentFrame window menu handling
+// ----------------------------------------------------------------------------
+
+void wxMDIParentFrame::AddWindowMenu()
+{
+    if ( m_windowMenu )
+        MDIInsertWindowMenu(GetClientWindow(), m_hMenu, GetMDIWindowMenu(this));
+}
+
+void wxMDIParentFrame::RemoveWindowMenu()
+{
+    if ( m_windowMenu )
+        MDIRemoveWindowMenu(GetClientWindow(), m_hMenu);
+}
+
 #if wxUSE_MENUS_NATIVE
 
 void wxMDIParentFrame::InternalSetMenuBar()
 {
     m_parentFrameActive = true;
 
-    InsertWindowMenu(GetClientWindow(), m_hMenu, GetMDIWindowMenu(this));
+    if ( GetActiveChild() )
+    {
+        AddWindowMenu();
+    }
+    else // we don't have any MDI children yet
+    {
+        // wait until we do to add the window menu but do set the main menu for
+        // now (this is done by AddWindowMenu() as a side effect)
+        MDISetMenu(GetClientWindow(), (HMENU)m_hMenu, NULL);
+    }
 }
 
 #endif // wxUSE_MENUS_NATIVE
 
 void wxMDIParentFrame::SetWindowMenu(wxMenu* menu)
 {
-    if (m_windowMenu)
-    {
-        if (GetMenuBar())
-        {
-            // Remove old window menu
-            RemoveWindowMenu(GetClientWindow(), m_hMenu);
-        }
+    // notice that Remove/AddWindowMenu() are safe to call even when
+    // m_windowMenu is NULL
+    RemoveWindowMenu();
 
-        delete m_windowMenu;
-        m_windowMenu = (wxMenu*) NULL;
-    }
+    delete m_windowMenu;
 
-    if (menu)
-    {
-        m_windowMenu = menu;
-        if (GetMenuBar())
-        {
-            InsertWindowMenu(GetClientWindow(), m_hMenu,
-                             GetHmenuOf(m_windowMenu));
-        }
-    }
+    m_windowMenu = menu;
+
+    AddWindowMenu();
 }
 
 void wxMDIParentFrame::DoMenuUpdates(wxMenu* menu)
@@ -355,15 +388,8 @@ wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
                                     WM_MDIGETACTIVE, 0, 0L);
     if ( hWnd == 0 )
         return NULL;
-    else
-        return (wxMDIChildFrame *)wxFindWinFromHandle((WXHWND) hWnd);
-}
 
-// Create the client window class (don't Create the window, just return a new
-// class)
-wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
-{
-    return new wxMDIClientWindow;
+    return (wxMDIChildFrame *)wxFindWinFromHandle(hWnd);
 }
 
 // Responds to colour changes, and passes event on to children.
@@ -686,6 +712,8 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
                              long style,
                              const wxString& name)
 {
+    m_mdiParent = parent;
+
   SetName(name);
 
   if ( id != wxID_ANY )
@@ -705,9 +733,12 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
 
   MDICREATESTRUCT mcs;
 
-  mcs.szClass = style & wxFULL_REPAINT_ON_RESIZE
-                    ? wxMDIChildFrameClassName
-                    : wxMDIChildFrameClassNameNoRedraw;
+  wxString className =
+      wxApp::GetRegisteredClassName(_T("wxMDIChildFrame"), COLOR_WINDOW);
+  if ( !(style & wxFULL_REPAINT_ON_RESIZE) )
+      className += wxApp::GetNoRedrawClassSuffix();
+
+  mcs.szClass = className.wx_str();
   mcs.szTitle = title.wx_str();
   mcs.hOwner = wxGetInstance();
   if (x != wxDefaultCoord)
@@ -763,6 +794,8 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
 
   SubclassWin(m_hWnd);
 
+  parent->AddMDIChild(this);
+
   return true;
 }
 
@@ -772,6 +805,8 @@ wxMDIChildFrame::~wxMDIChildFrame()
     if ( !m_hWnd )
         return;
 
+    GetMDIParent()->RemoveMDIChild(this);
+
     // will be destroyed by DestroyChildren() but reset them before calling it
     // to avoid using dangling pointers if a callback comes in the meanwhile
 #if wxUSE_TOOLBAR
@@ -783,7 +818,7 @@ wxMDIChildFrame::~wxMDIChildFrame()
 
     DestroyChildren();
 
-    RemoveWindowMenu(NULL, m_hMenu);
+    MDIRemoveWindowMenu(NULL, m_hMenu);
 
     MSWDestroyWindow();
 }
@@ -803,7 +838,7 @@ bool wxMDIChildFrame::Show(bool show)
 
     // we need to refresh the MDI frame window menu to include (or exclude if
     // we've been hidden) this frame
-    wxMDIParentFrame *parent = GetMDIParent();
+    wxMDIParentFrame * const parent = GetMDIParent();
     MDISetMenu(parent->GetClientWindow(), NULL, NULL);
 
     return true;
@@ -842,8 +877,8 @@ void wxMDIChildFrame::DoSetClientSize(int width, int height)
 
   // If there's an MDI parent, must subtract the parent's top left corner
   // since MoveWindow moves relative to the parent
-  wxMDIParentFrame *mdiParent = GetMDIParent();
-  ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
+  wxMDIParentFrame * const mdiParent = GetMDIParent();
+  ::ScreenToClient(GetHwndOf(mdiParent->GetClientWindow()), &point);
 
   MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)true);
 
@@ -878,8 +913,8 @@ void wxMDIChildFrame::DoGetPosition(int *x, int *y) const
 
   // Since we now have the absolute screen coords,
   // if there's a parent we must subtract its top left corner
-  wxMDIParentFrame *mdiParent = GetMDIParent();
-  ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
+  wxMDIParentFrame * const mdiParent = GetMDIParent();
+  ::ScreenToClient(GetHwndOf(mdiParent->GetClientWindow()), &point);
 
   if (x)
       *x = point.x;
@@ -889,9 +924,9 @@ void wxMDIChildFrame::DoGetPosition(int *x, int *y) const
 
 void wxMDIChildFrame::InternalSetMenuBar()
 {
-    wxMDIParentFrame *parent = GetMDIParent();
+    wxMDIParentFrame * const parent = GetMDIParent();
 
-    InsertWindowMenu(parent->GetClientWindow(),
+    MDIInsertWindowMenu(parent->GetClientWindow(),
                      m_hMenu, GetMDIWindowMenu(parent));
 
     parent->m_parentFrameActive = false;
@@ -899,7 +934,7 @@ void wxMDIChildFrame::InternalSetMenuBar()
 
 void wxMDIChildFrame::DetachMenuBar()
 {
-    RemoveWindowMenu(NULL, m_hMenu);
+    MDIRemoveWindowMenu(NULL, m_hMenu);
     wxFrame::DetachMenuBar();
 }
 
@@ -915,7 +950,7 @@ WXHICON wxMDIChildFrame::GetDefaultIcon() const
 
 void wxMDIChildFrame::Maximize(bool maximize)
 {
-    wxMDIParentFrame *parent = GetMDIParent();
+    wxMDIParentFrame * const parent = GetMDIParent();
     if ( parent && parent->GetClientWindow() )
     {
         ::SendMessage(GetWinHwnd(parent->GetClientWindow()),
@@ -926,7 +961,7 @@ void wxMDIChildFrame::Maximize(bool maximize)
 
 void wxMDIChildFrame::Restore()
 {
-    wxMDIParentFrame *parent = GetMDIParent();
+    wxMDIParentFrame * const parent = GetMDIParent();
     if ( parent && parent->GetClientWindow() )
     {
         ::SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIRESTORE,
@@ -936,7 +971,7 @@ void wxMDIChildFrame::Restore()
 
 void wxMDIChildFrame::Activate()
 {
-    wxMDIParentFrame *parent = GetMDIParent();
+    wxMDIParentFrame * const parent = GetMDIParent();
     if ( parent && parent->GetClientWindow() )
     {
         ::SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIACTIVATE,
@@ -1048,7 +1083,7 @@ bool wxMDIChildFrame::HandleMDIActivate(long WXUNUSED(activate),
                                         WXHWND hwndAct,
                                         WXHWND hwndDeact)
 {
-    wxMDIParentFrame *parent = GetMDIParent();
+    wxMDIParentFrame * const parent = GetMDIParent();
 
     HMENU menuToSet = 0;
 
@@ -1181,7 +1216,7 @@ bool wxMDIChildFrame::MSWTranslateMessage(WXMSG* msg)
 
 void wxMDIChildFrame::MSWDestroyWindow()
 {
-    wxMDIParentFrame *parent = GetMDIParent();
+    wxMDIParentFrame * const parent = GetMDIParent();
 
     // Must make sure this handle is invalidated (set to NULL) since all sorts
     // of things could happen after the child client is destroyed, but before
@@ -1191,8 +1226,8 @@ void wxMDIChildFrame::MSWDestroyWindow()
     SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIDESTROY,
                 (WPARAM)oldHandle, 0);
 
-    if (parent->GetActiveChild() == (wxMDIChildFrame*) NULL)
-        ResetWindowStyle((void*) NULL);
+    if (parent->GetActiveChild() == NULL)
+        ResetWindowStyle(NULL);
 
     if (m_hMenu)
     {
@@ -1208,7 +1243,7 @@ void wxMDIChildFrame::MSWDestroyWindow()
 bool wxMDIChildFrame::ResetWindowStyle(void *vrect)
 {
     RECT *rect = (RECT *)vrect;
-    wxMDIParentFrame* pFrameWnd = GetMDIParent();
+    wxMDIParentFrame * const pFrameWnd = GetMDIParent();
     wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild();
 
     if (!pChild || (pChild == this))
@@ -1405,7 +1440,7 @@ static void MDISetMenu(wxWindow *win, HMENU hmenuFrame, HMENU hmenuWindow)
     ::DrawMenuBar(GetWinHwnd(parent));
 }
 
-static void InsertWindowMenu(wxWindow *win, WXHMENU menu, HMENU subMenu)
+static void MDIInsertWindowMenu(wxWindow *win, WXHMENU menu, HMENU subMenu)
 {
     // Try to insert Window menu in front of Help, otherwise append it.
     HMENU hmenu = (HMENU)menu;
@@ -1445,7 +1480,7 @@ static void InsertWindowMenu(wxWindow *win, WXHMENU menu, HMENU subMenu)
     MDISetMenu(win, hmenu, subMenu);
 }
 
-static void RemoveWindowMenu(wxWindow *win, WXHMENU menu)
+static void MDIRemoveWindowMenu(wxWindow *win, WXHMENU menu)
 {
     HMENU hMenu = (HMENU)menu;