|
|
#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; }
// }
|