mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2270 lines
59 KiB
2270 lines
59 KiB
// This is a part of the Microsoft Foundation Classes C++ library.
|
|
// Copyright (C) 1992-1995 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Foundation Classes Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Microsoft Foundation Classes product.
|
|
|
|
#include "stdafx.h"
|
|
#include <dde.h> // for DDE execute shell requests
|
|
|
|
#ifdef AFX_CORE4_SEG
|
|
#pragma code_seg(AFX_CORE4_SEG)
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRect for creating windows with the default position/size
|
|
|
|
const AFX_DATADEF CRect CFrameWnd::rectDefault(
|
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
|
0 /* 2*CW_USEDEFAULT */, 0 /* 2*CW_USEDEFAULT */);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd
|
|
|
|
BEGIN_MESSAGE_MAP(CFrameWnd, CWnd)
|
|
//{{AFX_MSG_MAP(CFrameWnd)
|
|
ON_WM_INITMENUPOPUP()
|
|
ON_WM_MENUSELECT()
|
|
ON_MESSAGE(WM_POPMESSAGESTRING, OnPopMessageString)
|
|
ON_MESSAGE(WM_SETMESSAGESTRING, OnSetMessageString)
|
|
ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
|
|
ON_WM_ENTERIDLE()
|
|
ON_WM_HSCROLL()
|
|
ON_WM_VSCROLL()
|
|
ON_WM_SETFOCUS()
|
|
ON_WM_CREATE()
|
|
ON_WM_DESTROY()
|
|
ON_WM_CLOSE()
|
|
ON_WM_SIZE()
|
|
ON_WM_ERASEBKGND()
|
|
ON_WM_ACTIVATE()
|
|
ON_WM_NCACTIVATE()
|
|
ON_WM_SYSCOMMAND()
|
|
ON_WM_DROPFILES()
|
|
ON_WM_QUERYENDSESSION()
|
|
ON_WM_ENDSESSION()
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_ENABLE()
|
|
// OLE palette support
|
|
ON_WM_QUERYNEWPALETTE()
|
|
ON_WM_PALETTECHANGED()
|
|
ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
|
|
ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
|
|
ON_MESSAGE(WM_ACTIVATETOPLEVEL, OnActivateTopLevel)
|
|
// turning on and off standard frame gadgetry
|
|
ON_UPDATE_COMMAND_UI(ID_VIEW_STATUS_BAR, OnUpdateControlBarMenu)
|
|
ON_COMMAND_EX(ID_VIEW_STATUS_BAR, OnBarCheck)
|
|
ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR, OnUpdateControlBarMenu)
|
|
ON_COMMAND_EX(ID_VIEW_TOOLBAR, OnBarCheck)
|
|
// turning on and off standard mode indicators
|
|
ON_UPDATE_COMMAND_UI(ID_INDICATOR_CAPS, OnUpdateKeyIndicator)
|
|
ON_UPDATE_COMMAND_UI(ID_INDICATOR_NUM, OnUpdateKeyIndicator)
|
|
ON_UPDATE_COMMAND_UI(ID_INDICATOR_SCRL, OnUpdateKeyIndicator)
|
|
ON_UPDATE_COMMAND_UI(ID_INDICATOR_KANA, OnUpdateKeyIndicator)
|
|
// standard help handling
|
|
ON_UPDATE_COMMAND_UI(ID_CONTEXT_HELP, OnUpdateContextHelp)
|
|
// toolbar "tooltip" notification
|
|
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
|
|
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
|
|
//}}AFX_MSG_MAP
|
|
#ifndef _MAC
|
|
// message handling for standard DDE commands
|
|
ON_MESSAGE(WM_DDE_INITIATE, OnDDEInitiate)
|
|
ON_MESSAGE(WM_DDE_EXECUTE, OnDDEExecute)
|
|
ON_MESSAGE(WM_DDE_TERMINATE, OnDDETerminate)
|
|
#else
|
|
// special handling of app activation
|
|
ON_WM_ACTIVATEAPP()
|
|
// special handling for uncovered areas of the client area caused by
|
|
// Macintosh sizebox
|
|
ON_WM_PAINT()
|
|
#endif
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd construction/destruction
|
|
|
|
CFrameWnd::CFrameWnd()
|
|
{
|
|
ASSERT(m_hWnd == NULL);
|
|
|
|
m_nWindow = -1; // unknown window ID
|
|
m_bAutoMenuEnable = TRUE; // auto enable on by default
|
|
m_lpfnCloseProc = NULL;
|
|
m_hMenuDefault = NULL;
|
|
m_hAccelTable = NULL;
|
|
m_nIDHelp = 0;
|
|
m_nIDTracking = 0;
|
|
m_nIDLastMessage = 0;
|
|
m_pViewActive = NULL;
|
|
|
|
m_cModalStack = 0; // initialize modality support
|
|
m_phWndDisable = NULL;
|
|
m_pNotifyHook = NULL;
|
|
m_hMenuAlt = NULL;
|
|
m_nIdleFlags = 0; // no idle work at start
|
|
m_rectBorder.SetRectEmpty();
|
|
|
|
m_bHelpMode = HELP_INACTIVE; // not in Shift+F1 help mode
|
|
m_dwPromptContext = 0;
|
|
|
|
m_pNextFrameWnd = NULL; // not in list yet
|
|
|
|
m_bInRecalcLayout = FALSE;
|
|
m_pFloatingFrameClass = NULL;
|
|
m_nShowDelay = -1; // no delay pending
|
|
|
|
AddFrameWnd();
|
|
}
|
|
|
|
CFrameWnd::~CFrameWnd()
|
|
{
|
|
RemoveFrameWnd();
|
|
}
|
|
|
|
void CFrameWnd::AddFrameWnd()
|
|
{
|
|
// hook it into the CFrameWnd list
|
|
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
|
|
pState->m_frameList.AddHead(this);
|
|
}
|
|
|
|
void CFrameWnd::RemoveFrameWnd()
|
|
{
|
|
// remove this frame window from the list of frame windows
|
|
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
|
|
pState->m_frameList.Remove(this);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Special processing etc
|
|
|
|
BOOL CFrameWnd::LoadAccelTable(LPCTSTR lpszResourceName)
|
|
{
|
|
ASSERT(m_hAccelTable == NULL); // only do once
|
|
ASSERT(lpszResourceName != NULL);
|
|
|
|
HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_ACCELERATOR);
|
|
m_hAccelTable = ::LoadAccelerators(hInst, lpszResourceName);
|
|
return (m_hAccelTable != NULL);
|
|
}
|
|
|
|
HACCEL CFrameWnd::GetDefaultAccelerator()
|
|
{
|
|
// use document specific accelerator table over m_hAccelTable
|
|
HACCEL hAccelTable = m_hAccelTable;
|
|
HACCEL hAccel;
|
|
CDocument* pDoc = GetActiveDocument();
|
|
if (pDoc != NULL && (hAccel = pDoc->GetDefaultAccelerator()) != NULL)
|
|
hAccelTable = hAccel;
|
|
|
|
return hAccelTable;
|
|
}
|
|
|
|
BOOL CFrameWnd::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
// check for special cancel modes for combo boxes
|
|
if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN)
|
|
AfxCancelModes(pMsg->hwnd); // filter clicks
|
|
|
|
// allow tooltip messages to be filtered
|
|
if (CWnd::PreTranslateMessage(pMsg))
|
|
return TRUE;
|
|
|
|
#ifndef _AFX_NO_OLE_SUPPORT
|
|
// allow hook to consume message
|
|
if (m_pNotifyHook != NULL && m_pNotifyHook->OnPreTranslateMessage(pMsg))
|
|
return TRUE;
|
|
#endif
|
|
|
|
if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
|
|
{
|
|
// finally, translate the message
|
|
HACCEL hAccel = GetDefaultAccelerator();
|
|
return hAccel != NULL && ::TranslateAccelerator(m_hWnd, hAccel, pMsg);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void CFrameWnd::PostNcDestroy()
|
|
{
|
|
// default for frame windows is to allocate them on the heap
|
|
// the default post-cleanup is to 'delete this'.
|
|
// never explicitly call 'delete' on a CFrameWnd, use DestroyWindow instead
|
|
delete this;
|
|
}
|
|
|
|
void CFrameWnd::OnPaletteChanged(CWnd* pFocusWnd)
|
|
{
|
|
CWnd::OnPaletteChanged(pFocusWnd);
|
|
#ifndef _AFX_NO_OLE_SUPPORT
|
|
if (m_pNotifyHook != NULL)
|
|
m_pNotifyHook->OnPaletteChanged(pFocusWnd);
|
|
#endif
|
|
}
|
|
|
|
BOOL CFrameWnd::OnQueryNewPalette()
|
|
{
|
|
#ifndef _AFX_NO_OLE_SUPPORT
|
|
if (m_pNotifyHook != NULL && m_pNotifyHook->OnQueryNewPalette())
|
|
return TRUE;
|
|
#endif
|
|
return CWnd::OnQueryNewPalette();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd support for context sensitive help.
|
|
|
|
void CFrameWnd::ExitHelpMode()
|
|
{
|
|
// if not in help mode currently, this is a no-op
|
|
if (!m_bHelpMode)
|
|
return;
|
|
|
|
// only post new WM_EXITHELPMODE message if one doesn't already exist
|
|
// in the queue.
|
|
MSG msg;
|
|
if (!::PeekMessage(&msg, m_hWnd, WM_EXITHELPMODE, WM_EXITHELPMODE,
|
|
PM_REMOVE|PM_NOYIELD))
|
|
{
|
|
VERIFY(::PostMessage(m_hWnd, WM_EXITHELPMODE, 0, 0));
|
|
}
|
|
|
|
// release capture if this window has it
|
|
if (::GetCapture() == m_hWnd)
|
|
ReleaseCapture();
|
|
|
|
CFrameWnd* pFrameWnd = GetTopLevelFrame();
|
|
ASSERT_VALID(pFrameWnd);
|
|
pFrameWnd->m_bHelpMode = m_bHelpMode = HELP_INACTIVE;
|
|
PostMessage(WM_KICKIDLE); // trigger idle update
|
|
}
|
|
|
|
BOOL CFrameWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
CFrameWnd* pFrameWnd = GetTopLevelFrame();
|
|
ASSERT_VALID(pFrameWnd);
|
|
if (pFrameWnd->m_bHelpMode)
|
|
{
|
|
SetCursor(afxData.hcurHelp);
|
|
return TRUE;
|
|
}
|
|
return CWnd::OnSetCursor(pWnd, nHitTest, message);
|
|
}
|
|
|
|
LRESULT CFrameWnd::OnCommandHelp(WPARAM, LPARAM lParam)
|
|
{
|
|
if (lParam == 0)
|
|
{
|
|
if (IsTracking())
|
|
lParam = HID_BASE_COMMAND+m_nIDTracking;
|
|
else
|
|
lParam = HID_BASE_RESOURCE+m_nIDHelp;
|
|
}
|
|
if (lParam != 0)
|
|
{
|
|
AfxGetApp()->WinHelp(lParam);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT CFrameWnd::OnHelpHitTest(WPARAM, LPARAM)
|
|
{
|
|
if (m_nIDHelp != 0)
|
|
return HID_BASE_RESOURCE+m_nIDHelp;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
|
|
// return TRUE if command invocation was attempted
|
|
{
|
|
HWND hWndCtrl = (HWND)lParam;
|
|
UINT nID = LOWORD(wParam);
|
|
|
|
CFrameWnd* pFrameWnd = GetTopLevelFrame();
|
|
ASSERT_VALID(pFrameWnd);
|
|
if (pFrameWnd->m_bHelpMode && hWndCtrl == NULL &&
|
|
nID != ID_HELP && nID != ID_DEFAULT_HELP && nID != ID_CONTEXT_HELP)
|
|
{
|
|
// route as help
|
|
if (!SendMessage(WM_COMMANDHELP, 0, HID_BASE_COMMAND+nID))
|
|
SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
|
|
return TRUE;
|
|
}
|
|
|
|
// route as normal command
|
|
return CWnd::OnCommand(wParam, lParam);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd support for modality
|
|
|
|
BOOL AFXAPI AfxIsDescendant(HWND hWndParent, HWND hWndChild)
|
|
// helper for detecting whether child descendent of parent
|
|
// (works with owned popups as well)
|
|
{
|
|
ASSERT(::IsWindow(hWndParent));
|
|
ASSERT(::IsWindow(hWndChild));
|
|
|
|
do
|
|
{
|
|
if (hWndParent == hWndChild)
|
|
return TRUE;
|
|
|
|
hWndChild = AfxGetParentOwner(hWndChild);
|
|
} while (hWndChild != NULL);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void CFrameWnd::BeginModalState()
|
|
{
|
|
ASSERT(m_hWnd != NULL);
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
// allow stacking, but don't do anything
|
|
if (++m_cModalStack > 1)
|
|
return;
|
|
|
|
// determine top-level parent, since that is the true parent of any
|
|
// modeless windows anyway...
|
|
CWnd* pParent = GetTopLevelParent();
|
|
|
|
// first count all windows that need to be disabled
|
|
UINT nCount = 0;
|
|
HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
|
|
while (hWnd != NULL)
|
|
{
|
|
if (::IsWindowEnabled(hWnd) &&
|
|
CWnd::FromHandlePermanent(hWnd) != NULL &&
|
|
AfxIsDescendant(pParent->m_hWnd, hWnd) &&
|
|
::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0)
|
|
{
|
|
++nCount;
|
|
}
|
|
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
|
|
}
|
|
if (nCount == 0)
|
|
return;
|
|
|
|
m_phWndDisable = new HWND[nCount+1];
|
|
|
|
// disable all windows connected to this frame (and add them to the list)
|
|
UINT nIndex = 0;
|
|
hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
|
|
while (hWnd != NULL)
|
|
{
|
|
if (::IsWindowEnabled(hWnd) &&
|
|
CWnd::FromHandlePermanent(hWnd) != NULL &&
|
|
AfxIsDescendant(pParent->m_hWnd, hWnd) &&
|
|
::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0)
|
|
{
|
|
::EnableWindow(hWnd, FALSE);
|
|
ASSERT(nIndex < nCount);
|
|
m_phWndDisable[nIndex] = hWnd;
|
|
++nIndex;
|
|
}
|
|
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
|
|
}
|
|
|
|
// terminate the list with a NULL
|
|
ASSERT(nIndex < nCount+1);
|
|
m_phWndDisable[nIndex] = NULL;
|
|
}
|
|
|
|
void CFrameWnd::EndModalState()
|
|
{
|
|
// pop one off the stack (don't undo modalness unless stack is down to zero)
|
|
if (m_cModalStack == 0 || --m_cModalStack > 0 || m_phWndDisable == NULL)
|
|
return;
|
|
|
|
// enable all the windows disabled by BeginModalState
|
|
ASSERT(m_phWndDisable != NULL);
|
|
UINT nIndex = 0;
|
|
while (m_phWndDisable[nIndex] != NULL)
|
|
{
|
|
ASSERT(m_phWndDisable[nIndex] != NULL);
|
|
if (::IsWindow(m_phWndDisable[nIndex]))
|
|
::EnableWindow(m_phWndDisable[nIndex], TRUE);
|
|
++nIndex;
|
|
}
|
|
delete[] (void*)m_phWndDisable;
|
|
m_phWndDisable = NULL;
|
|
}
|
|
|
|
void CFrameWnd::ShowOwnedWindows(BOOL bShow)
|
|
{
|
|
// walk through all top-level windows
|
|
HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
|
|
while (hWnd != NULL)
|
|
{
|
|
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
|
|
if (pWnd != NULL && m_hWnd != hWnd && AfxIsDescendant(m_hWnd, hWnd))
|
|
{
|
|
DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE);
|
|
if (!bShow && (dwStyle & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE)
|
|
{
|
|
::ShowWindow(hWnd, SW_HIDE);
|
|
pWnd->m_nFlags |= WF_TEMPHIDE;
|
|
}
|
|
else if (bShow && (dwStyle & (WS_VISIBLE|WS_DISABLED)) == 0 &&
|
|
(pWnd->m_nFlags & WF_TEMPHIDE))
|
|
{
|
|
::ShowWindow(hWnd, SW_SHOWNOACTIVATE);
|
|
pWnd->m_nFlags &= ~WF_TEMPHIDE;
|
|
}
|
|
}
|
|
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
|
|
}
|
|
}
|
|
|
|
void CFrameWnd::OnEnable(BOOL bEnable)
|
|
{
|
|
if (bEnable && (m_nFlags & WF_STAYDISABLED))
|
|
{
|
|
// Work around for MAPI support. This makes sure the main window
|
|
// remains disabled even when the mail system is booting.
|
|
EnableWindow(FALSE);
|
|
::SetFocus(NULL);
|
|
return;
|
|
}
|
|
|
|
// only for top-level (and non-owned) windows
|
|
if (GetParent() != NULL)
|
|
return;
|
|
|
|
// this causes modal dialogs to be "truly modal"
|
|
if (!bEnable && !InModalState())
|
|
{
|
|
ASSERT((m_nFlags & WF_MODALDISABLE) == 0);
|
|
m_nFlags |= WF_MODALDISABLE;
|
|
BeginModalState();
|
|
}
|
|
else if (bEnable && (m_nFlags & WF_MODALDISABLE))
|
|
{
|
|
m_nFlags &= ~WF_MODALDISABLE;
|
|
EndModalState();
|
|
|
|
// cause normal focus logic to kick in
|
|
if (::GetActiveWindow() == m_hWnd)
|
|
SendMessage(WM_ACTIVATE, WA_ACTIVE);
|
|
}
|
|
|
|
// force WM_NCACTIVATE because Windows may think it is unecessary
|
|
if (bEnable && (m_nFlags & WF_STAYACTIVE))
|
|
SendMessage(WM_NCACTIVATE, TRUE);
|
|
// force WM_NCACTIVATE for floating windows too
|
|
NotifyFloatingWindows(bEnable ? FS_ENABLE : FS_DISABLE);
|
|
}
|
|
|
|
void CFrameWnd::NotifyFloatingWindows(DWORD dwFlags)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(m_hWnd != NULL);
|
|
|
|
// get top level parent frame window first unless this is a child window
|
|
CFrameWnd* pParent = (GetStyle() & WS_CHILD) ? this : GetTopLevelFrame();
|
|
ASSERT(pParent != NULL);
|
|
if (dwFlags & (FS_DEACTIVATE|FS_ACTIVATE))
|
|
{
|
|
// update parent window activation state
|
|
BOOL bActivate = !(dwFlags & FS_DEACTIVATE);
|
|
BOOL bEnabled = pParent->IsWindowEnabled();
|
|
|
|
if (bActivate && bEnabled && pParent != this)
|
|
{
|
|
// Excel will try to Activate itself when it receives a
|
|
// WM_NCACTIVATE so we need to keep it from doing that here.
|
|
m_nFlags |= WF_KEEPMINIACTIVE;
|
|
pParent->SendMessage(WM_NCACTIVATE, TRUE);
|
|
m_nFlags &= ~WF_KEEPMINIACTIVE;
|
|
}
|
|
else
|
|
{
|
|
pParent->SendMessage(WM_NCACTIVATE, FALSE);
|
|
}
|
|
}
|
|
|
|
// then update the state of all floating windows owned by the parent
|
|
HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
|
|
while (hWnd != NULL)
|
|
{
|
|
if (AfxIsDescendant(pParent->m_hWnd, hWnd))
|
|
::SendMessage(hWnd, WM_FLOATSTATUS, dwFlags, 0);
|
|
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd second phase creation
|
|
|
|
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
|
|
{
|
|
if (cs.lpszClass == NULL)
|
|
{
|
|
if (!AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG))
|
|
return FALSE;
|
|
|
|
cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background
|
|
}
|
|
|
|
if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)
|
|
cs.style |= FWS_PREFIXTITLE;
|
|
|
|
if (afxData.bWin4)
|
|
cs.dwExStyle |= WS_EX_CLIENTEDGE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
|
|
LPCTSTR lpszWindowName,
|
|
DWORD dwStyle,
|
|
const RECT& rect,
|
|
CWnd* pParentWnd,
|
|
LPCTSTR lpszMenuName,
|
|
DWORD dwExStyle,
|
|
CCreateContext* pContext)
|
|
{
|
|
HMENU hMenu = NULL;
|
|
if (lpszMenuName != NULL)
|
|
{
|
|
// load in a menu that will get destroyed when window gets destroyed
|
|
HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);
|
|
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
|
|
{
|
|
TRACE0("Warning: failed to load menu for CFrameWnd.\n");
|
|
PostNcDestroy(); // perhaps delete the C++ object
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
m_strTitle = lpszWindowName; // save title for later
|
|
|
|
#ifdef _MAC
|
|
dwExStyle |= WS_EX_FORCESIZEBOX;
|
|
#endif
|
|
|
|
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
|
|
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
|
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
|
|
{
|
|
TRACE0("Warning: failed to create CFrameWnd.\n");
|
|
if (hMenu != NULL)
|
|
DestroyMenu(hMenu);
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef _MAC
|
|
CMenu* pMenu = GetSystemMenu(FALSE);
|
|
if (pMenu != NULL)
|
|
{
|
|
CString strAbout;
|
|
TCHAR szFormat[256];
|
|
LPCTSTR pszAppName = AfxGetAppName();
|
|
|
|
// a statically linked dialog-based app might not have included afxres.rc
|
|
if (!AfxLoadString(AFX_IDS_ABOUT, szFormat))
|
|
_tcscpy(szFormat, _T("About %1..."));
|
|
|
|
AfxFormatStrings(strAbout, szFormat, &pszAppName, 1);
|
|
pMenu->ModifyMenu(0, MF_BYPOSITION | MF_STRING, ID_APP_ABOUT, strAbout);
|
|
}
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)
|
|
{
|
|
ASSERT(m_hWnd != NULL);
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
ASSERT(pContext != NULL);
|
|
ASSERT(pContext->m_pNewViewClass != NULL);
|
|
|
|
// Note: can be a CWnd with PostNcDestroy self cleanup
|
|
CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();
|
|
if (pView == NULL)
|
|
{
|
|
TRACE1("Warning: Dynamic create of view type %hs failed.\n",
|
|
pContext->m_pNewViewClass->m_lpszClassName);
|
|
return NULL;
|
|
}
|
|
ASSERT_KINDOF(CWnd, pView);
|
|
|
|
// views are always created with a border!
|
|
if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
|
|
CRect(0,0,0,0), this, nID, pContext))
|
|
{
|
|
TRACE0("Warning: could not create view for frame.\n");
|
|
return NULL; // can't continue without a view
|
|
}
|
|
|
|
if (afxData.bWin4 && (pView->GetExStyle() & WS_EX_CLIENTEDGE))
|
|
{
|
|
// remove the 3d style from the frame, since the view is
|
|
// providing it.
|
|
// make sure to recalc the non-client area
|
|
ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
|
|
}
|
|
return pView;
|
|
}
|
|
|
|
BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext)
|
|
{
|
|
// default create client will create a view if asked for it
|
|
if (pContext != NULL && pContext->m_pNewViewClass != NULL)
|
|
{
|
|
if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs)
|
|
{
|
|
CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;
|
|
return OnCreateHelper(lpcs, pContext);
|
|
}
|
|
|
|
int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext)
|
|
{
|
|
if (CWnd::OnCreate(lpcs) == -1)
|
|
return -1;
|
|
|
|
// create special children first
|
|
if (!OnCreateClient(lpcs, pContext))
|
|
{
|
|
TRACE0("Failed to create client pane/view for frame.\n");
|
|
return -1;
|
|
}
|
|
|
|
// post message for initial message string
|
|
PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
|
|
|
|
// make sure the child windows have been properly sized
|
|
RecalcLayout();
|
|
|
|
return 0; // create ok
|
|
}
|
|
|
|
LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource)
|
|
{
|
|
ASSERT_VALID_IDR(nIDResource);
|
|
HINSTANCE hInst = AfxFindResourceHandle(
|
|
MAKEINTRESOURCE(nIDResource), RT_GROUP_ICON);
|
|
HICON hIcon = ::LoadIcon(hInst, MAKEINTRESOURCE(nIDResource));
|
|
if (hIcon != NULL)
|
|
{
|
|
CREATESTRUCT cs;
|
|
memset(&cs, 0, sizeof(CREATESTRUCT));
|
|
cs.style = dwDefaultStyle;
|
|
PreCreateWindow(cs);
|
|
// will fill lpszClassName with default WNDCLASS name
|
|
// ignore instance handle from PreCreateWindow.
|
|
|
|
WNDCLASS wndcls;
|
|
if (cs.lpszClass != NULL &&
|
|
GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls) &&
|
|
wndcls.hIcon != hIcon)
|
|
{
|
|
// register a very similar WNDCLASS
|
|
return AfxRegisterWndClass(wndcls.style,
|
|
wndcls.hCursor, wndcls.hbrBackground, hIcon);
|
|
}
|
|
}
|
|
return NULL; // just use the default
|
|
}
|
|
|
|
BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
|
|
CWnd* pParentWnd, CCreateContext* pContext)
|
|
{
|
|
// only do this once
|
|
ASSERT_VALID_IDR(nIDResource);
|
|
ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
|
|
|
|
m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)
|
|
|
|
CString strFullString;
|
|
if (strFullString.LoadString(nIDResource))
|
|
AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string
|
|
|
|
if (!AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG))
|
|
return FALSE;
|
|
|
|
// attempt to create the window
|
|
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
|
|
LPCTSTR lpszTitle = m_strTitle;
|
|
if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault,
|
|
pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))
|
|
{
|
|
return FALSE; // will self destruct on failure normally
|
|
}
|
|
|
|
// save the default menu handle
|
|
ASSERT(m_hWnd != NULL);
|
|
m_hMenuDefault = ::GetMenu(m_hWnd);
|
|
|
|
// load accelerator resource
|
|
LoadAccelTable(MAKEINTRESOURCE(nIDResource));
|
|
|
|
if (pContext == NULL) // send initial update
|
|
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CFrameWnd::OnUpdateFrameMenu(HMENU hMenuAlt)
|
|
{
|
|
if (hMenuAlt == NULL)
|
|
{
|
|
// attempt to get default menu from document
|
|
CDocument* pDoc = GetActiveDocument();
|
|
if (pDoc != NULL)
|
|
hMenuAlt = pDoc->GetDefaultMenu();
|
|
// use default menu stored in frame if none from document
|
|
if (hMenuAlt == NULL)
|
|
hMenuAlt = m_hMenuDefault;
|
|
}
|
|
// finally, set the menu
|
|
::SetMenu(m_hWnd, hMenuAlt);
|
|
}
|
|
|
|
void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)
|
|
{
|
|
// if the frame does not have an active view, set to first pane
|
|
CView* pView = NULL;
|
|
if (GetActiveView() == NULL)
|
|
{
|
|
CWnd* pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE);
|
|
if (pWnd != NULL && pWnd->IsKindOf(RUNTIME_CLASS(CView)))
|
|
{
|
|
pView = (CView*)pWnd;
|
|
SetActiveView(pView, FALSE);
|
|
}
|
|
}
|
|
|
|
if (bMakeVisible)
|
|
{
|
|
// send initial update to all views (and other controls) in the frame
|
|
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
|
|
|
|
// give view a chance to save the focus (CFormView needs this)
|
|
if (pView != NULL)
|
|
pView->OnActivateFrame(WA_INACTIVE, this);
|
|
|
|
// finally, activate the frame
|
|
// (send the default show command unless the main desktop window)
|
|
int nCmdShow = -1; // default
|
|
CWinApp* pApp = AfxGetApp();
|
|
if (this == pApp->m_pMainWnd)
|
|
{
|
|
nCmdShow = pApp->m_nCmdShow; // use the parameter from WinMain
|
|
pApp->m_nCmdShow = -1; // set to default after first time
|
|
}
|
|
ActivateFrame(nCmdShow);
|
|
if (pView != NULL)
|
|
pView->OnActivateView(TRUE, pView, pView);
|
|
}
|
|
|
|
// update frame counts and frame title (may already have been visible)
|
|
if (pDoc != NULL)
|
|
pDoc->UpdateFrameCounts();
|
|
OnUpdateFrameTitle(TRUE);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd closing down
|
|
|
|
void CFrameWnd::OnClose()
|
|
{
|
|
if (m_lpfnCloseProc != NULL && !(*m_lpfnCloseProc)(this))
|
|
return;
|
|
|
|
// Note: only queries the active document
|
|
CDocument* pDocument = GetActiveDocument();
|
|
if (pDocument != NULL && !pDocument->CanCloseFrame(this))
|
|
{
|
|
// document can't close right now -- don't close it
|
|
return;
|
|
}
|
|
CWinApp* pApp = AfxGetApp();
|
|
if (pApp->m_pMainWnd == this)
|
|
{
|
|
// attempt to save all documents
|
|
if (pDocument == NULL && !pApp->SaveAllModified())
|
|
return; // don't close it
|
|
|
|
// hide the application's windows before closing all the documents
|
|
pApp->HideApplication();
|
|
|
|
// close all documents first
|
|
pApp->CloseAllDocuments(FALSE);
|
|
|
|
// don't exit if there are outstanding component objects
|
|
if (!AfxOleCanExitApp())
|
|
{
|
|
// take user out of control of the app
|
|
AfxOleSetUserCtrl(FALSE);
|
|
|
|
// don't destroy the main window and close down just yet
|
|
// (there are outstanding component (OLE) objects)
|
|
return;
|
|
}
|
|
|
|
// there are cases where destroying the documents may destroy the
|
|
// main window of the application.
|
|
if (!afxContextIsDLL && pApp->m_pMainWnd == NULL)
|
|
{
|
|
AfxPostQuitMessage(0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// detect the case that this is the last frame on the document and
|
|
// shut down with OnCloseDocument instead.
|
|
if (pDocument != NULL && pDocument->m_bAutoDelete)
|
|
{
|
|
BOOL bOtherFrame = FALSE;
|
|
POSITION pos = pDocument->GetFirstViewPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CView* pView = pDocument->GetNextView(pos);
|
|
ASSERT_VALID(pView);
|
|
if (pView->GetParentFrame() != this)
|
|
{
|
|
bOtherFrame = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!bOtherFrame)
|
|
{
|
|
pDocument->OnCloseDocument();
|
|
return;
|
|
}
|
|
|
|
// allow the document to cleanup before the window is destroyed
|
|
pDocument->PreCloseFrame(this);
|
|
}
|
|
|
|
// then destroy the window
|
|
DestroyWindow();
|
|
}
|
|
|
|
void CFrameWnd::OnDestroy()
|
|
{
|
|
DestroyDockBars();
|
|
|
|
// reset menu to default before final shutdown
|
|
if (m_hMenuDefault != NULL && ::GetMenu(m_hWnd) != m_hMenuDefault)
|
|
{
|
|
::SetMenu(m_hWnd, m_hMenuDefault);
|
|
ASSERT(::GetMenu(m_hWnd) == m_hMenuDefault);
|
|
}
|
|
|
|
// Automatically quit when the main window is destroyed.
|
|
if (AfxGetApp()->m_pMainWnd == this)
|
|
{
|
|
// closing the main application window
|
|
::WinHelp(m_hWnd, NULL, HELP_QUIT, 0L);
|
|
|
|
// will call PostQuitMessage in CWnd::OnNcDestroy
|
|
}
|
|
CWnd::OnDestroy();
|
|
}
|
|
|
|
void CFrameWnd::RemoveControlBar(CControlBar *pBar)
|
|
{
|
|
POSITION pos = m_listControlBars.Find(pBar);
|
|
if (pos != NULL)
|
|
m_listControlBars.RemoveAt(pos);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd command/message routing
|
|
|
|
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
|
|
AFX_CMDHANDLERINFO* pHandlerInfo)
|
|
{
|
|
// pump through current view FIRST
|
|
CView* pView = GetActiveView();
|
|
if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
|
|
return TRUE;
|
|
|
|
// then pump through frame
|
|
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
|
|
return TRUE;
|
|
|
|
// last but not least, pump through app
|
|
CWinApp* pApp = AfxGetApp();
|
|
if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Delegate scroll messages to active view as well
|
|
void CFrameWnd::OnHScroll(UINT, UINT, CScrollBar*)
|
|
{
|
|
CWnd* pActiveView = GetActiveView();
|
|
if (pActiveView != NULL)
|
|
{
|
|
const MSG* pMsg = GetCurrentMessage();
|
|
pActiveView->SendMessage(WM_HSCROLL, pMsg->wParam, pMsg->lParam);
|
|
}
|
|
}
|
|
|
|
void CFrameWnd::OnVScroll(UINT, UINT, CScrollBar*)
|
|
{
|
|
CWnd* pActiveView = GetActiveView();
|
|
if (pActiveView != NULL)
|
|
{
|
|
const MSG* pMsg = GetCurrentMessage();
|
|
pActiveView->SendMessage(WM_VSCROLL, pMsg->wParam, pMsg->lParam);
|
|
}
|
|
}
|
|
|
|
LRESULT CFrameWnd::OnActivateTopLevel(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
#ifdef _MAC
|
|
BOOL bActive = (LOWORD(wParam) != WA_INACTIVE && !HIWORD(wParam));
|
|
|
|
if(!bActive && afxData.bOleIgnoreSuspend)
|
|
{
|
|
afxData.bOleIgnoreSuspend = FALSE;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
CWnd::OnActivateTopLevel(wParam, lParam);
|
|
|
|
// exit Shift+F1 help mode on activation changes
|
|
ExitHelpMode();
|
|
|
|
#ifndef _AFX_NO_OLE_SUPPORT
|
|
// allow OnFrameWindowActivate to be sent to in-place items
|
|
if (m_pNotifyHook != NULL)
|
|
{
|
|
#ifdef _MAC
|
|
if (::GetWinActiveMode() != WAM_OLEIPCONTAINER)
|
|
#endif
|
|
{
|
|
// activate when active and when not minimized
|
|
m_pNotifyHook->OnActivate(
|
|
LOWORD(wParam) != WA_INACTIVE && !HIWORD(wParam));
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
// deactivate current active view
|
|
if (AfxGetThread()->m_pMainWnd == this)
|
|
{
|
|
CView* pActiveView = GetActiveView();
|
|
if (pActiveView == NULL)
|
|
pActiveView = GetActiveFrame()->GetActiveView();
|
|
if (pActiveView != NULL)
|
|
pActiveView->OnActivateView(FALSE, pActiveView, pActiveView);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CFrameWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
|
|
{
|
|
CWnd::OnActivate(nState, pWndOther, bMinimized);
|
|
|
|
// get top level frame unless this is a child window
|
|
// determine if window should be active or not
|
|
CFrameWnd* pTopLevel = (GetStyle() & WS_CHILD) ? this : GetTopLevelFrame();
|
|
ASSERT(pTopLevel != NULL);
|
|
CWnd* pActive = (nState == WA_INACTIVE ? pWndOther : this);
|
|
BOOL bStayActive =
|
|
(pTopLevel == pActive ||
|
|
(pTopLevel == pActive->GetTopLevelFrame() &&
|
|
(pActive == pTopLevel ||
|
|
pActive->SendMessage(WM_FLOATSTATUS, FS_SYNCACTIVE) != 0)));
|
|
pTopLevel->m_nFlags &= ~WF_STAYACTIVE;
|
|
if (bStayActive)
|
|
pTopLevel->m_nFlags |= WF_STAYACTIVE;
|
|
|
|
// sync floating windows to the new state
|
|
NotifyFloatingWindows(bStayActive ? FS_ACTIVATE : FS_DEACTIVATE);
|
|
|
|
// get active view (use active frame if no active view)
|
|
CView* pActiveView = GetActiveView();
|
|
if (pActiveView == NULL)
|
|
pActiveView = GetActiveFrame()->GetActiveView();
|
|
|
|
// when frame gets activated, re-activate current view
|
|
if (pActiveView != NULL)
|
|
{
|
|
if (nState != WA_INACTIVE && !bMinimized)
|
|
pActiveView->OnActivateView(TRUE, pActiveView, pActiveView);
|
|
|
|
// always notify the view of frame activations
|
|
pActiveView->OnActivateFrame(nState, this);
|
|
}
|
|
}
|
|
|
|
BOOL CFrameWnd::OnNcActivate(BOOL bActive)
|
|
{
|
|
// stay active if WF_STAYACTIVE bit is on
|
|
if (m_nFlags & WF_STAYACTIVE)
|
|
bActive = TRUE;
|
|
|
|
// but do not stay active if the window is disabled
|
|
if (!IsWindowEnabled())
|
|
bActive = FALSE;
|
|
|
|
// do not call the base class because it will call Default()
|
|
// and we may have changed bActive.
|
|
return (BOOL)DefWindowProc(WM_NCACTIVATE, bActive, 0L);
|
|
}
|
|
|
|
#ifdef _MAC
|
|
void CFrameWnd::OnActivateApp(BOOL bActive, HTASK hTask)
|
|
{
|
|
#ifndef _AFX_NO_OLE_SUPPORT
|
|
// allow OnFrameWindowActivate to be sent to in-place items
|
|
if (m_pNotifyHook != NULL && bActive)
|
|
{
|
|
if (::GetWinActiveMode() == WAM_OLEIPCONTAINER)
|
|
{
|
|
// ok, the container has an activate msg while the server is still
|
|
// UIVisible. This implies that the user has ESCaped the IP session.
|
|
CView* pActiveView = GetActiveView();
|
|
if (pActiveView == NULL)
|
|
pActiveView = GetActiveFrame()->GetActiveView();
|
|
ASSERT(pActiveView != NULL);
|
|
pActiveView->PostMessage(WM_KEYDOWN, VK_ESCAPE, 0);
|
|
}
|
|
else
|
|
{
|
|
m_pNotifyHook->OnActivate(TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
CWnd::OnActivateApp(bActive, hTask);
|
|
|
|
// The Macintosh DefFrameProc hides toolbars, status bars, etc. when
|
|
// a frame window is deactivated, and shows them again on activation.
|
|
// If the frame window changes size while it's deactivated (say because
|
|
// it's on a Radius Pivot monitor that's pivoted) then RecalcLayout is
|
|
// called while the control bars are hidden. In this case, we need to
|
|
// recalc the layout again when the window is reactivated and the
|
|
// controlbars shown again. Note that we must do the recalc *after*
|
|
// CWnd::OnActivateApp because it's inside that function that DefFrameProc
|
|
// gets called to re-show the controlbars.
|
|
|
|
if (bActive)
|
|
RecalcLayout();
|
|
}
|
|
#endif
|
|
|
|
void CFrameWnd::OnSysCommand(UINT nID, LONG lParam)
|
|
{
|
|
#ifdef _MAC
|
|
// the frame window's system menu is mapped to the Apple menu on the
|
|
// Macintosh, so choosing About MyApp results in a WM_SYSCOMMAND
|
|
if (nID == ID_APP_ABOUT)
|
|
{
|
|
OnCommand(ID_APP_ABOUT, 0);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
CFrameWnd* pFrameWnd = GetTopLevelFrame();
|
|
ASSERT_VALID(pFrameWnd);
|
|
|
|
// set status bar as appropriate
|
|
UINT nItemID = (nID & 0xFFF0);
|
|
|
|
// don't interfere with system commands if not in help mode
|
|
if (pFrameWnd->m_bHelpMode)
|
|
{
|
|
switch (nItemID)
|
|
{
|
|
case SC_SIZE:
|
|
case SC_MOVE:
|
|
case SC_MINIMIZE:
|
|
case SC_MAXIMIZE:
|
|
case SC_NEXTWINDOW:
|
|
case SC_PREVWINDOW:
|
|
case SC_CLOSE:
|
|
case SC_RESTORE:
|
|
case SC_TASKLIST:
|
|
if (!SendMessage(WM_COMMANDHELP, 0,
|
|
HID_BASE_COMMAND+ID_COMMAND_FROM_SC(nItemID)))
|
|
SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// call default functionality
|
|
CWnd::OnSysCommand(nID, lParam);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// default frame processing
|
|
|
|
// default drop processing will attempt to open the file
|
|
void CFrameWnd::OnDropFiles(HDROP hDropInfo)
|
|
{
|
|
SetActiveWindow(); // activate us first !
|
|
UINT nFiles = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);
|
|
|
|
CWinApp* pApp = AfxGetApp();
|
|
for (UINT iFile = 0; iFile < nFiles; iFile++)
|
|
{
|
|
TCHAR szFileName[_MAX_PATH];
|
|
::DragQueryFile(hDropInfo, iFile, szFileName, _MAX_PATH);
|
|
pApp->OpenDocumentFile(szFileName);
|
|
}
|
|
::DragFinish(hDropInfo);
|
|
}
|
|
|
|
// query end session for main frame will attempt to close it all down
|
|
BOOL CFrameWnd::OnQueryEndSession()
|
|
{
|
|
CWinApp* pApp = AfxGetApp();
|
|
if (pApp->m_pMainWnd == this)
|
|
return pApp->SaveAllModified();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// when Windows session ends, close all documents
|
|
void CFrameWnd::OnEndSession(BOOL bEnding)
|
|
{
|
|
CWinApp* pApp = AfxGetApp();
|
|
ASSERT_VALID(pApp);
|
|
if (bEnding && pApp->m_pMainWnd == this)
|
|
{
|
|
AfxOleSetUserCtrl(TRUE); // keeps from randomly shutting down
|
|
pApp->CloseAllDocuments(TRUE);
|
|
|
|
// allow application to save settings, etc.
|
|
pApp->ExitInstance();
|
|
}
|
|
}
|
|
|
|
#ifndef _MAC
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Support for Shell DDE Execute messages
|
|
|
|
LRESULT CFrameWnd::OnDDEInitiate(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CWinApp* pApp = AfxGetApp();
|
|
ASSERT_VALID(pApp);
|
|
if (LOWORD(lParam) != 0 && HIWORD(lParam) != 0 &&
|
|
(ATOM)LOWORD(lParam) == pApp->m_atomApp &&
|
|
(ATOM)HIWORD(lParam) == pApp->m_atomSystemTopic)
|
|
{
|
|
// make duplicates of the incoming atoms (really adding a reference)
|
|
TCHAR szAtomName[_MAX_PATH];
|
|
VERIFY(GlobalGetAtomName(pApp->m_atomApp,
|
|
szAtomName, _MAX_PATH - 1) != 0);
|
|
VERIFY(GlobalAddAtom(szAtomName) == pApp->m_atomApp);
|
|
VERIFY(GlobalGetAtomName(pApp->m_atomSystemTopic,
|
|
szAtomName, _MAX_PATH - 1) != 0);
|
|
VERIFY(GlobalAddAtom(szAtomName) == pApp->m_atomSystemTopic);
|
|
|
|
// send the WM_DDE_ACK (caller will delete duplicate atoms)
|
|
::SendMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)m_hWnd,
|
|
MAKELPARAM(pApp->m_atomApp, pApp->m_atomSystemTopic));
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
// always ACK the execute command - even if we do nothing
|
|
LRESULT CFrameWnd::OnDDEExecute(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// unpack the DDE message
|
|
UINT unused;
|
|
HGLOBAL hData;
|
|
VERIFY(UnpackDDElParam(WM_DDE_EXECUTE, lParam, &unused, (UINT*)&hData));
|
|
|
|
// get the command string
|
|
TCHAR szCommand[_MAX_PATH * 2];
|
|
LPCTSTR lpsz = (LPCTSTR)GlobalLock(hData);
|
|
lstrcpyn(szCommand, lpsz, _countof(szCommand));
|
|
GlobalUnlock(hData);
|
|
|
|
// acknowledge now - before attempting to execute
|
|
::PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)m_hWnd,
|
|
ReuseDDElParam(lParam, WM_DDE_EXECUTE, WM_DDE_ACK,
|
|
(UINT)0x8000, (UINT)hData));
|
|
|
|
// don't execute the command when the window is disabled
|
|
if (!IsWindowEnabled())
|
|
{
|
|
TRACE1("Warning: DDE command '%s' ignored because window is disabled.\n",
|
|
szCommand);
|
|
return 0;
|
|
}
|
|
|
|
// execute the command
|
|
if (!AfxGetApp()->OnDDECommand(szCommand))
|
|
TRACE1("Error: failed to execute DDE command '%s'.\n", szCommand);
|
|
|
|
return 0L;
|
|
}
|
|
|
|
LRESULT CFrameWnd::OnDDETerminate(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
::PostMessage((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)m_hWnd, lParam);
|
|
return 0L;
|
|
}
|
|
#endif //!_MAC
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd attributes
|
|
|
|
CView* CFrameWnd::GetActiveView() const
|
|
{
|
|
ASSERT(m_pViewActive == NULL ||
|
|
m_pViewActive->IsKindOf(RUNTIME_CLASS(CView)));
|
|
return m_pViewActive;
|
|
}
|
|
|
|
void CFrameWnd::SetActiveView(CView* pViewNew, BOOL bNotify)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (pViewNew != NULL)
|
|
{
|
|
ASSERT(IsChild(pViewNew));
|
|
ASSERT_KINDOF(CView, pViewNew);
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
CView* pViewOld = m_pViewActive;
|
|
if (pViewNew == pViewOld)
|
|
return; // do not re-activate if SetActiveView called more than once
|
|
|
|
m_pViewActive = NULL; // no active for the following processing
|
|
|
|
// deactivate the old one
|
|
if (pViewOld != NULL)
|
|
pViewOld->OnActivateView(FALSE, pViewNew, pViewOld);
|
|
|
|
// if the OnActivateView moves the active window,
|
|
// that will veto this change
|
|
if (m_pViewActive != NULL)
|
|
return; // already set
|
|
m_pViewActive = pViewNew;
|
|
|
|
// activate
|
|
if (pViewNew != NULL && bNotify)
|
|
pViewNew->OnActivateView(TRUE, pViewNew, pViewOld);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Special view swapping/activation
|
|
|
|
void CFrameWnd::OnSetFocus(CWnd* pOldWnd)
|
|
{
|
|
if (m_pViewActive != NULL)
|
|
m_pViewActive->SetFocus();
|
|
else
|
|
CWnd::OnSetFocus(pOldWnd);
|
|
}
|
|
|
|
CDocument* CFrameWnd::GetActiveDocument()
|
|
{
|
|
ASSERT_VALID(this);
|
|
CView* pView = GetActiveView();
|
|
if (pView != NULL)
|
|
return pView->GetDocument();
|
|
return NULL;
|
|
}
|
|
|
|
void CFrameWnd::ShowControlBar(CControlBar* pBar, BOOL bShow, BOOL bDelay)
|
|
{
|
|
ASSERT(pBar != NULL);
|
|
CFrameWnd* pParentFrame = pBar->GetDockingFrame();
|
|
ASSERT(pParentFrame->GetTopLevelParent() == GetTopLevelParent());
|
|
// parent frame of bar must be related
|
|
|
|
if (bDelay)
|
|
{
|
|
pBar->DelayShow(bShow);
|
|
pParentFrame->DelayRecalcLayout();
|
|
}
|
|
else
|
|
{
|
|
pBar->SetWindowPos(NULL, 0, 0, 0, 0,
|
|
SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
|
|
(bShow ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
|
|
// call DelayShow to clear any contradictory DelayShow
|
|
pBar->DelayShow(bShow);
|
|
if (bShow || !pBar->IsFloating())
|
|
pParentFrame->RecalcLayout(FALSE);
|
|
}
|
|
|
|
// show or hide the floating frame as appropriate
|
|
if (pBar->IsFloating())
|
|
{
|
|
int nVisCount = pBar->m_pDockBar != NULL ?
|
|
pBar->m_pDockBar->GetDockedVisibleCount() : bShow != FALSE;
|
|
if (nVisCount == 1 && bShow)
|
|
{
|
|
pParentFrame->m_nShowDelay = -1;
|
|
if (bDelay)
|
|
{
|
|
pParentFrame->m_nShowDelay = SW_SHOWNA;
|
|
pParentFrame->RecalcLayout(FALSE);
|
|
}
|
|
else
|
|
pParentFrame->ShowWindow(SW_SHOWNA);
|
|
}
|
|
else if (nVisCount == 0)
|
|
{
|
|
ASSERT(!bShow);
|
|
pParentFrame->m_nShowDelay = -1;
|
|
if (bDelay)
|
|
pParentFrame->m_nShowDelay = SW_HIDE;
|
|
else
|
|
pParentFrame->ShowWindow(SW_HIDE);
|
|
}
|
|
else if (!bDelay)
|
|
{
|
|
pParentFrame->RecalcLayout(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Command prompts
|
|
|
|
void CFrameWnd::OnInitMenuPopup(CMenu* pMenu, UINT, BOOL bSysMenu)
|
|
{
|
|
AfxCancelModes(m_hWnd);
|
|
|
|
if (bSysMenu)
|
|
return; // don't support system menu
|
|
|
|
ASSERT(pMenu != NULL);
|
|
// check the enabled state of various menu items
|
|
|
|
CCmdUI state;
|
|
state.m_pMenu = pMenu;
|
|
ASSERT(state.m_pOther == NULL);
|
|
ASSERT(state.m_pParentMenu == NULL);
|
|
|
|
// determine if menu is popup in top-level menu and set m_pOther to
|
|
// it if so (m_pParentMenu == NULL indicates that it is secondary popup)
|
|
HMENU hParentMenu;
|
|
if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu)
|
|
state.m_pParentMenu = pMenu; // parent == child for tracking popup
|
|
else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
|
|
{
|
|
CWnd* pParent = GetTopLevelParent();
|
|
// child windows don't have menus -- need to go to the top!
|
|
if (pParent != NULL &&
|
|
(hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
|
|
{
|
|
int nIndexMax = ::GetMenuItemCount(hParentMenu);
|
|
for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
|
|
{
|
|
if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu)
|
|
{
|
|
// when popup is found, m_pParentMenu is containing menu
|
|
state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
state.m_nIndexMax = pMenu->GetMenuItemCount();
|
|
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
|
|
state.m_nIndex++)
|
|
{
|
|
state.m_nID = pMenu->GetMenuItemID(state.m_nIndex);
|
|
if (state.m_nID == 0)
|
|
continue; // menu separator or invalid cmd - ignore it
|
|
|
|
ASSERT(state.m_pOther == NULL);
|
|
ASSERT(state.m_pMenu != NULL);
|
|
if (state.m_nID == (UINT)-1)
|
|
{
|
|
// possibly a popup menu, route to first item of that popup
|
|
state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex);
|
|
if (state.m_pSubMenu == NULL ||
|
|
(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
|
|
state.m_nID == (UINT)-1)
|
|
{
|
|
continue; // first item of popup can't be routed to
|
|
}
|
|
state.DoUpdate(this, FALSE); // popups are never auto disabled
|
|
}
|
|
else
|
|
{
|
|
// normal menu item
|
|
// Auto enable/disable if frame window has 'm_bAutoMenuEnable'
|
|
// set and command is _not_ a system command.
|
|
state.m_pSubMenu = NULL;
|
|
state.DoUpdate(this, m_bAutoMenuEnable && state.m_nID < 0xF000);
|
|
}
|
|
|
|
// adjust for menu deletions and additions
|
|
UINT nCount = pMenu->GetMenuItemCount();
|
|
if (nCount < state.m_nIndexMax)
|
|
{
|
|
state.m_nIndex -= (state.m_nIndexMax - nCount);
|
|
while (state.m_nIndex < nCount &&
|
|
pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
|
|
{
|
|
state.m_nIndex++;
|
|
}
|
|
}
|
|
state.m_nIndexMax = nCount;
|
|
}
|
|
}
|
|
|
|
void CFrameWnd::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU /*hSysMenu*/)
|
|
{
|
|
CFrameWnd* pFrameWnd = GetTopLevelFrame();
|
|
ASSERT_VALID(pFrameWnd);
|
|
|
|
// set the tracking state (update on idle)
|
|
if (nFlags == 0xFFFF)
|
|
{
|
|
// cancel menu operation (go back to idle now)
|
|
m_nFlags &= ~WF_NOPOPMSG;
|
|
if (!pFrameWnd->m_bHelpMode)
|
|
m_nIDTracking = AFX_IDS_IDLEMESSAGE;
|
|
else
|
|
m_nIDTracking = AFX_IDS_HELPMODEMESSAGE;
|
|
SendMessage(WM_SETMESSAGESTRING, (WPARAM)m_nIDTracking);
|
|
ASSERT(m_nIDTracking == m_nIDLastMessage);
|
|
|
|
// update right away
|
|
CWnd* pWnd = GetMessageBar();
|
|
if (pWnd != NULL)
|
|
pWnd->UpdateWindow();
|
|
}
|
|
else
|
|
{
|
|
if (nItemID == 0 || nFlags & (MF_SEPARATOR|MF_POPUP))
|
|
{
|
|
// nothing should be displayed
|
|
m_nIDTracking = 0;
|
|
}
|
|
#ifdef _MAC
|
|
else if (nItemID == SC_DESKACCESSORY)
|
|
{
|
|
m_nIDTracking = AFX_IDS_DESKACCESSORY;
|
|
}
|
|
#endif
|
|
else if (nItemID >= 0xF000 && nItemID < 0xF1F0) // max of 31 SC_s
|
|
{
|
|
// special strings table entries for system commands
|
|
m_nIDTracking = ID_COMMAND_FROM_SC(nItemID);
|
|
ASSERT(m_nIDTracking >= AFX_IDS_SCFIRST &&
|
|
m_nIDTracking < AFX_IDS_SCFIRST + 31);
|
|
}
|
|
else if (nItemID >= AFX_IDM_FIRST_MDICHILD)
|
|
{
|
|
// all MDI Child windows map to the same help id
|
|
m_nIDTracking = AFX_IDS_MDICHILD;
|
|
}
|
|
else
|
|
{
|
|
// track on idle
|
|
m_nIDTracking = nItemID;
|
|
}
|
|
pFrameWnd->m_nFlags |= WF_NOPOPMSG;
|
|
}
|
|
|
|
// when running in-place, it is necessary to cause a message to
|
|
// be pumped through the queue.
|
|
if (m_nIDTracking != m_nIDLastMessage && GetParent() != NULL)
|
|
PostMessage(WM_KICKIDLE);
|
|
}
|
|
|
|
void CFrameWnd::GetMessageString(UINT nID, CString& rMessage) const
|
|
{
|
|
// load appropriate string
|
|
LPTSTR lpsz = rMessage.GetBuffer(255);
|
|
if (AfxLoadString(nID, lpsz) != 0)
|
|
{
|
|
// first newline terminates actual string
|
|
lpsz = _tcschr(lpsz, '\n');
|
|
if (lpsz != NULL)
|
|
*lpsz = '\0';
|
|
}
|
|
else
|
|
{
|
|
// not found
|
|
TRACE1("Warning: no message line prompt for ID 0x%04X.\n", nID);
|
|
}
|
|
rMessage.ReleaseBuffer();
|
|
}
|
|
|
|
LRESULT CFrameWnd::OnPopMessageString(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (m_nFlags & WF_NOPOPMSG)
|
|
return 0;
|
|
|
|
return SendMessage(WM_SETMESSAGESTRING, wParam, lParam);
|
|
}
|
|
|
|
LRESULT CFrameWnd::OnSetMessageString(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UINT nIDLast = m_nIDLastMessage;
|
|
m_nFlags &= ~WF_NOPOPMSG;
|
|
|
|
CWnd* pMessageBar = GetMessageBar();
|
|
if (pMessageBar != NULL)
|
|
{
|
|
LPCTSTR lpsz = NULL;
|
|
CString strMessage;
|
|
|
|
// set the message bar text
|
|
if (lParam != 0)
|
|
{
|
|
ASSERT(wParam == 0); // can't have both an ID and a string
|
|
lpsz = (LPCTSTR)lParam; // set an explicit string
|
|
}
|
|
else if (wParam != 0)
|
|
{
|
|
// map SC_CLOSE to PREVIEW_CLOSE when in print preview mode
|
|
if (wParam == AFX_IDS_SCCLOSE && m_lpfnCloseProc != NULL)
|
|
wParam = AFX_IDS_PREVIEW_CLOSE;
|
|
|
|
// get message associated with the ID indicated by wParam
|
|
GetMessageString(wParam, strMessage);
|
|
lpsz = strMessage;
|
|
}
|
|
pMessageBar->SetWindowText(lpsz);
|
|
|
|
// update owner of the bar in terms of last message selected
|
|
CFrameWnd* pFrameWnd = pMessageBar->GetParentFrame();
|
|
if (pFrameWnd != NULL)
|
|
{
|
|
pFrameWnd->m_nIDLastMessage = (UINT)wParam;
|
|
pFrameWnd->m_nIDTracking = (UINT)wParam;
|
|
}
|
|
}
|
|
|
|
m_nIDLastMessage = (UINT)wParam; // new ID (or 0)
|
|
m_nIDTracking = (UINT)wParam; // so F1 on toolbar buttons work
|
|
return nIDLast;
|
|
}
|
|
|
|
CWnd* CFrameWnd::GetMessageBar()
|
|
{
|
|
return GetDescendantWindow(AFX_IDW_STATUS_BAR, TRUE);
|
|
}
|
|
|
|
void CFrameWnd::OnEnterIdle(UINT nWhy, CWnd* pWho)
|
|
{
|
|
CWnd::OnEnterIdle(nWhy, pWho);
|
|
|
|
if (nWhy != MSGF_MENU || m_nIDTracking == m_nIDLastMessage)
|
|
return;
|
|
|
|
SetMessageText(m_nIDTracking);
|
|
ASSERT(m_nIDTracking == m_nIDLastMessage);
|
|
}
|
|
|
|
void CFrameWnd::SetMessageText(LPCTSTR lpszText)
|
|
{
|
|
SendMessage(WM_SETMESSAGESTRING, 0, (LPARAM)lpszText);
|
|
}
|
|
|
|
void CFrameWnd::SetMessageText(UINT nID)
|
|
{
|
|
SendMessage(WM_SETMESSAGESTRING, (WPARAM)nID);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd standard control bar management
|
|
|
|
void CFrameWnd::DestroyDockBars()
|
|
{
|
|
// create a list of all the dock bars
|
|
// this is necessary because m_listControlBars will change
|
|
// as the dock bars and floating frames are destroyed
|
|
CPtrList listDockBars;
|
|
POSITION pos = m_listControlBars.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CDockBar* pDockBar = (CDockBar*)m_listControlBars.GetNext(pos);
|
|
ASSERT(pDockBar != NULL);
|
|
if (pDockBar->IsDockBar())
|
|
listDockBars.AddTail(pDockBar);
|
|
}
|
|
pos = listDockBars.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CDockBar* pDockBar = (CDockBar*)listDockBars.GetNext(pos);
|
|
if (pDockBar->m_bFloating)
|
|
{
|
|
CFrameWnd* pFrameWnd = pDockBar->GetParentFrame();
|
|
ASSERT_VALID(pFrameWnd);
|
|
pFrameWnd->DestroyWindow();
|
|
}
|
|
else
|
|
pDockBar->DestroyWindow();
|
|
}
|
|
}
|
|
|
|
CControlBar* CFrameWnd::GetControlBar(UINT nID)
|
|
{
|
|
if (nID == 0)
|
|
return NULL;
|
|
POSITION pos = m_listControlBars.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CControlBar* pBar = (CControlBar*)m_listControlBars.GetNext(pos);
|
|
ASSERT(pBar != NULL);
|
|
ASSERT_VALID(pBar);
|
|
if (_AfxGetDlgCtrlID(pBar->m_hWnd) == nID)
|
|
{
|
|
ASSERT_KINDOF(CControlBar, pBar);
|
|
return pBar;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void CFrameWnd::OnUpdateControlBarMenu(CCmdUI* pCmdUI)
|
|
{
|
|
ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
|
|
ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);
|
|
|
|
CControlBar* pBar = GetControlBar(pCmdUI->m_nID);
|
|
if (pBar != NULL)
|
|
{
|
|
pCmdUI->SetCheck((pBar->GetStyle() & WS_VISIBLE) != 0);
|
|
return;
|
|
}
|
|
pCmdUI->ContinueRouting();
|
|
}
|
|
|
|
BOOL CFrameWnd::OnBarCheck(UINT nID)
|
|
{
|
|
ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
|
|
ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);
|
|
|
|
CControlBar* pBar = GetControlBar(nID);
|
|
if (pBar != NULL)
|
|
{
|
|
ShowControlBar(pBar, (pBar->GetStyle() & WS_VISIBLE) == 0, FALSE);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CFrameWnd::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
|
|
|
|
// allow top level routing frame to handle the message
|
|
if (GetRoutingFrame() != NULL)
|
|
return FALSE;
|
|
|
|
// need to handle both ANSI and UNICODE versions of the message
|
|
TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
|
|
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
|
|
TCHAR szFullText[256];
|
|
CString strTipText;
|
|
UINT nID = pNMHDR->idFrom;
|
|
if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
|
|
pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
|
|
{
|
|
// idFrom is actually the HWND of the tool
|
|
nID = _AfxGetDlgCtrlID((HWND)nID);
|
|
}
|
|
|
|
if (nID != 0) // will be zero on a separator
|
|
{
|
|
AfxLoadString(nID, szFullText);
|
|
// this is the command id, not the button index
|
|
AfxExtractSubString(strTipText, szFullText, 1, '\n');
|
|
}
|
|
#ifndef _UNICODE
|
|
if (pNMHDR->code == TTN_NEEDTEXTA)
|
|
lstrcpyn(pTTTA->szText, strTipText, _countof(pTTTA->szText));
|
|
else
|
|
_mbstowcsz(pTTTW->szText, strTipText, _countof(pTTTW->szText));
|
|
#else
|
|
if (pNMHDR->code == TTN_NEEDTEXTA)
|
|
_wcstombsz(pTTTA->szText, strTipText, _countof(pTTTA->szText));
|
|
else
|
|
lstrcpyn(pTTTW->szText, strTipText, _countof(pTTTW->szText));
|
|
#endif
|
|
*pResult = 0;
|
|
|
|
// bring the tooltip window above other popup windows
|
|
::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
|
|
SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
|
|
|
|
return TRUE; // message was handled
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Support for standard status bar
|
|
|
|
void CFrameWnd::OnUpdateKeyIndicator(CCmdUI* pCmdUI)
|
|
{
|
|
UINT nVK;
|
|
UINT flag = 0x0001;
|
|
|
|
switch (pCmdUI->m_nID)
|
|
{
|
|
case ID_INDICATOR_CAPS:
|
|
nVK = VK_CAPITAL;
|
|
break;
|
|
|
|
case ID_INDICATOR_NUM:
|
|
nVK = VK_NUMLOCK;
|
|
break;
|
|
|
|
case ID_INDICATOR_SCRL:
|
|
nVK = VK_SCROLL;
|
|
break;
|
|
|
|
case ID_INDICATOR_KANA:
|
|
nVK = VK_KANA;
|
|
// WINBUG: Special case for Windows 3.x. The wrong bit was toggled
|
|
// in those systems so this must be special cased. This is fixed
|
|
// on systems whose version is 4.x or greater.
|
|
if (afxData.bWin31)
|
|
flag = 0x8000;
|
|
break;
|
|
|
|
default:
|
|
TRACE1("Warning: OnUpdateKeyIndicator - unknown indicator 0x%04X.\n",
|
|
pCmdUI->m_nID);
|
|
pCmdUI->ContinueRouting();
|
|
return; // not for us
|
|
}
|
|
|
|
pCmdUI->Enable(::GetKeyState(nVK) & flag);
|
|
// enable static text based on toggled key state
|
|
ASSERT(pCmdUI->m_bEnableChanged);
|
|
}
|
|
|
|
void CFrameWnd::OnUpdateContextHelp(CCmdUI* pCmdUI)
|
|
{
|
|
if (AfxGetMainWnd() == this)
|
|
pCmdUI->SetCheck(!!m_bHelpMode);
|
|
else
|
|
pCmdUI->ContinueRouting();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Setting title of frame window - UISG standard
|
|
|
|
void CFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle)
|
|
{
|
|
if ((GetStyle() & FWS_ADDTOTITLE) == 0)
|
|
return; // leave it alone!
|
|
|
|
#ifndef _AFX_NO_OLE_SUPPORT
|
|
// allow hook to set the title (used for OLE support)
|
|
if (m_pNotifyHook != NULL && m_pNotifyHook->OnUpdateFrameTitle())
|
|
return;
|
|
#endif
|
|
|
|
CDocument* pDocument = GetActiveDocument();
|
|
if (bAddToTitle && pDocument != NULL)
|
|
UpdateFrameTitleForDocument(pDocument->GetTitle());
|
|
else
|
|
UpdateFrameTitleForDocument(NULL);
|
|
}
|
|
|
|
void CFrameWnd::UpdateFrameTitleForDocument(LPCTSTR lpszDocName)
|
|
{
|
|
// copy first part of title loaded at time of frame creation
|
|
TCHAR szText[256+_MAX_PATH];
|
|
|
|
if (GetStyle() & FWS_PREFIXTITLE)
|
|
{
|
|
szText[0] = '\0'; // start with nothing
|
|
|
|
// get name of currently active view
|
|
if (lpszDocName != NULL)
|
|
{
|
|
lstrcpy(szText, lpszDocName);
|
|
// add current window # if needed
|
|
if (m_nWindow > 0)
|
|
wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);
|
|
lstrcat(szText, _T(" - "));
|
|
}
|
|
lstrcat(szText, m_strTitle);
|
|
}
|
|
else
|
|
{
|
|
// get name of currently active view
|
|
lstrcpy(szText, m_strTitle);
|
|
if (lpszDocName != NULL)
|
|
{
|
|
lstrcat(szText, _T(" - "));
|
|
lstrcat(szText, lpszDocName);
|
|
// add current window # if needed
|
|
if (m_nWindow > 0)
|
|
wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);
|
|
}
|
|
}
|
|
|
|
// set title if changed, but don't remove completely
|
|
// Note: will be excessive for MDI Frame with maximized child
|
|
AfxSetWindowText(m_hWnd, szText);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CFrameWnd::OnSetPreviewMode(BOOL bPreview, CPrintPreviewState* pState)
|
|
{
|
|
// default implementation changes control bars, menu and main pane window
|
|
|
|
#ifndef _AFX_NO_OLE_SUPPORT
|
|
CFrameWnd* pActiveFrame = GetActiveFrame();
|
|
ASSERT_VALID(pActiveFrame);
|
|
if (bPreview && pActiveFrame->m_pNotifyHook != NULL)
|
|
pActiveFrame->m_pNotifyHook->OnDocActivate(FALSE);
|
|
#endif
|
|
|
|
// Set visibility of standard ControlBars (only the first 32)
|
|
DWORD dwOldStates = 0;
|
|
POSITION pos = m_listControlBars.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CControlBar* pBar = (CControlBar*)m_listControlBars.GetNext(pos);
|
|
ASSERT_VALID(pBar);
|
|
UINT nID = _AfxGetDlgCtrlID(pBar->m_hWnd);
|
|
if (nID >= AFX_IDW_CONTROLBAR_FIRST && nID <= AFX_IDW_CONTROLBAR_FIRST+31)
|
|
{
|
|
DWORD dwMask = 1L << (nID - AFX_IDW_CONTROLBAR_FIRST);
|
|
if (pBar->IsVisible())
|
|
dwOldStates |= dwMask; // save if previously visible
|
|
if (!pBar->IsDockBar() || nID != AFX_IDW_DOCKBAR_FLOAT)
|
|
ShowControlBar(pBar, (pState->dwStates & dwMask), TRUE);
|
|
}
|
|
}
|
|
pState->dwStates = dwOldStates; // save for restore
|
|
|
|
if (bPreview)
|
|
{
|
|
// Entering Print Preview
|
|
ASSERT(m_lpfnCloseProc == NULL); // no chaining
|
|
m_lpfnCloseProc = pState->lpfnCloseProc;
|
|
|
|
// show any modeless dialogs, popup windows, float tools, etc
|
|
ShowOwnedWindows(FALSE);
|
|
|
|
// Hide the main pane
|
|
HWND hWnd = ::GetDlgItem(m_hWnd, pState->nIDMainPane);
|
|
ASSERT(hWnd != NULL); // must be one that we are hiding!
|
|
::ShowWindow(hWnd, SW_HIDE);
|
|
|
|
// Get rid of the menu first (will resize the window)
|
|
pState->hMenu = ::GetMenu(m_hWnd);
|
|
if (pState->hMenu != NULL)
|
|
{
|
|
// Invalidate before SetMenu since we are going to replace
|
|
// the frame's client area anyway
|
|
Invalidate();
|
|
SetMenu(NULL);
|
|
m_nIdleFlags &= ~idleMenu; // avoid any idle menu processing
|
|
}
|
|
|
|
// Save the accelerator table and remove it.
|
|
pState->hAccelTable = m_hAccelTable;
|
|
m_hAccelTable = NULL;
|
|
LoadAccelTable(MAKEINTRESOURCE(AFX_IDR_PREVIEW_ACCEL));
|
|
|
|
// Make room for the PreviewView by changing AFX_IDW_PANE_FIRST's ID
|
|
// to AFX_IDW_PREVIEW_FIRST
|
|
if (pState->nIDMainPane != AFX_IDW_PANE_FIRST)
|
|
hWnd = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_FIRST);
|
|
if (hWnd != NULL)
|
|
_AfxSetDlgCtrlID(hWnd, AFX_IDW_PANE_SAVE);
|
|
|
|
#ifdef _DEBUG
|
|
if ((::GetWindowLong(m_hWnd, GWL_STYLE) & (WS_HSCROLL|WS_VSCROLL)) != 0)
|
|
TRACE0("Warning: scroll bars in frame windows may cause unusual behaviour.\n");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Leaving Preview
|
|
m_lpfnCloseProc = NULL;
|
|
|
|
// shift original AFX_IDW_PANE_FIRST back to its rightful ID
|
|
HWND hWnd = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_SAVE);
|
|
if (hWnd != NULL)
|
|
{
|
|
HWND hWndTemp = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_FIRST);
|
|
if (hWndTemp != NULL)
|
|
_AfxSetDlgCtrlID(hWndTemp, AFX_IDW_PANE_SAVE);
|
|
_AfxSetDlgCtrlID(hWnd, AFX_IDW_PANE_FIRST);
|
|
}
|
|
|
|
// put the menu back in place if it was removed before
|
|
if (pState->hMenu != NULL)
|
|
{
|
|
// Invalidate before SetMenu since we are going to replace
|
|
// the frame's client area anyway
|
|
Invalidate();
|
|
::SetMenu(m_hWnd, pState->hMenu);
|
|
}
|
|
|
|
// recalc layout now, before showing the main pane
|
|
#ifndef _AFX_NO_OLE_SUPPORT
|
|
if (pActiveFrame->m_pNotifyHook != NULL)
|
|
pActiveFrame->m_pNotifyHook->OnDocActivate(TRUE);
|
|
#endif
|
|
RecalcLayout();
|
|
|
|
// now show main pane that was hidden
|
|
if (pState->nIDMainPane != AFX_IDW_PANE_FIRST)
|
|
hWnd = ::GetDlgItem(m_hWnd, pState->nIDMainPane);
|
|
ASSERT(hWnd != NULL);
|
|
::ShowWindow(hWnd, SW_SHOW);
|
|
|
|
// Restore the Accelerator table
|
|
m_hAccelTable = pState->hAccelTable;
|
|
|
|
// show any modeless dialogs, popup windows, float tools, etc
|
|
ShowOwnedWindows(TRUE);
|
|
}
|
|
}
|
|
|
|
void CFrameWnd::DelayUpdateFrameMenu(HMENU hMenuAlt)
|
|
{
|
|
m_hMenuAlt = hMenuAlt;
|
|
m_nIdleFlags |= idleMenu;
|
|
}
|
|
|
|
void CFrameWnd::OnIdleUpdateCmdUI()
|
|
{
|
|
// update menu if necessary
|
|
if (m_nIdleFlags & idleMenu)
|
|
OnUpdateFrameMenu(m_hMenuAlt);
|
|
|
|
// update title if necessary
|
|
if (m_nIdleFlags & idleTitle)
|
|
OnUpdateFrameTitle(TRUE);
|
|
|
|
// recalc layout if necessary
|
|
if (m_nIdleFlags & idleLayout)
|
|
{
|
|
RecalcLayout(m_nIdleFlags & idleNotify);
|
|
UpdateWindow();
|
|
}
|
|
|
|
// set the current message string if necessary
|
|
if (m_nIDTracking != m_nIDLastMessage)
|
|
{
|
|
SetMessageText(m_nIDTracking);
|
|
ASSERT(m_nIDTracking == m_nIDLastMessage);
|
|
}
|
|
m_nIdleFlags = 0;
|
|
}
|
|
|
|
CFrameWnd* CFrameWnd::GetActiveFrame()
|
|
{
|
|
// by default, the active frame is the frame itself (MDI is different)
|
|
return this;
|
|
}
|
|
|
|
void CFrameWnd::RecalcLayout(BOOL bNotify)
|
|
{
|
|
if (m_bInRecalcLayout)
|
|
return;
|
|
|
|
m_bInRecalcLayout = TRUE;
|
|
// clear idle flags for recalc layout if called elsewhere
|
|
if (m_nIdleFlags & idleNotify)
|
|
bNotify = TRUE;
|
|
m_nIdleFlags &= ~(idleLayout|idleNotify);
|
|
|
|
#ifndef _AFX_NO_OLE_SUPPORT
|
|
// call the layout hook -- OLE support uses this hook
|
|
if (bNotify && m_pNotifyHook != NULL)
|
|
m_pNotifyHook->OnRecalcLayout();
|
|
#endif
|
|
|
|
// reposition all the child windows (regardless of ID)
|
|
if (GetStyle() & FWS_SNAPTOBARS)
|
|
{
|
|
CRect rect(0, 0, 32767, 32767);
|
|
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery,
|
|
&rect, &rect, FALSE);
|
|
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra,
|
|
&m_rectBorder, &rect, TRUE);
|
|
CalcWindowRect(&rect);
|
|
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(),
|
|
SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
|
|
}
|
|
else
|
|
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder);
|
|
m_bInRecalcLayout = FALSE;
|
|
}
|
|
|
|
// CFrameWnd implementation of OLE border space negotiation
|
|
BOOL CFrameWnd::NegotiateBorderSpace(UINT nBorderCmd, LPRECT lpRectBorder)
|
|
{
|
|
CRect border, request;
|
|
|
|
switch (nBorderCmd)
|
|
{
|
|
case borderGet:
|
|
ASSERT(lpRectBorder != NULL);
|
|
#ifdef _MAC
|
|
if (m_pViewActive->GetParentFrame() == GetTopLevelFrame())
|
|
{
|
|
// SDI
|
|
ASSERT((GetExStyle() & WS_EX_MDIFRAME) == 0);
|
|
|
|
lpRectBorder->left = 0;
|
|
lpRectBorder->top = GetSystemMetrics(SM_CYMENU);
|
|
lpRectBorder->right = GetSystemMetrics(SM_CXSCREEN) - 1;
|
|
lpRectBorder->bottom = GetSystemMetrics(SM_CYSCREEN) - 1 + GetSystemMetrics(SM_CYMENU);
|
|
ScreenToClient((POINT*)lpRectBorder);
|
|
ScreenToClient((POINT*)lpRectBorder + 1);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery,
|
|
lpRectBorder);
|
|
break;
|
|
|
|
case borderRequest:
|
|
return TRUE;
|
|
|
|
case borderSet:
|
|
if (lpRectBorder == NULL)
|
|
{
|
|
if (!m_rectBorder.IsRectNull())
|
|
{
|
|
// releasing all border space -- recalc needed
|
|
#ifdef _MAC
|
|
if (m_pViewActive->GetParentFrame() == GetTopLevelFrame())
|
|
{
|
|
// SDI
|
|
ASSERT((GetExStyle() & WS_EX_MDIFRAME) == 0);
|
|
|
|
CRect rcNew;
|
|
GetWindowRect(&rcNew);
|
|
rcNew += &m_rectBorder;
|
|
m_bInRecalcLayout = TRUE;
|
|
MoveWindow(rcNew);
|
|
m_bInRecalcLayout = FALSE;
|
|
}
|
|
#endif
|
|
m_rectBorder.SetRectEmpty();
|
|
return TRUE;
|
|
}
|
|
// original rect is empty & lpRectBorder is NULL, no recalc needed
|
|
return FALSE;
|
|
}
|
|
if (!_AfxIdenticalRect(m_rectBorder, lpRectBorder))
|
|
{
|
|
// the rects are different -- recalc needed
|
|
#ifdef _MAC
|
|
if (m_pViewActive->GetParentFrame() == GetTopLevelFrame())
|
|
{
|
|
// SDI
|
|
ASSERT((GetExStyle() & WS_EX_MDIFRAME) == 0);
|
|
|
|
CRect rcNew;
|
|
GetWindowRect(&rcNew);
|
|
rcNew += &m_rectBorder;
|
|
rcNew -= lpRectBorder;
|
|
MoveWindow(rcNew);
|
|
m_rectBorder.CopyRect(lpRectBorder);
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
m_rectBorder.CopyRect(lpRectBorder);
|
|
return TRUE;
|
|
}
|
|
return FALSE; // no recalc needed
|
|
|
|
default:
|
|
ASSERT(FALSE); // invalid CFrameWnd::BorderCmd
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CFrameWnd::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CWnd::OnSize(nType, cx, cy); // important for MDI Children
|
|
if (nType != SIZE_MINIMIZED)
|
|
RecalcLayout();
|
|
}
|
|
|
|
BOOL CFrameWnd::OnEraseBkgnd(CDC* pDC)
|
|
{
|
|
if (m_pViewActive != NULL)
|
|
return TRUE; // active view will erase/paint itself
|
|
// for view-less frame just use the default background fill
|
|
return CWnd::OnEraseBkgnd(pDC);
|
|
}
|
|
|
|
|
|
#ifdef _MAC
|
|
// With Macintosh sizeboxes, it's possible for there to be uncovered areas on
|
|
// the frame's client area after RepositionBars. We add this paint handler
|
|
// to redraw only those uncovered areas. Because we may not be a
|
|
// WS_CLIPCHILDREN window, we go to some effort to avoid drawing on top of
|
|
// our children
|
|
void CFrameWnd::OnPaint()
|
|
{
|
|
if (m_pViewActive == NULL)
|
|
{
|
|
CWnd::OnPaint();
|
|
return;
|
|
}
|
|
|
|
CWnd* pWnd;
|
|
CRgn rgnUpdate;
|
|
CRgn rgn;
|
|
CRect rect;
|
|
|
|
CPaintDC dc(this);
|
|
|
|
// compute the area not covered by child windows in screen coordinates
|
|
rect = dc.m_ps.rcPaint;
|
|
ClientToScreen(&rect);
|
|
rgnUpdate.CreateRectRgnIndirect(&rect);
|
|
rgn.CreateRectRgn(0, 0, 0, 0);
|
|
for (pWnd = GetWindow(GW_CHILD); pWnd != NULL;
|
|
pWnd = pWnd->GetWindow(GW_HWNDNEXT))
|
|
{
|
|
pWnd->GetWindowRect(&rect);
|
|
rgn.SetRectRgn(&rect);
|
|
if (rgnUpdate.CombineRgn(&rgnUpdate, &rgn, RGN_DIFF) == NULLREGION)
|
|
return;
|
|
}
|
|
|
|
// convert the bounding box of the uncovered region into client
|
|
// coordinates and fill it with a nice color
|
|
rgnUpdate.GetRgnBox(&rect);
|
|
BOOL bMono = AfxCheckMonochrome(&rect);
|
|
ScreenToClient(&rect);
|
|
dc.FillSolidRect(rect, bMono ? RGB(0xFF, 0xFF, 0xFF) : afxData.clrBtnFace);
|
|
}
|
|
#endif
|
|
|
|
|
|
void CFrameWnd::ActivateFrame(int nCmdShow)
|
|
// nCmdShow is the normal show mode this frame should be in
|
|
{
|
|
// translate default nCmdShow (-1)
|
|
if (nCmdShow == -1)
|
|
{
|
|
if (!IsWindowVisible())
|
|
nCmdShow = SW_SHOWNORMAL;
|
|
else if (IsIconic())
|
|
nCmdShow = SW_RESTORE;
|
|
}
|
|
|
|
// bring to top before showing
|
|
BringToTop(nCmdShow);
|
|
|
|
if (nCmdShow != -1)
|
|
{
|
|
// show the window as specified
|
|
ShowWindow(nCmdShow);
|
|
|
|
// and finally, bring to top after showing
|
|
BringToTop(nCmdShow);
|
|
}
|
|
}
|
|
|
|
void CFrameWnd::BringToTop(int nCmdShow)
|
|
{
|
|
// place the window on top except for certain nCmdShow
|
|
if (nCmdShow != SW_HIDE &&
|
|
nCmdShow != SW_MINIMIZE && nCmdShow != SW_SHOWMINNOACTIVE &&
|
|
nCmdShow != SW_SHOWNA && nCmdShow != SW_SHOWNOACTIVATE)
|
|
{
|
|
// if no last active popup, it will return m_hWnd
|
|
HWND hWndLastPop = ::GetLastActivePopup(m_hWnd);
|
|
::BringWindowToTop(hWndLastPop);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFrameWnd Diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CFrameWnd::AssertValid() const
|
|
{
|
|
CWnd::AssertValid();
|
|
if (m_pViewActive != NULL)
|
|
ASSERT_VALID(m_pViewActive);
|
|
}
|
|
|
|
void CFrameWnd::Dump(CDumpContext& dc) const
|
|
{
|
|
CWnd::Dump(dc);
|
|
|
|
dc << "m_hAccelTable = " << (UINT)m_hAccelTable;
|
|
dc << "\nm_nWindow = " << m_nWindow;
|
|
dc << "\nm_nIDHelp = " << m_nIDHelp;
|
|
dc << "\nm_nIDTracking = " << m_nIDTracking;
|
|
dc << "\nm_nIDLastMessage = " << m_nIDLastMessage;
|
|
if (m_pViewActive != NULL)
|
|
dc << "\nwith active view: " << m_pViewActive;
|
|
else
|
|
dc << "\nno active view";
|
|
|
|
dc << "\n";
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CControlBar segmentation
|
|
|
|
CFrameWnd* CControlBar::GetDockingFrame() const
|
|
{
|
|
CFrameWnd* pFrameWnd = GetParentFrame();
|
|
if (pFrameWnd == NULL)
|
|
pFrameWnd = m_pDockSite;
|
|
|
|
ASSERT(pFrameWnd != NULL);
|
|
ASSERT_KINDOF(CFrameWnd, pFrameWnd);
|
|
return pFrameWnd;
|
|
}
|
|
|
|
BOOL CControlBar::IsFloating() const
|
|
{
|
|
if (IsDockBar())
|
|
return ((CDockBar*)this)->m_bFloating;
|
|
else
|
|
return m_pDockBar != NULL && m_pDockBar->m_bFloating;
|
|
}
|
|
|
|
#ifdef AFX_INIT_SEG
|
|
#pragma code_seg(AFX_INIT_SEG)
|
|
#endif
|
|
|
|
// in this file for IsKindOf library granularity (IsKindOf references these)
|
|
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
|
|
IMPLEMENT_DYNAMIC(CView, CWnd)
|
|
IMPLEMENT_DYNAMIC(CControlBar, CWnd)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|