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