// headers
// ---------------------------------------------------------------------------
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
- #pragma implementation "mdi.h"
-#endif
-
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if wxUSE_MDI && !defined(__WXUNIVERSAL__)
+#include "wx/mdi.h"
+
#ifndef WX_PRECOMP
- #include "wx/setup.h"
#include "wx/frame.h"
#include "wx/menu.h"
#include "wx/app.h"
#include "wx/utils.h"
#include "wx/dialog.h"
- #if wxUSE_STATUSBAR
- #include "wx/statusbr.h"
- #endif
+ #include "wx/statusbr.h"
#include "wx/settings.h"
#include "wx/intl.h"
#include "wx/log.h"
+ #include "wx/toolbar.h"
#endif
-#include "wx/mdi.h"
+#include "wx/stockitem.h"
#include "wx/msw/private.h"
-#if wxUSE_STATUSBAR && wxUSE_NATIVE_STATUSBAR
- #include "wx/msw/statbr95.h"
-#endif
-
-#if wxUSE_TOOLBAR
- #include "wx/toolbar.h"
-#endif // wxUSE_TOOLBAR
-
#include <string.h>
// ---------------------------------------------------------------------------
extern const wxChar *wxMDIFrameClassName; // from app.cpp
extern const wxChar *wxMDIChildFrameClassName;
extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
-extern void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win);
extern void wxRemoveHandleAssociation(wxWindow *win);
-static HWND invalidHandle = 0;
-
// ---------------------------------------------------------------------------
// constants
// ---------------------------------------------------------------------------
// 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)
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();
BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
EVT_SIZE(wxMDIParentFrame::OnSize)
+ EVT_ICONIZE(wxMDIParentFrame::OnIconized)
EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
END_EVENT_TABLE()
{
m_clientWindow = NULL;
m_currentChild = NULL;
- m_windowMenu = (wxMenu*) NULL;
+ m_windowMenu = NULL;
m_parentFrameActive = true;
}
// "Window" menu
if ( style & wxFRAME_NO_WINDOW_MENU )
{
- m_windowMenu = (wxMenu *)NULL;
+ m_windowMenu = NULL;
}
else // normal case: we have the window menu, so construct it
{
msflags &= ~WS_HSCROLL;
if ( !wxWindow::MSWCreate(wxMDIFrameClassName,
- title,
+ title.wx_str(),
pos, size,
msflags,
exflags) )
return false;
}
+ SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
+
// unlike (almost?) all other windows, frames are created hidden
m_isShown = false;
DestroyChildren();
- if (m_windowMenu)
- {
- delete m_windowMenu;
- m_windowMenu = (wxMenu*) NULL;
- }
+ delete m_windowMenu;
// 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 )
{
}
}
+// ----------------------------------------------------------------------------
+// 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
{
if (m_windowMenu)
{
- if (GetMenuBar())
- {
- // Remove old window menu
- RemoveWindowMenu(GetClientWindow(), m_hMenu);
- }
+ RemoveWindowMenu();
delete m_windowMenu;
- m_windowMenu = (wxMenu*) NULL;
+ m_windowMenu = NULL;
}
if (menu)
{
m_windowMenu = menu;
- if (GetMenuBar())
- {
- InsertWindowMenu(GetClientWindow(), m_hMenu,
- GetHmenuOf(m_windowMenu));
- }
+
+ AddWindowMenu();
}
}
{
int nCount = bar->GetMenuCount();
for (int n = 0; n < nCount; n++)
- bar->GetMenu(n)->UpdateUI(source);
+ bar->GetMenu(n)->UpdateUI(source);
}
}
}
}
}
-void wxMDIParentFrame::OnSize(wxSizeEvent&)
+const wxMenuItem *wxMDIParentFrame::FindItemInMenuBar(int menuId) const
+{
+ const wxMenuItem *item = wxFrame::FindItemInMenuBar(menuId);
+ if ( !item && m_currentChild )
+ {
+ item = m_currentChild->FindItemInMenuBar(menuId);
+ }
+
+ return item;
+}
+
+void wxMDIParentFrame::UpdateClientSize()
{
if ( GetClientWindow() )
{
}
}
+void wxMDIParentFrame::OnSize(wxSizeEvent& WXUNUSED(event))
+{
+ UpdateClientSize();
+
+ // do not call event.Skip() here, it somehow messes up MDI client window
+}
+
+void wxMDIParentFrame::OnIconized(wxIconizeEvent& event)
+{
+ event.Skip();
+
+ if ( !event.IsIconized() )
+ UpdateClientSize();
+}
+
// Returns the active MDI child window
wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
{
WM_MDIGETACTIVE, 0, 0L);
if ( hWnd == 0 )
return NULL;
- else
- return (wxMDIChildFrame *)wxFindWinFromHandle((WXHWND) hWnd);
+
+ return (wxMDIChildFrame *)wxFindWinFromHandle(hWnd);
}
// Create the client window class (don't Create the window, just return a new
rc = true;
break;
- case WM_MENUSELECT:
- {
- WXWORD item, flags;
- WXHMENU hmenu;
- UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu);
-
- if ( m_parentFrameActive )
- {
- processed = HandleMenuSelect(item, flags, hmenu);
- }
- else if (m_currentChild)
- {
- processed = m_currentChild->
- HandleMenuSelect(item, flags, hmenu);
- }
- }
- break;
-
case WM_SIZE:
// though we don't (usually) resize the MDI client to exactly fit the
// client area we need to pass this one to DefFrameProc to allow the children to show
{
wxActivateEvent event(wxEVT_ACTIVATE, true, m_currentChild->GetId());
event.SetEventObject( m_currentChild );
- if ( m_currentChild->GetEventHandler()->ProcessEvent(event) )
+ if ( m_currentChild->HandleWindowEvent(event) )
processed = true;
}
return processed;
}
-bool wxMDIParentFrame::HandleCommand(WXWORD id, WXWORD cmd, WXHWND hwnd)
+bool wxMDIParentFrame::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND hwnd)
{
+ // sign extend to int from short before comparing with the other int ids
+ int id = (signed short)id_;
+
// In case it's e.g. a toolbar.
if ( hwnd )
{
return win->MSWCommand(cmd, id);
}
+ if (wxCurrentPopupMenu)
+ {
+ wxMenu *popupMenu = wxCurrentPopupMenu;
+ wxCurrentPopupMenu = NULL;
+ if (popupMenu->MSWCommand(cmd, id))
+ return true;
+ }
+
// is it one of standard MDI commands?
WXWPARAM wParam = 0;
WXLPARAM lParam = 0;
wxWindow *child = node->GetData();
if ( child->GetHWND() )
{
- long childId = wxGetWindowId(child->GetHWND());
- if (childId == (long)id)
+ int childId = wxGetWindowId(child->GetHWND());
+ if ( childId == (signed short)id )
{
::SendMessage( GetWinHwnd(GetClientWindow()),
WM_MDIACTIVATE,
if ( id != wxID_ANY )
m_windowId = id;
else
- m_windowId = (int)NewControlId();
+ m_windowId = NewControlId();
if ( parent )
{
mcs.szClass = style & wxFULL_REPAINT_ON_RESIZE
? wxMDIChildFrameClassName
: wxMDIChildFrameClassNameNoRedraw;
- mcs.szTitle = title;
+ mcs.szTitle = title.wx_str();
mcs.hOwner = wxGetInstance();
if (x != wxDefaultCoord)
mcs.x = x;
msflags |= WS_MINIMIZEBOX;
if (style & wxMAXIMIZE_BOX)
msflags |= WS_MAXIMIZEBOX;
- if (style & wxTHICK_FRAME)
+ if (style & wxRESIZE_BORDER)
msflags |= WS_THICKFRAME;
if (style & wxSYSTEM_MENU)
msflags |= WS_SYSMENU;
wxWindowCreationHook hook(this);
m_hWnd = (WXHWND)::SendMessage(GetWinHwnd(parent->GetClientWindow()),
- WM_MDICREATE, 0, (LONG)(LPSTR)&mcs);
+ WM_MDICREATE, 0, (LPARAM)&mcs);
+
+ if ( !m_hWnd )
+ {
+ wxLogLastError(_T("WM_MDICREATE"));
+ return false;
+ }
- wxAssociateWinWithHandle((HWND) GetHWND(), this);
+ SubclassWin(m_hWnd);
+
+ parent->AddMDIChild(this);
return true;
}
wxMDIChildFrame::~wxMDIChildFrame()
{
+ // if we hadn't been created, there is nothing to destroy
+ 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
DestroyChildren();
- RemoveWindowMenu(NULL, m_hMenu);
+ MDIRemoveWindowMenu(NULL, m_hMenu);
MSWDestroyWindow();
}
bool wxMDIChildFrame::Show(bool show)
{
m_needsInitialShow = false;
- return wxFrame::Show(show);
+
+ if (!wxFrame::Show(show))
+ return false;
+
+ // KH: Without this call, new MDI children do not become active.
+ // This was added here after the same BringWindowToTop call was
+ // removed from wxTopLevelWindow::Show (November 2005)
+ if ( show )
+ ::BringWindowToTop(GetHwnd());
+
+ // we need to refresh the MDI frame window menu to include (or exclude if
+ // we've been hidden) this frame
+ wxMDIParentFrame *parent = GetMDIParent();
+ MDISetMenu(parent->GetClientWindow(), NULL, NULL);
+
+ return true;
}
// Set the client size (i.e. leave the calculation of borders etc.
// If there's an MDI parent, must subtract the parent's top left corner
// since MoveWindow moves relative to the parent
- wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
+ wxMDIParentFrame *mdiParent = GetMDIParent();
::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)true);
wxSize size(width, height);
wxSizeEvent event(size, m_windowId);
event.SetEventObject( this );
- GetEventHandler()->ProcessEvent(event);
+ HandleWindowEvent(event);
+}
+
+// Unlike other wxTopLevelWindowBase, the mdi child's "GetPosition" is not the
+// same as its GetScreenPosition
+void wxMDIChildFrame::DoGetScreenPosition(int *x, int *y) const
+{
+ HWND hWnd = GetHwnd();
+
+ RECT rect;
+ ::GetWindowRect(hWnd, &rect);
+ if (x)
+ *x = rect.left;
+ if (y)
+ *y = rect.top;
}
+
void wxMDIChildFrame::DoGetPosition(int *x, int *y) const
{
RECT rect;
// Since we now have the absolute screen coords,
// if there's a parent we must subtract its top left corner
- wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
+ wxMDIParentFrame *mdiParent = GetMDIParent();
::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
if (x)
void wxMDIChildFrame::InternalSetMenuBar()
{
- wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
+ wxMDIParentFrame *parent = GetMDIParent();
- InsertWindowMenu(parent->GetClientWindow(),
+ MDIInsertWindowMenu(parent->GetClientWindow(),
m_hMenu, GetMDIWindowMenu(parent));
parent->m_parentFrameActive = false;
}
+void wxMDIChildFrame::DetachMenuBar()
+{
+ MDIRemoveWindowMenu(NULL, m_hMenu);
+ wxFrame::DetachMenuBar();
+}
+
WXHICON wxMDIChildFrame::GetDefaultIcon() const
{
// we don't have any standard icons (any more)
void wxMDIChildFrame::Maximize(bool maximize)
{
- wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
+ wxMDIParentFrame *parent = GetMDIParent();
if ( parent && parent->GetClientWindow() )
{
::SendMessage(GetWinHwnd(parent->GetClientWindow()),
void wxMDIChildFrame::Restore()
{
- wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
+ wxMDIParentFrame *parent = GetMDIParent();
if ( parent && parent->GetClientWindow() )
{
::SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIRESTORE,
void wxMDIChildFrame::Activate()
{
- wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
+ wxMDIParentFrame *parent = GetMDIParent();
if ( parent && parent->GetClientWindow() )
{
::SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIACTIVATE,
return rc;
}
-bool wxMDIChildFrame::HandleCommand(WXWORD id, WXWORD cmd, WXHWND hwnd)
+bool wxMDIChildFrame::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND hwnd)
{
+ // sign extend to int from short before comparing with the other int ids
+ int id = (signed short)id_;
+
// In case it's e.g. a toolbar.
if ( hwnd )
{
WXHWND hwndAct,
WXHWND hwndDeact)
{
- wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
+ wxMDIParentFrame *parent = GetMDIParent();
HMENU menuToSet = 0;
ResetWindowStyle((void *)NULL);
- return GetEventHandler()->ProcessEvent(event);
+ return HandleWindowEvent(event);
}
bool wxMDIChildFrame::HandleWindowPosChanging(void *pos)
{
WINDOWPOS *lpPos = (WINDOWPOS *)pos;
-#if defined(__WIN95__)
+
if (!(lpPos->flags & SWP_NOSIZE))
{
RECT rectClient;
lpPos->cx = rectClient.right - rectClient.left;
lpPos->cy = rectClient.bottom - rectClient.top;
}
-#if wxUSE_TOOLBAR
- wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
- if (pFrameWnd && pFrameWnd->GetToolBar() && pFrameWnd->GetToolBar()->IsShown())
- {
- pFrameWnd->GetToolBar()->Refresh();
- }
-#endif
}
-#endif // Win95
return false;
}
minHeight = GetMinHeight();
// but allow GetSizeHints() to set the min size
- if ( minWidth != -1 )
+ if ( minWidth != wxDefaultCoord )
{
info->ptMinTrackSize.x = minWidth;
processed = true;
}
- if ( minHeight != -1 )
+ if ( minHeight != wxDefaultCoord )
{
info->ptMinTrackSize.y = minHeight;
bool wxMDIChildFrame::MSWTranslateMessage(WXMSG* msg)
{
- return wxFrame::MSWTranslateMessage(msg);
+ // we must pass the parent frame to ::TranslateAccelerator(), otherwise it
+ // doesn't do its job correctly for MDI child menus
+ return MSWDoTranslateMessage(GetMDIParent(), msg);
}
// ---------------------------------------------------------------------------
void wxMDIChildFrame::MSWDestroyWindow()
{
- invalidHandle = GetHwnd();
-
- wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
+ wxMDIParentFrame *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
SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIDESTROY,
(WPARAM)oldHandle, 0);
- if (parent->GetActiveChild() == (wxMDIChildFrame*) NULL)
- ResetWindowStyle((void*) NULL);
-
- invalidHandle = 0;
+ if (parent->GetActiveChild() == NULL)
+ ResetWindowStyle(NULL);
if (m_hMenu)
{
// style when a child is maximised (a double border looks silly.)
bool wxMDIChildFrame::ResetWindowStyle(void *vrect)
{
-#if defined(__WIN95__)
RECT *rect = (RECT *)vrect;
- wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
+ wxMDIParentFrame* pFrameWnd = GetMDIParent();
wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild();
+
if (!pChild || (pChild == this))
{
HWND hwndClient = GetWinHwnd(pFrameWnd->GetClientWindow());
return true;
}
}
-#endif // Win95
return false;
}
if ( style & wxVSCROLL )
msStyle |= WS_VSCROLL;
-#if defined(__WIN95__)
DWORD exStyle = WS_EX_CLIENTEDGE;
-#else
- DWORD exStyle = 0;
-#endif
wxWindowCreationHook hook(this);
m_hWnd = (WXHWND)::CreateWindowEx
// (see OGL studio sample). So check if the position is changed and if so,
// redraw the MDI child frames.
- wxPoint oldPos = GetPosition();
+ const wxPoint oldPos = GetPosition();
- wxWindow::DoSetSize(x, y, width, height, sizeFlags);
+ wxWindow::DoSetSize(x, y, width, height, sizeFlags | wxSIZE_FORCE);
- wxPoint newPos = GetPosition();
+ const wxPoint newPos = GetPosition();
if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y))
{
static void MDISetMenu(wxWindow *win, HMENU hmenuFrame, HMENU hmenuWindow)
{
- ::SendMessage(GetWinHwnd(win), WM_MDISETMENU,
-#ifdef __WIN32__
- (WPARAM)hmenuFrame, (LPARAM)hmenuWindow
-#else
- 0, MAKELPARAM(hmenuFrame, hmenuWindow)
-#endif
- );
+ if ( hmenuFrame || hmenuWindow )
+ {
+ if ( !::SendMessage(GetWinHwnd(win),
+ WM_MDISETMENU,
+ (WPARAM)hmenuFrame,
+ (LPARAM)hmenuWindow) )
+ {
+#ifdef __WXDEBUG__
+ DWORD err = ::GetLastError();
+ if ( err )
+ wxLogApiError(_T("SendMessage(WM_MDISETMENU)"), err);
+#endif // __WXDEBUG__
+ }
+ }
// update menu bar of the parent window
wxWindow *parent = win->GetParent();
::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;
continue;
}
- if ( wxStripMenuCodes(wxString(buf)).IsSameAs(_("Help")) )
+ wxString strBuf(buf);
+ if ( wxStripMenuCodes(strBuf) == wxGetStockLabel(wxID_HELP,false) )
{
success = true;
::InsertMenu(hmenu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
- (UINT)subMenu, _("&Window"));
+ (UINT_PTR)subMenu, _("&Window").wx_str());
break;
}
}
if ( !success )
{
- ::AppendMenu(hmenu, MF_POPUP, (UINT)subMenu, _("&Window"));
+ ::AppendMenu(hmenu, MF_POPUP,
+ (UINT_PTR)subMenu, _("&Window").wx_str());
}
}
MDISetMenu(win, hmenu, subMenu);
}
-static void RemoveWindowMenu(wxWindow *win, WXHMENU menu)
+static void MDIRemoveWindowMenu(wxWindow *win, WXHMENU menu)
{
HMENU hMenu = (HMENU)menu;
}
#endif // wxUSE_MDI && !defined(__WXUNIVERSAL__)
-