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 static void UnpackMDIActivate(WXWPARAM wParam
, WXLPARAM lParam
, 
 116                               WXWORD 
*activate
, WXHWND 
*hwndAct
, WXHWND 
*hwndDeact
); 
 118 // =========================================================================== 
 120 // =========================================================================== 
 122 // --------------------------------------------------------------------------- 
 124 // --------------------------------------------------------------------------- 
 126 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
) 
 127 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
) 
 128 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
) 
 130 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
) 
 131     EVT_SIZE(wxMDIParentFrame::OnSize
) 
 132     EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
) 
 135 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 136     EVT_IDLE(wxMDIChildFrame::OnIdle
) 
 139 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxWindow
) 
 140     EVT_SCROLL(wxMDIClientWindow::OnScroll
) 
 143 // =========================================================================== 
 144 // wxMDIParentFrame: the frame which contains the client window which manages 
 146 // =========================================================================== 
 148 wxMDIParentFrame::wxMDIParentFrame() 
 150     m_clientWindow 
= NULL
; 
 151     m_currentChild 
= NULL
; 
 152     m_windowMenu 
= (wxMenu
*) NULL
; 
 153     m_parentFrameActive 
= TRUE
; 
 156 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
 158                               const wxString
& title
, 
 162                               const wxString
& name
) 
 164   m_clientWindow 
= NULL
; 
 165   m_currentChild 
= NULL
; 
 167   // this style can be used to prevent a window from having the standard MDI 
 169   if ( style 
& wxFRAME_NO_WINDOW_MENU 
) 
 171       m_windowMenu 
= (wxMenu 
*)NULL
; 
 173   else // normal case: we have the window menu, so construct it 
 175       m_windowMenu 
= new wxMenu
; 
 177       m_windowMenu
->Append(IDM_WINDOWCASCADE
, _("&Cascade")); 
 178       m_windowMenu
->Append(IDM_WINDOWTILEHOR
, _("Tile &Horizontally")); 
 179       m_windowMenu
->Append(IDM_WINDOWTILEVERT
, _("Tile &Vertically")); 
 180       m_windowMenu
->AppendSeparator(); 
 181       m_windowMenu
->Append(IDM_WINDOWICONS
, _("&Arrange Icons")); 
 182       m_windowMenu
->Append(IDM_WINDOWNEXT
, _("&Next")); 
 185   m_parentFrameActive 
= TRUE
; 
 188     wxTopLevelWindows
.Append(this); 
 191   m_windowStyle 
= style
; 
 194       parent
->AddChild(this); 
 199     m_windowId 
= NewControlId(); 
 202   long msflags 
= MSWGetCreateWindowFlags(&exflags
); 
 204   if ( !wxWindow::MSWCreate(wxMDIFrameClassName
, 
 213   wxModelessWindows
.Append(this); 
 215   // unlike (almost?) all other windows, frames are created hidden 
 221 wxMDIParentFrame::~wxMDIParentFrame() 
 224     // already delete by DestroyChildren() 
 225     m_frameToolBar 
= NULL
; 
 226     m_frameStatusBar 
= NULL
; 
 228     // ::DestroyMenu((HMENU)m_windowMenu); 
 232         m_windowMenu 
= (wxMenu
*) NULL
; 
 235     if ( m_clientWindow 
) 
 237         if ( m_clientWindow
->MSWGetOldWndProc() ) 
 238             m_clientWindow
->UnsubclassWin(); 
 240         m_clientWindow
->SetHWND(0); 
 241         delete m_clientWindow
; 
 245 #if wxUSE_MENUS_NATIVE 
 247 void wxMDIParentFrame::InternalSetMenuBar() 
 249     m_parentFrameActive 
= TRUE
; 
 251     wxMenu 
*menu 
= GetWindowMenu(); 
 252     HMENU subMenu 
= menu 
? GetHmenuOf(menu
) : 0; 
 254     InsertWindowMenu(GetClientWindow(), m_hMenu
, subMenu
); 
 257 #endif // wxUSE_MENUS_NATIVE 
 259 void wxMDIParentFrame::SetWindowMenu(wxMenu
* menu
) 
 265             // Remove old window menu 
 266             RemoveWindowMenu(GetClientWindow(), m_hMenu
); 
 270         m_windowMenu 
= (wxMenu
*) NULL
; 
 277             InsertWindowMenu(GetClientWindow(), m_hMenu
, 
 278                              GetHmenuOf(m_windowMenu
)); 
 283 void wxMDIParentFrame::OnSize(wxSizeEvent
&) 
 285     if ( GetClientWindow() ) 
 288         GetClientSize(&width
, &height
); 
 290         GetClientWindow()->SetSize(0, 0, width
, height
); 
 294 // Returns the active MDI child window 
 295 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 297     HWND hWnd 
= (HWND
)::SendMessage(GetWinHwnd(GetClientWindow()), 
 298                                     WM_MDIGETACTIVE
, 0, 0L); 
 302         return (wxMDIChildFrame 
*)wxFindWinFromHandle((WXHWND
) hWnd
); 
 305 // Create the client window class (don't Create the window, just return a new 
 307 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 309     return new wxMDIClientWindow
; 
 312 // Responds to colour changes, and passes event on to children. 
 313 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
 315     if ( m_clientWindow 
) 
 317         m_clientWindow
->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
)); 
 318         m_clientWindow
->Refresh(); 
 324 WXHICON 
wxMDIParentFrame::GetDefaultIcon() const 
 326     return (WXHICON
)(wxSTD_MDIPARENTFRAME_ICON 
? wxSTD_MDIPARENTFRAME_ICON
 
 327                                                : wxDEFAULT_MDIPARENTFRAME_ICON
); 
 330 // --------------------------------------------------------------------------- 
 332 // --------------------------------------------------------------------------- 
 334 void wxMDIParentFrame::Cascade() 
 336     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDICASCADE
, 0, 0); 
 339 // TODO: add a direction argument (hor/vert) 
 340 void wxMDIParentFrame::Tile() 
 342     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDITILE
, MDITILE_HORIZONTAL
, 0); 
 345 void wxMDIParentFrame::ArrangeIcons() 
 347     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDIICONARRANGE
, 0, 0); 
 350 void wxMDIParentFrame::ActivateNext() 
 352     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 0); 
 355 void wxMDIParentFrame::ActivatePrevious() 
 357     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 1); 
 360 // --------------------------------------------------------------------------- 
 361 // the MDI parent frame window proc 
 362 // --------------------------------------------------------------------------- 
 364 long wxMDIParentFrame::MSWWindowProc(WXUINT message
, 
 369     bool processed 
= FALSE
; 
 375                 WXWORD state
, minimized
; 
 377                 UnpackActivate(wParam
, lParam
, &state
, &minimized
, &hwnd
); 
 379                 processed 
= HandleActivate(state
, minimized 
!= 0, hwnd
); 
 387                 UnpackCommand(wParam
, lParam
, &id
, &hwnd
, &cmd
); 
 389                 (void)HandleCommand(id
, cmd
, hwnd
); 
 391                 // even if the frame didn't process it, there is no need to try it 
 392                 // once again (i.e. call wxFrame::HandleCommand()) - we just dud it, 
 393                 // so pretend we processed the message anyhow 
 397             // always pass this message DefFrameProc(), otherwise MDI menu 
 398             // commands (and sys commands - more surprizingly!) won't work 
 399             MSWDefWindowProc(message
, wParam
, lParam
); 
 403             m_clientWindow 
= OnCreateClient(); 
 404             // Uses own style for client style 
 405             if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) ) 
 407                 wxLogMessage(_("Failed to create MDI parent frame.")); 
 418             // we erase background ourselves 
 426                 UnpackMenuSelect(wParam
, lParam
, &item
, &flags
, &hmenu
); 
 428                 if ( m_parentFrameActive 
) 
 430                     processed 
= HandleMenuSelect(item
, flags
, hmenu
); 
 432                 else if (m_currentChild
) 
 434                     processed 
= m_currentChild
-> 
 435                         HandleMenuSelect(item
, flags
, hmenu
); 
 441             // as we don't (usually) resize the MDI client to exactly fit the 
 442             // client area (we put it below the toolbar, above statusbar &c), 
 443             // we should not pass this one to DefFrameProc 
 448         rc 
= wxFrame::MSWWindowProc(message
, wParam
, lParam
); 
 453 bool wxMDIParentFrame::HandleActivate(int state
, bool minimized
, WXHWND activate
) 
 455     bool processed 
= FALSE
; 
 457     if ( wxWindow::HandleActivate(state
, minimized
, activate
) ) 
 463     // If this window is an MDI parent, we must also send an OnActivate message 
 464     // to the current child. 
 465     if ( (m_currentChild 
!= NULL
) && 
 466          ((state 
== WA_ACTIVE
) || (state 
== WA_CLICKACTIVE
)) ) 
 468         wxActivateEvent 
event(wxEVT_ACTIVATE
, TRUE
, m_currentChild
->GetId()); 
 469         event
.SetEventObject( m_currentChild 
); 
 470         if ( m_currentChild
->GetEventHandler()->ProcessEvent(event
) ) 
 477 bool wxMDIParentFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
) 
 479     // In case it's e.g. a toolbar. 
 482         wxWindow 
*win 
= wxFindWinFromHandle(hwnd
); 
 484             return win
->MSWCommand(cmd
, id
); 
 487     // is it one of standard MDI commands? 
 492         case IDM_WINDOWCASCADE
: 
 494             wParam 
= MDITILE_SKIPDISABLED
; 
 497         case IDM_WINDOWTILEHOR
: 
 498             wParam 
|= MDITILE_HORIZONTAL
; 
 501         case IDM_WINDOWTILEVERT
: 
 503                 wParam 
= MDITILE_VERTICAL
; 
 505             wParam 
|= MDITILE_SKIPDISABLED
; 
 508         case IDM_WINDOWICONS
: 
 509             msg 
= WM_MDIICONARRANGE
; 
 522         ::SendMessage(GetWinHwnd(GetClientWindow()), msg
, wParam
, 0); 
 527     // FIXME VZ: what does this test do?? 
 530         return FALSE
; // Get WndProc to call default proc 
 533     if ( IsMdiCommandId(id
) ) 
 535         wxWindowList::Node
* node 
= GetChildren().GetFirst(); 
 538             wxWindow
* child 
= node
->GetData(); 
 539             if ( child
->GetHWND() ) 
 541                 long childId 
= wxGetWindowId(child
->GetHWND()); 
 542                 if (childId 
== (long)id
) 
 544                     ::SendMessage( GetWinHwnd(GetClientWindow()), 
 546                                    (WPARAM
)child
->GetHWND(), 0); 
 550             node 
= node
->GetNext(); 
 553     else if ( m_parentFrameActive 
) 
 555         return ProcessCommand(id
); 
 557     else if ( m_currentChild 
) 
 559         return m_currentChild
->HandleCommand(id
, cmd
, hwnd
); 
 563         // this shouldn't happen because it means that our messages are being 
 564         // lost (they're not sent to the parent frame nor to the children) 
 565         wxFAIL_MSG(wxT("MDI parent frame is not active, yet there is no active MDI child?")); 
 571 long wxMDIParentFrame::MSWDefWindowProc(WXUINT message
, 
 576     if ( GetClientWindow() ) 
 577         clientWnd 
= GetClientWindow()->GetHWND(); 
 581     return DefFrameProc(GetHwnd(), (HWND
)clientWnd
, message
, wParam
, lParam
); 
 584 bool wxMDIParentFrame::MSWTranslateMessage(WXMSG
* msg
) 
 586     MSG 
*pMsg 
= (MSG 
*)msg
; 
 588     // first let the current child get it 
 589     if ( m_currentChild 
&& m_currentChild
->GetHWND() && 
 590          m_currentChild
->MSWTranslateMessage(msg
) ) 
 595     // then try out accel table (will also check the menu accels) 
 596     if ( wxFrame::MSWTranslateMessage(msg
) ) 
 601     // finally, check for MDI specific built in accel keys 
 602     if ( pMsg
->message 
== WM_KEYDOWN 
|| pMsg
->message 
== WM_SYSKEYDOWN 
) 
 604         if ( ::TranslateMDISysAccel(GetWinHwnd(GetClientWindow()), pMsg
)) 
 611 // =========================================================================== 
 613 // =========================================================================== 
 615 void wxMDIChildFrame::Init() 
 617     m_needsResize 
= TRUE
; 
 620 bool wxMDIChildFrame::Create(wxMDIParentFrame 
*parent
, 
 622                              const wxString
& title
, 
 626                              const wxString
& name
) 
 629   wxWindowBase::Show(TRUE
); // MDI child frame starts off shown 
 634     m_windowId 
= (int)NewControlId(); 
 638       parent
->AddChild(this); 
 648   mcs
.szClass 
= style 
& wxNO_FULL_REPAINT_ON_RESIZE
 
 649                     ? wxMDIChildFrameClassNameNoRedraw
 
 650                     : wxMDIChildFrameClassName
; 
 652   mcs
.hOwner 
= wxGetInstance(); 
 656       mcs
.x 
= CW_USEDEFAULT
; 
 661       mcs
.y 
= CW_USEDEFAULT
; 
 666       mcs
.cx 
= CW_USEDEFAULT
; 
 671       mcs
.cy 
= CW_USEDEFAULT
; 
 673   DWORD msflags 
= WS_OVERLAPPED 
| WS_CLIPCHILDREN 
| WS_THICKFRAME 
| WS_VISIBLE 
; 
 674   if (style 
& wxMINIMIZE_BOX
) 
 675     msflags 
|= WS_MINIMIZEBOX
; 
 676   if (style 
& wxMAXIMIZE_BOX
) 
 677     msflags 
|= WS_MAXIMIZEBOX
; 
 678   if (style 
& wxTHICK_FRAME
) 
 679     msflags 
|= WS_THICKFRAME
; 
 680   if (style 
& wxSYSTEM_MENU
) 
 681     msflags 
|= WS_SYSMENU
; 
 682   if ((style 
& wxMINIMIZE
) || (style 
& wxICONIZE
)) 
 683     msflags 
|= WS_MINIMIZE
; 
 684   if (style 
& wxMAXIMIZE
) 
 685     msflags 
|= WS_MAXIMIZE
; 
 686   if (style 
& wxCAPTION
) 
 687     msflags 
|= WS_CAPTION
; 
 693   wxWindowCreationHook 
hook(this); 
 695   m_hWnd 
= (WXHWND
)::SendMessage(GetWinHwnd(parent
->GetClientWindow()), 
 696                                  WM_MDICREATE
, 0, (LONG
)(LPSTR
)&mcs
); 
 698   wxAssociateWinWithHandle((HWND
) GetHWND(), this); 
 700   wxModelessWindows
.Append(this); 
 705 wxMDIChildFrame::~wxMDIChildFrame() 
 709     // already delete by DestroyChildren() 
 710     m_frameToolBar 
= NULL
; 
 711     m_frameStatusBar 
= NULL
; 
 716 // Set the client size (i.e. leave the calculation of borders etc. 
 718 void wxMDIChildFrame::DoSetClientSize(int width
, int height
) 
 720   HWND hWnd 
= GetHwnd(); 
 723   ::GetClientRect(hWnd
, &rect
); 
 726   GetWindowRect(hWnd
, &rect2
); 
 728   // Find the difference between the entire window (title bar and all) 
 729   // and the client area; add this to the new client size to move the 
 731   int actual_width 
= rect2
.right 
- rect2
.left 
- rect
.right 
+ width
; 
 732   int actual_height 
= rect2
.bottom 
- rect2
.top 
- rect
.bottom 
+ height
; 
 734   if (GetStatusBar() && GetStatusBar()->IsShown()) 
 737     GetStatusBar()->GetSize(&sx
, &sy
); 
 742   point
.x 
= rect2
.left
; 
 745   // If there's an MDI parent, must subtract the parent's top left corner 
 746   // since MoveWindow moves relative to the parent 
 747   wxMDIParentFrame 
*mdiParent 
= (wxMDIParentFrame 
*)GetParent(); 
 748   ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
); 
 750   MoveWindow(hWnd
, point
.x
, point
.y
, actual_width
, actual_height
, (BOOL
)TRUE
); 
 752   wxSizeEvent 
event(wxSize(width
, height
), m_windowId
); 
 753   event
.SetEventObject( this ); 
 754   GetEventHandler()->ProcessEvent(event
); 
 757 void wxMDIChildFrame::DoGetPosition(int *x
, int *y
) const 
 760   GetWindowRect(GetHwnd(), &rect
); 
 765   // Since we now have the absolute screen coords, 
 766   // if there's a parent we must subtract its top left corner 
 767   wxMDIParentFrame 
*mdiParent 
= (wxMDIParentFrame 
*)GetParent(); 
 768   ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
); 
 774 void wxMDIChildFrame::InternalSetMenuBar() 
 776     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 778     // HMENU subMenu = GetSubMenu((HMENU)parent->GetWindowMenu(), 0); 
 779     HMENU subMenu 
= (HMENU
) 0; 
 780     if (parent
->GetWindowMenu()) 
 781         subMenu 
= (HMENU
) parent
->GetWindowMenu()->GetHMenu(); 
 783     InsertWindowMenu(parent
->GetClientWindow(), m_hMenu
, subMenu
); 
 785     parent
->m_parentFrameActive 
= FALSE
; 
 788 WXHICON 
wxMDIChildFrame::GetDefaultIcon() const 
 790     return (WXHICON
)(wxSTD_MDICHILDFRAME_ICON 
? wxSTD_MDICHILDFRAME_ICON
 
 791                                               : wxDEFAULT_MDICHILDFRAME_ICON
); 
 794 // --------------------------------------------------------------------------- 
 796 // --------------------------------------------------------------------------- 
 798 void wxMDIChildFrame::Maximize(bool maximize
) 
 800     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 801     if ( parent 
&& parent
->GetClientWindow() ) 
 803         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), 
 804                       maximize 
? WM_MDIMAXIMIZE 
: WM_MDIRESTORE
, 
 805                       (WPARAM
)GetHwnd(), 0); 
 809 void wxMDIChildFrame::Restore() 
 811     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 812     if ( parent 
&& parent
->GetClientWindow() ) 
 814         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIRESTORE
, 
 815                       (WPARAM
) GetHwnd(), 0); 
 819 void wxMDIChildFrame::Activate() 
 821     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 822     if ( parent 
&& parent
->GetClientWindow() ) 
 824         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIACTIVATE
, 
 825                       (WPARAM
) GetHwnd(), 0); 
 829 // --------------------------------------------------------------------------- 
 830 // MDI window proc and message handlers 
 831 // --------------------------------------------------------------------------- 
 833 long wxMDIChildFrame::MSWWindowProc(WXUINT message
, 
 838     bool processed 
= FALSE
; 
 846                 UnpackCommand((WXWPARAM
)wParam
, (WXLPARAM
)lParam
, 
 849                 processed 
= HandleCommand(id
, cmd
, (WXHWND
)hwnd
); 
 853         case WM_GETMINMAXINFO
: 
 854             processed 
= HandleGetMinMaxInfo((MINMAXINFO 
*)lParam
); 
 860                 WXHWND hwndAct
, hwndDeact
; 
 861                 UnpackMDIActivate(wParam
, lParam
, &act
, &hwndAct
, &hwndDeact
); 
 863                 processed 
= HandleMDIActivate(act
, hwndAct
, hwndDeact
); 
 868             // must pass WM_MOVE to DefMDIChildProc() to recalculate MDI client 
 869             // scrollbars if necessary 
 874             // must pass WM_SIZE to DefMDIChildProc(), otherwise many weird 
 876             MSWDefWindowProc(message
, wParam
, lParam
); 
 880             // DefMDIChildProc handles SC_{NEXT/PREV}WINDOW here, so pass it 
 881             // the message (the base class version does not) 
 882             return MSWDefWindowProc(message
, wParam
, lParam
); 
 884         case WM_WINDOWPOSCHANGING
: 
 885             processed 
= HandleWindowPosChanging((LPWINDOWPOS
)lParam
); 
 890         rc 
= wxFrame::MSWWindowProc(message
, wParam
, lParam
); 
 895 bool wxMDIChildFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
) 
 897     // In case it's e.g. a toolbar. 
 900         wxWindow 
*win 
= wxFindWinFromHandle(hwnd
); 
 902             return win
->MSWCommand(cmd
, id
); 
 905     if (wxCurrentPopupMenu
) 
 907         wxMenu 
*popupMenu 
= wxCurrentPopupMenu
; 
 908         wxCurrentPopupMenu 
= NULL
; 
 909         if (popupMenu
->MSWCommand(cmd
, id
)) 
 914     if (GetMenuBar() && GetMenuBar()->FindItem(id
)) 
 916         processed 
= ProcessCommand(id
); 
 926 bool wxMDIChildFrame::HandleMDIActivate(long WXUNUSED(activate
), 
 930     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 936     if ( m_hWnd 
== hwndAct 
) 
 939         parent
->m_currentChild 
= this; 
 941         HMENU child_menu 
= (HMENU
)GetWinMenu(); 
 944             parent
->m_parentFrameActive 
= FALSE
; 
 946             menuToSet 
= child_menu
; 
 949     else if ( m_hWnd 
== hwndDeact 
) 
 951         wxASSERT_MSG( parent
->m_currentChild 
== this, 
 952                       wxT("can't deactivate MDI child which wasn't active!") ); 
 955         parent
->m_currentChild 
= NULL
; 
 957         HMENU parent_menu 
= (HMENU
)parent
->GetWinMenu(); 
 959         // activate the the parent menu only when there is no other child 
 960         // that has been activated 
 961         if ( parent_menu 
&& !hwndAct 
) 
 963             parent
->m_parentFrameActive 
= TRUE
; 
 965             menuToSet 
= parent_menu
; 
 970         // we have nothing to do with it 
 976         HMENU subMenu 
= (HMENU
) 0; 
 977         if (parent
->GetWindowMenu()) 
 978             subMenu 
= (HMENU
) parent
->GetWindowMenu()->GetHMenu(); 
 980         MDISetMenu(parent
->GetClientWindow(), menuToSet
, subMenu
); 
 983     wxActivateEvent 
event(wxEVT_ACTIVATE
, activated
, m_windowId
); 
 984     event
.SetEventObject( this ); 
 986     ResetWindowStyle((void *)NULL
); 
 988     return GetEventHandler()->ProcessEvent(event
); 
 991 bool wxMDIChildFrame::HandleWindowPosChanging(void *pos
) 
 993     WINDOWPOS 
*lpPos 
= (WINDOWPOS 
*)pos
; 
 994 #if defined(__WIN95__) 
 995     if (!(lpPos
->flags 
& SWP_NOSIZE
)) 
 998         DWORD dwExStyle 
= ::GetWindowLong(GetHwnd(), GWL_EXSTYLE
); 
 999         DWORD dwStyle 
= ::GetWindowLong(GetHwnd(), GWL_STYLE
); 
1000         if (ResetWindowStyle((void *) & rectClient
) && (dwStyle 
& WS_MAXIMIZE
)) 
1002             ::AdjustWindowRectEx(&rectClient
, dwStyle
, FALSE
, dwExStyle
); 
1003             lpPos
->x 
= rectClient
.left
; 
1004             lpPos
->y 
= rectClient
.top
; 
1005             lpPos
->cx 
= rectClient
.right 
- rectClient
.left
; 
1006             lpPos
->cy 
= rectClient
.bottom 
- rectClient
.top
; 
1008         wxMDIParentFrame
* pFrameWnd 
= (wxMDIParentFrame 
*)GetParent(); 
1009         if (pFrameWnd 
&& pFrameWnd
->GetToolBar() && pFrameWnd
->GetToolBar()->IsShown()) 
1011             pFrameWnd
->GetToolBar()->Refresh(); 
1019 bool wxMDIChildFrame::HandleGetMinMaxInfo(void *mmInfo
) 
1021     MINMAXINFO 
*info 
= (MINMAXINFO 
*)mmInfo
; 
1023     // let the default window proc calculate the size of MDI children 
1024     // frames because it is based on the size of the MDI client window, 
1025     // not on the values specified in wxWindow m_max variables 
1026     bool processed 
= MSWDefWindowProc(WM_GETMINMAXINFO
, 0, (LPARAM
)mmInfo
) != 0; 
1028     // but allow GetSizeHints() to set the min size 
1029     if ( m_minWidth 
!= -1 ) 
1031         info
->ptMinTrackSize
.x 
= m_minWidth
; 
1036     if ( m_minHeight 
!= -1 ) 
1038         info
->ptMinTrackSize
.y 
= m_minHeight
; 
1046 // --------------------------------------------------------------------------- 
1047 // MDI specific message translation/preprocessing 
1048 // --------------------------------------------------------------------------- 
1050 long wxMDIChildFrame::MSWDefWindowProc(WXUINT message
, WXUINT wParam
, WXLPARAM lParam
) 
1052     return DefMDIChildProc(GetHwnd(), 
1053                            (UINT
)message
, (WPARAM
)wParam
, (LPARAM
)lParam
); 
1056 bool wxMDIChildFrame::MSWTranslateMessage(WXMSG
* msg
) 
1058     return wxFrame::MSWTranslateMessage(msg
); 
1061 // --------------------------------------------------------------------------- 
1063 // --------------------------------------------------------------------------- 
1065 void wxMDIChildFrame::MSWDestroyWindow() 
1067     MSWDetachWindowMenu(); 
1068     invalidHandle 
= GetHwnd(); 
1070     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
1072     // Must make sure this handle is invalidated (set to NULL) since all sorts 
1073     // of things could happen after the child client is destroyed, but before 
1074     // the wxFrame is destroyed. 
1076     HWND oldHandle 
= (HWND
)GetHWND(); 
1077     SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIDESTROY
, 
1078                 (WPARAM
)oldHandle
, 0); 
1080     if (parent
->GetActiveChild() == (wxMDIChildFrame
*) NULL
) 
1081         ResetWindowStyle((void*) NULL
); 
1087         ::DestroyMenu((HMENU
) m_hMenu
); 
1090     wxRemoveHandleAssociation(this); 
1094 // Change the client window's extended style so we don't get a client edge 
1095 // style when a child is maximised (a double border looks silly.) 
1096 bool wxMDIChildFrame::ResetWindowStyle(void *vrect
) 
1098 #if defined(__WIN95__) 
1099     RECT 
*rect 
= (RECT 
*)vrect
; 
1100     wxMDIParentFrame
* pFrameWnd 
= (wxMDIParentFrame 
*)GetParent(); 
1101     wxMDIChildFrame
* pChild 
= pFrameWnd
->GetActiveChild(); 
1102     if (!pChild 
|| (pChild 
== this)) 
1104         HWND hwndClient 
= GetWinHwnd(pFrameWnd
->GetClientWindow()); 
1105         DWORD dwStyle 
= ::GetWindowLong(hwndClient
, GWL_EXSTYLE
); 
1107         // we want to test whether there is a maximized child, so just set 
1108         // dwThisStyle to 0 if there is no child at all 
1109         DWORD dwThisStyle 
= pChild
 
1110             ? ::GetWindowLong(GetWinHwnd(pChild
), GWL_STYLE
) : 0; 
1111         DWORD dwNewStyle 
= dwStyle
; 
1112         if ( dwThisStyle 
& WS_MAXIMIZE 
) 
1113             dwNewStyle 
&= ~(WS_EX_CLIENTEDGE
); 
1115             dwNewStyle 
|= WS_EX_CLIENTEDGE
; 
1117         if (dwStyle 
!= dwNewStyle
) 
1119             // force update of everything 
1120             ::RedrawWindow(hwndClient
, NULL
, NULL
, 
1121                            RDW_INVALIDATE 
| RDW_ALLCHILDREN
); 
1122             ::SetWindowLong(hwndClient
, GWL_EXSTYLE
, dwNewStyle
); 
1123             ::SetWindowPos(hwndClient
, NULL
, 0, 0, 0, 0, 
1124                            SWP_FRAMECHANGED 
| SWP_NOACTIVATE 
| 
1125                            SWP_NOMOVE 
| SWP_NOSIZE 
| SWP_NOZORDER 
| 
1128                 ::GetClientRect(hwndClient
, rect
); 
1138 // =========================================================================== 
1139 // wxMDIClientWindow: the window of predefined (by Windows) class which 
1140 // contains the child frames 
1141 // =========================================================================== 
1143 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame 
*parent
, long style
) 
1145     m_backgroundColour 
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
); 
1147     CLIENTCREATESTRUCT ccs
; 
1148     m_windowStyle 
= style
; 
1151     ccs
.hWindowMenu 
= (HMENU
) 0; 
1152     if (parent
->GetWindowMenu()) 
1153         ccs
.hWindowMenu 
= (HMENU
) parent
->GetWindowMenu()->GetHMenu(); 
1154     ccs
.idFirstChild 
= wxFIRST_MDI_CHILD
; 
1156     DWORD msStyle 
= MDIS_ALLCHILDSTYLES 
| WS_VISIBLE 
| WS_CHILD 
| 
1157                     WS_CLIPCHILDREN 
| WS_CLIPSIBLINGS
; 
1159     if ( style 
& wxHSCROLL 
) 
1160         msStyle 
|= WS_HSCROLL
; 
1161     if ( style 
& wxVSCROLL 
) 
1162         msStyle 
|= WS_VSCROLL
; 
1164 #if defined(__WIN95__) 
1165     DWORD exStyle 
= WS_EX_CLIENTEDGE
; 
1170     wxWindowCreationHook 
hook(this); 
1171     m_hWnd 
= (WXHWND
)::CreateWindowEx
 
1181                         (LPSTR
)(LPCLIENTCREATESTRUCT
)&ccs
); 
1184         wxLogLastError(wxT("CreateWindowEx(MDI client)")); 
1189     SubclassWin(m_hWnd
); 
1194 // Explicitly call default scroll behaviour 
1195 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
) 
1197     // Note: for client windows, the scroll position is not set in 
1198     // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what 
1199     // scroll position we're at. 
1200     // This makes it hard to paint patterns or bitmaps in the background, 
1201     // and have the client area scrollable as well. 
1203     if ( event
.GetOrientation() == wxHORIZONTAL 
) 
1204         m_scrollX 
= event
.GetPosition(); // Always returns zero! 
1206         m_scrollY 
= event
.GetPosition(); // Always returns zero! 
1211 void wxMDIClientWindow::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
1213     // Try to fix a problem whereby if you show an MDI child frame, then reposition the 
1214     // client area, you can end up with a non-refreshed portion in the client window 
1215     // (see OGL studio sample). So check if the position is changed and if so, 
1216     // redraw the MDI child frames. 
1218     wxPoint oldPos 
= GetPosition(); 
1220     wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
); 
1222     wxPoint newPos 
= GetPosition(); 
1224     if ((newPos
.x 
!= oldPos
.x
) || (newPos
.y 
!= oldPos
.y
)) 
1228             wxNode
* node 
= GetParent()->GetChildren().First(); 
1231                 wxWindow
* child 
= (wxWindow
*) node
->Data(); 
1232                 if (child
->IsKindOf(CLASSINFO(wxMDIChildFrame
))) 
1234                     HWND hWnd 
= (HWND
) child
->GetHWND(); 
1235                    ::RedrawWindow(hWnd
, NULL
, NULL
, RDW_FRAME
|RDW_ALLCHILDREN
|RDW_INVALIDATE 
); 
1237                 node 
= node
->Next(); 
1243 void wxMDIChildFrame::OnIdle(wxIdleEvent
& event
) 
1245     // MDI child frames get their WM_SIZE when they're constructed but at this 
1246     // moment they don't have any children yet so all child windows will be 
1247     // positioned incorrectly when they are added later - to fix this, we 
1248     // generate an artificial size event here 
1249     if ( m_needsResize 
) 
1251         m_needsResize 
= FALSE
; // avoid any possibility of recursion 
1259 // --------------------------------------------------------------------------- 
1260 // non member functions 
1261 // --------------------------------------------------------------------------- 
1263 static void MDISetMenu(wxWindow 
*win
, HMENU hmenuFrame
, HMENU hmenuWindow
) 
1265     ::SendMessage(GetWinHwnd(win
), WM_MDISETMENU
, 
1267                   (WPARAM
)hmenuFrame
, (LPARAM
)hmenuWindow
 
1269                   0, MAKELPARAM(hmenuFrame
, hmenuWindow
) 
1273     // update menu bar of the parent window 
1274     wxWindow 
*parent 
= win
->GetParent(); 
1275     wxCHECK_RET( parent
, wxT("MDI client without parent frame? weird...") ); 
1278     ::SendMessage(GetWinHwnd(win
), WM_MDIREFRESHMENU
, 0, 0L); 
1281     ::DrawMenuBar(GetWinHwnd(parent
)); 
1284 static void InsertWindowMenu(wxWindow 
*win
, WXHMENU menu
, HMENU subMenu
) 
1286     // Try to insert Window menu in front of Help, otherwise append it. 
1287     HMENU hmenu 
= (HMENU
)menu
; 
1291     int N 
= GetMenuItemCount(hmenu
); 
1292     bool success 
= FALSE
; 
1293     for ( int i 
= 0; i 
< N
; i
++ ) 
1296         int chars 
= GetMenuString(hmenu
, i
, buf
, WXSIZEOF(buf
), MF_BYPOSITION
); 
1299             wxLogLastError(wxT("GetMenuString")); 
1304         if ( wxStripMenuCodes(wxString(buf
)).IsSameAs(_("Help")) ) 
1307             ::InsertMenu(hmenu
, i
, MF_BYPOSITION 
| MF_POPUP 
| MF_STRING
, 
1308                          (UINT
)subMenu
, _("&Window")); 
1315         ::AppendMenu(hmenu
, MF_POPUP
, (UINT
)subMenu
, _("&Window")); 
1319     MDISetMenu(win
, hmenu
, subMenu
); 
1322 static void RemoveWindowMenu(wxWindow 
*win
, WXHMENU menu
) 
1324     // Try to insert Window menu in front of Help, otherwise append it. 
1325     HMENU hmenu 
= (HMENU
)menu
; 
1326     int N 
= GetMenuItemCount(hmenu
); 
1327     for ( int i 
= 0; i 
< N
; i
++ ) 
1330         int chars 
= GetMenuString(hmenu
, i
, buf
, WXSIZEOF(buf
), MF_BYPOSITION
); 
1333             wxLogLastError(wxT("GetMenuString")); 
1338         if ( wxStripMenuCodes(wxString(buf
)).IsSameAs(_("Window")) ) 
1340             ::RemoveMenu(hmenu
, i
, MF_BYPOSITION
); 
1345     // Does passing 0 for the window menu really work with WM_MDISETMENU? 
1346     MDISetMenu(win
, hmenu
, 0); 
1349 static void UnpackMDIActivate(WXWPARAM wParam
, WXLPARAM lParam
, 
1350                               WXWORD 
*activate
, WXHWND 
*hwndAct
, WXHWND 
*hwndDeact
) 
1354     *hwndAct 
= (WXHWND
)lParam
; 
1355     *hwndDeact 
= (WXHWND
)wParam
; 
1357     *activate 
= (WXWORD
)wParam
; 
1358     *hwndAct 
= (WXHWND
)LOWORD(lParam
); 
1359     *hwndDeact 
= (WXHWND
)HIWORD(lParam
); 
1360 #endif // Win32/Win16