]> git.saurik.com Git - wxWidgets.git/blame - src/msw/mdi.cpp
fixed an over-optimisation
[wxWidgets.git] / src / msw / mdi.cpp
CommitLineData
2bda0e17
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: mdi.cpp
3// Purpose: MDI classes
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
c2dcfdef 9// Licence: wxWindows license
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
a23fd0e1
VZ
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
2bda0e17 20#ifdef __GNUG__
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
31#ifndef WX_PRECOMP
a23fd0e1
VZ
32 #include "wx/setup.h"
33 #include "wx/frame.h"
34 #include "wx/menu.h"
35 #include "wx/app.h"
36 #include "wx/utils.h"
37 #include "wx/dialog.h"
38 #include "wx/statusbr.h"
39 #include "wx/settings.h"
2bda0e17
KB
40#endif
41
42#include "wx/mdi.h"
43#include "wx/msw/private.h"
44
47d67540 45#if wxUSE_NATIVE_STATUSBAR
a23fd0e1 46 #include <wx/msw/statbr95.h>
2bda0e17
KB
47#endif
48
49#include <string.h>
50
a23fd0e1
VZ
51// ---------------------------------------------------------------------------
52// global variables
53// ---------------------------------------------------------------------------
54
55extern wxWindowList wxModelessWindows; // from dialog.cpp
e1a6fc11 56extern wxMenu *wxCurrentPopupMenu;
2bda0e17 57
a23fd0e1
VZ
58extern char wxMDIFrameClassName[];
59extern char wxMDIChildFrameClassName[];
60extern wxWindow *wxWndHook; // from window.cpp
61
62extern wxList *wxWinHandleList;
63
64// ---------------------------------------------------------------------------
65// constants
66// ---------------------------------------------------------------------------
67
68static const int IDM_WINDOWTILE = 4001;
69static const int IDM_WINDOWCASCADE = 4002;
70static const int IDM_WINDOWICONS = 4003;
71static const int IDM_WINDOWNEXT = 4004;
72
73// This range gives a maximum of 500 MDI children. Should be enough :-)
74static const int wxFIRST_MDI_CHILD = 4100;
75static const int wxLAST_MDI_CHILD = 4600;
2bda0e17
KB
76
77// Status border dimensions
a23fd0e1
VZ
78static const int wxTHICK_LINE_BORDER = 3;
79static const int wxTHICK_LINE_WIDTH = 1;
2bda0e17 80
a23fd0e1
VZ
81// ===========================================================================
82// implementation
83// ===========================================================================
84
85// ---------------------------------------------------------------------------
86// wxWin macros
87// ---------------------------------------------------------------------------
2bda0e17
KB
88
89#if !USE_SHARED_LIBRARY
a23fd0e1
VZ
90 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
91 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
92 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
93#endif // USE_SHARED_LIBRARY
2bda0e17
KB
94
95BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
a23fd0e1
VZ
96 EVT_SIZE(wxMDIParentFrame::OnSize)
97 EVT_ACTIVATE(wxMDIParentFrame::OnActivate)
98 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
2bda0e17
KB
99END_EVENT_TABLE()
100
101BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow)
a23fd0e1 102 EVT_SCROLL(wxMDIClientWindow::OnScroll)
2bda0e17
KB
103END_EVENT_TABLE()
104
a23fd0e1
VZ
105// ---------------------------------------------------------------------------
106// wxMDIParentFrame
107// ---------------------------------------------------------------------------
2bda0e17 108
c2dcfdef 109wxMDIParentFrame::wxMDIParentFrame()
2bda0e17
KB
110{
111 m_clientWindow = NULL;
112 m_currentChild = NULL;
113 m_windowMenu = 0;
114 m_parentFrameActive = TRUE;
2bda0e17
KB
115}
116
117bool wxMDIParentFrame::Create(wxWindow *parent,
a23fd0e1
VZ
118 wxWindowID id,
119 const wxString& title,
120 const wxPoint& pos,
121 const wxSize& size,
122 long style,
123 const wxString& name)
2bda0e17
KB
124{
125 m_defaultIcon = (WXHICON) (wxSTD_MDIPARENTFRAME_ICON ? wxSTD_MDIPARENTFRAME_ICON : wxDEFAULT_MDIPARENTFRAME_ICON);
126
2bda0e17
KB
127 m_clientWindow = NULL;
128 m_currentChild = NULL;
129 m_windowMenu = 0;
130 m_parentFrameActive = TRUE;
131
132 if (!parent)
133 wxTopLevelWindows.Append(this);
134
135 SetName(name);
136 m_windowStyle = style;
137
138 if (parent) parent->AddChild(this);
139
140 if ( id > -1 )
141 m_windowId = id;
142 else
143 m_windowId = (int)NewControlId();
144
145 int x = pos.x;
146 int y = pos.y;
147 int width = size.x;
148 int height = size.y;
149
150 m_windowMenu = (WXHMENU) ::LoadMenu(wxGetInstance(), "wxWindowMenu");
151
46851318 152 DWORD msflags = WS_OVERLAPPED ;
2bda0e17
KB
153 if (style & wxMINIMIZE_BOX)
154 msflags |= WS_MINIMIZEBOX;
155 if (style & wxMAXIMIZE_BOX)
156 msflags |= WS_MAXIMIZEBOX;
157 if (style & wxTHICK_FRAME)
158 msflags |= WS_THICKFRAME;
159 if (style & wxSYSTEM_MENU)
160 msflags |= WS_SYSMENU;
161 if ((style & wxMINIMIZE) || (style & wxICONIZE))
162 msflags |= WS_MINIMIZE;
163 if (style & wxMAXIMIZE)
164 msflags |= WS_MAXIMIZE;
165 if (style & wxCAPTION)
166 msflags |= WS_CAPTION;
46851318
JS
167
168 // Adding WS_CLIPCHILDREN causes children not to be properly
169 // drawn when first displaying them.
170// if (style & wxCLIP_CHILDREN)
171// msflags |= WS_CLIPCHILDREN;
2bda0e17
KB
172
173 wxWindow::MSWCreate(m_windowId, parent, wxMDIFrameClassName, this, title, x, y, width, height,
174 msflags);
175
176 wxModelessWindows.Append(this);
177
178 return TRUE;
179}
180
c2dcfdef 181wxMDIParentFrame::~wxMDIParentFrame()
2bda0e17
KB
182{
183 DestroyChildren();
184
185 DestroyMenu((HMENU) m_windowMenu); // Destroy dummy "Window" menu
186 m_windowMenu = 0;
187
188 if (m_clientWindow->MSWGetOldWndProc())
c2dcfdef 189 m_clientWindow->UnsubclassWin();
2bda0e17 190
cc2b7472 191 m_clientWindow->SetHWND(0);
2bda0e17
KB
192 delete m_clientWindow;
193}
194
2bda0e17
KB
195void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar)
196{
197 if (!menu_bar)
198 {
199 m_frameMenuBar = NULL;
200 return;
201 }
2bda0e17 202
c2dcfdef
VZ
203 if ( menu_bar->IsAttached() )
204 return;
2bda0e17 205
c2dcfdef 206 m_hMenu = menu_bar->Create();
2bda0e17 207
2bda0e17
KB
208 if (m_frameMenuBar)
209 delete m_frameMenuBar;
210
2bda0e17
KB
211 // MDI parent-specific code follows
212
213 HMENU subMenu = GetSubMenu((HMENU) m_windowMenu, 0);
214
215 // Try to insert Window menu in front of Help, otherwise append it.
c2dcfdef 216 HMENU menu = (HMENU)m_hMenu;
2bda0e17
KB
217 int N = GetMenuItemCount(menu);
218 bool success = FALSE;
c2dcfdef 219 for (int i = 0; i < N; i++)
2bda0e17
KB
220 {
221 char buf[100];
222 int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION);
223 if ((chars > 0) && (strcmp(buf, "&Help") == 0 ||
224 strcmp(buf, "Help") == 0))
225 {
226 success = TRUE;
227 InsertMenu(menu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
228 (UINT)subMenu, "&Window");
229 break;
230 }
231 }
232 if (!success)
233 AppendMenu(menu, MF_POPUP,
234 (UINT)subMenu,
235 "&Window");
236 m_parentFrameActive = TRUE;
237#ifdef __WIN32__
238 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDISETMENU,
239 (WPARAM)menu,
240 (LPARAM)subMenu);
241#else
242 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
243 MAKELPARAM(menu, subMenu));
244#endif
245 DrawMenuBar((HWND) GetHWND());
246
247 m_frameMenuBar = menu_bar;
c2dcfdef 248 menu_bar->Attach(this);
2bda0e17
KB
249}
250
251void wxMDIParentFrame::OnSize(wxSizeEvent& event)
252{
47d67540 253#if wxUSE_CONSTRAINTS
a23fd0e1
VZ
254 if ( GetAutoLayout() )
255 {
256 Layout();
257 return;
258 }
259#endif // wxUSE_CONSTRAINTS
260
2bda0e17
KB
261 int x = 0;
262 int y = 0;
263 int width, height;
264 GetClientSize(&width, &height);
2bda0e17
KB
265
266 if ( GetClientWindow() )
267 GetClientWindow()->SetSize(x, y, width, height);
2bda0e17
KB
268}
269
270void wxMDIParentFrame::OnActivate(wxActivateEvent& event)
271{
c2dcfdef 272 // Do nothing
2bda0e17
KB
273}
274
2bda0e17 275// Returns the active MDI child window
c2dcfdef 276wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
2bda0e17 277{
a23fd0e1
VZ
278 HWND hWnd = (HWND)::SendMessage(GetWinHwnd(GetClientWindow()),
279 WM_MDIGETACTIVE, 0, 0L);
280 if ( hWnd == 0 )
281 return NULL;
282 else
283 return (wxMDIChildFrame *)wxFindWinFromHandle((WXHWND) hWnd);
2bda0e17
KB
284}
285
a23fd0e1
VZ
286// Create the client window class (don't Create the window, just return a new
287// class)
c2dcfdef 288wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
2bda0e17 289{
a23fd0e1 290 return new wxMDIClientWindow;
2bda0e17
KB
291}
292
293// Responds to colour changes, and passes event on to children.
294void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
295{
296 if ( m_clientWindow )
297 {
298 m_clientWindow->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
299 m_clientWindow->Refresh();
300 }
301/*
302 if ( m_frameToolBar )
303 {
304 wxSysColourChangedEvent event2;
305 event2.eventObject = m_frameToolBar;
306 m_frameToolBar->GetEventHandler()->ProcessEvent(event2);
307 }
308*/
309
310 // Propagate the event to the non-top-level children
311 wxFrame::OnSysColourChanged(event);
312}
313
314// MDI operations
c2dcfdef 315void wxMDIParentFrame::Cascade()
2bda0e17 316{
a23fd0e1 317 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDICASCADE, 0, 0);
2bda0e17
KB
318}
319
c2dcfdef 320void wxMDIParentFrame::Tile()
2bda0e17 321{
a23fd0e1 322 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDITILE, MDITILE_HORIZONTAL, 0);
2bda0e17
KB
323}
324
c2dcfdef 325void wxMDIParentFrame::ArrangeIcons()
2bda0e17 326{
a23fd0e1 327 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDIICONARRANGE, 0, 0);
2bda0e17
KB
328}
329
c2dcfdef 330void wxMDIParentFrame::ActivateNext()
2bda0e17 331{
a23fd0e1 332 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT, 0, 0);
2bda0e17
KB
333}
334
c2dcfdef 335void wxMDIParentFrame::ActivatePrevious()
2bda0e17 336{
a23fd0e1 337 ::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT, 0, 1);
2bda0e17
KB
338}
339
a23fd0e1
VZ
340// the MDI parent frame window proc
341long wxMDIParentFrame::MSWWindowProc(WXUINT message,
342 WXWPARAM wParam,
343 WXLPARAM lParam)
2bda0e17 344{
a23fd0e1
VZ
345 long rc = 0;
346 bool processed = FALSE;
2bda0e17 347
a23fd0e1
VZ
348 switch ( message )
349 {
350 case WM_CREATE:
351 m_clientWindow = OnCreateClient();
352 // Uses own style for client style
353 if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
354 {
355 wxLogMessage(_("Failed to create MDI parent frame."));
2bda0e17 356
a23fd0e1
VZ
357 rc = -1;
358 }
2bda0e17 359
a23fd0e1
VZ
360 processed = TRUE;
361 break;
2bda0e17 362
a23fd0e1
VZ
363 case WM_ERASEBKGND:
364 processed = TRUE;
2bda0e17 365
a23fd0e1
VZ
366 // we erase background ourselves
367 rc = TRUE;
368 break;
369
370 case WM_MENUSELECT:
371 {
372 WORD item = (WORD)wParam;
373#ifdef __WIN32__
374 WORD flags = HIWORD(wParam);
375 HMENU menu = (HMENU)lParam;
376#else
377 WORD flags = LOWORD(lParam);
378 HMENU menu = (HMENU)HIWORD(lParam);
2bda0e17 379#endif
a23fd0e1
VZ
380 if ( m_parentFrameActive )
381 {
382 processed = HandleMenuSelect(item, flags, (WXHMENU)menu);
383 }
384 else if (m_currentChild)
385 {
386 processed = m_currentChild->
387 HandleMenuSelect(item, flags, (WXHMENU)menu);
388 }
389 }
390 break;
391 }
2bda0e17 392
a23fd0e1
VZ
393 if ( !processed )
394 rc = wxFrame::MSWWindowProc(message, wParam, lParam);
2bda0e17 395
a23fd0e1 396 return rc;
2bda0e17
KB
397}
398
debe6624 399bool wxMDIParentFrame::MSWOnActivate(int state, bool minimized, WXHWND activate)
2bda0e17 400{
a23fd0e1
VZ
401 bool processed = FALSE;
402
403 if ( wxWindow::MSWOnActivate(state, minimized, activate) )
404 {
405 // already processed
406 processed = TRUE;
407 }
2bda0e17
KB
408
409 // If this window is an MDI parent, we must also send an OnActivate message
410 // to the current child.
a23fd0e1
VZ
411 if ( (m_currentChild != NULL) &&
412 ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE)) )
c2dcfdef 413 {
debe6624
JS
414 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_currentChild->GetId());
415 event.SetEventObject( m_currentChild );
a23fd0e1
VZ
416 if ( m_currentChild->GetEventHandler()->ProcessEvent(event) )
417 processed = TRUE;
2bda0e17 418 }
a23fd0e1
VZ
419
420 return processed;
2bda0e17
KB
421}
422
debe6624 423bool wxMDIParentFrame::MSWOnCommand(WXWORD id, WXWORD cmd, WXHWND control)
2bda0e17 424{
57a7b7c1 425// if (cmd == 0) // Why did I do this test?
2bda0e17
KB
426 {
427 // In case it's e.g. a toolbar.
428 wxWindow *win = wxFindWinFromHandle(control);
429 if (win)
430 return win->MSWCommand(cmd, id);
431
db5d183b 432/*
e1a6fc11
JS
433 if (wxCurrentPopupMenu)
434 {
435 wxMenu *popupMenu = wxCurrentPopupMenu;
436 wxCurrentPopupMenu = NULL;
437 if (!popupMenu->MSWCommand(cmd, id))
438 return TRUE;
439 }
db5d183b 440*/
e1a6fc11 441
2bda0e17
KB
442 switch (id)
443 {
444 case IDM_WINDOWCASCADE:
445 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDICASCADE, MDITILE_SKIPDISABLED, 0);
446 return TRUE;
447 case IDM_WINDOWTILE:
448 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDITILE, MDITILE_HORIZONTAL, 0);
449 return TRUE;
450 case IDM_WINDOWICONS:
451 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIICONARRANGE, 0, 0);
452 return TRUE;
453 case IDM_WINDOWNEXT:
454 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 0);
455 return TRUE;
456 default:
457 break;
458 }
459 if (id >= 0xF000)
460 {
2bda0e17
KB
461 return FALSE; // Get WndProc to call default proc
462 }
c2dcfdef 463
2bda0e17
KB
464 if (m_parentFrameActive && (id < wxFIRST_MDI_CHILD || id > wxLAST_MDI_CHILD))
465 {
466 ProcessCommand(id);
467 return TRUE;
468 }
469 else if (m_currentChild && (id < wxFIRST_MDI_CHILD || id > wxLAST_MDI_CHILD))
470 {
2bda0e17
KB
471 return m_currentChild->MSWOnCommand(id, cmd, control);
472 }
473 }
474 if (id >= wxFIRST_MDI_CHILD && id <= wxLAST_MDI_CHILD)
475 {
c0ed460c 476 wxNode* node = GetChildren().First();
2bda0e17
KB
477 while (node)
478 {
479 wxWindow* child = (wxWindow*) node->Data();
480 if (child->GetHWND())
481 {
482#ifdef __WIN32__
483 long childId = GetWindowLong((HWND) child->GetHWND(), GWL_ID);
484#else
485 long childId = GetWindowWord((HWND) child->GetHWND(), GWW_ID);
486#endif
487 if (childId == id)
488 {
489 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) child->GetHWND(), 0);
490 return TRUE;
491 }
492 }
493 node = node->Next();
494 }
495/*
496 wxWindow* child = FindItem(id);
497 if (child)
498 {
499 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) child->GetHWND(), 0);
500 return TRUE;
501 }
502*/
503 }
504
c4b10e41 505 return wxWindow::MSWOnCommand(id, cmd, control);
2bda0e17
KB
506}
507
2bda0e17
KB
508long wxMDIParentFrame::MSWDefWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
509{
c2dcfdef
VZ
510 WXHWND clientWnd;
511 if ( GetClientWindow() )
512 clientWnd = GetClientWindow()->GetHWND();
513 else
514 clientWnd = 0;
2bda0e17 515
a23fd0e1 516 return DefFrameProc(GetHwnd(), (HWND)clientWnd, message, wParam, lParam);
2bda0e17
KB
517}
518
519bool wxMDIParentFrame::MSWProcessMessage(WXMSG* msg)
520{
a23fd0e1
VZ
521 return m_currentChild && m_currentChild->GetHWND() &&
522 m_currentChild->MSWProcessMessage(msg);
57a7b7c1
JS
523}
524
525bool wxMDIParentFrame::MSWTranslateMessage(WXMSG* msg)
526{
a23fd0e1 527 MSG *pMsg = (MSG *)msg;
2bda0e17 528
a23fd0e1
VZ
529 if ( m_currentChild && m_currentChild->GetHWND() &&
530 m_currentChild->MSWTranslateMessage(msg) )
531 {
532 return TRUE;
533 }
2bda0e17 534
a23fd0e1
VZ
535 if ( m_acceleratorTable.Ok() &&
536 ::TranslateAccelerator(GetHwnd(),
537 GetTableHaccel(&m_acceleratorTable),
538 pMsg) )
539 {
540 return TRUE;
541 }
2bda0e17 542
a23fd0e1
VZ
543 if ( pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN )
544 {
545 if ( ::TranslateMDISysAccel(GetWinHwnd(GetClientWindow()), pMsg))
546 return TRUE;
547 }
57a7b7c1 548
a23fd0e1 549 return FALSE;
2bda0e17
KB
550}
551
a23fd0e1
VZ
552// ---------------------------------------------------------------------------
553// wxMDIChildFrame
554// ---------------------------------------------------------------------------
2bda0e17 555
c2dcfdef 556wxMDIChildFrame::wxMDIChildFrame()
2bda0e17 557{
c2dcfdef 558// m_active = FALSE;
2bda0e17
KB
559}
560
561bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
a23fd0e1
VZ
562 wxWindowID id,
563 const wxString& title,
564 const wxPoint& pos,
565 const wxSize& size,
566 long style,
567 const wxString& name)
2bda0e17
KB
568{
569 m_defaultIcon = (WXHICON) (wxSTD_MDICHILDFRAME_ICON ? wxSTD_MDICHILDFRAME_ICON : wxDEFAULT_MDICHILDFRAME_ICON);
570
571 SetName(name);
572
573 if ( id > -1 )
574 m_windowId = id;
575 else
576 m_windowId = (int)NewControlId();
577
578 if (parent) parent->AddChild(this);
579
580 wxWndHook = this;
581
582 int x = pos.x;
583 int y = pos.y;
584 int width = size.x;
585 int height = size.y;
586
587 MDICREATESTRUCT mcs;
c2dcfdef 588
2bda0e17
KB
589 mcs.szClass = wxMDIChildFrameClassName;
590 mcs.szTitle = title;
591 mcs.hOwner = wxGetInstance();
592 if (x > -1) mcs.x = x;
593 else mcs.x = CW_USEDEFAULT;
594
595 if (y > -1) mcs.y = y;
596 else mcs.y = CW_USEDEFAULT;
597
598 if (width > -1) mcs.cx = width;
599 else mcs.cx = CW_USEDEFAULT;
600
601 if (height > -1) mcs.cy = height;
602 else mcs.cy = CW_USEDEFAULT;
603
604 DWORD msflags = WS_OVERLAPPED | WS_CLIPCHILDREN ;
605 if (style & wxMINIMIZE_BOX)
606 msflags |= WS_MINIMIZEBOX;
607 if (style & wxMAXIMIZE_BOX)
608 msflags |= WS_MAXIMIZEBOX;
609 if (style & wxTHICK_FRAME)
610 msflags |= WS_THICKFRAME;
611 if (style & wxSYSTEM_MENU)
612 msflags |= WS_SYSMENU;
613 if ((style & wxMINIMIZE) || (style & wxICONIZE))
614 msflags |= WS_MINIMIZE;
615 if (style & wxMAXIMIZE)
616 msflags |= WS_MAXIMIZE;
617 if (style & wxCAPTION)
618 msflags |= WS_CAPTION;
619
620 mcs.style = msflags;
621
622 mcs.lParam = 0;
623
624 DWORD Return = SendMessage((HWND) parent->GetClientWindow()->GetHWND(),
c2dcfdef 625 WM_MDICREATE, 0, (LONG)(LPSTR)&mcs);
2bda0e17
KB
626
627 //handle = (HWND)LOWORD(Return);
628 // Must be the DWORRD for WIN32. And in 16 bits, HIWORD=0 (says Microsoft)
629 m_hWnd = (WXHWND)Return;
630
631 // This gets reassigned so can't be stored
632// m_windowId = GetWindowLong((HWND) m_hWnd, GWL_ID);
633
634 wxWndHook = NULL;
635 wxWinHandleList->Append((long)GetHWND(), this);
636
637 SetWindowLong((HWND) GetHWND(), 0, (long)this);
638
639 wxModelessWindows.Append(this);
640 return TRUE;
641}
642
c2dcfdef 643wxMDIChildFrame::~wxMDIChildFrame()
2bda0e17 644{
c2dcfdef 645 MSWDestroyWindow();
2bda0e17
KB
646
647 ResetWindowStyle(NULL);
648}
649
650// Set the client size (i.e. leave the calculation of borders etc.
651// to wxWindows)
cc2b7472 652void wxMDIChildFrame::DoSetClientSize(int width, int height)
2bda0e17
KB
653{
654 HWND hWnd = (HWND) GetHWND();
655
656 RECT rect;
2de8030d 657 ::GetClientRect(hWnd, &rect);
2bda0e17
KB
658
659 RECT rect2;
660 GetWindowRect(hWnd, &rect2);
661
662 // Find the difference between the entire window (title bar and all)
663 // and the client area; add this to the new client size to move the
664 // window
665 int actual_width = rect2.right - rect2.left - rect.right + width;
666 int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
667
668 if (GetStatusBar())
669 {
c2dcfdef
VZ
670 int sx, sy;
671 GetStatusBar()->GetSize(&sx, &sy);
2bda0e17
KB
672 actual_height += sy;
673 }
674
675 POINT point;
676 point.x = rect2.left;
677 point.y = rect2.top;
678
679 // If there's an MDI parent, must subtract the parent's top left corner
680 // since MoveWindow moves relative to the parent
681 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
682 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
683
684 MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE);
debe6624 685
2bda0e17 686 wxSizeEvent event(wxSize(width, height), m_windowId);
debe6624 687 event.SetEventObject( this );
2bda0e17 688 GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
689}
690
cc2b7472 691void wxMDIChildFrame::DoGetPosition(int *x, int *y) const
2bda0e17
KB
692{
693 RECT rect;
694 GetWindowRect((HWND) GetHWND(), &rect);
695 POINT point;
696 point.x = rect.left;
697 point.y = rect.top;
698
699 // Since we now have the absolute screen coords,
700 // if there's a parent we must subtract its top left corner
701 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
702 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
703
704 *x = point.x;
705 *y = point.y;
706}
707
708void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar)
709{
710 if (!menu_bar)
711 {
712 m_frameMenuBar = NULL;
713 return;
714 }
2bda0e17 715
c2dcfdef
VZ
716 if ( menu_bar->IsAttached() )
717 return;
2bda0e17 718
c2dcfdef 719 m_hMenu = menu_bar->Create();
2bda0e17 720
2bda0e17
KB
721 if (m_frameMenuBar)
722 delete m_frameMenuBar;
723
2bda0e17
KB
724 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
725
726 parent->m_parentFrameActive = FALSE;
c4e7c2aa 727 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
2bda0e17
KB
728
729 // Try to insert Window menu in front of Help, otherwise append it.
c2dcfdef 730 HMENU menu = (HMENU)m_hMenu;
2bda0e17
KB
731 int N = GetMenuItemCount(menu);
732 bool success = FALSE;
c2dcfdef 733 for (int i = 0; i < N; i++)
2bda0e17
KB
734 {
735 char buf[100];
736 int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION);
737 if ((chars > 0) && (strcmp(buf, "&Help") == 0 ||
738 strcmp(buf, "Help") == 0))
739 {
740 success = TRUE;
741 InsertMenu(menu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
742 (UINT)subMenu, "&Window");
743 break;
744 }
745 }
746 if (!success)
747 AppendMenu(menu, MF_POPUP,
748 (UINT)subMenu,
749 "&Window");
750#ifdef __WIN32__
751 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
752 (WPARAM)menu,
753 (LPARAM)subMenu);
754#else
755 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
756 MAKELPARAM(menu, subMenu));
757#endif
758
759 DrawMenuBar((HWND) parent->GetHWND());
760 m_frameMenuBar = menu_bar;
c2dcfdef 761 menu_bar->Attach(this);
2bda0e17
KB
762}
763
764// MDI operations
c2dcfdef 765void wxMDIChildFrame::Maximize()
2bda0e17
KB
766{
767 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
768 if ( parent && parent->GetClientWindow() )
769 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIMAXIMIZE, (WPARAM) (HWND) GetHWND(), 0);
770}
771
c2dcfdef 772void wxMDIChildFrame::Restore()
2bda0e17
KB
773{
774 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
775 if ( parent && parent->GetClientWindow() )
776 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIRESTORE, (WPARAM) (HWND) GetHWND(), 0);
777}
778
c2dcfdef 779void wxMDIChildFrame::Activate()
2bda0e17
KB
780{
781 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
782 if ( parent && parent->GetClientWindow() )
783 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) GetHWND(), 0);
784}
785
786static HWND invalidHandle = 0;
a23fd0e1 787bool wxMDIChildFrame::MSWOnSize(int x, int y, WXUINT id)
2bda0e17 788{
a23fd0e1
VZ
789 HWND hwnd = GetHwnd();
790
791 if ( !hwnd || hwnd == invalidHandle )
2bda0e17 792 {
a23fd0e1
VZ
793 return FALSE;
794 }
795
796 switch (id)
797 {
798 case SIZEFULLSCREEN:
799 case SIZENORMAL:
800 m_iconized = FALSE;
801 break;
802
803 case SIZEICONIC:
804 m_iconized = TRUE;
805 break;
2bda0e17 806 }
a23fd0e1
VZ
807
808 if (!m_iconized)
809 {
810 // forward WM_SIZE to status bar control
811#if wxUSE_NATIVE_STATUSBAR
812 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
813 {
814 wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId());
815 event.SetEventObject( m_frameStatusBar );
816
817 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
818 }
2bda0e17 819#endif
a23fd0e1
VZ
820
821 PositionStatusBar();
822 PositionToolBar();
823
824 return wxWindow::MSWOnSize(x, y, id);
825 }
826 else
827 {
828 return FALSE;
829 }
2bda0e17
KB
830}
831
debe6624 832bool wxMDIChildFrame::MSWOnCommand(WXWORD id, WXWORD cmd, WXHWND control)
2bda0e17 833{
57a7b7c1
JS
834// if ((cmd == 0) && GetHWND())
835 if (GetHWND())
2bda0e17
KB
836 {
837 // In case it's e.g. a toolbar.
838 wxWindow *win = wxFindWinFromHandle(control);
839 if (win)
840 return win->MSWCommand(cmd, id);
841
e1a6fc11
JS
842 if (wxCurrentPopupMenu)
843 {
844 wxMenu *popupMenu = wxCurrentPopupMenu;
845 wxCurrentPopupMenu = NULL;
846 if (popupMenu->MSWCommand(cmd, id))
847 return TRUE;
848 }
849
2bda0e17
KB
850 if (GetMenuBar() && GetMenuBar()->FindItemForId(id))
851 {
852 ProcessCommand(id);
853 return TRUE;
854 }
855 else
856 return FALSE;
857 return TRUE;
858 }
859 else
c4b10e41 860 return wxWindow::MSWOnCommand(id, cmd, control);
2bda0e17
KB
861}
862
863long wxMDIChildFrame::MSWDefWindowProc(WXUINT message, WXUINT wParam, WXLPARAM lParam)
864{
865 if (GetHWND())
866 return DefMDIChildProc((HWND) GetHWND(), (UINT) message, (WPARAM) wParam, (LPARAM) lParam);
867 else return 0;
868}
869
870bool wxMDIChildFrame::MSWProcessMessage(WXMSG *msg)
57a7b7c1
JS
871{
872 return FALSE;
873}
874
875bool wxMDIChildFrame::MSWTranslateMessage(WXMSG* msg)
2bda0e17
KB
876{
877 MSG *pMsg = (MSG *)msg;
57a7b7c1 878 if (m_acceleratorTable.Ok())
2bda0e17
KB
879 {
880 wxFrame *parent = (wxFrame *)GetParent();
881 HWND parent_hwnd = (HWND) parent->GetHWND();
57a7b7c1 882 return (::TranslateAccelerator(parent_hwnd, (HACCEL) m_acceleratorTable.GetHACCEL(), pMsg) != 0);
2bda0e17 883 }
57a7b7c1 884
2bda0e17
KB
885 return FALSE;
886}
887
a23fd0e1 888bool wxMDIChildFrame::MSWOnMDIActivate(long activate, WXHWND WXUNUSED(one), WXHWND WXUNUSED(two))
2bda0e17
KB
889{
890 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
891 HMENU parent_menu = (HMENU) parent->GetWinMenu();
2bda0e17 892 HMENU child_menu = (HMENU) GetWinMenu();
2bda0e17
KB
893
894 if (activate)
895 {
896// m_active = TRUE;
897 parent->m_currentChild = this;
898 if (child_menu)
899 {
900 parent->m_parentFrameActive = FALSE;
901 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
2bda0e17
KB
902#ifdef __WIN32__
903 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
904 (WPARAM)child_menu,
905 (LPARAM)subMenu);
906#else
907 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
908 MAKELONG(child_menu, subMenu));
909#endif
910
911 ::DrawMenuBar((HWND) parent->GetHWND());
912 }
debe6624
JS
913 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_windowId);
914 event.SetEventObject( this );
a23fd0e1 915 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
916 }
917 else
918 {
919 if (parent->m_currentChild == this)
920 parent->m_currentChild = NULL;
debe6624
JS
921
922 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, m_windowId);
923 event.SetEventObject( this );
a23fd0e1
VZ
924 if ( GetEventHandler()->ProcessEvent(event) )
925 return TRUE;
2bda0e17
KB
926
927// m_active = FALSE;
928 if (parent_menu)
929 {
930 parent->m_parentFrameActive = TRUE;
931 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
2bda0e17
KB
932#ifdef __WIN32__
933 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
934 (WPARAM)parent_menu,
935 (LPARAM)subMenu);
936#else
937 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
938 MAKELONG(parent_menu, subMenu));
939#endif
940
941 ::DrawMenuBar((HWND) parent->GetHWND());
942 }
943 }
2bda0e17 944 bool flag = (activate != 0);
debe6624
JS
945 wxActivateEvent event(wxEVT_ACTIVATE, flag, m_windowId);
946 event.SetEventObject( this );
a23fd0e1 947 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
948}
949
c2dcfdef 950void wxMDIChildFrame::MSWDestroyWindow()
2bda0e17
KB
951{
952 MSWDetachWindowMenu();
953 invalidHandle = (HWND) GetHWND();
954
955 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
956
957 // Must make sure this handle is invalidated (set to NULL)
958 // since all sorts of things could happen after the
959 // child client is destroyed, but before the wxFrame is
960 // destroyed.
961
962 HWND oldHandle = (HWND)GetHWND();
2bda0e17
KB
963#ifdef __WIN32__
964 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (WPARAM)oldHandle, (LPARAM)0);
965#else
966 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (HWND)oldHandle, 0);
2bda0e17
KB
967#endif
968 invalidHandle = 0;
969
970 if (m_hMenu)
971 {
972 ::DestroyMenu((HMENU) m_hMenu);
973 m_hMenu = 0;
974 }
975 m_hWnd = 0;
976}
977
978// Change the client window's extended style so we don't
979// get a client edge style when a child is maximised (a double
980// border looks silly.)
981bool wxMDIChildFrame::ResetWindowStyle(void *vrect)
982{
983#if defined(__WIN95__)
984 RECT *rect = (RECT *)vrect;
c2dcfdef
VZ
985 wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
986 wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild();
987 if (!pChild || (pChild == this))
988 {
989 DWORD dwStyle = ::GetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE);
2bda0e17 990 DWORD dwThisStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE);
c2dcfdef
VZ
991 DWORD dwNewStyle = dwStyle;
992 if (pChild != NULL && (dwThisStyle & WS_MAXIMIZE))
993 dwNewStyle &= ~(WS_EX_CLIENTEDGE);
994 else
995 dwNewStyle |= WS_EX_CLIENTEDGE;
996
997 if (dwStyle != dwNewStyle)
998 {
999 ::RedrawWindow((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
1000 ::SetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE, dwNewStyle);
1001 ::SetWindowPos((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, 0, 0, 0, 0,
1002 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS);
1003 if (rect)
1004 ::GetClientRect((HWND) pFrameWnd->GetClientWindow()->GetHWND(), rect);
1005 return TRUE;
1006 }
1007 }
1008 return FALSE;
2bda0e17
KB
1009#else
1010 return FALSE;
1011#endif
1012}
1013
a23fd0e1 1014bool wxMDIChildFrame::MSWOnWindowPosChanging(void *pos)
2bda0e17
KB
1015{
1016 WINDOWPOS *lpPos = (WINDOWPOS *)pos;
1017#if defined(__WIN95__)
1018 if (!(lpPos->flags & SWP_NOSIZE))
c2dcfdef
VZ
1019 {
1020 RECT rectClient;
1021 DWORD dwExStyle = ::GetWindowLong((HWND) GetHWND(), GWL_EXSTYLE);
2bda0e17 1022 DWORD dwStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE);
c2dcfdef
VZ
1023 if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE))
1024 {
1025 ::AdjustWindowRectEx(&rectClient, dwStyle, FALSE, dwExStyle);
1026 lpPos->x = rectClient.left;
2bda0e17 1027 lpPos->y = rectClient.top;
c2dcfdef 1028 lpPos->cx = rectClient.right - rectClient.left;
2bda0e17 1029 lpPos->cy = rectClient.bottom - rectClient.top;
c2dcfdef
VZ
1030 }
1031 wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
2bda0e17
KB
1032 if (pFrameWnd && pFrameWnd->GetToolBar())
1033 {
1034 pFrameWnd->GetToolBar()->Refresh();
1035 }
c2dcfdef 1036 }
2bda0e17 1037#endif
a23fd0e1
VZ
1038
1039 return FALSE;
2bda0e17
KB
1040}
1041
1042// Client window
c2dcfdef 1043wxMDIClientWindow::wxMDIClientWindow()
2bda0e17
KB
1044{
1045 m_scrollX = 0;
1046 m_scrollY = 0;
1047}
1048
c2dcfdef 1049wxMDIClientWindow::~wxMDIClientWindow()
2bda0e17
KB
1050{
1051}
1052
debe6624 1053bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
2bda0e17
KB
1054{
1055 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE);
1056
1057 CLIENTCREATESTRUCT ccs;
1058 m_windowStyle = style;
cc2b7472 1059 m_parent = parent;
c2dcfdef 1060
2bda0e17
KB
1061 ccs.hWindowMenu = (HMENU) parent->GetWindowMenu();
1062 ccs.idFirstChild = wxFIRST_MDI_CHILD;
1063
1064 DWORD msStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN ;
1065 if ( parent->GetWindowStyleFlag() & wxHSCROLL )
c2dcfdef 1066 msStyle |= WS_HSCROLL;
2bda0e17 1067 if ( parent->GetWindowStyleFlag() & wxVSCROLL )
c2dcfdef 1068 msStyle |= WS_VSCROLL ;
2bda0e17
KB
1069
1070#if defined(__WIN95__)
1071 DWORD exStyle = WS_EX_CLIENTEDGE;
1072#else
1073 DWORD exStyle = 0;
1074#endif
1075
1076 wxWndHook = this;
1077 m_hWnd = (WXHWND) ::CreateWindowEx(exStyle, "mdiclient", NULL,
1078 msStyle, 0, 0, 0, 0, (HWND) parent->GetHWND(), NULL,
1079 wxGetInstance(), (LPSTR)(LPCLIENTCREATESTRUCT)&ccs);
1080 SubclassWin(m_hWnd);
1081 wxWndHook = NULL;
1082
1083 return (m_hWnd != 0) ;
1084}
1085
1086// Window procedure: here for debugging purposes
1087long wxMDIClientWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1088{
1089 return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
1090// return MSWDefWindowProc(nMsg, wParam, lParam);
1091}
1092
1093long wxMDIClientWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1094{
c2dcfdef
VZ
1095 if ( MSWGetOldWndProc() != 0)
1096 return ::CallWindowProc(CASTWNDPROC MSWGetOldWndProc(), (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
1097 else
1098 return ::DefWindowProc((HWND) m_hWnd, (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
2bda0e17
KB
1099}
1100
1101// Explicitly call default scroll behaviour
1102void wxMDIClientWindow::OnScroll(wxScrollEvent& event)
1103{
1104 // Note: for client windows, the scroll position is not set in
1105 // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what
1106 // scroll position we're at.
1107 // This makes it hard to paint patterns or bitmaps in the background,
1108 // and have the client area scrollable as well.
1109
1110 if ( event.GetOrientation() == wxHORIZONTAL )
1111 m_scrollX = event.GetPosition(); // Always returns zero!
1112 else
1113 m_scrollY = event.GetPosition(); // Always returns zero!
1114
c2dcfdef 1115 Default();
2bda0e17 1116}