]> git.saurik.com Git - wxWidgets.git/blame - src/msw/mdi.cpp
Include commctrl.h properly.
[wxWidgets.git] / src / msw / mdi.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
a967ef9d
VZ
2// Name: src/msw/mdi.cpp
3// Purpose: MDI classes for wxMSW
2bda0e17
KB
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
a23fd0e1
VZ
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
a23fd0e1 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
efd17a1d 27#if wxUSE_MDI && !defined(__WXUNIVERSAL__)
b442f107 28
2bda0e17 29#ifndef WX_PRECOMP
a23fd0e1
VZ
30 #include "wx/frame.h"
31 #include "wx/menu.h"
32 #include "wx/app.h"
33 #include "wx/utils.h"
34 #include "wx/dialog.h"
7c0ea335
VZ
35 #if wxUSE_STATUSBAR
36 #include "wx/statusbr.h"
37 #endif
a23fd0e1 38 #include "wx/settings.h"
0c589ad0
BM
39 #include "wx/intl.h"
40 #include "wx/log.h"
2bda0e17
KB
41#endif
42
e27d9a91 43#include "wx/stockitem.h"
2bda0e17
KB
44#include "wx/mdi.h"
45#include "wx/msw/private.h"
46
7c0ea335 47#if wxUSE_STATUSBAR && wxUSE_NATIVE_STATUSBAR
3096bd2f 48 #include "wx/msw/statbr95.h"
2bda0e17
KB
49#endif
50
7c0ea335
VZ
51#if wxUSE_TOOLBAR
52 #include "wx/toolbar.h"
53#endif // wxUSE_TOOLBAR
54
2bda0e17
KB
55#include <string.h>
56
a23fd0e1
VZ
57// ---------------------------------------------------------------------------
58// global variables
59// ---------------------------------------------------------------------------
60
e1a6fc11 61extern wxMenu *wxCurrentPopupMenu;
2bda0e17 62
3ca6a5f0 63extern const wxChar *wxMDIFrameClassName; // from app.cpp
2ffa221c 64extern const wxChar *wxMDIChildFrameClassName;
3ca6a5f0 65extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
ac6482e0 66extern void wxRemoveHandleAssociation(wxWindow *win);
a23fd0e1
VZ
67
68// ---------------------------------------------------------------------------
69// constants
70// ---------------------------------------------------------------------------
71
42e69d6b 72static const int IDM_WINDOWTILEHOR = 4001;
a23fd0e1
VZ
73static const int IDM_WINDOWCASCADE = 4002;
74static const int IDM_WINDOWICONS = 4003;
75static const int IDM_WINDOWNEXT = 4004;
42e69d6b 76static const int IDM_WINDOWTILEVERT = 4005;
4f3b37fd 77static const int IDM_WINDOWPREV = 4006;
a23fd0e1
VZ
78
79// This range gives a maximum of 500 MDI children. Should be enough :-)
80static const int wxFIRST_MDI_CHILD = 4100;
81static const int wxLAST_MDI_CHILD = 4600;
2bda0e17 82
42e69d6b
VZ
83// ---------------------------------------------------------------------------
84// private functions
85// ---------------------------------------------------------------------------
86
87// set the MDI menus (by sending the WM_MDISETMENU message) and update the menu
88// of the parent of win (which is supposed to be the MDI client window)
89static void MDISetMenu(wxWindow *win, HMENU hmenuFrame, HMENU hmenuWindow);
90
91// insert the window menu (subMenu) into menu just before "Help" submenu or at
92// the very end if not found
93static void InsertWindowMenu(wxWindow *win, WXHMENU menu, HMENU subMenu);
94
df61c009
JS
95// Remove the window menu
96static void RemoveWindowMenu(wxWindow *win, WXHMENU menu);
97
42e69d6b
VZ
98// is this an id of an MDI child?
99inline bool IsMdiCommandId(int id)
100{
101 return (id >= wxFIRST_MDI_CHILD) && (id <= wxLAST_MDI_CHILD);
102}
103
4e152a23 104// unpack the parameters of WM_MDIACTIVATE message
2917e920
BM
105static void UnpackMDIActivate(WXWPARAM wParam, WXLPARAM lParam,
106 WXWORD *activate, WXHWND *hwndAct, WXHWND *hwndDeact);
42e69d6b 107
4e152a23
VZ
108// return the HMENU of the MDI menu
109static inline HMENU GetMDIWindowMenu(wxMDIParentFrame *frame)
110{
111 wxMenu *menu = frame->GetWindowMenu();
112 return menu ? GetHmenuOf(menu) : 0;
113}
114
a23fd0e1
VZ
115// ===========================================================================
116// implementation
117// ===========================================================================
118
119// ---------------------------------------------------------------------------
120// wxWin macros
121// ---------------------------------------------------------------------------
2bda0e17 122
225fe9d6
VZ
123IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
124IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
125IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
2bda0e17
KB
126
127BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
a23fd0e1 128 EVT_SIZE(wxMDIParentFrame::OnSize)
6bbe97b7 129 EVT_ICONIZE(wxMDIParentFrame::OnIconized)
a23fd0e1 130 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
2bda0e17
KB
131END_EVENT_TABLE()
132
f6bcfd97
BP
133BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
134 EVT_IDLE(wxMDIChildFrame::OnIdle)
135END_EVENT_TABLE()
136
2bda0e17 137BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow)
a23fd0e1 138 EVT_SCROLL(wxMDIClientWindow::OnScroll)
2bda0e17
KB
139END_EVENT_TABLE()
140
42e69d6b
VZ
141// ===========================================================================
142// wxMDIParentFrame: the frame which contains the client window which manages
143// the children
144// ===========================================================================
2bda0e17 145
c2dcfdef 146wxMDIParentFrame::wxMDIParentFrame()
2bda0e17
KB
147{
148 m_clientWindow = NULL;
149 m_currentChild = NULL;
df61c009 150 m_windowMenu = (wxMenu*) NULL;
4f8090e0 151 m_parentFrameActive = true;
2bda0e17
KB
152}
153
154bool wxMDIParentFrame::Create(wxWindow *parent,
a23fd0e1
VZ
155 wxWindowID id,
156 const wxString& title,
157 const wxPoint& pos,
158 const wxSize& size,
159 long style,
160 const wxString& name)
2bda0e17 161{
2bda0e17
KB
162 m_clientWindow = NULL;
163 m_currentChild = NULL;
df61c009 164
3d8dea7e
VZ
165 // this style can be used to prevent a window from having the standard MDI
166 // "Window" menu
167 if ( style & wxFRAME_NO_WINDOW_MENU )
168 {
169 m_windowMenu = (wxMenu *)NULL;
170 }
171 else // normal case: we have the window menu, so construct it
df61c009 172 {
df61c009
JS
173 m_windowMenu = new wxMenu;
174
b0a2157c
VZ
175 m_windowMenu->Append(IDM_WINDOWCASCADE, _("&Cascade"));
176 m_windowMenu->Append(IDM_WINDOWTILEHOR, _("Tile &Horizontally"));
177 m_windowMenu->Append(IDM_WINDOWTILEVERT, _("Tile &Vertically"));
df61c009 178 m_windowMenu->AppendSeparator();
b0a2157c
VZ
179 m_windowMenu->Append(IDM_WINDOWICONS, _("&Arrange Icons"));
180 m_windowMenu->Append(IDM_WINDOWNEXT, _("&Next"));
4f3b37fd 181 m_windowMenu->Append(IDM_WINDOWPREV, _("&Previous"));
df61c009
JS
182 }
183
4f8090e0 184 m_parentFrameActive = true;
2bda0e17
KB
185
186 if (!parent)
187 wxTopLevelWindows.Append(this);
188
189 SetName(name);
190 m_windowStyle = style;
191
b225f659
VZ
192 if ( parent )
193 parent->AddChild(this);
2bda0e17 194
598ddd96 195 if ( id != wxID_ANY )
2bda0e17
KB
196 m_windowId = id;
197 else
b225f659 198 m_windowId = NewControlId();
2bda0e17 199
912c192f
VZ
200 WXDWORD exflags;
201 WXDWORD msflags = MSWGetCreateWindowFlags(&exflags);
ea723360
JS
202 msflags &= ~WS_VSCROLL;
203 msflags &= ~WS_HSCROLL;
2bda0e17 204
b225f659 205 if ( !wxWindow::MSWCreate(wxMDIFrameClassName,
3ca6a5f0 206 title,
b225f659
VZ
207 pos, size,
208 msflags,
209 exflags) )
3ca6a5f0 210 {
4f8090e0 211 return false;
3ca6a5f0 212 }
2bda0e17 213
5bee6b2b
VZ
214 SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
215
f6bcfd97 216 // unlike (almost?) all other windows, frames are created hidden
4f8090e0 217 m_isShown = false;
f6bcfd97 218
4f8090e0 219 return true;
2bda0e17
KB
220}
221
c2dcfdef 222wxMDIParentFrame::~wxMDIParentFrame()
2bda0e17 223{
d1e44484 224 // see comment in ~wxMDIChildFrame
1904aa72 225#if wxUSE_TOOLBAR
f048e32f 226 m_frameToolBar = NULL;
1904aa72 227#endif
67a99992 228#if wxUSE_STATUSBAR
c0bcc480 229 m_frameStatusBar = NULL;
67a99992 230#endif // wxUSE_STATUSBAR
f048e32f 231
d1e44484
VZ
232 DestroyChildren();
233
df61c009
JS
234 if (m_windowMenu)
235 {
236 delete m_windowMenu;
237 m_windowMenu = (wxMenu*) NULL;
238 }
2bda0e17 239
4e152a23
VZ
240 // the MDI frame menubar is not automatically deleted by Windows unlike for
241 // the normal frames
242 if ( m_hMenu )
243 {
244 ::DestroyMenu((HMENU)m_hMenu);
7c46a16b 245 m_hMenu = (WXHMENU)NULL;
4e152a23
VZ
246 }
247
42e69d6b
VZ
248 if ( m_clientWindow )
249 {
250 if ( m_clientWindow->MSWGetOldWndProc() )
251 m_clientWindow->UnsubclassWin();
2bda0e17 252
42e69d6b
VZ
253 m_clientWindow->SetHWND(0);
254 delete m_clientWindow;
255 }
2bda0e17
KB
256}
257
1e6feb95
VZ
258#if wxUSE_MENUS_NATIVE
259
42e69d6b 260void wxMDIParentFrame::InternalSetMenuBar()
2bda0e17 261{
4f8090e0 262 m_parentFrameActive = true;
2bda0e17 263
4e152a23 264 InsertWindowMenu(GetClientWindow(), m_hMenu, GetMDIWindowMenu(this));
2bda0e17
KB
265}
266
1e6feb95
VZ
267#endif // wxUSE_MENUS_NATIVE
268
df61c009
JS
269void wxMDIParentFrame::SetWindowMenu(wxMenu* menu)
270{
271 if (m_windowMenu)
272 {
273 if (GetMenuBar())
274 {
275 // Remove old window menu
276 RemoveWindowMenu(GetClientWindow(), m_hMenu);
277 }
278
279 delete m_windowMenu;
280 m_windowMenu = (wxMenu*) NULL;
281 }
4e152a23 282
df61c009
JS
283 if (menu)
284 {
285 m_windowMenu = menu;
286 if (GetMenuBar())
b0a2157c
VZ
287 {
288 InsertWindowMenu(GetClientWindow(), m_hMenu,
88c49a0f 289 GetHmenuOf(m_windowMenu));
b0a2157c 290 }
df61c009
JS
291 }
292}
293
6aca4628
CE
294void wxMDIParentFrame::DoMenuUpdates(wxMenu* menu)
295{
296 wxMDIChildFrame *child = GetActiveChild();
297 if ( child )
298 {
299 wxEvtHandler* source = child->GetEventHandler();
300 wxMenuBar* bar = child->GetMenuBar();
301
302 if (menu)
303 {
304 menu->UpdateUI(source);
305 }
306 else
307 {
308 if ( bar != NULL )
309 {
310 int nCount = bar->GetMenuCount();
311 for (int n = 0; n < nCount; n++)
92218ce6 312 bar->GetMenu(n)->UpdateUI(source);
6aca4628
CE
313 }
314 }
315 }
316 else
317 {
318 wxFrameBase::DoMenuUpdates(menu);
319 }
320}
321
6bbe97b7 322void wxMDIParentFrame::UpdateClientSize()
2bda0e17 323{
2bda0e17 324 if ( GetClientWindow() )
42e69d6b
VZ
325 {
326 int width, height;
327 GetClientSize(&width, &height);
2bda0e17 328
42e69d6b
VZ
329 GetClientWindow()->SetSize(0, 0, width, height);
330 }
2bda0e17
KB
331}
332
6bbe97b7
VZ
333void wxMDIParentFrame::OnSize(wxSizeEvent& WXUNUSED(event))
334{
335 UpdateClientSize();
336
337 // do not call event.Skip() here, it somehow messes up MDI client window
338}
339
340void wxMDIParentFrame::OnIconized(wxIconizeEvent& event)
341{
342 event.Skip();
343
344 if ( !event.Iconized() )
345 {
346 UpdateClientSize();
347 }
348}
349
2bda0e17 350// Returns the active MDI child window
c2dcfdef 351wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
2bda0e17 352{
a23fd0e1
VZ
353 HWND hWnd = (HWND)::SendMessage(GetWinHwnd(GetClientWindow()),
354 WM_MDIGETACTIVE, 0, 0L);
355 if ( hWnd == 0 )
356 return NULL;
357 else
358 return (wxMDIChildFrame *)wxFindWinFromHandle((WXHWND) hWnd);
2bda0e17
KB
359}
360
a23fd0e1
VZ
361// Create the client window class (don't Create the window, just return a new
362// class)
c2dcfdef 363wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
2bda0e17 364{
a23fd0e1 365 return new wxMDIClientWindow;
2bda0e17
KB
366}
367
368// Responds to colour changes, and passes event on to children.
369void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
370{
371 if ( m_clientWindow )
372 {
a756f210 373 m_clientWindow->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
2bda0e17
KB
374 m_clientWindow->Refresh();
375 }
2bda0e17 376
42e69d6b 377 event.Skip();
2bda0e17
KB
378}
379
82c9f85c
VZ
380WXHICON wxMDIParentFrame::GetDefaultIcon() const
381{
94826170
VZ
382 // we don't have any standard icons (any more)
383 return (WXHICON)0;
82c9f85c
VZ
384}
385
42e69d6b 386// ---------------------------------------------------------------------------
2bda0e17 387// MDI operations
42e69d6b
VZ
388// ---------------------------------------------------------------------------
389
c2dcfdef 390void wxMDIParentFrame::Cascade()
2bda0e17 391{
a23fd0e1 392 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDICASCADE, 0, 0);
2bda0e17
KB
393}
394
0d97c090 395void wxMDIParentFrame::Tile(wxOrientation orient)
2bda0e17 396{
0d97c090
VZ
397 wxASSERT_MSG( orient == wxHORIZONTAL || orient == wxVERTICAL,
398 _T("invalid orientation value") );
399
400 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDITILE,
401 orient == wxHORIZONTAL ? MDITILE_HORIZONTAL
402 : MDITILE_VERTICAL, 0);
2bda0e17
KB
403}
404
c2dcfdef 405void wxMDIParentFrame::ArrangeIcons()
2bda0e17 406{
a23fd0e1 407 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDIICONARRANGE, 0, 0);
2bda0e17
KB
408}
409
c2dcfdef 410void wxMDIParentFrame::ActivateNext()
2bda0e17 411{
a23fd0e1 412 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT, 0, 0);
2bda0e17
KB
413}
414
c2dcfdef 415void wxMDIParentFrame::ActivatePrevious()
2bda0e17 416{
a23fd0e1 417 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT, 0, 1);
2bda0e17
KB
418}
419
42e69d6b 420// ---------------------------------------------------------------------------
a23fd0e1 421// the MDI parent frame window proc
42e69d6b
VZ
422// ---------------------------------------------------------------------------
423
c140b7e7 424WXLRESULT wxMDIParentFrame::MSWWindowProc(WXUINT message,
a23fd0e1
VZ
425 WXWPARAM wParam,
426 WXLPARAM lParam)
2bda0e17 427{
c140b7e7 428 WXLRESULT rc = 0;
4f8090e0 429 bool processed = false;
2bda0e17 430
a23fd0e1
VZ
431 switch ( message )
432 {
42e69d6b
VZ
433 case WM_ACTIVATE:
434 {
435 WXWORD state, minimized;
436 WXHWND hwnd;
437 UnpackActivate(wParam, lParam, &state, &minimized, &hwnd);
438
439 processed = HandleActivate(state, minimized != 0, hwnd);
440 }
441 break;
442
443 case WM_COMMAND:
444 {
445 WXWORD id, cmd;
446 WXHWND hwnd;
447 UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
448
449 (void)HandleCommand(id, cmd, hwnd);
450
451 // even if the frame didn't process it, there is no need to try it
01ebf752 452 // once again (i.e. call wxFrame::HandleCommand()) - we just did it,
42e69d6b 453 // so pretend we processed the message anyhow
4f8090e0 454 processed = true;
42e69d6b 455 }
b3818fbe
VZ
456
457 // always pass this message DefFrameProc(), otherwise MDI menu
01ebf752 458 // commands (and sys commands - more surprisingly!) won't work
b3818fbe 459 MSWDefWindowProc(message, wParam, lParam);
42e69d6b
VZ
460 break;
461
a23fd0e1
VZ
462 case WM_CREATE:
463 m_clientWindow = OnCreateClient();
464 // Uses own style for client style
465 if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
466 {
467 wxLogMessage(_("Failed to create MDI parent frame."));
2bda0e17 468
a23fd0e1
VZ
469 rc = -1;
470 }
2bda0e17 471
4f8090e0 472 processed = true;
a23fd0e1 473 break;
2bda0e17 474
a23fd0e1 475 case WM_ERASEBKGND:
4f8090e0 476 processed = true;
2bda0e17 477
a23fd0e1 478 // we erase background ourselves
4f8090e0 479 rc = true;
a23fd0e1
VZ
480 break;
481
482 case WM_MENUSELECT:
483 {
42e69d6b
VZ
484 WXWORD item, flags;
485 WXHMENU hmenu;
486 UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu);
487
a23fd0e1
VZ
488 if ( m_parentFrameActive )
489 {
42e69d6b 490 processed = HandleMenuSelect(item, flags, hmenu);
a23fd0e1
VZ
491 }
492 else if (m_currentChild)
493 {
494 processed = m_currentChild->
42e69d6b 495 HandleMenuSelect(item, flags, hmenu);
a23fd0e1
VZ
496 }
497 }
498 break;
b3818fbe
VZ
499
500 case WM_SIZE:
31f658e4
CE
501 // though we don't (usually) resize the MDI client to exactly fit the
502 // client area we need to pass this one to DefFrameProc to allow the children to show
b3818fbe 503 break;
a23fd0e1 504 }
2bda0e17 505
a23fd0e1
VZ
506 if ( !processed )
507 rc = wxFrame::MSWWindowProc(message, wParam, lParam);
2bda0e17 508
a23fd0e1 509 return rc;
2bda0e17
KB
510}
511
42e69d6b 512bool wxMDIParentFrame::HandleActivate(int state, bool minimized, WXHWND activate)
2bda0e17 513{
4f8090e0 514 bool processed = false;
a23fd0e1 515
42e69d6b 516 if ( wxWindow::HandleActivate(state, minimized, activate) )
a23fd0e1
VZ
517 {
518 // already processed
4f8090e0 519 processed = true;
a23fd0e1 520 }
2bda0e17
KB
521
522 // If this window is an MDI parent, we must also send an OnActivate message
523 // to the current child.
42e69d6b 524 if ( (m_currentChild != NULL) &&
a23fd0e1 525 ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE)) )
c2dcfdef 526 {
4f8090e0 527 wxActivateEvent event(wxEVT_ACTIVATE, true, m_currentChild->GetId());
debe6624 528 event.SetEventObject( m_currentChild );
a23fd0e1 529 if ( m_currentChild->GetEventHandler()->ProcessEvent(event) )
4f8090e0 530 processed = true;
2bda0e17 531 }
a23fd0e1
VZ
532
533 return processed;
2bda0e17
KB
534}
535
42e69d6b 536bool wxMDIParentFrame::HandleCommand(WXWORD id, WXWORD cmd, WXHWND hwnd)
2bda0e17 537{
2bda0e17 538 // In case it's e.g. a toolbar.
42e69d6b 539 if ( hwnd )
e1a6fc11 540 {
42e69d6b
VZ
541 wxWindow *win = wxFindWinFromHandle(hwnd);
542 if ( win )
543 return win->MSWCommand(cmd, id);
e1a6fc11
JS
544 }
545
7dbe942a
JS
546 if (wxCurrentPopupMenu)
547 {
548 wxMenu *popupMenu = wxCurrentPopupMenu;
549 wxCurrentPopupMenu = NULL;
550 if (popupMenu->MSWCommand(cmd, id))
551 return true;
552 }
553
42e69d6b
VZ
554 // is it one of standard MDI commands?
555 WXWPARAM wParam = 0;
4f3b37fd 556 WXLPARAM lParam = 0;
42e69d6b
VZ
557 int msg;
558 switch ( id )
2bda0e17 559 {
42e69d6b
VZ
560 case IDM_WINDOWCASCADE:
561 msg = WM_MDICASCADE;
562 wParam = MDITILE_SKIPDISABLED;
563 break;
564
565 case IDM_WINDOWTILEHOR:
566 wParam |= MDITILE_HORIZONTAL;
567 // fall through
568
569 case IDM_WINDOWTILEVERT:
570 if ( !wParam )
571 wParam = MDITILE_VERTICAL;
572 msg = WM_MDITILE;
573 wParam |= MDITILE_SKIPDISABLED;
574 break;
575
576 case IDM_WINDOWICONS:
577 msg = WM_MDIICONARRANGE;
578 break;
579
580 case IDM_WINDOWNEXT:
581 msg = WM_MDINEXT;
4f3b37fd
JS
582 lParam = 0; // next child
583 break;
584
585 case IDM_WINDOWPREV:
586 msg = WM_MDINEXT;
587 lParam = 1; // previous child
42e69d6b
VZ
588 break;
589
590 default:
591 msg = 0;
2bda0e17 592 }
c2dcfdef 593
42e69d6b 594 if ( msg )
2bda0e17 595 {
4f3b37fd 596 ::SendMessage(GetWinHwnd(GetClientWindow()), msg, wParam, lParam);
42e69d6b 597
4f8090e0 598 return true;
2bda0e17 599 }
42e69d6b
VZ
600
601 // FIXME VZ: what does this test do??
602 if (id >= 0xF000)
2bda0e17 603 {
4f8090e0 604 return false; // Get WndProc to call default proc
2bda0e17 605 }
42e69d6b
VZ
606
607 if ( IsMdiCommandId(id) )
2bda0e17 608 {
222ed1d6 609 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
42e69d6b 610 while ( node )
2bda0e17 611 {
d162a7ee 612 wxWindow *child = node->GetData();
42e69d6b 613 if ( child->GetHWND() )
2bda0e17 614 {
42e69d6b 615 long childId = wxGetWindowId(child->GetHWND());
48c12cb1 616 if (childId == (long)id)
42e69d6b
VZ
617 {
618 ::SendMessage( GetWinHwnd(GetClientWindow()),
619 WM_MDIACTIVATE,
620 (WPARAM)child->GetHWND(), 0);
4f8090e0 621 return true;
42e69d6b 622 }
2bda0e17 623 }
42e69d6b 624 node = node->GetNext();
2bda0e17 625 }
2bda0e17 626 }
42e69d6b 627 else if ( m_parentFrameActive )
2bda0e17 628 {
42e69d6b
VZ
629 return ProcessCommand(id);
630 }
631 else if ( m_currentChild )
632 {
633 return m_currentChild->HandleCommand(id, cmd, hwnd);
634 }
635 else
636 {
637 // this shouldn't happen because it means that our messages are being
638 // lost (they're not sent to the parent frame nor to the children)
f6bcfd97 639 wxFAIL_MSG(wxT("MDI parent frame is not active, yet there is no active MDI child?"));
2bda0e17 640 }
2bda0e17 641
4f8090e0 642 return false;
2bda0e17
KB
643}
644
c140b7e7 645WXLRESULT wxMDIParentFrame::MSWDefWindowProc(WXUINT message,
42e69d6b
VZ
646 WXWPARAM wParam,
647 WXLPARAM lParam)
2bda0e17 648{
c2dcfdef
VZ
649 WXHWND clientWnd;
650 if ( GetClientWindow() )
651 clientWnd = GetClientWindow()->GetHWND();
652 else
653 clientWnd = 0;
2bda0e17 654
a23fd0e1 655 return DefFrameProc(GetHwnd(), (HWND)clientWnd, message, wParam, lParam);
2bda0e17
KB
656}
657
57a7b7c1
JS
658bool wxMDIParentFrame::MSWTranslateMessage(WXMSG* msg)
659{
a23fd0e1 660 MSG *pMsg = (MSG *)msg;
2bda0e17 661
f6bcfd97 662 // first let the current child get it
a23fd0e1
VZ
663 if ( m_currentChild && m_currentChild->GetHWND() &&
664 m_currentChild->MSWTranslateMessage(msg) )
665 {
4f8090e0 666 return true;
a23fd0e1 667 }
2bda0e17 668
f6bcfd97
BP
669 // then try out accel table (will also check the menu accels)
670 if ( wxFrame::MSWTranslateMessage(msg) )
a23fd0e1 671 {
4f8090e0 672 return true;
a23fd0e1 673 }
2bda0e17 674
f6bcfd97 675 // finally, check for MDI specific built in accel keys
a23fd0e1
VZ
676 if ( pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN )
677 {
678 if ( ::TranslateMDISysAccel(GetWinHwnd(GetClientWindow()), pMsg))
4f8090e0 679 return true;
a23fd0e1 680 }
57a7b7c1 681
4f8090e0 682 return false;
2bda0e17
KB
683}
684
42e69d6b 685// ===========================================================================
a23fd0e1 686// wxMDIChildFrame
42e69d6b 687// ===========================================================================
2bda0e17 688
f6bcfd97 689void wxMDIChildFrame::Init()
2bda0e17 690{
4f8090e0 691 m_needsResize = true;
2596e9fb 692 m_needsInitialShow = true;
2bda0e17
KB
693}
694
695bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
a23fd0e1
VZ
696 wxWindowID id,
697 const wxString& title,
698 const wxPoint& pos,
699 const wxSize& size,
700 long style,
701 const wxString& name)
2bda0e17 702{
2bda0e17
KB
703 SetName(name);
704
598ddd96 705 if ( id != wxID_ANY )
2bda0e17
KB
706 m_windowId = id;
707 else
708 m_windowId = (int)NewControlId();
709
42e69d6b
VZ
710 if ( parent )
711 {
712 parent->AddChild(this);
713 }
2bda0e17 714
2bda0e17
KB
715 int x = pos.x;
716 int y = pos.y;
717 int width = size.x;
718 int height = size.y;
719
720 MDICREATESTRUCT mcs;
c2dcfdef 721
e441e1f4
VZ
722 mcs.szClass = style & wxFULL_REPAINT_ON_RESIZE
723 ? wxMDIChildFrameClassName
724 : wxMDIChildFrameClassNameNoRedraw;
2bda0e17
KB
725 mcs.szTitle = title;
726 mcs.hOwner = wxGetInstance();
598ddd96 727 if (x != wxDefaultCoord)
42e69d6b
VZ
728 mcs.x = x;
729 else
730 mcs.x = CW_USEDEFAULT;
2bda0e17 731
598ddd96 732 if (y != wxDefaultCoord)
42e69d6b
VZ
733 mcs.y = y;
734 else
735 mcs.y = CW_USEDEFAULT;
2bda0e17 736
598ddd96 737 if (width != wxDefaultCoord)
42e69d6b
VZ
738 mcs.cx = width;
739 else
740 mcs.cx = CW_USEDEFAULT;
2bda0e17 741
598ddd96 742 if (height != wxDefaultCoord)
42e69d6b
VZ
743 mcs.cy = height;
744 else
745 mcs.cy = CW_USEDEFAULT;
2bda0e17 746
2596e9fb 747 DWORD msflags = WS_OVERLAPPED | WS_CLIPCHILDREN;
2bda0e17
KB
748 if (style & wxMINIMIZE_BOX)
749 msflags |= WS_MINIMIZEBOX;
750 if (style & wxMAXIMIZE_BOX)
751 msflags |= WS_MAXIMIZEBOX;
1c067fe3 752 if (style & wxRESIZE_BORDER)
2bda0e17
KB
753 msflags |= WS_THICKFRAME;
754 if (style & wxSYSTEM_MENU)
755 msflags |= WS_SYSMENU;
756 if ((style & wxMINIMIZE) || (style & wxICONIZE))
757 msflags |= WS_MINIMIZE;
758 if (style & wxMAXIMIZE)
759 msflags |= WS_MAXIMIZE;
760 if (style & wxCAPTION)
761 msflags |= WS_CAPTION;
762
763 mcs.style = msflags;
764
765 mcs.lParam = 0;
766
b225f659
VZ
767 wxWindowCreationHook hook(this);
768
3ca6a5f0
BP
769 m_hWnd = (WXHWND)::SendMessage(GetWinHwnd(parent->GetClientWindow()),
770 WM_MDICREATE, 0, (LONG)(LPSTR)&mcs);
2bda0e17 771
05ae668c
VZ
772 if ( !m_hWnd )
773 {
774 wxLogLastError(_T("WM_MDICREATE"));
775 return false;
776 }
777
778 SubclassWin(m_hWnd);
2bda0e17 779
4f8090e0 780 return true;
2bda0e17
KB
781}
782
c2dcfdef 783wxMDIChildFrame::~wxMDIChildFrame()
2bda0e17 784{
d1e44484
VZ
785 // will be destroyed by DestroyChildren() but reset them before calling it
786 // to avoid using dangling pointers if a callback comes in the meanwhile
1904aa72 787#if wxUSE_TOOLBAR
627a3091 788 m_frameToolBar = NULL;
1904aa72 789#endif
67a99992 790#if wxUSE_STATUSBAR
627a3091 791 m_frameStatusBar = NULL;
67a99992 792#endif // wxUSE_STATUSBAR
627a3091 793
d1e44484
VZ
794 DestroyChildren();
795
4e152a23
VZ
796 RemoveWindowMenu(NULL, m_hMenu);
797
c2dcfdef 798 MSWDestroyWindow();
2bda0e17
KB
799}
800
2596e9fb
VS
801bool wxMDIChildFrame::Show(bool show)
802{
803 m_needsInitialShow = false;
6fa30495
KH
804
805 if (!wxFrame::Show(show))
806 return false;
807
808 // KH: Without this call, new MDI children do not become active.
809 // This was added here after the same BringWindowToTop call was
810 // removed from wxTopLevelWindow::Show (November 2005)
811 if ( show )
812 ::BringWindowToTop(GetHwnd());
813
e45a6885
VZ
814 // we need to refresh the MDI frame window menu to include (or exclude if
815 // we've been hidden) this frame
816 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
817 MDISetMenu(parent->GetClientWindow(), NULL, NULL);
818
6fa30495 819 return true;
2596e9fb
VS
820}
821
2bda0e17 822// Set the client size (i.e. leave the calculation of borders etc.
77ffb593 823// to wxWidgets)
cc2b7472 824void wxMDIChildFrame::DoSetClientSize(int width, int height)
2bda0e17 825{
b3818fbe 826 HWND hWnd = GetHwnd();
2bda0e17
KB
827
828 RECT rect;
2de8030d 829 ::GetClientRect(hWnd, &rect);
2bda0e17
KB
830
831 RECT rect2;
832 GetWindowRect(hWnd, &rect2);
833
834 // Find the difference between the entire window (title bar and all)
835 // and the client area; add this to the new client size to move the
836 // window
837 int actual_width = rect2.right - rect2.left - rect.right + width;
838 int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
839
67a99992 840#if wxUSE_STATUSBAR
a2327a9f 841 if (GetStatusBar() && GetStatusBar()->IsShown())
2bda0e17 842 {
c2dcfdef
VZ
843 int sx, sy;
844 GetStatusBar()->GetSize(&sx, &sy);
2bda0e17
KB
845 actual_height += sy;
846 }
67a99992 847#endif // wxUSE_STATUSBAR
2bda0e17
KB
848
849 POINT point;
850 point.x = rect2.left;
851 point.y = rect2.top;
852
853 // If there's an MDI parent, must subtract the parent's top left corner
854 // since MoveWindow moves relative to the parent
855 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
856 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
857
4f8090e0 858 MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)true);
debe6624 859
5c519b6c
WS
860 wxSize size(width, height);
861 wxSizeEvent event(size, m_windowId);
debe6624 862 event.SetEventObject( this );
2bda0e17 863 GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
864}
865
cc2b7472 866void wxMDIChildFrame::DoGetPosition(int *x, int *y) const
2bda0e17
KB
867{
868 RECT rect;
b3818fbe 869 GetWindowRect(GetHwnd(), &rect);
2bda0e17
KB
870 POINT point;
871 point.x = rect.left;
872 point.y = rect.top;
873
874 // Since we now have the absolute screen coords,
875 // if there's a parent we must subtract its top left corner
876 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
877 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
878
1696dde5
JS
879 if (x)
880 *x = point.x;
881 if (y)
882 *y = point.y;
2bda0e17
KB
883}
884
42e69d6b 885void wxMDIChildFrame::InternalSetMenuBar()
2bda0e17 886{
42e69d6b 887 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
2bda0e17 888
4e152a23
VZ
889 InsertWindowMenu(parent->GetClientWindow(),
890 m_hMenu, GetMDIWindowMenu(parent));
2bda0e17 891
4f8090e0 892 parent->m_parentFrameActive = false;
2bda0e17
KB
893}
894
e3307ddd
CE
895void wxMDIChildFrame::DetachMenuBar()
896{
6bbe97b7
VZ
897 RemoveWindowMenu(NULL, m_hMenu);
898 wxFrame::DetachMenuBar();
e3307ddd
CE
899}
900
82c9f85c
VZ
901WXHICON wxMDIChildFrame::GetDefaultIcon() const
902{
94826170
VZ
903 // we don't have any standard icons (any more)
904 return (WXHICON)0;
82c9f85c
VZ
905}
906
42e69d6b 907// ---------------------------------------------------------------------------
2bda0e17 908// MDI operations
42e69d6b
VZ
909// ---------------------------------------------------------------------------
910
9b73db3c 911void wxMDIChildFrame::Maximize(bool maximize)
2bda0e17
KB
912{
913 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
914 if ( parent && parent->GetClientWindow() )
9b73db3c
VZ
915 {
916 ::SendMessage(GetWinHwnd(parent->GetClientWindow()),
917 maximize ? WM_MDIMAXIMIZE : WM_MDIRESTORE,
918 (WPARAM)GetHwnd(), 0);
919 }
2bda0e17
KB
920}
921
c2dcfdef 922void wxMDIChildFrame::Restore()
2bda0e17
KB
923{
924 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
925 if ( parent && parent->GetClientWindow() )
9b73db3c
VZ
926 {
927 ::SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIRESTORE,
928 (WPARAM) GetHwnd(), 0);
929 }
2bda0e17
KB
930}
931
c2dcfdef 932void wxMDIChildFrame::Activate()
2bda0e17
KB
933{
934 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
935 if ( parent && parent->GetClientWindow() )
9b73db3c
VZ
936 {
937 ::SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIACTIVATE,
938 (WPARAM) GetHwnd(), 0);
939 }
2bda0e17
KB
940}
941
42e69d6b
VZ
942// ---------------------------------------------------------------------------
943// MDI window proc and message handlers
944// ---------------------------------------------------------------------------
945
c140b7e7 946WXLRESULT wxMDIChildFrame::MSWWindowProc(WXUINT message,
42e69d6b
VZ
947 WXWPARAM wParam,
948 WXLPARAM lParam)
949{
c140b7e7 950 WXLRESULT rc = 0;
4f8090e0 951 bool processed = false;
42e69d6b
VZ
952
953 switch ( message )
954 {
955 case WM_COMMAND:
956 {
957 WORD id, cmd;
958 WXHWND hwnd;
959 UnpackCommand((WXWPARAM)wParam, (WXLPARAM)lParam,
960 &id, &hwnd, &cmd);
961
962 processed = HandleCommand(id, cmd, (WXHWND)hwnd);
963 }
964 break;
965
42e69d6b 966 case WM_GETMINMAXINFO:
3ebcfb76
VZ
967 processed = HandleGetMinMaxInfo((MINMAXINFO *)lParam);
968 break;
42e69d6b
VZ
969
970 case WM_MDIACTIVATE:
971 {
972 WXWORD act;
973 WXHWND hwndAct, hwndDeact;
974 UnpackMDIActivate(wParam, lParam, &act, &hwndAct, &hwndDeact);
975
976 processed = HandleMDIActivate(act, hwndAct, hwndDeact);
977 }
b3818fbe
VZ
978 // fall through
979
980 case WM_MOVE:
981 // must pass WM_MOVE to DefMDIChildProc() to recalculate MDI client
982 // scrollbars if necessary
983
984 // fall through
985
986 case WM_SIZE:
987 // must pass WM_SIZE to DefMDIChildProc(), otherwise many weird
988 // things happen
989 MSWDefWindowProc(message, wParam, lParam);
42e69d6b
VZ
990 break;
991
b3818fbe
VZ
992 case WM_SYSCOMMAND:
993 // DefMDIChildProc handles SC_{NEXT/PREV}WINDOW here, so pass it
994 // the message (the base class version does not)
995 return MSWDefWindowProc(message, wParam, lParam);
996
42e69d6b
VZ
997 case WM_WINDOWPOSCHANGING:
998 processed = HandleWindowPosChanging((LPWINDOWPOS)lParam);
999 break;
1000 }
1001
1002 if ( !processed )
1003 rc = wxFrame::MSWWindowProc(message, wParam, lParam);
1004
1005 return rc;
1006}
1007
42e69d6b 1008bool wxMDIChildFrame::HandleCommand(WXWORD id, WXWORD cmd, WXHWND hwnd)
2bda0e17 1009{
2bda0e17 1010 // In case it's e.g. a toolbar.
42e69d6b
VZ
1011 if ( hwnd )
1012 {
1013 wxWindow *win = wxFindWinFromHandle(hwnd);
1014 if (win)
1015 return win->MSWCommand(cmd, id);
1016 }
2bda0e17 1017
e1a6fc11
JS
1018 if (wxCurrentPopupMenu)
1019 {
1020 wxMenu *popupMenu = wxCurrentPopupMenu;
1021 wxCurrentPopupMenu = NULL;
1022 if (popupMenu->MSWCommand(cmd, id))
4f8090e0 1023 return true;
e1a6fc11
JS
1024 }
1025
3ca6a5f0 1026 bool processed;
dd60b9ec 1027 if (GetMenuBar() && GetMenuBar()->FindItem(id))
2bda0e17 1028 {
3ca6a5f0 1029 processed = ProcessCommand(id);
2bda0e17
KB
1030 }
1031 else
3ca6a5f0 1032 {
4f8090e0 1033 processed = false;
3ca6a5f0 1034 }
42e69d6b 1035
3ca6a5f0 1036 return processed;
2bda0e17
KB
1037}
1038
42e69d6b
VZ
1039bool wxMDIChildFrame::HandleMDIActivate(long WXUNUSED(activate),
1040 WXHWND hwndAct,
1041 WXHWND hwndDeact)
2bda0e17 1042{
42e69d6b 1043 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
2bda0e17 1044
42e69d6b 1045 HMENU menuToSet = 0;
57a7b7c1 1046
42e69d6b 1047 bool activated;
57a7b7c1 1048
42e69d6b
VZ
1049 if ( m_hWnd == hwndAct )
1050 {
4f8090e0 1051 activated = true;
42e69d6b 1052 parent->m_currentChild = this;
2bda0e17 1053
42e69d6b
VZ
1054 HMENU child_menu = (HMENU)GetWinMenu();
1055 if ( child_menu )
1056 {
4f8090e0 1057 parent->m_parentFrameActive = false;
2bda0e17 1058
42e69d6b
VZ
1059 menuToSet = child_menu;
1060 }
1061 }
1062 else if ( m_hWnd == hwndDeact )
2bda0e17 1063 {
42e69d6b 1064 wxASSERT_MSG( parent->m_currentChild == this,
223d09f6 1065 wxT("can't deactivate MDI child which wasn't active!") );
42e69d6b 1066
4f8090e0 1067 activated = false;
42e69d6b 1068 parent->m_currentChild = NULL;
2bda0e17 1069
42e69d6b 1070 HMENU parent_menu = (HMENU)parent->GetWinMenu();
f4075804
VZ
1071
1072 // activate the the parent menu only when there is no other child
1073 // that has been activated
1074 if ( parent_menu && !hwndAct )
42e69d6b 1075 {
4f8090e0 1076 parent->m_parentFrameActive = true;
42e69d6b
VZ
1077
1078 menuToSet = parent_menu;
1079 }
1080 }
1081 else
1082 {
18d2e170 1083 // we have nothing to do with it
4f8090e0 1084 return false;
2bda0e17 1085 }
debe6624 1086
42e69d6b
VZ
1087 if ( menuToSet )
1088 {
4e152a23
VZ
1089 MDISetMenu(parent->GetClientWindow(),
1090 menuToSet, GetMDIWindowMenu(parent));
42e69d6b
VZ
1091 }
1092
1093 wxActivateEvent event(wxEVT_ACTIVATE, activated, m_windowId);
debe6624 1094 event.SetEventObject( this );
2bda0e17 1095
c03b48d7
GT
1096 ResetWindowStyle((void *)NULL);
1097
42e69d6b
VZ
1098 return GetEventHandler()->ProcessEvent(event);
1099}
1100
1101bool wxMDIChildFrame::HandleWindowPosChanging(void *pos)
1102{
1103 WINDOWPOS *lpPos = (WINDOWPOS *)pos;
a71d815b 1104
42e69d6b 1105 if (!(lpPos->flags & SWP_NOSIZE))
2bda0e17 1106 {
42e69d6b 1107 RECT rectClient;
b3818fbe
VZ
1108 DWORD dwExStyle = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
1109 DWORD dwStyle = ::GetWindowLong(GetHwnd(), GWL_STYLE);
42e69d6b
VZ
1110 if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE))
1111 {
4f8090e0 1112 ::AdjustWindowRectEx(&rectClient, dwStyle, false, dwExStyle);
42e69d6b
VZ
1113 lpPos->x = rectClient.left;
1114 lpPos->y = rectClient.top;
1115 lpPos->cx = rectClient.right - rectClient.left;
1116 lpPos->cy = rectClient.bottom - rectClient.top;
1117 }
42e69d6b 1118 }
42e69d6b 1119
4f8090e0 1120 return false;
42e69d6b
VZ
1121}
1122
3ebcfb76
VZ
1123bool wxMDIChildFrame::HandleGetMinMaxInfo(void *mmInfo)
1124{
1125 MINMAXINFO *info = (MINMAXINFO *)mmInfo;
1126
1127 // let the default window proc calculate the size of MDI children
1128 // frames because it is based on the size of the MDI client window,
1129 // not on the values specified in wxWindow m_max variables
d9f9aa2d 1130 bool processed = MSWDefWindowProc(WM_GETMINMAXINFO, 0, (LPARAM)mmInfo) != 0;
3ebcfb76 1131
e7dda1ff
VS
1132 int minWidth = GetMinWidth(),
1133 minHeight = GetMinHeight();
1134
3ebcfb76 1135 // but allow GetSizeHints() to set the min size
a71d815b 1136 if ( minWidth != wxDefaultCoord )
3ebcfb76 1137 {
e7dda1ff 1138 info->ptMinTrackSize.x = minWidth;
3ebcfb76 1139
4f8090e0 1140 processed = true;
3ebcfb76
VZ
1141 }
1142
a71d815b 1143 if ( minHeight != wxDefaultCoord )
3ebcfb76 1144 {
e7dda1ff 1145 info->ptMinTrackSize.y = minHeight;
3ebcfb76 1146
4f8090e0 1147 processed = true;
3ebcfb76
VZ
1148 }
1149
4c9d78a4 1150 return processed;
3ebcfb76
VZ
1151}
1152
42e69d6b
VZ
1153// ---------------------------------------------------------------------------
1154// MDI specific message translation/preprocessing
1155// ---------------------------------------------------------------------------
2bda0e17 1156
c140b7e7 1157WXLRESULT wxMDIChildFrame::MSWDefWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
42e69d6b
VZ
1158{
1159 return DefMDIChildProc(GetHwnd(),
1160 (UINT)message, (WPARAM)wParam, (LPARAM)lParam);
1161}
1162
1163bool wxMDIChildFrame::MSWTranslateMessage(WXMSG* msg)
1164{
1ac76609
VZ
1165 // we must pass the parent frame to ::TranslateAccelerator(), otherwise it
1166 // doesn't do its job correctly for MDI child menus
1167 return MSWDoTranslateMessage((wxMDIChildFrame *)GetParent(), msg);
2bda0e17
KB
1168}
1169
42e69d6b
VZ
1170// ---------------------------------------------------------------------------
1171// misc
1172// ---------------------------------------------------------------------------
1173
c2dcfdef 1174void wxMDIChildFrame::MSWDestroyWindow()
2bda0e17 1175{
42e69d6b 1176 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
2bda0e17 1177
42e69d6b
VZ
1178 // Must make sure this handle is invalidated (set to NULL) since all sorts
1179 // of things could happen after the child client is destroyed, but before
1180 // the wxFrame is destroyed.
2bda0e17 1181
42e69d6b 1182 HWND oldHandle = (HWND)GetHWND();
b3818fbe
VZ
1183 SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIDESTROY,
1184 (WPARAM)oldHandle, 0);
18d2e170
JS
1185
1186 if (parent->GetActiveChild() == (wxMDIChildFrame*) NULL)
1187 ResetWindowStyle((void*) NULL);
1188
42e69d6b
VZ
1189 if (m_hMenu)
1190 {
1191 ::DestroyMenu((HMENU) m_hMenu);
1192 m_hMenu = 0;
1193 }
ac6482e0 1194 wxRemoveHandleAssociation(this);
42e69d6b 1195 m_hWnd = 0;
2bda0e17
KB
1196}
1197
42e69d6b
VZ
1198// Change the client window's extended style so we don't get a client edge
1199// style when a child is maximised (a double border looks silly.)
2bda0e17
KB
1200bool wxMDIChildFrame::ResetWindowStyle(void *vrect)
1201{
2bda0e17 1202 RECT *rect = (RECT *)vrect;
c2dcfdef
VZ
1203 wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
1204 wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild();
a71d815b 1205
c2dcfdef
VZ
1206 if (!pChild || (pChild == this))
1207 {
47ca6bfb 1208 HWND hwndClient = GetWinHwnd(pFrameWnd->GetClientWindow());
8082a771
VZ
1209 DWORD dwStyle = ::GetWindowLong(hwndClient, GWL_EXSTYLE);
1210
1211 // we want to test whether there is a maximized child, so just set
1212 // dwThisStyle to 0 if there is no child at all
1213 DWORD dwThisStyle = pChild
1f3943e0 1214 ? ::GetWindowLong(GetWinHwnd(pChild), GWL_STYLE) : 0;
c2dcfdef 1215 DWORD dwNewStyle = dwStyle;
8082a771 1216 if ( dwThisStyle & WS_MAXIMIZE )
c2dcfdef
VZ
1217 dwNewStyle &= ~(WS_EX_CLIENTEDGE);
1218 else
1219 dwNewStyle |= WS_EX_CLIENTEDGE;
1220
1221 if (dwStyle != dwNewStyle)
1222 {
47ca6bfb
VZ
1223 // force update of everything
1224 ::RedrawWindow(hwndClient, NULL, NULL,
1225 RDW_INVALIDATE | RDW_ALLCHILDREN);
1226 ::SetWindowLong(hwndClient, GWL_EXSTYLE, dwNewStyle);
1227 ::SetWindowPos(hwndClient, NULL, 0, 0, 0, 0,
42e69d6b
VZ
1228 SWP_FRAMECHANGED | SWP_NOACTIVATE |
1229 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1230 SWP_NOCOPYBITS);
c2dcfdef 1231 if (rect)
47ca6bfb 1232 ::GetClientRect(hwndClient, rect);
2bda0e17 1233
4f8090e0 1234 return true;
2bda0e17 1235 }
c2dcfdef 1236 }
a23fd0e1 1237
4f8090e0 1238 return false;
2bda0e17
KB
1239}
1240
42e69d6b
VZ
1241// ===========================================================================
1242// wxMDIClientWindow: the window of predefined (by Windows) class which
1243// contains the child frames
1244// ===========================================================================
2bda0e17 1245
debe6624 1246bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
2bda0e17 1247{
a756f210 1248 m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
2bda0e17 1249
42e69d6b
VZ
1250 CLIENTCREATESTRUCT ccs;
1251 m_windowStyle = style;
1252 m_parent = parent;
c2dcfdef 1253
4e152a23 1254 ccs.hWindowMenu = GetMDIWindowMenu(parent);
42e69d6b 1255 ccs.idFirstChild = wxFIRST_MDI_CHILD;
2bda0e17 1256
5c44cd05 1257 DWORD msStyle = MDIS_ALLCHILDSTYLES | WS_VISIBLE | WS_CHILD |
b0766406
JS
1258 WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
1259
42e69d6b
VZ
1260 if ( style & wxHSCROLL )
1261 msStyle |= WS_HSCROLL;
1262 if ( style & wxVSCROLL )
1263 msStyle |= WS_VSCROLL;
2bda0e17 1264
42e69d6b 1265 DWORD exStyle = WS_EX_CLIENTEDGE;
2bda0e17 1266
b225f659 1267 wxWindowCreationHook hook(this);
42e69d6b
VZ
1268 m_hWnd = (WXHWND)::CreateWindowEx
1269 (
1270 exStyle,
223d09f6 1271 wxT("MDICLIENT"),
42e69d6b
VZ
1272 NULL,
1273 msStyle,
1274 0, 0, 0, 0,
1275 GetWinHwnd(parent),
1276 NULL,
1277 wxGetInstance(),
1278 (LPSTR)(LPCLIENTCREATESTRUCT)&ccs);
1279 if ( !m_hWnd )
1280 {
f6bcfd97 1281 wxLogLastError(wxT("CreateWindowEx(MDI client)"));
2bda0e17 1282
4f8090e0 1283 return false;
42e69d6b 1284 }
2bda0e17 1285
42e69d6b 1286 SubclassWin(m_hWnd);
2bda0e17 1287
4f8090e0 1288 return true;
2bda0e17
KB
1289}
1290
1291// Explicitly call default scroll behaviour
1292void wxMDIClientWindow::OnScroll(wxScrollEvent& event)
1293{
1294 // Note: for client windows, the scroll position is not set in
1295 // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what
1296 // scroll position we're at.
1297 // This makes it hard to paint patterns or bitmaps in the background,
1298 // and have the client area scrollable as well.
1299
1300 if ( event.GetOrientation() == wxHORIZONTAL )
1301 m_scrollX = event.GetPosition(); // Always returns zero!
1302 else
1303 m_scrollY = event.GetPosition(); // Always returns zero!
1304
42e69d6b
VZ
1305 event.Skip();
1306}
1307
ec06b234
JS
1308void wxMDIClientWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1309{
1310 // Try to fix a problem whereby if you show an MDI child frame, then reposition the
1311 // client area, you can end up with a non-refreshed portion in the client window
1312 // (see OGL studio sample). So check if the position is changed and if so,
1313 // redraw the MDI child frames.
1314
6bbe97b7 1315 const wxPoint oldPos = GetPosition();
ec06b234 1316
6bbe97b7 1317 wxWindow::DoSetSize(x, y, width, height, sizeFlags | wxSIZE_FORCE);
ec06b234 1318
6bbe97b7 1319 const wxPoint newPos = GetPosition();
ec06b234
JS
1320
1321 if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y))
1322 {
1323 if (GetParent())
1324 {
222ed1d6 1325 wxWindowList::compatibility_iterator node = GetParent()->GetChildren().GetFirst();
ec06b234
JS
1326 while (node)
1327 {
d162a7ee 1328 wxWindow *child = node->GetData();
ec06b234
JS
1329 if (child->IsKindOf(CLASSINFO(wxMDIChildFrame)))
1330 {
d162a7ee
VZ
1331 ::RedrawWindow(GetHwndOf(child),
1332 NULL,
1333 NULL,
1334 RDW_FRAME |
1335 RDW_ALLCHILDREN |
1336 RDW_INVALIDATE);
ec06b234 1337 }
4f8090e0 1338 node = node->GetNext();
ec06b234
JS
1339 }
1340 }
1341 }
1342}
1343
f6bcfd97
BP
1344void wxMDIChildFrame::OnIdle(wxIdleEvent& event)
1345{
2596e9fb
VS
1346 // wxMSW prior to 2.5.3 created MDI child frames as visible, which resulted
1347 // in flicker e.g. when the frame contained controls with non-trivial
1348 // layout. Since 2.5.3, the frame is created hidden as all other top level
1349 // windows. In order to maintain backward compatibility, the frame is shown
1350 // in OnIdle, unless Show(false) was called by the programmer before.
1351 if ( m_needsInitialShow )
1352 {
1353 Show(true);
1354 }
5c519b6c 1355
f6bcfd97
BP
1356 // MDI child frames get their WM_SIZE when they're constructed but at this
1357 // moment they don't have any children yet so all child windows will be
1358 // positioned incorrectly when they are added later - to fix this, we
1359 // generate an artificial size event here
1360 if ( m_needsResize )
1361 {
4f8090e0 1362 m_needsResize = false; // avoid any possibility of recursion
f6bcfd97
BP
1363
1364 SendSizeEvent();
1365 }
1366
1367 event.Skip();
1368}
1369
42e69d6b
VZ
1370// ---------------------------------------------------------------------------
1371// non member functions
1372// ---------------------------------------------------------------------------
1373
1374static void MDISetMenu(wxWindow *win, HMENU hmenuFrame, HMENU hmenuWindow)
1375{
e45a6885
VZ
1376 if ( hmenuFrame || hmenuWindow )
1377 {
1378 if ( !::SendMessage(GetWinHwnd(win),
1379 WM_MDISETMENU,
1380 (WPARAM)hmenuFrame,
1381 (LPARAM)hmenuWindow) )
1382 {
1383 wxLogLastError(_T("SendMessage(WM_MDISETMENU)"));
1384 }
1385 }
42e69d6b
VZ
1386
1387 // update menu bar of the parent window
1388 wxWindow *parent = win->GetParent();
223d09f6 1389 wxCHECK_RET( parent, wxT("MDI client without parent frame? weird...") );
42e69d6b 1390
a967ef9d 1391 ::SendMessage(GetWinHwnd(win), WM_MDIREFRESHMENU, 0, 0L);
788722ac 1392
42e69d6b
VZ
1393 ::DrawMenuBar(GetWinHwnd(parent));
1394}
1395
1396static void InsertWindowMenu(wxWindow *win, WXHMENU menu, HMENU subMenu)
1397{
1398 // Try to insert Window menu in front of Help, otherwise append it.
1399 HMENU hmenu = (HMENU)menu;
df61c009
JS
1400
1401 if (subMenu)
1402 {
4e152a23 1403 int N = GetMenuItemCount(hmenu);
4f8090e0 1404 bool success = false;
4e152a23 1405 for ( int i = 0; i < N; i++ )
42e69d6b 1406 {
4e152a23
VZ
1407 wxChar buf[256];
1408 int chars = GetMenuString(hmenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION);
1409 if ( chars == 0 )
1410 {
1411 wxLogLastError(wxT("GetMenuString"));
42e69d6b 1412
4e152a23
VZ
1413 continue;
1414 }
1415
4d931bcc 1416 wxString strBuf(buf);
e27d9a91 1417 if ( wxStripMenuCodes(strBuf) == wxGetStockLabel(wxID_HELP,false) )
4e152a23 1418 {
4f8090e0 1419 success = true;
4e152a23
VZ
1420 ::InsertMenu(hmenu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
1421 (UINT)subMenu, _("&Window"));
1422 break;
1423 }
42e69d6b
VZ
1424 }
1425
4e152a23 1426 if ( !success )
42e69d6b 1427 {
4e152a23 1428 ::AppendMenu(hmenu, MF_POPUP, (UINT)subMenu, _("&Window"));
42e69d6b
VZ
1429 }
1430 }
1431
42e69d6b
VZ
1432 MDISetMenu(win, hmenu, subMenu);
1433}
1434
df61c009
JS
1435static void RemoveWindowMenu(wxWindow *win, WXHMENU menu)
1436{
4e152a23
VZ
1437 HMENU hMenu = (HMENU)menu;
1438
1439 if ( hMenu )
df61c009 1440 {
4e152a23
VZ
1441 wxChar buf[1024];
1442
1443 int N = ::GetMenuItemCount(hMenu);
1444 for ( int i = 0; i < N; i++ )
df61c009 1445 {
4e152a23
VZ
1446 if ( !::GetMenuString(hMenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION) )
1447 {
2c62b3c3
VZ
1448 // Ignore successful read of menu string with length 0 which
1449 // occurs, for example, for a maximized MDI childs system menu
1450 if ( ::GetLastError() != 0 )
1451 {
1452 wxLogLastError(wxT("GetMenuString"));
1453 }
df61c009 1454
4e152a23
VZ
1455 continue;
1456 }
df61c009 1457
4e152a23
VZ
1458 if ( wxStrcmp(buf, _("&Window")) == 0 )
1459 {
1460 if ( !::RemoveMenu(hMenu, i, MF_BYPOSITION) )
1461 {
1462 wxLogLastError(wxT("RemoveMenu"));
1463 }
1464
1465 break;
1466 }
df61c009
JS
1467 }
1468 }
1469
4e152a23
VZ
1470 if ( win )
1471 {
1472 // we don't change the windows menu, but we update the main one
1473 MDISetMenu(win, hMenu, NULL);
1474 }
df61c009
JS
1475}
1476
2917e920
BM
1477static void UnpackMDIActivate(WXWPARAM wParam, WXLPARAM lParam,
1478 WXWORD *activate, WXHWND *hwndAct, WXHWND *hwndDeact)
42e69d6b 1479{
4f8090e0 1480 *activate = true;
42e69d6b
VZ
1481 *hwndAct = (WXHWND)lParam;
1482 *hwndDeact = (WXHWND)wParam;
2bda0e17 1483}
b9f933ab 1484
efd17a1d 1485#endif // wxUSE_MDI && !defined(__WXUNIVERSAL__)