// GlassControl.cpp : Implementation of CGlassControl
#include "stdafx.h"
#include "initguid.h"
#include "Glass.h"
#include "GlassCtl.h"
#include <stdio.h>
#include "COMDEF.h"
short _GetShiftState(void);
short _GetButtonState(WPARAM wParam);
/////////////////////////////////////////////////////////////////////////////
// CGlassControl
//=--------------------------------------------------------------------------=
// CGlassControl::CGlassControl
//=--------------------------------------------------------------------------=
//
// Notes:
//
CGlassControl::CGlassControl()
{
m_state.Brightness = 64;
m_state.iWidth = 10;
m_state.FadeInterval = 5;
m_state.fFreeze = 0;
m_state.fEnabled = TRUE;
m_state.fInvalid = TRUE;
m_pDirectDraw3 = NULL;
m_pTimer = NULL;
m_pTimerSink = NULL;
m_TimerCookie = 0;
m_timeLastAdvise = 0;
m_pSource = NULL;
m_pSite = NULL;
SetRect(&m_rc, 0, 0, 0, 0);
m_pCSSSite = NULL;
}
//=--------------------------------------------------------------------------=
// CGlassControl::~CGlassControl
//=--------------------------------------------------------------------------=
//
// Notes: Our timer sink is not part of this object to avoid circular
// references, but the sink must be told that the control is
// no longer around to be called.
//
CGlassControl::~CGlassControl ()
{
if ( m_pTimerSink )
m_pTimerSink->m_pGC = NULL; // Sink is on its own
if ( m_pDirectDraw3 )
m_pDirectDraw3->Release();
if ( m_pTimer )
m_pTimer->Release();
if (m_pSource)
{
m_pSource->SetSite(0);
m_pSource->Release();
}
if (m_pSite)
m_pSite->Release();
if (m_pCSSSite)
m_pCSSSite->Release();
}
//=--------------------------------------------------------------------------=
// CGlassControl::OnDraw
//=--------------------------------------------------------------------------=
//
// Parameters:
// ATL_DRAWINGO - [in] HDC, rects, and all that stuff
//
// Output:
// HRESULT
//
// Notes:
//
HRESULT CGlassControl::OnDraw(ATL_DRAWINFO& di)
{
HBRUSH hbrold;
HPEN hpen, hpenold;
IDirectDrawSurface *pDDSurface = NULL;
DDSURFACEDESC desc;
HRESULT hr = S_OK;
RECT rc, rcLens, rcClip;
HPALETTE hpal = NULL;
BYTE itoi[256];
VOID *pBits = NULL;
long pitch;
long x, y;
int bpp = 0, i;
BYTE* prow;
BYTE* pput;
//
// draw a thick, green rectangle border
//
hpen = CreatePen(PS_INSIDEFRAME, m_state.iWidth, RGB(0, 255, 0));
if (!hpen) return E_FAIL;
hpenold = (HPEN)SelectObject(di.hdcDraw, hpen);
if (!m_bInPlaceActive || m_bWndLess)
hbrold = (HBRUSH)SelectObject(di.hdcDraw, GetStockObject(HOLLOW_BRUSH));
Rectangle(di.hdcDraw, di.prcBounds->left, di.prcBounds->top, di.prcBounds->right, di.prcBounds->bottom);
if (!di.bOptimize) {
if (!m_bInPlaceActive || m_bWndLess)
SelectObject(di.hdcDraw, hbrold);
SelectObject(di.hdcDraw, hpenold);
}
rcLens = *(RECT*)di.prcBounds;
InflateRect(&rcLens, -m_state.iWidth, -m_state.iWidth);
GetClipBox(di.hdcDraw, &rcClip);
if (!IntersectRect(&rcLens, &rcClip, &rcLens))
// no intersection with interior "lens" area; nothing to do
goto Cleanup;
// get surface factory via service provider
if (!m_pDirectDraw3)
{
IServiceProvider * serviceProvider = 0;
if ( m_spClientSite ) // this is if we are an ole object thru the <OBJECT> tag
m_spClientSite->QueryInterface(
IID_IServiceProvider,
(void**)&serviceProvider);
else if ( m_pCSSSite ) // this is if we are a CSS Extension (Filter) object
{
hr = m_pCSSSite->QueryInterface( IID_IServiceProvider,
(void**)&serviceProvider);
if ( hr )
goto ErrorExit;
}
else
goto ErrorExit;
if (FAILED(hr))
goto ErrorExit;
hr = serviceProvider->QueryService(
SID_SDirectDraw3,
IID_IDirectDraw3,
(void**)&m_pDirectDraw3);
serviceProvider->Release();
if (FAILED(hr))
goto ErrorExit;
}
// get DDSurface pointer
hr = m_pDirectDraw3->GetSurfaceFromDC(di.hdcDraw, &pDDSurface);
if (FAILED(hr))
goto ErrorExit;
// map our rect into the surface coords
rc = rcLens;
LPtoDP(di.hdcDraw, (POINT*)&rcLens, 2);
// lock it to get pbits
desc.dwSize = sizeof(desc);
hr = pDDSurface->Lock(&rcLens, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
if (FAILED(hr))
goto ErrorExit;
pBits = desc.lpSurface;
pitch = desc.lPitch;
bpp = desc.ddpfPixelFormat.dwRGBBitCount;
if (bpp == 16
&& desc.ddpfPixelFormat.dwRBitMask == 0x7C00
&& desc.ddpfPixelFormat.dwGBitMask == 0x03E0
&& desc.ddpfPixelFormat.dwBBitMask == 0x001F)
{
bpp = 15;
}
switch (bpp)
{
case 8:
//
// 8-bpp paletted case
//
//
// modify the bits directly
//
struct
{
WORDpalVersion;
WORDpalNumEntries;
PALETTEENTRY palPalEntry[256];
} logpal;
logpal.palNumEntries = 256;
logpal.palVersion = 0x300;
IDirectDrawPalette* pDDPalette;
hr = pDDSurface->GetPalette(&pDDPalette);
if (SUCCEEDED(hr))
{
hr = pDDPalette->GetEntries(0, 0, 256, logpal.palPalEntry);
pDDPalette->Release();
}
if (SUCCEEDED(hr))
{
int r,g,b;
HPALETTE hpal;
hpal = (HPALETTE)GetCurrentObject(di.hdcDraw, OBJ_PAL);
for (i = 0; i < logpal.palNumEntries; ++i)
{
r = max(0, min(255, logpal.palPalEntry[i].peRed + m_state.Brightness));
g = max(0, min(255, logpal.palPalEntry[i].peGreen + m_state.Brightness));
b = max(0, min(255, logpal.palPalEntry[i].peBlue + m_state.Brightness));
itoi[i] = GetNearestPaletteIndex(hpal, RGB(r,g,b));
}
DeleteObject(hpal);
// then use the map to translate the pixels
prow = (BYTE*)pBits;
for (y = rcLens.top; y < rcLens.bottom; ++y)
{
pput = prow;
for (x = rcLens.left; x < rcLens.right; ++x)
{
*pput = itoi[*pput];
pput++;
}
prow += pitch;
}
}
break;
case 24:
//
// 24-bpp case
//
int p;
for (i = 0; i <= 255; ++i)
itoi[i] = max(0, min(255, i + m_state.Brightness));
prow = (BYTE*)pBits;
for (y = rcLens.top; y < rcLens.bottom; ++y)
{
pput = prow;
for (x = rcLens.left; x < rcLens.right; ++x)
{
for (p = 1; p <= 3; ++p)
{
*pput = itoi[*pput];
pput++;
}
}
prow += pitch;
}
break;
case 32:
//
// 32-bpp case; same as 24-bpp, but 4 bytes per pixel
//
for (i = 0; i <= 255; ++i)
itoi[i] = max(0, min(255, i + m_state.Brightness));
prow = (BYTE*)pBits;
for (y = rcLens.top; y < rcLens.bottom; ++y)
{
pput = prow;
for (x = rcLens.left; x < rcLens.right; ++x)
{
for (p = 1; p <= 3; ++p)
{
*pput = itoi[*pput];
pput++;
}
pput++; // do that extra dummy byte
}
prow += pitch;
}
break;
case 15:
{
//
// 16-bpp 555 case
//
typedef struct
{
unsigned short r:5;
unsigned short g:5;
unsigned short b:5;
} W555;
W555* pputw;
W555 w;
for (i = 0; i <= 31; ++i)
itoi[i] = max(0, min(31, ((i << 3) + m_state.Brightness + 3) >> 3));
prow = (BYTE*)pBits;
for (y = rcLens.top; y < rcLens.bottom; ++y)
{
pputw = (W555*)prow;
for (x = rcLens.left; x < rcLens.right; ++x)
{
w = *pputw;
w.r = itoi[w.r];
w.g = itoi[w.g];
w.b = itoi[w.b];
*pputw++ = w;
}
prow += pitch;
}
}
break;
case 16:
{
//
// 16-bpp 565 case
//
typedef struct
{
unsigned short r:5;
unsigned short g:6;
unsigned short b:5;
} W565;
W565* pputw;
W565 w;
for (i = 0; i <= 31; ++i)
itoi[i] = max(0, min(31, ((i << 3) + m_state.Brightness + 4) >> 3));
for (i = 0; i <= 63; ++i)
itoi[i+32] = max(0, min(63, ((i << 2) + m_state.Brightness + 1) >> 2));
prow = (BYTE*)pBits;
for (y = rcLens.top; y < rcLens.bottom; ++y)
{
pputw = (W565*)prow;
for (x = rcLens.left; x < rcLens.right; ++x)
{
w = *pputw;
w.r = itoi[w.r];
w.g = itoi[w.g+32];
w.b = itoi[w.b];
*pputw++ = w;
}
prow += pitch;
}
}
break;
case 4:
//
// 4-bpp case
//
prow = (BYTE*)pBits;
for (y = rcLens.top; y < rcLens.bottom; ++y)
{
pput = prow;
for (x = rcLens.left; x < rcLens.right; ++x)
{
// just an inversion, for demo purposes
if (x & 1)
{
*pput = *pput ^ 0x0F;
++pput;
}
else
{
*pput = *pput ^ 0xF0;
}
}
prow += pitch;
}
break;
case 1:
{
//
// 1-bpp case
//
static BYTE msk[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
prow = (BYTE*)pBits;
for (y = rcLens.top; y < rcLens.bottom; ++y)
{
pput = prow;
for (x = rcLens.left; x < rcLens.right; ++x)
{
// just an inversion, for demo purposes
*pput = *pput ^ msk[x & 0x7];
if ((x & 0x7) == 7)
++pput;
}
prow += pitch;
}
}
break;
default:
_ASSERT("Unsupported Buffer Depth");
break;
}
Cleanup:
if (pDDSurface)
{
// unlock pbits
if (pBits)
pDDSurface->Unlock(pBits);
pDDSurface->Release();
}
DeleteObject(hpen);
return S_OK;
ErrorExit:
// mark control with big X to let user know something went wrong
MoveToEx(di.hdcDraw, di.prcBounds->left+m_state.iWidth, di.prcBounds->top+m_state.iWidth, NULL);
LineTo( di.hdcDraw, di.prcBounds->right-m_state.iWidth, di.prcBounds->bottom-m_state.iWidth);
MoveToEx(di.hdcDraw, di.prcBounds->right-m_state.iWidth, di.prcBounds->top+m_state.iWidth, NULL);
LineTo( di.hdcDraw, di.prcBounds->left+m_state.iWidth, di.prcBounds->bottom-m_state.iWidth);
goto Cleanup;
}
//=--------------------------------------------------------------------------=
// CGlassControl::OnMouse
//=--------------------------------------------------------------------------=
// Handles Mouse events and forwards them on.
//
// Parameters:
// see win32sdk on window procs [sans HWND -- it's in m_hwnd if you have one]
//
// Notes:
//
LRESULT
CGlassControl::OnMouse(UINT msg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
switch (msg) {
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
OnMouseDown(_GetButtonState(wParam), _GetShiftState(),
(long)LOWORD(lParam), (long)HIWORD(lParam));
m_spInPlaceSite->SetCapture(TRUE);
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
OnMouseUp(_GetButtonState(wParam), _GetShiftState(),
(long)LOWORD(lParam), (long)HIWORD(lParam));
m_spInPlaceSite->SetCapture(FALSE);
break;
case WM_MOUSEMOVE:
OnMouseMove(_GetButtonState(wParam), _GetShiftState(),
(long)LOWORD(lParam), (long)HIWORD(lParam));
break;
}
return 0;
}
//=--------------------------------------------------------------------------=
// CGlassControl::get_LineWidth [IGlass]
//=--------------------------------------------------------------------------=
// returns out current width
//
// Parameters:
// long * - [out]
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::get_LineWidth
(
long *plWidth
)
{
CHECK_POINTER(plWidth);
*plWidth = m_state.iWidth;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::put_LineWidth [IGlass]
//=--------------------------------------------------------------------------=
// sets the current width
//
// Parameters:
// long - [in] new value
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::put_LineWidth
(
long lWidth
)
{
// sanity checking!
//
if (lWidth < 0 || lWidth > 255)
return CTL_E_INVALIDPROPERTYVALUE;
// set the value, tell everybody about it, and force a repaint.
//
m_state.iWidth = lWidth;
SetDirty(TRUE);
if ( m_pSite ) // if we're a filter, normal ole control invalidation doesn't work
InvalidateRect(NULL, FALSE);
else
FireViewChange();
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::get_Brightness [IGlass]
//=--------------------------------------------------------------------------=
// returns out current Brightness
//
// Parameters:
// long * - [out]
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::get_Brightness
(
long *plBrightness
)
{
CHECK_POINTER(plBrightness);
*plBrightness = m_state.Brightness;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::put_Brightness [IGlass]
//=--------------------------------------------------------------------------=
// sets the current Brightness
//
// Parameters:
// long - [in] new value
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::put_Brightness
(
long lBrightness
)
{
// sanity checking!
//
if (lBrightness < -255 || lBrightness > 255)
return CTL_E_INVALIDPROPERTYVALUE;
// set the value, tell everybody about it, and force a repaint.
//
m_state.Brightness = lBrightness;
SetDirty(TRUE);
if ( m_pSite ) // if we're a filter, normal ole control invalidation doesn't work
InvalidateRect(NULL, FALSE);
else
FireViewChange();
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::get_DynamicFade [IGlass]
//=--------------------------------------------------------------------------=
// returns out current DynamicFade
//
// Parameters:
// long * - [out]
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::get_DynamicFade
(
long *plDynamicFade
)
{
CHECK_POINTER(plDynamicFade);
*plDynamicFade = m_state.DynamicFade;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::put_DynamicFade [IGlass]
//=--------------------------------------------------------------------------=
// sets the current DynamicFade
//
// Parameters:
// long - [in] new value
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::put_DynamicFade
(
long lDynamicFade
)
{
VARIANT vtimeMin, vtimeMax, vtimeInt, vtimeGet;
// set the value, tell everybody about it
//
m_state.DynamicFade = (lDynamicFade > 0 ? lDynamicFade:0);
VariantInit( &vtimeMin );
VariantInit( &vtimeMax );
VariantInit( &vtimeInt );
VariantInit( &vtimeGet );
V_VT(&vtimeMin) = VT_UI4;
V_VT(&vtimeMax) = VT_UI4;
V_VT(&vtimeInt) = VT_UI4;
V_VT(&vtimeGet) = VT_UI4;
if ( m_state.DynamicFade > 0 )
{
if ( m_TimerCookie > 0 && m_pTimer )
{ // junk old advise
m_pTimer->Unadvise( m_TimerCookie );
m_TimerCookie = 0;
}
if ( !m_pTimer )
{ // get a timer
HRESULT hr;
IServiceProvider * serviceProvider = 0;
ITimerService *pTimerService = 0;
hr = m_spClientSite->QueryInterface(
IID_IServiceProvider,
(void**)&serviceProvider);
if (FAILED(hr))
return hr;
hr = serviceProvider->QueryService(
SID_STimerService,
IID_ITimerService,
(void**)&pTimerService);
serviceProvider->Release();
hr = pTimerService->CreateTimer(NULL, &m_pTimer);
if (FAILED(hr))
{
_ASSERTE(0 && "Timer creation failed" );
return hr;
}
pTimerService->Release();
}
// make sure we have our sink ready
if ( !m_pTimerSink )
{
m_pTimerSink = new CGlassControlSink( this );
if ( !m_pTimerSink )
return E_OUTOFMEMORY;
}
m_timeLastAdvise = 0; // reset interval counter
m_pTimer->GetTime(&vtimeGet);
V_UI4(&vtimeMin) = V_UI4(&vtimeGet);
V_UI4(&vtimeMax) = 0;
V_UI4(&vtimeInt) = (unsigned)m_state.DynamicFade;
m_pTimer->Advise( vtimeMin, vtimeMax, vtimeInt, 0,
(ITimerSink *)m_pTimerSink, &m_TimerCookie );
}
else
{
if ( m_pTimer && m_TimerCookie > 0 )
{
m_pTimer->Unadvise( m_TimerCookie );
m_TimerCookie = 0;
}
}
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::get_FadeInterval [IGlass]
//=--------------------------------------------------------------------------=
// returns out current FadeInterval
//
// Parameters:
// long * - [out]
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::get_FadeInterval
(
long *plFadeInterval
)
{
CHECK_POINTER(plFadeInterval);
*plFadeInterval = m_state.FadeInterval;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::put_FadeInterval [IGlass]
//=--------------------------------------------------------------------------=
// sets the current FadeInterval
//
// Parameters:
// long - [in] new value
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::put_FadeInterval
(
long lFadeInterval
)
{
// set the value, tell everybody about it
//
m_state.FadeInterval = (lFadeInterval > 0 ? lFadeInterval:0);
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::get_Freeze [IGlass]
//=--------------------------------------------------------------------------=
// returns out current Freeze
//
// Parameters:
// long * - [out]
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::get_Freeze
(
long *plFreeze
)
{
CHECK_POINTER(plFreeze);
*plFreeze = m_state.fFreeze;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::put_Freeze [IGlass]
//=--------------------------------------------------------------------------=
// sets the current Freeze
//
// Parameters:
// long - [in] new value
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::put_Freeze
(
long lFreeze
)
{
m_state.fFreeze = !!lFreeze;
if ( m_pTimer )
{
m_pTimer->Freeze( m_state.fFreeze );
}
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::get_Enabled [IGlass]
//=--------------------------------------------------------------------------=
// returns out current Enabled
//
// Parameters:
// long * - [out]
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::get_Enabled
(
long *plEnabled
)
{
CHECK_POINTER(plEnabled);
*plEnabled = m_state.fEnabled;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::put_Enabled [IGlass]
//=--------------------------------------------------------------------------=
// sets the current Enabled
//
// Parameters:
// long - [in] new value
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::put_Enabled
(
long lEnabled
)
{
// set the value, tell everybody about it
// Probably should freeze the timer, but then calling enabled true multiple
// times, or false multiple times, could get dicy, so we won't bother.
m_state.fEnabled = !!lEnabled;
if ( m_pSite ) // if we're a filter, normal ole control invalidation doesn't work
InvalidateRect(NULL, FALSE);
else
FireViewChange();
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::QueryHitPoint [IViewObjectEx]
//=--------------------------------------------------------------------------=
// asks whether or not the user has clicked on a portion of the control, or
// on a transparent portion
//
// Parameters:
// DWORD - [in] aspect
// LPCRECT - [in] Bounds rectangle
// POINT - [in] hit location client coordinates
// LONG - [in] what the container considers close
// DWORD * - [out] info about the hit
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControl::QueryHitPoint
(
DWORD dvAspect,
LPCRECT prcBounds,
POINT ptLocation,
LONG lCloseHint,
DWORD *pdwHitResult
)
{
RECT rcSmall;
CHECK_POINTER(pdwHitResult);
rcSmall = *prcBounds;
InflateRect(&rcSmall, -m_state.iWidth, -m_state.iWidth);
// if it's within the outer retangle, but not within iWidth pixels of it,
// then it's not a hit.
//
*pdwHitResult = (PtInRect(prcBounds, ptLocation) &&
!PtInRect(&rcSmall, ptLocation)) ? HITRESULT_HIT : HITRESULT_TRANSPARENT;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControl::HandleOnTimer [Helper]
//=--------------------------------------------------------------------------=
// Real handler for OnTimer call on TimerSink help class.
//
// Parameters:
// TIME - [in] scheduled time of event
//
// Output:
// HRESULT
//
// Notes: Brightness delta is time sensitive, so if some notifications get
// dropped it won't effect the perceived speed of the fading.
//
STDMETHODIMP CGlassControl::HandleOnTimer
(
DWORD timeAdvise
)
{
int cInterval = 1;
if ( m_timeLastAdvise != 0 && m_state.DynamicFade > 0 &&
timeAdvise > m_timeLastAdvise )
{
cInterval = (timeAdvise - m_timeLastAdvise) / m_state.DynamicFade;
}
m_timeLastAdvise = timeAdvise;
while ( cInterval-- > 0 )
{
m_state.Brightness += m_state.FadeInterval;
if ( m_state.Brightness >= 255 )
{
m_state.FadeInterval = -m_state.FadeInterval;
m_state.Brightness = 255;
}
else if ( m_state.Brightness <= -255 )
{
m_state.FadeInterval = -m_state.FadeInterval;
m_state.Brightness = -255;
}
}
// set the value, tell everybody about it
//
SetDirty(TRUE);
if ( m_pSite ) // if we're a filter, normal ole control invalidation doesn't work
InvalidateRect(NULL, FALSE);
else
FireViewChange();
return S_OK;
}
//=--------------------------------------------------------------------------=
// CGlassControlSink::*** [IUnknown]
//=--------------------------------------------------------------------------=
// Usual IUnknown implementation
//
ULONG
CGlassControlSink::AddRef()
{
return ++m_cRefs;
}
ULONG
CGlassControlSink::Release()
{
if ( 0 == --m_cRefs )
{
ULONG refCount = m_cRefs;
delete this;
return refCount;
}
return m_cRefs;
}
HRESULT
CGlassControlSink::QueryInterface(REFIID riid, void **ppv)
{
if ( !ppv )
return E_POINTER;
*ppv = NULL;
if (IID_IUnknown == riid) {
*ppv = (void *)(IUnknown *)this;
} else if (IID_ITimerSink == riid) {
*ppv = (void *)(ITimerSink *)this;
}
if (*ppv)
{
((IUnknown *)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
//=--------------------------------------------------------------------------=
// CGlassControlSink::OnTimer [ITimerSink]
//=--------------------------------------------------------------------------=
// callback proc for Timer notifications
//
// Parameters:
// TIME - [in] scheduled time of event
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP CGlassControlSink::OnTimer
(
VARIANT timeAdvise
)
{
_ASSERTE( VT_UI4 == V_VT(&timeAdvise) && "Variant type mismatch" );
return( m_pGC?m_pGC->HandleOnTimer(V_UI4(&timeAdvise)):S_OK );
}
//=--------------------------------------------------------------------------=
// _GetShiftState [standard helper!]
//=--------------------------------------------------------------------------=
// used by people to get shift state information
//
// Output:
// short - mask of shift, ctrl and alt keys
//
// Notes:
//
short _GetShiftState(void)
{
BOOL bShift = (GetKeyState(VK_SHIFT) < 0);
BOOL bCtrl = (GetKeyState(VK_CONTROL) < 0);
BOOL bAlt = (GetKeyState(VK_MENU) < 0);
return (short)(bShift + (bCtrl << 1) + (bAlt << 2));
}
//=--------------------------------------------------------------------------=
// _GetButtonState [standard helper!]
//=--------------------------------------------------------------------------=
// Returns which button was pressed. Does not handle cords
//
// Output:
// short - Left, Middle, Right, or no button
//
// Notes:
//
short _GetButtonState(WPARAM wParam)
{
return (short)(wParam & MK_LBUTTON) ? LEFT_BUTTON :
((wParam & MK_RBUTTON) ? RIGHT_BUTTON :
((wParam & MK_MBUTTON) ? MIDDLE_BUTTON : 0));
}
//
// IViewFilter and IViewFilterSite interface method implementations
// This is for making the Glass control a VISUAL filter
//
STDMETHODIMP CGlassControl::SetSource(IViewFilter *pFilter)
{
if (m_pSource)
{
m_pSource->SetSite(NULL);
m_pSource->Release();
}
m_pSource = pFilter;
if (m_pSource)
{
m_pSource->AddRef();
m_pSource->SetSite((IViewFilterSite*)this);
}
return S_OK;
}
STDMETHODIMP CGlassControl::GetSource(IViewFilter **ppFilter)
{
if (ppFilter == 0)
return E_POINTER;
*ppFilter = m_pSource;
if (m_pSource)
{
m_pSource->AddRef();
}
return S_OK;
}
STDMETHODIMP CGlassControl::SetSite(IViewFilterSite *pSink)
{
if (m_pSite)
m_pSite->Release();
m_pSite = pSink;
if (m_pSite)
{
m_pSite->AddRef();
}
return S_OK;
}
STDMETHODIMP CGlassControl::GetSite(IViewFilterSite **ppSink)
{
if (ppSink == 0)
return E_POINTER;
*ppSink = m_pSite;
if (m_pSite)
m_pSite->AddRef();
return S_OK;
}
STDMETHODIMP CGlassControl::GetStatusBits(DWORD *pdwFlags)
{
HRESULT hr = S_OK;
if (m_pSource)
{
HRESULT hr = m_pSource->GetStatusBits(pdwFlags);
if (SUCCEEDED(hr))
{
*pdwFlags &= ~FILTER_STATUS_OPAQUE;
}
}
return hr;
}
STDMETHODIMP CGlassControl::SetPosition(LPCRECT prc)
{
m_rc = *prc;
if (m_pSource)
{
return m_pSource->SetPosition(prc);
}
return S_OK;
}
STDMETHODIMP CGlassControl::Draw(HDC hdc, LPCRECT prcBounds)
{
HRESULT hr;
ATL_DRAWINFO di;
if (m_pSource == 0)
return VIEW_E_DRAW;
if (prcBounds == 0)
return E_POINTER;
// fill the hdc with the element we are attached to
hr = m_pSource->Draw(hdc, prcBounds);
if ( FAILED(hr) || !m_state.fEnabled )
return hr;
// Just Call through to OnDraw, but first fill in ATL_DRAWINFO
// struct with bare info
di.cbSize = sizeof(di);
di.hicTargetDev = hdc;
di.hdcDraw = hdc;
memcpy( &(di.prcBounds), &prcBounds, sizeof(RECT) );
memcpy( &(di.prcWBounds), &prcBounds, sizeof(RECT) );
di.bOptimize = FALSE;
di.bZoomed = FALSE;
hr = OnDraw(di);
return hr;
}
STDMETHODIMP CGlassControl::InvalidateRect(LPCRECT prc, BOOL fErase)
{
if (m_pSite)
return m_pSite->InvalidateRect(prc, fErase);
return S_OK;
}
STDMETHODIMP CGlassControl::InvalidateRgn(HRGN hrgn, BOOL fErase)
{
if (m_pSite)
return m_pSite->InvalidateRgn(hrgn, fErase);
return S_OK;
}
STDMETHODIMP CGlassControl::GetDC(LPCRECT prc, DWORD dwFlags, HDC *phdc)
{
// THIS SAMPLE IS JUST IGNORING THIS FOR NOW!
// can either return E_NOTIMPL or go thru site for default behavior
if (m_pSite)
return m_pSite->GetDC(prc, dwFlags, phdc);
return E_NOTIMPL;
}
STDMETHODIMP CGlassControl::ReleaseDC(HDC hdc)
{
// THIS SAMPLE IS JUST IGNORING THIS FOR NOW!
// can either return E_NOTIMPL or go thru site for default behavior
if (m_pSite)
return m_pSite->ReleaseDC(hdc);
return E_NOTIMPL;
}
STDMETHODIMP CGlassControl::OnStatusBitsChange(DWORD dwFlags)
{
HRESULT hr = S_OK;
if (m_pSite)
{
dwFlags &= ~FILTER_STATUS_OPAQUE;
hr = m_pSite->OnStatusBitsChange(dwFlags);
}
return hr;
}
//
// ICSSFilter interface method implementations
// This is for making the Glass control a CSS filter
//
STDMETHODIMP CGlassControl::SetSite(ICSSFilterSite *pSite)
{
IHTMLElement *pElem = NULL;
IHTMLControlElement *pCtrlElem = NULL;
IUnknown *pUnk = NULL;
HRESULT hr = S_OK;
if ( m_pCSSSite )
{
if ( SUCCEEDED(m_pCSSSite->GetElement( &pElem )) )
{
if ( SUCCEEDED(pElem->QueryInterface( IID_IHTMLControlElement,
(void **)&pCtrlElem )) )
{
ControlQueryInterface( IID_IUnknown, (void **)&pUnk );
hr = pCtrlElem->removeFilter( pUnk );
}
}
m_pCSSSite->Release();
}
m_pCSSSite = pSite;
if ( m_pCSSSite )
{
m_pCSSSite->AddRef();
// hook up with IViewFilter stuff now.
if ( SUCCEEDED(hr=m_pCSSSite->GetElement( &pElem )) )
{
if ( SUCCEEDED(hr=pElem->QueryInterface( IID_IHTMLControlElement,
(void **)&pCtrlElem )) )
{
hr = ControlQueryInterface( IID_IUnknown, (void **)&pUnk );
hr = pCtrlElem->addFilter( pUnk );
}
}
if ( FAILED(hr) )
goto error;
}
cleanup:
if ( pUnk )
pUnk->Release();
if ( pCtrlElem )
pCtrlElem->Release();
if ( pElem )
pElem->Release();
return hr;
error:
// Sorry, if I can't connect with a Site, I don't connect at all
if ( m_pCSSSite )
{
m_pCSSSite->Release();
m_pCSSSite = NULL;
}
goto cleanup;
}
STDMETHODIMP CGlassControl::OnAmbientPropertyChange( DISPID dispid )
{
return E_NOTIMPL;
}
//
// IPersistPropertyBag overrides
//
STDMETHODIMP CGlassControl::Load( IPropertyBag *pPropBag, IErrorLog *pErrorLog )
{
_variant_t vBrightness;
HRESULT hr = pPropBag->Read(L"brightness", &vBrightness, NULL);
if (SUCCEEDED(hr))
{
m_state.Brightness = (long)vBrightness;
}
_variant_t vEnabled;
hr = pPropBag->Read(L"enabled", &vEnabled, NULL);
if (SUCCEEDED(hr))
{
m_state.fEnabled = (bool)vEnabled;
}
return S_OK;
}
//
// IObjectSafety overrides
//
STDMETHODIMP
CGlassControl::GetInterfaceSafetyOptions( REFIID riid,
DWORD *pdwSupportedOptions,
DWORD *pdwEnabledOptions )
{
HRESULT hr;
if ( pdwSupportedOptions == NULL || pdwEnabledOptions == NULL )
return E_POINTER;
if ( riid == IID_IDispatch )
{
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
*pdwEnabledOptions = m_dwSafety & INTERFACESAFE_FOR_UNTRUSTED_CALLER;
}
else if ( riid == IID_IPersistPropertyBag )
{
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
*pdwEnabledOptions = m_dwSafety & INTERFACESAFE_FOR_UNTRUSTED_DATA;
}
else
{
IUnknown *pUnk;
*pdwSupportedOptions = 0;
*pdwEnabledOptions = 0;
hr = _InternalQueryInterface(riid, (void**)&pUnk);
if ( SUCCEEDED(hr) ) {
pUnk->Release();
hr = E_FAIL;
}
}
return hr;
}
STDMETHODIMP
CGlassControl::SetInterfaceSafetyOptions( REFIID riid,
DWORD dwOptionSetMask,
DWORD dwEnabledOptions )
{
HRESULT hr = S_OK;
// If we're being asked to set our safe for initializing or
// scripting option then oblige
if ( riid == IID_IDispatch )
{
// Store our current safety level to return in GetInterfaceSafetyOptions
m_dwSafety = dwEnabledOptions & dwOptionSetMask;
}
else if ( riid == IID_IPersistPropertyBag )
{
// Store our current safety level to return in GetInterfaceSafetyOptions
m_dwSafety = dwEnabledOptions & dwOptionSetMask;
}
else
{
IUnknown *pUnk;
hr = _InternalQueryInterface(riid, (void**)&pUnk);
if ( SUCCEEDED(hr) ) {
pUnk->Release();
hr = E_FAIL;
}
}
return hr;
}