463 lines
9.7 KiB
C++
463 lines
9.7 KiB
C++
#include "shellprv.h"
|
|
#include "apithk.h"
|
|
#include "basebar.h"
|
|
|
|
#define DBM_ONPOSRECTCHANGE (WM_USER)
|
|
|
|
|
|
//*** CBaseBar::IDeskBar::* {
|
|
//
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IDeskBar::SetClient
|
|
|
|
Usually the function that composes a bar/bandsite/band
|
|
union is responsible for calling this method to inform
|
|
the bar what the client (bandsite) is.
|
|
|
|
*/
|
|
HRESULT CBaseBar::SetClient(IUnknown *punkChild)
|
|
{
|
|
if (_punkChild != NULL)
|
|
{
|
|
// 4, 3, 2, 1 Release
|
|
_hwndChild = NULL;
|
|
|
|
if (_pDBC)
|
|
{
|
|
// This must happen first, before _pWEH becomes NULL so cleanup
|
|
// notifications can still go thru
|
|
_pDBC->SetDeskBarSite(NULL);
|
|
}
|
|
|
|
ATOMICRELEASE(_pDBC);
|
|
|
|
ATOMICRELEASE(_pWEH);
|
|
|
|
ATOMICRELEASE(_punkChild);
|
|
}
|
|
|
|
_punkChild = punkChild;
|
|
|
|
HRESULT hr = S_OK;
|
|
if (_punkChild != NULL)
|
|
{
|
|
// 1, 2, 3, 4 QI/AddRef/etc.
|
|
_punkChild->AddRef();
|
|
if (!_hwnd)
|
|
{
|
|
_RegisterDeskBarClass();
|
|
_CreateDeskBarWindow();
|
|
if (!_hwnd)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// can't do CBaseBar::_Initialize yet (haven't done SetSite yet)
|
|
}
|
|
|
|
hr = _punkChild->QueryInterface(IID_PPV_ARG(IWinEventHandler, &_pWEH));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _punkChild->QueryInterface(IID_PPV_ARG(IDeskBarClient, &_pDBC));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// nothing to cache yet due to lazy CreateWindow
|
|
hr = _pDBC->SetDeskBarSite(SAFECAST(this, IDeskBar*));
|
|
|
|
IUnknown_GetWindow(_punkChild, &_hwndChild);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CBaseBar::GetClient(IUnknown **ppunk)
|
|
{
|
|
*ppunk = _punkChild;
|
|
if (_punkChild)
|
|
_punkChild->AddRef();
|
|
return _punkChild ? S_OK : E_FAIL;
|
|
}
|
|
|
|
HRESULT CBaseBar::OnPosRectChangeDB(LPRECT prc)
|
|
{
|
|
_szChild.cx = RECTWIDTH(*prc);
|
|
_szChild.cy = RECTHEIGHT(*prc);
|
|
|
|
// We can't change our size right away because we haven't returned from processing
|
|
// this WM_SIZE message. If we resize right now, USER gets confused...
|
|
//
|
|
// We cannot use PeekMessage to determine if there is already a pending
|
|
// DBM_ONPOSRECTCHANGE because that allows incoming SendMessage's to
|
|
// arrive, and then we can get into a bad recursive situation when there
|
|
// are a lot of SHChangeNotify's arriving in rapid succession.
|
|
//
|
|
if (!_fPosRectChangePending)
|
|
{
|
|
_fPosRectChangePending = TRUE;
|
|
PostMessage(_hwnd, DBM_ONPOSRECTCHANGE, 0, 0);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// Derived classes are expected to implement this method and do something
|
|
// interesting...
|
|
void CBaseBar::_OnPostedPosRectChange()
|
|
{
|
|
}
|
|
|
|
// }
|
|
|
|
HRESULT CBaseBar::ShowDW(BOOL fShow)
|
|
{
|
|
fShow = BOOLIFY(fShow);
|
|
|
|
if (BOOLIFY(_fShow) == fShow)
|
|
return S_OK;
|
|
|
|
_fShow = fShow;
|
|
|
|
if (_pDBC)
|
|
return _pDBC->UIActivateDBC(fShow ? DBC_SHOW : DBC_HIDE);
|
|
else
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
void CBaseBar::_OnCreate()
|
|
{
|
|
SendMessage(_hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0);
|
|
}
|
|
|
|
LRESULT CBaseBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT lres = 0;
|
|
|
|
_CheckForwardWinEvent(uMsg, wParam, lParam, &lres);
|
|
|
|
return lres;
|
|
}
|
|
|
|
|
|
/***
|
|
*/
|
|
LRESULT CBaseBar::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT lres = 0;
|
|
|
|
switch (uMsg) {
|
|
case WM_CREATE:
|
|
_OnCreate();
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
return _OnCommand(uMsg, wParam, lParam);
|
|
|
|
|
|
case WM_SIZE:
|
|
_OnSize();
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
return _OnNotify(uMsg, wParam, lParam);
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
case WM_WININICHANGE:
|
|
case WM_CONTEXTMENU:
|
|
case WM_INITMENUPOPUP:
|
|
case WM_MEASUREITEM:
|
|
case WM_DRAWITEM:
|
|
case WM_MENUCHAR:
|
|
case WM_PALETTECHANGED:
|
|
_CheckForwardWinEvent(uMsg, wParam, lParam, &lres);
|
|
break;
|
|
|
|
case DBM_ONPOSRECTCHANGE:
|
|
_fPosRectChangePending = FALSE;
|
|
_OnPostedPosRectChange();
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProcWrap(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return lres;
|
|
}
|
|
|
|
/***
|
|
*/
|
|
CBaseBar::CBaseBar() : _cRef(1)
|
|
{
|
|
DllAddRef();
|
|
}
|
|
|
|
/***
|
|
*/
|
|
CBaseBar::~CBaseBar()
|
|
{
|
|
// see Release, where we call virtuals (which can't be called from dtor)
|
|
DllRelease();
|
|
}
|
|
|
|
/***
|
|
*/
|
|
void CBaseBar::_RegisterDeskBarClass()
|
|
{
|
|
WNDCLASS wc = {0};
|
|
wc.style = _GetClassStyle();
|
|
wc.lpfnWndProc = s_WndProc;
|
|
//wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = SIZEOF(CBaseBar*);
|
|
wc.hInstance = HINST_THISDLL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH) (COLOR_3DFACE+1);
|
|
//wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = TEXT("BaseBar");
|
|
//wc.hIcon = NULL;
|
|
|
|
SHRegisterClass(&wc);
|
|
}
|
|
|
|
DWORD CBaseBar::_GetExStyle()
|
|
{
|
|
return WS_EX_TOOLWINDOW;
|
|
}
|
|
|
|
DWORD CBaseBar::_GetClassStyle()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void CBaseBar::_CreateDeskBarWindow()
|
|
{
|
|
// _hwnd is set in s_WndProc
|
|
DWORD dwExStyle = _GetExStyle();
|
|
dwExStyle |= IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd : 0L;
|
|
HWND hwndDummy = CreateWindowEx(
|
|
dwExStyle,
|
|
TEXT("BaseBar"), NULL,
|
|
_hwndSite ? WS_CHILD | WS_CLIPCHILDREN : WS_POPUP | WS_CLIPCHILDREN,
|
|
0,0,100,100,
|
|
_hwndSite, NULL, HINST_THISDLL,
|
|
(LPVOID)SAFECAST(this, CImpWndProc*));
|
|
}
|
|
|
|
|
|
void CBaseBar::_OnSize(void)
|
|
{
|
|
RECT rc;
|
|
|
|
if (!_hwndChild)
|
|
return;
|
|
|
|
GetClientRect(_hwnd, &rc);
|
|
SetWindowPos(_hwndChild, 0,
|
|
rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc),
|
|
SWP_NOACTIVATE|SWP_NOZORDER);
|
|
}
|
|
|
|
void CBaseBar::_NotifyModeChange(DWORD dwMode)
|
|
{
|
|
if (_pDBC) {
|
|
_dwMode = dwMode;
|
|
// FEATURE: should we add an STBBIF_VIEWMODE_FLOAT?
|
|
_pDBC->SetModeDBC(_dwMode);
|
|
}
|
|
}
|
|
|
|
BOOL CBaseBar::_CheckForwardWinEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
|
|
{
|
|
HWND hwnd = NULL;
|
|
|
|
*plres = 0;
|
|
switch (uMsg)
|
|
{
|
|
case WM_CONTEXTMENU:
|
|
case WM_INITMENUPOPUP:
|
|
case WM_MEASUREITEM:
|
|
case WM_DRAWITEM:
|
|
case WM_MENUCHAR:
|
|
hwnd = _hwndChild;
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
hwnd = ((LPNMHDR)lParam)->hwndFrom;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
case WM_WININICHANGE:
|
|
case WM_PALETTECHANGED:
|
|
hwnd = _hwndChild;
|
|
break;
|
|
}
|
|
|
|
if (hwnd && _pWEH && _pWEH->IsWindowOwner(hwnd) == S_OK)
|
|
{
|
|
_pWEH->OnWinEvent(_hwnd, uMsg, wParam, lParam, plres);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***
|
|
*/
|
|
LRESULT CBaseBar::_OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT lres = 0;
|
|
|
|
_CheckForwardWinEvent(uMsg, wParam, lParam, &lres);
|
|
|
|
return lres;
|
|
}
|
|
|
|
HRESULT CBaseBar::CloseDW(DWORD dwReserved)
|
|
{
|
|
SetClient(NULL);
|
|
if (_hwnd) {
|
|
DestroyWindow(_hwnd);
|
|
_hwnd = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CBaseBar::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(CBaseBar, IOleWindow),
|
|
QITABENT(CBaseBar, IDeskBar),
|
|
QITABENT(CBaseBar, IInputObject),
|
|
QITABENT(CBaseBar, IInputObjectSite),
|
|
QITABENT(CBaseBar, IServiceProvider),
|
|
QITABENT(CBaseBar, IOleCommandTarget),
|
|
{ 0 },
|
|
};
|
|
|
|
return QISearch(this, (LPCQITAB)qit, riid, ppvObj);
|
|
}
|
|
|
|
|
|
ULONG CBaseBar::AddRef()
|
|
{
|
|
_cRef++;
|
|
return _cRef;
|
|
}
|
|
|
|
ULONG CBaseBar::Release()
|
|
{
|
|
ASSERT(_cRef > 0);
|
|
_cRef--;
|
|
|
|
if (_cRef > 0)
|
|
return _cRef;
|
|
|
|
// 'virtual dtor'
|
|
// gotta do virtual stuff here (not in dtor) because can't call
|
|
// any virtuals in the dtor
|
|
// CBaseBar::Destroy() {
|
|
CloseDW(0);
|
|
// }
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
//*** CBaseBar::IOleWindow::* {
|
|
//
|
|
|
|
HRESULT CBaseBar::GetWindow(HWND * lphwnd)
|
|
{
|
|
*lphwnd = _hwnd;
|
|
return (_hwnd) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
HRESULT CBaseBar::ContextSensitiveHelp(BOOL fEnterMode)
|
|
{
|
|
// FEATURE: Visit here later.
|
|
return E_NOTIMPL;
|
|
}
|
|
// }
|
|
|
|
|
|
// }
|
|
// some helpers... {
|
|
|
|
// What's the point of having
|
|
// these empty implementations in the base class?
|
|
//
|
|
|
|
//*** CBaseBar::IServiceProvider::*
|
|
//
|
|
HRESULT CBaseBar::QueryService(REFGUID guidService,
|
|
REFIID riid, void **ppvObj)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
*ppvObj = NULL;
|
|
|
|
return hres;
|
|
}
|
|
|
|
//*** CBaseBar::IOleCommandTarget::*
|
|
//
|
|
HRESULT CBaseBar::QueryStatus(const GUID *pguidCmdGroup,
|
|
ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
|
|
{
|
|
return MayQSForward(_pDBC, OCTD_DOWN, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
|
|
}
|
|
|
|
HRESULT CBaseBar::Exec(const GUID *pguidCmdGroup,
|
|
DWORD nCmdID, DWORD nCmdexecopt,
|
|
VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
|
|
{
|
|
return MayExecForward(_pDBC, OCTD_DOWN, pguidCmdGroup, nCmdID, nCmdexecopt,
|
|
pvarargIn, pvarargOut);
|
|
}
|
|
|
|
// }
|
|
|
|
|
|
//*** CDeskBar::IInputObject::* {
|
|
|
|
HRESULT CBaseBar::HasFocusIO()
|
|
{
|
|
HRESULT hres;
|
|
|
|
hres = IUnknown_HasFocusIO(_pDBC);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CBaseBar::TranslateAcceleratorIO(LPMSG lpMsg)
|
|
{
|
|
HRESULT hres;
|
|
|
|
hres = IUnknown_TranslateAcceleratorIO(_pDBC, lpMsg);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CBaseBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
|
|
{
|
|
HRESULT hres;
|
|
|
|
hres = IUnknown_UIActivateIO(_pDBC, fActivate, lpMsg);
|
|
return hres;
|
|
}
|
|
|
|
// }
|
|
|
|
//*** CDeskBar::IInputObjectSite::* {
|
|
|
|
HRESULT CBaseBar::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
// }
|
|
|