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