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