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