Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1193 lines
36 KiB

/////////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1997 Active Voice Corporation. All Rights Reserved.
//
// Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation.
//
// Other brand and product names used herein are trademarks of their respective owners.
//
// The entire program and user interface including the structure, sequence, selection,
// and arrangement of the dialog, the exclusively "yes" and "no" choices represented
// by "1" and "2," and each dialog message are protected by copyrights registered in
// the United States and by international treaties.
//
// Protected by one or more of the following United States patents: 5,070,526, 5,488,650,
// 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054.
//
// Active Voice Corporation
// Seattle, Washington
// USA
//
/////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// ConfRoomMembersWnd.cpp
//
#include "stdafx.h"
#include "TapiDialer.h"
#include "ConfRoom.h"
// Helper functions...
void AdvanceRect( RECT& rc, const RECT& rcClient, POINT &pt, const SIZE& sz, short nNumLines, VARIANT_BOOL bShowNames, LONG nHeight )
{
// Basic rectangle dimensions...
rc.left = pt.x;
rc.right = pt.x + sz.cx;
rc.top = pt.y;
rc.bottom = pt.y + sz.cy;
pt.x += RECTWIDTH(&rc) + VID_DX;
if ( (pt.x + RECTWIDTH(&rc)) > rcClient.right )
{
pt.x = VID_DX;
pt.y += RECTHEIGHT(&rc) + VID_DY;
// Include space for the names?
if ( bShowNames )
pt.y += nNumLines * nHeight;
}
}
HRESULT PlaceVideoWindow( IVideoWindow *pVideo, HWND hWnd, const RECT& rc )
{
_ASSERT( pVideo );
HWND hWndTemp;
HRESULT hr = pVideo->get_Owner( (OAHWND FAR*) &hWndTemp );
if ( SUCCEEDED(hr) )
{
pVideo->put_Visible( OAFALSE );
pVideo->put_Owner( (ULONG_PTR) hWnd );
pVideo->put_MessageDrain( (ULONG_PTR) ::GetParent(hWnd) );
pVideo->put_WindowStyle( WS_CHILD | WS_BORDER );
// Reposition window and set visibility accordingly
pVideo->SetWindowPosition( rc.left, rc.top, RECTWIDTH(&rc), RECTHEIGHT(&rc) );
pVideo->put_Visible( OATRUE );
}
return hr;
}
HRESULT SizeVideoWindow( IVideoWindow *pVideo, HWND hWnd, const RECT& rc )
{
// Only show ones that we actually now own!
HWND hWndOwner;
HRESULT hr = pVideo->get_Owner( (OAHWND FAR*) &hWndOwner );
if ( FAILED(hr) ) return hr;
// Take ownership of the window if it's just floating
if ( !hWndOwner )
{
PlaceVideoWindow( pVideo, hWnd, rc );
}
else if ( (hWndOwner == hWnd) )
{
long nLeft, nTop, nWidth, nHeight;
hr = pVideo->GetWindowPosition( &nLeft, &nTop, &nWidth, &nHeight );
if ( SUCCEEDED(hr) )
{
if ( (nLeft != rc.left) || (nTop != rc.top) || (nWidth != RECTWIDTH(&rc)) || (nHeight != RECTHEIGHT(&rc)) )
hr = pVideo->SetWindowPosition( rc.left, rc.top, RECTWIDTH(&rc), RECTHEIGHT(&rc) );
// Set visible only if necessary
if ( SUCCEEDED(hr) )
{
long lVisible;
pVideo->get_Visible( &lVisible );
if ( !lVisible )
hr = pVideo->put_Visible( OATRUE );
}
}
}
return hr;
}
#define MY_TIMER_ID 540
UINT CConfRoomMembersWnd::m_nFontHeight = 0;
CConfRoomMembersWnd::CConfRoomMembersWnd()
{
m_pConfRoomWnd = NULL;
m_nTimerID = 0;
}
CConfRoomMembersWnd::~CConfRoomMembersWnd()
{
EmptyList();
}
void CConfRoomMembersWnd::EmptyList()
{
RELEASE_CRITLIST_TRACE(m_lstFeeds, m_critFeedList );
}
HRESULT CConfRoomMembersWnd::FindVideoFeedFromParticipant( ITParticipant *pParticipant, IVideoFeed **ppFeed )
{
*ppFeed = NULL;
if ( !pParticipant ) return E_POINTER;
HRESULT hr = E_FAIL;
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
ITParticipant *pNewParticipant;
if ( SUCCEEDED((*i)->get_ITParticipant(&pNewParticipant)) && pNewParticipant )
{
if ( pNewParticipant == pParticipant )
{
hr = (*i)->QueryInterface( IID_IVideoFeed, (void **) ppFeed );
pNewParticipant->Release();
break;
}
pNewParticipant->Release();
}
}
m_critFeedList.Unlock();
return hr;
}
HRESULT CConfRoomMembersWnd::FindVideoPreviewFeed( IVideoFeed **ppFeed )
{
HRESULT hr = E_FAIL;
*ppFeed = NULL;
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
VARIANT_BOOL bPreview;
if ( SUCCEEDED((*i)->get_bPreview(&bPreview)) && bPreview )
{
hr = (*i)->QueryInterface( IID_IVideoFeed, (void **) ppFeed );
break;
}
}
m_critFeedList.Unlock();
return hr;
}
HRESULT CConfRoomMembersWnd::FindVideoFeed( IVideoWindow *pVideo, IVideoFeed **ppFeed )
{
*ppFeed = NULL;
if ( !pVideo ) return E_POINTER;
HRESULT hr = E_FAIL;
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
IVideoWindow *pNewVideo;
if ( SUCCEEDED((*i)->get_IVideoWindow((IUnknown **) &pNewVideo)) )
{
if ( pNewVideo == pVideo )
{
hr = (*i)->QueryInterface( IID_IVideoFeed, (void **) ppFeed );
pNewVideo->Release();
break;
}
pNewVideo->Release();
}
}
m_critFeedList.Unlock();
return hr;
}
IVideoFeed* CConfRoomMembersWnd::NewFeed( IVideoWindow *pVideo, const RECT& rc, VARIANT_BOOL bPreview )
{
// Store location of video feed info
IVideoFeed *pFeed = NULL;
if ( SUCCEEDED(FindVideoFeed(pVideo, &pFeed)) )
{
// Already represented on the list, don't bother adding
pFeed->Release();
}
else
{
// Add video feed to list
ATLTRACE(_T(".1.CConfRoomMembersWnd::NewVideo() -- adding video feed to list bPreview = %d.\n"), bPreview );
pFeed = new CComObject<CVideoFeed>;
if ( pFeed )
{
pFeed->AddRef();
pFeed->put_IVideoWindow( pVideo );
// Set position of feed
pFeed->put_rc( rc );
pFeed->put_bPreview( bPreview );
m_critFeedList.Lock();
if ( bPreview )
m_lstFeeds.push_front( pFeed );
else
m_lstFeeds.push_back( pFeed );
m_critFeedList.Unlock();
}
}
return pFeed;
}
HRESULT CConfRoomMembersWnd::Layout()
{
ATLTRACE(_T(".enter.CConfRoomMembersWnd::Layout().\n"));
HRESULT hr = S_FALSE;
if ( !IsWindow(m_hWnd) ) return hr;
m_critLayout.Lock();
_ASSERT( m_pConfRoomWnd && m_pConfRoomWnd->m_pConfRoom );
RECT rcClient;
GetClientRect( &rcClient );
POINT pt = { VID_DX, VID_DY };
VARIANT_BOOL bShowNames;
short nNumLines;
m_pConfRoomWnd->m_pConfRoom->get_bShowNames( &bShowNames );
m_pConfRoomWnd->m_pConfRoom->get_nShowNamesNumLines( &nNumLines );
// Retrieve font metrics if we're showing names
long nHeight;
if ( bShowNames ) nHeight = GetFontHeight();
short nPreview = 0;
short nCount = 0;
short nNumTerms;
SIZE sz;
IAVTapiCall *pAVCall = NULL;
// IVideoWindow *pTalker = NULL;
m_pConfRoomWnd->m_pConfRoom->get_IAVTapiCall( &pAVCall );
// Empty feed list
EmptyList();
// m_pConfRoomWnd->m_pConfRoom->get_TalkerVideo( (IDispatch **) &pTalker );
m_pConfRoomWnd->m_pConfRoom->get_nNumTerms( &nNumTerms );
m_pConfRoomWnd->m_pConfRoom->get_szMembers( &sz );
// Set up the original coordinates of the target rect
RECT rc = { pt.x, pt.y, pt.x + sz.cx, pt.y + sz.cy };
// Should we add the preview to the list?
CComPtr<IAVTapi> pAVTapi;
if ( pAVCall && (m_pConfRoomWnd->m_pConfRoom->IsConfRoomConnected() == S_OK) && SUCCEEDED(_Module.get_AVTapi(&pAVTapi)) )
{
// show preview in list of conference memebers
IVideoWindow *pPreviewVideo;
if ( SUCCEEDED(pAVCall->get_IVideoWindowPreview((IDispatch **) &pPreviewVideo)) )
{
nPreview = 1;
// Store for later reference
m_pConfRoomWnd->m_pConfRoom->set_PreviewVideo(pPreviewVideo);
if ( pAVCall->IsPreviewStreaming() == S_OK )
{
PlaceVideoWindow( pPreviewVideo, m_hWnd, rc );
AdvanceRect( rc, rcClient, pt, sz, nNumLines, bShowNames, nHeight );
}
else
{
// Insure window is hidden
pPreviewVideo->put_Visible( OAFALSE );
}
NewFeed( pPreviewVideo, rc, TRUE );
pPreviewVideo->Release();
}
}
// Loop for nNumTerms when there is no AVTapiCall, and loop for all terminals
// selected when there is an AVTapiCall
bool bContinue = true;
for ( int i = 0; (!pAVCall && (i < nNumTerms)) || (pAVCall && bContinue); i++ )
{
AdvanceRect( rc, rcClient, pt, sz, nNumLines, bShowNames, nHeight );
// If we have a call then assign an IVideoWindow interface to each feed
if ( pAVCall )
{
IVideoWindow *pVideo = NULL;
if ( pAVCall->get_IVideoWindow(nCount, (IDispatch **) &pVideo) == S_OK )
{
// Don't mess with talker video window
// if ( pVideo != pTalker )
hr = PlaceVideoWindow( pVideo, m_hWnd, rc );
// Increment counter
nCount++;
NewFeed( pVideo, rc, FALSE );
pVideo->Release();
}
else
{
// No more terminals, stop loop
bContinue = false;
}
}
else
{
NewFeed( NULL, rc, FALSE );
}
}
// Setup or destroy timer
if ( pAVCall && ((nCount + nPreview) > 0) && !m_nTimerID )
{
m_nTimerID = SetTimer( MY_TIMER_ID, 450, NULL );
}
else if ( !nCount && m_nTimerID )
{
if ( KillTimer(MY_TIMER_ID) )
m_nTimerID = 0;
}
RELEASE( pAVCall );
// RELEASE( pTalker );
m_critLayout.Unlock();
return hr;
}
HRESULT CConfRoomMembersWnd::HitTest( POINT pt, IVideoFeed **ppFeed )
{
HRESULT hr = E_FAIL;
*ppFeed = NULL;
ScreenToClient( &pt );
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
RECT rc;
(*i)->get_rc( &rc );
if ( PtInRect(&rc, pt) )
{
hr = (*i)->QueryInterface( IID_IVideoFeed, (void **) ppFeed );
break;
}
}
m_critFeedList.Unlock();
return hr;
}
void CConfRoomMembersWnd::ClearFeed( IVideoWindow *pVideo )
{
if ( !IsWindow(m_hWnd) ) return;
// Make sure we have a valid conference room pointer
if ( m_pConfRoomWnd && m_pConfRoomWnd->m_pConfRoom && !m_pConfRoomWnd->m_pConfRoom->IsExiting() )
{
IVideoFeed *pFeed;
if ( SUCCEEDED(FindVideoFeed(pVideo, &pFeed)) )
{
RECT rc;
pFeed->get_rc( &rc );
// Make a copy of the talker window
HDC hDC = GetDC();
if ( hDC )
{
// Erase border around feed
InflateRect( &rc, SEL_DX, SEL_DY );
rc.right++;
HBRUSH hbr = (HBRUSH) GetClassLongPtr( m_hWnd, GCLP_HBRBACKGROUND );
Erase3dBox( hDC, rc, hbr );
//
// We'll release here hDC resource, we don't need it anymore
//
ReleaseDC( hDC );
}
// Drop video feed back onto the members window
HWND hWndTemp;
if ( SUCCEEDED(pVideo->get_Owner((OAHWND FAR*) &hWndTemp)) )
{
pVideo->put_Visible( OAFALSE );
pVideo->put_Owner( (ULONG_PTR) m_hWnd );
pVideo->put_MessageDrain( (ULONG_PTR) GetParent() );
pVideo->SetWindowPosition( rc.left, rc.top, RECTWIDTH(&rc), RECTHEIGHT(&rc) );
pVideo->put_Visible( OATRUE );
}
pFeed->Release();
}
}
}
void CConfRoomMembersWnd::UpdateTalkerFeed( bool bUpdateAll, bool bForceSelect )
{
// Make sure we have a valid conference room pointer
if ( m_pConfRoomWnd && m_pConfRoomWnd->m_pConfRoom &&
(m_pConfRoomWnd->m_wndTalker.m_dlgTalker.m_callState == CS_CONNECTED) )
{
// If the talker video is invalid, or not showing video, select another
IVideoWindow *pVideo = NULL;
m_pConfRoomWnd->m_pConfRoom->get_TalkerVideo( (IDispatch **) &pVideo );
IAVTapiCall *pAVCall = NULL;
m_pConfRoomWnd->m_pConfRoom->get_IAVTapiCall( &pAVCall );
// Is the user requesting that we select something as the talker?
if ( pAVCall && bForceSelect && (!pVideo || (IsVideoWindowStreaming(pVideo) == S_FALSE)) )
{
RELEASE( pVideo );
// Find some video that's actually streaming
m_pConfRoomWnd->m_pConfRoom->GetFirstVideoWindowThatsStreaming((IDispatch **) &pVideo);
// Try for preview?
if ( !pVideo )
{
CComPtr<IAVTapi> pAVTapi;
if ( SUCCEEDED(_Module.get_AVTapi(&pAVTapi)) )
pAVCall->get_IVideoWindowPreview( (IDispatch **) &pVideo );
}
// Select the new talker
if ( pVideo )
m_pConfRoomWnd->m_pConfRoom->set_TalkerVideo( pVideo, false, true );
}
RELEASE( pAVCall );
// Get the video feed associated with the talker
IVideoFeed *pFeed = NULL;
if ( pVideo )
{
// Get the CVideoFeed object that's associated with the IVideoWindow
FindVideoFeed( pVideo, &pFeed );
pVideo->Release();
}
// Do we have a valid feed?
if ( pFeed )
{
HWND hWndTalker = FindWindowEx( m_pConfRoomWnd->m_wndTalker.m_hWnd, NULL, _T("VideoRenderer"), NULL );
if ( hWndTalker )
{
// Make a copy of the talker window
HDC hDC = GetDC();
if ( hDC )
{
if ( bUpdateAll )
pFeed->Paint( (ULONG_PTR) hDC, hWndTalker );
// Copy name off of dialog -- this way we don't risk deadlock with TAPI
BSTR bstrName = NULL;
SysReAllocString( &bstrName, m_pConfRoomWnd->m_wndTalker.m_dlgTalker.m_bstrCallerID );
if ( !bstrName )
{
USES_CONVERSION;
TCHAR szText[255];
LoadString( _Module.GetResourceInstance(), IDS_NO_PARTICIPANT, szText, ARRAYSIZE(szText) );
bstrName = SysAllocString( T2COLE(szText) );
}
if ( bstrName )
{
PaintFeedName( hDC, bstrName, pFeed );
SysFreeString( bstrName );
}
}
ReleaseDC( hDC );
}
pFeed->Release();
}
}
}
void CConfRoomMembersWnd::PaintFeed( HDC hDC, IVideoFeed *pFeed )
{
// These items must be defined to paint the feed
if ( !m_pConfRoomWnd || !m_pConfRoomWnd->m_pConfRoom ||
!m_pConfRoomWnd->m_hBmpFeed_Large || !m_pConfRoomWnd->m_hBmpFeed_Small )
{
return;
}
bool bFreeDC = false;
if ( !hDC )
{
hDC = GetDC();
bFreeDC = true;
}
// Draw the feed bitmap
if ( hDC )
{
// Show stock video feed window
RECT rc;
pFeed->get_rc( &rc );
Draw( hDC, (RECTWIDTH(&rc) == VID_SX) ? m_pConfRoomWnd->m_hBmpFeed_Small : m_pConfRoomWnd->m_hBmpFeed_Large,
rc.left, rc.top,
RECTWIDTH(&rc), RECTHEIGHT(&rc) );
// Clean up
if ( bFreeDC )
ReleaseDC( hDC );
}
}
void CConfRoomMembersWnd::PaintFeedName( HDC hDC, BSTR bstrName, IVideoFeed *pFeed )
{
_ASSERT( hDC && bstrName && pFeed );
_ASSERT( m_pConfRoomWnd && m_pConfRoomWnd->m_pConfRoom );
USES_CONVERSION;
VARIANT_BOOL bShowNames;
m_pConfRoomWnd->m_pConfRoom->get_bShowNames( &bShowNames );
if ( bShowNames )
{
// Don't paint feeds that aren't presently visible
IVideoWindow *pVideo;
if ( SUCCEEDED(pFeed->get_IVideoWindow((IUnknown **) &pVideo)) )
{
long lVisible = 0;
pVideo->get_Visible( &lVisible );
pVideo->Release();
if ( !lVisible )
return;
}
// Select same font as is TreeView if exists
HFONT hFontOld = NULL;
HWND hWnd = m_pConfRoomWnd->m_wndTalker.m_dlgTalker.GetDlgItem( IDC_LBL_CALLERID );
if ( hWnd )
hFontOld = (HFONT) SelectObject(hDC, (HFONT) ::SendMessage(hWnd, WM_GETFONT, 0, 0));
// Get height of font so we can determine our painting rect
TEXTMETRIC tm;
GetTextMetrics( hDC, &tm );
// Rectangle for writing text
short nNumLines = 1;
m_pConfRoomWnd->m_pConfRoom->get_nShowNamesNumLines( &nNumLines );
RECT rc;
pFeed->get_rc( &rc );
rc.top = rc.bottom + (VID_DY / 2);
rc.bottom = rc.top + (tm.tmHeight * nNumLines) + (VID_DY / 2);
// Erase rectangle for painting
HBRUSH hbrOld = (HBRUSH) SelectObject( hDC, GetSysColorBrush(COLOR_BTNFACE) );
PatBlt( hDC, rc.left, rc.top, RECTWIDTH(&rc), RECTHEIGHT(&rc), PATCOPY );
SelectObject( hDC, hbrOld );
// Use same background color
COLORREF crOld = SetBkColor( hDC, GetSysColor(COLOR_BTNFACE) );
COLORREF crTextOld = SetTextColor( hDC, GetSysColor(COLOR_BTNTEXT) );
DrawText( hDC, OLE2CT(bstrName), SysStringLen(bstrName), &rc, DT_CENTER | DT_WORDBREAK | DT_EDITCONTROL | DT_NOPREFIX );
SetTextColor( hDC, crTextOld );
SetBkColor( hDC, crOld );
if ( hFontOld ) SelectObject( hDC, hFontOld );
}
}
void CConfRoomMembersWnd::PaintFeedName( HDC hDC, IVideoFeed *pFeed )
{
_ASSERT( hDC && pFeed );
BSTR bstrName = NULL;
if ( SUCCEEDED(pFeed->get_bstrName(&bstrName)) && bstrName )
{
PaintFeedName( hDC, bstrName, pFeed );
}
SysFreeString( bstrName );
}
long CConfRoomMembersWnd::GetFontHeight()
{
return m_nFontHeight;
}
//////////////////////////////////////////////////////////////////
// Message Handlers
//
LRESULT CConfRoomMembersWnd::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
SetClassLongPtr( m_hWnd, GCLP_HBRBACKGROUND, GetClassLongPtr(GetParent(), GCLP_HBRBACKGROUND) );
// Store the font height to be used later
if ( !m_nFontHeight )
{
TEXTMETRIC tm;
tm.tmHeight = 0;
HDC hDC = GetDC();
if ( hDC )
{
HFONT hFontOld = (HFONT) SelectObject( hDC, GetFont() );
GetTextMetrics( hDC, &tm );
// Clean up
SelectObject( hDC, hFontOld );
ReleaseDC( hDC );
}
m_nFontHeight = tm.tmHeight;
}
return 0;
}
LRESULT CConfRoomMembersWnd::OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
if ( m_nTimerID ) KillTimer( m_nTimerID );
return 0;
}
LRESULT CConfRoomMembersWnd::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint( &ps );
if ( !hDC ) return 0;
IVideoWindow *pTalkerVideo = NULL;
if ( m_pConfRoomWnd && m_pConfRoomWnd->m_pConfRoom )
m_pConfRoomWnd->m_pConfRoom->get_TalkerVideo( (IDispatch **) &pTalkerVideo );
m_critFeedList.Lock();
// Draw stock video feed windows
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
// Paint picture of a TV
IVideoWindow *pVideo = NULL;
(*i)->get_IVideoWindow( (IUnknown **) &pVideo );
// Is the preview not streaming video?
bool bPreviewNotStreaming = false;
VARIANT_BOOL bPreview;
(*i)->get_bPreview( &bPreview );
if ( bPreview )
{
IAVTapiCall *pAVCall;
if ( SUCCEEDED(m_pConfRoomWnd->m_pConfRoom->get_IAVTapiCall(&pAVCall)) )
{
if ( pAVCall->IsPreviewStreaming() == S_FALSE )
bPreviewNotStreaming = true;
pAVCall->Release();
}
}
if ( !pVideo || (bPreview && bPreviewNotStreaming) )
PaintFeed( hDC, *i );
// Draw name
if ( !pTalkerVideo || (pVideo != pTalkerVideo) )
PaintFeedName( hDC, *i );
RELEASE(pVideo);
}
EndPaint( &ps );
m_critFeedList.Unlock();
// Repaint talker window
UpdateTalkerFeed( true, false );
RELEASE( pTalkerVideo );
bHandled = true;
return 0;
}
LRESULT CConfRoomMembersWnd::OnContextMenu(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
bHandled = true;
return ::SendMessage( GetParent(), nMsg, wParam, lParam );
}
LRESULT CConfRoomMembersWnd::OnTimer(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
bHandled = true;
UpdateTalkerFeed( true, false );
return 0;
}
LRESULT CConfRoomMembersWnd::OnParentNotify(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
// validate back pointer objects
if ( !m_pConfRoomWnd || !m_pConfRoomWnd->m_pConfRoom ) return 0;
if ( LOWORD(wParam) == WM_LBUTTONDOWN )
{
bHandled = true;
POINT pt;
GetCursorPos( &pt );
IVideoFeed *pFeed;
if ( SUCCEEDED(HitTest(pt, &pFeed)) )
{
IVideoWindow *pVideo;
if ( SUCCEEDED(pFeed->get_IVideoWindow((IUnknown **) &pVideo)) )
{
m_pConfRoomWnd->m_pConfRoom->set_TalkerVideo( pVideo, true, true );
pVideo->Release();
}
pFeed->Release();
}
}
return 0;
}
LRESULT CConfRoomMembersWnd::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
BOOL bHandledLayout;
return OnLayout( WM_LAYOUT, -1, -1, bHandledLayout );
}
LRESULT CConfRoomMembersWnd::OnLayout(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
DoLayout( wParam, lParam );
return 0;
}
void CConfRoomMembersWnd::DoLayout( WPARAM wParam, int nScrollPos )
{
if ( !m_pConfRoomWnd || !m_pConfRoomWnd->m_pConfRoom ) return;
VARIANT_BOOL bShowNames;
short nNumLines;
SIZE sz;
m_pConfRoomWnd->m_pConfRoom->get_bShowNames( &bShowNames );
m_pConfRoomWnd->m_pConfRoom->get_nShowNamesNumLines( &nNumLines );
m_pConfRoomWnd->m_pConfRoom->get_szMembers( &sz );
// Retrieve font metrics if we're showing names
long nHeight;
if ( bShowNames ) nHeight = GetFontHeight();
// Get size of client area to paint in
bool bAdvance = true;
RECT rcClient;
GetClientRect( &rcClient );
POINT pt = { VID_DX, VID_DY };
RECT rc = { pt.x, pt.y, pt.x + sz.cx, pt.y + sz.cy };
// Do all the messy calculations for laying out the video widows
int nFeedHeight = pt.y + sz.cy + ((bShowNames) ? nHeight : 0);
int nNumFeedsHorz = (RECTWIDTH(&rcClient) / (pt.x + sz.cx));
if ( nNumFeedsHorz == 0 ) nNumFeedsHorz = 1; // must have at least one feed
int nMaxFeeds = nNumFeedsHorz * (RECTHEIGHT(&rcClient) / nFeedHeight);
int nNumFeeds = GetStreamingCount();
//////////////////////////////////////////////////////////////
// Scroll bar setup
SCROLLINFO scrollInfo = { 0 };
scrollInfo.cbSize = sizeof(SCROLLINFO);
scrollInfo.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
GetScrollInfo( m_hWnd, SB_VERT, &scrollInfo );
// Process scroll requests
bool bBoundaryCheck = true;
switch ( wParam )
{
case SB_LINEUP: nScrollPos = scrollInfo.nPos - nFeedHeight; break;
case SB_PAGEUP: nScrollPos = scrollInfo.nPos - scrollInfo.nPage; break;
case SB_LINEDOWN: nScrollPos = scrollInfo.nPos + nFeedHeight; break;
case SB_PAGEDOWN: nScrollPos = scrollInfo.nPos + scrollInfo.nPage; break;
default:
bBoundaryCheck = false;
break;
}
// Make sure our scroll bar is within range
if ( bBoundaryCheck )
{
if ( nScrollPos < 0 ) nScrollPos = 0;
GetClientRect( &rcClient );
if ( nScrollPos > (scrollInfo.nMax - (RECTHEIGHT(&rcClient) - 1)) )
nScrollPos = scrollInfo.nMax - (RECTHEIGHT(&rcClient) - 1);
}
// -1 indicates that scroll position should not be set
if ( nScrollPos == -1 )
nScrollPos = scrollInfo.nPos;
scrollInfo.nPage = RECTHEIGHT(&rcClient);
scrollInfo.nPos = nScrollPos;
if ( nNumFeeds > 0 )
{
scrollInfo.nMax = (nNumFeeds / nNumFeedsHorz) * nFeedHeight;
if ( (nNumFeeds % nNumFeedsHorz) != 0 ) scrollInfo.nMax += nFeedHeight;
}
SetScrollInfo( m_hWnd, SB_VERT, &scrollInfo, true );
// Ignore scroll position if we can fit everything onto the display
if ( nNumFeeds <= nMaxFeeds )
nScrollPos = 0;
// Account for scrolling when painting
pt.y -= nScrollPos;
////////////////////////////////////////////////////////////////////
// Start placing the video feed windows
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i = m_lstFeeds.begin(), iEnd = m_lstFeeds.end();
while ( i != iEnd )
{
// Position the video feed
if ( bAdvance )
{
AdvanceRect( rc, rcClient, pt, sz, nNumLines, bShowNames, nHeight );
bAdvance = false;
}
// Store coordinates for video feed
(*i)->put_rc( rc );
// Are we showing preview? Show it first
IVideoWindow *pVideo;
VARIANT_BOOL bPreview;
(*i)->get_bPreview(&bPreview);
if ( bPreview )
{
// Size the preview window
CComPtr<IAVTapi> pAVTapi;
if ( SUCCEEDED(_Module.get_AVTapi(&pAVTapi)) )
{
if ( SUCCEEDED((*i)->get_IVideoWindow((IUnknown **) &pVideo)) )
{
// show preview in list of conference memebers
if ( SUCCEEDED(SizeVideoWindow(pVideo, m_hWnd, rc)) )
{
bAdvance = true;
// Must set as different background palette for low color systems
HDC hDC = GetDC();
if ( hDC )
{
int nNumBits = GetDeviceCaps( hDC, BITSPIXEL );
pVideo->put_BackgroundPalette( (nNumBits > 8) ? OAFALSE : OATRUE );
ReleaseDC( hDC );
}
}
pVideo->Release();
}
}
// Failed to position the video feed for one reason or another
if ( !bAdvance )
{
RECT rcTemp = { -1, -1, -1, -1 };
(*i)->put_rc( rcTemp );
}
}
else
{
// Only show the video window if it has a participant associated with it
if ( SUCCEEDED((*i)->get_IVideoWindow((IUnknown **) &pVideo)) )
{
// Size the member video window
if ( ((*i)->IsVideoStreaming(true) == S_OK) &&
SUCCEEDED(SizeVideoWindow(pVideo, m_hWnd, rc)) )
{
bAdvance = true;
}
else
{
// Hide this video window!
pVideo->put_Visible( OAFALSE );
RECT rcTemp = { -1, -1, -1, -1 };
(*i)->put_rc( rcTemp );
}
pVideo->Release();
}
else
{
bAdvance = true;
}
}
i++;
}
m_critFeedList.Unlock();
}
void CConfRoomMembersWnd::UpdateNames( ITParticipant *pParticipant )
{
VIDEOFEEDLIST lstTemp;
VIDEOFEEDLIST::iterator i, iEnd;
HDC hDC = GetDC();
if ( hDC )
{
// Copy the name list prior to update
m_critFeedList.Lock();
iEnd = m_lstFeeds.end();
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
(*i)->AddRef();
lstTemp.push_back( *i );
}
m_critFeedList.Unlock();
// Draw stock video feed windows
iEnd = lstTemp.end();
for ( i = lstTemp.begin(); i != iEnd; i++ )
{
// Does this participant need to update their name?
ITParticipant *pIndParticipant = NULL;
if ( SUCCEEDED((*i)->get_ITParticipant(&pIndParticipant)) )
{
if ( !pParticipant || (pParticipant == pIndParticipant) )
(*i)->UpdateName();
pIndParticipant->Release();
}
// Paint it.
PaintFeedName( hDC, *i );
}
UpdateTalkerFeed( false, false );
ReleaseDC( hDC );
}
RELEASE_LIST( lstTemp );
}
void CConfRoomMembersWnd::HideVideoFeeds()
{
ATLTRACE(_T(".enter.CConfRoomMembersWnd::HideVideoFeeds().\n"));
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
IVideoWindow *pVideo;
if ( SUCCEEDED((*i)->get_IVideoWindow((IUnknown **) &pVideo)) )
{
pVideo->put_Visible( OAFALSE );
pVideo->SetWindowPosition( -10, -10, 1, 1 );
pVideo->Release();
}
}
m_critFeedList.Unlock();
}
HRESULT CConfRoomMembersWnd::GetFirstVideoWindowThatsStreaming( IVideoWindow **ppVideo, bool bIncludePreview /*= true*/ )
{
HRESULT hr = E_FAIL;
int nTries = (bIncludePreview) ? 2 : 1;
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( int j = 0; FAILED(hr) && (j < nTries); j ++ )
{
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
if ( (*i)->IsVideoStreaming((VARIANT_BOOL) (j != 0)) == S_OK )
{
hr = (*i)->get_IVideoWindow( (IUnknown **) ppVideo );
break;
}
}
}
m_critFeedList.Unlock();
return hr;
}
HRESULT CConfRoomMembersWnd::GetFirstVideoFeedThatsStreaming( IVideoFeed **ppFeed, bool bIncludePreview /*= true*/ )
{
HRESULT hr = E_FAIL;
int nTries = (bIncludePreview) ? 2 : 1;
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( int j = 0; FAILED(hr) && (j < nTries); j ++ )
{
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
if ( (*i)->IsVideoStreaming((VARIANT_BOOL) (j != 0)) == S_OK )
{
hr = (*i)->QueryInterface( IID_IVideoFeed, (void **) ppFeed );
break;
}
}
}
m_critFeedList.Unlock();
return hr;
}
HRESULT CConfRoomMembersWnd::GetAndMoveVideoFeedThatStreamingForParticipantReMap( IVideoFeed **ppFeed )
{
HRESULT hr = E_FAIL;
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
if ( (*i)->IsVideoStreaming(FALSE) == S_OK )
{
hr = (*i)->QueryInterface( IID_IVideoFeed, (void **) ppFeed );
if ( SUCCEEDED(hr) )
{
// Move the feed to the tail of the list
IVideoFeed *pFeed;
if ( SUCCEEDED((*i)->QueryInterface(IID_IVideoFeed, (void **) &pFeed)) )
{
(*i)->Release();
m_lstFeeds.erase( i );
m_lstFeeds.push_back( pFeed );
}
}
break;
}
}
m_critFeedList.Unlock();
return hr;
}
HRESULT CConfRoomMembersWnd::IsVideoWindowStreaming( IVideoWindow *pVideo )
{
HRESULT hr = E_FAIL;
bool bBreak = false;
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i, iEnd = m_lstFeeds.end();
for ( i = m_lstFeeds.begin(); i != iEnd; i++ )
{
IVideoWindow *pFeedsVideo;
if ( SUCCEEDED((*i)->get_IVideoWindow( (IUnknown **) &pFeedsVideo)) )
{
if ( pFeedsVideo == pVideo )
{
hr = (*i)->IsVideoStreaming( true );
bBreak = true;
}
pFeedsVideo->Release();
}
if ( bBreak ) break;
}
m_critFeedList.Unlock();
return hr;
}
HRESULT CConfRoomMembersWnd::GetNameFromVideo( IVideoWindow *pVideo, BSTR *pbstrName, BSTR *pbstrInfo, bool bAllowNull, bool bPreview )
{
HRESULT hr;
IVideoFeed *pFeed;
if ( SUCCEEDED(hr = FindVideoFeed(pVideo, &pFeed)) )
{
hr = pFeed->GetNameFromVideo( pVideo, pbstrName, pbstrInfo, bAllowNull, bPreview );
pFeed->Release();
}
return hr;
}
LRESULT CConfRoomMembersWnd::OnVScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
int nScrollCode = (int) LOWORD(wParam); // scroll bar value
int nPos = (short int) HIWORD(wParam); // scroll box position
switch ( nScrollCode )
{
case SB_LINEUP:
case SB_LINEDOWN:
case SB_PAGEUP:
case SB_PAGEDOWN:
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
PostMessage( WM_LAYOUT, nScrollCode, nPos );
Invalidate();
break;
}
return 0;
}
int CConfRoomMembersWnd::GetStreamingCount()
{
int nCount = 0;
long nLeft, nTop, nWidth, nHeight;
m_critFeedList.Lock();
VIDEOFEEDLIST::iterator i = m_lstFeeds.begin(), iEnd = m_lstFeeds.end();
while ( i != iEnd )
{
IVideoWindow *pVideo;
VARIANT_BOOL bPreview;
(*i)->get_bPreview(&bPreview);
if ( bPreview )
{
if ( SUCCEEDED((*i)->get_IVideoWindow((IUnknown **) &pVideo)) )
{
if ( SUCCEEDED(pVideo->GetWindowPosition(&nLeft, &nTop, &nWidth, &nHeight)) )
nCount++;
pVideo->Release();
}
}
else
{
// Only show the video window if it has a participant associated with it
if ( SUCCEEDED((*i)->get_IVideoWindow((IUnknown **) &pVideo)) )
{
// Size the member video window
if ( ((*i)->IsVideoStreaming(true) == S_OK) && SUCCEEDED(pVideo->GetWindowPosition(&nLeft, &nTop, &nWidth, &nHeight)) )
nCount++;
pVideo->Release();
}
else
{
nCount++;
}
}
i++;
}
m_critFeedList.Unlock();
return nCount;
}