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