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 wxWindow 
*wxWndHook
;                 // from window.cpp 
  72 extern void wxAssociateWinWithHandle(HWND hWnd
, wxWindow 
*win
); 
  73 extern void wxRemoveHandleAssociation(wxWindow 
*win
); 
  75 static HWND invalidHandle 
= 0; 
  77 // --------------------------------------------------------------------------- 
  79 // --------------------------------------------------------------------------- 
  81 static const int IDM_WINDOWTILE  
= 4001; 
  82 static const int IDM_WINDOWTILEHOR  
= 4001; 
  83 static const int IDM_WINDOWCASCADE 
= 4002; 
  84 static const int IDM_WINDOWICONS 
= 4003; 
  85 static const int IDM_WINDOWNEXT 
= 4004; 
  86 static const int IDM_WINDOWTILEVERT 
= 4005; 
  88 // This range gives a maximum of 500 MDI children. Should be enough :-) 
  89 static const int wxFIRST_MDI_CHILD 
= 4100; 
  90 static const int wxLAST_MDI_CHILD 
= 4600; 
  92 // Status border dimensions 
  93 static const int wxTHICK_LINE_BORDER 
= 3; 
  94 static const int wxTHICK_LINE_WIDTH  
= 1; 
  96 // --------------------------------------------------------------------------- 
  98 // --------------------------------------------------------------------------- 
 100 // set the MDI menus (by sending the WM_MDISETMENU message) and update the menu 
 101 // of the parent of win (which is supposed to be the MDI client window) 
 102 static void MDISetMenu(wxWindow 
*win
, HMENU hmenuFrame
, HMENU hmenuWindow
); 
 104 // insert the window menu (subMenu) into menu just before "Help" submenu or at 
 105 // the very end if not found 
 106 static void InsertWindowMenu(wxWindow 
*win
, WXHMENU menu
, HMENU subMenu
); 
 108 // Remove the window menu 
 109 static void RemoveWindowMenu(wxWindow 
*win
, WXHMENU menu
); 
 111 // is this an id of an MDI child? 
 112 inline bool IsMdiCommandId(int id
) 
 114     return (id 
>= wxFIRST_MDI_CHILD
) && (id 
<= wxLAST_MDI_CHILD
); 
 117 static void UnpackMDIActivate(WXWPARAM wParam
, WXLPARAM lParam
, 
 118                               WXWORD 
*activate
, WXHWND 
*hwndAct
, WXHWND 
*hwndDeact
); 
 120 // =========================================================================== 
 122 // =========================================================================== 
 124 // --------------------------------------------------------------------------- 
 126 // --------------------------------------------------------------------------- 
 128 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
) 
 129 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
) 
 130 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
) 
 132 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
) 
 133     EVT_SIZE(wxMDIParentFrame::OnSize
) 
 134     EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
) 
 137 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 138     EVT_IDLE(wxMDIChildFrame::OnIdle
) 
 141 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxWindow
) 
 142     EVT_SCROLL(wxMDIClientWindow::OnScroll
) 
 145 // =========================================================================== 
 146 // wxMDIParentFrame: the frame which contains the client window which manages 
 148 // =========================================================================== 
 150 wxMDIParentFrame::wxMDIParentFrame() 
 152     m_clientWindow 
= NULL
; 
 153     m_currentChild 
= NULL
; 
 154     m_windowMenu 
= (wxMenu
*) NULL
; 
 155     m_parentFrameActive 
= TRUE
; 
 158 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
 160                               const wxString
& title
, 
 164                               const wxString
& name
) 
 166   m_defaultIcon 
= (WXHICON
) (wxSTD_MDIPARENTFRAME_ICON
 
 167                                 ? wxSTD_MDIPARENTFRAME_ICON
 
 168                                 : wxDEFAULT_MDIPARENTFRAME_ICON
); 
 170   m_clientWindow 
= NULL
; 
 171   m_currentChild 
= NULL
; 
 173   // this style can be used to prevent a window from having the standard MDI 
 175   if ( style 
& wxFRAME_NO_WINDOW_MENU 
) 
 177       m_windowMenu 
= (wxMenu 
*)NULL
; 
 179   else // normal case: we have the window menu, so construct it 
 181       m_windowMenu 
= new wxMenu
; 
 183       m_windowMenu
->Append(IDM_WINDOWCASCADE
, wxT("&Cascade")); 
 184       m_windowMenu
->Append(IDM_WINDOWTILEHOR
, wxT("Tile &Horizontally")); 
 185       m_windowMenu
->Append(IDM_WINDOWTILEVERT
, wxT("Tile &Vertically")); 
 186       m_windowMenu
->AppendSeparator(); 
 187       m_windowMenu
->Append(IDM_WINDOWICONS
, wxT("&Arrange Icons")); 
 188       m_windowMenu
->Append(IDM_WINDOWNEXT
, wxT("&Next")); 
 191   m_parentFrameActive 
= TRUE
; 
 194     wxTopLevelWindows
.Append(this); 
 197   m_windowStyle 
= style
; 
 199   if (parent
) parent
->AddChild(this); 
 204     m_windowId 
= (int)NewControlId(); 
 211   DWORD msflags 
= WS_OVERLAPPED
; 
 212   if (style 
& wxMINIMIZE_BOX
) 
 213     msflags 
|= WS_MINIMIZEBOX
; 
 214   if (style 
& wxMAXIMIZE_BOX
) 
 215     msflags 
|= WS_MAXIMIZEBOX
; 
 216   if (style 
& wxTHICK_FRAME
) 
 217     msflags 
|= WS_THICKFRAME
; 
 218   if (style 
& wxSYSTEM_MENU
) 
 219     msflags 
|= WS_SYSMENU
; 
 220   if ((style 
& wxMINIMIZE
) || (style 
& wxICONIZE
)) 
 221     msflags 
|= WS_MINIMIZE
; 
 222   if (style 
& wxMAXIMIZE
) 
 223     msflags 
|= WS_MAXIMIZE
; 
 224   if (style 
& wxCAPTION
) 
 225     msflags 
|= WS_CAPTION
; 
 227   if (style 
& wxCLIP_CHILDREN
) 
 228     msflags 
|= WS_CLIPCHILDREN
; 
 230   if ( !wxWindow::MSWCreate(m_windowId
, 
 241   wxModelessWindows
.Append(this); 
 243   // unlike (almost?) all other windows, frames are created hidden 
 249 wxMDIParentFrame::~wxMDIParentFrame() 
 252     // already delete by DestroyChildren() 
 253     m_frameToolBar 
= NULL
; 
 254     m_frameStatusBar 
= NULL
; 
 256     // ::DestroyMenu((HMENU)m_windowMenu); 
 260         m_windowMenu 
= (wxMenu
*) NULL
; 
 263     if ( m_clientWindow 
) 
 265         if ( m_clientWindow
->MSWGetOldWndProc() ) 
 266             m_clientWindow
->UnsubclassWin(); 
 268         m_clientWindow
->SetHWND(0); 
 269         delete m_clientWindow
; 
 273 void wxMDIParentFrame::InternalSetMenuBar() 
 275 //    HMENU subMenu = GetSubMenu((HMENU) m_windowMenu, 0); 
 277     m_parentFrameActive 
= TRUE
; 
 279     HMENU subMenu 
= (HMENU
) 0; 
 281         subMenu 
= (HMENU
) GetWindowMenu()->GetHMenu(); 
 283     InsertWindowMenu(GetClientWindow(), m_hMenu
, subMenu
); 
 286 void wxMDIParentFrame::SetWindowMenu(wxMenu
* menu
) 
 292             // Remove old window menu 
 293             RemoveWindowMenu(GetClientWindow(), m_hMenu
); 
 297         m_windowMenu 
= (wxMenu
*) NULL
; 
 303             InsertWindowMenu(GetClientWindow(), m_hMenu
, (HMENU
) m_windowMenu
->GetHMenu()); 
 307 void wxMDIParentFrame::OnSize(wxSizeEvent
&) 
 309     if ( GetClientWindow() ) 
 312         GetClientSize(&width
, &height
); 
 314         GetClientWindow()->SetSize(0, 0, width
, height
); 
 318 // Returns the active MDI child window 
 319 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 321     HWND hWnd 
= (HWND
)::SendMessage(GetWinHwnd(GetClientWindow()), 
 322                                     WM_MDIGETACTIVE
, 0, 0L); 
 326         return (wxMDIChildFrame 
*)wxFindWinFromHandle((WXHWND
) hWnd
); 
 329 // Create the client window class (don't Create the window, just return a new 
 331 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 333     return new wxMDIClientWindow
; 
 336 // Responds to colour changes, and passes event on to children. 
 337 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
 339     if ( m_clientWindow 
) 
 341         m_clientWindow
->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
)); 
 342         m_clientWindow
->Refresh(); 
 348 // --------------------------------------------------------------------------- 
 350 // --------------------------------------------------------------------------- 
 352 void wxMDIParentFrame::Cascade() 
 354     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDICASCADE
, 0, 0); 
 357 // TODO: add a direction argument (hor/vert) 
 358 void wxMDIParentFrame::Tile() 
 360     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDITILE
, MDITILE_HORIZONTAL
, 0); 
 363 void wxMDIParentFrame::ArrangeIcons() 
 365     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDIICONARRANGE
, 0, 0); 
 368 void wxMDIParentFrame::ActivateNext() 
 370     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 0); 
 373 void wxMDIParentFrame::ActivatePrevious() 
 375     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 1); 
 378 // --------------------------------------------------------------------------- 
 379 // the MDI parent frame window proc 
 380 // --------------------------------------------------------------------------- 
 382 long wxMDIParentFrame::MSWWindowProc(WXUINT message
, 
 387     bool processed 
= FALSE
; 
 393                 WXWORD state
, minimized
; 
 395                 UnpackActivate(wParam
, lParam
, &state
, &minimized
, &hwnd
); 
 397                 processed 
= HandleActivate(state
, minimized 
!= 0, hwnd
); 
 405                 UnpackCommand(wParam
, lParam
, &id
, &hwnd
, &cmd
); 
 407                 (void)HandleCommand(id
, cmd
, hwnd
); 
 409                 // even if the frame didn't process it, there is no need to try it 
 410                 // once again (i.e. call wxFrame::HandleCommand()) - we just dud it, 
 411                 // so pretend we processed the message anyhow 
 415             // always pass this message DefFrameProc(), otherwise MDI menu 
 416             // commands (and sys commands - more surprizingly!) won't work 
 417             MSWDefWindowProc(message
, wParam
, lParam
); 
 421             m_clientWindow 
= OnCreateClient(); 
 422             // Uses own style for client style 
 423             if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) ) 
 425                 wxLogMessage(_("Failed to create MDI parent frame.")); 
 436             // we erase background ourselves 
 444                 UnpackMenuSelect(wParam
, lParam
, &item
, &flags
, &hmenu
); 
 446                 if ( m_parentFrameActive 
) 
 448                     processed 
= HandleMenuSelect(item
, flags
, hmenu
); 
 450                 else if (m_currentChild
) 
 452                     processed 
= m_currentChild
-> 
 453                         HandleMenuSelect(item
, flags
, hmenu
); 
 459             // as we don't (usually) resize the MDI client to exactly fit the 
 460             // client area (we put it below the toolbar, above statusbar &c), 
 461             // we should not pass this one to DefFrameProc 
 466         rc 
= wxFrame::MSWWindowProc(message
, wParam
, lParam
); 
 471 bool wxMDIParentFrame::HandleActivate(int state
, bool minimized
, WXHWND activate
) 
 473     bool processed 
= FALSE
; 
 475     if ( wxWindow::HandleActivate(state
, minimized
, activate
) ) 
 481     // If this window is an MDI parent, we must also send an OnActivate message 
 482     // to the current child. 
 483     if ( (m_currentChild 
!= NULL
) && 
 484          ((state 
== WA_ACTIVE
) || (state 
== WA_CLICKACTIVE
)) ) 
 486         wxActivateEvent 
event(wxEVT_ACTIVATE
, TRUE
, m_currentChild
->GetId()); 
 487         event
.SetEventObject( m_currentChild 
); 
 488         if ( m_currentChild
->GetEventHandler()->ProcessEvent(event
) ) 
 495 bool wxMDIParentFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
) 
 497     // In case it's e.g. a toolbar. 
 500         wxWindow 
*win 
= wxFindWinFromHandle(hwnd
); 
 502             return win
->MSWCommand(cmd
, id
); 
 505     // is it one of standard MDI commands? 
 510         case IDM_WINDOWCASCADE
: 
 512             wParam 
= MDITILE_SKIPDISABLED
; 
 515         case IDM_WINDOWTILEHOR
: 
 516             wParam 
|= MDITILE_HORIZONTAL
; 
 519         case IDM_WINDOWTILEVERT
: 
 521                 wParam 
= MDITILE_VERTICAL
; 
 523             wParam 
|= MDITILE_SKIPDISABLED
; 
 526         case IDM_WINDOWICONS
: 
 527             msg 
= WM_MDIICONARRANGE
; 
 540         ::SendMessage(GetWinHwnd(GetClientWindow()), msg
, wParam
, 0); 
 545     // FIXME VZ: what does this test do?? 
 548         return FALSE
; // Get WndProc to call default proc 
 551     if ( IsMdiCommandId(id
) ) 
 553         wxWindowList::Node
* node 
= GetChildren().GetFirst(); 
 556             wxWindow
* child 
= node
->GetData(); 
 557             if ( child
->GetHWND() ) 
 559                 long childId 
= wxGetWindowId(child
->GetHWND()); 
 560                 if (childId 
== (long)id
) 
 562                     ::SendMessage( GetWinHwnd(GetClientWindow()), 
 564                                    (WPARAM
)child
->GetHWND(), 0); 
 568             node 
= node
->GetNext(); 
 571     else if ( m_parentFrameActive 
) 
 573         return ProcessCommand(id
); 
 575     else if ( m_currentChild 
) 
 577         return m_currentChild
->HandleCommand(id
, cmd
, hwnd
); 
 581         // this shouldn't happen because it means that our messages are being 
 582         // lost (they're not sent to the parent frame nor to the children) 
 583         wxFAIL_MSG(wxT("MDI parent frame is not active, yet there is no active MDI child?")); 
 589 long wxMDIParentFrame::MSWDefWindowProc(WXUINT message
, 
 594     if ( GetClientWindow() ) 
 595         clientWnd 
= GetClientWindow()->GetHWND(); 
 599     return DefFrameProc(GetHwnd(), (HWND
)clientWnd
, message
, wParam
, lParam
); 
 602 bool wxMDIParentFrame::MSWTranslateMessage(WXMSG
* msg
) 
 604     MSG 
*pMsg 
= (MSG 
*)msg
; 
 606     // first let the current child get it 
 607     if ( m_currentChild 
&& m_currentChild
->GetHWND() && 
 608          m_currentChild
->MSWTranslateMessage(msg
) ) 
 613     // then try out accel table (will also check the menu accels) 
 614     if ( wxFrame::MSWTranslateMessage(msg
) ) 
 619     // finally, check for MDI specific built in accel keys 
 620     if ( pMsg
->message 
== WM_KEYDOWN 
|| pMsg
->message 
== WM_SYSKEYDOWN 
) 
 622         if ( ::TranslateMDISysAccel(GetWinHwnd(GetClientWindow()), pMsg
)) 
 629 // =========================================================================== 
 631 // =========================================================================== 
 633 void wxMDIChildFrame::Init() 
 635     m_needsResize 
= TRUE
; 
 638 bool wxMDIChildFrame::Create(wxMDIParentFrame 
*parent
, 
 640                              const wxString
& title
, 
 644                              const wxString
& name
) 
 646   m_defaultIcon 
= (WXHICON
)(wxSTD_MDICHILDFRAME_ICON 
? wxSTD_MDICHILDFRAME_ICON
 
 647                                                      : wxDEFAULT_MDICHILDFRAME_ICON
); 
 654     m_windowId 
= (int)NewControlId(); 
 658       parent
->AddChild(this); 
 670   mcs
.szClass 
= style 
& wxNO_FULL_REPAINT_ON_RESIZE
 
 671                     ? wxMDIChildFrameClassNameNoRedraw
 
 672                     : wxMDIChildFrameClassName
; 
 674   mcs
.hOwner 
= wxGetInstance(); 
 678       mcs
.x 
= CW_USEDEFAULT
; 
 683       mcs
.y 
= CW_USEDEFAULT
; 
 688       mcs
.cx 
= CW_USEDEFAULT
; 
 693       mcs
.cy 
= CW_USEDEFAULT
; 
 695   DWORD msflags 
= WS_OVERLAPPED 
| WS_CLIPCHILDREN
; 
 696   if (style 
& wxMINIMIZE_BOX
) 
 697     msflags 
|= WS_MINIMIZEBOX
; 
 698   if (style 
& wxMAXIMIZE_BOX
) 
 699     msflags 
|= WS_MAXIMIZEBOX
; 
 700   if (style 
& wxTHICK_FRAME
) 
 701     msflags 
|= WS_THICKFRAME
; 
 702   if (style 
& wxSYSTEM_MENU
) 
 703     msflags 
|= WS_SYSMENU
; 
 704   if ((style 
& wxMINIMIZE
) || (style 
& wxICONIZE
)) 
 705     msflags 
|= WS_MINIMIZE
; 
 706   if (style 
& wxMAXIMIZE
) 
 707     msflags 
|= WS_MAXIMIZE
; 
 708   if (style 
& wxCAPTION
) 
 709     msflags 
|= WS_CAPTION
; 
 715   m_hWnd 
= (WXHWND
)::SendMessage(GetWinHwnd(parent
->GetClientWindow()), 
 716                                  WM_MDICREATE
, 0, (LONG
)(LPSTR
)&mcs
); 
 719   wxAssociateWinWithHandle((HWND
) GetHWND(), this); 
 721   // VZ: what's this? an act of piracy? 
 722   //SetWindowLong(GetHwnd(), 0, (long)this); 
 724   wxModelessWindows
.Append(this); 
 726   // Necessary to make ResetWindowStyle() work 
 727   // and will be called eventually anyway  
 730   // Without this, a maximized child will still 
 731   // a double border around the child 
 732   ResetWindowStyle((void *)NULL
); // Set the Client ExStyle right 
 737 wxMDIChildFrame::~wxMDIChildFrame() 
 741     // already delete by DestroyChildren() 
 742     m_frameToolBar 
= NULL
; 
 743     m_frameStatusBar 
= NULL
; 
 748 // Set the client size (i.e. leave the calculation of borders etc. 
 750 void wxMDIChildFrame::DoSetClientSize(int width
, int height
) 
 752   HWND hWnd 
= GetHwnd(); 
 755   ::GetClientRect(hWnd
, &rect
); 
 758   GetWindowRect(hWnd
, &rect2
); 
 760   // Find the difference between the entire window (title bar and all) 
 761   // and the client area; add this to the new client size to move the 
 763   int actual_width 
= rect2
.right 
- rect2
.left 
- rect
.right 
+ width
; 
 764   int actual_height 
= rect2
.bottom 
- rect2
.top 
- rect
.bottom 
+ height
; 
 766   if (GetStatusBar() && GetStatusBar()->IsShown()) 
 769     GetStatusBar()->GetSize(&sx
, &sy
); 
 774   point
.x 
= rect2
.left
; 
 777   // If there's an MDI parent, must subtract the parent's top left corner 
 778   // since MoveWindow moves relative to the parent 
 779   wxMDIParentFrame 
*mdiParent 
= (wxMDIParentFrame 
*)GetParent(); 
 780   ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
); 
 782   MoveWindow(hWnd
, point
.x
, point
.y
, actual_width
, actual_height
, (BOOL
)TRUE
); 
 784   wxSizeEvent 
event(wxSize(width
, height
), m_windowId
); 
 785   event
.SetEventObject( this ); 
 786   GetEventHandler()->ProcessEvent(event
); 
 789 void wxMDIChildFrame::DoGetPosition(int *x
, int *y
) const 
 792   GetWindowRect(GetHwnd(), &rect
); 
 797   // Since we now have the absolute screen coords, 
 798   // if there's a parent we must subtract its top left corner 
 799   wxMDIParentFrame 
*mdiParent 
= (wxMDIParentFrame 
*)GetParent(); 
 800   ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
); 
 806 void wxMDIChildFrame::InternalSetMenuBar() 
 808     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 810     // HMENU subMenu = GetSubMenu((HMENU)parent->GetWindowMenu(), 0); 
 811     HMENU subMenu 
= (HMENU
) 0; 
 812     if (parent
->GetWindowMenu()) 
 813         subMenu 
= (HMENU
) parent
->GetWindowMenu()->GetHMenu(); 
 815     InsertWindowMenu(parent
->GetClientWindow(), m_hMenu
, subMenu
); 
 817     parent
->m_parentFrameActive 
= FALSE
; 
 820 // --------------------------------------------------------------------------- 
 822 // --------------------------------------------------------------------------- 
 824 void wxMDIChildFrame::Maximize(bool maximize
) 
 826     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 827     if ( parent 
&& parent
->GetClientWindow() ) 
 829         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), 
 830                       maximize 
? WM_MDIMAXIMIZE 
: WM_MDIRESTORE
, 
 831                       (WPARAM
)GetHwnd(), 0); 
 835 void wxMDIChildFrame::Restore() 
 837     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 838     if ( parent 
&& parent
->GetClientWindow() ) 
 840         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIRESTORE
, 
 841                       (WPARAM
) GetHwnd(), 0); 
 845 void wxMDIChildFrame::Activate() 
 847     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 848     if ( parent 
&& parent
->GetClientWindow() ) 
 850         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIACTIVATE
, 
 851                       (WPARAM
) GetHwnd(), 0); 
 855 // --------------------------------------------------------------------------- 
 856 // MDI window proc and message handlers 
 857 // --------------------------------------------------------------------------- 
 859 long wxMDIChildFrame::MSWWindowProc(WXUINT message
, 
 864     bool processed 
= FALSE
; 
 872                 UnpackCommand((WXWPARAM
)wParam
, (WXLPARAM
)lParam
, 
 875                 processed 
= HandleCommand(id
, cmd
, (WXHWND
)hwnd
); 
 879         case WM_GETMINMAXINFO
: 
 880             // let the default window proc calculate the size of MDI children 
 881             // frames because it is based on the size of the MDI client window, 
 882             // not on the values specified in wxWindow m_min/max variables 
 883             return MSWDefWindowProc(message
, wParam
, lParam
); 
 888                 WXHWND hwndAct
, hwndDeact
; 
 889                 UnpackMDIActivate(wParam
, lParam
, &act
, &hwndAct
, &hwndDeact
); 
 891                 processed 
= HandleMDIActivate(act
, hwndAct
, hwndDeact
); 
 896             // must pass WM_MOVE to DefMDIChildProc() to recalculate MDI client 
 897             // scrollbars if necessary 
 902             // must pass WM_SIZE to DefMDIChildProc(), otherwise many weird 
 904             MSWDefWindowProc(message
, wParam
, lParam
); 
 908             // DefMDIChildProc handles SC_{NEXT/PREV}WINDOW here, so pass it 
 909             // the message (the base class version does not) 
 910             return MSWDefWindowProc(message
, wParam
, lParam
); 
 912         case WM_WINDOWPOSCHANGING
: 
 913             processed 
= HandleWindowPosChanging((LPWINDOWPOS
)lParam
); 
 918         rc 
= wxFrame::MSWWindowProc(message
, wParam
, lParam
); 
 923 bool wxMDIChildFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
) 
 925     // In case it's e.g. a toolbar. 
 928         wxWindow 
*win 
= wxFindWinFromHandle(hwnd
); 
 930             return win
->MSWCommand(cmd
, id
); 
 933     if (wxCurrentPopupMenu
) 
 935         wxMenu 
*popupMenu 
= wxCurrentPopupMenu
; 
 936         wxCurrentPopupMenu 
= NULL
; 
 937         if (popupMenu
->MSWCommand(cmd
, id
)) 
 942     if (GetMenuBar() && GetMenuBar()->FindItem(id
)) 
 944         processed 
= ProcessCommand(id
); 
 954 bool wxMDIChildFrame::HandleMDIActivate(long WXUNUSED(activate
), 
 958     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 964     if ( m_hWnd 
== hwndAct 
) 
 967         parent
->m_currentChild 
= this; 
 969         HMENU child_menu 
= (HMENU
)GetWinMenu(); 
 972             parent
->m_parentFrameActive 
= FALSE
; 
 974             menuToSet 
= child_menu
; 
 977     else if ( m_hWnd 
== hwndDeact 
) 
 979         wxASSERT_MSG( parent
->m_currentChild 
== this, 
 980                       wxT("can't deactivate MDI child which wasn't active!") ); 
 983         parent
->m_currentChild 
= NULL
; 
 985         HMENU parent_menu 
= (HMENU
)parent
->GetWinMenu(); 
 988             parent
->m_parentFrameActive 
= TRUE
; 
 990             menuToSet 
= parent_menu
; 
 995         // we have nothing to do with it 
1001         HMENU subMenu 
= (HMENU
) 0; 
1002         if (parent
->GetWindowMenu()) 
1003             subMenu 
= (HMENU
) parent
->GetWindowMenu()->GetHMenu(); 
1005         MDISetMenu(parent
->GetClientWindow(), menuToSet
, subMenu
); 
1008     wxActivateEvent 
event(wxEVT_ACTIVATE
, activated
, m_windowId
); 
1009     event
.SetEventObject( this ); 
1011     return GetEventHandler()->ProcessEvent(event
); 
1014 bool wxMDIChildFrame::HandleWindowPosChanging(void *pos
) 
1016     WINDOWPOS 
*lpPos 
= (WINDOWPOS 
*)pos
; 
1017 #if defined(__WIN95__) 
1018     if (!(lpPos
->flags 
& SWP_NOSIZE
)) 
1021         DWORD dwExStyle 
= ::GetWindowLong(GetHwnd(), GWL_EXSTYLE
); 
1022         DWORD dwStyle 
= ::GetWindowLong(GetHwnd(), GWL_STYLE
); 
1023         if (ResetWindowStyle((void *) & rectClient
) && (dwStyle 
& WS_MAXIMIZE
)) 
1025             ::AdjustWindowRectEx(&rectClient
, dwStyle
, FALSE
, dwExStyle
); 
1026             lpPos
->x 
= rectClient
.left
; 
1027             lpPos
->y 
= rectClient
.top
; 
1028             lpPos
->cx 
= rectClient
.right 
- rectClient
.left
; 
1029             lpPos
->cy 
= rectClient
.bottom 
- rectClient
.top
; 
1031         wxMDIParentFrame
* pFrameWnd 
= (wxMDIParentFrame 
*)GetParent(); 
1032         if (pFrameWnd 
&& pFrameWnd
->GetToolBar() && pFrameWnd
->GetToolBar()->IsShown()) 
1034             pFrameWnd
->GetToolBar()->Refresh(); 
1042 // --------------------------------------------------------------------------- 
1043 // MDI specific message translation/preprocessing 
1044 // --------------------------------------------------------------------------- 
1046 long wxMDIChildFrame::MSWDefWindowProc(WXUINT message
, WXUINT wParam
, WXLPARAM lParam
) 
1048     return DefMDIChildProc(GetHwnd(), 
1049                            (UINT
)message
, (WPARAM
)wParam
, (LPARAM
)lParam
); 
1052 bool wxMDIChildFrame::MSWTranslateMessage(WXMSG
* msg
) 
1054     return wxFrame::MSWTranslateMessage(msg
); 
1057 // --------------------------------------------------------------------------- 
1059 // --------------------------------------------------------------------------- 
1061 void wxMDIChildFrame::MSWDestroyWindow() 
1063     MSWDetachWindowMenu(); 
1064     invalidHandle 
= GetHwnd(); 
1066     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
1068     // Must make sure this handle is invalidated (set to NULL) since all sorts 
1069     // of things could happen after the child client is destroyed, but before 
1070     // the wxFrame is destroyed. 
1072     HWND oldHandle 
= (HWND
)GetHWND(); 
1073     SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIDESTROY
, 
1074                 (WPARAM
)oldHandle
, 0); 
1076     if (parent
->GetActiveChild() == (wxMDIChildFrame
*) NULL
) 
1077         ResetWindowStyle((void*) NULL
); 
1083         ::DestroyMenu((HMENU
) m_hMenu
); 
1086     wxRemoveHandleAssociation(this); 
1090 // Change the client window's extended style so we don't get a client edge 
1091 // style when a child is maximised (a double border looks silly.) 
1092 bool wxMDIChildFrame::ResetWindowStyle(void *vrect
) 
1094 #if defined(__WIN95__) 
1095     RECT 
*rect 
= (RECT 
*)vrect
; 
1096     wxMDIParentFrame
* pFrameWnd 
= (wxMDIParentFrame 
*)GetParent(); 
1097     wxMDIChildFrame
* pChild 
= pFrameWnd
->GetActiveChild(); 
1098     if (!pChild 
|| (pChild 
== this)) 
1100         HWND hwndClient 
= GetWinHwnd(pFrameWnd
->GetClientWindow()); 
1101         DWORD dwStyle 
= ::GetWindowLong(hwndClient
, GWL_EXSTYLE
); 
1103         // we want to test whether there is a maximized child, so just set 
1104         // dwThisStyle to 0 if there is no child at all 
1105         DWORD dwThisStyle 
= pChild
 
1106             ? ::GetWindowLong(GetWinHwnd(pChild
), GWL_STYLE
) : 0; 
1107         DWORD dwNewStyle 
= dwStyle
; 
1108         if ( dwThisStyle 
& WS_MAXIMIZE 
) 
1109             dwNewStyle 
&= ~(WS_EX_CLIENTEDGE
); 
1111             dwNewStyle 
|= WS_EX_CLIENTEDGE
; 
1113         if (dwStyle 
!= dwNewStyle
) 
1115             // force update of everything 
1116             ::RedrawWindow(hwndClient
, NULL
, NULL
, 
1117                            RDW_INVALIDATE 
| RDW_ALLCHILDREN
); 
1118             ::SetWindowLong(hwndClient
, GWL_EXSTYLE
, dwNewStyle
); 
1119             ::SetWindowPos(hwndClient
, NULL
, 0, 0, 0, 0, 
1120                            SWP_FRAMECHANGED 
| SWP_NOACTIVATE 
| 
1121                            SWP_NOMOVE 
| SWP_NOSIZE 
| SWP_NOZORDER 
| 
1124                 ::GetClientRect(hwndClient
, rect
); 
1134 // =========================================================================== 
1135 // wxMDIClientWindow: the window of predefined (by Windows) class which 
1136 // contains the child frames 
1137 // =========================================================================== 
1139 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame 
*parent
, long style
) 
1141     m_backgroundColour 
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
); 
1143     CLIENTCREATESTRUCT ccs
; 
1144     m_windowStyle 
= style
; 
1147     ccs
.hWindowMenu 
= (HMENU
) 0; 
1148     if (parent
->GetWindowMenu()) 
1149         ccs
.hWindowMenu 
= (HMENU
) parent
->GetWindowMenu()->GetHMenu(); 
1150     ccs
.idFirstChild 
= wxFIRST_MDI_CHILD
; 
1152     DWORD msStyle 
= MDIS_ALLCHILDSTYLES 
| WS_VISIBLE 
| WS_CHILD 
| WS_CLIPCHILDREN
; 
1153     if ( style 
& wxHSCROLL 
) 
1154         msStyle 
|= WS_HSCROLL
; 
1155     if ( style 
& wxVSCROLL 
) 
1156         msStyle 
|= WS_VSCROLL
; 
1158 #if defined(__WIN95__) 
1159     DWORD exStyle 
= WS_EX_CLIENTEDGE
; 
1165     m_hWnd 
= (WXHWND
)::CreateWindowEx
 
1175                         (LPSTR
)(LPCLIENTCREATESTRUCT
)&ccs
); 
1178         wxLogLastError(wxT("CreateWindowEx(MDI client)")); 
1183     SubclassWin(m_hWnd
); 
1189 // Explicitly call default scroll behaviour 
1190 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
) 
1192     // Note: for client windows, the scroll position is not set in 
1193     // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what 
1194     // scroll position we're at. 
1195     // This makes it hard to paint patterns or bitmaps in the background, 
1196     // and have the client area scrollable as well. 
1198     if ( event
.GetOrientation() == wxHORIZONTAL 
) 
1199         m_scrollX 
= event
.GetPosition(); // Always returns zero! 
1201         m_scrollY 
= event
.GetPosition(); // Always returns zero! 
1206 void wxMDIClientWindow::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
1208     // Try to fix a problem whereby if you show an MDI child frame, then reposition the 
1209     // client area, you can end up with a non-refreshed portion in the client window 
1210     // (see OGL studio sample). So check if the position is changed and if so, 
1211     // redraw the MDI child frames. 
1213     wxPoint oldPos 
= GetPosition(); 
1215     wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
); 
1217     wxPoint newPos 
= GetPosition(); 
1219     if ((newPos
.x 
!= oldPos
.x
) || (newPos
.y 
!= oldPos
.y
)) 
1223             wxNode
* node 
= GetParent()->GetChildren().First(); 
1226                 wxWindow
* child 
= (wxWindow
*) node
->Data(); 
1227                 if (child
->IsKindOf(CLASSINFO(wxMDIChildFrame
))) 
1229                     HWND hWnd 
= (HWND
) child
->GetHWND(); 
1230                    ::RedrawWindow(hWnd
, NULL
, NULL
, RDW_FRAME
|RDW_ALLCHILDREN
|RDW_INVALIDATE 
); 
1232                 node 
= node
->Next(); 
1238 void wxMDIChildFrame::OnIdle(wxIdleEvent
& event
) 
1240     // MDI child frames get their WM_SIZE when they're constructed but at this 
1241     // moment they don't have any children yet so all child windows will be 
1242     // positioned incorrectly when they are added later - to fix this, we 
1243     // generate an artificial size event here 
1244     if ( m_needsResize 
) 
1246         m_needsResize 
= FALSE
; // avoid any possibility of recursion 
1254 // --------------------------------------------------------------------------- 
1255 // non member functions 
1256 // --------------------------------------------------------------------------- 
1258 static void MDISetMenu(wxWindow 
*win
, HMENU hmenuFrame
, HMENU hmenuWindow
) 
1260     ::SendMessage(GetWinHwnd(win
), WM_MDISETMENU
, 
1262                   (WPARAM
)hmenuFrame
, (LPARAM
)hmenuWindow
 
1264                   0, MAKELPARAM(hmenuFrame
, hmenuWindow
) 
1268     // update menu bar of the parent window 
1269     wxWindow 
*parent 
= win
->GetParent(); 
1270     wxCHECK_RET( parent
, wxT("MDI client without parent frame? weird...") ); 
1272     ::SendMessage(GetWinHwnd(win
), WM_MDIREFRESHMENU
, 0, 0L); 
1273     ::DrawMenuBar(GetWinHwnd(parent
)); 
1276 static void InsertWindowMenu(wxWindow 
*win
, WXHMENU menu
, HMENU subMenu
) 
1278     // Try to insert Window menu in front of Help, otherwise append it. 
1279     HMENU hmenu 
= (HMENU
)menu
; 
1283     int N 
= GetMenuItemCount(hmenu
); 
1284     bool success 
= FALSE
; 
1285     for ( int i 
= 0; i 
< N
; i
++ ) 
1288         int chars 
= GetMenuString(hmenu
, i
, buf
, WXSIZEOF(buf
), MF_BYPOSITION
); 
1291             wxLogLastError(wxT("GetMenuString")); 
1296         if ( wxStripMenuCodes(wxString(buf
)).IsSameAs(_("Help")) ) 
1299             ::InsertMenu(hmenu
, i
, MF_BYPOSITION 
| MF_POPUP 
| MF_STRING
, 
1300                          (UINT
)subMenu
, _("&Window")); 
1307         ::AppendMenu(hmenu
, MF_POPUP
, (UINT
)subMenu
, _("&Window")); 
1311     MDISetMenu(win
, hmenu
, subMenu
); 
1314 static void RemoveWindowMenu(wxWindow 
*win
, WXHMENU menu
) 
1316     // Try to insert Window menu in front of Help, otherwise append it. 
1317     HMENU hmenu 
= (HMENU
)menu
; 
1318     int N 
= GetMenuItemCount(hmenu
); 
1319     for ( int i 
= 0; i 
< N
; i
++ ) 
1322         int chars 
= GetMenuString(hmenu
, i
, buf
, WXSIZEOF(buf
), MF_BYPOSITION
); 
1325             wxLogLastError(wxT("GetMenuString")); 
1330         if ( wxStripMenuCodes(wxString(buf
)).IsSameAs(_("Window")) ) 
1332             ::RemoveMenu(hmenu
, i
, MF_BYPOSITION
); 
1337     // Does passing 0 for the window menu really work with WM_MDISETMENU? 
1338     MDISetMenu(win
, hmenu
, 0); 
1341 static void UnpackMDIActivate(WXWPARAM wParam
, WXLPARAM lParam
, 
1342                               WXWORD 
*activate
, WXHWND 
*hwndAct
, WXHWND 
*hwndDeact
) 
1346     *hwndAct 
= (WXHWND
)lParam
; 
1347     *hwndDeact 
= (WXHWND
)wParam
; 
1349     *activate 
= (WXWORD
)wParam
; 
1350     *hwndAct 
= (WXHWND
)LOWORD(lParam
); 
1351     *hwndDeact 
= (WXHWND
)HIWORD(lParam
); 
1352 #endif // Win32/Win16