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
, _("&Cascade")); 
 184       m_windowMenu
->Append(IDM_WINDOWTILEHOR
, _("Tile &Horizontally")); 
 185       m_windowMenu
->Append(IDM_WINDOWTILEVERT
, _("Tile &Vertically")); 
 186       m_windowMenu
->AppendSeparator(); 
 187       m_windowMenu
->Append(IDM_WINDOWICONS
, _("&Arrange Icons")); 
 188       m_windowMenu
->Append(IDM_WINDOWNEXT
, _("&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 #if wxUSE_MENUS_NATIVE 
 275 void wxMDIParentFrame::InternalSetMenuBar() 
 277     m_parentFrameActive 
= TRUE
; 
 279     wxMenu 
*menu 
= GetWindowMenu(); 
 280     HMENU subMenu 
= menu 
? GetHmenuOf(menu
) : 0; 
 282     InsertWindowMenu(GetClientWindow(), m_hMenu
, subMenu
); 
 285 #endif // wxUSE_MENUS_NATIVE 
 287 void wxMDIParentFrame::SetWindowMenu(wxMenu
* menu
) 
 293             // Remove old window menu 
 294             RemoveWindowMenu(GetClientWindow(), m_hMenu
); 
 298         m_windowMenu 
= (wxMenu
*) NULL
; 
 305             InsertWindowMenu(GetClientWindow(), m_hMenu
, 
 306                              GetHmenuOf(m_windowMenu
)); 
 311 void wxMDIParentFrame::OnSize(wxSizeEvent
&) 
 313     if ( GetClientWindow() ) 
 316         GetClientSize(&width
, &height
); 
 318         GetClientWindow()->SetSize(0, 0, width
, height
); 
 322 // Returns the active MDI child window 
 323 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 325     HWND hWnd 
= (HWND
)::SendMessage(GetWinHwnd(GetClientWindow()), 
 326                                     WM_MDIGETACTIVE
, 0, 0L); 
 330         return (wxMDIChildFrame 
*)wxFindWinFromHandle((WXHWND
) hWnd
); 
 333 // Create the client window class (don't Create the window, just return a new 
 335 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 337     return new wxMDIClientWindow
; 
 340 // Responds to colour changes, and passes event on to children. 
 341 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
 343     if ( m_clientWindow 
) 
 345         m_clientWindow
->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
)); 
 346         m_clientWindow
->Refresh(); 
 352 // --------------------------------------------------------------------------- 
 354 // --------------------------------------------------------------------------- 
 356 void wxMDIParentFrame::Cascade() 
 358     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDICASCADE
, 0, 0); 
 361 // TODO: add a direction argument (hor/vert) 
 362 void wxMDIParentFrame::Tile() 
 364     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDITILE
, MDITILE_HORIZONTAL
, 0); 
 367 void wxMDIParentFrame::ArrangeIcons() 
 369     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDIICONARRANGE
, 0, 0); 
 372 void wxMDIParentFrame::ActivateNext() 
 374     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 0); 
 377 void wxMDIParentFrame::ActivatePrevious() 
 379     ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 1); 
 382 // --------------------------------------------------------------------------- 
 383 // the MDI parent frame window proc 
 384 // --------------------------------------------------------------------------- 
 386 long wxMDIParentFrame::MSWWindowProc(WXUINT message
, 
 391     bool processed 
= FALSE
; 
 397                 WXWORD state
, minimized
; 
 399                 UnpackActivate(wParam
, lParam
, &state
, &minimized
, &hwnd
); 
 401                 processed 
= HandleActivate(state
, minimized 
!= 0, hwnd
); 
 409                 UnpackCommand(wParam
, lParam
, &id
, &hwnd
, &cmd
); 
 411                 (void)HandleCommand(id
, cmd
, hwnd
); 
 413                 // even if the frame didn't process it, there is no need to try it 
 414                 // once again (i.e. call wxFrame::HandleCommand()) - we just dud it, 
 415                 // so pretend we processed the message anyhow 
 419             // always pass this message DefFrameProc(), otherwise MDI menu 
 420             // commands (and sys commands - more surprizingly!) won't work 
 421             MSWDefWindowProc(message
, wParam
, lParam
); 
 425             m_clientWindow 
= OnCreateClient(); 
 426             // Uses own style for client style 
 427             if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) ) 
 429                 wxLogMessage(_("Failed to create MDI parent frame.")); 
 440             // we erase background ourselves 
 448                 UnpackMenuSelect(wParam
, lParam
, &item
, &flags
, &hmenu
); 
 450                 if ( m_parentFrameActive 
) 
 452                     processed 
= HandleMenuSelect(item
, flags
, hmenu
); 
 454                 else if (m_currentChild
) 
 456                     processed 
= m_currentChild
-> 
 457                         HandleMenuSelect(item
, flags
, hmenu
); 
 463             // as we don't (usually) resize the MDI client to exactly fit the 
 464             // client area (we put it below the toolbar, above statusbar &c), 
 465             // we should not pass this one to DefFrameProc 
 470         rc 
= wxFrame::MSWWindowProc(message
, wParam
, lParam
); 
 475 bool wxMDIParentFrame::HandleActivate(int state
, bool minimized
, WXHWND activate
) 
 477     bool processed 
= FALSE
; 
 479     if ( wxWindow::HandleActivate(state
, minimized
, activate
) ) 
 485     // If this window is an MDI parent, we must also send an OnActivate message 
 486     // to the current child. 
 487     if ( (m_currentChild 
!= NULL
) && 
 488          ((state 
== WA_ACTIVE
) || (state 
== WA_CLICKACTIVE
)) ) 
 490         wxActivateEvent 
event(wxEVT_ACTIVATE
, TRUE
, m_currentChild
->GetId()); 
 491         event
.SetEventObject( m_currentChild 
); 
 492         if ( m_currentChild
->GetEventHandler()->ProcessEvent(event
) ) 
 499 bool wxMDIParentFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
) 
 501     // In case it's e.g. a toolbar. 
 504         wxWindow 
*win 
= wxFindWinFromHandle(hwnd
); 
 506             return win
->MSWCommand(cmd
, id
); 
 509     // is it one of standard MDI commands? 
 514         case IDM_WINDOWCASCADE
: 
 516             wParam 
= MDITILE_SKIPDISABLED
; 
 519         case IDM_WINDOWTILEHOR
: 
 520             wParam 
|= MDITILE_HORIZONTAL
; 
 523         case IDM_WINDOWTILEVERT
: 
 525                 wParam 
= MDITILE_VERTICAL
; 
 527             wParam 
|= MDITILE_SKIPDISABLED
; 
 530         case IDM_WINDOWICONS
: 
 531             msg 
= WM_MDIICONARRANGE
; 
 544         ::SendMessage(GetWinHwnd(GetClientWindow()), msg
, wParam
, 0); 
 549     // FIXME VZ: what does this test do?? 
 552         return FALSE
; // Get WndProc to call default proc 
 555     if ( IsMdiCommandId(id
) ) 
 557         wxWindowList::Node
* node 
= GetChildren().GetFirst(); 
 560             wxWindow
* child 
= node
->GetData(); 
 561             if ( child
->GetHWND() ) 
 563                 long childId 
= wxGetWindowId(child
->GetHWND()); 
 564                 if (childId 
== (long)id
) 
 566                     ::SendMessage( GetWinHwnd(GetClientWindow()), 
 568                                    (WPARAM
)child
->GetHWND(), 0); 
 572             node 
= node
->GetNext(); 
 575     else if ( m_parentFrameActive 
) 
 577         return ProcessCommand(id
); 
 579     else if ( m_currentChild 
) 
 581         return m_currentChild
->HandleCommand(id
, cmd
, hwnd
); 
 585         // this shouldn't happen because it means that our messages are being 
 586         // lost (they're not sent to the parent frame nor to the children) 
 587         wxFAIL_MSG(wxT("MDI parent frame is not active, yet there is no active MDI child?")); 
 593 long wxMDIParentFrame::MSWDefWindowProc(WXUINT message
, 
 598     if ( GetClientWindow() ) 
 599         clientWnd 
= GetClientWindow()->GetHWND(); 
 603     return DefFrameProc(GetHwnd(), (HWND
)clientWnd
, message
, wParam
, lParam
); 
 606 bool wxMDIParentFrame::MSWTranslateMessage(WXMSG
* msg
) 
 608     MSG 
*pMsg 
= (MSG 
*)msg
; 
 610     // first let the current child get it 
 611     if ( m_currentChild 
&& m_currentChild
->GetHWND() && 
 612          m_currentChild
->MSWTranslateMessage(msg
) ) 
 617     // then try out accel table (will also check the menu accels) 
 618     if ( wxFrame::MSWTranslateMessage(msg
) ) 
 623     // finally, check for MDI specific built in accel keys 
 624     if ( pMsg
->message 
== WM_KEYDOWN 
|| pMsg
->message 
== WM_SYSKEYDOWN 
) 
 626         if ( ::TranslateMDISysAccel(GetWinHwnd(GetClientWindow()), pMsg
)) 
 633 // =========================================================================== 
 635 // =========================================================================== 
 637 void wxMDIChildFrame::Init() 
 639     m_needsResize 
= TRUE
; 
 642 bool wxMDIChildFrame::Create(wxMDIParentFrame 
*parent
, 
 644                              const wxString
& title
, 
 648                              const wxString
& name
) 
 650   m_defaultIcon 
= (WXHICON
)(wxSTD_MDICHILDFRAME_ICON 
? wxSTD_MDICHILDFRAME_ICON
 
 651                                                      : wxDEFAULT_MDICHILDFRAME_ICON
); 
 654   wxWindowBase::Show(TRUE
); // MDI child frame starts off shown 
 659     m_windowId 
= (int)NewControlId(); 
 663       parent
->AddChild(this); 
 675   mcs
.szClass 
= style 
& wxNO_FULL_REPAINT_ON_RESIZE
 
 676                     ? wxMDIChildFrameClassNameNoRedraw
 
 677                     : wxMDIChildFrameClassName
; 
 679   mcs
.hOwner 
= wxGetInstance(); 
 683       mcs
.x 
= CW_USEDEFAULT
; 
 688       mcs
.y 
= CW_USEDEFAULT
; 
 693       mcs
.cx 
= CW_USEDEFAULT
; 
 698       mcs
.cy 
= CW_USEDEFAULT
; 
 700   DWORD msflags 
= WS_OVERLAPPED 
| WS_CLIPCHILDREN 
| WS_THICKFRAME 
| WS_VISIBLE 
; 
 701   if (style 
& wxMINIMIZE_BOX
) 
 702     msflags 
|= WS_MINIMIZEBOX
; 
 703   if (style 
& wxMAXIMIZE_BOX
) 
 704     msflags 
|= WS_MAXIMIZEBOX
; 
 705   if (style 
& wxTHICK_FRAME
) 
 706     msflags 
|= WS_THICKFRAME
; 
 707   if (style 
& wxSYSTEM_MENU
) 
 708     msflags 
|= WS_SYSMENU
; 
 709   if ((style 
& wxMINIMIZE
) || (style 
& wxICONIZE
)) 
 710     msflags 
|= WS_MINIMIZE
; 
 711   if (style 
& wxMAXIMIZE
) 
 712     msflags 
|= WS_MAXIMIZE
; 
 713   if (style 
& wxCAPTION
) 
 714     msflags 
|= WS_CAPTION
; 
 720   m_hWnd 
= (WXHWND
)::SendMessage(GetWinHwnd(parent
->GetClientWindow()), 
 721                                  WM_MDICREATE
, 0, (LONG
)(LPSTR
)&mcs
); 
 724   wxAssociateWinWithHandle((HWND
) GetHWND(), this); 
 726   // VZ: what's this? an act of piracy? 
 727   //SetWindowLong(GetHwnd(), 0, (long)this); 
 729   wxModelessWindows
.Append(this); 
 734 wxMDIChildFrame::~wxMDIChildFrame() 
 738     // already delete by DestroyChildren() 
 739     m_frameToolBar 
= NULL
; 
 740     m_frameStatusBar 
= NULL
; 
 745 // Set the client size (i.e. leave the calculation of borders etc. 
 747 void wxMDIChildFrame::DoSetClientSize(int width
, int height
) 
 749   HWND hWnd 
= GetHwnd(); 
 752   ::GetClientRect(hWnd
, &rect
); 
 755   GetWindowRect(hWnd
, &rect2
); 
 757   // Find the difference between the entire window (title bar and all) 
 758   // and the client area; add this to the new client size to move the 
 760   int actual_width 
= rect2
.right 
- rect2
.left 
- rect
.right 
+ width
; 
 761   int actual_height 
= rect2
.bottom 
- rect2
.top 
- rect
.bottom 
+ height
; 
 763   if (GetStatusBar() && GetStatusBar()->IsShown()) 
 766     GetStatusBar()->GetSize(&sx
, &sy
); 
 771   point
.x 
= rect2
.left
; 
 774   // If there's an MDI parent, must subtract the parent's top left corner 
 775   // since MoveWindow moves relative to the parent 
 776   wxMDIParentFrame 
*mdiParent 
= (wxMDIParentFrame 
*)GetParent(); 
 777   ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
); 
 779   MoveWindow(hWnd
, point
.x
, point
.y
, actual_width
, actual_height
, (BOOL
)TRUE
); 
 781   wxSizeEvent 
event(wxSize(width
, height
), m_windowId
); 
 782   event
.SetEventObject( this ); 
 783   GetEventHandler()->ProcessEvent(event
); 
 786 void wxMDIChildFrame::DoGetPosition(int *x
, int *y
) const 
 789   GetWindowRect(GetHwnd(), &rect
); 
 794   // Since we now have the absolute screen coords, 
 795   // if there's a parent we must subtract its top left corner 
 796   wxMDIParentFrame 
*mdiParent 
= (wxMDIParentFrame 
*)GetParent(); 
 797   ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
); 
 803 void wxMDIChildFrame::InternalSetMenuBar() 
 805     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 807     // HMENU subMenu = GetSubMenu((HMENU)parent->GetWindowMenu(), 0); 
 808     HMENU subMenu 
= (HMENU
) 0; 
 809     if (parent
->GetWindowMenu()) 
 810         subMenu 
= (HMENU
) parent
->GetWindowMenu()->GetHMenu(); 
 812     InsertWindowMenu(parent
->GetClientWindow(), m_hMenu
, subMenu
); 
 814     parent
->m_parentFrameActive 
= FALSE
; 
 817 // --------------------------------------------------------------------------- 
 819 // --------------------------------------------------------------------------- 
 821 void wxMDIChildFrame::Maximize(bool maximize
) 
 823     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 824     if ( parent 
&& parent
->GetClientWindow() ) 
 826         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), 
 827                       maximize 
? WM_MDIMAXIMIZE 
: WM_MDIRESTORE
, 
 828                       (WPARAM
)GetHwnd(), 0); 
 832 void wxMDIChildFrame::Restore() 
 834     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 835     if ( parent 
&& parent
->GetClientWindow() ) 
 837         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIRESTORE
, 
 838                       (WPARAM
) GetHwnd(), 0); 
 842 void wxMDIChildFrame::Activate() 
 844     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 845     if ( parent 
&& parent
->GetClientWindow() ) 
 847         ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIACTIVATE
, 
 848                       (WPARAM
) GetHwnd(), 0); 
 852 // --------------------------------------------------------------------------- 
 853 // MDI window proc and message handlers 
 854 // --------------------------------------------------------------------------- 
 856 long wxMDIChildFrame::MSWWindowProc(WXUINT message
, 
 861     bool processed 
= FALSE
; 
 869                 UnpackCommand((WXWPARAM
)wParam
, (WXLPARAM
)lParam
, 
 872                 processed 
= HandleCommand(id
, cmd
, (WXHWND
)hwnd
); 
 876         case WM_GETMINMAXINFO
: 
 877             processed 
= HandleGetMinMaxInfo((MINMAXINFO 
*)lParam
); 
 883                 WXHWND hwndAct
, hwndDeact
; 
 884                 UnpackMDIActivate(wParam
, lParam
, &act
, &hwndAct
, &hwndDeact
); 
 886                 processed 
= HandleMDIActivate(act
, hwndAct
, hwndDeact
); 
 891             // must pass WM_MOVE to DefMDIChildProc() to recalculate MDI client 
 892             // scrollbars if necessary 
 897             // must pass WM_SIZE to DefMDIChildProc(), otherwise many weird 
 899             MSWDefWindowProc(message
, wParam
, lParam
); 
 903             // DefMDIChildProc handles SC_{NEXT/PREV}WINDOW here, so pass it 
 904             // the message (the base class version does not) 
 905             return MSWDefWindowProc(message
, wParam
, lParam
); 
 907         case WM_WINDOWPOSCHANGING
: 
 908             processed 
= HandleWindowPosChanging((LPWINDOWPOS
)lParam
); 
 913         rc 
= wxFrame::MSWWindowProc(message
, wParam
, lParam
); 
 918 bool wxMDIChildFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
) 
 920     // In case it's e.g. a toolbar. 
 923         wxWindow 
*win 
= wxFindWinFromHandle(hwnd
); 
 925             return win
->MSWCommand(cmd
, id
); 
 928     if (wxCurrentPopupMenu
) 
 930         wxMenu 
*popupMenu 
= wxCurrentPopupMenu
; 
 931         wxCurrentPopupMenu 
= NULL
; 
 932         if (popupMenu
->MSWCommand(cmd
, id
)) 
 937     if (GetMenuBar() && GetMenuBar()->FindItem(id
)) 
 939         processed 
= ProcessCommand(id
); 
 949 bool wxMDIChildFrame::HandleMDIActivate(long WXUNUSED(activate
), 
 953     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
 959     if ( m_hWnd 
== hwndAct 
) 
 962         parent
->m_currentChild 
= this; 
 964         HMENU child_menu 
= (HMENU
)GetWinMenu(); 
 967             parent
->m_parentFrameActive 
= FALSE
; 
 969             menuToSet 
= child_menu
; 
 972     else if ( m_hWnd 
== hwndDeact 
) 
 974         wxASSERT_MSG( parent
->m_currentChild 
== this, 
 975                       wxT("can't deactivate MDI child which wasn't active!") ); 
 978         parent
->m_currentChild 
= NULL
; 
 980         HMENU parent_menu 
= (HMENU
)parent
->GetWinMenu(); 
 982         // activate the the parent menu only when there is no other child 
 983         // that has been activated 
 984         if ( parent_menu 
&& !hwndAct 
) 
 986             parent
->m_parentFrameActive 
= TRUE
; 
 988             menuToSet 
= parent_menu
; 
 993         // we have nothing to do with it 
 999         HMENU subMenu 
= (HMENU
) 0; 
1000         if (parent
->GetWindowMenu()) 
1001             subMenu 
= (HMENU
) parent
->GetWindowMenu()->GetHMenu(); 
1003         MDISetMenu(parent
->GetClientWindow(), menuToSet
, subMenu
); 
1006     wxActivateEvent 
event(wxEVT_ACTIVATE
, activated
, m_windowId
); 
1007     event
.SetEventObject( this ); 
1009     ResetWindowStyle((void *)NULL
); 
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 bool wxMDIChildFrame::HandleGetMinMaxInfo(void *mmInfo
) 
1044     MINMAXINFO 
*info 
= (MINMAXINFO 
*)mmInfo
; 
1046     // let the default window proc calculate the size of MDI children 
1047     // frames because it is based on the size of the MDI client window, 
1048     // not on the values specified in wxWindow m_max variables 
1049     bool processed 
= MSWDefWindowProc(WM_GETMINMAXINFO
, 0, (LPARAM
)mmInfo
) != 0; 
1051     // but allow GetSizeHints() to set the min size 
1052     if ( m_minWidth 
!= -1 ) 
1054         info
->ptMinTrackSize
.x 
= m_minWidth
; 
1059     if ( m_minHeight 
!= -1 ) 
1061         info
->ptMinTrackSize
.y 
= m_minHeight
; 
1069 // --------------------------------------------------------------------------- 
1070 // MDI specific message translation/preprocessing 
1071 // --------------------------------------------------------------------------- 
1073 long wxMDIChildFrame::MSWDefWindowProc(WXUINT message
, WXUINT wParam
, WXLPARAM lParam
) 
1075     return DefMDIChildProc(GetHwnd(), 
1076                            (UINT
)message
, (WPARAM
)wParam
, (LPARAM
)lParam
); 
1079 bool wxMDIChildFrame::MSWTranslateMessage(WXMSG
* msg
) 
1081     return wxFrame::MSWTranslateMessage(msg
); 
1084 // --------------------------------------------------------------------------- 
1086 // --------------------------------------------------------------------------- 
1088 void wxMDIChildFrame::MSWDestroyWindow() 
1090     MSWDetachWindowMenu(); 
1091     invalidHandle 
= GetHwnd(); 
1093     wxMDIParentFrame 
*parent 
= (wxMDIParentFrame 
*)GetParent(); 
1095     // Must make sure this handle is invalidated (set to NULL) since all sorts 
1096     // of things could happen after the child client is destroyed, but before 
1097     // the wxFrame is destroyed. 
1099     HWND oldHandle 
= (HWND
)GetHWND(); 
1100     SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIDESTROY
, 
1101                 (WPARAM
)oldHandle
, 0); 
1103     if (parent
->GetActiveChild() == (wxMDIChildFrame
*) NULL
) 
1104         ResetWindowStyle((void*) NULL
); 
1110         ::DestroyMenu((HMENU
) m_hMenu
); 
1113     wxRemoveHandleAssociation(this); 
1117 // Change the client window's extended style so we don't get a client edge 
1118 // style when a child is maximised (a double border looks silly.) 
1119 bool wxMDIChildFrame::ResetWindowStyle(void *vrect
) 
1121 #if defined(__WIN95__) 
1122     RECT 
*rect 
= (RECT 
*)vrect
; 
1123     wxMDIParentFrame
* pFrameWnd 
= (wxMDIParentFrame 
*)GetParent(); 
1124     wxMDIChildFrame
* pChild 
= pFrameWnd
->GetActiveChild(); 
1125     if (!pChild 
|| (pChild 
== this)) 
1127         HWND hwndClient 
= GetWinHwnd(pFrameWnd
->GetClientWindow()); 
1128         DWORD dwStyle 
= ::GetWindowLong(hwndClient
, GWL_EXSTYLE
); 
1130         // we want to test whether there is a maximized child, so just set 
1131         // dwThisStyle to 0 if there is no child at all 
1132         DWORD dwThisStyle 
= pChild
 
1133             ? ::GetWindowLong(GetWinHwnd(pChild
), GWL_STYLE
) : 0; 
1134         DWORD dwNewStyle 
= dwStyle
; 
1135         if ( dwThisStyle 
& WS_MAXIMIZE 
) 
1136             dwNewStyle 
&= ~(WS_EX_CLIENTEDGE
); 
1138             dwNewStyle 
|= WS_EX_CLIENTEDGE
; 
1140         if (dwStyle 
!= dwNewStyle
) 
1142             // force update of everything 
1143             ::RedrawWindow(hwndClient
, NULL
, NULL
, 
1144                            RDW_INVALIDATE 
| RDW_ALLCHILDREN
); 
1145             ::SetWindowLong(hwndClient
, GWL_EXSTYLE
, dwNewStyle
); 
1146             ::SetWindowPos(hwndClient
, NULL
, 0, 0, 0, 0, 
1147                            SWP_FRAMECHANGED 
| SWP_NOACTIVATE 
| 
1148                            SWP_NOMOVE 
| SWP_NOSIZE 
| SWP_NOZORDER 
| 
1151                 ::GetClientRect(hwndClient
, rect
); 
1161 // =========================================================================== 
1162 // wxMDIClientWindow: the window of predefined (by Windows) class which 
1163 // contains the child frames 
1164 // =========================================================================== 
1166 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame 
*parent
, long style
) 
1168     m_backgroundColour 
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
); 
1170     CLIENTCREATESTRUCT ccs
; 
1171     m_windowStyle 
= style
; 
1174     ccs
.hWindowMenu 
= (HMENU
) 0; 
1175     if (parent
->GetWindowMenu()) 
1176         ccs
.hWindowMenu 
= (HMENU
) parent
->GetWindowMenu()->GetHMenu(); 
1177     ccs
.idFirstChild 
= wxFIRST_MDI_CHILD
; 
1179     DWORD msStyle 
= MDIS_ALLCHILDSTYLES 
| WS_VISIBLE 
| WS_CHILD 
| 
1180                     WS_CLIPCHILDREN 
| WS_CLIPSIBLINGS
; 
1182     if ( style 
& wxHSCROLL 
) 
1183         msStyle 
|= WS_HSCROLL
; 
1184     if ( style 
& wxVSCROLL 
) 
1185         msStyle 
|= WS_VSCROLL
; 
1187 #if defined(__WIN95__) 
1188     DWORD exStyle 
= WS_EX_CLIENTEDGE
; 
1194     m_hWnd 
= (WXHWND
)::CreateWindowEx
 
1204                         (LPSTR
)(LPCLIENTCREATESTRUCT
)&ccs
); 
1207         wxLogLastError(wxT("CreateWindowEx(MDI client)")); 
1212     SubclassWin(m_hWnd
); 
1218 // Explicitly call default scroll behaviour 
1219 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
) 
1221     // Note: for client windows, the scroll position is not set in 
1222     // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what 
1223     // scroll position we're at. 
1224     // This makes it hard to paint patterns or bitmaps in the background, 
1225     // and have the client area scrollable as well. 
1227     if ( event
.GetOrientation() == wxHORIZONTAL 
) 
1228         m_scrollX 
= event
.GetPosition(); // Always returns zero! 
1230         m_scrollY 
= event
.GetPosition(); // Always returns zero! 
1235 void wxMDIClientWindow::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
1237     // Try to fix a problem whereby if you show an MDI child frame, then reposition the 
1238     // client area, you can end up with a non-refreshed portion in the client window 
1239     // (see OGL studio sample). So check if the position is changed and if so, 
1240     // redraw the MDI child frames. 
1242     wxPoint oldPos 
= GetPosition(); 
1244     wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
); 
1246     wxPoint newPos 
= GetPosition(); 
1248     if ((newPos
.x 
!= oldPos
.x
) || (newPos
.y 
!= oldPos
.y
)) 
1252             wxNode
* node 
= GetParent()->GetChildren().First(); 
1255                 wxWindow
* child 
= (wxWindow
*) node
->Data(); 
1256                 if (child
->IsKindOf(CLASSINFO(wxMDIChildFrame
))) 
1258                     HWND hWnd 
= (HWND
) child
->GetHWND(); 
1259                    ::RedrawWindow(hWnd
, NULL
, NULL
, RDW_FRAME
|RDW_ALLCHILDREN
|RDW_INVALIDATE 
); 
1261                 node 
= node
->Next(); 
1267 void wxMDIChildFrame::OnIdle(wxIdleEvent
& event
) 
1269     // MDI child frames get their WM_SIZE when they're constructed but at this 
1270     // moment they don't have any children yet so all child windows will be 
1271     // positioned incorrectly when they are added later - to fix this, we 
1272     // generate an artificial size event here 
1273     if ( m_needsResize 
) 
1275         m_needsResize 
= FALSE
; // avoid any possibility of recursion 
1283 // --------------------------------------------------------------------------- 
1284 // non member functions 
1285 // --------------------------------------------------------------------------- 
1287 static void MDISetMenu(wxWindow 
*win
, HMENU hmenuFrame
, HMENU hmenuWindow
) 
1289     ::SendMessage(GetWinHwnd(win
), WM_MDISETMENU
, 
1291                   (WPARAM
)hmenuFrame
, (LPARAM
)hmenuWindow
 
1293                   0, MAKELPARAM(hmenuFrame
, hmenuWindow
) 
1297     // update menu bar of the parent window 
1298     wxWindow 
*parent 
= win
->GetParent(); 
1299     wxCHECK_RET( parent
, wxT("MDI client without parent frame? weird...") ); 
1302     ::SendMessage(GetWinHwnd(win
), WM_MDIREFRESHMENU
, 0, 0L); 
1305     ::DrawMenuBar(GetWinHwnd(parent
)); 
1308 static void InsertWindowMenu(wxWindow 
*win
, WXHMENU menu
, HMENU subMenu
) 
1310     // Try to insert Window menu in front of Help, otherwise append it. 
1311     HMENU hmenu 
= (HMENU
)menu
; 
1315     int N 
= GetMenuItemCount(hmenu
); 
1316     bool success 
= FALSE
; 
1317     for ( int i 
= 0; i 
< N
; i
++ ) 
1320         int chars 
= GetMenuString(hmenu
, i
, buf
, WXSIZEOF(buf
), MF_BYPOSITION
); 
1323             wxLogLastError(wxT("GetMenuString")); 
1328         if ( wxStripMenuCodes(wxString(buf
)).IsSameAs(_("Help")) ) 
1331             ::InsertMenu(hmenu
, i
, MF_BYPOSITION 
| MF_POPUP 
| MF_STRING
, 
1332                          (UINT
)subMenu
, _("&Window")); 
1339         ::AppendMenu(hmenu
, MF_POPUP
, (UINT
)subMenu
, _("&Window")); 
1343     MDISetMenu(win
, hmenu
, subMenu
); 
1346 static void RemoveWindowMenu(wxWindow 
*win
, WXHMENU menu
) 
1348     // Try to insert Window menu in front of Help, otherwise append it. 
1349     HMENU hmenu 
= (HMENU
)menu
; 
1350     int N 
= GetMenuItemCount(hmenu
); 
1351     for ( int i 
= 0; i 
< N
; i
++ ) 
1354         int chars 
= GetMenuString(hmenu
, i
, buf
, WXSIZEOF(buf
), MF_BYPOSITION
); 
1357             wxLogLastError(wxT("GetMenuString")); 
1362         if ( wxStripMenuCodes(wxString(buf
)).IsSameAs(_("Window")) ) 
1364             ::RemoveMenu(hmenu
, i
, MF_BYPOSITION
); 
1369     // Does passing 0 for the window menu really work with WM_MDISETMENU? 
1370     MDISetMenu(win
, hmenu
, 0); 
1373 static void UnpackMDIActivate(WXWPARAM wParam
, WXLPARAM lParam
, 
1374                               WXWORD 
*activate
, WXHWND 
*hwndAct
, WXHWND 
*hwndDeact
) 
1378     *hwndAct 
= (WXHWND
)lParam
; 
1379     *hwndDeact 
= (WXHWND
)wParam
; 
1381     *activate 
= (WXWORD
)wParam
; 
1382     *hwndAct 
= (WXHWND
)LOWORD(lParam
); 
1383     *hwndDeact 
= (WXHWND
)HIWORD(lParam
); 
1384 #endif // Win32/Win16