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