X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/57a7b7c1484fda95240972aae876bdbdbbc98344..5778dedc92f6d31435aa1cda6846979a0e9ad35b:/src/msw/mdi.cpp diff --git a/src/msw/mdi.cpp b/src/msw/mdi.cpp index 774b215ca1..44f8c19f17 100644 --- a/src/msw/mdi.cpp +++ b/src/msw/mdi.cpp @@ -1,103 +1,174 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: mdi.cpp -// Purpose: MDI classes +// Name: src/msw/mdi.cpp +// Purpose: MDI classes for wxMSW // Author: Julian Smart -// Modified by: +// Modified by: Vadim Zeitlin on 2008-11-04 to use the base classes // Created: 04/01/98 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Copyright: (c) 1998 Julian Smart +// (c) 2008-2009 Vadim Zeitlin +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "mdi.h" -#endif +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif -#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" -#include "wx/statusbr.h" -#include "wx/settings.h" -#endif +#if wxUSE_MDI && !defined(__WXUNIVERSAL__) #include "wx/mdi.h" -#include "wx/msw/private.h" -#if USE_NATIVE_STATUSBAR -#include +#ifndef WX_PRECOMP + #include "wx/frame.h" + #include "wx/menu.h" + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/dialog.h" + #include "wx/statusbr.h" + #include "wx/settings.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/toolbar.h" #endif +#include "wx/stockitem.h" +#include "wx/msw/private.h" + #include -extern wxList wxModelessWindows; +// --------------------------------------------------------------------------- +// global variables +// --------------------------------------------------------------------------- + +extern wxMenu *wxCurrentPopupMenu; + +extern void wxRemoveHandleAssociation(wxWindow *win); + +namespace +{ + +// --------------------------------------------------------------------------- +// constants +// --------------------------------------------------------------------------- + +// This range gives a maximum of 500 MDI children. Should be enough :-) +const int wxFIRST_MDI_CHILD = 4100; +const int wxLAST_MDI_CHILD = 4600; + +// The MDI "Window" menu label +const char *WINDOW_MENU_LABEL = gettext_noop("&Window"); -#define IDM_WINDOWTILE 4001 -#define IDM_WINDOWCASCADE 4002 -#define IDM_WINDOWICONS 4003 -#define IDM_WINDOWNEXT 4004 -// This range gives a maximum of 500 -// MDI children. Should be enough :-) -#define wxFIRST_MDI_CHILD 4100 -#define wxLAST_MDI_CHILD 4600 +// --------------------------------------------------------------------------- +// private functions +// --------------------------------------------------------------------------- -// Status border dimensions -#define wxTHICK_LINE_BORDER 3 -#define wxTHICK_LINE_WIDTH 1 +// set the MDI menus (by sending the WM_MDISETMENU message) and update the menu +// of the parent of win (which is supposed to be the MDI client window) +void MDISetMenu(wxWindow *win, HMENU hmenuFrame, HMENU hmenuWindow); -extern char wxMDIFrameClassName[]; -extern char wxMDIChildFrameClassName[]; -extern wxWindow *wxWndHook; +// insert the window menu (subMenu) into menu just before "Help" submenu or at +// the very end if not found +void MDIInsertWindowMenu(wxWindow *win, WXHMENU hMenu, HMENU subMenu); + +// Remove the window menu +void MDIRemoveWindowMenu(wxWindow *win, WXHMENU hMenu); + +// unpack the parameters of WM_MDIACTIVATE message +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 +inline HMENU GetMDIWindowMenu(wxMDIParentFrame *frame) +{ + wxMenu *menu = frame->GetWindowMenu(); + return menu ? GetHmenuOf(menu) : 0; +} + +} // anonymous namespace + +// =========================================================================== +// implementation +// =========================================================================== + +// --------------------------------------------------------------------------- +// wxWin macros +// --------------------------------------------------------------------------- -#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_SIZE(wxMDIParentFrame::OnSize) + EVT_ICONIZE(wxMDIParentFrame::OnIconized) + EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged) + +#if wxUSE_MENUS + EVT_MENU_RANGE(wxFIRST_MDI_CHILD, wxLAST_MDI_CHILD, + wxMDIParentFrame::OnMDIChild) + EVT_MENU_RANGE(wxID_MDI_WINDOW_FIRST, wxID_MDI_WINDOW_LAST, + wxMDIParentFrame::OnMDICommand) +#endif // wxUSE_MENUS +END_EVENT_TABLE() + +BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame) + EVT_IDLE(wxMDIChildFrame::OnIdle) END_EVENT_TABLE() BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow) - EVT_SCROLL(wxMDIClientWindow::OnScroll) + EVT_SCROLL(wxMDIClientWindow::OnScroll) END_EVENT_TABLE() -#endif +// =========================================================================== +// wxMDIParentFrame: the frame which contains the client window which manages +// the children +// =========================================================================== -wxMDIParentFrame::wxMDIParentFrame(void) +void wxMDIParentFrame::Init() { - m_clientWindow = NULL; - m_currentChild = NULL; - m_windowMenu = 0; - m_parentFrameActive = TRUE; +#if wxUSE_MENUS && wxUSE_ACCEL + // the default menu doesn't have any accelerators (even if we have it) + m_accelWindowMenu = NULL; +#endif // wxUSE_MENUS && wxUSE_ACCEL } 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_defaultIcon = (WXHICON) (wxSTD_MDIPARENTFRAME_ICON ? wxSTD_MDIPARENTFRAME_ICON : wxDEFAULT_MDIPARENTFRAME_ICON); - - m_clientWindow = NULL; - m_currentChild = NULL; - m_windowMenu = 0; - m_parentFrameActive = TRUE; + // this style can be used to prevent a window from having the standard MDI + // "Window" menu + if ( !(style & wxFRAME_NO_WINDOW_MENU) ) + { + // normal case: we have the window menu, so construct it + m_windowMenu = new wxMenu; + + m_windowMenu->Append(wxID_MDI_WINDOW_CASCADE, _("&Cascade")); + m_windowMenu->Append(wxID_MDI_WINDOW_TILE_HORZ, _("Tile &Horizontally")); + m_windowMenu->Append(wxID_MDI_WINDOW_TILE_VERT, _("Tile &Vertically")); + m_windowMenu->AppendSeparator(); + m_windowMenu->Append(wxID_MDI_WINDOW_ARRANGE_ICONS, _("&Arrange Icons")); + m_windowMenu->Append(wxID_MDI_WINDOW_NEXT, _("&Next")); + m_windowMenu->Append(wxID_MDI_WINDOW_PREV, _("&Previous")); + } if (!parent) wxTopLevelWindows.Append(this); @@ -105,256 +176,295 @@ bool wxMDIParentFrame::Create(wxWindow *parent, SetName(name); m_windowStyle = style; - if (parent) parent->AddChild(this); + if ( parent ) + parent->AddChild(this); - if ( id > -1 ) + if ( id != wxID_ANY ) m_windowId = id; else - m_windowId = (int)NewControlId(); + m_windowId = NewControlId(); + + WXDWORD exflags; + WXDWORD msflags = MSWGetCreateWindowFlags(&exflags); + msflags &= ~WS_VSCROLL; + msflags &= ~WS_HSCROLL; + + if ( !wxWindow::MSWCreate(wxApp::GetRegisteredClassName(wxT("wxMDIFrame")), + title.wx_str(), + pos, size, + msflags, + exflags) ) + { + return false; + } - int x = pos.x; - int y = pos.y; - int width = size.x; - int height = size.y; + SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE)); + + // unlike (almost?) all other windows, frames are created hidden + m_isShown = false; - m_windowMenu = (WXHMENU) ::LoadMenu(wxGetInstance(), "wxWindowMenu"); + return true; +} -#if WXDEBUG > 1 - wxDebugMsg("Loaded m_windowMenu %d\n", m_windowMenu); +wxMDIParentFrame::~wxMDIParentFrame() +{ + // see comment in ~wxMDIChildFrame +#if wxUSE_TOOLBAR + m_frameToolBar = NULL; #endif +#if wxUSE_STATUSBAR + m_frameStatusBar = NULL; +#endif // wxUSE_STATUSBAR - DWORD msflags = WS_OVERLAPPED ; - if (style & wxMINIMIZE_BOX) - msflags |= WS_MINIMIZEBOX; - if (style & wxMAXIMIZE_BOX) - msflags |= WS_MAXIMIZEBOX; - if (style & wxTHICK_FRAME) - msflags |= WS_THICKFRAME; - if (style & wxSYSTEM_MENU) - msflags |= WS_SYSMENU; - if ((style & wxMINIMIZE) || (style & wxICONIZE)) - msflags |= WS_MINIMIZE; - if (style & wxMAXIMIZE) - msflags |= WS_MAXIMIZE; - if (style & wxCAPTION) - msflags |= WS_CAPTION; +#if wxUSE_MENUS && wxUSE_ACCEL + delete m_accelWindowMenu; +#endif // wxUSE_MENUS && wxUSE_ACCEL - // Adding WS_CLIPCHILDREN causes children not to be properly - // drawn when first displaying them. -// if (style & wxCLIP_CHILDREN) -// msflags |= WS_CLIPCHILDREN; + DestroyChildren(); - wxWindow::MSWCreate(m_windowId, parent, wxMDIFrameClassName, this, title, x, y, width, height, - msflags); + // the MDI frame menubar is not automatically deleted by Windows unlike for + // the normal frames + if ( m_hMenu ) + ::DestroyMenu((HMENU)m_hMenu); - wxModelessWindows.Append(this); + if ( m_clientWindow ) + { + if ( m_clientWindow->MSWGetOldWndProc() ) + m_clientWindow->UnsubclassWin(); - return TRUE; + m_clientWindow->SetHWND(0); + delete m_clientWindow; + } } -wxMDIParentFrame::~wxMDIParentFrame(void) +// ---------------------------------------------------------------------------- +// wxMDIParentFrame child management +// ---------------------------------------------------------------------------- + +wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const { - DestroyChildren(); + HWND hWnd = (HWND)::SendMessage(GetWinHwnd(GetClientWindow()), + WM_MDIGETACTIVE, 0, 0L); + if ( !hWnd ) + return NULL; - DestroyMenu((HMENU) m_windowMenu); // Destroy dummy "Window" menu - m_windowMenu = 0; + return static_cast(wxFindWinFromHandle(hWnd)); +} - if (m_clientWindow->MSWGetOldWndProc()) - m_clientWindow->UnsubclassWin(); +int wxMDIParentFrame::GetChildFramesCount() const +{ + int count = 0; + for ( wxWindowList::const_iterator i = GetChildren().begin(); + i != GetChildren().end(); + ++i ) + { + if ( wxDynamicCast(*i, wxMDIChildFrame) ) + count++; + } - m_clientWindow->m_hWnd = 0; - delete m_clientWindow; + return count; } -// Get size *available for subwindows* i.e. excluding menu bar. -void wxMDIParentFrame::GetClientSize(int *x, int *y) const +#if wxUSE_MENUS + +void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame * WXUNUSED(child)) { - RECT rect; - GetClientRect((HWND) GetHWND(), &rect); + switch ( GetChildFramesCount() ) + { + case 1: + // first MDI child was just added, we need to insert the window + // menu now if we have it + AddWindowMenu(); + + // and disable the items which can't be used until we have more + // than one child + UpdateWindowMenu(false); + break; + + case 2: + // second MDI child was added, enable the menu items which were + // disabled because they didn't make sense for a single window + UpdateWindowMenu(true); + break; + } +} - int cwidth = rect.right; - int cheight = rect.bottom; +void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame * WXUNUSED(child)) +{ + switch ( GetChildFramesCount() ) + { + case 1: + // last MDI child is being removed, remove the now unnecessary + // window menu too + RemoveWindowMenu(); + + // there is no need to call UpdateWindowMenu(true) here so this is + // not quite symmetric to AddMDIChild() above + break; + + case 2: + // only one MDI child is going to remain, disable the menu commands + // which don't make sense for a single child window + UpdateWindowMenu(false); + break; + } +} - if ( GetStatusBar() ) - { - int sw, sh; - GetStatusBar()->GetSize(&sw, &sh); - cheight -= sh; - } +// ---------------------------------------------------------------------------- +// wxMDIParentFrame window menu handling +// ---------------------------------------------------------------------------- - wxPoint pt(GetClientAreaOrigin()); - cheight -= pt.y; - cwidth -= pt.x; +void wxMDIParentFrame::AddWindowMenu() +{ + if ( m_windowMenu ) + MDIInsertWindowMenu(GetClientWindow(), m_hMenu, GetMDIWindowMenu(this)); +} - *x = cwidth; - *y = cheight; +void wxMDIParentFrame::RemoveWindowMenu() +{ + if ( m_windowMenu ) + MDIRemoveWindowMenu(GetClientWindow(), m_hMenu); } -void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar) +void wxMDIParentFrame::UpdateWindowMenu(bool enable) { - if (!menu_bar) - { - m_frameMenuBar = NULL; - return; - } - - if (menu_bar->m_menuBarFrame) - return; + if ( m_windowMenu ) + { + m_windowMenu->Enable(wxID_MDI_WINDOW_NEXT, enable); + m_windowMenu->Enable(wxID_MDI_WINDOW_PREV, enable); + } +} - int i; - HMENU menu = CreateMenu(); +#if wxUSE_MENUS_NATIVE - for (i = 0; i < menu_bar->m_menuCount; i ++) - { - HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu; - // - // After looking Bounds Checker result, it seems that all - // menus must be individually destroyed. So, don't reset m_hMenu, - // to allow ~wxMenu to do the job. - // - menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup; - // Uncommenting for the moment... JACS - menu_bar->m_menus[i]->m_hMenu = (WXHMENU) NULL; - AppendMenu(menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]); - } +void wxMDIParentFrame::InternalSetMenuBar() +{ + 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); + } +} - menu_bar->m_hMenu = (WXHMENU)menu; - if (m_frameMenuBar) - delete m_frameMenuBar; +#endif // wxUSE_MENUS_NATIVE - this->m_hMenu = (WXHMENU) menu; +void wxMDIParentFrame::SetWindowMenu(wxMenu* menu) +{ + if ( menu != m_windowMenu ) + { + // notice that Remove/AddWindowMenu() are safe to call even when + // m_windowMenu is NULL + RemoveWindowMenu(); - // MDI parent-specific code follows + delete m_windowMenu; - HMENU subMenu = GetSubMenu((HMENU) m_windowMenu, 0); + m_windowMenu = menu; - // Try to insert Window menu in front of Help, otherwise append it. - int N = GetMenuItemCount(menu); - bool success = FALSE; - for (i = 0; i < N; i++) - { - char buf[100]; - int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION); - if ((chars > 0) && (strcmp(buf, "&Help") == 0 || - strcmp(buf, "Help") == 0)) - { - success = TRUE; - InsertMenu(menu, i, MF_BYPOSITION | MF_POPUP | MF_STRING, - (UINT)subMenu, "&Window"); - break; - } - } - if (!success) - AppendMenu(menu, MF_POPUP, - (UINT)subMenu, - "&Window"); - m_parentFrameActive = TRUE; -#ifdef __WIN32__ - SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDISETMENU, - (WPARAM)menu, - (LPARAM)subMenu); -#else - SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDISETMENU, 0, - MAKELPARAM(menu, subMenu)); -#endif - DrawMenuBar((HWND) GetHWND()); + AddWindowMenu(); + } - m_frameMenuBar = menu_bar; - menu_bar->m_menuBarFrame = this; -} +#if wxUSE_ACCEL + wxDELETE(m_accelWindowMenu); -void wxMDIParentFrame::OnSize(wxSizeEvent& event) -{ -#if USE_CONSTRAINTS - if (GetAutoLayout()) - Layout(); -#endif - int x = 0; - int y = 0; - int width, height; - GetClientSize(&width, &height); + if ( menu && menu->HasAccels() ) + m_accelWindowMenu = menu->CreateAccelTable(); +#endif // wxUSE_ACCEL +} - if ( GetClientWindow() ) - GetClientWindow()->SetSize(x, y, width, height); +// ---------------------------------------------------------------------------- +// wxMDIParentFrame other menu-related stuff +// ---------------------------------------------------------------------------- -/* Already done in MSWOnSize - // forward WM_SIZE to status bar control -#if USE_NATIVE_STATUSBAR - if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95))) - ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event); -#endif -*/ +void wxMDIParentFrame::DoMenuUpdates(wxMenu* menu) +{ + wxMDIChildFrame *child = GetActiveChild(); + if ( child ) + { + wxEvtHandler* source = child->GetEventHandler(); + wxMenuBar* bar = child->GetMenuBar(); + if (menu) + { + menu->UpdateUI(source); + } + else + { + if ( bar != NULL ) + { + int nCount = bar->GetMenuCount(); + for (int n = 0; n < nCount; n++) + bar->GetMenu(n)->UpdateUI(source); + } + } + } + else + { + wxFrameBase::DoMenuUpdates(menu); + } } -void wxMDIParentFrame::OnActivate(wxActivateEvent& event) +wxMenuItem *wxMDIParentFrame::FindItemInMenuBar(int menuId) const { - // Do nothing + wxMenuItem *item = wxFrame::FindItemInMenuBar(menuId); + if ( !item && GetActiveChild() ) + { + item = GetActiveChild()->FindItemInMenuBar(menuId); + } + + if ( !item && m_windowMenu ) + item = m_windowMenu->FindItem(menuId); + + return item; } -#if WXWIN_COMPATIBILITY -/* -void wxMDIParentFrame::OldOnSize(int x, int y) +WXHMENU wxMDIParentFrame::MSWGetActiveMenu() const { -#if WXWIN_COMPATIBILITY == 1 - wxSizeEvent event(wxSize(x, y), m_windowId); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); -#else + wxMDIChildFrame * const child = GetActiveChild(); + if ( child ) + { + const WXHMENU hmenu = child->MSWGetActiveMenu(); + if ( hmenu ) + return hmenu; + } -#if USE_CONSTRAINTS - if (GetAutoLayout()) - Layout(); -#endif - int x = 0; - int y = 0; - int width, height; - GetClientSize(&width, &height); - if ( GetToolBar() ) - { - int wt, ht; - GetToolBar()->GetSize(&wt, &ht); - height -= ht; - y += ht; - } + return wxFrame::MSWGetActiveMenu(); +} - if ( GetClientWindow() ) - GetClientWindow()->SetSize(x, y, width, height); +#endif // wxUSE_MENUS -#endif -} +// ---------------------------------------------------------------------------- +// wxMDIParentFrame event handling +// ---------------------------------------------------------------------------- -// Default activation behaviour - nothing. -// Default activation behaviour - override dedault wxFrame behaviour -void wxMDIParentFrame::OldOnActivate(bool flag) +void wxMDIParentFrame::UpdateClientSize() { -#if WXWIN_COMPATIBILITY == 1 - wxActivateEvent event(wxEVT_ACTIVATE, flag, m_windowId); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); -#else -#endif -} -*/ + if ( GetClientWindow() ) + { + int width, height; + GetClientSize(&width, &height); -#endif + GetClientWindow()->SetSize(0, 0, width, height); + } +} -// Returns the active MDI child window -wxMDIChildFrame *wxMDIParentFrame::GetActiveChild(void) const +void wxMDIParentFrame::OnSize(wxSizeEvent& WXUNUSED(event)) { -// HWND hWnd = (HWND)LOWORD(SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L)); - HWND hWnd = (HWND)SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L); - if (hWnd == 0) - return NULL; - else - return (wxMDIChildFrame *)wxFindWinFromHandle((WXHWND) hWnd); + UpdateClientSize(); + + // do not call event.Skip() here, it somehow messes up MDI client window } -// Create the client window class (don't Create the window, -// just return a new class) -wxMDIClientWindow *wxMDIParentFrame::OnCreateClient(void) +void wxMDIParentFrame::OnIconized(wxIconizeEvent& event) { - return new wxMDIClientWindow ; + event.Skip(); + + if ( !event.IsIconized() ) + UpdateClientSize(); } // Responds to colour changes, and passes event on to children. @@ -362,300 +472,306 @@ void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event) { if ( m_clientWindow ) { - m_clientWindow->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE)); + m_clientWindow->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE)); m_clientWindow->Refresh(); } -/* - if ( m_frameToolBar ) - { - wxSysColourChangedEvent event2; - event2.eventObject = m_frameToolBar; - m_frameToolBar->GetEventHandler()->ProcessEvent(event2); - } -*/ - // Propagate the event to the non-top-level children - wxFrame::OnSysColourChanged(event); + event.Skip(); } -// MDI operations -void wxMDIParentFrame::Cascade(void) +WXHICON wxMDIParentFrame::GetDefaultIcon() const { - ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDICASCADE, 0, 0); + // we don't have any standard icons (any more) + return (WXHICON)0; } -void wxMDIParentFrame::Tile(void) -{ - ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDITILE, MDITILE_HORIZONTAL, 0); -} +// --------------------------------------------------------------------------- +// MDI operations +// --------------------------------------------------------------------------- -void wxMDIParentFrame::ArrangeIcons(void) +void wxMDIParentFrame::Cascade() { - ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIICONARRANGE, 0, 0); + ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDICASCADE, 0, 0); } -void wxMDIParentFrame::ActivateNext(void) +void wxMDIParentFrame::Tile(wxOrientation orient) { - ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 0); -} + wxASSERT_MSG( orient == wxHORIZONTAL || orient == wxVERTICAL, + wxT("invalid orientation value") ); -void wxMDIParentFrame::ActivatePrevious(void) -{ - ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 1); + ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDITILE, + orient == wxHORIZONTAL ? MDITILE_HORIZONTAL + : MDITILE_VERTICAL, 0); } - -/* -// Returns a style for the client window - usually 0 -// or, for example, wxHSCROLL | wxVSCROLL -long wxMDIParentFrame::GetClientStyle(void) const +void wxMDIParentFrame::ArrangeIcons() { - return wxHSCROLL | wxVSCROLL ; + ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDIICONARRANGE, 0, 0); } -*/ -bool wxMDIParentFrame::MSWOnDestroy(void) +void wxMDIParentFrame::ActivateNext() { - return FALSE; + ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT, 0, 0); } -void wxMDIParentFrame::MSWOnCreate(WXLPCREATESTRUCT WXUNUSED(cs)) +void wxMDIParentFrame::ActivatePrevious() { - m_clientWindow = OnCreateClient(); - // Uses own style for client style - m_clientWindow->CreateClient(this, GetWindowStyleFlag()); + ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT, 0, 1); } -void wxMDIParentFrame::MSWOnSize(int x, int y, WXUINT id) +// --------------------------------------------------------------------------- +// the MDI parent frame window proc +// --------------------------------------------------------------------------- + +WXLRESULT wxMDIParentFrame::MSWWindowProc(WXUINT message, + WXWPARAM wParam, + WXLPARAM lParam) { - switch (id) - { - case SIZEFULLSCREEN: - case SIZENORMAL: - m_iconized = FALSE; - break; - case SIZEICONIC: - m_iconized = TRUE; - break; - } + WXLRESULT rc = 0; + bool processed = false; - if (!m_iconized) - { - // forward WM_SIZE to status bar control -#if USE_NATIVE_STATUSBAR - if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95))) - { - wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId()); - event.SetEventObject( m_frameStatusBar ); + switch ( message ) + { + case WM_ACTIVATE: + { + WXWORD state, minimized; + WXHWND hwnd; + UnpackActivate(wParam, lParam, &state, &minimized, &hwnd); - ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event); - } -#endif + processed = HandleActivate(state, minimized != 0, hwnd); + } + break; - PositionStatusBar(); - PositionToolBar(); + case WM_COMMAND: + // system messages such as SC_CLOSE are sent as WM_COMMANDs to the + // parent MDI frame and we must let the DefFrameProc() have them + // for these commands to work (without it, closing the maximized + // MDI children doesn't work, for example) + { + WXWORD id, cmd; + WXHWND hwnd; + UnpackCommand(wParam, lParam, &id, &hwnd, &cmd); + + if ( cmd == 0 /* menu */ && + id >= SC_SIZE /* first system menu command */ ) + { + MSWDefWindowProc(message, wParam, lParam); + processed = true; + } + } + break; - wxSizeEvent event(wxSize(x, y), m_windowId); - event.SetEventObject( this ); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); - } -} + case WM_CREATE: + m_clientWindow = OnCreateClient(); + // Uses own style for client style + if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) ) + { + wxLogMessage(_("Failed to create MDI parent frame.")); -bool wxMDIParentFrame::MSWOnActivate(int state, bool minimized, WXHWND activate) -{ - wxWindow::MSWOnActivate(state, minimized, activate); + rc = -1; + } - // If this window is an MDI parent, we must also send an OnActivate message - // to the current child. - if ((m_currentChild != NULL) && ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE))) - { - wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_currentChild->GetId()); - event.SetEventObject( m_currentChild ); - m_currentChild->GetEventHandler()->ProcessEvent(event); + processed = true; + break; } - return 0; + + if ( !processed ) + rc = wxFrame::MSWWindowProc(message, wParam, lParam); + + return rc; } -bool wxMDIParentFrame::MSWOnCommand(WXWORD id, WXWORD cmd, WXHWND control) +bool wxMDIParentFrame::HandleActivate(int state, bool minimized, WXHWND activate) { -// if (cmd == 0) // Why did I do this test? - { - // In case it's e.g. a toolbar. - wxWindow *win = wxFindWinFromHandle(control); - if (win) - return win->MSWCommand(cmd, id); + bool processed = false; - switch (id) + if ( wxWindow::HandleActivate(state, minimized, activate) ) { - case IDM_WINDOWCASCADE: - SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDICASCADE, MDITILE_SKIPDISABLED, 0); - return TRUE; - case IDM_WINDOWTILE: - SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDITILE, MDITILE_HORIZONTAL, 0); - return TRUE; - case IDM_WINDOWICONS: - SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIICONARRANGE, 0, 0); - return TRUE; - case IDM_WINDOWNEXT: - SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 0); - return TRUE; - default: - break; - } - if (id >= 0xF000) - { -#if WXDEBUG > 1 - wxDebugMsg("wxMDIFrame::OnCommand %d: system command: calling default window proc\n", GetHWND()); -#endif - return FALSE; // Get WndProc to call default proc + // already processed + processed = true; } - - if (m_parentFrameActive && (id < wxFIRST_MDI_CHILD || id > wxLAST_MDI_CHILD)) - { - ProcessCommand(id); - return TRUE; - } - else if (m_currentChild && (id < wxFIRST_MDI_CHILD || id > wxLAST_MDI_CHILD)) + + // If this window is an MDI parent, we must also send an OnActivate message + // to the current child. + if ( GetActiveChild() && + ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE)) ) { -#if WXDEBUG > 1 - wxDebugMsg("wxMDIFrame::MSWOnCommand %d: calling child OnCommand\n", GetHWND()); -#endif - return m_currentChild->MSWOnCommand(id, cmd, control); + wxActivateEvent event(wxEVT_ACTIVATE, true, GetActiveChild()->GetId()); + event.SetEventObject( GetActiveChild() ); + if ( GetActiveChild()->HandleWindowEvent(event) ) + processed = true; } - } - if (id >= wxFIRST_MDI_CHILD && id <= wxLAST_MDI_CHILD) - { - wxNode* node = GetChildren()->First(); - while (node) + + return processed; +} + +#if wxUSE_MENUS + +void wxMDIParentFrame::OnMDIChild(wxCommandEvent& event) +{ + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while ( node ) { - wxWindow* child = (wxWindow*) node->Data(); - if (child->GetHWND()) + wxWindow *child = node->GetData(); + if ( child->GetHWND() ) { -#ifdef __WIN32__ - long childId = GetWindowLong((HWND) child->GetHWND(), GWL_ID); -#else - long childId = GetWindowWord((HWND) child->GetHWND(), GWW_ID); -#endif - if (childId == id) + int childId = wxGetWindowId(child->GetHWND()); + if ( childId == event.GetId() ) { - ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) child->GetHWND(), 0); - return TRUE; + ::SendMessage( GetWinHwnd(GetClientWindow()), + WM_MDIACTIVATE, + (WPARAM)child->GetHWND(), 0); + return; } } - node = node->Next(); - } -/* - wxWindow* child = FindItem(id); - if (child) - { - ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) child->GetHWND(), 0); - return TRUE; + + node = node->GetNext(); } -*/ - } - return FALSE; + wxFAIL_MSG( "unknown MDI child selected?" ); } -void wxMDIParentFrame::MSWOnMenuHighlight(WXWORD nItem, WXWORD nFlags, WXHMENU hSysMenu) +void wxMDIParentFrame::OnMDICommand(wxCommandEvent& event) { - if (m_parentFrameActive) - { - if (nFlags == 0xFFFF && hSysMenu == (WXHMENU) NULL) + WXWPARAM wParam = 0; + WXLPARAM lParam = 0; + int msg; + switch ( event.GetId() ) { - wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, -1); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); + case wxID_MDI_WINDOW_CASCADE: + msg = WM_MDICASCADE; + wParam = MDITILE_SKIPDISABLED; + break; + + case wxID_MDI_WINDOW_TILE_HORZ: + wParam |= MDITILE_HORIZONTAL; + // fall through + + case wxID_MDI_WINDOW_TILE_VERT: + if ( !wParam ) + wParam = MDITILE_VERTICAL; + msg = WM_MDITILE; + wParam |= MDITILE_SKIPDISABLED; + break; + + case wxID_MDI_WINDOW_ARRANGE_ICONS: + msg = WM_MDIICONARRANGE; + break; + + case wxID_MDI_WINDOW_NEXT: + msg = WM_MDINEXT; + lParam = 0; // next child + break; + + case wxID_MDI_WINDOW_PREV: + msg = WM_MDINEXT; + lParam = 1; // previous child + break; + + default: + wxFAIL_MSG( "unknown MDI command" ); + return; } - else if (nFlags != MF_SEPARATOR) - { - wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, nItem); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); - } - } - else if (m_currentChild) - { - m_currentChild->MSWOnMenuHighlight(nItem, nFlags, hSysMenu); - } + + ::SendMessage(GetWinHwnd(GetClientWindow()), msg, wParam, lParam); } -long wxMDIParentFrame::MSWDefWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) +#endif // wxUSE_MENUS + +bool wxMDIParentFrame::TryBefore(wxEvent& event) { - WXHWND clientWnd; - if ( GetClientWindow() ) - clientWnd = GetClientWindow()->GetHWND(); - else - clientWnd = 0; + // menu (and toolbar) events should be sent to the active child frame + // first, if any + if ( event.GetEventType() == wxEVT_COMMAND_MENU_SELECTED ) + { + wxMDIChildFrame * const child = GetActiveChild(); + if ( child && child->ProcessWindowEventLocally(event) ) + return true; + } - return DefFrameProc((HWND) GetHWND(), (HWND) clientWnd, message, wParam, lParam); + return wxMDIParentFrameBase::TryBefore(event); } -bool wxMDIParentFrame::MSWProcessMessage(WXMSG* msg) +WXLRESULT wxMDIParentFrame::MSWDefWindowProc(WXUINT message, + WXWPARAM wParam, + WXLPARAM lParam) { - MSG *pMsg = (MSG *)msg; + WXHWND clientWnd; + if ( GetClientWindow() ) + clientWnd = GetClientWindow()->GetHWND(); + else + clientWnd = 0; - if ((m_currentChild != (wxWindow *)NULL) && (m_currentChild->GetHWND() != (WXHWND) NULL) && m_currentChild->MSWProcessMessage(msg)) - return TRUE; - - return FALSE; + return DefFrameProc(GetHwnd(), (HWND)clientWnd, message, wParam, lParam); } bool wxMDIParentFrame::MSWTranslateMessage(WXMSG* msg) { - MSG *pMsg = (MSG *)msg; + MSG *pMsg = (MSG *)msg; - if ((m_currentChild != (wxWindow *)NULL) && (m_currentChild->GetHWND() != (WXHWND) NULL) && m_currentChild->MSWTranslateMessage(msg)) - return TRUE; - - if (m_acceleratorTable.Ok() && - ::TranslateAccelerator((HWND) GetHWND(), (HACCEL) m_acceleratorTable.GetHACCEL(), pMsg)) - return TRUE; + // first let the current child get it + wxMDIChildFrame * const child = GetActiveChild(); + if ( child && child->MSWTranslateMessage(msg) ) + { + return true; + } - if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN) - { - if (::TranslateMDISysAccel((HWND) GetClientWindow()->GetHWND(), pMsg)) - return TRUE; - } + // then try out accelerator table (will also check the accelerators for the + // normal menu items) + if ( wxFrame::MSWTranslateMessage(msg) ) + { + return true; + } - return FALSE; -} +#if wxUSE_MENUS && wxUSE_ACCEL + // but it doesn't check for the (custom) accelerators of the window menu + // items as it's not part of the menu bar as it's handled by Windows itself + // so we need to do this explicitly + if ( m_accelWindowMenu && m_accelWindowMenu->Translate(this, msg) ) + return true; +#endif // wxUSE_MENUS && wxUSE_ACCEL + // finally, check for MDI specific built-in accelerators + if ( pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN ) + { + if ( ::TranslateMDISysAccel(GetWinHwnd(GetClientWindow()), pMsg)) + return true; + } -bool wxMDIParentFrame::MSWOnEraseBkgnd(WXHDC WXUNUSED(pDC)) -{ - return TRUE; + return false; } -extern wxWindow *wxWndHook; -extern wxList *wxWinHandleList; +// =========================================================================== +// wxMDIChildFrame +// =========================================================================== -wxMDIChildFrame::wxMDIChildFrame(void) +void wxMDIChildFrame::Init() { -// m_active = FALSE; + m_needsResize = true; + m_needsInitialShow = true; } bool wxMDIChildFrame::Create(wxMDIParentFrame *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_defaultIcon = (WXHICON) (wxSTD_MDICHILDFRAME_ICON ? wxSTD_MDICHILDFRAME_ICON : wxDEFAULT_MDICHILDFRAME_ICON); + m_mdiParent = parent; SetName(name); - if ( id > -1 ) + if ( id != wxID_ANY ) m_windowId = id; else - m_windowId = (int)NewControlId(); + m_windowId = NewControlId(); - if (parent) parent->AddChild(this); - - wxWndHook = this; + if ( parent ) + { + parent->AddChild(this); + } int x = pos.x; int y = pos.y; @@ -663,28 +779,41 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, int height = size.y; MDICREATESTRUCT mcs; - - mcs.szClass = wxMDIChildFrameClassName; - mcs.szTitle = title; + + wxString className = + wxApp::GetRegisteredClassName(wxT("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 > -1) mcs.x = x; - else mcs.x = CW_USEDEFAULT; + if (x != wxDefaultCoord) + mcs.x = x; + else + mcs.x = CW_USEDEFAULT; - if (y > -1) mcs.y = y; - else mcs.y = CW_USEDEFAULT; + if (y != wxDefaultCoord) + mcs.y = y; + else + mcs.y = CW_USEDEFAULT; - if (width > -1) mcs.cx = width; - else mcs.cx = CW_USEDEFAULT; + if (width != wxDefaultCoord) + mcs.cx = width; + else + mcs.cx = CW_USEDEFAULT; - if (height > -1) mcs.cy = height; - else mcs.cy = CW_USEDEFAULT; + if (height != wxDefaultCoord) + mcs.cy = height; + else + mcs.cy = CW_USEDEFAULT; - DWORD msflags = WS_OVERLAPPED | WS_CLIPCHILDREN ; + DWORD msflags = WS_OVERLAPPED | WS_CLIPCHILDREN; if (style & wxMINIMIZE_BOX) 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; @@ -699,40 +828,85 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, mcs.lParam = 0; - DWORD Return = SendMessage((HWND) parent->GetClientWindow()->GetHWND(), - WM_MDICREATE, 0, (LONG)(LPSTR)&mcs); + wxWindowCreationHook hook(this); - //handle = (HWND)LOWORD(Return); - // Must be the DWORRD for WIN32. And in 16 bits, HIWORD=0 (says Microsoft) - m_hWnd = (WXHWND)Return; + m_hWnd = (WXHWND)::SendMessage(GetWinHwnd(parent->GetClientWindow()), + WM_MDICREATE, 0, (LPARAM)&mcs); - // This gets reassigned so can't be stored -// m_windowId = GetWindowLong((HWND) m_hWnd, GWL_ID); + if ( !m_hWnd ) + { + wxLogLastError(wxT("WM_MDICREATE")); + return false; + } - wxWndHook = NULL; - wxWinHandleList->Append((long)GetHWND(), this); + SubclassWin(m_hWnd); - SetWindowLong((HWND) GetHWND(), 0, (long)this); + parent->AddMDIChild(this); - wxModelessWindows.Append(this); - return TRUE; + return true; } -wxMDIChildFrame::~wxMDIChildFrame(void) +wxMDIChildFrame::~wxMDIChildFrame() { - MSWDestroyWindow(); + // if we hadn't been created, there is nothing to destroy + if ( !m_hWnd ) + return; - ResetWindowStyle(NULL); + 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 + m_frameToolBar = NULL; +#endif +#if wxUSE_STATUSBAR + m_frameStatusBar = NULL; +#endif // wxUSE_STATUSBAR + + DestroyChildren(); + + MDIRemoveWindowMenu(NULL, m_hMenu); + + MSWDestroyWindow(); +} + +bool wxMDIChildFrame::Show(bool show) +{ + m_needsInitialShow = false; + + 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 * const parent = GetMDIParent(); + MDISetMenu(parent->GetClientWindow(), NULL, NULL); + + return true; +} + +void +wxMDIChildFrame::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + // we need to disable client area origin adjustments used for the child + // windows for the frame itself + wxMDIChildFrameBase::DoSetSize(x, y, width, height, sizeFlags); } // Set the client size (i.e. leave the calculation of borders etc. -// to wxWindows) -void wxMDIChildFrame::SetClientSize(int width, int height) +// to wxWidgets) +void wxMDIChildFrame::DoSetClientSize(int width, int height) { - HWND hWnd = (HWND) GetHWND(); + HWND hWnd = GetHwnd(); RECT rect; - GetClientRect(hWnd, &rect); + ::GetClientRect(hWnd, &rect); RECT rect2; GetWindowRect(hWnd, &rect2); @@ -743,12 +917,14 @@ void wxMDIChildFrame::SetClientSize(int width, int height) int actual_width = rect2.right - rect2.left - rect.right + width; int actual_height = rect2.bottom - rect2.top - rect.bottom + height; - if (GetStatusBar()) +#if wxUSE_STATUSBAR + if (GetStatusBar() && GetStatusBar()->IsShown()) { - int sx, sy; - GetStatusBar()->GetSize(&sx, &sy); + int sx, sy; + GetStatusBar()->GetSize(&sx, &sy); actual_height += sy; } +#endif // wxUSE_STATUSBAR POINT point; point.x = rect2.left; @@ -756,459 +932,398 @@ void wxMDIChildFrame::SetClientSize(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 = (wxMDIParentFrame *)GetParent(); - ::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); + MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)true); - wxSizeEvent event(wxSize(width, height), m_windowId); + wxSize size(width, height); + wxSizeEvent event(size, m_windowId); event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); + HandleWindowEvent(event); } -void wxMDIChildFrame::GetPosition(int *x, int *y) const +// 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) GetHWND(), &rect); + ::GetWindowRect(hWnd, &rect); + if (x) + *x = rect.left; + if (y) + *y = rect.top; +} + + +void wxMDIChildFrame::DoGetPosition(int *x, int *y) const +{ + RECT rect; + GetWindowRect(GetHwnd(), &rect); POINT point; point.x = rect.left; point.y = rect.top; // Since we now have the absolute screen coords, // if there's a parent we must subtract its top left corner - wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent(); - ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point); + wxMDIParentFrame * const mdiParent = GetMDIParent(); + ::ScreenToClient(GetHwndOf(mdiParent->GetClientWindow()), &point); - *x = point.x; - *y = point.y; + if (x) + *x = point.x; + if (y) + *y = point.y; } -void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar) +void wxMDIChildFrame::InternalSetMenuBar() { - if (!menu_bar) - { - m_frameMenuBar = NULL; - return; - } - - if (menu_bar->m_menuBarFrame) - return; - - int i; - HMENU menu = CreateMenu(); - - for (i = 0; i < menu_bar->m_menuCount; i ++) - { - HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu; - // - // After looking Bounds Checker result, it seems that all - // menus must be individually destroyed. So, don't reset m_hMenu, - // to allow ~wxMenu to do the job. - // - menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup; - // Uncommenting for the moment... JACS - menu_bar->m_menus[i]->m_hMenu = 0; - ::AppendMenu((HMENU) menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]); - } - - menu_bar->m_hMenu = (WXHMENU)menu; - if (m_frameMenuBar) - delete m_frameMenuBar; - - this->m_hMenu = (WXHMENU) menu; - - wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); + wxMDIParentFrame * const parent = GetMDIParent(); - parent->m_parentFrameActive = FALSE; - HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0); + MDIInsertWindowMenu(parent->GetClientWindow(), + m_hMenu, GetMDIWindowMenu(parent)); +} - // Try to insert Window menu in front of Help, otherwise append it. - int N = GetMenuItemCount(menu); - bool success = FALSE; - for (i = 0; i < N; i++) - { - char buf[100]; - int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION); - if ((chars > 0) && (strcmp(buf, "&Help") == 0 || - strcmp(buf, "Help") == 0)) - { - success = TRUE; - InsertMenu(menu, i, MF_BYPOSITION | MF_POPUP | MF_STRING, - (UINT)subMenu, "&Window"); - break; - } - } - if (!success) - AppendMenu(menu, MF_POPUP, - (UINT)subMenu, - "&Window"); -#ifdef __WIN32__ - SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, - (WPARAM)menu, - (LPARAM)subMenu); -#else - SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0, - MAKELPARAM(menu, subMenu)); -#endif +void wxMDIChildFrame::DetachMenuBar() +{ + MDIRemoveWindowMenu(NULL, m_hMenu); + wxFrame::DetachMenuBar(); +} - DrawMenuBar((HWND) parent->GetHWND()); - m_frameMenuBar = menu_bar; - menu_bar->m_menuBarFrame = this; +WXHICON wxMDIChildFrame::GetDefaultIcon() const +{ + // we don't have any standard icons (any more) + return (WXHICON)0; } +// --------------------------------------------------------------------------- // MDI operations -void wxMDIChildFrame::Maximize(void) +// --------------------------------------------------------------------------- + +void wxMDIChildFrame::Maximize(bool maximize) { - wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); + wxMDIParentFrame * const parent = GetMDIParent(); if ( parent && parent->GetClientWindow() ) - ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIMAXIMIZE, (WPARAM) (HWND) GetHWND(), 0); + { + ::SendMessage(GetWinHwnd(parent->GetClientWindow()), + maximize ? WM_MDIMAXIMIZE : WM_MDIRESTORE, + (WPARAM)GetHwnd(), 0); + } } -void wxMDIChildFrame::Restore(void) +void wxMDIChildFrame::Restore() { - wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); + wxMDIParentFrame * const parent = GetMDIParent(); if ( parent && parent->GetClientWindow() ) - ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIRESTORE, (WPARAM) (HWND) GetHWND(), 0); + { + ::SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIRESTORE, + (WPARAM) GetHwnd(), 0); + } } -void wxMDIChildFrame::Activate(void) +void wxMDIChildFrame::Activate() { - wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); + wxMDIParentFrame * const parent = GetMDIParent(); if ( parent && parent->GetClientWindow() ) - ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) GetHWND(), 0); + { + ::SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIACTIVATE, + (WPARAM) GetHwnd(), 0); + } } -static HWND invalidHandle = 0; -void wxMDIChildFrame::MSWOnSize(int x, int y, WXUINT id) +// --------------------------------------------------------------------------- +// MDI window proc and message handlers +// --------------------------------------------------------------------------- + +WXLRESULT wxMDIChildFrame::MSWWindowProc(WXUINT message, + WXWPARAM wParam, + WXLPARAM lParam) { - if (!GetHWND()) return; + WXLRESULT rc = 0; + bool processed = false; - if (invalidHandle == (HWND) GetHWND()) - { -#if WXDEBUG > 1 - wxDebugMsg("wxMDIChildFrame::OnSize %d: invalid, so returning.\n", GetHWND()); -#endif - return; - } - - (void)MSWDefWindowProc(m_lastMsg, m_lastWParam, m_lastLParam); + switch ( message ) + { + case WM_GETMINMAXINFO: + processed = HandleGetMinMaxInfo((MINMAXINFO *)lParam); + break; - switch (id) - { - case SIZEFULLSCREEN: - case SIZENORMAL: - m_iconized = FALSE; - break; - case SIZEICONIC: - m_iconized = TRUE; - break; - } + case WM_MDIACTIVATE: + { + WXWORD act; + WXHWND hwndAct, hwndDeact; + UnpackMDIActivate(wParam, lParam, &act, &hwndAct, &hwndDeact); - if (!m_iconized) - { - // forward WM_SIZE to status bar control -#if USE_NATIVE_STATUSBAR - if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95))) - { - wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId()); - event.SetEventObject( m_frameStatusBar ); + processed = HandleMDIActivate(act, hwndAct, hwndDeact); + } + // fall through + + case WM_MOVE: + // must pass WM_MOVE to DefMDIChildProc() to recalculate MDI client + // scrollbars if necessary + + // fall through + + case WM_SIZE: + // must pass WM_SIZE to DefMDIChildProc(), otherwise many weird + // things happen + MSWDefWindowProc(message, wParam, lParam); + break; - ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event); + case WM_WINDOWPOSCHANGING: + processed = HandleWindowPosChanging((LPWINDOWPOS)lParam); + break; } -#endif - PositionStatusBar(); - PositionToolBar(); + if ( !processed ) + rc = wxFrame::MSWWindowProc(message, wParam, lParam); - wxWindow::MSWOnSize(x, y, id); - } + return rc; } -bool wxMDIChildFrame::MSWOnCommand(WXWORD id, WXWORD cmd, WXHWND control) +bool wxMDIChildFrame::HandleMDIActivate(long WXUNUSED(activate), + WXHWND hwndAct, + WXHWND hwndDeact) { -#if WXDEBUG > 1 - wxDebugMsg("wxMDIChildFrame::MSWOnCommand %d\n", GetHWND()); -#endif -// if ((cmd == 0) && GetHWND()) - if (GetHWND()) - { - // In case it's e.g. a toolbar. - wxWindow *win = wxFindWinFromHandle(control); - if (win) - return win->MSWCommand(cmd, id); + wxMDIParentFrame * const parent = GetMDIParent(); + + WXHMENU hMenuToSet = 0; - if (GetMenuBar() && GetMenuBar()->FindItemForId(id)) + bool activated; + + if ( m_hWnd == hwndAct ) { - ProcessCommand(id); - return TRUE; + activated = true; + parent->SetActiveChild(this); + + WXHMENU hMenuChild = m_hMenu; + if ( hMenuChild ) + hMenuToSet = hMenuChild; + } + else if ( m_hWnd == hwndDeact ) + { + wxASSERT_MSG( parent->GetActiveChild() == this, + wxT("can't deactivate MDI child which wasn't active!") ); + + activated = false; + parent->SetActiveChild(NULL); + + WXHMENU hMenuParent = parent->m_hMenu; + + // activate the the parent menu only when there is no other child + // that has been activated + if ( hMenuParent && !hwndAct ) + hMenuToSet = hMenuParent; } else - return FALSE; - return TRUE; - } - else - return FALSE; -} + { + // we have nothing to do with it + return false; + } -long wxMDIChildFrame::MSWDefWindowProc(WXUINT message, WXUINT wParam, WXLPARAM lParam) -{ - if (GetHWND()) - return DefMDIChildProc((HWND) GetHWND(), (UINT) message, (WPARAM) wParam, (LPARAM) lParam); - else return 0; -} + if ( hMenuToSet ) + { + MDISetMenu(parent->GetClientWindow(), + (HMENU)hMenuToSet, GetMDIWindowMenu(parent)); + } -bool wxMDIChildFrame::MSWProcessMessage(WXMSG *msg) -{ - return FALSE; + wxActivateEvent event(wxEVT_ACTIVATE, activated, m_windowId); + event.SetEventObject( this ); + + ResetWindowStyle(NULL); + + return HandleWindowEvent(event); } -bool wxMDIChildFrame::MSWTranslateMessage(WXMSG* msg) +bool wxMDIChildFrame::HandleWindowPosChanging(void *pos) { - MSG *pMsg = (MSG *)msg; - if (m_acceleratorTable.Ok()) - { - wxFrame *parent = (wxFrame *)GetParent(); - HWND parent_hwnd = (HWND) parent->GetHWND(); - return (::TranslateAccelerator(parent_hwnd, (HACCEL) m_acceleratorTable.GetHACCEL(), pMsg) != 0); - } + WINDOWPOS *lpPos = (WINDOWPOS *)pos; + + if (!(lpPos->flags & SWP_NOSIZE)) + { + RECT rectClient; + DWORD dwExStyle = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE); + DWORD dwStyle = ::GetWindowLong(GetHwnd(), GWL_STYLE); + if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE)) + { + ::AdjustWindowRectEx(&rectClient, dwStyle, false, dwExStyle); + lpPos->x = rectClient.left; + lpPos->y = rectClient.top; + lpPos->cx = rectClient.right - rectClient.left; + lpPos->cy = rectClient.bottom - rectClient.top; + } + } - return FALSE; + return false; } -long wxMDIChildFrame::MSWOnMDIActivate(long activate, WXHWND WXUNUSED(one), WXHWND WXUNUSED(two)) +bool wxMDIChildFrame::HandleGetMinMaxInfo(void *mmInfo) { - wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); - HMENU parent_menu = (HMENU) parent->GetWinMenu(); -#if WXDEBUG > 1 - wxDebugMsg("Parent menu is %d\n", parent_menu); -#endif - HMENU child_menu = (HMENU) GetWinMenu(); -#if WXDEBUG > 1 - wxDebugMsg("Child menu is %d\n", child_menu); -#endif + MINMAXINFO *info = (MINMAXINFO *)mmInfo; - if (activate) - { -// m_active = TRUE; - parent->m_currentChild = this; - if (child_menu) + // let the default window proc calculate the size of MDI children + // frames because it is based on the size of the MDI client window, + // not on the values specified in wxWindow m_max variables + bool processed = MSWDefWindowProc(WM_GETMINMAXINFO, 0, (LPARAM)mmInfo) != 0; + + int minWidth = GetMinWidth(), + minHeight = GetMinHeight(); + + // but allow GetSizeHints() to set the min size + if ( minWidth != wxDefaultCoord ) { - parent->m_parentFrameActive = FALSE; - HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0); -#if WXDEBUG > 1 - wxDebugMsg("Window submenu is %d\n", subMenu); -#endif -// HMENU subMenu = 0; -#ifdef __WIN32__ - ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, - (WPARAM)child_menu, - (LPARAM)subMenu); -#else - ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0, - MAKELONG(child_menu, subMenu)); -#endif + info->ptMinTrackSize.x = minWidth; - ::DrawMenuBar((HWND) parent->GetHWND()); + processed = true; } - wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_windowId); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); - } - else - { - if (parent->m_currentChild == this) - parent->m_currentChild = NULL; - wxActivateEvent event(wxEVT_ACTIVATE, FALSE, m_windowId); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); - -// m_active = FALSE; - if (parent_menu) + if ( minHeight != wxDefaultCoord ) { - parent->m_parentFrameActive = TRUE; - HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0); -#if WXDEBUG > 1 - wxDebugMsg("Window submenu is %d\n", subMenu); -#endif -// HMENU subMenu = 0; -#ifdef __WIN32__ - ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, - (WPARAM)parent_menu, - (LPARAM)subMenu); -#else - ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0, - MAKELONG(parent_menu, subMenu)); -#endif + info->ptMinTrackSize.y = minHeight; - ::DrawMenuBar((HWND) parent->GetHWND()); + processed = true; } - } - bool flag = (activate != 0); - wxActivateEvent event(wxEVT_ACTIVATE, flag, m_windowId); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); -#if WXDEBUG > 1 - wxDebugMsg("Finished (de)activating\n"); -#endif - return 0; + return processed; +} + +// --------------------------------------------------------------------------- +// MDI specific message translation/preprocessing +// --------------------------------------------------------------------------- + +WXLRESULT wxMDIChildFrame::MSWDefWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) +{ + return DefMDIChildProc(GetHwnd(), + (UINT)message, (WPARAM)wParam, (LPARAM)lParam); } -void wxMDIChildFrame::MSWDestroyWindow(void) +bool wxMDIChildFrame::MSWTranslateMessage(WXMSG* msg) { - MSWDetachWindowMenu(); - invalidHandle = (HWND) GetHWND(); + // we must pass the parent frame to ::TranslateAccelerator(), otherwise it + // doesn't do its job correctly for MDI child menus + return MSWDoTranslateMessage(GetMDIParent(), msg); +} - wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); +// --------------------------------------------------------------------------- +// misc +// --------------------------------------------------------------------------- - // 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 the wxFrame is - // destroyed. +void wxMDIChildFrame::MSWDestroyWindow() +{ + wxMDIParentFrame * const parent = GetMDIParent(); - HWND oldHandle = (HWND)GetHWND(); -#if WXDEBUG > 1 - wxDebugMsg("*** About to DestroyWindow MDI child %d\n", oldHandle); -#endif -#ifdef __WIN32__ - SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (WPARAM)oldHandle, (LPARAM)0); -#else - SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (HWND)oldHandle, 0); -#endif -#if WXDEBUG > 1 - wxDebugMsg("*** Finished DestroyWindow MDI child %d\n", oldHandle); -#endif - invalidHandle = 0; + // 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 + // the wxFrame is destroyed. - if (m_hMenu) - { - ::DestroyMenu((HMENU) m_hMenu); - m_hMenu = 0; - } - m_hWnd = 0; + HWND oldHandle = (HWND)GetHWND(); + SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIDESTROY, + (WPARAM)oldHandle, 0); + + if (parent->GetActiveChild() == NULL) + ResetWindowStyle(NULL); + + if (m_hMenu) + { + ::DestroyMenu((HMENU) m_hMenu); + m_hMenu = 0; + } + wxRemoveHandleAssociation(this); + m_hWnd = 0; } -// Change the client window's extended style so we don't -// get a client edge style when a child is maximised (a double -// border looks silly.) +// Change the client window's extended style so we don't get a client edge +// 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(); - wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild(); - if (!pChild || (pChild == this)) - { - DWORD dwStyle = ::GetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE); - DWORD dwThisStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE); - DWORD dwNewStyle = dwStyle; - if (pChild != NULL && (dwThisStyle & WS_MAXIMIZE)) - dwNewStyle &= ~(WS_EX_CLIENTEDGE); - else - dwNewStyle |= WS_EX_CLIENTEDGE; - - if (dwStyle != dwNewStyle) - { - ::RedrawWindow((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); - ::SetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE, dwNewStyle); - ::SetWindowPos((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS); - if (rect) - ::GetClientRect((HWND) pFrameWnd->GetClientWindow()->GetHWND(), rect); - return TRUE; - } - } - return FALSE; -#else - return FALSE; -#endif -} + wxMDIParentFrame * const pFrameWnd = GetMDIParent(); + wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild(); -void wxMDIChildFrame::MSWOnWindowPosChanging(void *pos) -{ - WINDOWPOS *lpPos = (WINDOWPOS *)pos; -#if defined(__WIN95__) - if (!(lpPos->flags & SWP_NOSIZE)) - { - RECT rectClient; - DWORD dwExStyle = ::GetWindowLong((HWND) GetHWND(), GWL_EXSTYLE); - DWORD dwStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE); - if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE)) - { - ::AdjustWindowRectEx(&rectClient, dwStyle, FALSE, dwExStyle); - lpPos->x = rectClient.left; - lpPos->y = rectClient.top; - lpPos->cx = rectClient.right - rectClient.left; - lpPos->cy = rectClient.bottom - rectClient.top; - } - wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent(); - if (pFrameWnd && pFrameWnd->GetToolBar()) + if (!pChild || (pChild == this)) + { + HWND hwndClient = GetWinHwnd(pFrameWnd->GetClientWindow()); + DWORD dwStyle = ::GetWindowLong(hwndClient, GWL_EXSTYLE); + + // we want to test whether there is a maximized child, so just set + // dwThisStyle to 0 if there is no child at all + DWORD dwThisStyle = pChild + ? ::GetWindowLong(GetWinHwnd(pChild), GWL_STYLE) : 0; + DWORD dwNewStyle = dwStyle; + if ( dwThisStyle & WS_MAXIMIZE ) + dwNewStyle &= ~(WS_EX_CLIENTEDGE); + else + dwNewStyle |= WS_EX_CLIENTEDGE; + + if (dwStyle != dwNewStyle) { - pFrameWnd->GetToolBar()->Refresh(); + // force update of everything + ::RedrawWindow(hwndClient, NULL, NULL, + RDW_INVALIDATE | RDW_ALLCHILDREN); + ::SetWindowLong(hwndClient, GWL_EXSTYLE, dwNewStyle); + ::SetWindowPos(hwndClient, NULL, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOACTIVATE | + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | + SWP_NOCOPYBITS); + if (rect) + ::GetClientRect(hwndClient, rect); + + return true; } - } -#endif - Default(); -} + } -// Client window -wxMDIClientWindow::wxMDIClientWindow(void) -{ - m_scrollX = 0; - m_scrollY = 0; + return false; } -wxMDIClientWindow::~wxMDIClientWindow(void) -{ -} +// =========================================================================== +// wxMDIClientWindow: the window of predefined (by Windows) class which +// contains the child frames +// =========================================================================== bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style) { - m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE); - - CLIENTCREATESTRUCT ccs; - m_windowStyle = style; - m_windowParent = parent; - - ccs.hWindowMenu = (HMENU) parent->GetWindowMenu(); - ccs.idFirstChild = wxFIRST_MDI_CHILD; - - DWORD msStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN ; - if ( parent->GetWindowStyleFlag() & wxHSCROLL ) - msStyle |= WS_HSCROLL; - if ( parent->GetWindowStyleFlag() & wxVSCROLL ) - msStyle |= WS_VSCROLL ; - -#if defined(__WIN95__) - DWORD exStyle = WS_EX_CLIENTEDGE; -#else - DWORD exStyle = 0; -#endif - - wxWndHook = this; - m_hWnd = (WXHWND) ::CreateWindowEx(exStyle, "mdiclient", NULL, - msStyle, 0, 0, 0, 0, (HWND) parent->GetHWND(), NULL, - wxGetInstance(), (LPSTR)(LPCLIENTCREATESTRUCT)&ccs); - SubclassWin(m_hWnd); - wxWndHook = NULL; + m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE); + + CLIENTCREATESTRUCT ccs; + m_windowStyle = style; + m_parent = parent; + + ccs.hWindowMenu = GetMDIWindowMenu(parent); + ccs.idFirstChild = wxFIRST_MDI_CHILD; + + DWORD msStyle = MDIS_ALLCHILDSTYLES | WS_VISIBLE | WS_CHILD | + WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + + if ( style & wxHSCROLL ) + msStyle |= WS_HSCROLL; + if ( style & wxVSCROLL ) + msStyle |= WS_VSCROLL; + + DWORD exStyle = WS_EX_CLIENTEDGE; + + wxWindowCreationHook hook(this); + m_hWnd = (WXHWND)::CreateWindowEx + ( + exStyle, + wxT("MDICLIENT"), + NULL, + msStyle, + 0, 0, 0, 0, + GetWinHwnd(parent), + NULL, + wxGetInstance(), + (LPSTR)(LPCLIENTCREATESTRUCT)&ccs); + if ( !m_hWnd ) + { + wxLogLastError(wxT("CreateWindowEx(MDI client)")); - return (m_hWnd != 0) ; -} + return false; + } -// Window procedure: here for debugging purposes -long wxMDIClientWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) -{ - return wxWindow::MSWWindowProc(nMsg, wParam, lParam); -// return MSWDefWindowProc(nMsg, wParam, lParam); -} + SubclassWin(m_hWnd); -long wxMDIClientWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) -{ - if ( MSWGetOldWndProc() != 0) - return ::CallWindowProc(CASTWNDPROC (FARPROC) MSWGetOldWndProc(), (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); - else - return ::DefWindowProc((HWND) m_hWnd, (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); + return true; } // Explicitly call default scroll behaviour @@ -1225,12 +1340,195 @@ void wxMDIClientWindow::OnScroll(wxScrollEvent& event) else m_scrollY = event.GetPosition(); // Always returns zero! - Default(); + event.Skip(); } -// Should hand the message to the default proc -long wxMDIClientWindow::MSWOnMDIActivate(long bActivate, WXHWND, WXHWND) +void wxMDIClientWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) { - return Default(); + // Try to fix a problem whereby if you show an MDI child frame, then reposition the + // client area, you can end up with a non-refreshed portion in the client window + // (see OGL studio sample). So check if the position is changed and if so, + // redraw the MDI child frames. + + const wxPoint oldPos = GetPosition(); + + wxWindow::DoSetSize(x, y, width, height, sizeFlags | wxSIZE_FORCE); + + const wxPoint newPos = GetPosition(); + + if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y)) + { + if (GetParent()) + { + wxWindowList::compatibility_iterator node = GetParent()->GetChildren().GetFirst(); + while (node) + { + wxWindow *child = node->GetData(); + if (child->IsKindOf(CLASSINFO(wxMDIChildFrame))) + { + ::RedrawWindow(GetHwndOf(child), + NULL, + NULL, + RDW_FRAME | + RDW_ALLCHILDREN | + RDW_INVALIDATE); + } + node = node->GetNext(); + } + } + } } +void wxMDIChildFrame::OnIdle(wxIdleEvent& event) +{ + // wxMSW prior to 2.5.3 created MDI child frames as visible, which resulted + // in flicker e.g. when the frame contained controls with non-trivial + // layout. Since 2.5.3, the frame is created hidden as all other top level + // windows. In order to maintain backward compatibility, the frame is shown + // in OnIdle, unless Show(false) was called by the programmer before. + if ( m_needsInitialShow ) + { + Show(true); + } + + // MDI child frames get their WM_SIZE when they're constructed but at this + // moment they don't have any children yet so all child windows will be + // positioned incorrectly when they are added later - to fix this, we + // generate an artificial size event here + if ( m_needsResize ) + { + m_needsResize = false; // avoid any possibility of recursion + + SendSizeEvent(); + } + + event.Skip(); +} + +// --------------------------------------------------------------------------- +// private helper functions +// --------------------------------------------------------------------------- + +namespace +{ + +void MDISetMenu(wxWindow *win, HMENU hmenuFrame, HMENU hmenuWindow) +{ + if ( hmenuFrame || hmenuWindow ) + { + if ( !::SendMessage(GetWinHwnd(win), + WM_MDISETMENU, + (WPARAM)hmenuFrame, + (LPARAM)hmenuWindow) ) + { + DWORD err = ::GetLastError(); + if ( err ) + { + wxLogApiError(wxT("SendMessage(WM_MDISETMENU)"), err); + } + } + } + + // update menu bar of the parent window + wxWindow *parent = win->GetParent(); + wxCHECK_RET( parent, wxT("MDI client without parent frame? weird...") ); + + ::SendMessage(GetWinHwnd(win), WM_MDIREFRESHMENU, 0, 0L); + + ::DrawMenuBar(GetWinHwnd(parent)); +} + +void MDIInsertWindowMenu(wxWindow *win, WXHMENU hMenu, HMENU menuWin) +{ + HMENU hmenu = (HMENU)hMenu; + + if ( menuWin ) + { + // Try to insert Window menu in front of Help, otherwise append it. + int N = GetMenuItemCount(hmenu); + bool inserted = false; + for ( int i = 0; i < N; i++ ) + { + wxChar buf[256]; + if ( !::GetMenuString(hmenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION) ) + { + wxLogLastError(wxT("GetMenuString")); + + continue; + } + + const wxString label = wxStripMenuCodes(buf); + if ( label == wxGetStockLabel(wxID_HELP, wxSTOCK_NOFLAGS) ) + { + inserted = true; + ::InsertMenu(hmenu, i, MF_BYPOSITION | MF_POPUP | MF_STRING, + (UINT_PTR)menuWin, + wxString(wxGetTranslation(WINDOW_MENU_LABEL)).wx_str()); + break; + } + } + + if ( !inserted ) + { + ::AppendMenu(hmenu, MF_POPUP, + (UINT_PTR)menuWin, + wxString(wxGetTranslation(WINDOW_MENU_LABEL)).wx_str()); + } + } + + MDISetMenu(win, hmenu, menuWin); +} + +void MDIRemoveWindowMenu(wxWindow *win, WXHMENU hMenu) +{ + HMENU hmenu = (HMENU)hMenu; + + if ( hmenu ) + { + wxChar buf[1024]; + + int N = ::GetMenuItemCount(hmenu); + for ( int i = 0; i < N; i++ ) + { + if ( !::GetMenuString(hmenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION) ) + { + // Ignore successful read of menu string with length 0 which + // occurs, for example, for a maximized MDI child system menu + if ( ::GetLastError() != 0 ) + { + wxLogLastError(wxT("GetMenuString")); + } + + continue; + } + + if ( wxStrcmp(buf, wxGetTranslation(WINDOW_MENU_LABEL)) == 0 ) + { + if ( !::RemoveMenu(hmenu, i, MF_BYPOSITION) ) + { + wxLogLastError(wxT("RemoveMenu")); + } + + break; + } + } + } + + if ( win ) + { + // we don't change the windows menu, but we update the main one + MDISetMenu(win, hmenu, NULL); + } +} + +void UnpackMDIActivate(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *activate, WXHWND *hwndAct, WXHWND *hwndDeact) +{ + *activate = true; + *hwndAct = (WXHWND)lParam; + *hwndDeact = (WXHWND)wParam; +} + +} // anonymous namespace + +#endif // wxUSE_MDI && !defined(__WXUNIVERSAL__)