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.
1938 lines
46 KiB
1938 lines
46 KiB
#include "precomp.h"
|
|
#define __MARS_INLINE_FAST_IS_EQUAL_GUID
|
|
#include "mcinc.h"
|
|
#include "marswin.h"
|
|
#include <exdispid.h>
|
|
#include "parser\marsload.h"
|
|
#include "panel.h"
|
|
#include "place.h"
|
|
#include <strsafe.h>
|
|
|
|
// CLASS_CMarsWindow = {172AF160-5CD4-11d3-97FA-00C04F45D0B3}
|
|
const GUID CLASS_CMarsWindow = { 0x172af160, 0x5cd4, 0x11d3, { 0x97, 0xfa, 0x0, 0xc0, 0x4f, 0x45, 0xd0, 0xb3 } };
|
|
|
|
// CLASS_CMarsDocument = {E0C4E3A8-20D6-47d6-87FB-0A43452117BA}
|
|
const GUID CLASS_CMarsDocument = { 0xe0c4e3a8, 0x20d6, 0x47d6, { 0x87, 0xfb, 0xa, 0x43, 0x45, 0x21, 0x17, 0xba } };
|
|
|
|
|
|
#define WZ_WINDOWPLACEMENT L"WindowPlacement\\%d_%d_%s"
|
|
#define WZ_POSITIONMAX L"Maximized"
|
|
#define WZ_POSITIONRECT L"Rect"
|
|
|
|
static void combineMin( long& out, long in1, long in2 )
|
|
{
|
|
if(in1 > 0)
|
|
{
|
|
out = (in2 > 0) ? in2 + in1 : in1;
|
|
}
|
|
else
|
|
{
|
|
out = in2;
|
|
}
|
|
}
|
|
|
|
static void combineMax( long& out, long in1, long in2 )
|
|
{
|
|
if(in1 < 0 || in2 < 0)
|
|
{
|
|
out = -1; // Don't care...
|
|
}
|
|
else
|
|
{
|
|
out = in2 + in1;
|
|
}
|
|
}
|
|
|
|
static void selectMin( long& out, long in1, long in2 )
|
|
{
|
|
if(in1 < 0)
|
|
{
|
|
out = in2;
|
|
}
|
|
else if(in2 < 0)
|
|
{
|
|
out = in1;
|
|
}
|
|
else
|
|
{
|
|
out = max( in1, in2 );
|
|
}
|
|
}
|
|
|
|
static void selectMax( long& out, long in1, long in2 )
|
|
{
|
|
if(in1 < 0)
|
|
{
|
|
out = in2;
|
|
}
|
|
else if(in2 < 0)
|
|
{
|
|
out = in1;
|
|
}
|
|
else
|
|
{
|
|
out = min( in1, in2 );
|
|
}
|
|
}
|
|
|
|
static BOOL WriteWindowPosition(CRegistryKey ®key, RECT *prc, BOOL fMaximized)
|
|
{
|
|
return ERROR_SUCCESS == regkey.SetBoolValue(fMaximized, WZ_POSITIONMAX)
|
|
&& ERROR_SUCCESS == regkey.SetBinaryValue(prc, sizeof(*prc), WZ_POSITIONRECT);
|
|
}
|
|
|
|
|
|
|
|
//==================================================================
|
|
//
|
|
// CMarsDocument implementation
|
|
//
|
|
//==================================================================
|
|
|
|
CMarsDocument::CMarsDocument()
|
|
{
|
|
}
|
|
|
|
CMarsDocument::~CMarsDocument()
|
|
{
|
|
}
|
|
|
|
HRESULT CMarsWindow::Passivate()
|
|
{
|
|
return CMarsComObject::Passivate();
|
|
}
|
|
|
|
HRESULT CMarsDocument::DoPassivate()
|
|
{
|
|
m_spPanels.PassivateAndRelease();
|
|
m_spPlaces.PassivateAndRelease();
|
|
|
|
m_spMarsWindow.Release();
|
|
m_spHostPanel.Release();
|
|
m_cwndDocument.Detach();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
IMPLEMENT_ADDREF_RELEASE(CMarsDocument);
|
|
|
|
STDMETHODIMP CMarsDocument::QueryInterface(REFIID iid, void **ppvObject)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ATLASSERT(ppvObject);
|
|
|
|
if(iid == IID_IUnknown ||
|
|
iid == IID_IServiceProvider )
|
|
{
|
|
*ppvObject = SAFECAST(this, IServiceProvider *);
|
|
}
|
|
else if(iid == CLASS_CMarsDocument)
|
|
{
|
|
*ppvObject = SAFECAST(this, CMarsDocument *);
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
}
|
|
|
|
if(*ppvObject)
|
|
{
|
|
AddRef();
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CMarsDocument::Init(CMarsWindow *pMarsWindow, CMarsPanel *pHostPanel)
|
|
{
|
|
ATLASSERT(pMarsWindow);
|
|
|
|
m_spMarsWindow = pMarsWindow;
|
|
|
|
m_spHostPanel = pHostPanel;
|
|
|
|
if(pHostPanel)
|
|
{
|
|
m_cwndDocument.Attach(m_spHostPanel->Window()->m_hWnd);
|
|
}
|
|
else
|
|
{
|
|
m_cwndDocument.Attach(m_spMarsWindow->m_hWnd);
|
|
}
|
|
|
|
m_spPlaces.Attach(new CPlaceCollection(this));
|
|
m_spPanels.Attach(new CPanelCollection(this));
|
|
|
|
return (m_spMarsWindow && m_spPanels && m_spPlaces) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
// static
|
|
HRESULT CMarsDocument::CreateInstance(CMarsWindow *pMarsWindow, CMarsPanel *pHostPanel, CMarsDocument **ppObj)
|
|
{
|
|
ATLASSERT(pMarsWindow && ppObj && (*ppObj==NULL));
|
|
|
|
*ppObj=NULL;
|
|
|
|
if(pMarsWindow)
|
|
{
|
|
CMarsDocument *pDoc;
|
|
|
|
pDoc = new CMarsDocument();
|
|
|
|
if(pDoc)
|
|
{
|
|
if(SUCCEEDED(pDoc->Init(pMarsWindow, pHostPanel)))
|
|
{
|
|
*ppObj = pDoc;
|
|
}
|
|
else
|
|
{
|
|
pDoc->Passivate();
|
|
pDoc->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
return (*ppObj) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
// IServiceProvider
|
|
HRESULT CMarsDocument::QueryService(REFGUID guidService, REFIID riid, void **ppv)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
*ppv = NULL;
|
|
|
|
if(!IsPassive())
|
|
{
|
|
if(guidService == SID_SMarsDocument)
|
|
{
|
|
hr = QueryInterface(riid, ppv);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CMarsDocument::GetPlaces(IMarsPlaceCollection **ppPlaces)
|
|
{
|
|
ATLASSERT(ppPlaces);
|
|
ATLASSERT(!IsPassive());
|
|
|
|
if(m_spPlaces)
|
|
{
|
|
return m_spPlaces.QueryInterface(ppPlaces);
|
|
}
|
|
|
|
*ppPlaces = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CMarsDocument::ReadPanelDefinition(LPCWSTR pwszUrl)
|
|
{
|
|
FAIL_AFTER_PASSIVATE();
|
|
|
|
HRESULT hr;
|
|
|
|
GetPanels()->lockLayout();
|
|
|
|
if(pwszUrl)
|
|
{
|
|
hr = CMMFParser::MMFToMars(pwszUrl, this);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
GetPanels()->unlockLayout();
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CMarsDocument::ForwardMessageToChildren(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CPanelCollection* panels = GetPanels();
|
|
|
|
if(panels)
|
|
{
|
|
for(int i=0; i < panels->GetSize(); i++)
|
|
{
|
|
CMarsPanel* pPanel = (*panels)[i];
|
|
|
|
if(pPanel) pPanel->ForwardMessage(uMsg, wParam, lParam);
|
|
}
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
//
|
|
// CMarsWindow implementation
|
|
//
|
|
//==================================================================
|
|
|
|
CMarsWindow::CMarsWindow()
|
|
{
|
|
m_fShowTitleBar = TRUE;
|
|
m_fEnableModeless = TRUE;
|
|
m_fLayoutLocked = FALSE;
|
|
}
|
|
|
|
CMarsWindow::~CMarsWindow()
|
|
{
|
|
if(m_hAccel)
|
|
{
|
|
DestroyAcceleratorTable(m_hAccel);
|
|
}
|
|
}
|
|
|
|
HRESULT CMarsWindow::DoPassivate()
|
|
{
|
|
(void)NotifyHost(MARSHOST_ON_WIN_PASSIVATE, SAFECAST(this, IMarsWindowOM *), 0);
|
|
|
|
CMarsDocument::DoPassivate();
|
|
|
|
if(IsWindow())
|
|
{
|
|
DestroyWindow();
|
|
}
|
|
|
|
m_spMarsHost.Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
IMPLEMENT_ADDREF_RELEASE(CMarsWindow);
|
|
|
|
STDMETHODIMP CMarsWindow::QueryInterface(REFIID iid, void **ppvObject)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ATLASSERT(ppvObject);
|
|
|
|
if(iid == IID_IMarsWindowOM ||
|
|
iid == IID_IDispatch ||
|
|
iid == IID_IUnknown )
|
|
{
|
|
*ppvObject = SAFECAST(this, IMarsWindowOM *);
|
|
}
|
|
else if(iid == IID_IOleWindow ||
|
|
iid == IID_IOleInPlaceUIWindow ||
|
|
iid == IID_IOleInPlaceFrame )
|
|
{
|
|
*ppvObject = SAFECAST(this, IOleInPlaceFrame *);
|
|
}
|
|
else if(iid == IID_IServiceProvider)
|
|
{
|
|
*ppvObject = SAFECAST(this, IServiceProvider *);
|
|
}
|
|
else if(iid == IID_IProfferService)
|
|
{
|
|
*ppvObject = SAFECAST(this, IProfferService *);
|
|
}
|
|
else if(iid == CLASS_CMarsWindow)
|
|
{
|
|
*ppvObject = SAFECAST(this, CMarsWindow *);
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
}
|
|
|
|
if(*ppvObject)
|
|
{
|
|
AddRef();
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = CMarsDocument::QueryInterface(iid, ppvObject);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Static creation function
|
|
//
|
|
HRESULT CMarsWindow::CreateInstance(IMarsHost *pMarsHost, MARSTHREADPARAM *pThreadParam, CMarsWindow **ppObj)
|
|
{
|
|
ATLASSERT(pThreadParam && ppObj && (*ppObj==NULL));
|
|
|
|
*ppObj=NULL;
|
|
|
|
if(pThreadParam)
|
|
{
|
|
CComClassPtr<CMarsWindow> spWin;
|
|
|
|
spWin.Attach(new CMarsWindow());
|
|
|
|
if(spWin)
|
|
{
|
|
if(pThreadParam->pwszFirstPlace)
|
|
{
|
|
spWin->m_bstrFirstPlace = pThreadParam->pwszFirstPlace;
|
|
}
|
|
|
|
if(SUCCEEDED(spWin->Init(pMarsHost, pThreadParam)) &&
|
|
SUCCEEDED(spWin->Startup() ) )
|
|
{
|
|
*ppObj = spWin.Detach();
|
|
}
|
|
else
|
|
{
|
|
spWin.PassivateAndRelease();
|
|
}
|
|
}
|
|
}
|
|
|
|
return (*ppObj) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
HRESULT CMarsWindow::Init(IMarsHost *pMarsHost, MARSTHREADPARAM *pThreadParam)
|
|
{
|
|
HRESULT hr;
|
|
|
|
m_pThreadParam = pThreadParam;
|
|
m_spMarsHost = pMarsHost;
|
|
|
|
Create(NULL,
|
|
rcDefault,
|
|
GetThreadParam()->pwszTitle,
|
|
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN
|
|
);
|
|
|
|
hr = CMarsDocument::Init(this, NULL);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
CGlobalSettingsRegKey regkey;
|
|
WINDOWPLACEMENT wp; wp.length = sizeof(wp);
|
|
BOOL fMaximized;
|
|
|
|
GetWindowPlacement( &wp );
|
|
|
|
if(GetThreadParam()->dwFlags & MTF_MANAGE_WINDOW_SIZE)
|
|
{
|
|
if(InitWindowPosition( regkey, FALSE ))
|
|
{
|
|
LoadWindowPosition( regkey, TRUE, wp, fMaximized );
|
|
}
|
|
}
|
|
|
|
if(SUCCEEDED(NotifyHost( MARSHOST_ON_WIN_SETPOS, SAFECAST(this, IMarsWindowOM *), (LPARAM)&wp )))
|
|
{
|
|
// Always make sure the window is fully on-screen
|
|
BoundWindowRectToMonitor( m_hWnd, &wp.rcNormalPosition );
|
|
}
|
|
|
|
if(wp.showCmd == SW_MAXIMIZE)
|
|
{
|
|
m_fStartMaximized = true;
|
|
}
|
|
wp.showCmd = SW_HIDE;
|
|
|
|
//// if(GetThreadParam()->dwFlags & MTF_DONT_SHOW_WINDOW)
|
|
//// {
|
|
//// wp.showCmd = SW_HIDE;
|
|
//// }
|
|
|
|
if(GetThreadParam()->dwFlags & MTF_MANAGE_WINDOW_SIZE)
|
|
{
|
|
// Make the next Mars window try and appear at the current location.
|
|
WriteWindowPosition( regkey, &wp.rcNormalPosition, fMaximized );
|
|
}
|
|
|
|
SetWindowPlacement( &wp );
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = NotifyHost( MARSHOST_ON_WIN_INIT, SAFECAST(this, IMarsWindowOM *), (LPARAM)m_hWnd );
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = ReadPanelDefinition(GetThreadParam()->pwszPanelURL);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CMarsWindow::Startup()
|
|
{
|
|
HRESULT hr;
|
|
|
|
if(SUCCEEDED(hr = NotifyHost( MARSHOST_ON_WIN_READY, SAFECAST(this, IMarsWindowOM *), 0 )))
|
|
{
|
|
if(hr == S_FALSE)
|
|
{
|
|
; // Host has taken care of the startup.
|
|
}
|
|
else
|
|
{
|
|
CComClassPtr<CMarsPlace> spPlace;
|
|
|
|
if(SUCCEEDED(hr = GetPlaces()->GetPlace( m_bstrFirstPlace, &spPlace )))
|
|
{
|
|
hr = spPlace->transitionTo();
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// IServiceProvider
|
|
HRESULT CMarsWindow::QueryService(REFGUID guidService, REFIID riid, void **ppv)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
*ppv = NULL;
|
|
|
|
if(!IsPassive())
|
|
{
|
|
if(guidService == SID_SProfferService ||
|
|
guidService == SID_SMarsWindow ||
|
|
guidService == SID_STopWindow )
|
|
{
|
|
hr = QueryInterface(riid, ppv);
|
|
}
|
|
else
|
|
{
|
|
hr = IProfferServiceImpl::QueryService(guidService, riid, ppv);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
hr = CMarsDocument::QueryService(guidService, riid, ppv);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
hr = IUnknown_QueryService(m_spMarsHost, guidService, riid, ppv);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// IMarsWindowOM
|
|
STDMETHODIMP CMarsWindow::get_active(VARIANT_BOOL *pbActive)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr( pbActive ))
|
|
{
|
|
if(VerifyNotPassive( &hr ))
|
|
{
|
|
*pbActive = VARIANT_BOOLIFY(IsWindowActive());
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
*pbActive = VARIANT_FALSE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_minimized(VARIANT_BOOL *pbMinimized)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr( pbMinimized ))
|
|
{
|
|
if(VerifyNotPassive( &hr ))
|
|
{
|
|
*pbMinimized = IsIconic() ? VARIANT_TRUE : VARIANT_FALSE;
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
*pbMinimized = VARIANT_FALSE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::put_minimized(VARIANT_BOOL bMinimized)
|
|
{
|
|
ATLASSERT(IsValidVariantBoolVal(bMinimized));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if(VerifyNotPassive( &hr ))
|
|
{
|
|
if(!!IsIconic() != !!bMinimized)
|
|
{
|
|
SendMessage(WM_SYSCOMMAND, (bMinimized ? SC_MINIMIZE : SC_RESTORE), 0);
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_maximized(VARIANT_BOOL *pbMaximized)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr( pbMaximized ))
|
|
{
|
|
if(VerifyNotPassive( &hr ))
|
|
{
|
|
*pbMaximized = IsZoomed() ? VARIANT_TRUE : VARIANT_FALSE;
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
*pbMaximized = VARIANT_FALSE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::put_maximized(VARIANT_BOOL bMaximized)
|
|
{
|
|
ATLASSERT(IsValidVariantBoolVal(bMaximized));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if(VerifyNotPassive( &hr ))
|
|
{
|
|
DWORD dwStyle = ::GetWindowLong( m_hWnd, GWL_STYLE );
|
|
DWORD dwNewStyle = dwStyle | (WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX);
|
|
|
|
if(dwStyle != dwNewStyle)
|
|
{
|
|
::SetWindowLong( m_hWnd, GWL_STYLE, dwNewStyle );
|
|
}
|
|
|
|
if(!!IsZoomed() != !!bMaximized)
|
|
{
|
|
SendMessage(WM_SYSCOMMAND, (bMaximized ? SC_MAXIMIZE : SC_RESTORE), 0);
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_title(BSTR *pbstrTitle)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(pbstrTitle))
|
|
{
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
int nLen = (int)SendMessage(WM_GETTEXTLENGTH, 0, 0);
|
|
|
|
// SysAllocStringLen adds 1 for the NULL terminator
|
|
*pbstrTitle = SysAllocStringLen(NULL, nLen);
|
|
|
|
if(*pbstrTitle)
|
|
{
|
|
GetWindowText(*pbstrTitle, nLen + 1);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pbstrTitle = NULL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::put_title(BSTR bstrTitle)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidBstr(bstrTitle))
|
|
{
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
// TODO: If the text is not displayable with the current system font
|
|
// we need to come up with something legible.
|
|
SetWindowText(bstrTitle);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_height(long *plHeight)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(plHeight))
|
|
{
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
hr = SCRIPT_ERROR;
|
|
RECT rc;
|
|
|
|
if(GetWindowRect(&rc))
|
|
{
|
|
*plHeight = RECTHEIGHT(rc);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::put_height(long lHeight)
|
|
{
|
|
HRESULT hr = SCRIPT_ERROR;
|
|
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
RECT rc;
|
|
|
|
if(GetWindowRect( &rc ) && SetWindowPos( NULL, 0, 0, RECTWIDTH(rc), lHeight, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE ))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_width(long *plWidth)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(plWidth))
|
|
{
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
hr = SCRIPT_ERROR;
|
|
RECT rc;
|
|
|
|
if(GetWindowRect(&rc))
|
|
{
|
|
*plWidth = RECTWIDTH(rc);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::put_width(long lWidth)
|
|
{
|
|
HRESULT hr = SCRIPT_ERROR;
|
|
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
RECT rc;
|
|
|
|
if(GetWindowRect( &rc ) && SetWindowPos( NULL, 0, 0, lWidth, RECTHEIGHT(rc), SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE ))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_x(long *plX)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(plX))
|
|
{
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
hr = SCRIPT_ERROR;
|
|
RECT rc;
|
|
|
|
if(GetWindowRect(&rc))
|
|
{
|
|
*plX = rc.left;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::put_x(long lX)
|
|
{
|
|
HRESULT hr = SCRIPT_ERROR;
|
|
|
|
if(VerifyNotPassive( &hr ))
|
|
{
|
|
RECT rc;
|
|
|
|
if(GetWindowRect( &rc ) && SetWindowPos( NULL, lX, rc.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE ))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_y(long *plY)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(plY))
|
|
{
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
hr = SCRIPT_ERROR;
|
|
RECT rc;
|
|
|
|
if(GetWindowRect(&rc))
|
|
{
|
|
*plY = rc.top;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::put_y(long lY)
|
|
{
|
|
HRESULT hr = SCRIPT_ERROR;
|
|
|
|
if(VerifyNotPassive( &hr ))
|
|
{
|
|
RECT rc;
|
|
|
|
if(GetWindowRect( &rc ) && SetWindowPos( NULL, rc.left, lY, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE ))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_visible(VARIANT_BOOL *pbVisible)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(pbVisible))
|
|
{
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
*pbVisible = IsWindowVisible() ? VARIANT_TRUE : VARIANT_FALSE;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::put_visible(VARIANT_BOOL bVisible)
|
|
{
|
|
HRESULT hr = SCRIPT_ERROR;
|
|
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
if(bVisible)
|
|
{
|
|
if(m_fUIPanelsReady)
|
|
{
|
|
DoShowWindow(SW_SHOW);
|
|
}
|
|
else
|
|
{
|
|
// Our UI hasn't finished loading yet so showing the window
|
|
// now is ugly. We'll remember this put_visible was done, and
|
|
// show the window when the UI panels have fully loaded.
|
|
|
|
m_fDeferMakeVisible = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DoShowWindow(SW_HIDE);
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_panels(IMarsPanelCollection **ppPanels)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(ppPanels))
|
|
{
|
|
*ppPanels = NULL;
|
|
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
hr = GetPanels()->QueryInterface(IID_IMarsPanelCollection, (void **)ppPanels);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::get_places(IMarsPlaceCollection **ppPlaces)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(ppPlaces))
|
|
{
|
|
*ppPlaces = NULL;
|
|
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
hr = GetPlaces()->QueryInterface(IID_IMarsPlaceCollection, (void **)ppPlaces);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::setWindowDimensions( /*[in]*/ long lX, /*[in]*/ long lY, /*[in]*/ long lW, /*[in]*/ long lH )
|
|
{
|
|
HRESULT hr = SCRIPT_ERROR;
|
|
|
|
if(VerifyNotPassive( &hr ))
|
|
{
|
|
if(SetWindowPos(NULL, lX, lY, lW, lH, SWP_NOACTIVATE | SWP_NOZORDER))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::close()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(VerifyNotPassive(&hr))
|
|
{
|
|
PostMessage(WM_CLOSE, 0, 0);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::refreshLayout()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(VerifyNotPassive( &hr ))
|
|
{
|
|
CPanelCollection *panels = GetPanels();
|
|
|
|
if(panels) panels->Layout();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
//------------------------------------------------------------------------------
|
|
|
|
// IOleWindow
|
|
STDMETHODIMP CMarsWindow::GetWindow(HWND *phwnd)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if(API_IsValidWritePtr(phwnd))
|
|
{
|
|
if(IsWindow())
|
|
{
|
|
*phwnd = m_hWnd;
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
*phwnd = NULL;
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::ContextSensitiveHelp(BOOL fEnterMode)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// IOleInPlaceUIWindow
|
|
STDMETHODIMP CMarsWindow::GetBorder(LPRECT lprectBorder)
|
|
{
|
|
ATLASSERT(lprectBorder);
|
|
|
|
// We don't negotiate any toolbar space -- if they want screen real estate
|
|
// they won't get it from us willingly.
|
|
return INPLACE_E_NOTOOLSPACE;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::RequestBorderSpace(LPCBORDERWIDTHS pborderwidths)
|
|
{
|
|
ATLASSERT(pborderwidths);
|
|
|
|
// Look buddy, we told you before -- we ain't giving you any of our pixels.
|
|
return INPLACE_E_NOTOOLSPACE;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::SetBorderSpace(LPCBORDERWIDTHS pborderwidths)
|
|
{
|
|
ATLASSERT(pborderwidths);
|
|
|
|
// Pushy OLE object wouldn't ya say?
|
|
return E_UNEXPECTED; // return E_BITEME;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
|
|
{
|
|
// REVIEW: Maybe this is how a panel should let us know it's active. We currently track that in
|
|
// the CPanelCollection via SetActivePanel().
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// IOleInPlaceFrame
|
|
STDMETHODIMP CMarsWindow::InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
|
|
{
|
|
// Menus? We don't need no steenkin' menus.
|
|
ATLASSERT(hmenuShared &&
|
|
API_IsValidWritePtr(lpMenuWidths) &&
|
|
(0 == lpMenuWidths->width[0]) &&
|
|
(0 == lpMenuWidths->width[2]) &&
|
|
(0 == lpMenuWidths->width[4]));
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::RemoveMenus(HMENU hmenuShared)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::SetStatusText(LPCOLESTR pszStatusText)
|
|
{
|
|
ATLASSERT((NULL == pszStatusText) || (API_IsValidString(pszStatusText)));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::EnableModeless(BOOL fEnable)
|
|
{
|
|
FAIL_AFTER_PASSIVATE();
|
|
|
|
m_fEnableModeless = BOOLIFY(fEnable);
|
|
return GetPanels()->DoEnableModeless(fEnable);
|
|
}
|
|
|
|
STDMETHODIMP CMarsWindow::TranslateAccelerator(LPMSG lpmsg, WORD wID)
|
|
{
|
|
// REVIEW: Should we make keyboard routing go through here?
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
//==================================================================
|
|
// Window message handlers
|
|
//==================================================================
|
|
LRESULT CMarsWindow::ForwardToMarsHost(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
bHandled = FALSE;
|
|
|
|
if(m_spMarsHost)
|
|
{
|
|
MSG msg;
|
|
|
|
msg.hwnd = m_hWnd;
|
|
msg.message = uMsg;
|
|
msg.wParam = wParam;
|
|
msg.lParam = lParam;
|
|
|
|
if(SUCCEEDED(m_spMarsHost->PreTranslateMessage( &msg )))
|
|
{
|
|
bHandled = TRUE;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
SetIcon(GetThreadParam()->hIcon);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
CPanelCollection *panels = GetPanels(); if(!panels) return 0;
|
|
|
|
switch(wParam)
|
|
{
|
|
case SIZE_MINIMIZED:
|
|
if(!m_fLayoutLocked)
|
|
{
|
|
panels->lockLayout();
|
|
m_fLayoutLocked = TRUE;
|
|
}
|
|
break;
|
|
|
|
case SIZE_MAXIMIZED:
|
|
case SIZE_RESTORED :
|
|
if(m_fLayoutLocked)
|
|
{
|
|
panels->unlockLayout();
|
|
|
|
m_fLayoutLocked = FALSE;
|
|
}
|
|
// Fall through...
|
|
|
|
default:
|
|
panels->Layout();
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
if(GetThreadParam()->dwFlags & MTF_MANAGE_WINDOW_SIZE)
|
|
{
|
|
CGlobalSettingsRegKey regkey;
|
|
|
|
if(InitWindowPosition( regkey, TRUE ))
|
|
{
|
|
SaveWindowPosition( regkey );
|
|
}
|
|
}
|
|
|
|
Passivate();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnNCActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
LRESULT lResult;
|
|
|
|
if(!m_fShowTitleBar && !IsIconic())
|
|
{
|
|
lResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
lResult = DefWindowProc(uMsg, wParam, lParam);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
WORD wActive = LOWORD(wParam);
|
|
|
|
if(wActive == WA_INACTIVE)
|
|
{
|
|
//
|
|
// If we are the active window, remember the focus location, to restore it later.
|
|
//
|
|
if(m_fActiveWindow)
|
|
{
|
|
if(!IsPassive()) m_hwndFocus = GetFocus();
|
|
|
|
m_fActiveWindow = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_fActiveWindow = TRUE;
|
|
}
|
|
|
|
bHandled = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
MINMAXINFO *pInfo = (MINMAXINFO *)lParam;
|
|
CPanelCollection *spPanels = GetPanels();
|
|
|
|
if(spPanels)
|
|
{
|
|
long lAdjustWidth;
|
|
long lAdjustHeight;
|
|
POINT ptMin;
|
|
POINT ptMax;
|
|
RECT rcClient;
|
|
RECT rcWindow;
|
|
|
|
|
|
GetMinMaxInfo( spPanels, 0, ptMin, ptMax );
|
|
|
|
|
|
GetClientRect( &rcClient );
|
|
GetWindowRect( &rcWindow );
|
|
|
|
lAdjustWidth = (rcWindow.right - rcWindow.left) - (rcClient.right - rcClient.left);
|
|
lAdjustHeight = (rcWindow.bottom - rcWindow.top ) - (rcClient.bottom - rcClient.top );
|
|
|
|
if(ptMin.x >= 0) pInfo->ptMinTrackSize.x = ptMin.x + lAdjustWidth ;
|
|
if(ptMin.y >= 0) pInfo->ptMinTrackSize.y = ptMin.y + lAdjustHeight;
|
|
|
|
if(ptMax.x >= 0) pInfo->ptMaxTrackSize.x = ptMax.x + lAdjustWidth ;
|
|
if(ptMax.y >= 0) pInfo->ptMaxTrackSize.y = ptMax.y + lAdjustHeight;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CMarsWindow::GetMinMaxInfo( CPanelCollection *spPanels, int index, POINT& ptMin, POINT& ptMax )
|
|
{
|
|
ptMin.x = -1;
|
|
ptMin.y = -1;
|
|
ptMax.x = -1;
|
|
ptMax.y = -1;
|
|
|
|
if(spPanels && index < spPanels->GetSize())
|
|
{
|
|
CMarsPanel* pPanel = (*spPanels)[index++];
|
|
|
|
if(pPanel)
|
|
{
|
|
PANEL_POSITION pos = pPanel->GetPosition();
|
|
if(pos != PANEL_POPUP)
|
|
{
|
|
if(pPanel->IsVisible())
|
|
{
|
|
POINT ptOurMin;
|
|
POINT ptOurMax;
|
|
POINT ptSubMin;
|
|
POINT ptSubMax;
|
|
|
|
pPanel->GetMinMaxInfo( ptOurMin, ptOurMax );
|
|
GetMinMaxInfo( spPanels, index, ptSubMin, ptSubMax );
|
|
|
|
|
|
if(pos == PANEL_BOTTOM || pos == PANEL_TOP)
|
|
{
|
|
selectMin( ptMin.x, ptOurMin.x, ptSubMin.x );
|
|
selectMax( ptMax.x, ptOurMax.x, ptSubMax.x );
|
|
}
|
|
else
|
|
{
|
|
combineMin( ptMin.x, ptOurMin.x, ptSubMin.x );
|
|
combineMax( ptMax.x, ptOurMax.x, ptSubMax.x );
|
|
}
|
|
|
|
if(pos == PANEL_LEFT || pos == PANEL_RIGHT)
|
|
{
|
|
selectMin( ptMin.y, ptOurMin.y, ptSubMin.y );
|
|
selectMax( ptMax.y, ptOurMax.y, ptSubMax.y );
|
|
}
|
|
else
|
|
{
|
|
combineMin( ptMin.y, ptOurMin.y, ptSubMin.y );
|
|
combineMax( ptMax.y, ptOurMax.y, ptSubMax.y );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetMinMaxInfo( spPanels, index, ptMin, ptMax );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CMarsWindow::CanLayout( /*[in/out]*/ RECT rcClient )
|
|
{
|
|
CPanelCollection *spPanels = GetPanels();
|
|
|
|
if(spPanels)
|
|
{
|
|
for(int i=0; i<spPanels->GetSize(); i++)
|
|
{
|
|
CMarsPanel* pPanel = (*spPanels)[i];
|
|
POINT ptDiff;
|
|
|
|
if(pPanel->CanLayout( rcClient, ptDiff ) == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CMarsWindow::FixLayout( /*[in/out]*/ RECT rcClient )
|
|
{
|
|
CPanelCollection *spPanels = GetPanels();
|
|
|
|
if(spPanels)
|
|
{
|
|
POINT ptDiff;
|
|
|
|
FixLayout( spPanels, 0, rcClient, ptDiff );
|
|
}
|
|
}
|
|
|
|
void CMarsWindow::FixLayout( CPanelCollection *spPanels, int index, RECT rcClient, POINT& ptDiff )
|
|
{
|
|
ptDiff.x = 0;
|
|
ptDiff.y = 0;
|
|
|
|
if(index < spPanels->GetSize())
|
|
{
|
|
CMarsPanel* pPanel = (*spPanels)[index++];
|
|
PANEL_POSITION pos = pPanel->GetPosition();
|
|
RECT rcClient2 = rcClient;
|
|
POINT ptSubDiff;
|
|
|
|
//
|
|
// First round, try to fix first ourselves and then lets the other fix themselves.
|
|
//
|
|
if(pPanel->CanLayout( rcClient2, ptDiff ) == false)
|
|
{
|
|
if(pos == PANEL_BOTTOM || pos == PANEL_TOP)
|
|
{
|
|
if(ptDiff.y)
|
|
{
|
|
pPanel->put_height( pPanel->GetHeight() - ptDiff.y );
|
|
}
|
|
}
|
|
|
|
if(pos == PANEL_LEFT || pos == PANEL_RIGHT)
|
|
{
|
|
if(ptDiff.x)
|
|
{
|
|
pPanel->put_width ( pPanel->GetWidth () - ptDiff.x );
|
|
}
|
|
}
|
|
|
|
rcClient2 = rcClient;
|
|
pPanel->CanLayout( rcClient2, ptDiff );
|
|
}
|
|
|
|
FixLayout( spPanels, index, rcClient2, ptSubDiff );
|
|
|
|
//
|
|
// Second round, based on what the other panels need, we adjust.
|
|
//
|
|
if(pos == PANEL_BOTTOM || pos == PANEL_TOP)
|
|
{
|
|
if(ptSubDiff.y)
|
|
{
|
|
pPanel->put_height( pPanel->GetHeight() - ptSubDiff.y );
|
|
}
|
|
}
|
|
|
|
if(pos == PANEL_LEFT || pos == PANEL_RIGHT)
|
|
{
|
|
if(ptSubDiff.x)
|
|
{
|
|
pPanel->put_width ( pPanel->GetWidth () - ptSubDiff.x );
|
|
}
|
|
}
|
|
|
|
|
|
pPanel->CanLayout( rcClient, ptDiff );
|
|
FixLayout( spPanels, index, rcClient2, ptSubDiff );
|
|
|
|
ptDiff.x += ptSubDiff.x;
|
|
ptDiff.y += ptSubDiff.y;
|
|
}
|
|
}
|
|
|
|
|
|
void DrawFrame(HDC hdc, LPRECT prc, HBRUSH hbrColor, int cl)
|
|
{
|
|
HBRUSH hbr;
|
|
int cx, cy;
|
|
RECT rcT;
|
|
|
|
ATLASSERT(NULL != prc);
|
|
|
|
int cyBorder = GetSystemMetrics(SM_CYBORDER);
|
|
int cxBorder = GetSystemMetrics(SM_CXBORDER);
|
|
|
|
rcT = *prc;
|
|
cx = cl * cxBorder;
|
|
cy = cl * cyBorder;
|
|
|
|
hbr = (HBRUSH)SelectObject(hdc, hbrColor);
|
|
|
|
PatBlt(hdc, rcT.left, rcT.top, cx, rcT.bottom - rcT.top, PATCOPY);
|
|
rcT.left += cx;
|
|
|
|
PatBlt(hdc, rcT.left, rcT.top, rcT.right - rcT.left, cy, PATCOPY);
|
|
rcT.top += cy;
|
|
|
|
rcT.right -= cx;
|
|
PatBlt(hdc, rcT.right, rcT.top, cx, rcT.bottom - rcT.top, PATCOPY);
|
|
|
|
rcT.bottom -= cy;
|
|
PatBlt(hdc, rcT.left, rcT.bottom, rcT.right - rcT.left, cy, PATCOPY);
|
|
|
|
SelectObject(hdc, hbr);
|
|
|
|
*prc = rcT;
|
|
}
|
|
|
|
// For now it looks like we can let windows handle this since we are adjusting
|
|
// the client rect ourselves in OnNCCalcSize.
|
|
|
|
LRESULT CMarsWindow::OnNCPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
LRESULT lResult;
|
|
|
|
if(!m_fShowTitleBar)
|
|
{
|
|
HDC hdc = GetDCEx(wParam != 1 ? (HRGN)wParam : NULL, DCX_WINDOW | DCX_INTERSECTRGN);
|
|
if(NULL == hdc)
|
|
{
|
|
hdc = GetWindowDC();
|
|
}
|
|
|
|
RECT rcWindow;
|
|
GetWindowRect(&rcWindow);
|
|
OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top);
|
|
|
|
HBRUSH hbrBorder = CreateSolidBrush(GetSysColor(COLOR_ACTIVEBORDER));
|
|
HBRUSH hbrFrame = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
|
|
|
|
DrawEdge(hdc, &rcWindow, EDGE_RAISED, (BF_RECT | BF_ADJUST));
|
|
|
|
NONCLIENTMETRICSA ncm;
|
|
ncm.cbSize = sizeof(ncm);
|
|
|
|
SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncm), (void *)(LPNONCLIENTMETRICS)&ncm, 0);
|
|
|
|
DrawFrame(hdc, &rcWindow, hbrBorder, ncm.iBorderWidth);
|
|
DrawFrame(hdc, &rcWindow, hbrFrame, 1);
|
|
|
|
DeleteObject(hbrBorder);
|
|
DeleteObject(hbrFrame);
|
|
|
|
ReleaseDC(hdc);
|
|
lResult = 0;
|
|
}
|
|
else
|
|
{
|
|
lResult = DefWindowProc(uMsg, wParam, lParam);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
|
|
BeginPaint(&ps);
|
|
EndPaint(&ps);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnPaletteChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
HWND hwndPaletteChange = (HWND)wParam;
|
|
|
|
// Ignore if we changed the palette
|
|
if(hwndPaletteChange == m_hWnd)
|
|
return 0;
|
|
|
|
// If we are the active window and one of our children set the forground palette
|
|
// we want to avoid realizing our palette in the foreground or we get in a tug-of-war
|
|
// with lots of flashing.
|
|
if(IsChild(hwndPaletteChange) && (m_hWnd == GetForegroundWindow()))
|
|
{
|
|
// Our child caused a palette change so force a redraw to use the
|
|
// new system palette. Children shouldn't do this, bad child!
|
|
RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
|
}
|
|
else
|
|
{
|
|
// Select our foreground palette
|
|
OnQueryNewPalette(uMsg, wParam, lParam, bHandled);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnQueryNewPalette(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
LRESULT lResult = FALSE;
|
|
|
|
// Realize our palette
|
|
if(g_hpalHalftone)
|
|
{
|
|
HDC hDC = GetDC();
|
|
if(hDC)
|
|
{
|
|
if(GetDeviceCaps(hDC, RASTERCAPS) & RC_PALETTE)
|
|
{
|
|
HPALETTE hOldPal = SelectPalette(hDC, g_hpalHalftone, FALSE);
|
|
UINT i = RealizePalette(hDC);
|
|
|
|
// Did the realization change? (We need to always invalidate background windows
|
|
// because when we have multiple windows up only the first top-level
|
|
// window will actually realize any colors. Windows lower in the
|
|
// z-order always get 0 returned from RealizePalette, but they
|
|
// may need repainting! We could further optimize by having the top
|
|
// html window invalidate all the rest when i is non-zero. -- StevePro)
|
|
if(i || (m_hWnd != GetForegroundWindow()))
|
|
{
|
|
// Yes, so force a repaint.
|
|
RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
|
}
|
|
|
|
SelectPalette(hDC, hOldPal, TRUE);
|
|
RealizePalette(hDC);
|
|
// lResult = i;
|
|
lResult = TRUE;
|
|
}
|
|
ReleaseDC(hDC);
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
// We need to update our palette because some of the "reserved" colors may have changed
|
|
HPALETTE hpal = SHCreateShellPalette(NULL);
|
|
hpal = (HPALETTE)InterlockedExchangePointer( (LPVOID*)&g_hpalHalftone, hpal);
|
|
if(hpal)
|
|
{
|
|
DeleteObject(hpal);
|
|
}
|
|
|
|
PostMessage(WM_QUERYNEWPALETTE, 0, (LPARAM) -1);
|
|
|
|
// Trident likes to know about these changes
|
|
ForwardMessageToChildren(uMsg, wParam, lParam);
|
|
|
|
bHandled = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnDisplayChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
return OnSysColorChange(uMsg, wParam, lParam, bHandled);
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
if(wParam == SC_MINIMIZE)
|
|
{
|
|
//
|
|
// If we are the active window, remember the focus location, to restore it later.
|
|
//
|
|
if(m_fActiveWindow)
|
|
{
|
|
if(!IsPassive()) m_hwndFocus = GetFocus();
|
|
|
|
m_fActiveWindow = FALSE;
|
|
}
|
|
}
|
|
|
|
bHandled = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
//
|
|
// If we have a saved focus location, restore it.
|
|
//
|
|
if(m_hwndFocus && m_hwndFocus != m_hWnd)
|
|
{
|
|
::SetFocus( m_hwndFocus );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnNCCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
LRESULT lResult;
|
|
|
|
if(!m_fShowTitleBar && !IsIconic())
|
|
{
|
|
RECT *prc = (RECT *)lParam;
|
|
NONCLIENTMETRICSA ncm;
|
|
|
|
ncm.cbSize = sizeof(ncm);
|
|
|
|
SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE);
|
|
int xDelta = GetSystemMetrics(SM_CXEDGE) + ncm.iBorderWidth + 1;
|
|
int yDelta = GetSystemMetrics(SM_CYEDGE) + ncm.iBorderWidth + 1;
|
|
|
|
InflateRect(prc, -xDelta, -yDelta);
|
|
|
|
lResult = 0;
|
|
}
|
|
else
|
|
{
|
|
lResult = DefWindowProc(uMsg, wParam, lParam);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
LRESULT CMarsWindow::OnSetText(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
// HACK 'O RAMA: Turn off one of the WS_CAPTION style bits (WS_CAPTION == WS_BORDER | WS_DLGFRAME)
|
|
// so that USER32 doesn't try and draw the title bar for us.
|
|
|
|
DWORD dwStyle = GetWindowLong(GWL_STYLE);
|
|
SetWindowLong(GWL_STYLE, dwStyle & ~WS_DLGFRAME);
|
|
|
|
LRESULT lResult = DefWindowProc();
|
|
|
|
SetWindowLong(GWL_STYLE, dwStyle);
|
|
|
|
return lResult;
|
|
}
|
|
|
|
void CMarsWindow::OnFinalMessage(HWND hWnd)
|
|
{
|
|
PostQuitMessage(0);
|
|
}
|
|
|
|
//==================================================================
|
|
// Panel/Place methods
|
|
//==================================================================
|
|
|
|
void CMarsWindow::DoShowWindow(int nCmdShow)
|
|
{
|
|
if(GetThreadParam()->dwFlags & MTF_DONT_SHOW_WINDOW) return;
|
|
|
|
ShowWindow( nCmdShow );
|
|
|
|
// Win95 doesn't let the window from another thread appear in front of an
|
|
// existing window, so we must grab the foreground
|
|
|
|
if(IsWindowVisible())
|
|
{
|
|
SetForegroundWindow(m_hWnd);
|
|
}
|
|
}
|
|
|
|
void CMarsWindow::OnTransitionComplete()
|
|
{
|
|
if(!m_fUIPanelsReady && !IsWindowVisible())
|
|
{
|
|
m_fUIPanelsReady = TRUE;
|
|
|
|
// start with the Mars window host's requested show mode
|
|
int nCmdShow = GetThreadParam()->nCmdShow;
|
|
|
|
if((nCmdShow == SW_HIDE) && m_fDeferMakeVisible)
|
|
{
|
|
// nCmdShow is SW_HIDE to indicate that the window should be shown
|
|
// via put_visible. In this case, someone did a pub_visible(TRUE) before
|
|
// our UI panels were finished loading, so we'll honor the request now.
|
|
|
|
nCmdShow = SW_SHOW;
|
|
}
|
|
|
|
// only promote to maximized state if we are going to become visible
|
|
if((nCmdShow != SW_HIDE) && m_fStartMaximized)
|
|
{
|
|
nCmdShow = SW_MAXIMIZE;
|
|
}
|
|
|
|
DoShowWindow(nCmdShow);
|
|
}
|
|
}
|
|
|
|
HRESULT CMarsWindow::ReleaseOwnedObjects(IUnknown *pUnknownOwner)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
void CMarsWindow::SetFirstPlace( LPCWSTR szPlace )
|
|
{
|
|
if(!m_bstrFirstPlace)
|
|
{
|
|
m_bstrFirstPlace = szPlace;
|
|
}
|
|
}
|
|
|
|
void CMarsWindow::ShowTitleBar(BOOL fShowTitleBar)
|
|
{
|
|
if(!!m_fShowTitleBar != !!fShowTitleBar)
|
|
{
|
|
m_fShowTitleBar = fShowTitleBar ? TRUE : FALSE;
|
|
SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_FRAMECHANGED);
|
|
}
|
|
}
|
|
|
|
BOOL CMarsWindow::TranslateAccelerator(MSG &msg)
|
|
{
|
|
BOOL bProcessed = FALSE;
|
|
|
|
// if(msg.message == WM_SYSKEYDOWN)
|
|
// {
|
|
// switch (msg.wParam)
|
|
// {
|
|
// case VK_LEFT:
|
|
// case VK_RIGHT:
|
|
// GetTravelLog()->travel((msg.wParam == VK_LEFT) ? -1 : 1);
|
|
// bProcessed = TRUE;
|
|
// break;
|
|
// }
|
|
// }
|
|
|
|
return bProcessed;
|
|
}
|
|
|
|
BOOL CMarsWindow::PreTranslateMessage(MSG &msg)
|
|
{
|
|
// Set to TRUE if you don't want this message dispatched normally
|
|
BOOL bProcessed = FALSE;
|
|
|
|
switch (msg.message)
|
|
{
|
|
case WM_SETFOCUS:
|
|
break;
|
|
|
|
default:
|
|
if((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
|
|
{
|
|
// First we take a crack
|
|
bProcessed = TranslateAccelerator(msg);
|
|
|
|
// Now let the active place try
|
|
if(!bProcessed)
|
|
{
|
|
CMarsPlace *pPlace = GetPlaces()->GetCurrentPlace();
|
|
if(NULL != pPlace)
|
|
{
|
|
bProcessed = (pPlace->TranslateAccelerator(&msg) == S_OK);
|
|
}
|
|
}
|
|
}
|
|
else if((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
|
|
{
|
|
if(m_bSingleButtonMouse)
|
|
{
|
|
switch (msg.message)
|
|
{
|
|
case WM_RBUTTONDOWN:
|
|
case WM_MBUTTONDOWN:
|
|
msg.message = WM_LBUTTONDOWN;
|
|
break;
|
|
|
|
case WM_RBUTTONUP:
|
|
case WM_MBUTTONUP:
|
|
msg.message = WM_LBUTTONUP;
|
|
break;
|
|
|
|
case WM_RBUTTONDBLCLK:
|
|
case WM_MBUTTONDBLCLK:
|
|
msg.message = WM_LBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return bProcessed;
|
|
}
|
|
|
|
|
|
bool CMarsWindow::InitWindowPosition( CGlobalSettingsRegKey& regkey, BOOL fWrite )
|
|
{
|
|
WCHAR rgPath[MAX_PATH];
|
|
RECT rc;
|
|
|
|
if(::GetClientRect( ::GetDesktopWindow(), &rc ))
|
|
{
|
|
LPCWSTR szTitle = GetThreadParam()->pwszTitle; if(!szTitle) szTitle = L"<DEFAULT>";
|
|
LONG Screen_width = rc.right - rc.left;
|
|
LONG Screen_height = rc.bottom - rc.top;
|
|
|
|
StringCchPrintfW( rgPath, ARRAYSIZE(rgPath), WZ_WINDOWPLACEMENT, (int)Screen_width, (int)Screen_height, szTitle );
|
|
|
|
if(fWrite)
|
|
{
|
|
if(regkey.CreateGlobalSubkey( rgPath ) == ERROR_SUCCESS) return true;
|
|
}
|
|
else
|
|
{
|
|
if(regkey.OpenGlobalSubkey( rgPath ) == ERROR_SUCCESS) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CMarsWindow::SaveWindowPosition( CGlobalSettingsRegKey& regkey )
|
|
{
|
|
WINDOWPLACEMENT wp; wp.length = sizeof(wp);
|
|
|
|
GetWindowPlacement( &wp );
|
|
|
|
WriteWindowPosition(regkey, &wp.rcNormalPosition, IsZoomed());
|
|
}
|
|
|
|
|
|
void CMarsWindow::LoadWindowPosition( CGlobalSettingsRegKey& regkey, BOOL fAllowMaximized, WINDOWPLACEMENT& wp, BOOL& fMaximized )
|
|
{
|
|
RECT rc;
|
|
|
|
|
|
// Use default values if there is no valid registry data
|
|
if(ERROR_SUCCESS != regkey.QueryBoolValue(fMaximized, WZ_POSITIONMAX))
|
|
{
|
|
fMaximized = fAllowMaximized;
|
|
}
|
|
|
|
if(ERROR_SUCCESS != regkey.QueryBinaryValue(&rc, sizeof(rc), WZ_POSITIONRECT))
|
|
{
|
|
rc = wp.rcNormalPosition;
|
|
|
|
GetThreadParam()->dwFlags &= ~MTF_RESTORING_FROM_REGISTRY;
|
|
}
|
|
else
|
|
{
|
|
GetThreadParam()->dwFlags |= MTF_RESTORING_FROM_REGISTRY;
|
|
}
|
|
|
|
// If the window is about to open with the same top-left corner as another
|
|
// Mars window, cascade it.
|
|
|
|
if(IsWindowOverlayed( m_hWnd, rc.left, rc.top ))
|
|
{
|
|
CascadeWindowRectOnMonitor( m_hWnd, &rc );
|
|
}
|
|
|
|
// Always make sure the window is fully on-screen
|
|
BoundWindowRectToMonitor( m_hWnd, &rc );
|
|
|
|
// Don't use maximized setting if we're opened by script
|
|
m_fStartMaximized = fMaximized && fAllowMaximized;
|
|
|
|
// Now set the size of the window -- we should be hidden at this point
|
|
wp.rcNormalPosition = rc;
|
|
wp.showCmd = IsWindowVisible() ? (fMaximized ? SW_MAXIMIZE : SW_NORMAL) : SW_HIDE;
|
|
}
|
|
|
|
void CMarsWindow::SpinMessageLoop( BOOL fWait )
|
|
{
|
|
MSG msg;
|
|
|
|
while(fWait ? GetMessage( &msg, NULL, 0, 0 ) : PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
|
|
{
|
|
if(m_spMarsHost && SUCCEEDED(m_spMarsHost->PreTranslateMessage( &msg ))) continue;
|
|
|
|
if(!PreTranslateMessage( msg ))
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessage ( &msg );
|
|
}
|
|
|
|
if(IsPassive()) break;
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
// Mars App
|
|
//==================================================================
|
|
|
|
HRESULT STDMETHODCALLTYPE MarsThreadProc(IMarsHost *pMarsHost, MARSTHREADPARAM *pThreadParam)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!CThreadData::HaveData() && (NULL != pThreadParam) &&
|
|
(pThreadParam->cbSize == sizeof(*pThreadParam)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
CThreadData *pThreadData = new CThreadData;
|
|
|
|
if (pThreadData && CThreadData::TlsSetValue(pThreadData))
|
|
{
|
|
hr = CoInitialize(NULL);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
MarsAxWinInit();
|
|
|
|
CComClassPtr<CMarsWindow> spMarsWindow;
|
|
|
|
CMarsWindow::CreateInstance(pMarsHost, pThreadParam, &spMarsWindow);
|
|
|
|
|
|
if(spMarsWindow)
|
|
{
|
|
spMarsWindow->SpinMessageLoop( TRUE );
|
|
|
|
// Ensure that no matter what the window is passivated & then release it
|
|
if (!spMarsWindow->IsPassive())
|
|
{
|
|
spMarsWindow->Passivate();
|
|
}
|
|
}
|
|
|
|
CoUninitialize();
|
|
}
|
|
|
|
CThreadData::TlsSetValue(NULL); // paranoia
|
|
}
|
|
|
|
delete pThreadData;
|
|
}
|
|
else
|
|
{
|
|
if(pThreadParam)
|
|
{
|
|
ATLASSERT(pThreadParam->cbSize == sizeof(*pThreadParam));
|
|
}
|
|
|
|
// If we already have TLS data then we are being reentered -- this is not a good thing!
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
return hr;
|
|
}
|