1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/mdi.cpp 
   3 // Purpose:     MDI classes for wxMSW 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  21     #pragma implementation "mdi.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  37     #include "wx/dialog.h" 
  39         #include "wx/statusbr.h" 
  41     #include "wx/settings.h" 
  47 #include "wx/msw/private.h" 
  49 #if wxUSE_STATUSBAR && wxUSE_NATIVE_STATUSBAR 
  50     #include "wx/msw/statbr95.h" 
  54     #include "wx/toolbar.h" 
  55 #endif // wxUSE_TOOLBAR 
  59 // --------------------------------------------------------------------------- 
  61 // --------------------------------------------------------------------------- 
  63 extern wxWindowList wxModelessWindows
;      // from dialog.cpp 
  64 extern wxMenu 
*wxCurrentPopupMenu
; 
  66 extern const wxChar 
*wxMDIFrameClassName
;   // from app.cpp 
  67 extern const wxChar 
*wxMDIChildFrameClassName
; 
  68 extern const wxChar 
*wxMDIChildFrameClassNameNoRedraw
; 
  70 extern void wxAssociateWinWithHandle(HWND hWnd
, wxWindow 
*win
); 
  71 extern void wxRemoveHandleAssociation(wxWindow 
*win
); 
  73 static HWND invalidHandle 
= 0; 
  75 // --------------------------------------------------------------------------- 
  77 // --------------------------------------------------------------------------- 
  79 static const int IDM_WINDOWTILE  
= 4001; 
  80 static const int IDM_WINDOWTILEHOR  
= 4001; 
  81 static const int IDM_WINDOWCASCADE 
= 4002; 
  82 static const int IDM_WINDOWICONS 
= 4003; 
  83 static const int IDM_WINDOWNEXT 
= 4004; 
  84 static const int IDM_WINDOWTILEVERT 
= 4005; 
  86 // This range gives a maximum of 500 MDI children. Should be enough :-) 
  87 static const int wxFIRST_MDI_CHILD 
= 4100; 
  88 static const int wxLAST_MDI_CHILD 
= 4600; 
  90 // Status border dimensions 
  91 static const int wxTHICK_LINE_BORDER 
= 3; 
  92 static const int wxTHICK_LINE_WIDTH  
= 1; 
  94 // --------------------------------------------------------------------------- 
  96 // --------------------------------------------------------------------------- 
  98 // set the MDI menus (by sending the WM_MDISETMENU message) and update the menu 
  99 // of the parent of win (which is supposed to be the MDI client window) 
 100 static void MDISetMenu(wxWindow 
*win
, HMENU hmenuFrame
, HMENU hmenuWindow
); 
 102 // insert the window menu (subMenu) into menu just before "Help" submenu or at 
 103 // the very end if not found 
 104 static void InsertWindowMenu(wxWindow 
*win
, WXHMENU menu
, HMENU subMenu
); 
 106 // Remove the window menu 
 107 static void RemoveWindowMenu(wxWindow 
*win
, WXHMENU menu
); 
 109 // is this an id of an MDI child? 
 110 inline bool IsMdiCommandId(int id
) 
 112     return (id 
>= wxFIRST_MDI_CHILD
) && (id 
<= wxLAST_MDI_CHILD
); 
 115 // unpack the parameters of WM_MDIACTIVATE message 
 116 static void UnpackMDIActivate(WXWPARAM wParam
, WXLPARAM lParam
, 
 117                               WXWORD 
*activate
, WXHWND 
*hwndAct
, WXHWND 
*hwndDeact
); 
 119 // return the HMENU of the MDI menu 
 120 static inline HMENU 
GetMDIWindowMenu(wxMDIParentFrame 
*frame
) 
 122     wxMenu 
*menu 
= frame
->GetWindowMenu(); 
 123     return menu 
? GetHmenuOf(menu
) : 0; 
 126 // =========================================================================== 
 128 // =========================================================================== 
 130 // --------------------------------------------------------------------------- 
 132 // --------------------------------------------------------------------------- 
 134 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
) 
 135 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
) 
 136 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
) 
 138 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
) 
 139     EVT_SIZE(wxMDIParentFrame::OnSize
) 
 140     EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
) 
 143 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 144     EVT_IDLE(wxMDIChildFrame::OnIdle
) 
 147 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxWindow
) 
 148     EVT_SCROLL(wxMDIClientWindow::OnScroll
) 
 151 // =========================================================================== 
 152 // wxMDIParentFrame: the frame which contains the client window which manages 
 154 // =========================================================================== 
 156 wxMDIParentFrame::wxMDIParentFrame() 
 158     m_clientWindow 
= NULL
; 
 159     m_currentChild 
= NULL
; 
 160     m_windowMenu 
= (wxMenu
*) NULL
; 
 161     m_parentFrameActive 
= TRUE
; 
 164 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
 166                               const wxString
& title
, 
 170                               const wxString
& name
) 
 172   m_clientWindow 
= NULL
; 
 173   m_currentChild 
= NULL
; 
 175   // this style can be used to prevent a window from having the standard MDI 
 177   if ( style 
& wxFRAME_NO_WINDOW_MENU 
) 
 179       m_windowMenu 
= (wxMenu 
*)NULL
; 
 181   else // normal case: we have the window menu, so construct it 
 183       m_windowMenu 
= new wxMenu
; 
 185       m_windowMenu
->Append(IDM_WINDOWCASCADE
, _("&Cascade")); 
 186       m_windowMenu
->Append(IDM_WINDOWTILEHOR
, _("Tile &Horizontally")); 
 187       m_windowMenu
->Append(IDM_WINDOWTILEVERT
, _("Tile &Vertically")); 
 188       m_windowMenu
->AppendSeparator(); 
 189       m_windowMenu
->Append(IDM_WINDOWICONS
, _("&Arrange Icons")); 
 190       m_windowMenu
->Append(IDM_WINDOWNEXT
, _("&Next")); 
 193   m_parentFrameActive 
= TRUE
; 
 196     wxTopLevelWindows
.Append(this); 
 199   m_windowStyle 
= style
; 
 202       parent
->AddChild(this); 
 207     m_windowId 
= NewControlId(); 
 210   long msflags 
= MSWGetCreateWindowFlags(&exflags
); 
 212   if ( !wxWindow::MSWCreate(wxMDIFrameClassName
, 
 221   wxModelessWindows
.Append(this); 
 223   // unlike (almost?) all other windows, frames are created hidden 
 229 wxMDIParentFrame::~wxMDIParentFrame() 
 233     // already delete by DestroyChildren() 
 234     m_frameToolBar 
= NULL
; 
 235     m_frameStatusBar 
= NULL
; 
 240         m_windowMenu 
= (wxMenu
*) NULL
; 
 243     // the MDI frame menubar is not automatically deleted by Windows unlike for 
 247         ::DestroyMenu((HMENU
)m_hMenu
); 
 251     if ( m_clientWindow 
) 
 253         if ( m_clientWindow
->MSWGetOldWndProc() ) 
 254             m_clientWindow
->UnsubclassWin(); 
 256         m_clientWindow
->SetHWND(0); 
 257         delete m_clientWindow
; 
 261 #if wxUSE_MENUS_NATIVE 
 263 void wxMDIParentFrame::InternalSetMenuBar() 
 265     m_parentFrameActive 
= TRUE
; 
 267     InsertWindowMenu(GetClientWindow(), m_hMenu
, GetMDIWindowMenu(this)); 
 270 #endif // wxUSE_MENUS_NATIVE 
 272 void wxMDIParentFrame::SetWindowMenu(wxMenu
* menu
) 
 278             // Remove old window menu 
 279             RemoveWindowMenu(GetClientWindow(), m_hMenu
); 
 283         m_windowMenu 
= (wxMenu
*) NULL
; 
 291             InsertWindowMenu(GetClientWindow(), m_hMenu
, 
 292                              GetHmenuOf(m_windowMenu
)); 
 297 void wxMDIParentFrame::OnSize(wxSizeEvent
&) 
 299     if ( GetClientWindow() ) 
 302         GetClientSize(&width
, &height
); 
 304         GetClientWindow()->SetSize(0, 0, width
, height
); 
 308 // Returns the active MDI child window 
 309 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 311     HWND hWnd 
= (HWND
)::SendMessage(GetWinHwnd(GetClientWindow()), 
 312                                     WM_MDIGETACTIVE
, 0, 0L); 
 316         return (wxMDIChildFrame 
*)wxFindWinFromHandle((WXHWND
) hWnd
); 
 319 // Create the client window class (don't Create the window, just return a new 
 321 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 323     return new wxMDIClientWindow
; 
 326 // Responds to colour changes, and passes event on to children. 
 327 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
 329     if ( m_clientWindow 
) 
 331         m_clientWindow
->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
)); 
 332         m_clientWindow
->Refresh(); 
 338 WXHICON 
wxMDIParentFrame::GetDefaultIcon() const 
 340     return (WXHICON
)(wxSTD_MDIPARENTFRAME_ICON 
? wxSTD_MDIPARENTFRAME_ICON
 
 341                                                : wxDEFAULT_MDIPARENTFRAME_ICON
); 
 344 // --------------------------------------------------------------------------- 
 346 // --------------------------------------------------------------------------- 
 348 void wxMDIParentFrame::Cascade() 
 350     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDICASCADE
, 0, 0); 
 353 // TODO: add a direction argument (hor/vert) 
 354 void wxMDIParentFrame::Tile() 
 356     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDITILE
, MDITILE_HORIZONTAL
, 0); 
 359 void wxMDIParentFrame::ArrangeIcons() 
 361     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDIICONARRANGE
, 0, 0); 
 364 void wxMDIParentFrame::ActivateNext() 
 366     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 0); 
 369 void wxMDIParentFrame::ActivatePrevious() 
 371     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 1); 
 374 // --------------------------------------------------------------------------- 
 375 // the MDI parent frame window proc 
 376 // --------------------------------------------------------------------------- 
 378 long wxMDIParentFrame::MSWWindowProc(WXUINT message
, 
 383     bool processed 
= FALSE
; 
 389                 WXWORD state
, minimized
; 
 391                 UnpackActivate(wParam
, lParam
, &state
, &minimized
, &hwnd
); 
 393                 processed 
= HandleActivate(state
, minimized 
!= 0, hwnd
); 
 401                 UnpackCommand(wParam
, lParam
, &id
, &hwnd
, &cmd
); 
 403                 (void)HandleCommand(id
, cmd
, hwnd
); 
 405                 // even if the frame didn't process it, there is no need to try it 
 406                 // once again (i.e. call wxFrame::HandleCommand()) - we just dud it, 
 407                 // so pretend we processed the message anyhow 
 411             // always pass this message DefFrameProc(), otherwise MDI menu 
 412             // commands (and sys commands - more surprizingly!) won't work 
 413             MSWDefWindowProc(message
, wParam
, lParam
); 
 417             m_clientWindow 
= OnCreateClient(); 
 418             // Uses own style for client style 
 419             if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) ) 
 421                 wxLogMessage(_("Failed to create MDI parent frame.")); 
 432             // we erase background ourselves 
 440                 UnpackMenuSelect(wParam
, lParam
, &item
, &flags
, &hmenu
); 
 442                 if ( m_parentFrameActive 
) 
 444                     processed 
= HandleMenuSelect(item
, flags
, hmenu
); 
 446                 else if (m_currentChild
) 
 448                     processed 
= m_currentChild
-> 
 449                         HandleMenuSelect(item
, flags
, hmenu
); 
 455             // as we don't (usually) resize the MDI client to exactly fit the 
 456             // client area (we put it below the toolbar, above statusbar &c), 
 457             // we should not pass this one to DefFrameProc 
 462         rc 
= wxFrame::MSWWindowProc(message
, wParam
, lParam
); 
 467 bool wxMDIParentFrame::HandleActivate(int state
, bool minimized
, WXHWND activate
) 
 469     bool processed 
= FALSE
; 
 471     if ( wxWindow::HandleActivate(state
, minimized
, activate
) ) 
 477     // If this window is an MDI parent, we must also send an OnActivate message 
 478     // to the current child. 
 479     if ( (m_currentChild 
!= NULL
) && 
 480          ((state 
== WA_ACTIVE
) || (state 
== WA_CLICKACTIVE
)) ) 
 482         wxActivateEvent 
event(wxEVT_ACTIVATE
, TRUE
, m_currentChild
->GetId()); 
 483         event
.SetEventObject( m_currentChild 
); 
 484         if ( m_currentChild
->GetEventHandler()->ProcessEvent(event
) ) 
 491 bool wxMDIParentFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
) 
 493     // In case it's e.g. a toolbar. 
 496         wxWindow 
*win 
= wxFindWinFromHandle(hwnd
); 
 498             return win
->MSWCommand(cmd
, id
); 
 501     // is it one of standard MDI commands? 
 506         case IDM_WINDOWCASCADE
: 
 508             wParam 
= MDITILE_SKIPDISABLED
; 
 511         case IDM_WINDOWTILEHOR
: 
 512             wParam 
|= MDITILE_HORIZONTAL
; 
 515         case IDM_WINDOWTILEVERT
: 
 517                 wParam 
= MDITILE_VERTICAL
; 
 519             wParam 
|= MDITILE_SKIPDISABLED
; 
 522         case IDM_WINDOWICONS
: 
 523             msg 
= WM_MDIICONARRANGE
; 
 536         ::SendMessage(GetWinHwnd(GetClientWindow()), msg
, wParam
, 0); 
 541     // FIXME VZ: what does this test do?? 
 544         return FALSE
; // Get WndProc to call default proc 
 547     if ( IsMdiCommandId(id
) ) 
 549         wxWindowList::Node
* node 
= GetChildren().GetFirst(); 
 552             wxWindow
* child 
= node
->GetData(); 
 553             if ( child
->GetHWND() ) 
 555                 long childId 
= wxGetWindowId(child
->GetHWND()); 
 556                 if (childId 
== (long)id
) 
 558                     ::SendMessage( GetWinHwnd(GetClientWindow()), 
 560                                    (WPARAM
)child
->GetHWND(), 0); 
 564             node 
= node
->GetNext(); 
 567     else if ( m_parentFrameActive 
) 
 569         return ProcessCommand(id
); 
 571     else if ( m_currentChild 
) 
 573         return m_currentChild
->HandleCommand(id
, cmd
, hwnd
); 
 577         // this shouldn't happen because it means that our messages are being 
 578         // lost (they're not sent to the parent frame nor to the children) 
 579         wxFAIL_MSG(wxT("MDI parent frame is not active, yet there is no active MDI child?")); 
 585 long wxMDIParentFrame::MSWDefWindowProc(WXUINT message
, 
 590     if ( GetClientWindow() ) 
 591         clientWnd 
= GetClientWindow()->GetHWND(); 
 595     return DefFrameProc(GetHwnd(), (HWND
)clientWnd
, message
, wParam
, lParam
); 
 598 bool wxMDIParentFrame::MSWTranslateMessage(WXMSG
* msg
) 
 600     MSG 
*pMsg 
= (MSG 
*)msg
; 
 602     // first let the current child get it 
 603     if ( m_currentChild 
&& m_currentChild
->GetHWND() && 
 604          m_currentChild
->MSWTranslateMessage(msg
) ) 
 609     // then try out accel table (will also check the menu accels) 
 610     if ( wxFrame::MSWTranslateMessage(msg
) ) 
 615     // finally, check for MDI specific built in accel keys 
 616     if ( pMsg
->message 
== WM_KEYDOWN 
|| pMsg
->message 
== WM_SYSKEYDOWN 
) 
 618         if ( ::TranslateMDISysAccel(GetWinHwnd(GetClientWindow()), pMsg
)) 
 625 // =========================================================================== 
 627 // =========================================================================== 
 629 void wxMDIChildFrame::Init() 
 631     m_needsResize 
= TRUE
; 
 634 bool wxMDIChildFrame::Create(wxMDIParentFrame 
*parent
, 
 636                              const wxString
& title
, 
 640                              const wxString
& name
) 
 643   wxWindowBase::Show(TRUE
); // MDI child frame starts off shown 
 648     m_windowId 
= (int)NewControlId(); 
 652       parent
->AddChild(this); 
 662   mcs
.szClass 
= style 
& wxNO_FULL_REPAINT_ON_RESIZE
 
 663                     ? wxMDIChildFrameClassNameNoRedraw
 
 664                     : wxMDIChildFrameClassName
; 
 666   mcs
.hOwner 
= wxGetInstance(); 
 670       mcs
.x 
= CW_USEDEFAULT
; 
 675       mcs
.y 
= CW_USEDEFAULT
; 
 680       mcs
.cx 
= CW_USEDEFAULT
; 
 685       mcs
.cy 
= CW_USEDEFAULT
; 
 687   DWORD msflags 
= WS_OVERLAPPED 
| WS_CLIPCHILDREN 
| WS_THICKFRAME 
| WS_VISIBLE 
; 
 688   if (style 
& wxMINIMIZE_BOX
) 
 689     msflags 
|= WS_MINIMIZEBOX
; 
 690   if (style 
& wxMAXIMIZE_BOX
) 
 691     msflags 
|= WS_MAXIMIZEBOX
; 
 692   if (style 
& wxTHICK_FRAME
) 
 693     msflags 
|= WS_THICKFRAME
; 
 694   if (style 
& wxSYSTEM_MENU
) 
 695     msflags 
|= WS_SYSMENU
; 
 696   if ((style 
& wxMINIMIZE
) || (style 
& wxICONIZE
)) 
 697     msflags 
|= WS_MINIMIZE
; 
 698   if (style 
& wxMAXIMIZE
) 
 699     msflags 
|= WS_MAXIMIZE
; 
 700   if (style 
& wxCAPTION
) 
 701     msflags 
|= WS_CAPTION
; 
 707   wxWindowCreationHook 
hook(this); 
 709   m_hWnd 
= (WXHWND
)::SendMessage(GetWinHwnd(parent
->GetClientWindow()), 
 710                                  WM_MDICREATE
, 0, (LONG
)(LPSTR
)&mcs
); 
 712   wxAssociateWinWithHandle((HWND
) GetHWND(), this); 
 714   wxModelessWindows
.Append(this); 
 719 wxMDIChildFrame::~wxMDIChildFrame() 
 723     // already deleted by DestroyChildren() 
 724     m_frameToolBar 
= NULL
; 
 725     m_frameStatusBar 
= NULL
; 
 727     RemoveWindowMenu(NULL
, m_hMenu
); 
 732 // Set the client size (i.e. leave the calculation of borders etc. 
 734 void wxMDIChildFrame::DoSetClientSize(int width
, int height
) 
 736   HWND hWnd 
= GetHwnd(); 
 739   ::GetClientRect(hWnd
, &rect
); 
 742   GetWindowRect(hWnd
, &rect2
); 
 744   // Find the difference between the entire window (title bar and all) 
 745   // and the client area; add this to the new client size to move the 
 747   int actual_width 
= rect2
.right 
- rect2
.left 
- rect
.right 
+ width
; 
 748   int actual_height 
= rect2
.bottom 
- rect2
.top 
- rect
.bottom 
+ height
; 
 750   if (GetStatusBar() && GetStatusBar()->IsShown()) 
 753     GetStatusBar()->GetSize(&sx
, &sy
); 
 758   point
.x 
= rect2
.left
; 
 761   // If there's an MDI parent, must subtract the parent's top left corner 
 762   // since MoveWindow moves relative to the parent 
 763   wxMDIParentFrame 
*mdiParent 
= (wxMDIParentFrame 
*)GetParent(); 
 764   ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
); 
 766   MoveWindow(hWnd
, point
.x
, point
.y
, actual_width
, actual_height
, (BOOL
)TRUE
); 
 768   wxSizeEvent 
event(wxSize(width
, height
), m_windowId
); 
 769   event
.SetEventObject( this ); 
 770   GetEventHandler()->ProcessEvent(event
); 
 773 void wxMDIChildFrame::DoGetPosition(int *x
, int *y
) const 
 776   GetWindowRect(GetHwnd(), &rect
); 
 781   // Since we now have the absolute screen coords, 
 782   // if there's a parent we must subtract its top left corner 
 783   wxMDIParentFrame 
*mdiParent 
= (wxMDIParentFrame 
*)GetParent(); 
 784   ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
); 
 790 void wxMDIChildFrame::InternalSetMenuBar() 
 792     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 794     InsertWindowMenu(parent
->GetClientWindow(), 
 795                      m_hMenu
, GetMDIWindowMenu(parent
)); 
 797     parent
->m_parentFrameActive 
= FALSE
; 
 800 WXHICON 
wxMDIChildFrame::GetDefaultIcon() const 
 802     return (WXHICON
)(wxSTD_MDICHILDFRAME_ICON 
? wxSTD_MDICHILDFRAME_ICON
 
 803                                               : wxDEFAULT_MDICHILDFRAME_ICON
); 
 806 // --------------------------------------------------------------------------- 
 808 // --------------------------------------------------------------------------- 
 810 void wxMDIChildFrame::Maximize(bool maximize
) 
 812     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 813     if ( parent 
&& parent
->GetClientWindow() ) 
 815         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), 
 816                       maximize 
? WM_MDIMAXIMIZE 
: WM_MDIRESTORE
, 
 817                       (WPARAM
)GetHwnd(), 0); 
 821 void wxMDIChildFrame::Restore() 
 823     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 824     if ( parent 
&& parent
->GetClientWindow() ) 
 826         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIRESTORE
, 
 827                       (WPARAM
) GetHwnd(), 0); 
 831 void wxMDIChildFrame::Activate() 
 833     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 834     if ( parent 
&& parent
->GetClientWindow() ) 
 836         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIACTIVATE
, 
 837                       (WPARAM
) GetHwnd(), 0); 
 841 // --------------------------------------------------------------------------- 
 842 // MDI window proc and message handlers 
 843 // --------------------------------------------------------------------------- 
 845 long wxMDIChildFrame::MSWWindowProc(WXUINT message
, 
 850     bool processed 
= FALSE
; 
 858                 UnpackCommand((WXWPARAM
)wParam
, (WXLPARAM
)lParam
, 
 861                 processed 
= HandleCommand(id
, cmd
, (WXHWND
)hwnd
); 
 865         case WM_GETMINMAXINFO
: 
 866             processed 
= HandleGetMinMaxInfo((MINMAXINFO 
*)lParam
); 
 872                 WXHWND hwndAct
, hwndDeact
; 
 873                 UnpackMDIActivate(wParam
, lParam
, &act
, &hwndAct
, &hwndDeact
); 
 875                 processed 
= HandleMDIActivate(act
, hwndAct
, hwndDeact
); 
 880             // must pass WM_MOVE to DefMDIChildProc() to recalculate MDI client 
 881             // scrollbars if necessary 
 886             // must pass WM_SIZE to DefMDIChildProc(), otherwise many weird 
 888             MSWDefWindowProc(message
, wParam
, lParam
); 
 892             // DefMDIChildProc handles SC_{NEXT/PREV}WINDOW here, so pass it 
 893             // the message (the base class version does not) 
 894             return MSWDefWindowProc(message
, wParam
, lParam
); 
 896         case WM_WINDOWPOSCHANGING
: 
 897             processed 
= HandleWindowPosChanging((LPWINDOWPOS
)lParam
); 
 902         rc 
= wxFrame::MSWWindowProc(message
, wParam
, lParam
); 
 907 bool wxMDIChildFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
) 
 909     // In case it's e.g. a toolbar. 
 912         wxWindow 
*win 
= wxFindWinFromHandle(hwnd
); 
 914             return win
->MSWCommand(cmd
, id
); 
 917     if (wxCurrentPopupMenu
) 
 919         wxMenu 
*popupMenu 
= wxCurrentPopupMenu
; 
 920         wxCurrentPopupMenu 
= NULL
; 
 921         if (popupMenu
->MSWCommand(cmd
, id
)) 
 926     if (GetMenuBar() && GetMenuBar()->FindItem(id
)) 
 928         processed 
= ProcessCommand(id
); 
 938 bool wxMDIChildFrame::HandleMDIActivate(long WXUNUSED(activate
), 
 942     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 948     if ( m_hWnd 
== hwndAct 
) 
 951         parent
->m_currentChild 
= this; 
 953         HMENU child_menu 
= (HMENU
)GetWinMenu(); 
 956             parent
->m_parentFrameActive 
= FALSE
; 
 958             menuToSet 
= child_menu
; 
 961     else if ( m_hWnd 
== hwndDeact 
) 
 963         wxASSERT_MSG( parent
->m_currentChild 
== this, 
 964                       wxT("can't deactivate MDI child which wasn't active!") ); 
 967         parent
->m_currentChild 
= NULL
; 
 969         HMENU parent_menu 
= (HMENU
)parent
->GetWinMenu(); 
 971         // activate the the parent menu only when there is no other child 
 972         // that has been activated 
 973         if ( parent_menu 
&& !hwndAct 
) 
 975             parent
->m_parentFrameActive 
= TRUE
; 
 977             menuToSet 
= parent_menu
; 
 982         // we have nothing to do with it 
 988         MDISetMenu(parent
->GetClientWindow(), 
 989                    menuToSet
, GetMDIWindowMenu(parent
)); 
 992     wxActivateEvent 
event(wxEVT_ACTIVATE
, activated
, m_windowId
); 
 993     event
.SetEventObject( this ); 
 995     ResetWindowStyle((void *)NULL
); 
 997     return GetEventHandler()->ProcessEvent(event
); 
1000 bool wxMDIChildFrame::HandleWindowPosChanging(void *pos
) 
1002     WINDOWPOS 
*lpPos 
= (WINDOWPOS 
*)pos
; 
1003 #if defined(__WIN95__) 
1004     if (!(lpPos
->flags 
& SWP_NOSIZE
)) 
1007         DWORD dwExStyle 
= ::GetWindowLong(GetHwnd(), GWL_EXSTYLE
); 
1008         DWORD dwStyle 
= ::GetWindowLong(GetHwnd(), GWL_STYLE
); 
1009         if (ResetWindowStyle((void *) & rectClient
) && (dwStyle 
& WS_MAXIMIZE
)) 
1011             ::AdjustWindowRectEx(&rectClient
, dwStyle
, FALSE
, dwExStyle
); 
1012             lpPos
->x 
= rectClient
.left
; 
1013             lpPos
->y 
= rectClient
.top
; 
1014             lpPos
->cx 
= rectClient
.right 
- rectClient
.left
; 
1015             lpPos
->cy 
= rectClient
.bottom 
- rectClient
.top
; 
1017         wxMDIParentFrame
* pFrameWnd 
= (wxMDIParentFrame 
*)GetParent(); 
1018         if (pFrameWnd 
&& pFrameWnd
->GetToolBar() && pFrameWnd
->GetToolBar()->IsShown()) 
1020             pFrameWnd
->GetToolBar()->Refresh(); 
1028 bool wxMDIChildFrame::HandleGetMinMaxInfo(void *mmInfo
) 
1030     MINMAXINFO 
*info 
= (MINMAXINFO 
*)mmInfo
; 
1032     // let the default window proc calculate the size of MDI children 
1033     // frames because it is based on the size of the MDI client window, 
1034     // not on the values specified in wxWindow m_max variables 
1035     bool processed 
= MSWDefWindowProc(WM_GETMINMAXINFO
, 0, (LPARAM
)mmInfo
) != 0; 
1037     // but allow GetSizeHints() to set the min size 
1038     if ( m_minWidth 
!= -1 ) 
1040         info
->ptMinTrackSize
.x 
= m_minWidth
; 
1045     if ( m_minHeight 
!= -1 ) 
1047         info
->ptMinTrackSize
.y 
= m_minHeight
; 
1055 // --------------------------------------------------------------------------- 
1056 // MDI specific message translation/preprocessing 
1057 // --------------------------------------------------------------------------- 
1059 long wxMDIChildFrame::MSWDefWindowProc(WXUINT message
, WXUINT wParam
, WXLPARAM lParam
) 
1061     return DefMDIChildProc(GetHwnd(), 
1062                            (UINT
)message
, (WPARAM
)wParam
, (LPARAM
)lParam
); 
1065 bool wxMDIChildFrame::MSWTranslateMessage(WXMSG
* msg
) 
1067     return wxFrame::MSWTranslateMessage(msg
); 
1070 // --------------------------------------------------------------------------- 
1072 // --------------------------------------------------------------------------- 
1074 void wxMDIChildFrame::MSWDestroyWindow() 
1076     invalidHandle 
= GetHwnd(); 
1078     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
1080     // Must make sure this handle is invalidated (set to NULL) since all sorts 
1081     // of things could happen after the child client is destroyed, but before 
1082     // the wxFrame is destroyed. 
1084     HWND oldHandle 
= (HWND
)GetHWND(); 
1085     SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIDESTROY
, 
1086                 (WPARAM
)oldHandle
, 0); 
1088     if (parent
->GetActiveChild() == (wxMDIChildFrame
*) NULL
) 
1089         ResetWindowStyle((void*) NULL
); 
1095         ::DestroyMenu((HMENU
) m_hMenu
); 
1098     wxRemoveHandleAssociation(this); 
1102 // Change the client window's extended style so we don't get a client edge 
1103 // style when a child is maximised (a double border looks silly.) 
1104 bool wxMDIChildFrame::ResetWindowStyle(void *vrect
) 
1106 #if defined(__WIN95__) 
1107     RECT 
*rect 
= (RECT 
*)vrect
; 
1108     wxMDIParentFrame
* pFrameWnd 
= (wxMDIParentFrame 
*)GetParent(); 
1109     wxMDIChildFrame
* pChild 
= pFrameWnd
->GetActiveChild(); 
1110     if (!pChild 
|| (pChild 
== this)) 
1112         HWND hwndClient 
= GetWinHwnd(pFrameWnd
->GetClientWindow()); 
1113         DWORD dwStyle 
= ::GetWindowLong(hwndClient
, GWL_EXSTYLE
); 
1115         // we want to test whether there is a maximized child, so just set 
1116         // dwThisStyle to 0 if there is no child at all 
1117         DWORD dwThisStyle 
= pChild
 
1118             ? ::GetWindowLong(GetWinHwnd(pChild
), GWL_STYLE
) : 0; 
1119         DWORD dwNewStyle 
= dwStyle
; 
1120         if ( dwThisStyle 
& WS_MAXIMIZE 
) 
1121             dwNewStyle 
&= ~(WS_EX_CLIENTEDGE
); 
1123             dwNewStyle 
|= WS_EX_CLIENTEDGE
; 
1125         if (dwStyle 
!= dwNewStyle
) 
1127             // force update of everything 
1128             ::RedrawWindow(hwndClient
, NULL
, NULL
, 
1129                            RDW_INVALIDATE 
| RDW_ALLCHILDREN
); 
1130             ::SetWindowLong(hwndClient
, GWL_EXSTYLE
, dwNewStyle
); 
1131             ::SetWindowPos(hwndClient
, NULL
, 0, 0, 0, 0, 
1132                            SWP_FRAMECHANGED 
| SWP_NOACTIVATE 
| 
1133                            SWP_NOMOVE 
| SWP_NOSIZE 
| SWP_NOZORDER 
| 
1136                 ::GetClientRect(hwndClient
, rect
); 
1146 // =========================================================================== 
1147 // wxMDIClientWindow: the window of predefined (by Windows) class which 
1148 // contains the child frames 
1149 // =========================================================================== 
1151 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame 
*parent
, long style
) 
1153     m_backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
); 
1155     CLIENTCREATESTRUCT ccs
; 
1156     m_windowStyle 
= style
; 
1159     ccs
.hWindowMenu 
= GetMDIWindowMenu(parent
); 
1160     ccs
.idFirstChild 
= wxFIRST_MDI_CHILD
; 
1162     DWORD msStyle 
= MDIS_ALLCHILDSTYLES 
| WS_VISIBLE 
| WS_CHILD 
| 
1163                     WS_CLIPCHILDREN 
| WS_CLIPSIBLINGS
; 
1165     if ( style 
& wxHSCROLL 
) 
1166         msStyle 
|= WS_HSCROLL
; 
1167     if ( style 
& wxVSCROLL 
) 
1168         msStyle 
|= WS_VSCROLL
; 
1170 #if defined(__WIN95__) 
1171     DWORD exStyle 
= WS_EX_CLIENTEDGE
; 
1176     wxWindowCreationHook 
hook(this); 
1177     m_hWnd 
= (WXHWND
)::CreateWindowEx
 
1187                         (LPSTR
)(LPCLIENTCREATESTRUCT
)&ccs
); 
1190         wxLogLastError(wxT("CreateWindowEx(MDI client)")); 
1195     SubclassWin(m_hWnd
); 
1200 // Explicitly call default scroll behaviour 
1201 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
) 
1203     // Note: for client windows, the scroll position is not set in 
1204     // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what 
1205     // scroll position we're at. 
1206     // This makes it hard to paint patterns or bitmaps in the background, 
1207     // and have the client area scrollable as well. 
1209     if ( event
.GetOrientation() == wxHORIZONTAL 
) 
1210         m_scrollX 
= event
.GetPosition(); // Always returns zero! 
1212         m_scrollY 
= event
.GetPosition(); // Always returns zero! 
1217 void wxMDIClientWindow::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
1219     // Try to fix a problem whereby if you show an MDI child frame, then reposition the 
1220     // client area, you can end up with a non-refreshed portion in the client window 
1221     // (see OGL studio sample). So check if the position is changed and if so, 
1222     // redraw the MDI child frames. 
1224     wxPoint oldPos 
= GetPosition(); 
1226     wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
); 
1228     wxPoint newPos 
= GetPosition(); 
1230     if ((newPos
.x 
!= oldPos
.x
) || (newPos
.y 
!= oldPos
.y
)) 
1234             wxNode
* node 
= GetParent()->GetChildren().First(); 
1237                 wxWindow
* child 
= (wxWindow
*) node
->Data(); 
1238                 if (child
->IsKindOf(CLASSINFO(wxMDIChildFrame
))) 
1240                     HWND hWnd 
= (HWND
) child
->GetHWND(); 
1241                    ::RedrawWindow(hWnd
, NULL
, NULL
, RDW_FRAME
|RDW_ALLCHILDREN
|RDW_INVALIDATE 
); 
1243                 node 
= node
->Next(); 
1249 void wxMDIChildFrame::OnIdle(wxIdleEvent
& event
) 
1251     // MDI child frames get their WM_SIZE when they're constructed but at this 
1252     // moment they don't have any children yet so all child windows will be 
1253     // positioned incorrectly when they are added later - to fix this, we 
1254     // generate an artificial size event here 
1255     if ( m_needsResize 
) 
1257         m_needsResize 
= FALSE
; // avoid any possibility of recursion 
1265 // --------------------------------------------------------------------------- 
1266 // non member functions 
1267 // --------------------------------------------------------------------------- 
1269 static void MDISetMenu(wxWindow 
*win
, HMENU hmenuFrame
, HMENU hmenuWindow
) 
1271     ::SendMessage(GetWinHwnd(win
), WM_MDISETMENU
, 
1273                   (WPARAM
)hmenuFrame
, (LPARAM
)hmenuWindow
 
1275                   0, MAKELPARAM(hmenuFrame
, hmenuWindow
) 
1279     // update menu bar of the parent window 
1280     wxWindow 
*parent 
= win
->GetParent(); 
1281     wxCHECK_RET( parent
, wxT("MDI client without parent frame? weird...") ); 
1284     ::SendMessage(GetWinHwnd(win
), WM_MDIREFRESHMENU
, 0, 0L); 
1287     ::DrawMenuBar(GetWinHwnd(parent
)); 
1290 static void InsertWindowMenu(wxWindow 
*win
, WXHMENU menu
, HMENU subMenu
) 
1292     // Try to insert Window menu in front of Help, otherwise append it. 
1293     HMENU hmenu 
= (HMENU
)menu
; 
1297         int N 
= GetMenuItemCount(hmenu
); 
1298         bool success 
= FALSE
; 
1299         for ( int i 
= 0; i 
< N
; i
++ ) 
1302             int chars 
= GetMenuString(hmenu
, i
, buf
, WXSIZEOF(buf
), MF_BYPOSITION
); 
1305                 wxLogLastError(wxT("GetMenuString")); 
1310             if ( wxStripMenuCodes(wxString(buf
)).IsSameAs(_("Help")) ) 
1313                 ::InsertMenu(hmenu
, i
, MF_BYPOSITION 
| MF_POPUP 
| MF_STRING
, 
1314                              (UINT
)subMenu
, _("&Window")); 
1321             ::AppendMenu(hmenu
, MF_POPUP
, (UINT
)subMenu
, _("&Window")); 
1325     MDISetMenu(win
, hmenu
, subMenu
); 
1328 static void RemoveWindowMenu(wxWindow 
*win
, WXHMENU menu
) 
1330     HMENU hMenu 
= (HMENU
)menu
; 
1336         int N 
= ::GetMenuItemCount(hMenu
); 
1337         for ( int i 
= 0; i 
< N
; i
++ ) 
1339             if ( !::GetMenuString(hMenu
, i
, buf
, WXSIZEOF(buf
), MF_BYPOSITION
) ) 
1341                 wxLogLastError(wxT("GetMenuString")); 
1346             if ( wxStrcmp(buf
, _("&Window")) == 0 ) 
1348                 if ( !::RemoveMenu(hMenu
, i
, MF_BYPOSITION
) ) 
1350                     wxLogLastError(wxT("RemoveMenu")); 
1360         // we don't change the windows menu, but we update the main one 
1361         MDISetMenu(win
, hMenu
, NULL
); 
1365 static void UnpackMDIActivate(WXWPARAM wParam
, WXLPARAM lParam
, 
1366                               WXWORD 
*activate
, WXHWND 
*hwndAct
, WXHWND 
*hwndDeact
) 
1370     *hwndAct 
= (WXHWND
)lParam
; 
1371     *hwndDeact 
= (WXHWND
)wParam
; 
1373     *activate 
= (WXWORD
)wParam
; 
1374     *hwndAct 
= (WXHWND
)LOWORD(lParam
); 
1375     *hwndDeact 
= (WXHWND
)HIWORD(lParam
); 
1376 #endif // Win32/Win16