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