// BarSite.cpp : Implementation of cBarSite #include "stdafx.h" #include "Inject.h" #include "LayerSite.h" #include "Manager.h" #include "Button.h" #include "Pager.h" ///////////////////////////////////////////////////////////////////////////// // cBarSite enum eSinkCaps { eSinkCapRender = 0x01, eSinkCapMouse = 0x02, eSinkCapKeyboard = 0x04, eSinkCapPopup = 0x08, eSinkCapTimer = 0x10 }; cLayerSite::cLayerSite() : m_pParent( NULL ), m_dwSinkCaps( 0 ), m_Alpha( 255 ) { } cLayerSite::~cLayerSite() { // Make sure we're really destroyed _ASSERTE( m_pParent == NULL ); _ASSERTE( m_children.size() == 0 ); } void cLayerSite::removeChild( cLayerSite *pChild ) { for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i ) { if( *i == pChild ) { m_children.erase( i ); break; } } } struct cSinkCapTest { eSinkCaps m_mask; const IID *m_iid; }; void cLayerSite::create( LayerParams *pParams, cLayerSite *pParent, ILayer *pSink ) { // First copy all the relevant data m_params = *pParams; m_pParent = pParent; static cSinkCapTest _capstest[] = { { eSinkCapRender, &IID_ILayerRender }, { eSinkCapMouse, &IID_ILayerMouse }, { eSinkCapKeyboard, &IID_ILayerKeyboard }, { eSinkCapPopup, &IID_ILayerPopup }, { eSinkCapTimer, &IID_ILayerTimer }, }; static cSinkCapTest *_end_caps = _capstest + ( sizeof( _capstest ) / sizeof( cSinkCapTest ) ); m_pSink = pSink; // Probe for relevant interfaces for( cSinkCapTest *i = _capstest; i != _end_caps; ++ i ) { CComPtr< IUnknown > pUnk; if( SUCCEEDED( pSink->QueryInterface( *( i->m_iid ), reinterpret_cast< void ** >( &pUnk ) ) ) ) m_dwSinkCaps |= i->m_mask; } // Do initialization activities if( !( m_params.render & eRenderClipped ) ) { // Create the back buffer SIZE sz = { m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top }; if( sz.cx > 0 && sz.cy > 0 ) cManager::_p->CreateCanvas( &sz, &m_pBuffer ); } // Add in the default render flags // All layer begin their life transparent until set otherwise m_params.render |= eRenderTransparent; // Make this control format itself next round Reformat(); Invalidate(); m_pSink->LayerCreate( this ); } void cLayerSite::destroy() { // First destroy all of our children while( !m_children.empty() ) { #ifdef _DEBUG int nChildren = m_children.size(); m_children.front()->destroy(); _ASSERTE( m_children.size() == ( nChildren - 1 ) ); #else m_children.front()->destroy(); #endif } // Remove from parent if( m_pParent != NULL ) { m_pParent->removeChild( this ); m_pParent = NULL; } // The child now releases the reference - this should trick our reference count to 0 m_pSink->LayerDestroy(); // After LayerDestroy returns this object has already been deleted - // do not touch any data members and we're OK // Reset capture pointers if( cManager::_p->m_pMouseDown == this ) cManager::_p->m_pMouseDown = NULL; if( cManager::_p->m_pMouseOver == this ) cManager::_p->m_pMouseOver = NULL; if( cManager::_p->m_pKeyboard == this ) cManager::_p->m_pKeyboard = NULL; for( cManager::cLayerList::iterator i = cManager::_p->m_popups.begin(); i != cManager::_p->m_popups.end(); ++ i ) { if( *i == this ) { cManager::_p->m_popups.erase( i ); break; } } } void cLayerSite::format() { // ::MessageBox( NULL, _T( "cLayerSite::format" ), _T( "Inject.dll" ), MB_OK ); // This is no longer recursive - in all cases, parents position their children formatLayer(); } void cLayerSite::formatLayer() { // Check for timers if( m_timers.size() > 0 ) { long nCurrentTime = ::timeGetTime(); for( cTimerList::iterator i = m_timers.begin(); i != m_timers.end(); ) { if( ( i->m_nLastTimeout + i->m_nInterval ) <= nCurrentTime ) { // Default to false, prevent the assert from going off *lots* VARIANT_BOOL bContinue = VARIANT_FALSE; ++ i->m_nRepetitions; if( m_dwSinkCaps & eSinkCapTimer ) { CComPtr< ILayerTimer > pTimer; m_pSink->QueryInterface( &pTimer ); pTimer->TimerTimeout( i->m_nID, nCurrentTime - i->m_nLastTimeout, i->m_nRepetitions, &bContinue ); } if( bContinue ) i->m_nLastTimeout = nCurrentTime; else { // Do not continue timing i = m_timers.erase( i ); continue; } } ++ i; } } // When reformatting - never reformat a surface that's 0,0 size if( ( m_params.render & eRenderReformatNext ) && m_params.pos.right > m_params.pos.left && m_params.pos.bottom > m_params.pos.top ) { // Do a reformat - NOTE: it's done here becasue a reformat will almost // always destroy the surface if( m_dwSinkCaps & eSinkCapRender ) { CComPtr< ILayerRender > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->Reformat(); } // Clear the reformat flag m_params.render &= ~eRenderReformatNext; } // Iterate over the children for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i ) ( *i )->formatLayer(); } void cLayerSite::prerender() { if( m_dwSinkCaps & eSinkCapRender ) { CComPtr< ILayerRender > pRender; m_pSink->QueryInterface( &pRender ); pRender->PreRender(); } // Iterate over the children for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i ) ( *i )->prerender(); } void cLayerSite::render(ICanvas *pPrimary) { if( !( m_params.render & eRenderClipped ) ) { // Check for 0,0 size if( m_params.pos.right > m_params.pos.left && m_params.pos.bottom > m_params.pos.top ) { // ::MessageBox( NULL, _T( "cLayerSite::render" ), _T( "Inject.dll" ), MB_OK ); _ASSERTE( m_pBuffer.p != NULL ); VARIANT_BOOL bRedraw; m_pBuffer->get_WasLost( &bRedraw ); // Here we push a scratch clip rect for the entire area // This is intended for unclipped layers that modfiy their // child clipping area. RECT rcAll = { 0, 0, m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top }; VARIANT_BOOL bDrawChildren; m_pBuffer->PushClipRect( &rcAll, &bDrawChildren ); // Assuming this area is non-0 size _ASSERTE( bDrawChildren ); renderBuffer( m_pBuffer, !!bRedraw ); m_pBuffer->PopClipRect(); // Place it on the screen POINT pt = { m_params.pos.left, m_params.pos.top }; RECT rc = { 0, 0, m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top }; pPrimary->put_Alpha(m_Alpha); pPrimary->Blt( &rc, m_pBuffer, &pt ); } else // This object has no size, it should have no canvas _ASSERTE( m_pBuffer.p == NULL ); } // Iterate through children - look for more non-clipped layers to render for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i ) ( *i )->render( pPrimary ); } void cLayerSite::renderBuffer( ICanvas *pBuffer, bool bForce ) { // Remove the next flag VARIANT_BOOL bRenderChildren = VARIANT_TRUE; bool bRendered = bForce; if( m_dwSinkCaps & eSinkCapRender ) { CComPtr< ILayerRender > pLayer; m_pSink->QueryInterface( &pLayer ); if( bForce || ( m_params.render & eRenderNext ) ) { if( !( m_params.render & eRenderClipped ) ) { RECT rcClient = { 0, 0, m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top }; // Unclipped layers all get an inital transparent fill m_pBuffer->Fill( &rcClient, RGB( 0, 255, 255 ) ); } bRendered = true; pLayer->Render( pBuffer ); } pLayer->AdjustRenderArea( pBuffer, &bRenderChildren ); } m_params.render &= ~eRenderNext; if( !bRenderChildren ) // While adjusting the render parameters, the rectangle got clipped out of existance return; // Walk through the children and transform the surface params for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i ) { if( !( ( *i )->m_params.render & eRenderClipped ) ) // Only clipped children continue; // Clip the child rectangle VARIANT_BOOL bRenderChild; pBuffer->PushClipRect( &( *i )->m_params.pos, &bRenderChild ); if( bRenderChild ) // Iterate ( *i )->renderBuffer( pBuffer, bRendered ); pBuffer->PopClipRect(); } } void cLayerSite::reformat() { if( m_dwSinkCaps & eSinkCapRender ) // Schedule a reformat for next render cycle m_params.render |= eRenderReformatNext; // Propagate reformat to children for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i ) ( *i )->reformat(); } cLayerSite *cLayerSite::hitTestUnclipped( POINTS pt, ICanvas *pCanvas ) { // First test if any children have been hit and delegate to them // as children have a higher z-order value cLayerSite *pSite; for( cChildList::reverse_iterator i = m_children.rbegin(); i != m_children.rend(); ++ i ) { pSite = ( *i )->hitTestUnclipped( pt, pCanvas ); if( pSite != NULL ) // Found a child hit - overlapping children are not tested // as there is no sibling clipping return pSite; } // Children are not hit, check if we hit ourselves if( !( m_params.render & eRenderClipped ) ) { POINT ptl = { pt.x, pt.y }; VARIANT_BOOL bVisible; pCanvas->PushClipRect( &m_params.pos, &bVisible ); cLayerSite *pHit = NULL; if( bVisible ) { VARIANT_BOOL bHit; pCanvas->HitTest( &ptl, &bHit ); if( bHit ) { // Check for transparent area hitting if( ( m_dwSinkCaps & eSinkCapRender ) && ( m_params.render & eRenderTransparent ) ) { // This may contain transparent areas // TODO: Check for transparent areas pHit = this; } else pHit = this; } } pCanvas->PopClipRect(); return pHit; } // Nothing hit in this branch return NULL; } cLayerSite *cLayerSite::hitTestClipped( POINTS pt, LPPOINT pptHit, ICanvas *pCanvas ) { // ::MessageBox( NULL, _T( "cLayerSite::hitTestClipped" ), _T( "Inject.dll" ), MB_OK ); // Convert the render params VARIANT_BOOL bRenderChildren = VARIANT_TRUE; if( m_dwSinkCaps & eSinkCapRender ) { CComPtr< ILayerRender > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->AdjustRenderArea( pCanvas, &bRenderChildren ); } POINT ptm = { pt.x, pt.y }; if( bRenderChildren ) { for( cChildList::reverse_iterator i = m_children.rbegin(); i != m_children.rend(); ++ i ) { if( !( ( *i )->m_params.render & eRenderClipped ) ) // Only clipped children continue; // Clip the child rectangle VARIANT_BOOL bVisible; pCanvas->PushClipRect( &( *i )->m_params.pos, &bVisible ); if( bVisible ) { VARIANT_BOOL bHit; pCanvas->HitTest( &ptm, &bHit ); if( bHit ) { cLayerSite *pRet = ( *i )->hitTestClipped( pt, pptHit, pCanvas ); pCanvas->PopClipRect(); return pRet; } } pCanvas->PopClipRect(); } } *pptHit = ptm; pCanvas->ToClient( pptHit ); return this; } cLayerSite *cLayerSite::hitTest( POINTS pt, LPPOINT pptHit, ICanvas *pCanvas ) { // First, find the unclipped parent cLayerSite *pHitUnclipped = hitTestUnclipped( pt, pCanvas ); if( pHitUnclipped == NULL ) // Absolutely nothing hit return NULL; VARIANT_BOOL bVisible; pCanvas->PushClipRect( &pHitUnclipped->m_params.pos, &bVisible ); cLayerSite *pHitClipped = pHitUnclipped->hitTestClipped( pt, pptHit, pCanvas ); pCanvas->PopClipRect(); return pHitClipped; } void cLayerSite::clipCanvas(ICanvas *pCanvas) { if( m_params.render & eRenderClipped ) m_pParent->clipCanvas( pCanvas ); VARIANT_BOOL bVisible; pCanvas->PushClipRect( &m_params.pos, &bVisible ); if( m_dwSinkCaps & eSinkCapRender ) { CComPtr< ILayerRender > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->AdjustRenderArea( pCanvas, &bVisible ); } } bool cLayerSite::isClippedChild( cLayerSite *pChild ) { for( cLayerSite *pChildLayer = pChild; pChild != NULL; pChild = pChild->m_pParent ) { if( pChildLayer == this ) return true; if( !( pChildLayer->m_params.render & eRenderClipped ) ) break; } return false; } bool cLayerSite::isChild( cLayerSite *pChild ) { for( cLayerSite *pChildLayer = pChild; pChildLayer != NULL; pChildLayer = pChildLayer->m_pParent ) { if( pChildLayer == this ) return true; } return false; } cLayerSite *cLayerSite::getCommonClippedParent( cLayerSite *pHit ) { for( cLayerSite *pCurrentParent = this; pCurrentParent != NULL; pCurrentParent = pCurrentParent->m_pParent ) { for( cLayerSite *pHitParent = pHit; pHitParent != NULL; pHitParent = pHitParent->m_pParent ) { if( pHitParent == pCurrentParent ) return pHitParent; if( !( pCurrentParent->m_params.render & eRenderClipped ) ) break; } if( !( pCurrentParent->m_params.render & eRenderClipped ) ) break; } return NULL; } void cLayerSite::sendMouseEnter( cLayerSite *pCommonParent, MouseState *pMS ) { if( pCommonParent != this && ( m_params.render & eRenderClipped ) ) // Enter our parent first - note that we stop at the unclipped parent m_pParent->sendMouseEnter( pCommonParent, pMS ); if( m_dwSinkCaps & eSinkCapMouse ) { CComPtr< ILayerMouse > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->MouseEnter( pMS ); } } void cLayerSite::sendMouseExit( cLayerSite *pCommonParent, MouseState *pMS ) { for( cLayerSite *pExit = this; pExit != pCommonParent; pExit = pExit->m_pParent ) { if( !( pExit->m_params.render & eRenderClipped ) ) // Common parent may be set to NULL if we're switching // to another unclipped parent break; if( pExit->m_dwSinkCaps & eSinkCapMouse ) { CComPtr< ILayerMouse > pLayer; pExit->m_pSink->QueryInterface( &pLayer ); pLayer->MouseExit( pMS ); } } } void cLayerSite::sendMouseDown( MouseState *pMS ) { if( m_dwSinkCaps & eSinkCapMouse ) { CComPtr< ILayerMouse > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->MouseDown( pMS ); } } void cLayerSite::sendMouseUp( MouseState *pMS ) { if( m_dwSinkCaps & eSinkCapMouse ) { CComPtr< ILayerMouse > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->MouseUp( pMS ); } } void cLayerSite::sendMouseMove( MouseState *pMS ) { if( m_dwSinkCaps & eSinkCapMouse ) { CComPtr< ILayerMouse > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->MouseMove( pMS ); } } void cLayerSite::sendMouseDblClk( MouseState *pMS ) { if( m_dwSinkCaps & eSinkCapMouse ) { CComPtr< ILayerMouse > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->MouseDblClk( pMS ); } } void cLayerSite::sendMouseEvent( long nMsg, long wParam, long lParam ) { if( m_dwSinkCaps & eSinkCapMouse ) { CComPtr< ILayerMouse > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->MouseEvent( nMsg, wParam, lParam ); } } void cLayerSite::sendKeyboardEndCapture( VARIANT_BOOL bCancel ) { if( m_dwSinkCaps & eSinkCapKeyboard ) { CComPtr< ILayerKeyboard > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->KeyboardEndCapture( bCancel ); } } void cLayerSite::sendKeyboardChar( KeyState *pKS ) { if( m_dwSinkCaps & eSinkCapKeyboard ) { CComPtr< ILayerKeyboard > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->KeyboardChar( pKS ); } } void cLayerSite::sendKeyboardEvent( long nMsg, long wParam, long lParam ) { if( m_dwSinkCaps & eSinkCapKeyboard ) { CComPtr< ILayerKeyboard > pLayer; m_pSink->QueryInterface( &pLayer ); pLayer->KeyboardEvent( nMsg, wParam, lParam ); } } bool cLayerSite::sendPopupCancel( MouseState *pMS ) { if( m_dwSinkCaps & eSinkCapPopup ) { CComPtr< ILayerPopup > pLayer; m_pSink->QueryInterface( &pLayer ); VARIANT_BOOL bContinue; pLayer->PopupCancel( pMS, &bContinue ); return !!bContinue; } // Default action is to cancel the popup return false; } STDMETHODIMP cLayerSite::Destroy() { cManager::_p->m_destroy.push_back( this ); AddRef(); return S_OK; } STDMETHODIMP cLayerSite::CreateChild(LayerParams *params, ILayer *pSink) { CComObject< cLayerSite > *pChild; CComObject< cLayerSite >::CreateInstance( &pChild ); pChild->create( params, this, pSink ); m_children.push_back( pChild ); return S_OK; } STDMETHODIMP cLayerSite::GetSink(REFIID iid, void **ppvItf) { return m_pSink->QueryInterface( iid, ppvItf ); } STDMETHODIMP cLayerSite::Invalidate() { for( cLayerSite *pSite = this; pSite != NULL; pSite = pSite->m_pParent ) { if( !( pSite->m_params.render & eRenderTransparent ) || !( pSite->m_params.render & eRenderClipped ) || pSite->m_pParent == NULL ) break; } pSite->m_params.render |= eRenderNext; return S_OK; } STDMETHODIMP cLayerSite::get_PluginSite(IPluginSite **ppSite) { *ppSite = cManager::_p; ( *ppSite )->AddRef(); return S_OK; } STDMETHODIMP cLayerSite::Reformat() { if( m_params.pos.right != m_params.pos.left && m_params.pos.top != m_params.pos.bottom && m_dwSinkCaps & eSinkCapRender ) m_params.render |= eRenderReformatNext; return S_OK; } STDMETHODIMP cLayerSite::GetParentSink(REFIID iid, void **ppvItf) { for( cLayerSite *pSite = m_pParent; pSite != NULL; pSite = pSite->m_pParent ) { HRESULT hRes = pSite->m_pSink->QueryInterface( iid, ppvItf ); if( SUCCEEDED( hRes ) ) // Found our requested interface, return happy return hRes; } return E_NOINTERFACE; } STDMETHODIMP cLayerSite::get_Position(LPRECT pVal) { _ASSERTE( pVal != NULL ); *pVal = m_params.pos; return S_OK; } STDMETHODIMP cLayerSite::put_Position(LPRECT newVal) { _ASSERTE( newVal != NULL ); _ASSERTE( newVal->right >= newVal->left && newVal->bottom >= newVal->top ); m_params.pos = *newVal; if( !( m_params.render & eRenderClipped ) ) { // This is unclipped, check the buffer size bool bHasBuffer = ( m_params.pos.right > m_params.pos.left && m_params.pos.bottom > m_params.pos.top ); if( bHasBuffer ) { SIZE sz = { m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top }; if( m_pBuffer.p == NULL ) cManager::_p->CreateCanvas( &sz, &m_pBuffer ); else m_pBuffer->put_Size( &sz ); } else { if( m_pBuffer.p != NULL ) m_pBuffer.Release(); } } // Mark for format change only if area > 0 Reformat(); return S_OK; } STDMETHODIMP cLayerSite::get_ID(long *pVal) { _ASSERTE( pVal != NULL ); *pVal = m_params.ID; return S_OK; } STDMETHODIMP cLayerSite::get_ChildCount(long *pVal) { _ASSERTE( pVal != NULL ); *pVal = m_children.size(); return S_OK; } STDMETHODIMP cLayerSite::get_Child(long nIndex, ePositionType posType, ILayerSite **pVal) { _ASSERTE( pVal != NULL ); if( posType == ePositionByIndex ) { if( nIndex < 0 || nIndex >= m_children.size() ) // Out of range return E_INVALIDARG; *pVal = m_children[ nIndex ]; ( *pVal )->AddRef(); return S_OK; } if( posType != ePositionByID ) // Invalid position type return E_INVALIDARG; // Scan for child by ID for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i ) { if( ( *i )->m_params.ID == nIndex ) { *pVal = *i; ( *pVal )->AddRef(); return S_OK; } } // Invalid Index return E_INVALIDARG; } void cLayerSite::moveChildToFront(long nIndex) { // TODO : Fix this, it doesn't properly move the Z order of the children if they are at the front if( m_children.back()->m_params.ID == nIndex ) return; for (cChildList::iterator i = m_children.begin(); i != m_children.end(); ++i) { if((*i)->m_params.ID == nIndex) { cLayerSite *layerSite = *i; m_children.erase(i); m_children.push_back(layerSite); break; } } } STDMETHODIMP cLayerSite::moveToFront() { _ASSERTE(m_pParent); m_pParent->moveChildToFront(m_params.ID); return S_OK; } STDMETHODIMP cLayerSite::CaptureKeyboard() { // Cancel capture in the existing keyboard capture- if any // Don't fire EndCapture if we already have the capture. cyn -- 15/10/2002 if( ( cManager::_p->m_pKeyboard != NULL ) && ( cManager::_p->m_pKeyboard != this ) ) cManager::_p->m_pKeyboard->sendKeyboardEndCapture( VARIANT_TRUE ); // Start capturing cManager::_p->m_pKeyboard = this; return S_OK; } STDMETHODIMP cLayerSite::IsChild(ILayerSite *pSite, VARIANT_BOOL bTestUnclipped, VARIANT_BOOL *pbIsChild) { cLayerSite *pInternalSite = static_cast< cLayerSite * >( pSite ); *pbIsChild = ( ( bTestUnclipped ) ? isChild( pInternalSite ) : isClippedChild( pInternalSite ) ) ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } STDMETHODIMP cLayerSite::put_Popup(VARIANT_BOOL newVal) { if( newVal ) { #ifdef _DEBUG // Check for an existing popup record for( cManager::cLayerList::iterator i = cManager::_p->m_popups.begin(); i != cManager::_p->m_popups.end(); ++ i ) _ASSERTE( *i != this ); #endif // Ok, add it into the list cManager::_p->m_popups.push_back( this ); } else { for( cManager::cLayerList::iterator i = cManager::_p->m_popups.begin(); i != cManager::_p->m_popups.end(); ++ i ) { if( *i == this ) { cManager::_p->m_popups.erase( i ); return S_OK; } } // This popup is not in the list _ASSERTE( FALSE ); } return S_OK; } STDMETHODIMP cLayerSite::get_ScreenPosition(LPRECT pVal) { CComPtr< ICanvas > pPrimary; cManager::_p->GetPrimarySurface( &pPrimary ); { ClipParams cp; pPrimary->GetClipParams( &cp ); // First push the identity RECT RECT rcIdentity = { 0, 0, cp.window.right - cp.window.left, cp.window.bottom - cp.window.top }; VARIANT_BOOL bVisible; pPrimary->PushClipRect( &rcIdentity, &bVisible ); // Now set the origin POINT pt = { cp.window.left, cp.window.top }; pPrimary->OffsetOrg( &pt, &bVisible ); } // ::MessageBox( NULL, _T( "cLayerSite::get_ScreenPosition" ), _T( "Inject.dll" ), MB_OK ); clipCanvas( pPrimary ); // Extract the bounds ClipParams cp; pPrimary->GetClipParams( &cp ); *pVal = cp.window; return S_OK; } STDMETHODIMP cLayerSite::StartTimer(long nID, long nInterval) { #ifdef _DEBUG // Walk through the list of timers to make sure the ID isn't in use for( cTimerList::iterator i = m_timers.begin(); i != m_timers.end(); ++ i ) _ASSERTE( i->m_nID != nID ); #endif // NOTE: An interval of 0 is valid in that it'll fire every frame, this would be an // alternate method to creating an animated layer _ASSERTE( nInterval >= 0 ); // The layer should implement ILayerTimer _ASSERTE( m_dwSinkCaps & eSinkCapTimer ); // Add in the timer cTimer t = { ::timeGetTime(), nID, nInterval, 0 }; m_timers.push_back( t ); return S_OK; } STDMETHODIMP cLayerSite::EndTimer(long nID) { // Find the timer by ID for( cTimerList::iterator i = m_timers.begin(); i != m_timers.end(); ++ i ) { if( i->m_nID == nID ) { m_timers.erase( i ); return S_OK; } } return E_INVALIDARG; } STDMETHODIMP cLayerSite::get_Transparent(VARIANT_BOOL *pVal) { _ASSERTE( pVal != NULL ); *pVal = ( m_params.render & eRenderTransparent ) ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } STDMETHODIMP cLayerSite::put_Transparent(VARIANT_BOOL newVal) { if( newVal ) m_params.render |= eRenderTransparent; else m_params.render &= ~eRenderTransparent; return S_OK; } STDMETHODIMP cLayerSite::put_Alpha(long Alpha) { m_Alpha = Alpha; return S_OK; }