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