|
|
#include "priv.h"
#include "sccls.h"
#include "resource.h"
#include "dhuihand.h"
#include <varutil.h>
#include "mstimeid.h"
#include <mluisupp.h>
#include "mediahlpr.h"
#include "mediaband.h"
#include "apithk.h"
#include "mbBehave.h"
#define SUPERCLASS CToolBand
#define MIN_WINDOW_WIDTH 145
#define MIN_WINDOW_HEIGHT 60
#define MIN_POPOUT_HEIGHT 300
#define MIN_POPOUT_WIDTH 300
#define MIN_VOLUME_WIDTH 50
#define MIN_VOLUME_HEIGHT 16
#define MIN_HORZ_SPACING 10
#define SEEK_PART_WIDTH 18
#define SEEK_PART_HEIGHT 5
#define SEEK_HEIGHT 16
#define VOLUME_GRIPPER_LENGTH 6
#define COLOR_BKGND16 RGB(192, 192, 192)
#define COLOR_BKGNDMIDDLE RGB(99, 129, 193)
#define VOLUME_BITMAP_WIDTH 42
#define VIDEO_MIN_HEIGHT 60
#define VIEW_MARGIN_BOTTOM 7
#define VIEW_MARGIN_LEFT 6
#define VIEW_MARGIN_INFO_LEFT 5
#define VIEW_MARGIN_RIGHT 10
#define VIEW_MARGIN_TOP 5
#define VIEW_MARGIN_TOP_VIDEO 6
#define VIEW_MARGIN_BOTTOM 7
#define VIEW_CONTROLS_HEIGHT 33
#define VIEW_CONTROLS_MARGIN 2
#define SCALEX(x) (_fHighDPI ? ((INT)(((float)(x))*_scaleX)) : (x))
#define SCALEY(x) (_fHighDPI ? ((INT)(((float)(x))*_scaleY)) : (x))
#define WZ_SMIE_MEDIA_MIME REG_MEDIA_STR TEXT("\\MimeTypes")
#define REG_VALUE_MRU_INTERNET REG_MEDIA_STR TEXT("\\Internet")
#define REG_VALUE_PATH TEXT("MusicPath")
//
// ISSUE: dilipk: these are localizable strings and need to be moved eventually !!!
//
#define WZ_WINDOWSMEDIA L"http://www.windowsmedia.com"
#define WZ_ASX_MIMETYPE L"video/x-ms-asx"
static const TCHAR c_szMediaBandProp[] = TEXT("CMediaBand_This"); static const TCHAR c_szMediaBarClassName[] = TEXT("MediaPane"); static const TCHAR c_szMediaBarPopupClassName[] = TEXT("MediaPopupPane"); static const TCHAR c_szMediaBarLayoutClassName[] = TEXT("MediaLayoutPane");
// ISSUE: these two should be deleted when reg utilities are completely moved to mediautil.cpp
static const UINT MAX_REG_VALUE_LENGTH = 50;
// This is the number of ticks (from MSTIME) to skip each time before polling System Time
// for the navigation timeout counter
#define POLL_INTERVAL 30
// This is the number of milli-seconds after which navigation times out
#define TIMEOUT_INTERVAL 90000
static const TCHAR c_szContentUrl[] = TEXT("http://go.microsoft.com/fwlink/?LinkId=511"); static const TCHAR c_szMoreMediaUrl[] = TEXT("http://go.microsoft.com/fwlink/?LinkId=512"); static const TCHAR c_szRadioUrl[] = TEXT("http://go.microsoft.com/fwlink/?LinkId=822");
static const TCHAR c_szOfflineURL[] = TEXT("mbOffline.htm"); static const TCHAR c_szLoadingURL[] = TEXT("mbLoading.htm"); static const TCHAR c_sz404URL[] = TEXT("mb404.htm");
extern HBITMAP CreateMirroredBitmap( HBITMAP hbmOrig);
//
// ISSUE: this is a temporary guid for the content pane sync feature.
//
static const IID SID_SMediaBarSync = { 0x2efc8085, 0x066b, 0x4823, { 0x9d, 0xb4, 0xd1, 0xe7, 0x69, 0x16, 0xda, 0xa0 } }; static const GUID SID_STimeContent = { 0x1ae98e18, 0xc527, 0x4f78, {0xb2, 0xa2, 0x6a, 0x81, 0x7f, 0x9c, 0xd4, 0xf8}};
// ISSUE where could be #include this GUID from?????
static const GUID CLSID_JITWMP8 = { 0x6BF52A52, 0x394A, 0x11d3, 0xb1, 0x53, 0x00, 0xc0, 0x4f, 0x79, 0xfa, 0xa6 };
CMediaBand::CMediaBand() : _fPlayButton(TRUE), _fPlayEnabled(TRUE), _iCurTrack(-1), _lTickCount(-1), _iElement(-1), _dblVol(-1.0), _fHiColour(TRUE), _fUserPaused(FALSE), _iOptionsWidth(0), _hbmpBackground(NULL), _hwndContent(NULL), _dwcpCookie(0), _fContentInFocus(FALSE), _hkeyWMP(NULL), _fShow(FALSE), _fAttached(FALSE) { _sizeLayout.cx = MIN_WINDOW_WIDTH; _sizeLayout.cy = MIN_WINDOW_HEIGHT; _sizeVideo.cx = 0 ; _sizeVideo.cy = 0 ; _fCanFocus = TRUE; _scaleX = _scaleY = 1.0;
// HighDPI support requires nice comctl32 6.0 functionality.
if (IsOS(OS_WHISTLERORGREATER)) { HDC hdcScreen = GetDC(NULL); if (hdcScreen) { _scaleX = (GetDeviceCaps(hdcScreen, LOGPIXELSX) / 96.0f); _scaleY = (GetDeviceCaps(hdcScreen, LOGPIXELSY) / 96.0f); ReleaseDC(NULL, hdcScreen); } } _fHighDPI = (_scaleX!=1.0) || (_scaleY!=1.0); }
CMediaBand::~CMediaBand() { DestroyPlayer();
if (_spBrowser) { _ConnectToCP(FALSE); _spBrowser.Release(); _poipao.Release(); } DESTROY_OBJ_WITH_HANDLE(_hwndContent, DestroyWindow);
DESTROY_OBJ_WITH_HANDLE(_hwndPopup, DestroyWindow); DESTROY_OBJ_WITH_HANDLE(_hwndLayout, DestroyWindow); DESTROY_OBJ_WITH_HANDLE(_hPlayListMenu, DestroyMenu); DESTROY_OBJ_WITH_HANDLE(_himlSeekBack, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlSeekFill, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlGripper, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlVolumeBack, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlVolumeFill, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_hbmpBackground, DeleteObject);
// need to check IsWindow because this window can also be destroyed by CMediaBarPlayer
if (_hwndVideo && ::IsWindow(_hwndVideo)) DestroyWindow(_hwndVideo);
if (_szToolTipUrl) { delete [] _szToolTipUrl; }
if (_pszStatus) { delete [] _pszStatus; }
for (int i=0; i < ARRAYSIZE(_pmw); i++) { if (_pmw[i]) { delete _pmw[i]; } }
if (_hkeyWMP) RegCloseKey(_hkeyWMP); }
// helper to get up to service provider and to do register/unregister
// two forms:
// pService != NULL, register, pdwCookie is [out] returns cookie
// pService == NULL, unregister, *pdwCookie is [in] de-registers the service
STDMETHODIMP CMediaBand::ProfferService(IUnknown *punkSite, REFGUID sidWhat, IServiceProvider *pService, DWORD *pdwCookie) { IProfferService *pps; HRESULT hr = IUnknown_QueryService(punkSite, SID_SProfferService, IID_PPV_ARG(IProfferService, &pps)); if (SUCCEEDED(hr)) { if (pService) hr = pps->ProfferService(sidWhat, pService, pdwCookie); else { hr = pps->RevokeService(*pdwCookie); *pdwCookie = 0; } pps->Release(); } return hr; }
HRESULT CMediaBand::SetSite(IUnknown *punkSite) { // Make sure we proffer the service only once
// This is important since we get created multiple times,
CComPtr<IUnknown> spUnk;
// Check if we need to revoke our service, or if our service was already proffered by
// another instance of CMediaBar
if ((!punkSite && _dwCookieServiceMediaBar) || (punkSite && FAILED(IUnknown_QueryService(punkSite, SID_SMediaBar, IID_PPV_ARG(IUnknown, &spUnk))))) { // Proffer or Revoke BrandBand service as appropriate
ProfferService(punkSite ? punkSite : _punkSite, SID_SMediaBar, punkSite ? SAFECAST(this, IServiceProvider *) : NULL, &_dwCookieServiceMediaBar); // Failure here does not require special handling
}
return SUPERCLASS::SetSite(punkSite); }
HRESULT CMediaBand::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CMediaBand, IMediaBar), QITABENT(CMediaBand, IWinEventHandler), QITABENT(CMediaBand, IObjectWithSite), QITABENT(CMediaBand, INamespaceWalkCB), QITABENTMULTI(CMediaBand, IDispatch, DWebBrowserEvents2), QITABENTMULTI2(CMediaBand, DIID_DWebBrowserEvents2, DWebBrowserEvents2), QITABENT(CMediaBand, IElementBehaviorFactory), QITABENT(CMediaBand, IBrowserBand), QITABENT(CMediaBand, IBandNavigate), QITABENT(CMediaBand, IMediaHost), { 0 }, }; HRESULT hr = QISearch(this, qit, riid, ppv); if (FAILED(hr)) { hr = SUPERCLASS::QueryInterface(riid, ppv); } return hr; }
// *** IWinEventHandler ***
HRESULT CMediaBand::IsWindowOwner(HWND hwnd) { for (int i=0; i < ARRAYSIZE(_pmw); i++) { if (_pmw[i] && (hwnd==_pmw[i]->_hwnd)) { return S_OK; } }
return S_FALSE; }
// *** IWinEventHandler ***
HRESULT CMediaBand::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres) { CMediaBand* pmb = reinterpret_cast<CMediaBand *>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); switch (uMsg) { case WM_COMMAND: { HWND hwndControl = GET_WM_COMMAND_HWND(wParam, lParam); UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam); if (HIWORD(wParam) == BN_CLICKED && hwndControl) { RECT rc; VARIANTARG var;
var.vt = VT_I4; GetWindowRect(hwndControl, &rc); MapWindowPoints(hwndControl, HWND_DESKTOP, (LPPOINT)&rc, 2); var.lVal = MAKELONG(rc.left, rc.bottom); return Exec(&CLSID_MediaBand, idCmd, 0, &var, NULL); } } break; } return S_FALSE; }
void CMediaBand::_ClearFolderItems() { if (_ppidls) { FreeIDListArray(_ppidls, _cidls); _ppidls = NULL; } _cidls = 0; }
// INamespaceWalkCB methods
HRESULT CMediaBand::FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl) { if (NULL == _hkeyWMP) { RegOpenKey(HKEY_CLASSES_ROOT, TEXT("Applications\\mplayer2.exe\\SupportedTypes"), &_hkeyWMP); }
HRESULT hr = S_FALSE; // default to no
if (_hkeyWMP) { TCHAR szName[MAX_PATH]; if (SUCCEEDED(DisplayNameOf(psf, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, szName, ARRAYSIZE(szName)))) { if (ERROR_SUCCESS == RegQueryValueEx(_hkeyWMP, PathFindExtension(szName), NULL, NULL, NULL, NULL)) { hr = S_OK; } } } return hr; }
STDMETHODIMP CMediaBand::InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel) { TCHAR szText[200]; MLLoadString(IDS_MEDIABANDSEARCH, szText, ARRAYSIZE(szText));
SHStrDup(szText, ppszTitle); *ppszCancel = NULL; return S_OK; }
HRESULT CMediaBand::_GetMusicFromFolder() { _ClearFolderItems();
INamespaceWalk *pnsw; HRESULT hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC, IID_PPV_ARG(INamespaceWalk, &pnsw)); if (SUCCEEDED(hr)) { hr = pnsw->Walk(_punkSite, NSWF_ONE_IMPLIES_ALL | NSWF_NONE_IMPLIES_ALL | NSWF_SHOW_PROGRESS, 10, this); if (SUCCEEDED(hr)) { hr = pnsw->GetIDArrayResult(&_cidls, &_ppidls); } pnsw->Release(); } return hr; }
// *** IOleCommandTarget methods ***
HRESULT CMediaBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { HRESULT hr = S_OK; if (pguidCmdGroup) { if (IsEqualGUID(CLSID_MediaBand, *pguidCmdGroup)) { switch (nCmdID) { case FCIDM_MEDIABAND_POPOUT: { DockMediaPlayer(); } break; case FCIDM_MEDIABAND_PLAY: if (!_pMediaPlayer || _pMediaPlayer->isStopped()) { _CleanupStopTimer(); hr = _GetMusicFromFolder(); if (S_OK == hr) { _strLastUrl.Empty(); // would be nicer to replay same local file if navigated away....
PlayLocalTrack(0); } else if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr) { // if we already played a media in this session, replay it
if (_strLastUrl.Length() > 0) { if (_fLastUrlIsAutoPlay) { // repeat playing last auto-play
CComVariant vtURL = _strLastUrl; CComVariant vtMime = _strLastMime; Exec(&CGID_MediaBar, MBID_PLAY, 0, &vtMime, &vtURL); } else { // replay media thru content pane and media bar behavior
NavigateContentPane(_strLastUrl); } } else { NavigateMoreMedia(); } } } else { _TogglePause(); TogglePlayPause(); } break; case FCIDM_MEDIABAND_PREVIOUS: if (EnsurePlayer()) { LONG_PTR lCurTrack = _pMediaPlayer->GetPlayListItemIndex(); LONG_PTR lItemCount = _pMediaPlayer->GetPlayListItemCount();
if (lCurTrack > 0) { _pMediaPlayer->Prev(); } else if (_iCurTrack >= 0) { int i = _iCurTrack; _iCurTrack = -1; // don't auto-step to next on finished event
_pMediaPlayer->Stop(); // generates MEDIA_TRACK_FINISHED
PlayLocalTrack((i - 1 >= 0) ? i - 1 : 0); } UpdateBackForwardControls(); TogglePlayPause(); } break; case FCIDM_MEDIABAND_NEXT: if (EnsurePlayer()) { LONG_PTR lCurTrack = _pMediaPlayer->GetPlayListItemIndex(); LONG_PTR lItemCount = _pMediaPlayer->GetPlayListItemCount();
if ((lCurTrack >= 0) && (lCurTrack < lItemCount - 1)) { _pMediaPlayer->Next(); } else if (_iCurTrack >= 0) { int i = _iCurTrack; _iCurTrack = -1; // don't auto-step to next on finished event
_pMediaPlayer->Stop(); // generates MEDIA_TRACK_FINISHED
PlayLocalTrack(i + 1); } UpdateBackForwardControls(); TogglePlayPause(); } break; case FCIDM_MEDIABAND_STOP: // when player is attached thru mediaBar behavior to script in media content pane,
// we want to give the user a chance to get rid of the script and return to the default media content
// the first click simply stops the player, clicking again within N secs will also navigate
// the content pane to the default URL
if (_idStopTimer == 0) { if (_IsProxyRunning()) { _idStopTimer = SetTimer(_hwnd, 747, 10000, NULL); } ResetPlayer(); _OnUserOverrideDisableUI(); } else { // clicked again, navigate media content to default URL
_CleanupStopTimer(); _NavigateContentToDefaultURL(); } break; case FCIDM_MEDIABAND_MUTE: ToggleMute(); break; } } else if (IsEqualGUID(CGID_MediaBar, *pguidCmdGroup)) { switch (nCmdID) { case MBID_PLAY: if (pvarargIn && pvarargOut) { _CleanupStopTimer(); if (_IsProxyRunning()) { // user clicked on a media link in the main content pane, unfreeze controls!
_OnUserOverrideDisableUI(); _DetachProxies(); _NavigateContentToDefaultURL(); }
if (V_VT(pvarargOut) == VT_BSTR) { _strLastUrl = V_BSTR(pvarargOut); } if (V_VT(pvarargIn) == VT_BSTR) { _strLastMime = V_BSTR(pvarargIn); } _fLastUrlIsAutoPlay = TRUE;
// ISSUE: fix this to use the right CmdId & CmdIdGroup, not just zero, to prevent collisions.
// this is an auto-play command
_HandleAutoPlay(pvarargIn, pvarargOut); hr = S_OK; } break;
case MBID_POPOUT: if (pvarargOut) { V_VT(pvarargOut) = VT_BOOL; V_BOOL(pvarargOut) = _hwndPopup && IsWindowVisible(_hwndPopup); hr = S_OK; } break;
default: ASSERT(FALSE); break; } } else { hr = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } } else { hr = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } return hr; }
void CMediaBand::_HandleAutoPlay(VARIANTARG *pvarargMime, VARIANTARG *pvarargUrl) { // check the mime type argument
if ( (!pvarargMime) || (VT_BSTR != V_VT(pvarargMime)) || (!V_BSTR(pvarargMime)) || (L'' == (*V_BSTR(pvarargMime)))) { goto done; }
// check the Url argument
if ( (!pvarargUrl) || ( VT_BSTR != V_VT(pvarargUrl)) || (!V_BSTR(pvarargUrl)) || (L'' == (*V_BSTR(pvarargUrl)))) { goto done; }
if (EnsurePlayer()) { // reset this to -1 to indicate we are not playing a mymusic track
_iCurTrack = -1;
#ifdef _USE_MEDIA_MRU
// ISSUE: temp fix for radio protocol. If this is an ASX mimetype, we know it is radio
if (!SHRestricted(REST_NORECENTDOCSHISTORY)) { CMediaMRU mmru; mmru.Load(REG_VALUE_MRU_INTERNET); mmru.Add(V_BSTR(pvarargUrl)); } #endif // _USE_MEDIA_MRU
if (0 == StrCmpNIW(V_BSTR(pvarargMime), WZ_ASX_MIMETYPE, wcslen(WZ_ASX_MIMETYPE))) { _PutUrl(V_BSTR(pvarargUrl), V_BSTR(pvarargMime)); } else { _PutUrl(V_BSTR(pvarargUrl), NULL); }
TogglePlayPause(); // clear the url to indicate we are handling this url
::VariantClear(pvarargUrl); } else { ASSERT(FALSE); } done: ; }
VOID CMediaBand::_BeginTimeOutCounter(BOOL fClear /* = TRUE */) { _dwStartTime = GetPerfTime(); _lTickCount = 0; if (TRUE == fClear) { _dblLastBufProgress = 0; _dblLastPlayProgress = 0; } }
VOID CMediaBand::_EndTimeOutCounter() { _lTickCount = -1; }
VOID CMediaBand::_UpdateTimeOutCounter(double dblCurrBufProgress, double dblCurrPlayProgress) { BOOL fTimeOut = FALSE;
// bail if the counter has not been started
if (_lTickCount < 0) return;
// Order of checking is important here.
// If play progress is increasing then restart the counter
if (dblCurrPlayProgress > _dblLastPlayProgress) { _BeginTimeOutCounter(FALSE); _dblLastPlayProgress = dblCurrPlayProgress; } // if buffering progress is increasing then restart the counter
else if (dblCurrBufProgress > _dblLastBufProgress) { _BeginTimeOutCounter(FALSE); _dblLastBufProgress = dblCurrBufProgress; } else { // both play and buffering progress are stalled, so update the timeout counter
// We poll the system time every POLL_INTERVAL ticks since we tick at a very high rate
// (a tick is each time this function is called)
if ((1 + _lTickCount) == POLL_INTERVAL) { DWORD dwCurrentTime = GetPerfTime();
DWORD dwElapsedTime = (dwCurrentTime - _dwStartTime) + (dwCurrentTime < _dwStartTime ? 0xffffffff : 0); // if timer wraps around 2^32 milliseconds
if (dwElapsedTime >= TIMEOUT_INTERVAL) { fTimeOut = TRUE; } }
if (fTimeOut) { _OnNavigationTimeOut(); } else { // update the poll interval counter and mod it by POLL_INTERVAL
_lTickCount = (1 + _lTickCount) - (static_cast<long>(_lTickCount / POLL_INTERVAL) * POLL_INTERVAL); } } }
VOID CMediaBand::_OnNavigationTimeOut() { _EndTimeOutCounter();
// stop the player and show the timeout message
if (EnsurePlayer()) { if (VARIANT_FALSE == _pMediaPlayer->isStopped()) { _pMediaPlayer->Stop(); TogglePlayPause();
// Show timeout error message
TCHAR szText[200]; szText[0] = TEXT('\0'); MLLoadString(IDS_MEDIABAND_NAVTIMEOUT, szText, ARRAYSIZE(szText)); SetStatusText(szText); } } }
STDMETHODIMP CMediaBand::_PutUrl(LPWSTR pstrUrl, LPWSTR pstrMime) { HRESULT hr = E_FAIL;
if (EnsurePlayer()) { TCHAR szText[200]; szText[0] = TEXT('\0');
SetStatusText(_szConnecting); hr = _pMediaPlayer->put_type(pstrMime); if (SUCCEEDED(hr)) { hr = _pMediaPlayer->put_url(pstrUrl); if (SUCCEEDED(hr)) { // start the timeout counter
if (_dblVol!=-1) { _pMediaPlayer->put_volume(_dblVol); } _pMediaPlayer->put_mute(_fMuted); _BeginTimeOutCounter(); UpdateBackForwardControls(); SetPlayPause(FALSE); SetPlayerControl(FCIDM_MEDIABAND_STOP, TRUE);
// make sure we undavise from soon-to-be obsolete player object
_AttachPlayerToProxies(FALSE); } } } return hr; }
// *** IInputObject methods ***
HRESULT CMediaBand::TranslateAcceleratorIO(LPMSG pMsg) { ASSERT(pMsg); TraceMsg(TF_ACCESSIBILITY, "CMediaBand::TranslateAcceleratorIO (hwnd=0x%08X) key=%d", _hwnd, pMsg->wParam);
BOOL fHasFocus = ( (_iElement>=0) || (HasFocusIO() == S_OK) || _fContentInFocus);
if (fHasFocus && IsVK_CtlTABCycler(pMsg)) { // Bail on ctl-tab/F6 if one of our guys already has focus
return S_FALSE; }
// if any child in focus, let them have a shot at it
HRESULT hr = S_FALSE; if (fHasFocus) { if (_iElement >=0) { if (_hwndPopup && IsWindowVisible(_hwndPopup) && (pMsg->message==WM_KEYDOWN) && (pMsg->wParam==VK_ESCAPE)) { DockMediaPlayer(); hr = S_OK; } else { hr = _pmw[_iElement]->TranslateAccelerator(pMsg); } } else if (_fContentInFocus && _poipao) { hr = _poipao->TranslateAccelerator(pMsg); } if (hr == S_OK) { return S_OK; // handled!!
} }
hr = S_FALSE; // try shifting focus to next element
if (IsVK_TABCycler(pMsg)) { BOOL fReverse = (GetKeyState(VK_SHIFT) < 0); if (fReverse) { // content pane is last tab target, move to last control widget with this backward tab
if (_fContentInFocus) { _ContentActivateIO(FALSE, NULL); if (!(_hwndPopup && IsWindowVisible(_hwndPopup))) { _iElement = ARRAYSIZE(_pmw)-1; } else { return S_FALSE; } } else do { _iElement--; if (_iElement<0) { if (_fPopoutHasFocus) { _iElement = ARRAYSIZE(_pmw)-1; } break; } } while (!ISVALIDWIDGET(_pmw[_iElement]) || (!_pmw[_iElement]->IsEnabled())); } else { // content pane is last tab target, move away from mediabar with this forward tab
if (_fContentInFocus) { _ContentActivateIO(FALSE, NULL); return S_FALSE; } // try next control widget
if (!(_hwndPopup && IsWindowVisible(_hwndPopup)) || _fPopoutHasFocus) { if (_iElement<0) { _iElement = 0; } else do { _iElement++; if (_iElement>=ARRAYSIZE(_pmw)) { _iElement = _fPopoutHasFocus ? 0 : -1; break; } } while (!ISVALIDWIDGET(_pmw[_iElement]) || (!_pmw[_iElement]->IsEnabled())); } // none of the control widgets claimed focus, try content pane
if (_iElement<0) { hr = _ContentActivateIO(TRUE, pMsg); if (hr == S_OK) { return S_OK; // handled!!
} } } if (_iElement<0) { return S_FALSE; }
ASSERT(ISVALIDWIDGET(_pmw[_iElement])); ::SetFocus(_pmw[_iElement]->_hwnd); return S_OK; } return S_FALSE; // unhandled non-tab
}
//------------------------------------------------------------------------
HRESULT CMediaBand::UIActivateIO(BOOL fActivate, LPMSG pMsg) { TraceMsg(TF_ACCESSIBILITY, "CMediaBand::UIActivateIO (hwnd=0x%08X) fActivate=%d", _hwnd, fActivate); HRESULT hr = S_OK;
// activation:
if (fActivate) { if (!(_hwndPopup && IsWindowVisible(_hwndPopup)) || _fPopoutHasFocus) { if (_iElement==-1) { _ContentActivateIO(FALSE, NULL); _iElement = 0; } if (_pmw[_iElement] && _pmw[_iElement]->_hwnd) { ::SetFocus(_pmw[_iElement]->_hwnd); } } else { _iElement = -1; _ContentActivateIO(TRUE, pMsg); } IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), TRUE); } else { _ContentActivateIO(FALSE, NULL); _iElement = -1; if (_hwndPopup && IsWindowVisible(_hwndPopup)) { IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), FALSE); } } return hr; }
//------------------------------------------------------------------------
HRESULT CMediaBand::HasFocusIO() { HRESULT hr = SHIsChildOrSelf((_hwndPopup && IsWindowVisible(_hwndPopup)) ? _hwndPopup : _hwnd, ::GetFocus()); if (hr==S_FALSE) { // Focus might be in the content pane, which won't be a child if the popout is out
hr = SHIsChildOrSelf(_hwndContent, ::GetFocus()); } return hr; }
HRESULT CMediaBand::_ContentActivateIO(BOOL fActivate, PMSG pMsg) { ASSERT(_hwndContent); ASSERT(_poipao);
if (_fContentInFocus == fActivate) { return S_OK; }
_fContentInFocus = fActivate; if (fActivate) { _iElement = -1; } int iVerb = fActivate ? OLEIVERB_UIACTIVATE : OLEIVERB_INPLACEACTIVATE;
HRESULT hr = S_OK; hr = OCHost_DoVerb(_hwndContent, iVerb, pMsg);
// OCHost UIActivate is different than IInputObject::UIActivateIO. It
// doesn't do anything with the lpMsg parameter. So, we need to pass
// it to them via TranslateAccelerator. Since the only case we care
// about is when they're getting tabbed into (we want them to highlight
// the first/last link), just do this in the case of a tab. However,
// don't give it to them if it's a ctl-tab. The rule is that you shouldn't
// handle ctl-tab when UI-active (ctl-tab switches between contexts), and
// since Trident is always UI-active (for perf?), they'll always reject
// ctl-tab.
// suppress sending any tabs
if (pMsg && _poipao && IsVK_TABCycler(pMsg) && !IsVK_CtlTABCycler(pMsg)) { hr = _poipao->TranslateAccelerator(pMsg); // ignore if translate of tab fails when activating!
if (FAILED(hr) && fActivate) { hr = S_OK; } }
return hr; }
LRESULT CMediaBand::_OnNotify(LPNMHDR pnm) { switch (pnm->code) { case OCN_ONUIACTIVATE: // UIActivate
ASSERT(SHIsSameObject(((LPOCNONUIACTIVATEMSG)pnm)->punk, _poipao));
_fContentInFocus = TRUE; _iElement = -1; IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), TRUE); return OCNONUIACTIVATE_HANDLED;
case OCN_ONSETSTATUSTEXT: { HRESULT hr = E_FAIL; IShellBrowser *psb;
hr = QueryService(SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &psb)); if (SUCCEEDED(hr)) { hr = psb->SetStatusTextSB(((LPOCNONSETSTATUSTEXTMSG)pnm)->pwszStatusText); psb->Release(); } } break;
default: break; }
ASSERT(OCNONUIACTIVATE_HANDLED != 0); return 0; }
// *** IDeskBand methods ***
HRESULT CMediaBand::GetBandInfo(DWORD dwBandID, DWORD fViewMode, DESKBANDINFO* pdbi) { _dwBandID = dwBandID;
pdbi->dwModeFlags = DBIMF_FIXEDBMP | DBIMF_VARIABLEHEIGHT; if (pdbi->dwMask & DBIM_MINSIZE) { pdbi->ptMinSize.x = 16; pdbi->ptMinSize.y = 16; } if (pdbi->dwMask & DBIM_MAXSIZE) { pdbi->ptMaxSize.x = 32000; // random
pdbi->ptMaxSize.y = 32000; // random
}
if (pdbi->dwMask & DBIM_ACTUAL) { pdbi->ptActual.x = -1; pdbi->ptActual.y = -1; }
if (pdbi->dwMask & DBIM_INTEGRAL) { pdbi->ptIntegral.y = 1; }
MLLoadStringW(IDS_MEDIABANDTEXT, pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle));
return S_OK; }
/*** CMediaBand::IPersistStream::**/ HRESULT CMediaBand::GetClassID(CLSID *pClassID) { *pClassID = CLSID_MediaBand; return S_OK; }
// *** IPersistStream methods ***
HRESULT CMediaBand::Load(IStream *pstm) { return S_OK; }
// *** IPersistStream methods ***
HRESULT CMediaBand::Save(IStream *pstm, BOOL fClearDirty) { return S_OK; }
// *** IOleWindow methods ***
HRESULT CMediaBand::GetWindow(HWND *phwnd) { if (!_hwnd) { CreateParentPane(); }
if (!_hwndLayout) { CreateLayoutPane(); } if (!_hwndContent) { InitContentPane(); }
if (phwnd) { *phwnd = _hwnd ; return S_OK; } return SUPERCLASS::GetWindow(phwnd); }
// *** IDockingWindow methods ***
HRESULT CMediaBand::ShowDW(BOOL fShow) { if (!_hwnd) return S_FALSE; // The window needs to be created first.
_fVideoAdjust = FALSE; if (fShow) { _InitializeMediaUI();
// FEATURE/010228/davidjen uncomment this to suppress MediaBar's title bar
#ifdef _SUPPRESS_MB_TITLEBAR
// hide caption/titlebar
CComQIPtr<IBandSite, &IID_IBandSite> pbs = _punkSite; if (pbs) { BANDSITEINFO bsi; bsi.dwMask = BSIM_STYLE; HRESULT hr = pbs->GetBandSiteInfo(&bsi); if (SUCCEEDED(hr)) { // suppress caption
bsi.dwStyle |= BSIS_NOCAPTION; hr = pbs->SetBandSiteInfo(&bsi); } } #endif // _SUPPRESS_MB_TITLEBAR
if (!(_hwndPopup && IsWindowVisible(_hwndPopup))) { RECT rcParent, rc; GetClientRect(_hwnd, &rcParent); GetClientRect(_hwndLayout, &rc);
if (RECTWIDTH(rcParent) > 0 || RECTHEIGHT(rcParent) > 0) { _ResizeChildWindows(_hwndLayout, RECTWIDTH(rc), RECTHEIGHT(rc), TRUE); SetWindowPos(_hwnd, NULL, 0, 0,RECTWIDTH(rcParent), RECTHEIGHT(rcParent), SWP_SHOWWINDOW | SWP_NOACTIVATE); RedrawWindow(_hwnd, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN); } } } else { _ShowAllWindows(fShow); } if (fShow != _fShow) { _fShow = fShow; _FireEventToProxies(_fShow ? OnShow : OnHide); } return CToolBand::ShowDW(fShow); }
HRESULT CMediaBand::CloseDW(DWORD dwReserved) { if (!_hwnd) return S_FALSE; // The window needs to be created first.
WTSUnRegisterSessionNotification(_hwnd);
DestroyPlayer();
if (_spBrowser) { _ConnectToCP(FALSE); _spBrowser.Release(); _poipao.Release(); }
if (_hwndLayout && IsWindow(_hwndLayout)) { DestroyWindow(_hwndLayout); _hwndLayout = NULL; } if (_hwndPopup && IsWindow(_hwndPopup)) { DestroyWindow(_hwndPopup); _hwndPopup = NULL; }
SUPERCLASS::CloseDW(dwReserved);
return S_OK; }
//-------------- Interface IElementBehaviorFactory
//------------------------------------------------------------------------
STDMETHODIMP CMediaBand::FindBehavior(BSTR bstrBehavior, BSTR bstrBehaviorUrl, IElementBehaviorSite* pSite, IElementBehavior** ppBehavior) { if (ppBehavior == NULL) { return E_POINTER; } *ppBehavior = NULL;
// check namespace and URL
if (StrCmpIW(bstrBehavior, TEXT("mediaBar")) != 0) { return E_NOTIMPL; // don't know this behavior!!
}
HRESULT hr = S_OK; // create new behavior instance for this HTML pane
IContentProxy * pProxy = NULL; pProxy = CMediaBehavior_CreateInstance(this); if (pProxy) { hr = pProxy->QueryInterface(IID_IElementBehavior, (void**)ppBehavior); if (FAILED(hr)) { // make sure we get rid our reference
removeProxy(pProxy); } } else { hr = E_OUTOFMEMORY; } return hr; }
// IMediaHost
//------------------------------------------------------------------------
STDMETHODIMP CMediaBand::getMediaPlayer(IUnknown **ppPlayer) { if (ppPlayer == NULL) return E_POINTER; *ppPlayer = NULL;
if (_pMediaPlayer) { ITIMEMediaElement *pElem = NULL; if (SUCCEEDED(_pMediaPlayer->get_mediaElement(&pElem))) { *ppPlayer = pElem; // no AddRef, get_mediaElement already did ref counting!!
} } return *ppPlayer ? S_OK : S_FALSE; }
//------------------------------------------------------------------------
STDMETHODIMP CMediaBand::playURL(BSTR bstrURL, BSTR bstrMIME) { HRESULT hr = _EnsureWMPInstalled(); if (FAILED(hr)) { return hr; } CComVariant varMime = bstrMIME; CComVariant varUrl = bstrURL;
_strLastUrl = _strCurrentContentUrl; _strLastMime.Empty(); _fLastUrlIsAutoPlay = FALSE;
_HandleAutoPlay(&varMime, &varUrl); return S_OK; }
//------------------------------------------------------------------------
STDMETHODIMP CMediaBand::addProxy(IUnknown *punkProxy) { HRESULT hr = E_POINTER; if (punkProxy) { // add to our array of proxies
if (_apContentProxies == NULL) { _apContentProxies.Create(2); } if (_apContentProxies == NULL) { return E_OUTOFMEMORY; }
// want to be sure proxy knows our protocol, also does add ref
IContentProxy *pProxy = NULL; hr = punkProxy->QueryInterface(IID_PPV_ARG(IContentProxy, &pProxy)); if (SUCCEEDED(hr)) { _apContentProxies.AppendPtr(pProxy); }
} return hr; }
//------------------------------------------------------------------------
STDMETHODIMP CMediaBand::removeProxy(IUnknown *punkProxy) { if (_apContentProxies == NULL) return S_FALSE;
HRESULT hr = S_FALSE; int cnt = _apContentProxies.GetPtrCount(); for (int i = 0; i < cnt; i++) { IContentProxy* pProxy = _apContentProxies.GetPtr(i); ASSERT(pProxy); if (pProxy) { if (SHIsSameObject(pProxy, punkProxy)) { _apContentProxies.DeletePtr(i); pProxy->Release(); ResetPlayer(); // privacy issue:
// make sure player is stopped and proxy/behavior in next page cannot access current media
_fAttached = FALSE; // force reattaching to player once a new behavior is up
hr = S_OK; break; } } } return hr; }
// IMediaHost2
//------------------------------------------------------------------------
STDMETHODIMP CMediaBand::OnDisableUIChanged(BOOL fDisabled) { return S_OK; }
//------------------------------------------------------------------------
void CMediaBand::_AttachPlayerToProxies(BOOL fAttach) { if (_apContentProxies == NULL) return; if (_fAttached == fAttach) return;
int cnt = _apContentProxies.GetPtrCount(); for (int i = 0; i < cnt; i++) { IContentProxy* pProxy = _apContentProxies.GetPtr(i); ASSERT(pProxy); if (pProxy) { HRESULT hr; if (fAttach) { hr = pProxy->OnCreatedPlayer(); } else { pProxy->detachPlayer(); hr = S_OK; } if (SUCCEEDED(hr)) { _fAttached = fAttach; } } } }
//------------------------------------------------------------------------
void CMediaBand::_DetachProxies() { if (_apContentProxies == NULL) return;
int cnt = _apContentProxies.GetPtrCount(); // need to iterate from last to first, call to removeProxy() will also remove it from DPA!
for (int i = cnt - 1; i >= 0; i--) { IContentProxy* pProxy = _apContentProxies.GetPtr(i); ASSERT(pProxy); if (pProxy) { removeProxy(pProxy); } } _apContentProxies.Destroy(); return; }
//------------------------------------------------------------------------
BOOL CMediaBand::_isUIDisabled() { if (_apContentProxies == NULL) return FALSE;
int cnt = _apContentProxies.GetPtrCount(); BOOL fDisabled = FALSE; for (int i = 0; i < cnt; i++) { CComQIPtr<IMediaBehaviorContentProxy, &IID_IMediaBehaviorContentProxy> pProxy = _apContentProxies.GetPtr(i); if (pProxy) { BOOL fQueryDisabled = FALSE; pProxy->IsDisableUIRequested(&fQueryDisabled); if (fQueryDisabled) { fDisabled = TRUE; break; } } } return fDisabled; }
//------------------------------------------------------------------------
BOOL CMediaBand::_isProxiesNextEnabled() { if (_apContentProxies == NULL) return TRUE;
int cnt = _apContentProxies.GetPtrCount(); BOOL fEnabled = TRUE; for (int i = 0; i < cnt; i++) { CComQIPtr<IMediaBehaviorContentProxy, &IID_IMediaBehaviorContentProxy> pProxy = _apContentProxies.GetPtr(i); if (pProxy) { BOOL fQueryEnabled = FALSE; pProxy->IsNextEnabled(&fQueryEnabled); if (!fQueryEnabled) { fEnabled = FALSE; break; } } } return fEnabled; }
//------------------------------------------------------------------------
void CMediaBand::_OnUserOverrideDisableUI() { if (_apContentProxies == NULL) return;
int cnt = _apContentProxies.GetPtrCount(); BOOL fDisabled = FALSE; for (int i = 0; i < cnt; i++) { CComQIPtr<IMediaBehaviorContentProxy, &IID_IMediaBehaviorContentProxy> pProxy = _apContentProxies.GetPtr(i); if (pProxy) { pProxy->OnUserOverrideDisableUI(); } } }
//------------------------------------------------------------------------
void CMediaBand::_FireEventToProxies(enum contentProxyEvent event) { if (_apContentProxies == NULL) return;
int cnt = _apContentProxies.GetPtrCount(); BOOL fDisabled = FALSE; for (int i = 0; i < cnt; i++) { IContentProxy* pProxy = _apContentProxies.GetPtr(i); ASSERT(pProxy); if (pProxy) { pProxy->fireEvent(event); } } }
//------------------------------------------------------------------------
void CMediaBand::_CleanupStopTimer() { if (_idStopTimer != 0) { KillTimer(_hwnd, _idStopTimer); _idStopTimer = 0; // make sure user hasn't initiated another media action yet!!!
SetPlayerControl(FCIDM_MEDIABAND_STOP, FALSE); } }
//------------------------------------------------------------------------
HRESULT CMediaBand::_EnsureWMPInstalled(BOOL fShowErrorMsg) { HRESULT hr = S_OK; if (!CMediaBarUtil::IsWMP7OrGreaterInstalled()) { // ISSUE: assumption that XP already has matching WMP version
if (!IsOS(OS_WHISTLERORGREATER)) { // try to web-jit WMP8.
uCLSSPEC ucs; QUERYCONTEXT qc = { 0 };
ucs.tyspec = TYSPEC_CLSID; ucs.tagged_union.clsid = CLSID_JITWMP8;
hr = FaultInIEFeature(_hwnd, &ucs, &qc, FIEF_FLAG_FORCE_JITUI); } if (!CMediaBarUtil::IsWMP7OrGreaterInstalled()) { // still no WMP, user might have aborted or install failed
if (fShowErrorMsg) { MLShellMessageBox(_hwnd, MAKEINTRESOURCE(IDS_MEDIABAND_NOWMP7), MAKEINTRESOURCE(IDS_MEDIABAND_NOWMP7TITLE), MB_OK); } hr = E_UNEXPECTED; } } return hr; }
// *** IBrowserBand methods ***
STDMETHODIMP CMediaBand::GetObjectBB(REFIID riid, LPVOID *ppv) { return _spBrowser ? _spBrowser->QueryInterface(riid, ppv) : E_UNEXPECTED; }
// *** IBandNavigate methods ***
STDMETHODIMP CMediaBand::Select(LPCITEMIDLIST pidl) { _strDeferredURL.Empty(); // cancel any deferred navigation (usually during initial launch of mediabar
return NavigateContentPane(pidl); }
HRESULT CMediaBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { // aggregation checking is handled in class factory
CMediaBand * pmb = new CMediaBand();
if (!pmb) return E_OUTOFMEMORY;
// if you change this cast, fix up CChannelBand_CreateInstance
*ppunk = SAFECAST(pmb, IDeskBand *);
return S_OK; }
//+-------------------------------------------------------------------------
// Creates Player
//--------------------------------------------------------------------------
BOOL CMediaBand::EnsurePlayer() { BOOL fResult = _pMediaPlayer ? TRUE : FALSE; if (!fResult) { fResult = CreatePlayer(); } return fResult && _pMediaPlayer; }
BOOL CMediaBand::CreatePlayer() { HRESULT hr = CMediaBarPlayer_CreateInstance(IID_PPV_ARG(IMediaBarPlayer, &_pMediaPlayer)); if (SUCCEEDED(hr)) { hr = _pMediaPlayer->Init(_hwndLayout, SAFECAST(this, IMediaBar*)); if (SUCCEEDED(hr)) { hr = _pMediaPlayer->GetVideoHwnd(&_hwndVideo); } if (FAILED(hr)) { ASSERT(FALSE); DestroyPlayer(); } } return SUCCEEDED(hr); }
VOID CMediaBand::DestroyPlayer() { _AttachPlayerToProxies(FALSE); if (_pMediaPlayer) { _pMediaPlayer->DeInit(); _pMediaPlayer->Release(); _pMediaPlayer = NULL; } _DetachProxies(); }
// notifications from the player
STDMETHODIMP CMediaBand::Notify(long lReason) { HRESULT hr = E_FAIL; if (EnsurePlayer()) { // update play/pause state
TogglePlayPause(); if (!_fAttached) { _AttachPlayerToProxies(TRUE); }
switch (lReason) { case DISPID_TIMESTATE_PROGRESS: { double dblProgress = _pMediaPlayer->GetTrackProgress(); if (!_fSeeking) { SetSeekPos(static_cast<float>(dblProgress)); } // Update download/buffering progress, if any
{ ProgressType ProgType = PT_None; double dblBufProg = 0.0; hr = _pMediaPlayer->GetBufProgress(&dblBufProg, &ProgType); // S_OK only means that there's some buffering going on
if ((hr == S_OK) && dblBufProg >= 0.0 && dblBufProg < 100.0) { SetStatusText(_szConnecting); } else { ShowPlayingStatus(); } if (TRUE == _pMediaPlayer->IsStreaming()) { // if this is streamed then substitute progress with track time
// since progress is not meaningful
dblProgress = _pMediaPlayer->GetTrackTime(); _UpdateTimeOutCounter(dblBufProg, dblProgress); } else { _UpdateTimeOutCounter(dblBufProg, dblProgress); } } } break; // case DISPID_TIMESTATE_PROGRESS
case MEDIACOMPLETE: case TRACK_CHANGE: _fPlaying = TRUE; ShowPlayingStatus(TRUE); AdjustVideoHeight(TRUE); _EndTimeOutCounter(); SetPlayPause(_pMediaPlayer->IsPausePossible()); UpdateBackForwardControls(); if (ISVALIDWIDGET(_pmwSeek)) { _pmwSeek->SetState(_pMediaPlayer->IsSeekPossible()); } break; case MEDIA_TRACK_FINISHED: if (_iCurTrack != -1) { PlayNextTrack(); } else { _fSeeking = FALSE; ResetPlayer(); } break; case DISPID_TIMEMEDIAELEMENT_TITLE: _OnTitleChange(); ShowPlayingStatus(TRUE); break; } // switch (lReason)
hr = S_OK; } // end if
return hr; }
STDMETHODIMP CMediaBand::OnMediaError(int iErrCode) { _EndTimeOutCounter();
if (-1 == iErrCode) { // if there is no rich erro info display the generic error message
TCHAR szText[MAX_PATH]; szText[0] = TEXT('\0'); MLLoadString(IDS_MEDIABAND_INVALIDFILE, szText, ARRAYSIZE(szText)); SetStatusText(szText); } else { // ISSUE: to do: display the appropriate error message
ASSERT(FALSE); }
#ifdef PLAY_INDEFAULT
// delegate the playback to the default player (fix for 24146)
{ //
// ISSUE: What should we do for errors within a playlist??????
//
CComBSTR sbstrUrl; if (EnsurePlayer() && SUCCEEDED(_pMediaPlayer->get_url(&sbstrUrl)) && (NULL != sbstrUrl.m_str)) { _OpenInDefaultPlayer(sbstrUrl); } } #endif
return S_OK; }
//+-------------------------------------------------------------------------
// Handler for property change notification
//--------------------------------------------------------------------------
void CMediaBand::_OnTitleChange() { // The status text and playlist menu should be updated here
}
//+-------------------------------------------------------------------------
// Resize the video
//--------------------------------------------------------------------------
void CMediaBand::_ResizeVideo(LONG* plWidth, LONG* plHeight) { if (EnsurePlayer() && _hwndVideo && ::IsWindow(_hwndVideo)) { _pMediaPlayer->Resize(plHeight, plWidth, FALSE); } }
//+-------------------------------------------------------------------------
// Redraw/show/hide the video window only if something has changed
//--------------------------------------------------------------------------
VOID CMediaBand::AdjustVideoHeight(BOOL fForceResize) { VARIANT_BOOL vbHasVisual = VARIANT_FALSE; CComPtr<ITIMEMediaElement> spMediaElem; if (_pMediaPlayer && SUCCEEDED(_pMediaPlayer->get_mediaElement(&spMediaElem))) { // Show/hide the video display window
if (SUCCEEDED(spMediaElem->get_hasVisual(&vbHasVisual))) { BOOL fVideo = (VARIANT_TRUE == vbHasVisual ? TRUE : FALSE) && _fPlaying;
if (fVideo) { if (!IsWindowVisible(_hwndVideo) && !_fIsVideo) { ShowWindow(_hwndVideo, SW_SHOW); _fVideoAdjust = TRUE; _fIsVideo = TRUE; } } else { if (IsWindowVisible(_hwndVideo) && _fIsVideo) { _fVideoAdjust = TRUE; ShowWindow(_hwndVideo, SW_HIDE); _fIsVideo = FALSE; } }
if (!_fVideoAdjust && fForceResize) { _fVideoAdjust = TRUE; }
// redraw only if something has changed, so that this function can be called very often
// (e.g. from Notify) without causing excessive drawing.
if (_fVideoAdjust) { _fVideoAdjust = FALSE; if (_hwndPopup && IsWindowVisible(_hwndPopup)) { LONG lHeight = GetPopoutHeight(TRUE, _sizeVideo.cx); SetWindowPos(_hwndPopup, HWND_TOPMOST, 0, 0, _sizeLayout.cx, lHeight, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE);
InvalidateRect(_hwndPopup, NULL, TRUE); ShowWindow(_hwndPopup, SW_SHOW); UpdateWindow(_hwndPopup); } else { RECT rcParent; GetClientRect(_hwnd, &rcParent); LONG lHeight = RECTHEIGHT(rcParent);
lHeight = GetLayoutHeight(); AdjustLayout(RECTWIDTH(rcParent), lHeight); SendMessage(_hwnd, WM_SIZE, (WPARAM)0, (LPARAM) MAKELONG(RECTWIDTH(rcParent), lHeight)); } } } } }
VOID CMediaBand::AdjustLayout(LONG_PTR lWidth, LONG_PTR lHeight) { RECT rcClient;
if (!(_hwndPopup && IsWindowVisible(_hwndPopup))) { GetClientRect(_hwnd, &rcClient);
if (lWidth<=MIN_WINDOW_WIDTH) { if (RECTWIDTH(rcClient) < MIN_WINDOW_WIDTH) lWidth = MIN_WINDOW_WIDTH ; else lWidth = RECTWIDTH(rcClient); }
if (lHeight<=MIN_WINDOW_HEIGHT) { if (RECTHEIGHT(rcClient) < MIN_WINDOW_HEIGHT) lHeight = MIN_WINDOW_HEIGHT ; else lHeight = RECTHEIGHT(rcClient); } } _ResizeChildWindows(_hwndLayout, (LONG)lWidth, (LONG)lHeight, TRUE); }
// IServiceProvider implementation
HRESULT CMediaBand::QueryService(REFGUID guidService, REFIID riid, void ** ppvObj) { HRESULT hr = E_UNEXPECTED;
if (IsEqualIID(guidService, SID_SMediaBar)) { hr = QueryInterface(riid, ppvObj); } else if (IsEqualIID(guidService, SID_SMediaBarSync)) { hr = QueryInterface(riid, ppvObj); } else if (IsEqualGUID(guidService, SID_SElementBehaviorFactory)) { hr = QueryInterface(riid, ppvObj); } else if (IsEqualGUID(guidService, SID_STimeContent)) { hr = QueryInterface(riid, ppvObj); } else { hr = SUPERCLASS::QueryService(guidService, riid, ppvObj); } return hr; }
STDMETHODIMP CMediaBand::_TogglePause() { HRESULT hr = E_FAIL;
if (EnsurePlayer()) { if (VARIANT_TRUE == _pMediaPlayer->isPaused()) { _fUserPaused = FALSE; if (SUCCEEDED(_pMediaPlayer->Resume())) { _BeginTimeOutCounter(); hr = S_OK; } } else { _fUserPaused = TRUE; hr = _pMediaPlayer->Pause(); if (SUCCEEDED(hr)) { _EndTimeOutCounter(); hr = S_OK; } }
TogglePlayPause(); } return hr; }
//+-------------------------------------------------------------------------
// Creates and shows buttons
//--------------------------------------------------------------------------
HRESULT CMediaBand::CreateControls() { // _pmwPlay
_pmw[MW_PLAY] = CMediaWidgetButton_CreateInstance(_hwndLayout, 31, 33, FCIDM_MEDIABAND_PLAY, IDB_MEDIABAND_PLAY, IDB_MEDIABAND_PAUSE, IDS_MEDIABAND_PLAY, IDS_MEDIABAND_PAUSE); // _pmwStop
_pmw[MW_STOP] = CMediaWidgetButton_CreateInstance(_hwndLayout, 18, 33, FCIDM_MEDIABAND_STOP, IDB_MEDIABAND_STOP, 0, IDS_MEDIABAND_STOP); // _pmwBack
_pmw[MW_BACK] = CMediaWidgetButton_CreateInstance(_hwndLayout, 22, 16, FCIDM_MEDIABAND_PREVIOUS, IDB_MEDIABAND_BACK, 0, IDS_MEDIABAND_BACK); // _pmwNext
_pmw[MW_NEXT] = CMediaWidgetButton_CreateInstance(_hwndLayout, 22, 16, FCIDM_MEDIABAND_NEXT, IDB_MEDIABAND_NEXT, 0, IDS_MEDIABAND_NEXT);
_pmw[MW_MUTE] = new CMediaWidgetToggle(_hwndLayout, 22, 16); if (_pmwMute) { HRESULT hr = _pmwMute->Initialize(FCIDM_MEDIABAND_MUTE, IDS_MEDIABAND_UNMUTE, IDS_MEDIABAND_MUTE); if (SUCCEEDED(hr)) { hr = _pmwMute->SetImageList(IDB_MEDIABAND_MUTE); } if (SUCCEEDED(hr)) { hr = _pmwMute->SetAlternateImageList(IDB_MEDIABAND_MUTE); } _pmwMute->SetState(FALSE); if (FAILED(hr)) { delete _pmwMute; _pmw[MW_MUTE] = NULL; } }
_pmw[MW_OPTIONS] = new CMediaWidgetOptions(_hwndLayout, 16, 16); if (_pmwOptions) { HRESULT hr = _pmwOptions->Initialize(FCIDM_MEDIABAND_MUTE, IDS_MEDIABAND_UNMUTE, IDS_MEDIABAND_MUTE); if (FAILED(hr)) { delete _pmwOptions; _pmw[MW_OPTIONS] = NULL; } }
// _pmwPop
_pmw[MW_POP] = CMediaWidgetButton_CreateInstance(_hwndLayout, 19, 20, FCIDM_MEDIABAND_POPOUT, IDB_MEDIABAND_POPOUT, IDB_MEDIABAND_POPIN, IDS_MEDIABAND_UNDOCK, IDS_MEDIABAND_DOCK); return S_OK; }
HRESULT CMediaBand::CreateSeekBar() { DWORD dwWindowStyles = WS_TABSTOP | WS_VISIBLE | WS_CHILD | TBS_NOTICKS | TBS_FIXEDLENGTH; DWORD dwExStyle = WS_EX_TRANSPARENT;
_hwndSeek = CreateWindowEx(dwExStyle, TRACKBAR_CLASS, NULL, dwWindowStyles, 0, 0, 0, 0, _hwndLayout, (HMENU) FCIDM_MEDIABAND_SEEK, HINST_THISDLL, NULL);
if (_hwndSeek) { if (SetProp(_hwndSeek, c_szMediaBandProp, this)) { SetWindowLongPtr(_hwndSeek, GWLP_USERDATA, (LPARAM)(WNDPROC)(GetWindowLongPtr(_hwndSeek, GWLP_WNDPROC))); SetWindowLongPtr(_hwndSeek, GWLP_WNDPROC, (LPARAM)s_SeekWndSubClassProc); } SendMessage(_hwndSeek, TBM_SETRANGE, (WPARAM)TRUE , (LPARAM)MAKELONG(0, 100)); // min. & max. positions
SendMessage(_hwndSeek, TBM_SETPAGESIZE, 0, (LPARAM)4); // new page size
SendMessage(_hwndSeek, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
// ISSUE: For some reason, the length of the trackbar slider is screwed up, and the rect returned by the slider is half the actual width
SendMessage(_hwndSeek, TBM_SETTHUMBLENGTH, (WPARAM)VOLUME_GRIPPER_LENGTH*2, 0); _himlSeekBack = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_SEEKBACK), SEEK_PART_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlSeekFill = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_SEEKFILL), SEEK_PART_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _pmw[MW_SEEK] = new CMediaWidgetSeek(); if (_pmwSeek) { _pmwSeek->Initialize(_hwndSeek); } Comctl32_SetDPIScale(_hwndSeek); ShowWindow(_hwndSeek, SW_SHOW);
return S_OK; } else { return E_FAIL; } }
HRESULT CMediaBand::CreateVolumeControl() { DWORD dwWindowStyles = WS_TABSTOP | WS_VISIBLE | WS_CHILD | TBS_NOTICKS | TBS_TOOLTIPS; DWORD dwExStyle = WS_EX_TRANSPARENT;
_hwndVolume = CreateWindowEx(dwExStyle, TRACKBAR_CLASS, NULL, dwWindowStyles, 0, 0, 0, 0, _hwndLayout, (HMENU) FCIDM_MEDIABAND_VOLUME, HINST_THISDLL, NULL);
if (_hwndVolume) { if (SetProp(_hwndVolume, c_szMediaBandProp, this)) { SetWindowLongPtr(_hwndVolume, GWLP_USERDATA, (LPARAM)(WNDPROC)(GetWindowLongPtr(_hwndVolume, GWLP_WNDPROC))); SetWindowLongPtr(_hwndVolume, GWLP_WNDPROC, (LPARAM)s_VolumeWndSubClassProc); }
SendMessage(_hwndVolume, TBM_SETRANGE, (WPARAM)TRUE , (LPARAM)MAKELONG(0, 100)); // min. & max. positions
SendMessage(_hwndVolume, TBM_SETPAGESIZE, 0, (LPARAM) 4); // new page size
SendMessage(_hwndVolume, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)50);
ShowWindow(_hwndVolume, SW_SHOW);
_himlVolumeBack = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_VOLBKGND), VOLUME_BITMAP_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlVolumeFill = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_VOLFILL), VOLUME_BITMAP_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlGripper = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_VOLTAB), VOLUME_GRIPPER_LENGTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION);
_pmw[MW_VOLUME] = new CMediaWidgetVolume; if (_pmwVolume) { _pmwVolume->Initialize(_hwndVolume); } return S_OK; } else { return E_FAIL; } }
HRESULT CMediaBand::CreateLayoutPane() { if (!_hwndLayout) { WNDCLASS wndclass = { 0 }; wndclass.style = CS_PARENTDC; // | CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = s_LayoutWndProc; wndclass.hInstance = MLGetHinst(); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.lpszClassName = c_szMediaBarLayoutClassName;
SHRegisterClass(&wndclass);
_hwndLayout = CreateWindowEx(WS_EX_CONTROLPARENT, c_szMediaBarLayoutClassName, NULL, WS_TABSTOP | WS_VISIBLE | WS_CHILD, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, _hwnd, NULL, MLGetHinst(), (void *)this);
if (_hwndLayout == NULL) { ASSERT(FALSE); return E_FAIL; } else { ::ShowWindow(_hwndLayout, SW_SHOW); } }
return S_OK; }
#define BACKGROUND_WIDTH (240/3)
#define BACKGROUND_TOP 12
#define BACKGROUND_MIDDLE 2
#define BACKGROUND_BOTTOM 55
VOID CMediaBand::DrawBackground(HDC hdc, HWND hwnd) { if (_fHiColour) { HDC hdcSrc = CreateCompatibleDC(hdc); if (hdcSrc) { if (_hbmpBackground) { RECT rc; if (GetClientRect(hwnd, &rc)) { SelectObject(hdcSrc, _hbmpBackground);
UINT xTra = 0;
if (g_bRunOnMemphis && IS_WINDOW_RTL_MIRRORED(_hwnd)) { rc.right++; xTra++; }
// We have 9 regions to paint. First we'll bitblt the corners, and then we'll do middle sections, which can be stretched without
// loss of fidelity in a given direction.
// |A|B|C|
// |D|E|F|
// |G|H|I|
// Corners are bitblted
// A
BitBlt(hdc, rc.left, rc.top, BACKGROUND_WIDTH, BACKGROUND_TOP, hdcSrc, 0, 0, SRCCOPY); // C
BitBlt(hdc, max(rc.right-BACKGROUND_WIDTH, rc.left+BACKGROUND_WIDTH), rc.top, BACKGROUND_WIDTH, BACKGROUND_TOP, hdcSrc, 2*BACKGROUND_WIDTH, 0, SRCCOPY); // G
BitBlt(hdc, rc.left, max(rc.bottom-BACKGROUND_BOTTOM, rc.top+BACKGROUND_TOP), BACKGROUND_WIDTH, BACKGROUND_BOTTOM, hdcSrc, 0, BACKGROUND_TOP+BACKGROUND_MIDDLE, SRCCOPY); // I
BitBlt(hdc, max(rc.right-BACKGROUND_WIDTH, rc.left+BACKGROUND_WIDTH), max(rc.bottom-BACKGROUND_BOTTOM, rc.top+BACKGROUND_TOP), BACKGROUND_WIDTH*2, BACKGROUND_BOTTOM, hdcSrc, BACKGROUND_WIDTH*2, BACKGROUND_TOP+BACKGROUND_MIDDLE, SRCCOPY);
// Middles are all repeated/stetched
if (rc.right-BACKGROUND_WIDTH > rc.left+BACKGROUND_WIDTH) { // B
StretchBlt(hdc, rc.left+BACKGROUND_WIDTH, rc.top, RECTWIDTH(rc)-2*BACKGROUND_WIDTH+xTra, BACKGROUND_TOP, hdcSrc, BACKGROUND_WIDTH, 0, BACKGROUND_WIDTH, BACKGROUND_TOP, SRCCOPY); // H
StretchBlt(hdc, rc.left+BACKGROUND_WIDTH, max(rc.bottom-BACKGROUND_BOTTOM, rc.top+BACKGROUND_TOP), RECTWIDTH(rc)-2*BACKGROUND_WIDTH+xTra, BACKGROUND_BOTTOM, hdcSrc, BACKGROUND_WIDTH, BACKGROUND_TOP+BACKGROUND_MIDDLE, BACKGROUND_WIDTH, BACKGROUND_BOTTOM, SRCCOPY); }
if (rc.bottom-BACKGROUND_BOTTOM > rc.top+BACKGROUND_TOP) { // D
StretchBlt(hdc, rc.left, rc.top+BACKGROUND_TOP, BACKGROUND_WIDTH, RECTHEIGHT(rc)-BACKGROUND_TOP-BACKGROUND_BOTTOM, hdcSrc, 0, BACKGROUND_TOP, BACKGROUND_WIDTH, BACKGROUND_MIDDLE, SRCCOPY); // F
StretchBlt(hdc, max(rc.right-BACKGROUND_WIDTH, rc.left+BACKGROUND_WIDTH), rc.top+BACKGROUND_TOP, BACKGROUND_WIDTH, RECTHEIGHT(rc)-BACKGROUND_TOP-BACKGROUND_BOTTOM, hdcSrc, BACKGROUND_WIDTH*2, BACKGROUND_TOP, BACKGROUND_WIDTH, BACKGROUND_MIDDLE, SRCCOPY); // E
// This section is one solid colour.
if (rc.right-BACKGROUND_WIDTH > rc.left+BACKGROUND_WIDTH) { RECT rc2; rc2.left = rc.left+BACKGROUND_WIDTH; rc2.right = rc.right-BACKGROUND_WIDTH; rc2.top = rc.top+BACKGROUND_TOP; rc2.bottom = rc.bottom-BACKGROUND_BOTTOM; SHFillRectClr(hdc, &rc2, COLOR_BKGNDMIDDLE); } } } } DeleteDC(hdcSrc); } } else { RECT rc; if (GetClientRect(hwnd, &rc)) { SHFillRectClr(hdc, &rc, COLOR_BKGND16); } }
if (_hwndVideo && IsWindowVisible(_hwndVideo)) { RedrawWindow(_hwndVideo, NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE); } }
// WndProc for main window to go in rebar
LRESULT CALLBACK CMediaBand::s_LayoutWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = reinterpret_cast<CMediaBand *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (msg==WM_CREATE) { SetWindowLongPtr(hWnd, GWLP_USERDATA, (reinterpret_cast<LONG_PTR>((reinterpret_cast<CREATESTRUCT *>(lParam))->lpCreateParams))); return 0; } else if (pmb) { switch (msg) { case WM_PAINT: { break; }
case WM_ERASEBKGND: pmb->DrawBackground((HDC)wParam, hWnd); return TRUE;
case WM_SIZE: if ((LONG)LOWORD(lParam) <= 0 || (LONG)HIWORD(lParam) <= 0 ) break;
pmb->AdjustLayout(LOWORD(lParam), HIWORD(lParam)); break;
case WM_SYSCOLORCHANGE: case WM_WININICHANGE: { BOOL fNewColours = (SHGetCurColorRes() > 8); if (fNewColours!=pmb->_fHiColour) { pmb->SwitchBitmaps(fNewColours); } pmb->AdjustVideoHeight(TRUE); } break;
case WM_VSCROLL: case WM_HSCROLL: if ((HWND)lParam == pmb->_hwndSeek) { SendMessage(pmb->_hwndSeek, msg, wParam, lParam); } else if ((HWND)lParam == pmb->_hwndVolume) { SendMessage(pmb->_hwndVolume, msg, wParam, lParam); } break;
case WM_NOTIFY: { LRESULT lres; if (pmb->OnNotify((LPNMHDR)lParam, &lres)) { return lres; } break; } break;
case WM_COMMAND: { LRESULT lres; if (pmb->OnWinEvent(hWnd, msg, wParam, lParam, &lres) == S_OK) return lres; } break; } } return DefWindowProc(hWnd, msg, wParam, lParam); }
HRESULT CMediaBand::CreateParentPane() { if (!_hwnd) { WNDCLASS wndclass = { 0 }; wndclass.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = s_WndProc; wndclass.hInstance = MLGetHinst(); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.lpszClassName = c_szMediaBarClassName;
SHRegisterClass(&wndclass); _hwnd = CreateWindowEx(WS_EX_CONTROLPARENT, c_szMediaBarClassName, NULL, WS_TABSTOP | WS_VISIBLE | WS_CHILD, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, _hwndParent, NULL, MLGetHinst(), (void *)this); if (_hwnd == NULL) { ASSERT(FALSE); return E_FAIL; } else { ::ShowWindow(_hwnd, SW_SHOW); } } return S_OK; }
VOID CMediaBand::Resize(HWND hwnd, LONG lWidth, LONG lHeight) { if (lWidth <= 0 || lHeight <= 0) return; RECT rcParent; if (GetClientRect(_hwnd, &rcParent)) { if (IsWindowVisible(_hwndPopup)) { MoveWindow(_hwndContent, rcParent.left, rcParent.top, RECTWIDTH(rcParent), RECTHEIGHT(rcParent), FALSE); } else { LONG lPaneHeight = GetLayoutHeight(); MoveWindow(_hwndLayout, rcParent.left, rcParent.bottom-lPaneHeight, lWidth, lPaneHeight, FALSE); MoveWindow(_hwndContent, rcParent.left, rcParent.top, lWidth, RECTHEIGHT(rcParent)-lPaneHeight, FALSE); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); } } }
// WndProc for main window to go in rebar
LRESULT CALLBACK CMediaBand::s_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = reinterpret_cast<CMediaBand *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
switch (msg) { case WM_ERASEBKGND: break;
case WM_CREATE: SetWindowLongPtr(hWnd, GWLP_USERDATA, (reinterpret_cast<LONG_PTR>((reinterpret_cast<CREATESTRUCT *>(lParam))->lpCreateParams))); return 0;
case WM_SIZE: if (pmb) { pmb->Resize(hWnd, (LONG)LOWORD(lParam), (LONG)HIWORD(lParam)); } break;
case WM_MB_DEFERRED_NAVIGATE: // navigation cancelled by IBandNavigate::ISelect() call
if (pmb && (pmb->_strDeferredURL.Length() > 0)) { pmb->NavigateContentPane(pmb->_strDeferredURL); pmb->_strDeferredURL.Empty(); } break;
case WM_NOTIFY: if (pmb) { return pmb->_OnNotify((LPNMHDR)lParam); } break;
case WM_COMMAND: { LRESULT lres; if (pmb->OnWinEvent(hWnd, msg, wParam, lParam, &lres) == S_OK) return lres; }
case WM_TIMER: // timeout of user's second chance to click stop again and navigate to media content pane to default URL
if (pmb) { pmb->_CleanupStopTimer(); } break;
case WM_WTSSESSION_CHANGE: // stop playing media when media bar is no more in current terminal server session
// this avoids "background noise" when user does fast user switching to other login in XP
// NOTE: logging on as same user remotely will also stop stream
if (pmb && ((wParam == WTS_CONSOLE_DISCONNECT) || (wParam == WTS_REMOTE_DISCONNECT))) { pmb->Exec(&CLSID_MediaBand, FCIDM_MEDIABAND_STOP, 0, NULL, NULL); } break;
break; } return DefWindowProc(hWnd, msg, wParam, lParam); }
LRESULT CALLBACK CMediaBand::s_PopupWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = reinterpret_cast<CMediaBand *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
switch (uMsg) { case WM_CREATE: ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams); break;
case WM_ACTIVATE: if (pmb) { pmb->ActivatePopout(LOWORD(wParam)!=WA_INACTIVE); } return 0;
case WM_KEYDOWN: if (wParam==VK_ESCAPE) { pmb->DockMediaPlayer(); } break;
case WM_GETMINMAXINFO: // prevent it from getting too small or too large
if (pmb) { pmb->ComputeMinMax((MINMAXINFO *)lParam); } break;
case WM_SIZE: if (pmb && IsWindowVisible(hwnd)) { SetWindowPos(pmb->_hwndLayout, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOACTIVATE); // MoveWindow(pmb->_hwndLayout, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
} break;
case WM_SYSCOMMAND : if (wParam == SC_CLOSE) pmb->DockMediaPlayer(); break; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
VOID CMediaBand::ActivatePopout(BOOL fState) { _fPopoutHasFocus = fState; UIActivateIO(fState, NULL); }
VOID CMediaBand::ComputeMinMax(MINMAXINFO *pMinMax) { pMinMax->ptMinTrackSize.x = GetMinPopoutWidth(); if (_fIsVideo) { pMinMax->ptMinTrackSize.y = GetPopoutHeight(FALSE) + VIDEO_MIN_HEIGHT; } else { pMinMax->ptMaxTrackSize.y = pMinMax->ptMinTrackSize.y = GetPopoutHeight(FALSE); } }
LRESULT CALLBACK CMediaBand::s_VolumeWndSubClassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = (CMediaBand*)GetProp(hwnd, c_szMediaBandProp);
if (!pmb) return DefWindowProcWrap(hwnd, uMsg, wParam, lParam);
WNDPROC pfnOldWndProc = (WNDPROC)(GetWindowLongPtr(hwnd, GWLP_USERDATA));
switch (uMsg) { case WM_HSCROLL: case WM_VSCROLL: { INT_PTR lPos = SendMessage(hwnd, TBM_GETPOS, (WPARAM) 0 ,(LPARAM) 0);
switch (LOWORD(wParam)) { case TB_THUMBPOSITION: case TB_THUMBTRACK: { if (pmb != NULL) { pmb->_dblVol = (double)lPos; if (pmb->_pMediaPlayer) { pmb->_pMediaPlayer->put_volume(pmb->_dblVol); } } InvalidateRect(hwnd,NULL,TRUE); UpdateWindow(hwnd); } break ;
case TB_TOP: { if (pmb) { pmb->_dblVol = 0; if (pmb->_pMediaPlayer) { pmb->_pMediaPlayer->put_volume(0); } } } break;
case TB_BOTTOM: { if (pmb) { pmb->_dblVol = 100; if (pmb->_pMediaPlayer) { pmb->_pMediaPlayer->put_volume(100); } } } break; } } break; case WM_DESTROY: { //
// Unsubclass myself.
//
RemoveProp(hwnd, c_szMediaBandProp); if (pfnOldWndProc) { SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) pfnOldWndProc); } } break; } return CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, lParam); }
LRESULT CALLBACK CMediaBand::s_SeekWndSubClassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMediaBand* pmb = (CMediaBand*)GetProp(hwnd, c_szMediaBandProp); if (!pmb) return DefWindowProcWrap(hwnd, uMsg, wParam, lParam); WNDPROC pfnOldWndProc = (WNDPROC)(GetWindowLongPtr(hwnd, GWLP_USERDATA)); switch (uMsg) { case WM_ERASEBKGND: break; case WM_HSCROLL: { if (pmb && pmb->_pMediaPlayer && pmb->_fPlaying) { if (pmb->_pMediaPlayer->IsSeekPossible() && !pmb->_isUIDisabled()) { INT_PTR lPos = SendMessage(hwnd, TBM_GETPOS, (WPARAM) 0 ,(LPARAM) 0); switch (LOWORD(wParam)) { case TB_THUMBPOSITION: { pmb->_fSeeking = FALSE; pmb->Seek(lPos / 100.0); if (!pmb->_fUserPaused) { pmb->_pMediaPlayer->Resume(); } } break; case TB_THUMBTRACK: { pmb->_fSeeking = TRUE; if (!pmb->_fUserPaused) { pmb->_pMediaPlayer->Pause(); } pmb->Seek(lPos / 100.0); InvalidateRect(hwnd,NULL,TRUE); UpdateWindow(hwnd); } break; case TB_PAGEUP: case TB_TOP: { double dblProgress = pmb->_pMediaPlayer->GetTrackProgress(); // seek backwards by 5%
pmb->Seek(dblProgress - 0.05); } break; case TB_PAGEDOWN: case TB_BOTTOM: { double dblProgress = pmb->_pMediaPlayer->GetTrackProgress(); // seek ahead by 5%
pmb->Seek(dblProgress + 0.05); } break; } } else { // disallow seeking by setting the seek position to what it was
double dblProgress = pmb->_pMediaPlayer->GetTrackProgress(); pmb->SetSeekPos(static_cast<float>(dblProgress)); } } } break; case WM_DESTROY: { //
// Unsubclass myself.
//
RemoveProp(hwnd, c_szMediaBandProp); if (pfnOldWndProc) { SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) pfnOldWndProc); } } break; } return CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, lParam); }
// sends appropriate resize messages to our children windows
VOID CMediaBand::_ResizeChildWindows(HWND hwnd, LONG width, LONG height, BOOL fRepaint) { // Calculate the display rectangle
RECT rc; SIZE sizeTB = {0}, sizePopout = {0}; LONG lHorzSpacing = MIN_HORZ_SPACING; _sizeLayout.cx = width; _sizeLayout.cy = GetLayoutHeight();
SetRect(&rc, 0, 0, width, height);
LONG lWidthOffset = rc.left+lHorzSpacing;
HDWP hdwp = BeginDeferWindowPos(10);
lWidthOffset = rc.left+lHorzSpacing; if (_fIsVideo && _hwndVideo) { LONG lWidth, lHeight, lVideoStart = 0; if (_hwndPopup && IsWindowVisible(_hwndPopup)) { lWidth = width-rc.left-lHorzSpacing*2; lHeight = GetVideoHeight(); } else { lWidth = SCALEX(MIN_WINDOW_WIDTH-rc.left-lHorzSpacing*2); lHeight = SCALEY(MIN_WINDOW_WIDTH-rc.left); } // Resize the video and try to get the video sizes
_ResizeVideo(&lWidth,&lHeight);
_sizeVideo.cx = (LONG)lWidth ; _sizeVideo.cy = (LONG)lHeight ; if (lWidth >= width-rc.left-lHorzSpacing*2) lVideoStart = rc.left + lHorzSpacing; else lVideoStart = (width-rc.left-lHorzSpacing*2-lWidth)/2 + rc.left + lHorzSpacing ;
DeferWindowPos(hdwp, _hwndVideo, HWND_TOP, (LONG)lVideoStart, rc.top+VIEW_MARGIN_TOP_VIDEO, (LONG)lWidth, (LONG)lHeight, SWP_NOZORDER); } else { _sizeVideo.cx = 0 ; _sizeVideo.cy = 0; }
// Bottom-most row
LONG lHeightOffset = height - VIEW_MARGIN_BOTTOM; lWidthOffset = rc.left + VIEW_MARGIN_LEFT;
LONG lSeekY = lHeightOffset, lSeekX = 0; if (_pmwPlay && _pmwPlay->_hwnd) { GetToolbarSize(_pmwPlay->_hwnd, &sizeTB); lSeekY = lHeightOffset-sizeTB.cy; DeferWindowPos(hdwp, _pmwPlay->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); lWidthOffset += sizeTB.cx; }
if (_pmwStop && _pmwStop->_hwnd) { GetToolbarSize(_pmwStop->_hwnd, &sizeTB); DeferWindowPos(hdwp, _pmwStop->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); lWidthOffset += sizeTB.cx; } if (_pmwBack && _pmwBack->_hwnd) { GetToolbarSize(_pmwBack->_hwnd, &sizeTB); lSeekX = lWidthOffset; DeferWindowPos(hdwp, _pmwBack->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); lWidthOffset += sizeTB.cx; } if (_pmwNext && _pmwNext->_hwnd) { GetToolbarSize(_pmwNext->_hwnd, &sizeTB); DeferWindowPos(hdwp, _pmwNext->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); lWidthOffset += sizeTB.cx; }
if (_pmwMute && _pmwMute->_hwnd) { GetToolbarSize(_pmwMute->_hwnd, &sizeTB); LONG lVolumeWidth = SCALEX(MIN_VOLUME_WIDTH); lWidthOffset = max(lWidthOffset+lHorzSpacing, (width - sizeTB.cx - lVolumeWidth - VIEW_MARGIN_RIGHT)); DeferWindowPos(hdwp, _pmwMute->_hwnd, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, sizeTB.cx, sizeTB.cy, SWP_NOZORDER); if (_hwndVolume) { lWidthOffset += sizeTB.cx; DeferWindowPos(hdwp, _hwndVolume, HWND_TOP, lWidthOffset, lHeightOffset-sizeTB.cy, lVolumeWidth, SCALEY(MIN_VOLUME_HEIGHT), SWP_NOZORDER); } }
lWidthOffset = rc.left + lHorzSpacing; if (_hwndSeek) { LONG lSeekWidth = max(width-lHorzSpacing-lSeekX-2, 0); DeferWindowPos(hdwp, _hwndSeek, HWND_TOP, lSeekX+2, lSeekY, lSeekWidth, SCALEY(SEEK_HEIGHT), SWP_NOZORDER); }
lWidthOffset = rc.left + VIEW_MARGIN_INFO_LEFT; if (ISVALIDWIDGET(_pmwPop)) { GetToolbarSize(_pmwPop->_hwnd, &sizePopout); DeferWindowPos(hdwp, _pmwPop->_hwnd, HWND_TOP, width-sizePopout.cx-VIEW_MARGIN_INFO_LEFT, lSeekY-sizePopout.cy-VIEW_CONTROLS_MARGIN, sizePopout.cx, sizePopout.cy, SWP_NOZORDER); }
if (ISVALIDWIDGET(_pmwOptions)) { GetToolbarSize(_pmwOptions->_hwnd, &sizeTB); DeferWindowPos(hdwp, _pmwOptions->_hwnd, HWND_TOP, lWidthOffset, lSeekY-sizeTB.cy-VIEW_CONTROLS_MARGIN, width-lHorzSpacing*3-sizePopout.cx, sizeTB.cy, SWP_NOZORDER); _iOptionsWidth = width-lHorzSpacing*3-sizePopout.cx-10; SendMessage(_pmwOptions->_hwnd, TB_SETBUTTONWIDTH, 0, (LPARAM) MAKELONG(0, _iOptionsWidth)); SendMessage(_pmwOptions->_hwnd, TB_AUTOSIZE, 0, 0); }
EndDeferWindowPos(hdwp);
if (fRepaint) { InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); } else { InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); } }
LONG CMediaBand::GetControlsHeight() { LONG lHeightOffset = VIEW_MARGIN_TOP; // Compute height for options here
if (ISVALIDWIDGET(_pmwOptions)) { SIZE sizeTB = {0}; GetToolbarSize(_pmwOptions->_hwnd, &sizeTB); lHeightOffset += SCALEY(sizeTB.cy) + VIEW_CONTROLS_MARGIN; } // Rest of controls
lHeightOffset += VIEW_MARGIN_BOTTOM + SCALEY(VIEW_CONTROLS_HEIGHT); return lHeightOffset; }
LONG CMediaBand::GetLayoutHeight(LONG lWidth) { LONG lHeightOffset = GetControlsHeight(); if (_hwndVideo && (IsWindowVisible(_hwndVideo) || _fIsVideo)) { LONG lHeight = GetVideoHeight(lWidth); if (lHeight>0) lHeightOffset += lHeight + VIEW_MARGIN_TOP_VIDEO; } return lHeightOffset; }
float CMediaBand::GetSeekPos() { INT_PTR lMax = SendMessage(_hwndSeek, TBM_GETRANGEMAX, 0, 0) ; INT_PTR lMin = SendMessage(_hwndSeek, TBM_GETRANGEMIN, 0, 0) ; INT_PTR lPos = SendMessage(_hwndSeek, TBM_GETPOS, 0, 0) ; return ((float)lPos / (float)(lMax - lMin)); } VOID CMediaBand::SetSeekPos(float fPosition) { INT_PTR lMax = SendMessage(_hwndSeek, TBM_GETRANGEMAX, 0, 0) ; INT_PTR lMin = SendMessage(_hwndSeek, TBM_GETRANGEMIN, 0, 0) ; fPosition *= (lMax - lMin) ; INT_PTR lPos = SendMessage(_hwndSeek, TBM_GETPOS, 0, 0) ; if (lPos!=(LONG) fPosition) { SendMessage(_hwndSeek, TBM_SETPOS, TRUE, (LPARAM) (LONG) fPosition); InvalidateRect(_hwndSeek, NULL,TRUE); UpdateWindow(_hwndSeek); } }
HRESULT CMediaBand::_InitializeMediaUI() { HRESULT hr = S_OK;
_fHiColour = (SHGetCurColorRes() > 8);
if (!_hwndLayout) { CreateLayoutPane(); } if (!_hwndContent) { InitContentPane(); }
if (!_fInitialized && _hwndLayout) { _szConnecting[0] = TEXT('\0'); MLLoadString(IDS_MEDIABAND_NOWDOWNLOADING, _szConnecting, ARRAYSIZE(_szConnecting));
_hbmpBackground = LoadBitmap(HINST_THISDLL, MAKEINTRESOURCE(IDB_MEDIABAND_BG_BASE));
CreateControls(); CreateSeekBar(); CreateVolumeControl();
ResetPlayer(); if (!_fHiColour) { // Assume high colour. If not, switch to low colour versions.
SwitchBitmaps(_fHiColour); }
// want to sink notification when fast user switch occurs:
WTSRegisterSessionNotification(_hwnd, NOTIFY_FOR_THIS_SESSION);
_fInitialized = TRUE; } _ShowAllWindows(TRUE);
return hr; }
VOID CMediaBand::_ShowAllWindows(BOOL fShow) { if (_hwndPopup && IsWindowVisible(_hwndPopup)) { // SendMessage(_hwndPopup, WM_SYSCOMMAND, (WPARAM)SC_CLOSE, (LPARAM)0);
return; } if (_hwndLayout) ShowWindow(_hwndLayout, fShow ? SW_SHOW : SW_HIDE);
for (int i=0; i < ARRAYSIZE(_pmw); i++) { if (ISVALIDWIDGET(_pmw[i])) ShowWindow(_pmw[i]->_hwnd, fShow ? SW_SHOW : SW_HIDE); } if (_hwndContent) { ShowWindow(_hwndContent, fShow ? SW_SHOW : SW_HIDE); } }
VOID CMediaBand::ToggleMute() { _fMuted = !_fMuted; if (_pmwMute) { _pmwMute->SetState(_fMuted); } if (_pMediaPlayer) { _pMediaPlayer->put_mute(_fMuted); } }
VOID CMediaBand::TogglePlayPause() { if (!EnsurePlayer()) { return; }
VARIANT_BOOL vbPaused = _pMediaPlayer->isPaused(); VARIANT_BOOL vbStopped = _pMediaPlayer->isStopped();
// if player is in paused state, show the play button and vice-versa
// _fPlayButton==FALSE means that the pause button is currently displayed
// _fPlayButton==TRUE means that the play button is currently displayed
if (vbStopped || vbPaused) { if (!_fPlayButton) { _fPlayButton = TRUE; if (_pmwPlay) { _pmwPlay->SetMode(MWB_NORMAL); _pmwPlay->SetImageSource(TRUE); } } } else { if (_fPlayButton) { _fPlayButton = FALSE;
if (_pMediaPlayer->IsPausePossible()) { // ISSUE (akabir): The following line doesn't work correctly
// _pmwPlay->SetMode(MWB_DISABLED);
}
// change button bitmaps
if (_pmwPlay) { _pmwPlay->SetImageSource(FALSE); } } } }
HWND CMediaBand::GetBrowserWindow() { CComPtr<IWebBrowser2> spWebBrowser;
// QS for the browser main window
if (SUCCEEDED(QueryService(SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &spWebBrowser)))) { LONG_PTR hwndApp; if (SUCCEEDED(spWebBrowser->get_HWND(&hwndApp))) { return ((HWND)hwndApp); } } return NULL; }
// Called only by CMediaBand::CreateInstance
HRESULT CMediaBand::InitPlayerPopup() { HRESULT hr = E_FAIL;
WNDCLASS wndclass = { 0 }; wndclass.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = s_PopupWndProc; wndclass.hInstance = HINST_THISDLL; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.lpszClassName = c_szMediaBarPopupClassName; wndclass.hIcon = (HICON)LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(IDB_TB_MEDIA_HOT)); wndclass.hbrBackground = NULL; SHRegisterClass(&wndclass);
DWORD dwStyle = (WS_OVERLAPPEDWINDOW & ~(WS_MINIMIZEBOX)); DWORD dwExStyle = WS_EX_CONTROLPARENT | (IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd : 0);
_hwndPopup = CreateWindowEx(dwExStyle, c_szMediaBarPopupClassName, NULL, dwStyle, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, GetBrowserWindow(), NULL, HINST_THISDLL, (void *)this);
hr = (_hwndPopup && _hwndLayout) ? S_OK : E_FAIL;
// modify the properties of the window as appropriate
if (SUCCEEDED(hr)) { // set parent
SHSetParentHwnd(_hwndLayout, _hwndPopup);
WCHAR szTitle[256]; MLLoadStringW(IDS_MEDIABANDTEXT, szTitle, ARRAYSIZE(szTitle)); SetWindowText(_hwndPopup, szTitle);
if (_sizeLayout.cx < GetMinPopoutWidth()) _sizeLayout.cx = GetMinPopoutWidth();
if (_fSavedPopoutState) { SetWindowPlacement(_hwndPopup, &_wpPopout); } else { RECT rc = { 0 }; INT iHeight = GetPopoutHeight(TRUE, _sizeLayout.cx); INT x = 10, y = 10; if (GetWindowRect(_hwnd, &rc)) { x = IS_WINDOW_RTL_MIRRORED(_hwnd) ? (rc.right - _sizeLayout.cx) : rc.left; y = rc.bottom - iHeight; if (y < 0) { y = rc.bottom; } } SetWindowPos(_hwndPopup, HWND_TOPMOST, x, y, _sizeLayout.cx, iHeight, SWP_FRAMECHANGED | SWP_SHOWWINDOW); }
ShowWindow(_hwndPopup, SW_SHOW); UpdateWindow(_hwndPopup);
if (_pmwPop && _pmwPop->_hwnd) { _pmwPop->SetImageSource(FALSE); if (_iElement==MW_POP) { _fPopoutHasFocus = TRUE; UIActivateIO(TRUE, NULL); } } } return hr; }
HRESULT CMediaBand::GetTrackTitle(BSTR *pbstrTitle) { USES_CONVERSION;
CComPtr<ITIMEMediaElement> spMediaElem; HRESULT hr = E_FAIL;
if ( !EnsurePlayer() || !pbstrTitle) { hr = E_FAIL; goto done; }
*pbstrTitle = NULL;
//
// if a title is available from the media element, display it
//
hr = _pMediaPlayer->get_mediaElement(&spMediaElem); if ( FAILED(hr) || !spMediaElem.p) { hr = E_FAIL; goto done; }
hr = spMediaElem->get_title(pbstrTitle); if (SUCCEEDED(hr) && (*pbstrTitle != NULL)) { if (SysStringLen(*pbstrTitle)>0) { goto done; } else { SysFreeString(*pbstrTitle); *pbstrTitle = NULL; } }
//
// if title is not available, display the the url
//
hr = _pMediaPlayer->get_url(pbstrTitle); if (SUCCEEDED(hr) && *pbstrTitle && (SysStringLen(*pbstrTitle)<=0)) { SysFreeString(*pbstrTitle); *pbstrTitle = NULL; }
if (SUCCEEDED(hr) && (*pbstrTitle != NULL)) { // If the url is available, display it
DWORD dwcchUnescaped; TCHAR tszPath[MAX_PATH];
StrCpyN(tszPath, W2T(*pbstrTitle), ARRAYSIZE(tszPath)); PathStripPath(tszPath);
if (SUCCEEDED(UrlUnescape(tszPath, NULL, &dwcchUnescaped, URL_UNESCAPE_INPLACE))) { SysFreeString(*pbstrTitle); *pbstrTitle = SysAllocString(tszPath); } }
hr = S_OK; done: return hr; }
VOID CMediaBand::ShowPlayingStatus(BOOL fInitial) { USES_CONVERSION;
BSTR bstrTitle = NULL; if (EnsurePlayer() && _fPlaying) { if (!_isUIDisabled()) { GetTrackTitle(&bstrTitle); // Display the name of the title
if (bstrTitle && bstrTitle[0] != 0) SetStatusText(W2T(bstrTitle)); } else { TCHAR szText[MAX_PATH]; szText[0] = TEXT('\0'); MLLoadString(IDS_MEDIABAND_PLAYING, szText, ARRAYSIZE(szText)); SetStatusText(szText); }
CComPtr<ITIMEMediaElement> spMediaElem; HRESULT hr = _pMediaPlayer->get_mediaElement(&spMediaElem); ERROREXIT(hr)
// store away the natural length of the media
hr = spMediaElem->get_mediaDur(&_dblMediaDur); ERROREXIT(hr) }
done : if (bstrTitle) SysFreeString(bstrTitle); }
VOID CMediaBand::SetStatusText(LPTSTR lpwStatusInfo) { if (ISVALIDWIDGET(_pmwOptions)) { // change buttons
TBBUTTONINFO tbbi; TCHAR szText[MAX_PATH]; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_BYINDEX | TBIF_TEXT; tbbi.pszText = szText ; tbbi.cchText = MAX_PATH ; SendMessage(_pmwOptions->_hwnd, TB_GETBUTTONINFO, (WPARAM)0, (LPARAM)&tbbi);
if (StrCmpIW(tbbi.pszText,lpwStatusInfo)) { tbbi.pszText = lpwStatusInfo; if (_pszStatus) { delete [] _pszStatus; } _pszStatus = new TCHAR[lstrlen(lpwStatusInfo)+1]; if (_pszStatus) { StringCchCopy(_pszStatus, ARRAYSIZE(_pszStatus), lpwStatusInfo); } SendMessage(_pmwOptions->_hwnd, TB_SETBUTTONINFO, (WPARAM)0, (LPARAM)&tbbi); // Need to force a resizing to accommodate new text
SendMessage(_pmwOptions->_hwnd, TB_SETBUTTONWIDTH, 0, (LPARAM) MAKELONG(0, _iOptionsWidth-1)); SendMessage(_pmwOptions->_hwnd, TB_SETBUTTONWIDTH, 0, (LPARAM) MAKELONG(0, _iOptionsWidth)); } } }
HRESULT CMediaBand::ShowPlayListMenu(HWND hwnd, RECTL* rc) { if (_hPlayListMenu) { DestroyMenu(_hPlayListMenu); _hPlayListMenu = NULL; }
_hPlayListMenu = GetSubMenu(LoadMenu(MLGetHinst(), MAKEINTRESOURCE(MENU_MEDIA_GENERIC)), 0);
if (_EnumPlayItems() != S_OK) { DestroyMenu(_hPlayListMenu); _hPlayListMenu = NULL; return S_OK; }
ASSERT(_pMediaPlayer); UINT nID = FCIDM_PLAYITEM_START + (UINT)_pMediaPlayer->GetPlayListItemIndex(); CheckMenuRadioItem(_hPlayListMenu, FCIDM_PLAYITEM_START, FCIDM_PLAYITEM_END, nID, MF_BYCOMMAND); UpdateMenuItems(_hPlayListMenu);
POINT pt = {rc->left ,rc->bottom}; int idCmd = TrackPopupMenu(_hPlayListMenu, TPM_LEFTBUTTON | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL);
if (idCmd>=FCIDM_PLAYITEM_START && idCmd<=FCIDM_PLAYITEM_END) { UINT iCurTrack = idCmd - FCIDM_PLAYITEM_START ; _pMediaPlayer->SetActiveTrack(iCurTrack); UpdateBackForwardControls(); } else { HandleMenuTasks(idCmd); } return S_OK; }
STDMETHODIMP CMediaBand::_EnumPlayItems() { USES_CONVERSION;
CComPtr<ITIMEMediaElement> spMediaElem; CComPtr<ITIMEPlayList> spPlayList; CComVariant svarIndex; long lLength = 0; INT i = 0; MENUITEMINFO mii = { sizeof(mii) };
HRESULT hr = _pMediaPlayer->get_mediaElement(&spMediaElem); ERROREXIT(hr)
hr = spMediaElem->get_playList(&spPlayList); ERROREXIT(hr)
if (!(spPlayList.p)) return S_FALSE;
hr = spPlayList->get_length(&lLength); ERROREXIT(hr)
svarIndex.vt = VT_I4;
mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; mii.fType = MFT_STRING | MFT_RADIOCHECK; mii.fState = MF_ENABLED;
for (; i < lLength; i++) { CComPtr<ITIMEPlayItem> spPlayItem; CComBSTR sbstrTitle; TCHAR wszPath[40];
V_I4(&svarIndex) = i;
hr = spPlayList->item(svarIndex, &spPlayItem); ERROREXIT(hr)
hr = spPlayItem->get_title(&sbstrTitle); ERROREXIT(hr)
mii.wID = i + FCIDM_PLAYITEM_START; if (sbstrTitle.Length() != 0) { StrCpyN(wszPath, sbstrTitle, ARRAYSIZE(wszPath)); } else { CComBSTR sbstrSrc;
if (SUCCEEDED(spPlayItem->get_src(&sbstrSrc)) && sbstrSrc.Length() != 0) { PWSTR psz = PathFindFileName(sbstrSrc); StrCpyN(wszPath, psz, ARRAYSIZE(wszPath)); } else { WCHAR szTemplate[64]; if (!MLLoadStringW(IDS_MEDIABAND_TRACKNUMBER, szTemplate, ARRAYSIZE(szTemplate))) { StrCpy(szTemplate, TEXT("%d")); } wnsprintf(wszPath, ARRAYSIZE(wszPath), szTemplate, i+1); } } mii.dwTypeData = (LPTSTR)wszPath; InsertMenuItem(_hPlayListMenu, i, TRUE, &mii); } mii.fMask = MIIM_TYPE; mii.fType = MFT_SEPARATOR; InsertMenuItem(_hPlayListMenu, i, TRUE, &mii); hr = S_OK; done: return hr; }
HRESULT CMediaBand::ShowGenericMenu(HWND hwnd, RECTL* rc) { HMENU hMenu = GetSubMenu(LoadMenu(MLGetHinst(), MAKEINTRESOURCE(MENU_MEDIA_GENERIC)), 0); if (hMenu) { UpdateMenuItems(hMenu); int idCmd = TrackPopupMenu(hMenu, TPM_LEFTBUTTON | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, rc->left, rc->bottom, 0, hwnd, NULL); HandleMenuTasks(idCmd); DestroyMenu(hMenu); }
return S_OK; }
HRESULT CMediaBand::HandleMenuTasks(INT idCmd) { switch (idCmd) { case IDM_MEDIA_PLAYINDEFAULT: { CComBSTR sbstrUrl;
if (SUCCEEDED(_pMediaPlayer->get_url(&sbstrUrl)) && (NULL != sbstrUrl.m_str)) { _OpenInDefaultPlayer(sbstrUrl); } } break;
case IDM_MEDIA_ADDTOFAVORITES: { BSTR bstr = NULL, bstrTitle = NULL; if (EnsurePlayer() && !_isUIDisabled() && SUCCEEDED(_pMediaPlayer->get_url(&bstr)) && bstr && SUCCEEDED(GetTrackTitle(&bstrTitle))) { if (*bstr) { AddToFavorites(bstr, bstrTitle); } SysFreeString(bstr); } break; }
case IDM_MEDIA_PLAYINBAR: ToggleAutoplay(!GetAutoplay()); break;
case IDM_MEDIA_ASKTYPES: ToggleAutoplayPrompting(!GetAutoplayPrompt()); break;
case IDM_MEDIA_RESETTYPES: ResetMimePreferences(); break;
case IDM_MEDIA_TAKEOVERTYPES: if (PromptSettings(IDD_MEDIA_TAKEOVERMIMEPROMPT)) { // do take over file types here
} break;
case IDM_MEDIA_RADIO_GOTO: _NavigateMainWindow(c_szRadioUrl); break;
case IDM_MEDIA_BROADBAND_GUIDE: NavigateMoreMedia(); break; } return S_OK; } HRESULT CMediaBand::_NavigateMainWindow(LPCTSTR wstrUrl, bool fSuppressFirstAutoPlay /* = false */) { CComPtr<IWebBrowser2> spWB2;
// QS for the media bar
HRESULT hr = QueryService(SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &spWB2)); if (SUCCEEDED(hr)) { CComBSTR sbstrUrl(wstrUrl); CComVariant svarEmpty;
if (fSuppressFirstAutoPlay) { hr = CMediaBarHelper::DisableFirstAutoPlay(spWB2); if (FAILED(hr)) goto done; }
if (sbstrUrl) { hr = spWB2->Navigate(sbstrUrl, &svarEmpty, &svarEmpty, &svarEmpty, &svarEmpty); } else { hr = E_OUTOFMEMORY; } }
done: return hr; }
HRESULT CMediaBand::ResetMimePreferences() { HRESULT hr = S_OK;
if (PromptSettings(IDD_MEDIA_RESETMIMEPROMPT)) { DWORD dwRet = SHDeleteKey(HKEY_CURRENT_USER, WZ_SMIE_MEDIA_MIME); if (ERROR_SUCCESS != dwRet) { hr = E_FAIL; } } return hr; }
BOOL CMediaBand::PromptSettings(UINT IDPROMPT) { return (DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDPROMPT), GetBrowserWindow(), s_PromptMimeDlgProc, NULL) == IDOK); }
INT_PTR CALLBACK CMediaBand::s_PromptMimeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COMMAND: if (GET_WM_COMMAND_ID(wParam, lParam)==IDC_MEDIA_MOREINFO) { SHHtmlHelpOnDemandWrap(GetParent(hDlg), TEXT("iexplore.chm > iedefault"), 0, (DWORD_PTR) TEXT("mediabar_settings.htm"), ML_CROSSCODEPAGE); } else { EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); } break; } return FALSE; }
HRESULT CMediaBand::AddToFavorites(BSTR bstrUrl, BSTR bstrTitle) { HRESULT hr = E_FAIL;
if (_hwndPopup && IsWindowVisible(_hwndPopup)) { DockMediaPlayer(); }
if (bstrUrl) { CComPtr<IShellUIHelper> spShellUIHelper; hr = CoCreateInstance(CLSID_ShellUIHelper, NULL, CLSCTX_INPROC_SERVER, IID_IShellUIHelper, (void**) &spShellUIHelper); if (SUCCEEDED(hr)) { CComVariant svarTitle(bstrTitle);
hr = spShellUIHelper->AddFavorite(bstrUrl, &svarTitle); } } return hr; }
LONG CMediaBand::GetVideoHeight(LONG lSpecifiedWidth, BOOL fNewVideo) { LONG lPaneWidth = lSpecifiedWidth==0 ? SCALEX(MIN_WINDOW_WIDTH) : lSpecifiedWidth; LONG lWidth = lPaneWidth-MIN_HORZ_SPACING*2, lHeight = lWidth; // Assumption: Video is never taller than it is wide
if (_hwndPopup && IsWindowVisible(_hwndPopup)) { RECT rcWindow; GetClientRect(_hwndPopup,&rcWindow); lPaneWidth = RECTWIDTH(rcWindow); // minimum widths as per spec
lWidth = lPaneWidth - MIN_HORZ_SPACING * 2;
// Allow for controls.
if (fNewVideo) { lHeight = lWidth; } else { lHeight = RECTHEIGHT(rcWindow)-GetControlsHeight()-VIEW_MARGIN_TOP_VIDEO; } }
// Resize the video and get video sizes
_ResizeVideo(&lWidth,&lHeight);
if (lWidth != -1 || lHeight != -1) return (lHeight>0 ? lHeight : (lPaneWidth-MIN_HORZ_SPACING*5)) ; else return -1; }
VOID CMediaBand::DockMediaPlayer() { if (!_hwndPopup) { InitPlayerPopup(); } else if (IsWindowVisible(_hwndPopup)) { // map the system window close request into a redocking operation instead
// of closing
_wpPopout.length = sizeof(_wpPopout); _fSavedPopoutState = GetWindowPlacement(_hwndPopup, &_wpPopout);
// set the parent back to embedded window
SHSetParentHwnd(_hwndLayout, _hwnd);
DestroyWindow(_hwndPopup); _hwndPopup = NULL;
if (_pmwPop && _pmwPop->_hwnd) { _pmwPop->SetImageSource(TRUE); } }
RECT rcParent; GetClientRect(_hwnd, &rcParent); SendMessage(_hwnd, WM_SIZE, (WPARAM)0, (LPARAM)MAKELONG(RECTWIDTH(rcParent), RECTHEIGHT(rcParent))); InvalidateRect(_hwnd, NULL, TRUE); UpdateWindow(_hwnd); }
VOID CMediaBand::GetToolbarSize(HWND hwndTB, SIZE *pSize) { int nButtons = ToolBar_ButtonCount(hwndTB); pSize->cx = 0 ; pSize->cy = 0 ; for (int nIndex = 0; nIndex < nButtons; nIndex++) { RECTL rc ; SendMessage(hwndTB, TB_GETITEMRECT, nIndex, (LPARAM)&rc); pSize->cx += RECTWIDTH(rc); pSize->cy = max(RECTHEIGHT(rc),pSize->cy); } }
//+-------------------------------------------------------------------------
// Name: Invoke, IDispatch
//
// Abstract:
// This switches on the dispid looking for dispid's of events
// that it should handle. Note, this is called for all events
// fired from the window, only the selected events are handled.
//--------------------------------------------------------------------------
STDMETHODIMP CMediaBand::Invoke( /* [in] */ DISPID dispidMember, /* [in] */ REFIID /*riid*/, /* [in] */ LCID /*lcid*/, /* [in] */ WORD /*wFlags*/, /* [out][in] */ DISPPARAMS* pdispparams, /* [out] */ VARIANT* pVarResult, /* [out] */ EXCEPINFO* /*pExcepInfo*/, /* [out] */ UINT* puArgErr) { USES_CONVERSION; HRESULT hr = E_FAIL; if (!pdispparams) return E_INVALIDARG;
// show our friendly 404 page on navigation error:
if (dispidMember == DISPID_NAVIGATEERROR) { // validate expected param list
if ( (pdispparams->cArgs != 5) || (pdispparams->rgvarg[4].vt != VT_DISPATCH) // IWebBrowser2 as IDispatch
|| (pdispparams->rgvarg[3].vt != (VT_BYREF | VT_VARIANT)) // target URL as BSTR
|| (pdispparams->rgvarg[2].vt != (VT_BYREF | VT_VARIANT)) // target frame as BSTR
|| (pdispparams->rgvarg[1].vt != (VT_BYREF | VT_VARIANT)) // status code as VT_I4
|| (pdispparams->rgvarg[0].vt != (VT_BYREF | VT_BOOL))) // Cancel as VT_BOOL, OUT param
{ ASSERTMSG(0, "unexpected param list for NavigateError"); return E_INVALIDARG; } LPCTSTR pszURL = W2CT(VariantToStrCast(&pdispparams->rgvarg[3])); int iStatus = VariantToInt(pdispparams->rgvarg[1]); // can't navigate to page, give help page
TCHAR szResURL[2*MAX_URL_STRING]; // expect URL to help page and original URL
HRESULT hr; hr = _BuildPageURLWithParam(c_sz404URL, pszURL, szResURL, ARRAYSIZE(szResURL)); if (FAILED(hr)) { return hr; }
// navigate deferred, caller of this Invoke() will cancel the current navigation
_DeferredNavigate(szResURL);
// have our own page, cancel the std error page:
ASSERT(pdispparams->rgvarg[0].vt == (VT_BYREF | VT_BOOL)); *V_BOOLREF(&pdispparams->rgvarg[0]) = VARIANT_TRUE; }
// just for additional leak protection: give up proxy refs if not done already
// before we get out of current document context
if (dispidMember == DISPID_BEFORENAVIGATE) { _DetachProxies(); }
return S_OK; }
LRESULT CMediaBand::_OnVolumeCustomDraw(LPNMCUSTOMDRAW pnm) { RECT rcClient; GetClientRect(pnm->hdr.hwndFrom, &rcClient);
switch (pnm->dwDrawStage) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW;
case CDDS_PREERASE: return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: { HDC hdc = (HDC)pnm->hdc; RECT rcFill; SendMessage(pnm->hdr.hwndFrom, TBM_GETCHANNELRECT, (WPARAM)0, (LPARAM)(LPRECT)&rcFill); RECT rcThumb; SendMessage(pnm->hdr.hwndFrom, TBM_GETTHUMBRECT, 0L, (LPARAM)&rcThumb);
SHFillRectClr(hdc, &rcClient, _fHiColour ? COLOR_BKGND : COLOR_BKGND16); UINT uFlags = ILD_TRANSPARENT | (IsOS(OS_WHISTLERORGREATER) ? ILD_DPISCALE : 0); if (_himlVolumeBack) { ImageList_Draw(_himlVolumeBack, 0, hdc, rcClient.left, rcClient.top, uFlags); } if (_himlVolumeFill) { ImageList_DrawEx(_himlVolumeFill, 0, hdc, rcClient.left, rcClient.top, rcThumb.left, SEEK_HEIGHT, 0, 0, uFlags); } if (_himlGripper) { ImageList_Draw(_himlGripper, 0, hdc, rcThumb.left, 0, uFlags); } } return CDRF_SKIPDEFAULT; } return CDRF_DODEFAULT; }
LRESULT CMediaBand::_OnSeekBarCustomDraw(LPNMCUSTOMDRAW pnm) { RECT rcClient; GetClientRect(pnm->hdr.hwndFrom, &rcClient);
switch (pnm->dwDrawStage) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW;
case CDDS_PREERASE: return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: { HDC hdc = (HDC)pnm->hdc;
SHFillRectClr(hdc, &rcClient, _fHiColour ? COLOR_BKGND2 : COLOR_BKGND16);
RECT rcFill; SendMessage(pnm->hdr.hwndFrom, TBM_GETCHANNELRECT, (WPARAM)0, (LPARAM)(LPRECT)&rcFill); RECT rcThumb; SendMessage(pnm->hdr.hwndFrom, TBM_GETTHUMBRECT, 0L, (LPARAM)&rcThumb); int x, y = 1+(SEEK_HEIGHT-SEEK_PART_HEIGHT)/2; UINT uFlags = ILD_TRANSPARENT | (IsOS(OS_WHISTLERORGREATER) ? ILD_DPISCALE : 0);
// always draw background with progress
if (_himlSeekBack) { INT lPartWidth = SCALEX(SEEK_PART_WIDTH); x = rcFill.left; ImageList_Draw(_himlSeekBack, 0, hdc, x, y, uFlags); x = rcFill.right - lPartWidth; int inx = rcFill.left + lPartWidth; while (inx < x) { ImageList_Draw(_himlSeekBack, 1, hdc, inx, y, uFlags); inx += lPartWidth; } ImageList_Draw(_himlSeekBack, 2, hdc, x, y, uFlags); }
if (pnm->dwItemSpec==TBCD_THUMB) {
if ((!(pnm->uItemState & CDIS_DISABLED)) && ISVALIDWIDGET(_pmwSeek) && _pmwSeek->IsEnabled()) {
x = rcFill.left; int seekWidth = rcThumb.left-x; if (_himlSeekFill && seekWidth) { if (seekWidth < SEEK_PART_WIDTH) { ImageList_DrawEx(_himlSeekFill, 0, hdc, x, y, seekWidth, SEEK_PART_HEIGHT, 0, 0, uFlags); } else { ImageList_Draw(_himlSeekFill, 0, hdc, x, y, uFlags); x += SEEK_PART_WIDTH; while ((rcThumb.left-x)>0) { ImageList_DrawEx(_himlSeekFill, 1, hdc, x, y, min(SEEK_PART_WIDTH, (rcThumb.left-x)), SEEK_PART_HEIGHT, 0, 0, uFlags); x += SEEK_PART_WIDTH; } } }
INT iState = MWB_NORMAL; if (pnm->uItemState & CDIS_SELECTED) { iState = MWB_PRESSED; } else if (pnm->uItemState & CDIS_HOT) { iState = MWB_HOT; } if (_himlGripper) { ImageList_Draw(_himlGripper, iState, hdc, rcThumb.left, 0, uFlags); } } } } return CDRF_SKIPDEFAULT; } return CDRF_DODEFAULT; }
LONG CMediaBand::GetPopoutHeight(BOOL fMeasureVideo, LONG lWidth) { LONG lHeight = (fMeasureVideo ? GetLayoutHeight(lWidth) : GetControlsHeight()) + GetSystemMetrics(SM_CYSIZE) + GetSystemMetrics(SM_CYEDGE)*2 + GetSystemMetrics(SM_CYSIZEFRAME)*2; return lHeight; }
LONG CMediaBand::GetMinPopoutWidth() { return MIN_POPOUT_WIDTH + (GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME))*2; }
BOOL CMediaBand::ResetPlayer() { _iCurTrack = -1; _fPlaying = FALSE; if (ISVALIDWIDGET(_pmwSeek)) { _pmwSeek->SetState(FALSE); } if (_pMediaPlayer) { _pMediaPlayer->Stop(); SetSeekPos(0.0); TogglePlayPause(); if (_hwndVideo && IsWindowVisible(_hwndVideo)) { _fIsVideo = FALSE; ShowWindow(_hwndVideo, SW_HIDE); } AdjustVideoHeight(TRUE); } TCHAR szTitle[MAX_PATH]; MLLoadStringW(IDS_MEDIABAND_MYMUSIC, szTitle, ARRAYSIZE(szTitle)); SetStatusText(szTitle); SetPlayerControl(FCIDM_MEDIABAND_PREVIOUS, FALSE); SetPlayerControl(FCIDM_MEDIABAND_NEXT, FALSE); // while timer is running , give user a second chance to click stop again and reset media content pane
if (_idStopTimer == 0) { SetPlayerControl(FCIDM_MEDIABAND_STOP, FALSE); } SetPlayPause(TRUE); return TRUE; }
HRESULT CMediaBand::PlayLocalTrack(int iTrackNum) { HRESULT hr = E_FAIL;
if (_ppidls && (iTrackNum < (int)_cidls)) { // to avoid pot. privacy leak, unload mediabar behavior
if (_IsProxyRunning()) { // user clicked on a media link in the main content pane, unfreeze controls!
_OnUserOverrideDisableUI(); _DetachProxies(); _NavigateContentToDefaultURL(); }
TCHAR szFile[MAX_PATH]; if (SUCCEEDED(SHGetNameAndFlags(_ppidls[iTrackNum], SHGDN_FORPARSING, szFile, ARRAYSIZE(szFile), NULL))) { _iCurTrack = iTrackNum;
if (EnsurePlayer()) _PutUrl(szFile, NULL); hr = S_OK; } } return hr; }
HRESULT CMediaBand::PlayNextTrack() { if (EnsurePlayer() && (_iCurTrack != -1)) { LONG_PTR lCurTrack = _pMediaPlayer->GetPlayListItemIndex(); LONG_PTR lItemCount = _pMediaPlayer->GetPlayListItemCount(); if ((lItemCount <= 1) || (lCurTrack == lItemCount - 1)) { PlayLocalTrack(_iCurTrack + 1); } else { ResetPlayer(); } } return S_OK; }
BOOL CMediaBand::SetPlayerControl(UINT ui, BOOL fState) { CMediaWidget* pmw = NULL;
switch (ui) { case FCIDM_MEDIABAND_PREVIOUS: // while UI frozen by mediabar behavior, previous is always disabled
if (fState && _pMediaPlayer) { fState = _pMediaPlayer->IsSkippable(); } if (_isUIDisabled()) { fState = FALSE; // override to always disable
} pmw = _pmwBack; break;
case FCIDM_MEDIABAND_NEXT: // only override if any of the proxies are running
if (fState && _pMediaPlayer) { fState = _pMediaPlayer->IsSkippable(); } if (_apContentProxies != NULL) { if (_isUIDisabled() && _pMediaPlayer && !_pMediaPlayer->IsSeekPossible()) { fState = FALSE; } // only force a disabled next button if stream has NOSKIP attribute set
if (!_isProxiesNextEnabled()) { fState = FALSE; } } pmw = _pmwNext; break;
case FCIDM_MEDIABAND_STOP: pmw = _pmwStop; break;
default: ASSERT(FALSE); break; } if (pmw && pmw->_hwnd) { SendMessage(pmw->_hwnd, TB_ENABLEBUTTON, ui, MAKELONG(fState, 0)); } return TRUE; }
BOOL CMediaBand::UpdateBackForwardControls() { BOOL fPrevious = FALSE, fNext = FALSE; if (_iCurTrack != -1) { fPrevious = _iCurTrack != 0; fNext = ((_iCurTrack + 1) < (int)_cidls); } else if (EnsurePlayer()) { LONG_PTR lItemCount= _pMediaPlayer->GetPlayListItemCount(); if (lItemCount > 1) { LONG_PTR lCurTrack = _pMediaPlayer->GetPlayListItemIndex(); fPrevious = (lCurTrack > 0); fNext = lCurTrack < lItemCount - 1; } } SetPlayerControl(FCIDM_MEDIABAND_PREVIOUS, fPrevious); SetPlayerControl(FCIDM_MEDIABAND_NEXT, fNext); return TRUE; }
HRESULT CMediaBand::Seek(double dblProgress) { HRESULT hr = S_OK; if (EnsurePlayer()) { hr = _pMediaPlayer->Seek(dblProgress); if (SUCCEEDED(hr)) { // play/pause state may have been changed by Seek
TogglePlayPause(); } } return hr; }
LPTSTR CMediaBand::GetUrlForStatusBarToolTip() { USES_CONVERSION;
LPTSTR szRet = NULL;
if (_pMediaPlayer) { if (_pMediaPlayer->isStopped()) { return _pszStatus; }
CComBSTR sbstrUrl;
HRESULT hr = _pMediaPlayer->get_url(&sbstrUrl); if ( SUCCEEDED(hr) && (sbstrUrl.m_str) && (sbstrUrl.Length()>0)) { szRet = W2T(sbstrUrl); if (szRet) { //
// The tooltip structure (NMTTDISPINFO.lpszText) requires a pointer to a private buffer.
// Store the pointer so we can free it later.
//
int len = lstrlen(szRet);
delete [] _szToolTipUrl;
_szToolTipUrl = new TCHAR[len + 1];
if (_szToolTipUrl) { memcpy(_szToolTipUrl, szRet, sizeof(TCHAR) * (len + 1)); }
szRet = _szToolTipUrl; } } }
return szRet; }
VOID CMediaBand::UpdateMenuItems(HMENU hmenu) { ASSERT(hmenu); CComBSTR sbstrUrl; if (GetAutoplay()) { CheckMenuItem(hmenu, IDM_MEDIA_PLAYINBAR, MF_BYCOMMAND | MF_CHECKED); }
if (GetAutoplayPrompt()) { CheckMenuItem(hmenu, IDM_MEDIA_ASKTYPES, MF_BYCOMMAND | MF_CHECKED); }
if (!_pMediaPlayer || _pMediaPlayer->isStopped() || FAILED(_pMediaPlayer->get_url(&sbstrUrl)) || !sbstrUrl.m_str || (sbstrUrl.Length()<=0) || _isUIDisabled()) { DeleteMenu(hmenu, IDM_MEDIA_PLAYINDEFAULT, MF_BYCOMMAND); DeleteMenu(hmenu, IDM_MEDIA_ADDTOFAVORITES, MF_BYCOMMAND); DeleteMenu(hmenu, 0, MF_BYPOSITION); } }
BOOL CMediaBand::OnNotify(LPNMHDR pnm, LRESULT* plres) { ASSERT(plres); BOOL fRet = FALSE;
switch (pnm->code) { case NM_CUSTOMDRAW: { LRESULT lres; LPNMCUSTOMDRAW pnmc = (LPNMCUSTOMDRAW)pnm; if (pnm->hwndFrom == _hwndVolume) { lres = _OnVolumeCustomDraw(pnmc); } else if (pnm->hwndFrom == _hwndSeek) { lres = _OnSeekBarCustomDraw(pnmc); } else { for (int i=0; i<ARRAYSIZE(_pmw); i++) { if (_pmw[i] && (pnm->hwndFrom == _pmw[i]->_hwnd)) { lres = _pmw[i]->Draw((LPNMTBCUSTOMDRAW)pnm); } } } fRet = TRUE; *plres = lres; } break; case TBN_DROPDOWN: { LPNMTOOLBAR lpnmTB = ((LPNMTOOLBAR)pnm); HWND hwndTB = pnm->hwndFrom; UINT nCmdID = lpnmTB->iItem;
// figure out coordinates to use
INT_PTR iBtn = SendMessage(hwndTB, TB_GETHOTITEM, 0, 0);
RECTL rc ; SendMessage(hwndTB, TB_GETITEMRECT, iBtn, (LPARAM)&rc); MapWindowPoints(hwndTB, HWND_DESKTOP, (LPPOINT)&rc , 2);
if (_pmwOptions && hwndTB==_pmwOptions->_hwnd) { if (_pMediaPlayer && (_pMediaPlayer->GetPlayListItemCount() > 0) && !_pMediaPlayer->isStopped() && !_isUIDisabled() && _pMediaPlayer->IsSkippable()) { ShowPlayListMenu(hwndTB, &rc); } else { ShowGenericMenu(hwndTB, &rc); } } else { VARIANTARG var; var.vt = VT_I4; var.lVal = MAKELONG(rc.left, rc.bottom); *plres = Exec(&CLSID_MediaBand, nCmdID, 0, &var, NULL); fRet = TRUE; } // end of else
} break; case TBN_GETDISPINFO: { LPNMTBDISPINFO lptbi = (LPNMTBDISPINFO)pnm;
if (lptbi->hdr.hwndFrom == _pmwPlay->_hwnd && lptbi->dwMask & TBNF_IMAGE) { TBBUTTONINFO tbbi; tbbi.dwMask = TBIF_COMMAND | TBIF_STATE; SendMessage(lptbi->hdr.hwndFrom, TB_GETBUTTONINFO, (WPARAM)lptbi->idCommand, (LPARAM)&tbbi);
if (_fPlayButton) lptbi->iImage = (!(tbbi.fsState & TBSTATE_INDETERMINATE) && (tbbi.fsState & TBSTATE_PRESSED)) ? 3 : 1 ; else lptbi->iImage = (!(tbbi.fsState & TBSTATE_INDETERMINATE) && (tbbi.fsState & TBSTATE_PRESSED)) ? 2 : 0 ;
lptbi->dwMask |= TBNF_DI_SETITEM; } else if (_pmwOptions && (lptbi->hdr.hwndFrom ==_pmwOptions->_hwnd)) { lptbi->iImage = 0; lptbi->dwMask |= TBNF_DI_SETITEM; } } break;
case TTN_GETDISPINFO: { LPNMTTDISPINFO pnmtt = (LPNMTTDISPINFO)pnm; pnmtt->hinst = MLGetHinst();
switch (pnmtt->hdr.idFrom) { case FCIDM_MEDIABAND_POPOUT: pnmtt->lpszText = (PTSTR)MAKEINTRESOURCE(_hwndPopup ? IDS_MEDIABAND_DOCK : IDS_MEDIABAND_UNDOCK); break;
case FCIDM_MEDIABAND_PLAY: pnmtt->lpszText = (PTSTR)MAKEINTRESOURCE(_fPlayButton ? IDS_MEDIABAND_PLAY : IDS_MEDIABAND_PAUSE); break; case FCIDM_MEDIABAND_MUTE: pnmtt->lpszText = (PTSTR)MAKEINTRESOURCE(_fMuted ? IDS_MEDIABAND_UNMUTE : IDS_MEDIABAND_MUTE); break;
case FCIDM_MEDIABAND_PLAYINFO: { if (_pMediaPlayer && !_isUIDisabled()) { LPTSTR szUrl = GetUrlForStatusBarToolTip(); if (szUrl) { pnmtt->lpszText = szUrl; } } break; } } } }
return fRet; }
HRESULT CMediaBand::_OpenInDefaultPlayer(BSTR bstrUrl) { HRESULT hr = E_FAIL;
if ( !bstrUrl || !(*bstrUrl)) { hr = E_FAIL; goto done; }
// suppress first autoplay and navigate main IE window
hr = _NavigateMainWindow(bstrUrl, true); if (FAILED(hr)) { goto done; }
if (_hwndPopup && IsWindowVisible(_hwndPopup)) { DockMediaPlayer(); } // pause/stop the playback
if (_pMediaPlayer->IsPausePossible()) { _pMediaPlayer->Pause(); } else { _pMediaPlayer->Stop(); }
hr = S_OK; done: return hr; }
VOID CMediaBand::SetPlayPause(BOOL fState) { _fPlayEnabled = fState; if (_pmwPlay && _pmwPlay->_hwnd) { SendMessage(_pmwPlay->_hwnd, TB_SETSTATE, FCIDM_MEDIABAND_PLAY, MAKELONG((_fPlayEnabled ? TBSTATE_ENABLED : 0), 0)); InvalidateRect(_pmwPlay->_hwnd, NULL, FALSE); UpdateWindow(_pmwPlay->_hwnd); } }
INT idNormalHi[MW_NUMBER] = { IDB_MEDIABAND_PLAY, // MW_PLAY = 0,
IDB_MEDIABAND_STOP, // MW_STOP,
IDB_MEDIABAND_BACK, // MW_BACK,
IDB_MEDIABAND_NEXT, // MW_NEXT,
IDB_MEDIABAND_MUTE, // MW_MUTE,
IDB_MEDIABAND_VOLBKGND, // MW_VOLUME,
0, // MW_OPTIONS,
IDB_MEDIABAND_POPOUT, // MW_POP,
IDB_MEDIABAND_SEEKBACK, // MW_SEEK,
};
INT idAltHi[MW_NUMBER] = { IDB_MEDIABAND_PAUSE, // MW_PLAY = 0,
0, // MW_STOP,
0, // MW_BACK,
0, // MW_NEXT,
0, // MW_MUTE,
IDB_MEDIABAND_VOLFILL, // MW_VOLUME,
0, // MW_OPTIONS,
IDB_MEDIABAND_POPIN, // MW_POP,
IDB_MEDIABAND_SEEKFILL, // MW_SEEK,
};
INT idNormalLo[MW_NUMBER] = { IDB_MEDIABAND_PLAY16, // MW_PLAY = 0,
IDB_MEDIABAND_STOP16, // MW_STOP,
IDB_MEDIABAND_BACK16, // MW_BACK,
IDB_MEDIABAND_NEXT16, // MW_NEXT,
IDB_MEDIABAND_MUTE16, // MW_MUTE,
IDB_MEDIABAND_VOLBKGND16, // MW_VOLUME,
0, // MW_OPTIONS,
IDB_MEDIABAND_POPOUT16, // MW_POP,
IDB_MEDIABAND_SEEKBACK16, // MW_SEEK,
};
INT idAltLo[MW_NUMBER] = { IDB_MEDIABAND_PAUSE16, // MW_PLAY = 0,
0, // MW_STOP,
0, // MW_BACK,
0, // MW_NEXT,
0, // MW_MUTE,
IDB_MEDIABAND_VOLFILL16, // MW_VOLUME,
0, // MW_OPTIONS,
IDB_MEDIABAND_POPIN16, // MW_POP,
IDB_MEDIABAND_SEEKFILL16, // MW_SEEK,
};
VOID CMediaBand::SwitchBitmaps(BOOL fNewSetting) { INT* idAlt = fNewSetting ? idAltHi : idAltLo; INT* idNormal = fNewSetting ? idNormalHi : idNormalLo;
for (int i=0; i<MW_NUMBER; i++) { if (ISVALIDWIDGET(_pmw[i])) { switch (i) { case MW_SEEK: DESTROY_OBJ_WITH_HANDLE(_himlSeekBack, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlSeekFill, ImageList_Destroy); _himlSeekBack = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(idNormal[i]), SEEK_PART_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlSeekFill = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(idAlt[i]), SEEK_PART_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION);
break;
case MW_OPTIONS: { CMediaWidgetOptions* pmwb = (CMediaWidgetOptions*)_pmw[i]; pmwb->SetDepth(fNewSetting); } break;
case MW_VOLUME: DESTROY_OBJ_WITH_HANDLE(_himlVolumeBack, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlVolumeFill, ImageList_Destroy); DESTROY_OBJ_WITH_HANDLE(_himlGripper, ImageList_Destroy); _himlVolumeBack = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(idNormal[i]), VOLUME_BITMAP_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlVolumeFill = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(idAlt[i]), VOLUME_BITMAP_WIDTH, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); _himlGripper = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(fNewSetting ? IDB_MEDIABAND_VOLTAB : IDB_MEDIABAND_VOLTAB16), 6, 0, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION); break;
default: // The rest are buttons
{ CMediaWidgetButton* pmwb = (CMediaWidgetButton*)_pmw[i]; pmwb->SetImageList(idNormal[i]); if (idAlt[i]) { pmwb->SetAlternateImageList(idAlt[i]); } } break; } } }
_fHiColour = fNewSetting; InvalidateRect(_hwnd, NULL, TRUE); UpdateWindow(_hwnd); }
VOID CMediaBand::InitContentPane() { SHDRC shdrc = {sizeof(SHDRC), SHDRCF_OCHOST}; shdrc.cbSize = sizeof (SHDRC); shdrc.dwFlags |= SHDRCF_OCHOST; if (_hwnd && IsWindow(_hwnd) && DllRegisterWindowClasses(&shdrc)) { // Create an OCHost window
_hwndContent = CreateWindow(OCHOST_CLASS, NULL, WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_TABSTOP, 0, 0, 0, 0, _hwnd, NULL, HINST_THISDLL, NULL); if (_hwndContent) { OCHINITSTRUCT ocs; ocs.cbSize = SIZEOF(OCHINITSTRUCT); ocs.clsidOC = CLSID_WebBrowser; ocs.punkOwner = SAFECAST(this, IDispatch*); if (SUCCEEDED(OCHost_InitOC(_hwndContent, (LPARAM)&ocs))) { OCHost_QueryInterface(_hwndContent, IID_PPV_ARG(IWebBrowser2, &_spBrowser)); OCHost_QueryInterface(_hwndContent, IID_PPV_ARG(IOleInPlaceActiveObject, &_poipao)); OCHost_DoVerb(_hwndContent, OLEIVERB_INPLACEACTIVATE, FALSE); _ConnectToCP(TRUE); } _NavigateContentToDefaultURL(); } } }
HRESULT CMediaBand::_ConnectToCP(BOOL fConnect) { // get ready to sink the OCHost's browser events
if (!_spBrowser) { return E_FAIL; } if (!fConnect && (_dwcpCookie == 0)) { return S_FALSE; //
} return ConnectToConnectionPoint(SAFECAST(this, IDispatch*), DIID_DWebBrowserEvents2, fConnect, _spBrowser, &_dwcpCookie, NULL); }
HRESULT CMediaBand::NavigateContentPane(BSTR bstrUrl) { HRESULT hr = E_FAIL; if (_spBrowser && bstrUrl) { _strCurrentContentUrl = bstrUrl;
CComVariant svarEmpty; svarEmpty.vt = VT_NULL; hr = _spBrowser->Navigate(bstrUrl, &svarEmpty, &svarEmpty, &svarEmpty, &svarEmpty); } return hr; }
HRESULT CMediaBand::NavigateContentPane(LPCITEMIDLIST pidl) { HRESULT hr = E_FAIL; if (_spBrowser && pidl) { TCHAR szURL[MAX_URL_STRING];
if (SUCCEEDED(::IEGetDisplayName(pidl, szURL, SHGDN_FORPARSING))) { _strCurrentContentUrl = szURL; } else { _strCurrentContentUrl.Empty(); }
CComVariant svarEmpty; svarEmpty.vt = VT_NULL; CComVariant varURL; InitVariantFromIDList(&varURL, pidl);
hr = _spBrowser->Navigate2(&varURL, &svarEmpty, &svarEmpty, &svarEmpty, &svarEmpty); } return hr; }
VOID CMediaBand::NavigateMoreMedia() { _NavigateMainWindow(c_szMoreMediaUrl); }
HRESULT CMediaBand::_NavigateContentToDefaultURL() { TCHAR szResURL[2*MAX_URL_STRING]; // expect URL to help page and original URL
HRESULT hr; LPCTSTR pszStartURL = NULL; // load inital page, this is always a local resource
BOOL fSuppressOnline = SHRegGetBoolUSValue(REG_MEDIA_STR, TEXT("SuppressOnlineContent"), FALSE, FALSE); BOOL fStayOffline = SHIsGlobalOffline() || fSuppressOnline || SHRestricted2W(REST_No_MediaBarOnlineContent, NULL, 0); // ISSUE/010426/davidjen with the restriction set,
// do we need a second offline page without external links, only MyMusic???????????????
if (fStayOffline) { pszStartURL = c_szOfflineURL; } else { pszStartURL = c_szLoadingURL; } hr = _BuildPageURLWithParam(pszStartURL, NULL, szResURL, ARRAYSIZE(szResURL)); if (FAILED(hr)) { StrCpyN(szResURL, c_szOfflineURL, ARRAYSIZE(szResURL)); hr = S_OK; } NavigateContentPane(szResURL); // if online, try navigating to windowsmedia.com
if (!fStayOffline) { _DeferredNavigate(c_szContentUrl); } return S_OK; }
HRESULT CMediaBand::_BuildPageURLWithParam(LPCTSTR pszURL, LPCTSTR pszParam, OUT LPTSTR pszBuffer, UINT uiBufSize) { USES_CONVERSION; // build a string of the form: "res://d:\winnt\system32\browselc.dll\helppage.htm#http://www.windowsmedia.com/xyz.html"
HRESULT hr = S_OK;
ASSERT(pszBuffer); hr = MLBuildResURLWrap(TEXT("browselc.dll"), HINST_THISDLL, ML_CROSSCODEPAGE, T2W((LPTSTR)pszURL), pszBuffer, uiBufSize, TEXT("browseui.dll")); if (SUCCEEDED(hr) && pszParam && (lstrlen(pszParam) > 0)) { StrCatBuff(pszBuffer, TEXT("#"), uiBufSize); StrCatBuff(pszBuffer, pszParam, uiBufSize); }
return hr; }
BOOL CMediaBand::_DeferredNavigate(LPCTSTR pszURL) { ASSERT(_strDeferredURL.Length() == 0); _strDeferredURL = pszURL; return PostMessage(_hwnd, WM_MB_DEFERRED_NAVIGATE, 0, (LPARAM) _hwnd); }
|