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