1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: MDI classes
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
;
67 extern const wxChar
*wxMDIChildFrameClassName
;
68 extern wxWindow
*wxWndHook
; // from window.cpp
70 extern void wxAssociateWinWithHandle(HWND hWnd
, wxWindow
*win
);
72 static HWND invalidHandle
= 0;
74 // ---------------------------------------------------------------------------
76 // ---------------------------------------------------------------------------
78 static const int IDM_WINDOWTILE
= 4001;
79 static const int IDM_WINDOWTILEHOR
= 4001;
80 static const int IDM_WINDOWCASCADE
= 4002;
81 static const int IDM_WINDOWICONS
= 4003;
82 static const int IDM_WINDOWNEXT
= 4004;
83 static const int IDM_WINDOWTILEVERT
= 4005;
85 // This range gives a maximum of 500 MDI children. Should be enough :-)
86 static const int wxFIRST_MDI_CHILD
= 4100;
87 static const int wxLAST_MDI_CHILD
= 4600;
89 // Status border dimensions
90 static const int wxTHICK_LINE_BORDER
= 3;
91 static const int wxTHICK_LINE_WIDTH
= 1;
93 // ---------------------------------------------------------------------------
95 // ---------------------------------------------------------------------------
97 // set the MDI menus (by sending the WM_MDISETMENU message) and update the menu
98 // of the parent of win (which is supposed to be the MDI client window)
99 static void MDISetMenu(wxWindow
*win
, HMENU hmenuFrame
, HMENU hmenuWindow
);
101 // insert the window menu (subMenu) into menu just before "Help" submenu or at
102 // the very end if not found
103 static void InsertWindowMenu(wxWindow
*win
, WXHMENU menu
, HMENU subMenu
);
105 // is this an id of an MDI child?
106 inline bool IsMdiCommandId(int id
)
108 return (id
>= wxFIRST_MDI_CHILD
) && (id
<= wxLAST_MDI_CHILD
);
111 static void UnpackMDIActivate(WXWPARAM wParam
, WXLPARAM lParam
,
112 WXWORD
*activate
, WXHWND
*hwndAct
, WXHWND
*hwndDeact
);
114 // ===========================================================================
116 // ===========================================================================
118 // ---------------------------------------------------------------------------
120 // ---------------------------------------------------------------------------
122 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
123 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
124 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
)
126 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
127 EVT_SIZE(wxMDIParentFrame::OnSize
)
128 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
131 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxWindow
)
132 EVT_SCROLL(wxMDIClientWindow::OnScroll
)
135 // ===========================================================================
136 // wxMDIParentFrame: the frame which contains the client window which manages
138 // ===========================================================================
140 wxMDIParentFrame::wxMDIParentFrame()
142 m_clientWindow
= NULL
;
143 m_currentChild
= NULL
;
145 m_parentFrameActive
= TRUE
;
148 bool wxMDIParentFrame::Create(wxWindow
*parent
,
150 const wxString
& title
,
154 const wxString
& name
)
156 m_defaultIcon
= (WXHICON
) (wxSTD_MDIPARENTFRAME_ICON
? wxSTD_MDIPARENTFRAME_ICON
: wxDEFAULT_MDIPARENTFRAME_ICON
);
158 m_clientWindow
= NULL
;
159 m_currentChild
= NULL
;
161 m_parentFrameActive
= TRUE
;
164 wxTopLevelWindows
.Append(this);
167 m_windowStyle
= style
;
169 if (parent
) parent
->AddChild(this);
174 m_windowId
= (int)NewControlId();
181 m_windowMenu
= (WXHMENU
) ::LoadMenu(wxGetInstance(), wxT("wxWindowMenu"));
183 DWORD msflags
= WS_OVERLAPPED
;
184 if (style
& wxMINIMIZE_BOX
)
185 msflags
|= WS_MINIMIZEBOX
;
186 if (style
& wxMAXIMIZE_BOX
)
187 msflags
|= WS_MAXIMIZEBOX
;
188 if (style
& wxTHICK_FRAME
)
189 msflags
|= WS_THICKFRAME
;
190 if (style
& wxSYSTEM_MENU
)
191 msflags
|= WS_SYSMENU
;
192 if ((style
& wxMINIMIZE
) || (style
& wxICONIZE
))
193 msflags
|= WS_MINIMIZE
;
194 if (style
& wxMAXIMIZE
)
195 msflags
|= WS_MAXIMIZE
;
196 if (style
& wxCAPTION
)
197 msflags
|= WS_CAPTION
;
199 if (style
& wxCLIP_CHILDREN
)
200 msflags
|= WS_CLIPCHILDREN
;
202 wxWindow::MSWCreate(m_windowId
, parent
, wxMDIFrameClassName
, this, title
, x
, y
, width
, height
,
205 wxModelessWindows
.Append(this);
210 wxMDIParentFrame::~wxMDIParentFrame()
213 // already delete by DestroyChildren()
214 m_frameToolBar
= NULL
;
216 ::DestroyMenu((HMENU
)m_windowMenu
);
219 if ( m_clientWindow
)
221 if ( m_clientWindow
->MSWGetOldWndProc() )
222 m_clientWindow
->UnsubclassWin();
224 m_clientWindow
->SetHWND(0);
225 delete m_clientWindow
;
229 void wxMDIParentFrame::InternalSetMenuBar()
231 HMENU subMenu
= GetSubMenu((HMENU
) m_windowMenu
, 0);
233 m_parentFrameActive
= TRUE
;
235 InsertWindowMenu(GetClientWindow(), m_hMenu
, subMenu
);
238 void wxMDIParentFrame::OnSize(wxSizeEvent
& event
)
240 if ( GetClientWindow() )
243 GetClientSize(&width
, &height
);
245 GetClientWindow()->SetSize(0, 0, width
, height
);
249 // Returns the active MDI child window
250 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
252 HWND hWnd
= (HWND
)::SendMessage(GetWinHwnd(GetClientWindow()),
253 WM_MDIGETACTIVE
, 0, 0L);
257 return (wxMDIChildFrame
*)wxFindWinFromHandle((WXHWND
) hWnd
);
260 // Create the client window class (don't Create the window, just return a new
262 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
264 return new wxMDIClientWindow
;
267 // Responds to colour changes, and passes event on to children.
268 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
270 if ( m_clientWindow
)
272 m_clientWindow
->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
273 m_clientWindow
->Refresh();
279 // ---------------------------------------------------------------------------
281 // ---------------------------------------------------------------------------
283 void wxMDIParentFrame::Cascade()
285 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDICASCADE
, 0, 0);
288 // TODO: add a direction argument (hor/vert)
289 void wxMDIParentFrame::Tile()
291 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDITILE
, MDITILE_HORIZONTAL
, 0);
294 void wxMDIParentFrame::ArrangeIcons()
296 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDIICONARRANGE
, 0, 0);
299 void wxMDIParentFrame::ActivateNext()
301 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 0);
304 void wxMDIParentFrame::ActivatePrevious()
306 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT
, 0, 1);
309 // ---------------------------------------------------------------------------
310 // the MDI parent frame window proc
311 // ---------------------------------------------------------------------------
313 long wxMDIParentFrame::MSWWindowProc(WXUINT message
,
318 bool processed
= FALSE
;
324 WXWORD state
, minimized
;
326 UnpackActivate(wParam
, lParam
, &state
, &minimized
, &hwnd
);
328 processed
= HandleActivate(state
, minimized
!= 0, hwnd
);
336 UnpackCommand(wParam
, lParam
, &id
, &hwnd
, &cmd
);
338 (void)HandleCommand(id
, cmd
, hwnd
);
340 // even if the frame didn't process it, there is no need to try it
341 // once again (i.e. call wxFrame::HandleCommand()) - we just dud it,
342 // so pretend we processed the message anyhow
346 // always pass this message DefFrameProc(), otherwise MDI menu
347 // commands (and sys commands - more surprizingly!) won't work
348 MSWDefWindowProc(message
, wParam
, lParam
);
352 m_clientWindow
= OnCreateClient();
353 // Uses own style for client style
354 if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) )
356 wxLogMessage(_("Failed to create MDI parent frame."));
367 // we erase background ourselves
375 UnpackMenuSelect(wParam
, lParam
, &item
, &flags
, &hmenu
);
377 if ( m_parentFrameActive
)
379 processed
= HandleMenuSelect(item
, flags
, hmenu
);
381 else if (m_currentChild
)
383 processed
= m_currentChild
->
384 HandleMenuSelect(item
, flags
, hmenu
);
390 // as we don't (usually) resize the MDI client to exactly fit the
391 // client area (we put it below the toolbar, above statusbar &c),
392 // we should not pass this one to DefFrameProc
397 rc
= wxFrame::MSWWindowProc(message
, wParam
, lParam
);
402 bool wxMDIParentFrame::HandleActivate(int state
, bool minimized
, WXHWND activate
)
404 bool processed
= FALSE
;
406 if ( wxWindow::HandleActivate(state
, minimized
, activate
) )
412 // If this window is an MDI parent, we must also send an OnActivate message
413 // to the current child.
414 if ( (m_currentChild
!= NULL
) &&
415 ((state
== WA_ACTIVE
) || (state
== WA_CLICKACTIVE
)) )
417 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, m_currentChild
->GetId());
418 event
.SetEventObject( m_currentChild
);
419 if ( m_currentChild
->GetEventHandler()->ProcessEvent(event
) )
426 bool wxMDIParentFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
)
428 // In case it's e.g. a toolbar.
431 wxWindow
*win
= wxFindWinFromHandle(hwnd
);
433 return win
->MSWCommand(cmd
, id
);
436 // is it one of standard MDI commands?
441 case IDM_WINDOWCASCADE
:
443 wParam
= MDITILE_SKIPDISABLED
;
446 case IDM_WINDOWTILEHOR
:
447 wParam
|= MDITILE_HORIZONTAL
;
450 case IDM_WINDOWTILEVERT
:
452 wParam
= MDITILE_VERTICAL
;
454 wParam
|= MDITILE_SKIPDISABLED
;
457 case IDM_WINDOWICONS
:
458 msg
= WM_MDIICONARRANGE
;
471 ::SendMessage(GetWinHwnd(GetClientWindow()), msg
, wParam
, 0);
476 // FIXME VZ: what does this test do??
479 return FALSE
; // Get WndProc to call default proc
482 if ( IsMdiCommandId(id
) )
484 wxWindowList::Node
* node
= GetChildren().GetFirst();
487 wxWindow
* child
= node
->GetData();
488 if ( child
->GetHWND() )
490 long childId
= wxGetWindowId(child
->GetHWND());
491 if (childId
== (long)id
)
493 ::SendMessage( GetWinHwnd(GetClientWindow()),
495 (WPARAM
)child
->GetHWND(), 0);
499 node
= node
->GetNext();
502 else if ( m_parentFrameActive
)
504 return ProcessCommand(id
);
506 else if ( m_currentChild
)
508 return m_currentChild
->HandleCommand(id
, cmd
, hwnd
);
512 // this shouldn't happen because it means that our messages are being
513 // lost (they're not sent to the parent frame nor to the children)
514 wxFAIL_MSG(wxT("MDI parent frame is not active, "
515 "yet there is no active MDI child?"));
521 long wxMDIParentFrame::MSWDefWindowProc(WXUINT message
,
526 if ( GetClientWindow() )
527 clientWnd
= GetClientWindow()->GetHWND();
531 return DefFrameProc(GetHwnd(), (HWND
)clientWnd
, message
, wParam
, lParam
);
534 bool wxMDIParentFrame::MSWTranslateMessage(WXMSG
* msg
)
536 MSG
*pMsg
= (MSG
*)msg
;
538 if ( m_currentChild
&& m_currentChild
->GetHWND() &&
539 m_currentChild
->MSWTranslateMessage(msg
) )
544 if ( m_acceleratorTable
.Translate(this, msg
) )
549 if ( pMsg
->message
== WM_KEYDOWN
|| pMsg
->message
== WM_SYSKEYDOWN
)
551 if ( ::TranslateMDISysAccel(GetWinHwnd(GetClientWindow()), pMsg
))
558 // ===========================================================================
560 // ===========================================================================
562 wxMDIChildFrame::wxMDIChildFrame()
566 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
568 const wxString
& title
,
572 const wxString
& name
)
574 m_defaultIcon
= (WXHICON
)(wxSTD_MDICHILDFRAME_ICON
? wxSTD_MDICHILDFRAME_ICON
575 : wxDEFAULT_MDICHILDFRAME_ICON
);
582 m_windowId
= (int)NewControlId();
586 parent
->AddChild(this);
598 mcs
.szClass
= wxMDIChildFrameClassName
;
600 mcs
.hOwner
= wxGetInstance();
604 mcs
.x
= CW_USEDEFAULT
;
609 mcs
.y
= CW_USEDEFAULT
;
614 mcs
.cx
= CW_USEDEFAULT
;
619 mcs
.cy
= CW_USEDEFAULT
;
621 DWORD msflags
= WS_OVERLAPPED
| WS_CLIPCHILDREN
;
622 if (style
& wxMINIMIZE_BOX
)
623 msflags
|= WS_MINIMIZEBOX
;
624 if (style
& wxMAXIMIZE_BOX
)
625 msflags
|= WS_MAXIMIZEBOX
;
626 if (style
& wxTHICK_FRAME
)
627 msflags
|= WS_THICKFRAME
;
628 if (style
& wxSYSTEM_MENU
)
629 msflags
|= WS_SYSMENU
;
630 if ((style
& wxMINIMIZE
) || (style
& wxICONIZE
))
631 msflags
|= WS_MINIMIZE
;
632 if (style
& wxMAXIMIZE
)
633 msflags
|= WS_MAXIMIZE
;
634 if (style
& wxCAPTION
)
635 msflags
|= WS_CAPTION
;
641 DWORD Return
= SendMessage(GetWinHwnd(parent
->GetClientWindow()),
642 WM_MDICREATE
, 0, (LONG
)(LPSTR
)&mcs
);
644 //handle = (HWND)LOWORD(Return);
645 // Must be the DWORRD for WIN32. And in 16 bits, HIWORD=0 (says Microsoft)
646 m_hWnd
= (WXHWND
)Return
;
649 wxAssociateWinWithHandle((HWND
) GetHWND(), this);
651 // VZ: what's this? an act of piracy?
652 //SetWindowLong(GetHwnd(), 0, (long)this);
654 wxModelessWindows
.Append(this);
658 wxMDIChildFrame::~wxMDIChildFrame()
663 // Set the client size (i.e. leave the calculation of borders etc.
665 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
667 HWND hWnd
= GetHwnd();
670 ::GetClientRect(hWnd
, &rect
);
673 GetWindowRect(hWnd
, &rect2
);
675 // Find the difference between the entire window (title bar and all)
676 // and the client area; add this to the new client size to move the
678 int actual_width
= rect2
.right
- rect2
.left
- rect
.right
+ width
;
679 int actual_height
= rect2
.bottom
- rect2
.top
- rect
.bottom
+ height
;
684 GetStatusBar()->GetSize(&sx
, &sy
);
689 point
.x
= rect2
.left
;
692 // If there's an MDI parent, must subtract the parent's top left corner
693 // since MoveWindow moves relative to the parent
694 wxMDIParentFrame
*mdiParent
= (wxMDIParentFrame
*)GetParent();
695 ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
);
697 MoveWindow(hWnd
, point
.x
, point
.y
, actual_width
, actual_height
, (BOOL
)TRUE
);
699 wxSizeEvent
event(wxSize(width
, height
), m_windowId
);
700 event
.SetEventObject( this );
701 GetEventHandler()->ProcessEvent(event
);
704 void wxMDIChildFrame::DoGetPosition(int *x
, int *y
) const
707 GetWindowRect(GetHwnd(), &rect
);
712 // Since we now have the absolute screen coords,
713 // if there's a parent we must subtract its top left corner
714 wxMDIParentFrame
*mdiParent
= (wxMDIParentFrame
*)GetParent();
715 ::ScreenToClient((HWND
) mdiParent
->GetClientWindow()->GetHWND(), &point
);
721 void wxMDIChildFrame::InternalSetMenuBar()
723 wxMDIParentFrame
*parent
= (wxMDIParentFrame
*)GetParent();
725 HMENU subMenu
= GetSubMenu((HMENU
)parent
->GetWindowMenu(), 0);
727 InsertWindowMenu(parent
->GetClientWindow(), m_hMenu
, subMenu
);
729 parent
->m_parentFrameActive
= FALSE
;
732 // ---------------------------------------------------------------------------
734 // ---------------------------------------------------------------------------
736 void wxMDIChildFrame::Maximize(bool maximize
)
738 wxMDIParentFrame
*parent
= (wxMDIParentFrame
*)GetParent();
739 if ( parent
&& parent
->GetClientWindow() )
741 ::SendMessage(GetWinHwnd(parent
->GetClientWindow()),
742 maximize
? WM_MDIMAXIMIZE
: WM_MDIRESTORE
,
743 (WPARAM
)GetHwnd(), 0);
747 void wxMDIChildFrame::Restore()
749 wxMDIParentFrame
*parent
= (wxMDIParentFrame
*)GetParent();
750 if ( parent
&& parent
->GetClientWindow() )
752 ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIRESTORE
,
753 (WPARAM
) GetHwnd(), 0);
757 void wxMDIChildFrame::Activate()
759 wxMDIParentFrame
*parent
= (wxMDIParentFrame
*)GetParent();
760 if ( parent
&& parent
->GetClientWindow() )
762 ::SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIACTIVATE
,
763 (WPARAM
) GetHwnd(), 0);
767 // ---------------------------------------------------------------------------
768 // MDI window proc and message handlers
769 // ---------------------------------------------------------------------------
771 long wxMDIChildFrame::MSWWindowProc(WXUINT message
,
776 bool processed
= FALSE
;
784 UnpackCommand((WXWPARAM
)wParam
, (WXLPARAM
)lParam
,
787 processed
= HandleCommand(id
, cmd
, (WXHWND
)hwnd
);
791 case WM_GETMINMAXINFO
:
792 // let the default window proc calculate the size of MDI children
793 // frames because it is based on the size of the MDI client window,
794 // not on the values specified in wxWindow m_min/max variables
795 return MSWDefWindowProc(message
, wParam
, lParam
);
800 WXHWND hwndAct
, hwndDeact
;
801 UnpackMDIActivate(wParam
, lParam
, &act
, &hwndAct
, &hwndDeact
);
803 processed
= HandleMDIActivate(act
, hwndAct
, hwndDeact
);
808 // must pass WM_MOVE to DefMDIChildProc() to recalculate MDI client
809 // scrollbars if necessary
814 // must pass WM_SIZE to DefMDIChildProc(), otherwise many weird
816 MSWDefWindowProc(message
, wParam
, lParam
);
820 // DefMDIChildProc handles SC_{NEXT/PREV}WINDOW here, so pass it
821 // the message (the base class version does not)
822 return MSWDefWindowProc(message
, wParam
, lParam
);
824 case WM_WINDOWPOSCHANGING
:
825 processed
= HandleWindowPosChanging((LPWINDOWPOS
)lParam
);
830 rc
= wxFrame::MSWWindowProc(message
, wParam
, lParam
);
835 bool wxMDIChildFrame::HandleSize(int x
, int y
, WXUINT id
)
837 HWND hwnd
= GetHwnd();
839 if ( !hwnd
|| hwnd
== invalidHandle
)
858 // forward WM_SIZE to status bar control
859 #if wxUSE_NATIVE_STATUSBAR
860 if (m_frameStatusBar
&& m_frameStatusBar
->IsKindOf(CLASSINFO(wxStatusBar95
)))
862 wxSizeEvent
event(wxSize(x
, y
), m_frameStatusBar
->GetId());
863 event
.SetEventObject( m_frameStatusBar
);
865 ((wxStatusBar95
*)m_frameStatusBar
)->OnSize(event
);
867 #endif // wxUSE_NATIVE_STATUSBAR
872 return wxWindow::HandleSize(x
, y
, id
);
880 bool wxMDIChildFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND hwnd
)
882 // In case it's e.g. a toolbar.
885 wxWindow
*win
= wxFindWinFromHandle(hwnd
);
887 return win
->MSWCommand(cmd
, id
);
890 if (wxCurrentPopupMenu
)
892 wxMenu
*popupMenu
= wxCurrentPopupMenu
;
893 wxCurrentPopupMenu
= NULL
;
894 if (popupMenu
->MSWCommand(cmd
, id
))
898 if (GetMenuBar() && GetMenuBar()->FindItem(id
))
909 bool wxMDIChildFrame::HandleMDIActivate(long WXUNUSED(activate
),
913 wxMDIParentFrame
*parent
= (wxMDIParentFrame
*)GetParent();
919 if ( m_hWnd
== hwndAct
)
922 parent
->m_currentChild
= this;
924 HMENU child_menu
= (HMENU
)GetWinMenu();
927 parent
->m_parentFrameActive
= FALSE
;
929 menuToSet
= child_menu
;
932 else if ( m_hWnd
== hwndDeact
)
934 wxASSERT_MSG( parent
->m_currentChild
== this,
935 wxT("can't deactivate MDI child which wasn't active!") );
938 parent
->m_currentChild
= NULL
;
940 HMENU parent_menu
= (HMENU
)parent
->GetWinMenu();
943 parent
->m_parentFrameActive
= TRUE
;
945 menuToSet
= parent_menu
;
950 // we have nothing to with it
956 HMENU subMenu
= GetSubMenu((HMENU
) parent
->GetWindowMenu(), 0);
958 MDISetMenu(parent
->GetClientWindow(), menuToSet
, subMenu
);
961 wxActivateEvent
event(wxEVT_ACTIVATE
, activated
, m_windowId
);
962 event
.SetEventObject( this );
964 return GetEventHandler()->ProcessEvent(event
);
967 bool wxMDIChildFrame::HandleWindowPosChanging(void *pos
)
969 WINDOWPOS
*lpPos
= (WINDOWPOS
*)pos
;
970 #if defined(__WIN95__)
971 if (!(lpPos
->flags
& SWP_NOSIZE
))
974 DWORD dwExStyle
= ::GetWindowLong(GetHwnd(), GWL_EXSTYLE
);
975 DWORD dwStyle
= ::GetWindowLong(GetHwnd(), GWL_STYLE
);
976 if (ResetWindowStyle((void *) & rectClient
) && (dwStyle
& WS_MAXIMIZE
))
978 ::AdjustWindowRectEx(&rectClient
, dwStyle
, FALSE
, dwExStyle
);
979 lpPos
->x
= rectClient
.left
;
980 lpPos
->y
= rectClient
.top
;
981 lpPos
->cx
= rectClient
.right
- rectClient
.left
;
982 lpPos
->cy
= rectClient
.bottom
- rectClient
.top
;
984 wxMDIParentFrame
* pFrameWnd
= (wxMDIParentFrame
*)GetParent();
985 if (pFrameWnd
&& pFrameWnd
->GetToolBar())
987 pFrameWnd
->GetToolBar()->Refresh();
995 // ---------------------------------------------------------------------------
996 // MDI specific message translation/preprocessing
997 // ---------------------------------------------------------------------------
999 long wxMDIChildFrame::MSWDefWindowProc(WXUINT message
, WXUINT wParam
, WXLPARAM lParam
)
1001 return DefMDIChildProc(GetHwnd(),
1002 (UINT
)message
, (WPARAM
)wParam
, (LPARAM
)lParam
);
1005 bool wxMDIChildFrame::MSWTranslateMessage(WXMSG
* msg
)
1007 return m_acceleratorTable
.Translate(GetParent(), msg
);
1010 // ---------------------------------------------------------------------------
1012 // ---------------------------------------------------------------------------
1014 void wxMDIChildFrame::MSWDestroyWindow()
1016 MSWDetachWindowMenu();
1017 invalidHandle
= GetHwnd();
1019 wxMDIParentFrame
*parent
= (wxMDIParentFrame
*)GetParent();
1021 // Must make sure this handle is invalidated (set to NULL) since all sorts
1022 // of things could happen after the child client is destroyed, but before
1023 // the wxFrame is destroyed.
1025 HWND oldHandle
= (HWND
)GetHWND();
1026 SendMessage(GetWinHwnd(parent
->GetClientWindow()), WM_MDIDESTROY
,
1027 (WPARAM
)oldHandle
, 0);
1032 ::DestroyMenu((HMENU
) m_hMenu
);
1038 // Change the client window's extended style so we don't get a client edge
1039 // style when a child is maximised (a double border looks silly.)
1040 bool wxMDIChildFrame::ResetWindowStyle(void *vrect
)
1042 #if defined(__WIN95__)
1043 RECT
*rect
= (RECT
*)vrect
;
1044 wxMDIParentFrame
* pFrameWnd
= (wxMDIParentFrame
*)GetParent();
1045 wxMDIChildFrame
* pChild
= pFrameWnd
->GetActiveChild();
1046 if (!pChild
|| (pChild
== this))
1048 DWORD dwStyle
= ::GetWindowLong(GetWinHwnd(pFrameWnd
->GetClientWindow()), GWL_EXSTYLE
);
1049 DWORD dwThisStyle
= ::GetWindowLong(GetHwnd(), GWL_STYLE
);
1050 DWORD dwNewStyle
= dwStyle
;
1051 if (pChild
!= NULL
&& (dwThisStyle
& WS_MAXIMIZE
))
1052 dwNewStyle
&= ~(WS_EX_CLIENTEDGE
);
1054 dwNewStyle
|= WS_EX_CLIENTEDGE
;
1056 if (dwStyle
!= dwNewStyle
)
1058 HWND hwnd
= GetWinHwnd(pFrameWnd
->GetClientWindow());
1059 ::RedrawWindow(hwnd
, NULL
, NULL
, RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1060 ::SetWindowLong(hwnd
, GWL_EXSTYLE
, dwNewStyle
);
1061 ::SetWindowPos(hwnd
, NULL
, 0, 0, 0, 0,
1062 SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1063 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
|
1066 ::GetClientRect(hwnd
, rect
);
1076 // ===========================================================================
1077 // wxMDIClientWindow: the window of predefined (by Windows) class which
1078 // contains the child frames
1079 // ===========================================================================
1081 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
1083 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
);
1085 CLIENTCREATESTRUCT ccs
;
1086 m_windowStyle
= style
;
1089 ccs
.hWindowMenu
= (HMENU
)parent
->GetWindowMenu();
1090 ccs
.idFirstChild
= wxFIRST_MDI_CHILD
;
1092 DWORD msStyle
= WS_VISIBLE
| WS_CHILD
| WS_CLIPCHILDREN
;
1093 if ( style
& wxHSCROLL
)
1094 msStyle
|= WS_HSCROLL
;
1095 if ( style
& wxVSCROLL
)
1096 msStyle
|= WS_VSCROLL
;
1098 #if defined(__WIN95__)
1099 DWORD exStyle
= WS_EX_CLIENTEDGE
;
1105 m_hWnd
= (WXHWND
)::CreateWindowEx
1115 (LPSTR
)(LPCLIENTCREATESTRUCT
)&ccs
);
1118 wxLogLastError("CreateWindowEx(MDI client)");
1123 SubclassWin(m_hWnd
);
1129 // Explicitly call default scroll behaviour
1130 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
)
1132 // Note: for client windows, the scroll position is not set in
1133 // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what
1134 // scroll position we're at.
1135 // This makes it hard to paint patterns or bitmaps in the background,
1136 // and have the client area scrollable as well.
1138 if ( event
.GetOrientation() == wxHORIZONTAL
)
1139 m_scrollX
= event
.GetPosition(); // Always returns zero!
1141 m_scrollY
= event
.GetPosition(); // Always returns zero!
1146 // ---------------------------------------------------------------------------
1147 // non member functions
1148 // ---------------------------------------------------------------------------
1150 static void MDISetMenu(wxWindow
*win
, HMENU hmenuFrame
, HMENU hmenuWindow
)
1152 ::SendMessage(GetWinHwnd(win
), WM_MDISETMENU
,
1154 (WPARAM
)hmenuFrame
, (LPARAM
)hmenuWindow
);
1156 0, MAKELPARAM(hmenuFrame
, hmenuWindow
));
1159 // update menu bar of the parent window
1160 wxWindow
*parent
= win
->GetParent();
1161 wxCHECK_RET( parent
, wxT("MDI client without parent frame? weird...") );
1163 ::DrawMenuBar(GetWinHwnd(parent
));
1166 static void InsertWindowMenu(wxWindow
*win
, WXHMENU menu
, HMENU subMenu
)
1168 // Try to insert Window menu in front of Help, otherwise append it.
1169 HMENU hmenu
= (HMENU
)menu
;
1170 int N
= GetMenuItemCount(hmenu
);
1171 bool success
= FALSE
;
1172 for ( int i
= 0; i
< N
; i
++ )
1175 int chars
= GetMenuString(hmenu
, i
, buf
, WXSIZEOF(buf
), MF_BYPOSITION
);
1178 wxLogLastError(wxT("GetMenuString"));
1183 if ( wxStripMenuCodes(wxString(buf
)).IsSameAs(wxT("Help")) )
1186 ::InsertMenu(hmenu
, i
, MF_BYPOSITION
| MF_POPUP
| MF_STRING
,
1187 (UINT
)subMenu
, wxT("&Window"));
1194 ::AppendMenu(hmenu
, MF_POPUP
, (UINT
)subMenu
, wxT("&Window"));
1197 MDISetMenu(win
, hmenu
, subMenu
);
1200 static void UnpackMDIActivate(WXWPARAM wParam
, WXLPARAM lParam
,
1201 WXWORD
*activate
, WXHWND
*hwndAct
, WXHWND
*hwndDeact
)
1205 *hwndAct
= (WXHWND
)lParam
;
1206 *hwndDeact
= (WXHWND
)wParam
;
1208 *activate
= (WXWORD
)wParam
;
1209 *hwndAct
= (WXHWND
)LOWORD(lParam
);
1210 *hwndDeact
= (WXHWND
)HIWORD(lParam
);
1211 #endif // Win32/Win16