Merge MPC-HC code(01b8dbf34d6a486fa1cd02d7a123249fec1e4160) [PART 2] (HdmvSub)
[xy_vsfilter.git] / src / thirdparty / mfc / winmdi.cpp
blob7e7d1cc2771412f21870a3c907bbc1d6eb4c48c8
1 // This is a part of the Microsoft Foundation Classes C++ library.
2 // Copyright (C) Microsoft Corporation
3 // All rights reserved.
4 //
5 // This source code is only intended as a supplement to the
6 // Microsoft Foundation Classes Reference and related
7 // electronic documentation provided with the library.
8 // See these sources for detailed information regarding the
9 // Microsoft Foundation Classes product.
11 #include "stdafx.h"
12 //#include "afxmdichildwndex.h"
13 //#include "afxmdiframewndex.h"
16 /////////////////////////////////////////////////////////////////////////////
17 // CMDIFrameWnd
19 BEGIN_MESSAGE_MAP(CMDIFrameWnd, CFrameWnd)
20 //{{AFX_MSG_MAP(CMDIFrameWnd)
21 ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI, CMDIFrameWnd::OnIdleUpdateCmdUI)
22 ON_UPDATE_COMMAND_UI(ID_WINDOW_ARRANGE, &CMDIFrameWnd::OnUpdateMDIWindowCmd)
23 ON_UPDATE_COMMAND_UI(ID_WINDOW_CASCADE, &CMDIFrameWnd::OnUpdateMDIWindowCmd)
24 ON_UPDATE_COMMAND_UI(ID_WINDOW_TILE_HORZ, &CMDIFrameWnd::OnUpdateMDIWindowCmd)
25 ON_UPDATE_COMMAND_UI(ID_WINDOW_TILE_VERT, &CMDIFrameWnd::OnUpdateMDIWindowCmd)
26 ON_WM_SIZE()
27 ON_COMMAND_EX(ID_WINDOW_ARRANGE, &CMDIFrameWnd::OnMDIWindowCmd)
28 ON_COMMAND_EX(ID_WINDOW_CASCADE, &CMDIFrameWnd::OnMDIWindowCmd)
29 ON_COMMAND_EX(ID_WINDOW_TILE_HORZ, &CMDIFrameWnd::OnMDIWindowCmd)
30 ON_COMMAND_EX(ID_WINDOW_TILE_VERT, &CMDIFrameWnd::OnMDIWindowCmd)
31 ON_UPDATE_COMMAND_UI(ID_WINDOW_NEW, &CMDIFrameWnd::OnUpdateMDIWindowCmd)
32 ON_COMMAND(ID_WINDOW_NEW, &CMDIFrameWnd::OnWindowNew)
33 ON_WM_DESTROY()
34 ON_MESSAGE(WM_COMMANDHELP, &CMDIFrameWnd::OnCommandHelp)
35 ON_WM_MENUCHAR()
36 //}}AFX_MSG_MAP
37 END_MESSAGE_MAP()
39 CMDIFrameWnd::CMDIFrameWnd()
41 m_hWndMDIClient = NULL;
44 BOOL CMDIFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
46 // send to MDI child first - will be re-sent through OnCmdMsg later
47 CMDIChildWnd* pActiveChild = MDIGetActive();
48 if (pActiveChild != NULL && AfxCallWndProc(pActiveChild,
49 pActiveChild->m_hWnd, WM_COMMAND, wParam, lParam) != 0)
50 return TRUE; // handled by child
52 if (CFrameWnd::OnCommand(wParam, lParam))
53 return TRUE; // handled through normal mechanism (MDI child or frame)
55 HWND hWndCtrl = (HWND)lParam;
57 ASSERT(AFX_IDM_FIRST_MDICHILD == 0xFF00);
58 if (hWndCtrl == NULL && (LOWORD(wParam) & 0xf000) == 0xf000)
60 // menu or accelerator within range of MDI children
61 // default frame proc will handle it
62 DefWindowProc(WM_COMMAND, wParam, lParam);
63 return TRUE;
66 return FALSE; // not handled
69 BOOL CMDIFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
70 AFX_CMDHANDLERINFO* pHandlerInfo)
72 CMDIChildWnd* pActiveChild = MDIGetActive();
73 // pump through active child FIRST
74 if (pActiveChild != NULL)
76 CPushRoutingFrame push(this);
77 if (pActiveChild->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
78 return TRUE;
81 // then pump through normal frame
82 return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
85 LRESULT CMDIFrameWnd::OnCommandHelp(WPARAM wParam, LPARAM lParam)
87 if (lParam == 0 && IsTracking())
88 lParam = HID_BASE_COMMAND+m_nIDTracking;
90 CMDIChildWnd* pActiveChild = MDIGetActive();
91 if (pActiveChild != NULL && AfxCallWndProc(pActiveChild,
92 pActiveChild->m_hWnd, WM_COMMANDHELP, wParam, lParam) != 0)
94 // handled by child
95 return TRUE;
98 if (CFrameWnd::OnCommandHelp(wParam, lParam))
100 // handled by our base
101 return TRUE;
104 if (lParam != 0)
106 CWinApp* pApp = AfxGetApp();
107 if (pApp != NULL)
109 AfxGetApp()->WinHelpInternal(lParam);
110 return TRUE;
113 return FALSE;
116 BOOL CMDIFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext*)
118 CMenu* pMenu = NULL;
119 if (m_hMenuDefault == NULL)
121 // default implementation for MFC V1 backward compatibility
122 pMenu = GetMenu();
123 ASSERT(pMenu != NULL);
124 // This is attempting to guess which sub-menu is the Window menu.
125 // The Windows user interface guidelines say that the right-most
126 // menu on the menu bar should be Help and Window should be one
127 // to the left of that.
128 int iMenu = pMenu->GetMenuItemCount() - 2;
130 // If this assertion fails, your menu bar does not follow the guidelines
131 // so you will have to override this function and call CreateClient
132 // appropriately or use the MFC V2 MDI functionality.
133 ASSERT(iMenu >= 0);
134 pMenu = pMenu->GetSubMenu(iMenu);
135 ASSERT(pMenu != NULL);
138 return CreateClient(lpcs, pMenu);
141 BOOL CMDIFrameWnd::CreateClient(LPCREATESTRUCT lpCreateStruct,
142 CMenu* pWindowMenu)
144 ASSERT(m_hWnd != NULL);
145 ASSERT(m_hWndMDIClient == NULL);
146 DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_BORDER |
147 WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
148 MDIS_ALLCHILDSTYLES; // allow children to be created invisible
149 DWORD dwExStyle = 0;
150 // will be inset by the frame
152 // special styles for 3d effect on Win4
153 dwStyle &= ~WS_BORDER;
154 dwExStyle = WS_EX_CLIENTEDGE;
156 CLIENTCREATESTRUCT ccs;
157 ccs.hWindowMenu = pWindowMenu->GetSafeHmenu();
158 // set hWindowMenu for MFC V1 backward compatibility
159 // for MFC V2, window menu will be set in OnMDIActivate
160 ccs.idFirstChild = AFX_IDM_FIRST_MDICHILD;
162 if (lpCreateStruct->style & (WS_HSCROLL|WS_VSCROLL))
164 // parent MDIFrame's scroll styles move to the MDICLIENT
165 dwStyle |= (lpCreateStruct->style & (WS_HSCROLL|WS_VSCROLL));
167 // fast way to turn off the scrollbar bits (without a resize)
168 ModifyStyle(WS_HSCROLL|WS_VSCROLL, 0, SWP_NOREDRAW|SWP_FRAMECHANGED);
171 // Create MDICLIENT control with special IDC
172 if ((m_hWndMDIClient = ::AfxCtxCreateWindowEx(dwExStyle, _T("mdiclient"), NULL,
173 dwStyle, 0, 0, 0, 0, m_hWnd, (HMENU)AFX_IDW_PANE_FIRST,
174 AfxGetInstanceHandle(), (LPVOID)&ccs)) == NULL)
176 TRACE(traceAppMsg, 0, _T("Warning: CMDIFrameWnd::OnCreateClient: failed to create MDICLIENT.")
177 _T(" GetLastError returns 0x%8.8X\n"), ::GetLastError());
178 return FALSE;
180 // Move it to the top of z-order
181 ::BringWindowToTop(m_hWndMDIClient);
183 return TRUE;
186 LRESULT CMDIFrameWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
188 return ::DefFrameProc(m_hWnd, m_hWndMDIClient, nMsg, wParam, lParam);
191 BOOL CMDIFrameWnd::PreTranslateMessage(MSG* pMsg)
193 // check for special cancel modes for ComboBoxes
194 if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN)
195 AfxCancelModes(pMsg->hwnd); // filter clicks
197 // allow tooltip messages to be filtered
198 if (CWnd::PreTranslateMessage(pMsg))
199 return TRUE;
201 #ifndef _AFX_NO_OLE_SUPPORT
202 // allow hook to consume message
203 if (m_pNotifyHook != NULL && m_pNotifyHook->OnPreTranslateMessage(pMsg))
204 return TRUE;
205 #endif
207 CMDIChildWnd* pActiveChild = MDIGetActive();
209 // current active child gets first crack at it
210 if (pActiveChild != NULL && pActiveChild->PreTranslateMessage(pMsg))
211 return TRUE;
213 if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
215 // translate accelerators for frame and any children
216 if (m_hAccelTable != NULL &&
217 ::TranslateAccelerator(m_hWnd, m_hAccelTable, pMsg))
219 return TRUE;
222 // special processing for MDI accelerators last
223 // and only if it is not in SDI mode (print preview)
224 if (GetActiveView() == NULL)
226 if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN)
228 // the MDICLIENT window may translate it
229 if (::TranslateMDISysAccel(m_hWndMDIClient, pMsg))
230 return TRUE;
235 return FALSE;
238 void CMDIFrameWnd::DelayUpdateFrameMenu(HMENU hMenuAlt)
240 OnUpdateFrameMenu(hMenuAlt);
242 m_nIdleFlags |= idleMenu;
245 void CMDIFrameWnd::OnIdleUpdateCmdUI()
247 if (m_nIdleFlags & idleMenu)
249 DrawMenuBar();
250 m_nIdleFlags &= ~idleMenu;
252 CFrameWnd::OnIdleUpdateCmdUI();
255 CFrameWnd* CMDIFrameWnd::GetActiveFrame()
257 CMDIChildWnd* pActiveChild = MDIGetActive();
258 if (pActiveChild == NULL)
259 return this;
260 return pActiveChild;
263 BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
265 if (cs.lpszClass == NULL)
267 VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG));
268 cs.lpszClass = _afxWndMDIFrame;
270 return TRUE;
273 BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
274 CWnd* pParentWnd, CCreateContext* pContext)
276 if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,
277 pParentWnd, pContext))
278 return FALSE;
280 // save menu to use when no active MDI child window is present
281 ASSERT(m_hWnd != NULL);
282 m_hMenuDefault = ::GetMenu(m_hWnd);
283 return TRUE;
286 void CMDIFrameWnd::OnDestroy()
288 CFrameWnd::OnDestroy(); // exit and misc cleanup
290 // owned menu stored in shared slot for MDIFRAME
291 if (m_hMenuDefault != NULL && ::GetMenu(m_hWnd) != m_hMenuDefault)
293 // must go through MDI client to get rid of MDI menu additions
294 ::SendMessage(m_hWndMDIClient, WM_MDISETMENU,
295 (WPARAM)m_hMenuDefault, NULL);
296 ASSERT(::GetMenu(m_hWnd) == m_hMenuDefault);
300 void CMDIFrameWnd::OnSize(UINT nType, int, int)
302 // do not call default - it will reposition the MDICLIENT
303 if (nType != SIZE_MINIMIZED)
304 RecalcLayout();
307 LRESULT CMDIFrameWnd::OnMenuChar(UINT nChar, UINT, CMenu*)
309 // do not call Default() for Alt+(-) when in print preview mode
310 if (m_lpfnCloseProc != NULL && nChar == (UINT)'-')
311 return 0;
312 else
313 return Default();
316 CMDIChildWnd* CMDIFrameWnd::MDIGetActive(BOOL* pbMaximized) const
318 // check first for MDI client window not created
319 if (m_hWndMDIClient == NULL)
321 if (pbMaximized != NULL)
322 *pbMaximized = FALSE;
323 return NULL;
326 // MDI client has been created, get active MDI child
327 HWND hWnd = (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0,
328 (LPARAM)pbMaximized);
329 CMDIChildWnd* pWnd = (CMDIChildWnd*)CWnd::FromHandlePermanent(hWnd);
330 ASSERT(pWnd == NULL || pWnd->IsKindOf(RUNTIME_CLASS(CMDIChildWnd)));
332 // check for special pseudo-inactive state
333 if (pWnd != NULL && pWnd->m_bPseudoInactive &&
334 (pWnd->GetStyle() & WS_VISIBLE) == 0)
336 // Window is hidden, active, but m_bPseudoInactive -- return NULL
337 pWnd = NULL;
338 // Ignore maximized flag if pseudo-inactive and maximized
339 if (pbMaximized != NULL)
340 *pbMaximized = FALSE;
342 return pWnd;
346 CMDIChildWnd* CMDIFrameWnd::CreateNewChild(CRuntimeClass* pClass,
347 UINT nResources, HMENU hMenu /* = NULL */, HACCEL hAccel /* = NULL */)
349 ASSERT(pClass != NULL);
350 CMDIChildWnd* pFrame = (CMDIChildWnd*) pClass->CreateObject();
351 ASSERT_KINDOF(CMDIChildWnd, pFrame);
353 // load the frame
354 CCreateContext context;
355 context.m_pCurrentFrame = this;
357 pFrame->SetHandles(hMenu, hAccel);
358 if (!pFrame->LoadFrame(nResources,
359 WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, &context))
361 TRACE(traceAppMsg, 0, "Couldn't load frame window.\n");
362 return NULL;
365 CString strFullString, strTitle;
366 if (strFullString.LoadString(nResources))
367 AfxExtractSubString(strTitle, strFullString, CDocTemplate::docName);
369 // redraw the frame and parent
370 pFrame->SetTitle(strTitle);
371 pFrame->InitialUpdateFrame(NULL, TRUE);
373 return pFrame;
376 /////////////////////////////////////////////////////////////////////////////
377 // CMDIFrameWnd Diagnostics
379 #ifdef _DEBUG
380 void CMDIFrameWnd::AssertValid() const
382 CFrameWnd::AssertValid();
383 ASSERT(m_hWndMDIClient == NULL || ::IsWindow(m_hWndMDIClient));
384 ASSERT(m_hMenuDefault == NULL || ::IsMenu(m_hMenuDefault));
387 void CMDIFrameWnd::Dump(CDumpContext& dc) const
389 CFrameWnd::Dump(dc);
391 dc << "m_hWndMDIClient = " << (void*)m_hWndMDIClient;
392 dc << "\nm_hMenuDefault = " << (void*)m_hMenuDefault;
394 dc << "\n";
396 #endif //_DEBUG
398 /////////////////////////////////////////////////////////////////////////////
399 // CMDIChildWnd
401 BEGIN_MESSAGE_MAP(CMDIChildWnd, CFrameWnd)
402 //{{AFX_MSG_MAP(CMDIChildWnd)
403 ON_WM_MOUSEACTIVATE()
404 ON_WM_NCACTIVATE()
405 ON_WM_MDIACTIVATE()
406 ON_WM_SIZE()
407 ON_WM_WINDOWPOSCHANGING()
408 ON_WM_NCCREATE()
409 ON_WM_CREATE()
410 ON_WM_DESTROY()
411 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, &CMDIChildWnd::OnToolTipText)
412 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, &CMDIChildWnd::OnToolTipText)
413 //}}AFX_MSG_MAP
414 END_MESSAGE_MAP()
416 CMDIChildWnd::CMDIChildWnd()
418 m_hMenuShared = NULL;
419 m_bPseudoInactive = FALSE;
422 /////////////////////////////////////////////////////////////////////////////
423 // CMDIChildWnd special processing
425 LRESULT CMDIChildWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
427 return ::DefMDIChildProc(m_hWnd, nMsg, wParam, lParam);
430 BOOL CMDIChildWnd::DestroyWindow()
432 if (m_hWnd == NULL)
433 return FALSE;
435 // avoid changing the caption during the destroy message(s)
436 CMDIFrameWnd* pFrameWnd = GetMDIFrame();
437 HWND hWndFrame = pFrameWnd->m_hWnd;
438 ASSERT(::IsWindow(hWndFrame));
439 DWORD dwStyle = SetWindowLong(hWndFrame, GWL_STYLE,
440 GetWindowLong(hWndFrame, GWL_STYLE) & ~FWS_ADDTOTITLE);
442 MDIDestroy();
444 if (::IsWindow(hWndFrame))
446 ASSERT(hWndFrame == pFrameWnd->m_hWnd);
447 SetWindowLong(hWndFrame, GWL_STYLE, dwStyle);
448 pFrameWnd->OnUpdateFrameTitle(TRUE);
451 return TRUE;
454 BOOL CMDIChildWnd::PreTranslateMessage(MSG* pMsg)
456 // check for special cancel modes for combo boxes
457 if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN)
458 AfxCancelModes(pMsg->hwnd); // filter clicks
460 // allow tooltip messages to be filtered
461 if (CWnd::PreTranslateMessage(pMsg))
462 return TRUE;
464 // we can't call 'CFrameWnd::PreTranslate' since it will translate
465 // accelerators in the context of the MDI Child - but since MDI Child
466 // windows don't have menus this doesn't work properly. MDI Child
467 // accelerators must be translated in context of their MDI Frame.
469 if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
471 // use document specific accelerator table over m_hAccelTable
472 HACCEL hAccel = GetDefaultAccelerator();
473 return hAccel != NULL &&
474 ::TranslateAccelerator(GetMDIFrame()->m_hWnd, hAccel, pMsg);
476 return FALSE;
479 BOOL CMDIChildWnd::PreCreateWindow(CREATESTRUCT& cs)
481 ASSERT(cs.style & WS_CHILD);
482 // MFC V2 requires that MDI Children are created with proper styles,
483 // usually: WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW.
484 // See Technical note TN019 for more details on MFC V1->V2 migration.
486 return CFrameWnd::PreCreateWindow(cs);
489 BOOL CMDIChildWnd::Create(LPCTSTR lpszClassName,
490 LPCTSTR lpszWindowName, DWORD dwStyle,
491 const RECT& rect, CMDIFrameWnd* pParentWnd,
492 CCreateContext* pContext)
494 if (pParentWnd == NULL)
496 CWinThread *pThread = AfxGetThread();
497 ENSURE_VALID(pThread);
498 CWnd* pMainWnd = pThread->m_pMainWnd;
499 ENSURE_VALID(pMainWnd);
500 ASSERT_KINDOF(CMDIFrameWnd, pMainWnd);
501 pParentWnd = (CMDIFrameWnd*)pMainWnd;
503 ASSERT(::IsWindow(pParentWnd->m_hWndMDIClient));
505 // insure correct window positioning
506 pParentWnd->RecalcLayout();
508 // first copy into a CREATESTRUCT for PreCreate
509 CREATESTRUCT cs;
510 cs.dwExStyle = 0L;
511 cs.lpszClass = lpszClassName;
512 cs.lpszName = lpszWindowName;
513 cs.style = dwStyle;
514 cs.x = rect.left;
515 cs.y = rect.top;
516 cs.cx = rect.right - rect.left;
517 cs.cy = rect.bottom - rect.top;
518 cs.hwndParent = pParentWnd->m_hWnd;
519 cs.hMenu = NULL;
520 cs.hInstance = AfxGetInstanceHandle();
521 cs.lpCreateParams = (LPVOID)pContext;
523 if (!PreCreateWindow(cs))
525 PostNcDestroy();
526 return FALSE;
528 // extended style must be zero for MDI Children (except under Win4)
529 ASSERT(cs.hwndParent == pParentWnd->m_hWnd); // must not change
531 // now copy into a MDICREATESTRUCT for real create
532 MDICREATESTRUCT mcs;
533 mcs.szClass = cs.lpszClass;
534 mcs.szTitle = cs.lpszName;
535 mcs.hOwner = cs.hInstance;
536 mcs.x = cs.x;
537 mcs.y = cs.y;
538 mcs.cx = cs.cx;
539 mcs.cy = cs.cy;
540 mcs.style = cs.style & ~(WS_MAXIMIZE | WS_VISIBLE);
541 mcs.lParam = (LPARAM)cs.lpCreateParams;
543 // create the window through the MDICLIENT window
544 AfxHookWindowCreate(this);
545 HWND hWnd = (HWND)::SendMessage(pParentWnd->m_hWndMDIClient,
546 WM_MDICREATE, 0, (LPARAM)&mcs);
547 if (!AfxUnhookWindowCreate())
548 PostNcDestroy(); // cleanup if MDICREATE fails too soon
550 if (hWnd == NULL)
551 return FALSE;
553 // special handling of visibility (always created invisible)
554 if (cs.style & WS_VISIBLE)
556 // place the window on top in z-order before showing it
557 ::BringWindowToTop(hWnd);
559 // show it as specified
560 if (cs.style & WS_MINIMIZE)
561 ShowWindow(SW_SHOWMINIMIZED);
562 else if (cs.style & WS_MAXIMIZE)
563 ShowWindow(SW_SHOWMAXIMIZED);
564 else
565 ShowWindow(SW_SHOWNORMAL);
567 // make sure it is active (visibility == activation)
568 pParentWnd->MDIActivate(this);
570 // refresh MDI Window menu
571 ::SendMessage(pParentWnd->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
574 ASSERT(hWnd == m_hWnd);
575 return TRUE;
578 BOOL CMDIChildWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
579 CWnd* pParentWnd, CCreateContext* pContext)
581 // only do this once
582 ASSERT_VALID_IDR(nIDResource);
583 ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
585 m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)
587 // parent must be MDI Frame (or NULL for default)
588 ASSERT(pParentWnd == NULL || pParentWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)));
589 // will be a child of MDIClient
590 ASSERT(!(dwDefaultStyle & WS_POPUP));
591 dwDefaultStyle |= WS_CHILD;
593 // if available - get MDI child menus from doc template
594 CMultiDocTemplate* pTemplate;
595 if (pContext != NULL &&
596 (pTemplate = (CMultiDocTemplate*)pContext->m_pNewDocTemplate) != NULL)
598 ASSERT_KINDOF(CMultiDocTemplate, pTemplate);
599 // get shared menu from doc template
600 m_hMenuShared = pTemplate->m_hMenuShared;
601 m_hAccelTable = pTemplate->m_hAccelTable;
603 else
605 TRACE(traceAppMsg, 0, "Warning: no shared menu/acceltable for MDI Child window.\n");
606 // if this happens, programmer must load these manually
609 CString strFullString, strTitle;
610 if (strFullString.LoadString(nIDResource))
611 AfxExtractSubString(strTitle, strFullString, 0); // first sub-string
613 ASSERT(m_hWnd == NULL);
614 if (!Create(GetIconWndClass(dwDefaultStyle, nIDResource),
615 strTitle, dwDefaultStyle, rectDefault,
616 (CMDIFrameWnd*)pParentWnd, pContext))
618 return FALSE; // will self destruct on failure normally
621 // it worked !
622 return TRUE;
625 void CMDIChildWnd::OnSize(UINT nType, int cx, int cy)
627 CFrameWnd::OnSize(nType, cx, cy);
629 // update our parent frame - in case we are now maximized or not
630 GetMDIFrame()->OnUpdateFrameTitle(TRUE);
633 BOOL CMDIChildWnd::UpdateClientEdge(LPRECT lpRect)
635 // only adjust for active MDI child window
636 CMDIFrameWnd* pFrameWnd = GetMDIFrame();
637 CMDIChildWnd* pChild = pFrameWnd->MDIGetActive();
639 // Only adjust for regular MDI child windows, not tabbed windows. Attempting to set WS_EX_CLIENTEDGE on the tabbed
640 // MDI client area window is subverted by CMDIClientAreaWnd::OnStyleChanging, so we always try to reset the style and
641 // always repaint, none of which is necessary since the tabbed MDI children never change from maximized to restored.
642 //CMDIChildWndEx* pChildEx = (pChild == NULL) ? NULL : DYNAMIC_DOWNCAST(CMDIChildWndEx, pChild);
643 //BOOL bIsTabbedMDIChild = (pChildEx == NULL) ? FALSE : pChildEx->GetMDIFrameWndEx() != NULL && pChildEx->GetMDIFrameWndEx()->AreMDITabs();
644 if ((pChild == NULL || pChild == this) /*&& !bIsTabbedMDIChild*/)
646 // need to adjust the client edge style as max/restore happens
647 DWORD dwStyle = ::GetWindowLong(pFrameWnd->m_hWndMDIClient, GWL_EXSTYLE);
648 DWORD dwNewStyle = dwStyle;
649 if (pChild != NULL && !(GetExStyle() & WS_EX_CLIENTEDGE) && (GetStyle() & WS_MAXIMIZE))
651 dwNewStyle &= ~(WS_EX_CLIENTEDGE);
653 else
655 dwNewStyle |= WS_EX_CLIENTEDGE;
658 if (dwStyle != dwNewStyle)
660 // SetWindowPos will not move invalid bits
661 ::RedrawWindow(pFrameWnd->m_hWndMDIClient, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
663 // remove/add WS_EX_CLIENTEDGE to MDI client area
664 ::SetWindowLong(pFrameWnd->m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle);
665 ::SetWindowPos(pFrameWnd->m_hWndMDIClient, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS);
667 // return new client area
668 if (lpRect != NULL)
670 ::GetClientRect(pFrameWnd->m_hWndMDIClient, lpRect);
673 return TRUE;
677 return FALSE;
680 void CMDIChildWnd::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
682 if (!(lpWndPos->flags & SWP_NOSIZE))
684 CRect rectClient;
685 if (UpdateClientEdge(rectClient) && (GetStyle() & WS_MAXIMIZE))
687 // adjust maximized window size and position based on new
688 // size/position of the MDI client area.
689 ::AdjustWindowRectEx(rectClient, GetStyle(), FALSE, GetExStyle());
690 lpWndPos->x = rectClient.left;
691 lpWndPos->y = rectClient.top;
692 lpWndPos->cx = rectClient.Width();
693 lpWndPos->cy = rectClient.Height();
697 CFrameWnd::OnWindowPosChanging(lpWndPos);
700 void CMDIChildWnd::OnDestroy()
702 UpdateClientEdge();
704 CFrameWnd::OnDestroy();
707 BOOL CMDIChildWnd::OnNcActivate(BOOL bActive)
709 // bypass CFrameWnd::OnNcActivate()
710 return CWnd::OnNcActivate(bActive);
713 int CMDIChildWnd::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
715 int nResult = CFrameWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
716 if (nResult == MA_NOACTIVATE || nResult == MA_NOACTIVATEANDEAT)
717 return nResult; // frame does not want to activate
719 // activate this window if necessary
720 CMDIFrameWnd* pFrameWnd = GetMDIFrame();
721 ENSURE_VALID(pFrameWnd);
722 CMDIChildWnd* pActive = pFrameWnd->MDIGetActive();
723 if (pActive != this)
724 MDIActivate();
726 return nResult;
729 BOOL CMDIChildWnd::OnToolTipText(UINT msg, NMHDR* pNMHDR, LRESULT* pResult)
731 ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
732 UNUSED(pNMHDR);
734 // check to see if the message is going directly to this window or not
735 const MSG* pMsg = GetCurrentMessage();
736 if (pMsg->hwnd != m_hWnd)
738 // let top level frame handle this for us
739 return FALSE;
742 // otherwise, handle it ourselves
743 return CFrameWnd::OnToolTipText(msg, pNMHDR, pResult);
746 void CMDIChildWnd::ActivateFrame(int nCmdShow)
748 BOOL bVisibleThen = (GetStyle() & WS_VISIBLE) != 0;
749 CMDIFrameWnd* pFrameWnd = GetMDIFrame();
750 ASSERT_VALID(pFrameWnd);
752 // determine default show command
753 if (nCmdShow == -1)
755 // get maximized state of frame window (previously active child)
756 BOOL bMaximized;
757 pFrameWnd->MDIGetActive(&bMaximized);
759 // convert show command based on current style
760 DWORD dwStyle = GetStyle();
761 if (bMaximized || (dwStyle & WS_MAXIMIZE))
762 nCmdShow = SW_SHOWMAXIMIZED;
763 else if (dwStyle & WS_MINIMIZE)
764 nCmdShow = SW_SHOWMINIMIZED;
767 // finally, show the window
768 CFrameWnd::ActivateFrame(nCmdShow);
770 // update the Window menu to reflect new child window
771 CMDIFrameWnd* pFrame = GetMDIFrame();
772 ::SendMessage(pFrame->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
774 // Note: Update the m_bPseudoInactive flag. This is used to handle the
775 // last MDI child getting hidden. Windows provides no way to deactivate
776 // an MDI child window.
778 BOOL bVisibleNow = (GetStyle() & WS_VISIBLE) != 0;
779 if (bVisibleNow == bVisibleThen)
780 return;
782 if (!bVisibleNow)
784 // get current active window according to Windows MDI
785 HWND hWnd = (HWND)::SendMessage(pFrameWnd->m_hWndMDIClient,
786 WM_MDIGETACTIVE, 0, 0);
787 if (hWnd != m_hWnd)
789 // not active any more -- window must have been deactivated
790 ASSERT(!m_bPseudoInactive);
791 return;
794 // check next window
795 ASSERT(hWnd != NULL);
796 pFrameWnd->MDINext();
798 // see if it has been deactivated now...
799 hWnd = (HWND)::SendMessage(pFrameWnd->m_hWndMDIClient,
800 WM_MDIGETACTIVE, 0, 0);
801 if (hWnd == m_hWnd)
803 // still active -- fake deactivate it
804 ASSERT(hWnd != NULL);
805 ::SendMessage(pFrameWnd->m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)m_hWnd, NULL);
806 m_bPseudoInactive = TRUE; // so MDIGetActive returns NULL
809 else if (m_bPseudoInactive)
811 // if state transitioned from not visible to visible, but
812 // was pseudo deactivated -- send activate notify now
813 ::SendMessage(pFrameWnd->m_hWndMDIClient, WM_MDIACTIVATE, NULL, (LPARAM)m_hWnd);
814 ASSERT(!m_bPseudoInactive); // should get set in OnMDIActivate!
818 void CMDIChildWnd::SetHandles(HMENU hMenu, HACCEL hAccel)
820 m_hMenuShared = hMenu;
821 m_hAccelTable = hAccel;
824 /////////////////////////////////////////////////////////////////////////////
825 // CMDIChildWnd Diagnostics
827 #ifdef _DEBUG
828 void CMDIChildWnd::AssertValid() const
830 CFrameWnd::AssertValid();
831 ASSERT(m_hMenuShared == NULL || ::IsMenu(m_hMenuShared));
834 void CMDIChildWnd::Dump(CDumpContext& dc) const
836 CFrameWnd::Dump(dc);
838 dc << "m_hMenuShared = " << (void*)m_hMenuShared;
839 dc << "\n";
841 #endif //_DEBUG
843 /////////////////////////////////////////////////////////////////////////////
844 // Smarts for the "Window" menu
846 HMENU CMDIFrameWnd::GetWindowMenuPopup(HMENU hMenuBar)
847 // find which popup is the "Window" menu
849 if (hMenuBar == NULL)
850 return NULL;
852 ASSERT(::IsMenu(hMenuBar));
854 int iItem = ::GetMenuItemCount(hMenuBar);
855 while (iItem--)
857 HMENU hMenuPop = ::GetSubMenu(hMenuBar, iItem);
858 if (hMenuPop != NULL)
860 int iItemMax = ::GetMenuItemCount(hMenuPop);
861 for (int iItemPop = 0; iItemPop < iItemMax; iItemPop++)
863 UINT nID = GetMenuItemID(hMenuPop, iItemPop);
864 if (nID >= AFX_IDM_WINDOW_FIRST && nID <= AFX_IDM_WINDOW_LAST)
865 return hMenuPop;
870 // no default menu found
871 TRACE(traceAppMsg, 0, "Warning: GetWindowMenuPopup failed!\n");
872 return NULL;
875 /////////////////////////////////////////////////////////////////////////////
876 // Smarts for updating the window menu based on the current child
878 void CMDIFrameWnd::OnUpdateFrameMenu(HMENU hMenuAlt)
880 CMDIChildWnd* pActiveWnd = MDIGetActive();
881 if (pActiveWnd != NULL)
883 // let child update the menu bar
884 pActiveWnd->OnUpdateFrameMenu(TRUE, pActiveWnd, hMenuAlt);
886 else
888 // no child active, so have to update it ourselves
889 // (we can't send it to a child window, since pActiveWnd is NULL)
890 if (hMenuAlt == NULL)
891 hMenuAlt = m_hMenuDefault; // use default
892 ::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuAlt, NULL);
896 /////////////////////////////////////////////////////////////////////////////
897 // MDI Child Extensions
899 // walk up two parents for MDIFrame that owns MDIChild (skip MDIClient)
900 CMDIFrameWnd* CMDIChildWnd::GetMDIFrame()
902 ASSERT_KINDOF(CMDIChildWnd, this);
903 ASSERT(m_hWnd != NULL);
904 HWND hWndMDIClient = ::GetParent(m_hWnd);
905 ASSERT(hWndMDIClient != NULL);
907 CMDIFrameWnd* pMDIFrame;
908 pMDIFrame = (CMDIFrameWnd*)CWnd::FromHandle(::GetParent(hWndMDIClient));
909 ASSERT(pMDIFrame != NULL);
910 ASSERT_KINDOF(CMDIFrameWnd, pMDIFrame);
911 ASSERT(pMDIFrame->m_hWndMDIClient == hWndMDIClient);
912 ASSERT_VALID(pMDIFrame);
913 return pMDIFrame;
916 CWnd* CMDIChildWnd::GetMessageBar()
918 // status bar/message bar owned by parent MDI frame
919 return GetMDIFrame()->GetMessageBar();
922 void CMDIChildWnd::OnUpdateFrameTitle(BOOL bAddToTitle)
924 // update our parent window first
925 GetMDIFrame()->OnUpdateFrameTitle(bAddToTitle);
927 if ((GetStyle() & FWS_ADDTOTITLE) == 0)
928 return; // leave child window alone!
930 CDocument* pDocument = GetActiveDocument();
931 if (bAddToTitle)
933 TCHAR szText[256+_MAX_PATH];
934 if (pDocument == NULL)
935 Checked::tcsncpy_s(szText, _countof(szText), m_strTitle, _TRUNCATE);
936 else
937 Checked::tcsncpy_s(szText, _countof(szText), pDocument->GetTitle(), _TRUNCATE);
938 if (m_nWindow > 0)
940 TCHAR szWinNumber[16+1];
941 _stprintf_s(szWinNumber, _countof(szWinNumber), _T(":%d"), m_nWindow);
943 if( lstrlen(szText) + lstrlen(szWinNumber) < _countof(szText) )
945 Checked::tcscat_s( szText, _countof(szText), szWinNumber );
949 // set title if changed, but don't remove completely
950 AfxSetWindowText(m_hWnd, szText);
954 void CMDIChildWnd::OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd*)
956 m_bPseudoInactive = FALSE; // must be happening for real
958 // make sure MDI client window has correct client edge
959 UpdateClientEdge();
961 // send deactivate notification to active view
962 CView* pActiveView = GetActiveView();
963 if (!bActivate && pActiveView != NULL)
964 pActiveView->OnActivateView(FALSE, pActiveView, pActiveView);
966 // allow hook to short circuit normal activation
967 BOOL bHooked = FALSE;
968 #ifndef _AFX_NO_OLE_SUPPORT
969 if (m_pNotifyHook != NULL && m_pNotifyHook->OnDocActivate(bActivate))
970 bHooked = TRUE;
971 #endif
973 // update titles (don't AddToTitle if deactivate last)
974 if (!bHooked)
975 OnUpdateFrameTitle(bActivate || (pActivateWnd != NULL));
977 // re-activate the appropriate view
978 if (bActivate)
980 if (pActiveView != NULL && GetMDIFrame() == GetActiveWindow())
981 pActiveView->OnActivateView(TRUE, pActiveView, pActiveView);
984 // update menus
985 if (!bHooked)
987 OnUpdateFrameMenu(bActivate, pActivateWnd, NULL);
988 GetMDIFrame()->DrawMenuBar();
992 void CMDIChildWnd::OnUpdateFrameMenu(BOOL bActivate, CWnd* pActivateWnd,
993 HMENU hMenuAlt)
995 CMDIFrameWnd* pFrame = GetMDIFrame();
997 if (hMenuAlt == NULL && bActivate)
999 // attempt to get default menu from document
1000 CDocument* pDoc = GetActiveDocument();
1001 if (pDoc != NULL)
1002 hMenuAlt = pDoc->GetDefaultMenu();
1005 // use default menu stored in frame if none from document
1006 if (hMenuAlt == NULL)
1007 hMenuAlt = m_hMenuShared;
1009 if (hMenuAlt != NULL && bActivate)
1011 ASSERT(pActivateWnd == this);
1013 // activating child, set parent menu
1014 ::SendMessage(pFrame->m_hWndMDIClient, WM_MDISETMENU,
1015 (WPARAM)hMenuAlt, (LPARAM)pFrame->GetWindowMenuPopup(hMenuAlt));
1017 else if (hMenuAlt != NULL && !bActivate && pActivateWnd == NULL)
1019 // destroying last child
1020 HMENU hMenuLast = NULL;
1021 ::SendMessage(pFrame->m_hWndMDIClient, WM_MDISETMENU,
1022 (WPARAM)pFrame->m_hMenuDefault, (LPARAM)hMenuLast);
1024 else
1026 // refresh MDI Window menu (even if non-shared menu)
1027 ::SendMessage(pFrame->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
1031 BOOL CMDIChildWnd::OnNcCreate(LPCREATESTRUCT lpCreateStruct)
1033 if (!CFrameWnd::OnNcCreate(lpCreateStruct))
1034 return FALSE;
1036 // handle extended styles under Win4
1037 // call PreCreateWindow again just to get dwExStyle
1038 VERIFY(PreCreateWindow(*lpCreateStruct));
1039 SetWindowLong(m_hWnd, GWL_EXSTYLE, lpCreateStruct->dwExStyle);
1041 return TRUE;
1044 int CMDIChildWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
1046 // call base class with lParam context (not MDI one)
1047 MDICREATESTRUCT* lpmcs;
1048 lpmcs = (MDICREATESTRUCT*)lpCreateStruct->lpCreateParams;
1049 CCreateContext* pContext = (CCreateContext*)lpmcs->lParam;
1051 return OnCreateHelper(lpCreateStruct, pContext);
1054 /////////////////////////////////////////////////////////////////////////////
1055 // Special UI processing depending on current active child
1057 void CMDIFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle)
1059 if ((GetStyle() & FWS_ADDTOTITLE) == 0)
1060 return; // leave it alone!
1062 #ifndef _AFX_NO_OLE_SUPPORT
1063 // allow hook to set the title (used for OLE support)
1064 if (m_pNotifyHook != NULL && m_pNotifyHook->OnUpdateFrameTitle())
1065 return;
1066 #endif
1068 CMDIChildWnd* pActiveChild = NULL;
1069 CDocument* pDocument = GetActiveDocument();
1070 if (bAddToTitle &&
1071 (pActiveChild = MDIGetActive()) != NULL &&
1072 (pActiveChild->GetStyle() & WS_MAXIMIZE) == 0 &&
1073 (pDocument != NULL ||
1074 (pDocument = pActiveChild->GetActiveDocument()) != NULL))
1075 UpdateFrameTitleForDocument(pDocument->GetTitle());
1076 else
1078 LPCTSTR lpstrTitle = NULL;
1079 CString strTitle;
1081 if (pActiveChild != NULL &&
1082 (pActiveChild->GetStyle() & WS_MAXIMIZE) == 0)
1084 strTitle = pActiveChild->GetTitle();
1085 if (!strTitle.IsEmpty())
1086 lpstrTitle = strTitle;
1088 UpdateFrameTitleForDocument(lpstrTitle);
1092 /////////////////////////////////////////////////////////////////////////////
1093 // Standard MDI Commands
1095 // Two function for all standard MDI "Window" commands
1096 void CMDIFrameWnd::OnUpdateMDIWindowCmd(CCmdUI* pCmdUI)
1098 ASSERT(m_hWndMDIClient != NULL);
1099 pCmdUI->Enable(MDIGetActive() != NULL);
1102 BOOL CMDIFrameWnd::OnMDIWindowCmd(UINT nID)
1104 ASSERT(m_hWndMDIClient != NULL);
1106 UINT msg;
1107 UINT wParam = 0;
1108 switch (nID)
1110 default:
1111 return FALSE; // not for us
1112 case ID_WINDOW_ARRANGE:
1113 msg = WM_MDIICONARRANGE;
1114 break;
1115 case ID_WINDOW_CASCADE:
1116 msg = WM_MDICASCADE;
1117 break;
1118 case ID_WINDOW_TILE_HORZ:
1119 wParam = MDITILE_HORIZONTAL;
1120 // fall through
1121 case ID_WINDOW_TILE_VERT:
1122 ASSERT(MDITILE_VERTICAL == 0);
1123 msg = WM_MDITILE;
1124 break;
1127 ::SendMessage(m_hWndMDIClient, msg, wParam, 0);
1128 return TRUE;
1131 void CMDIFrameWnd::OnWindowNew()
1133 CMDIChildWnd* pActiveChild = MDIGetActive();
1134 CDocument* pDocument;
1135 if (pActiveChild == NULL ||
1136 (pDocument = pActiveChild->GetActiveDocument()) == NULL)
1138 TRACE(traceAppMsg, 0, "Warning: No active document for WindowNew command.\n");
1139 AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
1140 return; // command failed
1143 // otherwise we have a new frame !
1144 CDocTemplate* pTemplate = pDocument->GetDocTemplate();
1145 ASSERT_VALID(pTemplate);
1146 CFrameWnd* pFrame = pTemplate->CreateNewFrame(pDocument, pActiveChild);
1147 if (pFrame == NULL)
1149 TRACE(traceAppMsg, 0, "Warning: failed to create new frame.\n");
1150 return; // command failed
1153 pTemplate->InitialUpdateFrame(pFrame, pDocument);
1156 void CMDIFrameWnd::SetMenuBarVisibility(DWORD dwStyle)
1158 ENSURE_ARG(dwStyle == AFX_MBV_KEEPVISIBLE);
1159 ASSERT(m_dwMenuBarVisibility == AFX_MBV_KEEPVISIBLE);
1162 BOOL CMDIFrameWnd::SetMenuBarState(DWORD dwState)
1164 return m_dwMenuBarState == AFX_MBS_HIDDEN ? FALSE : CFrameWnd::SetMenuBarState(dwState);
1167 IMPLEMENT_DYNCREATE(CMDIFrameWnd, CFrameWnd)
1168 IMPLEMENT_DYNCREATE(CMDIChildWnd, CFrameWnd)
1170 ////////////////////////////////////////////////////////////////////////////