windows-nt/Source/XPSP1/NT/shell/browseui/basebar.cpp
2020-09-26 16:20:57 +08:00

507 lines
11 KiB
C++

#include "priv.h"
#include "apithk.h"
#include "mshtmhst.h"
#include "basebar.h"
#ifdef MAINWIN
#include <mainwin.h>
EXTERN_C MwPaintSpecialEOBorder( HWND hWnd, HDC hDC );
#endif
#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);
#if 0
// we'd like to set focus to the 1st band when somebody clicks in
// 'dead space' on the bar (i.e. make it look like they TABed in).
// however for some reason the below code has the bad effect of
// de-selecting text in (e.g.) the addr edit control (it's as if
// the control thinks we've clicked there 2x rather than 1x).
case WM_SETFOCUS:
if (IUnknown_HasFocusIO(_pDBC) == S_FALSE)
IUnknown_UIActivateIO(_pDBC, TRUE, NULL);
break;
#endif
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;
#ifdef MAINWIN
case WM_NCPAINTSPECIALFRAME:
// In case of motif look the MwPaintBorder paints a Etched In
// border if WM_NCPAINTSPECIALFRAME returns FALSE. We are handling
// this message here and drawing the Etched Out frame explicitly.
// wParam - HDC
if (MwCurrentLook() == LOOK_MOTIF)
{
MwPaintSpecialEOBorder( hwnd, (HDC)wParam );
return TRUE;
}
#endif
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 CS_HREDRAW | CS_VREDRAW;
}
void CBaseBar::_CreateDeskBarWindow()
{
#ifndef UNIX
// _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*));
#else
// This change removes a flash at the corner of the
// screen. We create a small 1,1 window.
HWND hwndDummy = CreateWindowEx(
_GetExStyle(),
TEXT("BaseBar"), NULL,
_hwndSite ? WS_CHILD | WS_CLIPCHILDREN : WS_POPUP | WS_CLIPCHILDREN,
-100,-100,1,1,
_hwndSite, NULL, HINST_THISDLL,
(LPVOID)SAFECAST(this, CImpWndProc*));
#endif
}
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;
}
// }