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