You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3293 lines
93 KiB
3293 lines
93 KiB
#include "priv.h"
|
|
#include "sccls.h"
|
|
#include <uxtheme.h>
|
|
#define WANT_CBANDSITE_CLASS
|
|
#include "bandsite.h"
|
|
#include "bandobj.h"
|
|
#include "caggunk.h"
|
|
#include "droptgt.h"
|
|
#include "resource.h"
|
|
#include "bands.h"
|
|
#include "legacy.h"
|
|
#include "apithk.h"
|
|
|
|
#include "mluisupp.h"
|
|
|
|
#define TF_BANDDD 0x00400000
|
|
#define DM_INIT 0 //
|
|
#define DM_PERSIST 0 // trace IPS::Load, ::Save, etc.
|
|
#define DM_MENU 0 // menu code
|
|
#define DM_DRAG 0 // drag&drop
|
|
#define DM_FOCUS 0 // focus
|
|
#define DM_PERF 0 // perf tune
|
|
#define DM_PERF2 0 // perf tune (verbose)
|
|
|
|
#define IDM_DRAGDROP 1
|
|
|
|
#define ISMOVEDDISABLED(dwBandID) ((S_OK == _IsRestricted(dwBandID, RA_MOVE, BAND_ADMIN_NOMOVE)) ? TRUE : FALSE)
|
|
#define ISDDCLOSEDISABLED(dwBandID) ((S_OK == _IsRestricted(dwBandID, RA_DRAG, BAND_ADMIN_NODDCLOSE)) ? TRUE : FALSE)
|
|
|
|
// drag state (NOTE from dockbar.h)
|
|
#define DRAG_NIL 0 // nil
|
|
#define DRAG_MOVE 1 // moving
|
|
#define DRAG_SIZE 2 // sizing
|
|
|
|
typedef struct {
|
|
UINT cx;
|
|
UINT fStyle;
|
|
UINT cxMinChild;
|
|
UINT cyMinChild;
|
|
UINT cyIntegral;
|
|
UINT cyMaxChild;
|
|
UINT cyChild;
|
|
} PERSISTBANDINFO_V3;
|
|
|
|
|
|
typedef struct {
|
|
UINT cx;
|
|
UINT fStyle;
|
|
UINT cxMinChild; // UNUSED. reclaim!
|
|
UINT cyMinChild;
|
|
UINT cyIntegral; // UNUSED
|
|
UINT cyMaxChild; // UNUSED.
|
|
UINT cyChild;
|
|
DWORD dwAdminSettings;
|
|
BITBOOL fNoTitle:1;
|
|
} PERSISTBANDINFO;
|
|
#define RBBIM_XPERSIST (RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE)
|
|
|
|
#ifdef DEBUG
|
|
|
|
extern unsigned long DbStreamTell(IStream *pstm);
|
|
|
|
#else
|
|
|
|
#define DbStreamTell(pstm) ((ULONG) 0)
|
|
|
|
#endif
|
|
|
|
UINT _FixMenuIndex(HMENU hmenu, UINT indexMenu)
|
|
{
|
|
UINT i;
|
|
|
|
i = GetMenuItemCount(hmenu);
|
|
if (indexMenu > i)
|
|
indexMenu = i;
|
|
return indexMenu;
|
|
}
|
|
|
|
#define SUPERCLASS CAggregatedUnknown
|
|
|
|
|
|
HRESULT CBandSite::v_InternalQueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
// perf: last tuned 980728
|
|
QITABENT(CBandSite, IBandSite), // IID_IBandSite
|
|
QITABENT(CBandSite, IInputObject), // IID_IInputObject
|
|
QITABENT(CBandSite, IServiceProvider), // IID_IServiceProvider
|
|
QITABENT(CBandSite, IOleCommandTarget), // IID_IOleCommandTarget
|
|
QITABENTMULTI(CBandSite, IOleWindow, IDeskBarClient), // IID_IOleWindow
|
|
QITABENT(CBandSite, IWinEventHandler), // IID_IWinEventHandler
|
|
QITABENT(CBandSite, IInputObjectSite), // IID_IInputObjectSite
|
|
QITABENT(CBandSite, IDeskBarClient), // IID_IDeskBarClient
|
|
QITABENTMULTI(CBandSite, IPersist, IPersistStream), // rare IID_IPersist
|
|
QITABENT(CBandSite, IPersistStream), // rare IID_IPersistStream
|
|
QITABENT(CBandSite, IBandSiteHelper), // rare IBandSiteHelper
|
|
QITABENT(CBandSite, IDropTarget), // rare IID_IDropTarget
|
|
{ 0 },
|
|
};
|
|
|
|
return QISearch(this, qit, riid, ppvObj);
|
|
}
|
|
|
|
DWORD _SetDataListFlags(IUnknown *punk, DWORD dwMaskBits, DWORD dwValue)
|
|
{
|
|
DWORD dw = 0;
|
|
IShellLinkDataList *pdl;
|
|
if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IShellLinkDataList, &pdl))))
|
|
{
|
|
pdl->GetFlags(&dw);
|
|
dw = (dw & ~dwMaskBits) | (dwValue & dwMaskBits);
|
|
pdl->SetFlags(dw);
|
|
pdl->Release();
|
|
}
|
|
return dw;
|
|
}
|
|
|
|
|
|
///// impl of IServiceProvider
|
|
HRESULT CBandSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
*ppvObj = NULL; // assume error
|
|
|
|
if (IsEqualIID(guidService, SID_IBandProxy))
|
|
{
|
|
hres = QueryService_SID_IBandProxy(_punkSite, riid, &_pbp, ppvObj);
|
|
if(!_pbp)
|
|
{
|
|
// We need to create it ourselves since our parent couldn't help
|
|
ASSERT(FALSE == _fCreatedBandProxy);
|
|
|
|
hres = CreateIBandProxyAndSetSite(_punkSite, riid, &_pbp, ppvObj);
|
|
if(_pbp)
|
|
{
|
|
ASSERT(S_OK == hres);
|
|
_fCreatedBandProxy = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else if (IsEqualIID(guidService, SID_ITopViewHost))
|
|
{
|
|
return QueryInterface(riid, ppvObj);
|
|
}
|
|
else if (IsEqualIID(guidService, IID_IBandSite))
|
|
{
|
|
// It is common for bands to save/load pidls for persistence.
|
|
// CShellLink is a robust way to do this, so let's share one
|
|
// among all the bands.
|
|
//
|
|
// NOTE: This is shared between bands, so if you request it
|
|
// you must complete your use of it within the scope of your
|
|
// function call!
|
|
//
|
|
if (IsEqualIID(riid, IID_IShellLinkA) ||
|
|
IsEqualIID(riid, IID_IShellLinkW))
|
|
{
|
|
if (NULL == _plink)
|
|
CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &_plink));
|
|
if (_plink)
|
|
{
|
|
// we know that the bandsite is going to be pointing to local folders
|
|
// to avoid a perf hit we get in loading the LINKINFO.DLL we explictly
|
|
// disable that functionality here.
|
|
_SetDataListFlags(_plink, SLDF_FORCE_NO_LINKINFO, SLDF_FORCE_NO_LINKINFO);
|
|
hres = _plink->QueryInterface(riid, ppvObj);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = IUnknown_QueryService(_punkSite, guidService, riid, ppvObj);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CBandSite::GetWindow(HWND * lphwnd)
|
|
{
|
|
*lphwnd = _hwnd;
|
|
|
|
return *lphwnd ? S_OK : E_FAIL;
|
|
}
|
|
|
|
CBandSite::CBandSite(IUnknown* punkAgg) : SUPERCLASS(punkAgg)
|
|
{
|
|
DWORD dwData = 0;
|
|
DWORD dwSize = sizeof(dwData);
|
|
|
|
// We assume this object was zero inited.
|
|
ASSERT(!_pbp);
|
|
ASSERT(FALSE == _fCreatedBandProxy);
|
|
SHRegGetUSValue(SZ_REGKEY_GLOBALADMINSETTINGS, SZ_REGVALUE_GLOBALADMINSETTINGS,
|
|
NULL, &dwData, &dwSize, FALSE, NULL, 0);
|
|
|
|
if (IsFlagSet(dwData, BAND_ADMIN_ADMINMACHINE))
|
|
_fIEAKInstalled = TRUE;
|
|
else
|
|
_fIEAKInstalled = FALSE;
|
|
|
|
_dwStyle = BSIS_AUTOGRIPPER;
|
|
|
|
//
|
|
// We check whether or not this succeeded in CBandSite::_Initialize
|
|
//
|
|
_QueryOuterInterface(IID_PPV_ARG(IBandSite, &_pbsOuter));
|
|
DllAddRef();
|
|
}
|
|
|
|
void CBandSite::_ReleaseBandItemData(CBandItemData *pbid, int iIndex)
|
|
{
|
|
if (pbid->pdb)
|
|
{
|
|
pbid->pdb->CloseDW(0);
|
|
|
|
if (-1 != iIndex)
|
|
{
|
|
REBARBANDINFO rbbi;
|
|
|
|
// The band's hwnd is typically destroyed in CloseDW
|
|
rbbi.cbSize = sizeof(rbbi);
|
|
rbbi.fMask = RBBIM_CHILD | RBBIM_LPARAM;
|
|
rbbi.hwndChild = NULL;
|
|
rbbi.lParam = NULL;
|
|
SendMessage(_hwnd, RB_SETBANDINFO, iIndex, (LPARAM) &rbbi);
|
|
}
|
|
|
|
// this is called from remove and the destroy.
|
|
IUnknown_SetSite(pbid->pdb, NULL);
|
|
ATOMICRELEASE(pbid->pdb);
|
|
}
|
|
|
|
if (pbid->pweh == _pwehCache)
|
|
ATOMICRELEASE(_pwehCache);
|
|
|
|
ATOMICRELEASE(pbid->pweh);
|
|
pbid->Release();
|
|
}
|
|
|
|
CBandSite::~CBandSite()
|
|
{
|
|
ATOMICRELEASE(_pdtobj);
|
|
|
|
if(_pbp && _fCreatedBandProxy)
|
|
_pbp->SetSite(NULL);
|
|
|
|
ATOMICRELEASE(_pbp);
|
|
|
|
ATOMICRELEASE(_pwehCache);
|
|
_CacheActiveBand(NULL);
|
|
|
|
_Close();
|
|
|
|
SetDeskBarSite(NULL);
|
|
|
|
if (_plink)
|
|
_plink->Release();
|
|
|
|
RELEASEOUTERINTERFACE(_pbsOuter);
|
|
DllRelease();
|
|
}
|
|
|
|
//*** _IsBandDeleteable --
|
|
// ENTRY/EXIT
|
|
// idBand band ID
|
|
// ret TRUE if deletable, o.w. FALSE (also FALSE on bogus band)
|
|
BOOL CBandSite::_IsBandDeleteable(DWORD dwBandID)
|
|
{
|
|
DWORD dwState;
|
|
|
|
if (FAILED(_pbsOuter->QueryBand(dwBandID, NULL, &dwState, NULL, 0))
|
|
|| (dwState & BSSF_UNDELETEABLE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ASSERT(dwBandID != (DWORD)-1); // make sure QueryBand catches this
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD CBandSite::_GetAdminSettings(DWORD dwBandID)
|
|
{
|
|
DWORD dwAdminSettings = BAND_ADMIN_NORMAL;
|
|
|
|
CBandItemData *pbid = _GetBandItem(_BandIDToIndex(dwBandID));
|
|
if (pbid)
|
|
{
|
|
dwAdminSettings = pbid->dwAdminSettings;
|
|
pbid->Release();
|
|
}
|
|
return dwAdminSettings;
|
|
}
|
|
|
|
|
|
void CBandSite::_SetAdminSettings(DWORD dwBandID, DWORD dwNewAdminSettings)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(_BandIDToIndex(dwBandID));
|
|
if (pbid)
|
|
{
|
|
pbid->dwAdminSettings = dwNewAdminSettings;
|
|
pbid->Release();
|
|
}
|
|
}
|
|
|
|
|
|
//*** CBandSite::IBandSite::* {
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IBandSite::EnumBands method
|
|
|
|
*/
|
|
HRESULT CBandSite::EnumBands(UINT uBand, DWORD* pdwBandID)
|
|
{
|
|
ASSERT((NULL == pdwBandID && (UINT)-1 == uBand) ||
|
|
IS_VALID_WRITE_PTR(pdwBandID, DWORD));
|
|
|
|
if (uBand == (UINT)-1)
|
|
return _GetBandItemCount(); // query count
|
|
|
|
CBandItemData *pbid = _GetBandItem(uBand);
|
|
if (pbid)
|
|
{
|
|
*pdwBandID = pbid->dwBandID;
|
|
pbid->Release();
|
|
return S_OK;
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IBandSite::QueryBand method
|
|
|
|
*/
|
|
HRESULT CBandSite::QueryBand(DWORD dwBandID, IDeskBand** ppstb, DWORD* pdwState, LPWSTR pszName, int cchName)
|
|
{
|
|
ASSERT(NULL == ppstb || IS_VALID_WRITE_PTR(ppstb, IDeskBand));
|
|
ASSERT(NULL == pdwState || IS_VALID_WRITE_PTR(pdwState, DWORD));
|
|
ASSERT(NULL == pszName || IS_VALID_WRITE_BUFFER(pszName, WCHAR, cchName));
|
|
|
|
if (ppstb)
|
|
*ppstb = NULL;
|
|
|
|
CBandItemData *pbid = _GetBandItemDataStructByID(dwBandID);
|
|
if (!pbid)
|
|
return E_FAIL;
|
|
if (pszName)
|
|
{
|
|
StrCpyNW(pszName, pbid->szTitle, cchName);
|
|
}
|
|
|
|
if (ppstb)
|
|
{
|
|
*ppstb = pbid->pdb;
|
|
if (pbid->pdb)
|
|
{
|
|
pbid->pdb->AddRef();
|
|
}
|
|
}
|
|
|
|
if (pdwState)
|
|
{
|
|
*pdwState = 0;
|
|
if (pbid->fShow)
|
|
*pdwState = BSSF_VISIBLE;
|
|
if (pbid->fNoTitle)
|
|
*pdwState |= BSSF_NOTITLE;
|
|
if (pbid->dwModeFlags & DBIMF_UNDELETEABLE)
|
|
*pdwState |= BSSF_UNDELETEABLE;
|
|
}
|
|
|
|
pbid->Release();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IBandSite::SetBandState
|
|
|
|
* NOTES
|
|
* failure handling is inconsistent (1 band vs. all bands case)
|
|
*/
|
|
HRESULT CBandSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (dwBandID == (DWORD) -1)
|
|
{
|
|
BOOL fChange = FALSE;
|
|
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
hr = _SetBandStateHelper(pbid->dwBandID, dwMask, dwState);
|
|
ASSERT(SUCCEEDED(hr));
|
|
fChange |= (hr != S_OK);
|
|
pbid->Release();
|
|
}
|
|
else
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
if (fChange)
|
|
_UpdateAllBands(FALSE, FALSE);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = _SetBandStateHelper(dwBandID, dwMask, dwState);
|
|
if (SUCCEEDED(hr) && hr != S_OK)
|
|
{
|
|
_UpdateBand(dwBandID);
|
|
return S_OK;
|
|
}
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
//***
|
|
// ENTRY/EXIT
|
|
// ret S_OK|changed on success, o.w. E_*.
|
|
// NOTES
|
|
// only a helper for SetBandState, don't call directly
|
|
HRESULT CBandSite::_SetBandStateHelper(DWORD dwBandID, DWORD dwMask, DWORD dwState)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CBandItemData *pbid = _GetBandItem(_BandIDToIndex(dwBandID));
|
|
if (pbid)
|
|
{
|
|
DWORD dwOldState;
|
|
|
|
if (FAILED(QueryBand(dwBandID, NULL, &dwOldState, NULL, 0)))
|
|
{
|
|
ASSERT(0); // 'impossible'
|
|
dwOldState = (DWORD)-1;
|
|
}
|
|
|
|
if (dwMask & BSSF_VISIBLE)
|
|
_ShowBand(pbid, dwState & BSSF_VISIBLE);
|
|
|
|
if (dwMask & BSSF_NOTITLE)
|
|
pbid->fNoTitle = BOOLIFY(dwState & BSSF_NOTITLE);
|
|
|
|
// FEATURE: (kkahl): BSSF_UNDELETABLE cannot currently be modified with
|
|
// this interface.
|
|
hr = ResultFromShort((dwOldState ^ dwState) & dwMask);
|
|
pbid->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//*** _CheckNotifyOnAddRemove -- handle notifies for add/remove/empty
|
|
// DESCRIPTION
|
|
// add/remove always sends a BSID_BANDADDED/BSID_BANDREMOVED.
|
|
// remove of last always sends a DBCID_EMPTY.
|
|
// in floating mode, a transition to/from 1 band does a refresh.
|
|
//
|
|
void CBandSite::_CheckNotifyOnAddRemove(DWORD dwBandID, int iCode)
|
|
{
|
|
int cBands;
|
|
if (!_pct)
|
|
return;
|
|
|
|
if (iCode == CNOAR_CLOSEBAR)
|
|
{
|
|
// Shut down the whole thing
|
|
cBands = 0;
|
|
}
|
|
else
|
|
{
|
|
VARIANTARG var;
|
|
int nCmdID;
|
|
|
|
cBands = _GetBandItemCount(); // post-op # (since op happened in caller)
|
|
|
|
VariantInit(&var);
|
|
var.vt = VT_UI4;
|
|
var.ulVal = dwBandID;
|
|
|
|
BOOL fOne = FALSE;
|
|
switch (iCode)
|
|
{
|
|
case CNOAR_ADDBAND:
|
|
fOne = (cBands == 2); // 1->2
|
|
nCmdID = BSID_BANDADDED;
|
|
break;
|
|
case CNOAR_REMOVEBAND:
|
|
fOne = (cBands == 1); // 2->1
|
|
nCmdID = BSID_BANDREMOVED;
|
|
break;
|
|
default:
|
|
ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
if ((fOne && (_dwMode & DBIF_VIEWMODE_FLOATING)))
|
|
{
|
|
// n.b. fBSOnly *must* be TRUE for perf
|
|
_UpdateAllBands(TRUE, TRUE); // force refresh of optional gripper/title
|
|
}
|
|
|
|
_pct->Exec(&CGID_BandSite, nCmdID, 0, &var, NULL);
|
|
}
|
|
|
|
if (cBands == 0)
|
|
{
|
|
ASSERT(iCode != CNOAR_ADDBAND); // sanity check
|
|
_pct->Exec(&CGID_DeskBarClient, DBCID_EMPTY, 0, NULL, NULL);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IBandSite::RemoveBand method
|
|
|
|
*/
|
|
HRESULT CBandSite::RemoveBand(DWORD dwBandID)
|
|
{
|
|
int iIndex = _BandIDToIndex(dwBandID);
|
|
CBandItemData *pbid = _GetBandItem(iIndex);
|
|
if (pbid)
|
|
{
|
|
// Release the banditem data first, while it can still
|
|
// receive cleanup notifications from its control. *Then*
|
|
// delete the band item.
|
|
_ReleaseBandItemData(pbid, iIndex);
|
|
_DeleteBandItem(iIndex); // unhook from host (rebar)
|
|
_CheckNotifyOnAddRemove(dwBandID, CNOAR_REMOVEBAND);
|
|
pbid->Release();
|
|
return S_OK;
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
void CBandSite::_OnCloseBand(DWORD dwBandID)
|
|
{
|
|
if (dwBandID == -1)
|
|
{
|
|
// Close everything
|
|
_CheckNotifyOnAddRemove(dwBandID, CNOAR_CLOSEBAR);
|
|
}
|
|
else
|
|
{
|
|
// Close just this band
|
|
|
|
CBandItemData *pbid = _GetBandItemDataStructByID(dwBandID);
|
|
if (pbid)
|
|
{
|
|
if (ConfirmRemoveBand(_hwnd, IDS_CONFIRMCLOSEBAND, pbid->szTitle))
|
|
{
|
|
RemoveBand(dwBandID);
|
|
}
|
|
pbid->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CBandSite::_MinimizeBand(DWORD dwBandID)
|
|
{
|
|
SendMessage(_hwnd, RB_MINIMIZEBAND, _BandIDToIndex(dwBandID), TRUE);
|
|
}
|
|
|
|
void CBandSite::_MaximizeBand(DWORD dwBandID)
|
|
{
|
|
SendMessage(_hwnd, RB_MAXIMIZEBAND, _BandIDToIndex(dwBandID), TRUE);
|
|
}
|
|
|
|
//
|
|
// private insert a band into the container control by ID
|
|
// returns the band ID in ShortFromResult(hres)
|
|
//
|
|
|
|
HRESULT CBandSite::_AddBandByID(IUnknown *punk, DWORD dwID)
|
|
{
|
|
IDeskBand *pdb;
|
|
HRESULT hr = punk->QueryInterface(IID_PPV_ARG(IDeskBand, &pdb));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT(pdb);
|
|
CBandItemData *pbid = new CBandItemData();
|
|
if (pbid)
|
|
{
|
|
pbid->dwBandID = dwID;
|
|
pbid->pdb = pdb;
|
|
pdb->AddRef();
|
|
pbid->fShow = TRUE; // initially visible
|
|
|
|
pbid->pdb->QueryInterface(IID_PPV_ARG(IWinEventHandler, &pbid->pweh));
|
|
hr = IUnknown_SetSite(pbid->pdb, SAFECAST(this, IBandSite*));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pbid->pdb->GetWindow(&pbid->hwnd);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// takes ownership in success case
|
|
if (_AddBandItem(pbid))
|
|
{
|
|
if (_dwShowState == DBC_SHOW)
|
|
{
|
|
ASSERT(pbid->fShow);
|
|
pbid->pdb->ShowDW(TRUE);
|
|
_MinimizeBand(pbid->dwBandID);
|
|
}
|
|
|
|
_CheckNotifyOnAddRemove(pbid->dwBandID, CNOAR_ADDBAND);
|
|
hr = ResultFromShort(pbid->dwBandID); // success
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// clean up
|
|
_ReleaseBandItemData(pbid, -1);
|
|
}
|
|
|
|
// Now that we've added the band, clear the _SendToToolband cache.
|
|
//
|
|
// We need to do this because we might have gotten a message for
|
|
// the band before it was inserted, in which case we'll have cached
|
|
// a NULL handler for the band's hwnd (preventing the band from
|
|
// getting any messages thereafter).
|
|
ATOMICRELEASE(_pwehCache);
|
|
_hwndCache = NULL;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
pdb->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IBandSite::AddBand method.
|
|
|
|
Insert a band into the container control.
|
|
|
|
Returns: the band ID in ShortFromResult(hres)
|
|
|
|
*/
|
|
HRESULT CBandSite::AddBand(IUnknown *punk)
|
|
{
|
|
HRESULT hres = _AddBandByID(punk, _dwBandIDNext);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
_dwBandIDNext++;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
void CBandSite::_UpdateBand(DWORD dwBandID)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(_BandIDToIndex(dwBandID));
|
|
if (pbid)
|
|
{
|
|
_UpdateBandInfo(pbid, FALSE);
|
|
_OnRBAutoSize(NULL);
|
|
pbid->Release();
|
|
}
|
|
}
|
|
|
|
void CBandSite::_UpdateAllBands(BOOL fBSOnly, BOOL fNoAutoSize)
|
|
{
|
|
BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
|
|
|
|
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
_UpdateBandInfo(pbid, fBSOnly);
|
|
pbid->Release();
|
|
}
|
|
}
|
|
|
|
SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
|
|
|
|
if (!fNoAutoSize)
|
|
{
|
|
SendMessage(_hwnd, RB_SIZETORECT, 0, 0);
|
|
_OnRBAutoSize(NULL);
|
|
}
|
|
}
|
|
|
|
// *** IOleCommandTarget ***
|
|
HRESULT CBandSite::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
|
|
{
|
|
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
|
|
|
|
if (pguidCmdGroup)
|
|
{
|
|
if (IsEqualIID(*pguidCmdGroup, IID_IDockingWindow))
|
|
{
|
|
for (ULONG i=0 ; i<cCmds ; i++)
|
|
{
|
|
switch (rgCmds[i].cmdID)
|
|
{
|
|
case DBID_BANDINFOCHANGED:
|
|
case DBID_PUSHCHEVRON:
|
|
rgCmds[i].cmdf = OLECMDF_ENABLED;
|
|
break;
|
|
|
|
case DBID_PERMITAUTOHIDE:
|
|
// defer decision to the bands
|
|
for (int iBand = _GetBandItemCount() - 1; iBand >= 0; iBand--)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(iBand);
|
|
if (pbid)
|
|
{
|
|
HRESULT hrTemp = IUnknown_QueryStatus(pbid->pdb, pguidCmdGroup, 1, &rgCmds[i], pcmdtext);
|
|
pbid->Release();
|
|
if (SUCCEEDED(hrTemp) &&
|
|
((rgCmds[i].cmdf & OLECMDF_SUPPORTED) && !(rgCmds[i].cmdf & OLECMDF_ENABLED)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rgCmds[i].cmdf = 0;
|
|
break;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
|
|
{
|
|
return IUnknown_QueryStatus(_ptbActive, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
|
|
}
|
|
}
|
|
|
|
// if we got here, we didn't handle it
|
|
// forward it down
|
|
return MayQSForward(_ptbActive, OCTD_DOWN, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
|
|
}
|
|
|
|
|
|
int _QueryServiceCallback(CBandItemData *pbid, void *pv)
|
|
{
|
|
QSDATA* pqsd = (QSDATA*)pv;
|
|
|
|
if (pbid->fShow)
|
|
pqsd->hres = IUnknown_QueryService(pbid->pdb, *(pqsd->pguidService), *(pqsd->piid), pqsd->ppvObj);
|
|
|
|
// stop if we found the service
|
|
return SUCCEEDED(pqsd->hres) ? FALSE : TRUE;
|
|
}
|
|
|
|
|
|
typedef struct {
|
|
HRESULT hres;
|
|
const GUID *pguidCmdGroup;
|
|
DWORD nCmdID;
|
|
DWORD nCmdexecopt;
|
|
VARIANTARG *pvarargIn;
|
|
VARIANTARG *pvarargOut;
|
|
} EXECDATA;
|
|
|
|
int _ExecCallback(CBandItemData *pbid, void *pv)
|
|
{
|
|
EXECDATA* ped = (EXECDATA*)pv;
|
|
|
|
ped->hres = IUnknown_Exec(pbid->pdb, ped->pguidCmdGroup, ped->nCmdID, ped->nCmdexecopt,
|
|
ped->pvarargIn, ped->pvarargOut);
|
|
return 1;
|
|
}
|
|
|
|
HRESULT CBandSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
|
|
{
|
|
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
|
|
HRESULT hresTmp;
|
|
|
|
if (pguidCmdGroup == NULL)
|
|
{
|
|
/*NOTHING*/
|
|
;
|
|
}
|
|
else if (IsEqualIID(*pguidCmdGroup, CGID_DeskBand))
|
|
{
|
|
switch (nCmdID)
|
|
{
|
|
case DBID_BANDINFOCHANGED:
|
|
if (!pvarargIn)
|
|
_UpdateAllBands(FALSE, FALSE);
|
|
else if (pvarargIn->vt == VT_I4)
|
|
_UpdateBand(pvarargIn->lVal);
|
|
hres = S_OK;
|
|
|
|
// forward this up.
|
|
if (_pct)
|
|
{
|
|
_pct->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
}
|
|
goto Lret;
|
|
|
|
case DBID_PUSHCHEVRON:
|
|
if (pvarargIn && pvarargIn->vt == VT_I4)
|
|
{
|
|
int iIndex = _BandIDToIndex(nCmdexecopt);
|
|
SendMessage(_hwnd, RB_PUSHCHEVRON, iIndex, pvarargIn->lVal);
|
|
hres = S_OK;
|
|
}
|
|
goto Lret;
|
|
|
|
case DBID_MAXIMIZEBAND:
|
|
if (pvarargIn && pvarargIn->vt == VT_UI4)
|
|
_MaximizeBand(pvarargIn->ulVal);
|
|
hres = S_OK;
|
|
goto Lret;
|
|
#if 1 // { FEATURE: temporary until add cbs::Select() mfunc
|
|
case DBID_SHOWONLY:
|
|
{
|
|
int iCount = _GetBandItemCount();
|
|
|
|
// pvaIn->punkVal:
|
|
// punk hide everyone except me
|
|
// 0 hide everyone
|
|
// 1 show everyone
|
|
// FEATURE: we should use pvaIn->lVal not punkVal since we're
|
|
// allowing 0 & 1 !!! (and not doing addref/release)
|
|
ASSERT(pvarargIn && pvarargIn->vt == VT_UNKNOWN);
|
|
if (pvarargIn->punkVal == NULL || pvarargIn->punkVal == (IUnknown*)1)
|
|
TraceMsg(TF_BANDDD, "cbs.e: (id=DBID_SHOWONLY, punk=%x)", pvarargIn->punkVal);
|
|
// show myself, hide everyone else
|
|
TraceMsg(TF_BANDDD, "cbs.Exec(DBID_SHOWONLY): n=%d", _GetBandItemCount());
|
|
|
|
// wait to show this band until we've hidden the others
|
|
CBandItemData *pbidShow = NULL;
|
|
// FEATURE: this (IUnknown*)1 is bogus! Also mentioned above.
|
|
BOOL bShowAll = (pvarargIn->punkVal == (IUnknown*)1);
|
|
for (int i = iCount - 1; i >= 0; i--)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
BOOL fShow = bShowAll || SHIsSameObject(pbid->pdb, pvarargIn->punkVal);
|
|
if (!fShow || bShowAll)
|
|
{
|
|
_ShowBand(pbid, fShow);
|
|
}
|
|
else
|
|
{
|
|
pbidShow = pbid;
|
|
pbidShow->AddRef();
|
|
}
|
|
pbid->Release();
|
|
}
|
|
}
|
|
if (pbidShow)
|
|
{
|
|
_ShowBand(pbidShow, TRUE);
|
|
// nash:37290 set focus to band on open
|
|
if (_dwShowState == DBC_SHOW)
|
|
IUnknown_UIActivateIO(pbidShow->pdb, TRUE, NULL);
|
|
else
|
|
ASSERT(0);
|
|
pbidShow->Release();
|
|
}
|
|
}
|
|
break;
|
|
#endif // }
|
|
}
|
|
}
|
|
else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
|
|
{
|
|
return IUnknown_Exec(_ptbActive, pguidCmdGroup, nCmdID, nCmdexecopt,
|
|
pvarargIn, pvarargOut);
|
|
}
|
|
else if (IsEqualIID(*pguidCmdGroup, CGID_DeskBarClient))
|
|
{
|
|
switch (nCmdID)
|
|
{
|
|
case DBCID_ONDRAG:
|
|
if (pvarargIn->vt == VT_I4)
|
|
{
|
|
ASSERT(pvarargIn->lVal == 0 || pvarargIn->lVal == DRAG_MOVE);
|
|
TraceMsg(DM_TRACE, "cbs.e: DBCID_ONDRAG i=%d", pvarargIn->lVal);
|
|
_fDragging = pvarargIn->lVal;
|
|
}
|
|
break;
|
|
|
|
case DBCID_GETBAR:
|
|
// return IUnkown of my IDeskBar host
|
|
if ((pvarargOut != NULL) && _pdb)
|
|
{
|
|
::VariantInit(pvarargOut);
|
|
V_VT(pvarargOut) = VT_UNKNOWN;
|
|
V_UNKNOWN(pvarargOut) = _pdb;
|
|
_pdb->AddRef();
|
|
hres = S_OK;
|
|
goto Lret;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// if we got here, we didn't handle it
|
|
// see if we should forward it down
|
|
hresTmp = IsExecForward(pguidCmdGroup, nCmdID);
|
|
if (SUCCEEDED(hresTmp) && HRESULT_CODE(hresTmp) > 0)
|
|
{
|
|
// down (singleton or broadcast)
|
|
if (HRESULT_CODE(hresTmp) == OCTD_DOWN)
|
|
{
|
|
// down (singleton)
|
|
|
|
hres = IUnknown_Exec(_ptbActive, pguidCmdGroup, nCmdID, nCmdexecopt,
|
|
pvarargIn, pvarargOut);
|
|
}
|
|
else
|
|
{
|
|
// down (broadcast)
|
|
// n.b. hres is a bit weird: 'last one wins'
|
|
// FEATURE: should we just return S_OK?
|
|
ASSERT(HRESULT_CODE(hresTmp) == OCTD_DOWNBROADCAST);
|
|
|
|
EXECDATA ctd = { hres, pguidCmdGroup, nCmdID, nCmdexecopt,
|
|
pvarargIn, pvarargOut };
|
|
|
|
_BandItemEnumCallback(1, _ExecCallback, &ctd);
|
|
hres = ctd.hres;
|
|
}
|
|
}
|
|
|
|
Lret:
|
|
return hres;
|
|
}
|
|
|
|
/*** _ShowBand -- show/hide band (cached state, band, and rebar band)
|
|
*/
|
|
void CBandSite::_ShowBand(CBandItemData *pbid, BOOL fShow)
|
|
{
|
|
int i;
|
|
|
|
pbid->fShow = BOOLIFY(fShow);
|
|
if (pbid->pdb)
|
|
{
|
|
pbid->pdb->ShowDW(fShow && (_dwShowState == DBC_SHOW));
|
|
}
|
|
|
|
i = _BandIDToIndex(pbid->dwBandID);
|
|
SendMessage(_hwnd, RB_SHOWBAND, i, fShow);
|
|
|
|
// get me a window to draw D&D curosors on. . .
|
|
SHGetTopBrowserWindow(SAFECAST(this, IBandSite*), &_hwndDD);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IBandSite::GetBandSiteInfo
|
|
|
|
*/
|
|
HRESULT CBandSite::GetBandSiteInfo(BANDSITEINFO * pbsinfo)
|
|
{
|
|
ASSERT(IS_VALID_WRITE_PTR(pbsinfo, BANDSITEINFO));
|
|
|
|
if (pbsinfo->dwMask & BSIM_STATE)
|
|
pbsinfo->dwState = _dwMode;
|
|
|
|
if (pbsinfo->dwMask & BSIM_STYLE)
|
|
pbsinfo->dwStyle = _dwStyle;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IBandSite::SetBandSiteInfo
|
|
|
|
*/
|
|
HRESULT CBandSite::SetBandSiteInfo(const BANDSITEINFO * pbsinfo)
|
|
{
|
|
ASSERT(IS_VALID_READ_PTR(pbsinfo, BANDSITEINFO));
|
|
|
|
if (pbsinfo->dwMask & BSIM_STATE)
|
|
_dwMode = pbsinfo->dwState;
|
|
|
|
if (pbsinfo->dwMask & BSIM_STYLE)
|
|
{
|
|
// If the BSIS_SINGLECLICK style changed, change the rebar style
|
|
if ( _hwnd && ((_dwStyle ^ pbsinfo->dwStyle) & BSIS_SINGLECLICK) )
|
|
SHSetWindowBits(_hwnd, GWL_STYLE, RBS_DBLCLKTOGGLE, (pbsinfo->dwStyle & BSIS_SINGLECLICK)?0:RBS_DBLCLKTOGGLE);
|
|
|
|
_dwStyle = pbsinfo->dwStyle;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IBandSite::GetBandObject
|
|
|
|
*/
|
|
HRESULT CBandSite::GetBandObject(DWORD dwBandID, REFIID riid, void **ppvObj)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if (IsEqualIID(riid, IID_IDataObject))
|
|
{
|
|
*ppvObj = _DataObjForBand(dwBandID);
|
|
if (*ppvObj)
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
CBandItemData *pbid = _GetBandItemDataStructByID(dwBandID);
|
|
if (pbid)
|
|
{
|
|
if (pbid->pdb)
|
|
{
|
|
hres = pbid->pdb->QueryInterface(riid, ppvObj);
|
|
}
|
|
pbid->Release();
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Returns a pointer to the band item data given an
|
|
externally known band ID.
|
|
|
|
Returns: NULL if band ID is illegal
|
|
*/
|
|
CBandItemData* CBandSite::_GetBandItemDataStructByID(DWORD uID)
|
|
{
|
|
int iBand = _BandIDToIndex(uID);
|
|
if (iBand == -1)
|
|
return NULL;
|
|
return _GetBandItem(iBand);
|
|
}
|
|
|
|
|
|
__inline HRESULT _FwdWinEvent(IWinEventHandler* pweh, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
|
|
{
|
|
ASSERT(pweh);
|
|
ASSERT(hwnd == HWND_BROADCAST || pweh->IsWindowOwner(hwnd) == S_OK);
|
|
|
|
return pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Forwards messages to the band that owns the window.
|
|
|
|
Returns: TRUE if the message was forwarded
|
|
|
|
*/
|
|
BOOL CBandSite::_SendToToolband(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
|
|
{
|
|
BOOL fSent = FALSE;
|
|
LRESULT lres = 0;
|
|
|
|
if (hwnd)
|
|
{
|
|
if (hwnd == _hwndCache)
|
|
{
|
|
ASSERT(hwnd != HWND_BROADCAST);
|
|
|
|
if (_pwehCache)
|
|
{
|
|
_FwdWinEvent(_pwehCache, hwnd, uMsg, wParam, lParam, &lres);
|
|
fSent = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CBandItemData *pbid = NULL;
|
|
// pbid ownership is goofy here -- we still have a ref once we break out of the loop.
|
|
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
|
|
{
|
|
if (pbid)
|
|
pbid->Release();
|
|
|
|
pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
if (pbid->pweh)
|
|
{
|
|
if (hwnd == HWND_BROADCAST ||
|
|
(pbid->pweh->IsWindowOwner(hwnd) == S_OK))
|
|
{
|
|
_FwdWinEvent(pbid->pweh, hwnd, uMsg, wParam, lParam, &lres);
|
|
fSent = TRUE;
|
|
|
|
if (hwnd != HWND_BROADCAST)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hwnd == HWND_BROADCAST && pbid->hwnd)
|
|
{
|
|
lres = SendMessage(pbid->hwnd, uMsg, wParam, lParam);
|
|
fSent = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hwnd != HWND_BROADCAST)
|
|
{
|
|
ATOMICRELEASE(_pwehCache);
|
|
_hwndCache = hwnd;
|
|
if (fSent && pbid)
|
|
{
|
|
_pwehCache = pbid->pweh;
|
|
_pwehCache->AddRef();
|
|
}
|
|
}
|
|
if (pbid)
|
|
pbid->Release();
|
|
}
|
|
}
|
|
|
|
if (plres)
|
|
*plres = lres;
|
|
|
|
return fSent;
|
|
}
|
|
|
|
typedef struct {
|
|
HWND hwnd;
|
|
HRESULT hres;
|
|
} WINDOWOWNERDATA;
|
|
|
|
int _IsWindowOwnerCallback(CBandItemData *pbid, void *pv)
|
|
{
|
|
WINDOWOWNERDATA* pwod = (WINDOWOWNERDATA*)pv;
|
|
|
|
if (pbid->pweh && (pbid->pweh->IsWindowOwner(pwod->hwnd) == S_OK))
|
|
{
|
|
pwod->hres = S_OK;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
HRESULT CBandSite::IsWindowOwner(HWND hwnd)
|
|
{
|
|
if (hwnd == _hwnd)
|
|
return S_OK;
|
|
|
|
WINDOWOWNERDATA wod = { hwnd, S_FALSE };
|
|
_BandItemEnumCallback(1, _IsWindowOwnerCallback, &wod);
|
|
return wod.hres;
|
|
}
|
|
|
|
//*** CBandSite::IDeskBarClient::* {
|
|
HRESULT CBandSite::GetSize(DWORD dwWhich, LPRECT prc)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
switch (dwWhich)
|
|
{
|
|
case DBC_GS_IDEAL:
|
|
{
|
|
prc->right = 0;
|
|
prc->bottom = 0;
|
|
|
|
BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
|
|
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
RECT rc;
|
|
|
|
SendMessage(_hwnd, RB_GETBANDBORDERS, _BandIDToIndex(pbid->dwBandID), (LPARAM) &rc);
|
|
_UpdateBandInfo(pbid, FALSE);
|
|
|
|
if (pbid->fShow)
|
|
{
|
|
if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
|
|
{
|
|
prc->right = max(prc->right, pbid->ptActual.x + (rc.left + rc.right));
|
|
prc->bottom += pbid->ptActual.y + rc.top + rc.bottom;
|
|
}
|
|
else
|
|
{
|
|
prc->bottom = max(prc->right, pbid->ptActual.x + (rc.left + rc.right));
|
|
prc->right += pbid->ptActual.y + rc.top + rc.bottom;
|
|
}
|
|
}
|
|
hres = S_OK;
|
|
pbid->Release();
|
|
}
|
|
}
|
|
SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
|
|
}
|
|
break;
|
|
|
|
case DBC_GS_SIZEDOWN:
|
|
{
|
|
// Used to make a band change size in chuncks
|
|
SendMessage(_hwnd, RB_SIZETORECT, RBSTR_CHANGERECT, (LPARAM)prc);
|
|
hres = S_OK;
|
|
}
|
|
break;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
void CBandSite::_Close()
|
|
{
|
|
if (_hwnd)
|
|
{
|
|
// (scotth): This method is getting called by the destructor,
|
|
// and calls _DeleteAllBandItems, which sends messages to _hwnd.
|
|
// _hwnd is already destroyed by this time. If you hit this assert
|
|
// it is because in debug windows it RIPs like crazy.
|
|
// 970508 (adp): pblm was that we weren't doing DestroyWnd etc.
|
|
//
|
|
// Do no remove this assert....please fix the root problem.
|
|
ASSERT(IS_VALID_HANDLE(_hwnd, WND));
|
|
SendMessage(_hwnd, WM_SETREDRAW, 0, 0);
|
|
_DeleteAllBandItems();
|
|
|
|
DestroyWindow(_hwnd);
|
|
_hwnd = 0;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT CBandSite::UIActivateDBC(DWORD dwState)
|
|
{
|
|
if (dwState != _dwShowState)
|
|
{
|
|
BOOL fShow = dwState;
|
|
|
|
_dwShowState = dwState;
|
|
// map UIActivateDBC to ShowDW
|
|
if (DBC_SHOWOBSCURE == dwState)
|
|
fShow = FALSE;
|
|
|
|
BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
|
|
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
if (pbid->pdb)
|
|
{
|
|
pbid->pdb->ShowDW(fShow && pbid->fShow);
|
|
}
|
|
pbid->Release();
|
|
}
|
|
}
|
|
|
|
// do this now intead of at creation so that
|
|
// rebar doesn't keep trying to autosize us while
|
|
// we're not even visible
|
|
SHSetWindowBits(_hwnd, GWL_STYLE, RBS_AUTOSIZE, RBS_AUTOSIZE);
|
|
SendMessage(_hwnd, WM_SIZE, 0, 0);
|
|
SendMessage(_hwnd, WM_SETREDRAW, (DBC_SHOW == dwState) ? TRUE : fRedraw, 0);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
DWORD CBandSite::_GetWindowStyle(DWORD* pdwExStyle)
|
|
{
|
|
*pdwExStyle = WS_EX_TOOLWINDOW;
|
|
DWORD dwStyle = RBS_REGISTERDROP | RBS_VARHEIGHT | RBS_BANDBORDERS |
|
|
WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN |
|
|
WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN;
|
|
if (_dwStyle & BSIS_LEFTALIGN)
|
|
{
|
|
dwStyle |= RBS_VERTICALGRIPPER;
|
|
}
|
|
|
|
if (!(_dwStyle & BSIS_SINGLECLICK))
|
|
{
|
|
dwStyle |= RBS_DBLCLKTOGGLE;
|
|
}
|
|
|
|
return dwStyle;
|
|
}
|
|
|
|
HRESULT CBandSite::_Initialize(HWND hwndParent)
|
|
{
|
|
//
|
|
// I hope we have an IBandSite to talk to.
|
|
//
|
|
if (!_pbsOuter)
|
|
return E_FAIL;
|
|
|
|
if (!_hwnd)
|
|
{
|
|
DWORD dwExStyle;
|
|
DWORD dwStyle = _GetWindowStyle(&dwExStyle);
|
|
|
|
_hwnd = CreateWindowEx(dwExStyle, REBARCLASSNAME, NULL, dwStyle,
|
|
0, 0, 0, 0, hwndParent, (HMENU) FCIDM_REBAR, HINST_THISDLL, NULL);
|
|
|
|
if (_hwnd)
|
|
{
|
|
SendMessage(_hwnd, RB_SETTEXTCOLOR, 0, CLR_DEFAULT);
|
|
SendMessage(_hwnd, RB_SETBKCOLOR, 0, CLR_DEFAULT);
|
|
SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
|
|
}
|
|
}
|
|
|
|
return _hwnd ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT CBandSite::SetDeskBarSite(IUnknown* punkSite)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!punkSite)
|
|
{
|
|
// Time to tell the bands to free their
|
|
// back pointers on us or we never get freed...
|
|
|
|
// 970325 for now bs::SetDeskBarSite(NULL) is 'overloaded'
|
|
// to mean do both a CloseDW and a SetSite.
|
|
// when we clean up our act and have a bs::Close iface
|
|
// we'll go back to the '#else' code below.
|
|
if (_hwnd)
|
|
_Close();
|
|
}
|
|
|
|
ATOMICRELEASE(_pct);
|
|
ATOMICRELEASE(_pdb);
|
|
ATOMICRELEASE(_punkSite);
|
|
|
|
if (_pbp && _fCreatedBandProxy)
|
|
_pbp->SetSite(punkSite);
|
|
|
|
if (punkSite)
|
|
{
|
|
_punkSite = punkSite;
|
|
_punkSite->AddRef();
|
|
|
|
if (!_hwnd)
|
|
{
|
|
HWND hwndParent;
|
|
IUnknown_GetWindow(punkSite, &hwndParent);
|
|
hr = _Initialize(hwndParent);
|
|
}
|
|
|
|
punkSite->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &_pct));
|
|
punkSite->QueryInterface(IID_PPV_ARG(IDeskBar, &_pdb));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CBandSite::SetModeDBC(DWORD dwMode)
|
|
{
|
|
if (dwMode != _dwMode)
|
|
{
|
|
_dwMode = dwMode;
|
|
|
|
if (_hwnd)
|
|
{
|
|
DWORD dwStyle = 0;
|
|
if (dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
|
|
{
|
|
dwStyle |= CCS_VERT;
|
|
}
|
|
SHSetWindowBits(_hwnd, GWL_STYLE, CCS_VERT, dwStyle);
|
|
}
|
|
|
|
_UpdateAllBands(FALSE, FALSE);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
// }
|
|
|
|
IDropTarget* CBandSite::_WrapDropTargetForBand(IDropTarget* pdtBand)
|
|
{
|
|
if (!pdtBand || (_dwStyle & BSIS_NODROPTARGET))
|
|
{
|
|
// addref it for the new pointer
|
|
if (pdtBand)
|
|
pdtBand->AddRef();
|
|
return pdtBand;
|
|
}
|
|
else
|
|
{
|
|
return DropTargetWrap_CreateInstance(pdtBand, SAFECAST(this, IDropTarget*), _hwndDD);
|
|
}
|
|
}
|
|
|
|
LRESULT CBandSite::_OnNotify(LPNMHDR pnm)
|
|
{
|
|
NMOBJECTNOTIFY *pnmon = (NMOBJECTNOTIFY *)pnm;
|
|
|
|
switch (pnm->code)
|
|
{
|
|
case RBN_GETOBJECT:
|
|
{
|
|
pnmon->hResult = E_FAIL;
|
|
|
|
// if we're the drag source, then a band is dragging... we want to only
|
|
// give out the bandsite's drop target
|
|
if (pnmon->iItem != -1 && !_fDragSource)
|
|
{
|
|
CBandItemData *pbid = _GetBandItemDataStructByID(pnmon->iItem);
|
|
if (pbid)
|
|
{
|
|
if (pbid->pdb)
|
|
{
|
|
pnmon->hResult = pbid->pdb->QueryInterface(*pnmon->piid, &pnmon->pObject);
|
|
|
|
// give a wrapped droptarget instead of the band's droptarget
|
|
if (IsEqualIID(*pnmon->piid, IID_IDropTarget))
|
|
{
|
|
IDropTarget* pdtBand;
|
|
BOOL fNeedReleasePdtBand = FALSE;
|
|
|
|
if (SUCCEEDED(pnmon->hResult))
|
|
{
|
|
pdtBand = (IDropTarget*)(pnmon->pObject);
|
|
}
|
|
else
|
|
{
|
|
CDropDummy *pdtgt = new CDropDummy(_hwndDD);
|
|
pdtBand = SAFECAST(pdtgt, IDropTarget*);
|
|
fNeedReleasePdtBand = TRUE;
|
|
}
|
|
|
|
IDropTarget* pdt = _WrapDropTargetForBand(pdtBand);
|
|
if (pdt)
|
|
{
|
|
pnmon->pObject = pdt;
|
|
pnmon->hResult = S_OK;
|
|
|
|
// we've handed off pdtBand to pdt
|
|
fNeedReleasePdtBand = TRUE;
|
|
}
|
|
|
|
if (fNeedReleasePdtBand && pdtBand)
|
|
pdtBand->Release();
|
|
}
|
|
|
|
if (FAILED(pnmon->hResult) && !(_dwStyle & BSIS_NODROPTARGET))
|
|
pnmon->hResult = QueryInterface(*pnmon->piid, &pnmon->pObject);
|
|
}
|
|
pbid->Release();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RBN_BEGINDRAG:
|
|
return _OnBeginDrag((NMREBAR*)pnm);
|
|
|
|
case RBN_AUTOSIZE:
|
|
_OnRBAutoSize((NMRBAUTOSIZE*)pnm);
|
|
break;
|
|
|
|
case RBN_CHEVRONPUSHED:
|
|
{
|
|
LPNMREBARCHEVRON pnmch = (LPNMREBARCHEVRON) pnm;
|
|
CBandItemData *pbid = _GetBandItem(pnmch->uBand);
|
|
if (pbid)
|
|
{
|
|
MapWindowPoints(_hwnd, HWND_DESKTOP, (LPPOINT)&pnmch->rc, 2);
|
|
ToolbarMenu_Popup(_hwnd, &pnmch->rc, pbid->pdb, pbid->hwnd, 0, (DWORD)pnmch->lParamNM);
|
|
pbid->Release();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RBN_AUTOBREAK:
|
|
{
|
|
if (_dwStyle & BSIS_PREFERNOLINEBREAK)
|
|
{
|
|
Comctl32_FixAutoBreak(pnm);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CBandSite::_OnRBAutoSize(NMRBAUTOSIZE* pnm)
|
|
{
|
|
// DRAG_MOVE: we turn off autosize during (most of) a move because
|
|
// fVertical is out of sync until the very end
|
|
if (_pdb && _GetBandItemCount() && _fDragging != DRAG_MOVE)
|
|
{
|
|
RECT rc;
|
|
int iHeightCur;
|
|
int iHeight = (int)SendMessage(_hwnd, RB_GETBARHEIGHT, 0, 0);
|
|
|
|
#ifdef DEBUG
|
|
DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
|
|
#endif
|
|
|
|
GetWindowRect(_hwnd, &rc);
|
|
MapWindowRect(HWND_DESKTOP, GetParent(_hwnd), &rc);
|
|
|
|
if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
|
|
{
|
|
ASSERT((dwStyle & CCS_VERT));
|
|
iHeightCur = RECTWIDTH(rc);
|
|
rc.right = rc.left + iHeight;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(!(dwStyle & CCS_VERT));
|
|
iHeightCur = RECTHEIGHT(rc);
|
|
rc.bottom = rc.top + iHeight;
|
|
}
|
|
|
|
if ((iHeightCur != iHeight) || (IsOS(OS_WHISTLERORGREATER)))
|
|
{
|
|
_pdb->OnPosRectChangeDB(&rc);
|
|
}
|
|
}
|
|
}
|
|
|
|
IDataObject* CBandSite::_DataObjForBand(DWORD dwBandID)
|
|
{
|
|
IDataObject* pdtobjReturn = NULL;
|
|
|
|
CBandItemData *pbid = _GetBandItemDataStructByID(dwBandID);
|
|
if (pbid)
|
|
{
|
|
if (pbid->pdb)
|
|
{
|
|
CBandDataObject* pdtobj = new CBandDataObject();
|
|
if (pdtobj)
|
|
{
|
|
if (SUCCEEDED(pdtobj->Init(pbid->pdb, this, dwBandID)))
|
|
{
|
|
pdtobjReturn = pdtobj;
|
|
pdtobjReturn->AddRef();
|
|
}
|
|
pdtobj->Release();
|
|
}
|
|
}
|
|
pbid->Release();
|
|
}
|
|
return pdtobjReturn;
|
|
}
|
|
|
|
LRESULT CBandSite::_OnBeginDrag(NMREBAR* pnm)
|
|
{
|
|
LRESULT lres = 0;
|
|
DWORD dwBandID = _IndexToBandID(pnm->uBand);
|
|
|
|
IDataObject* pdtobj = _DataObjForBand(dwBandID);
|
|
|
|
ATOMICRELEASE(_pdtobj);
|
|
|
|
_uDragBand = pnm->uBand;
|
|
_pdtobj = pdtobj;
|
|
// because the RBN_BEGINDRAG is synchronous and so is SHDoDragDrop
|
|
// post this message to ourselves instead of calling dragdrop directly.
|
|
// note that we don't have a window of our own, so we post to our parent
|
|
// and let the message reflector send it back to us
|
|
PostMessage(GetParent(_hwnd), WM_COMMAND, MAKELONG(0, IDM_DRAGDROP), (LPARAM)_hwnd);
|
|
return 1;
|
|
}
|
|
|
|
// return TRUE if the user drags out of the rect of the rebar meaning that we should
|
|
// go into ole drag drop.
|
|
BOOL CBandSite::_PreDragDrop()
|
|
{
|
|
BOOL f = FALSE;
|
|
RECT rc;
|
|
POINT pt;
|
|
DWORD dwBandID = _IndexToBandID(_uDragBand); // Find the BandID before an reordering that may happen.
|
|
|
|
GetWindowRect(_hwnd, &rc);
|
|
SetCapture(_hwnd);
|
|
|
|
InflateRect(&rc, GetSystemMetrics(SM_CXEDGE) * 3, GetSystemMetrics(SM_CYEDGE) * 3);
|
|
while (GetCapture() == _hwnd)
|
|
{
|
|
MSG msg;
|
|
|
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
switch (msg.message)
|
|
{
|
|
case WM_MOUSEMOVE:
|
|
GetCursorPos(&pt);
|
|
if (!ISMOVEDDISABLED(dwBandID))
|
|
{
|
|
if (PtInRect(&rc, pt))
|
|
{
|
|
SendMessage(_hwnd, RB_DRAGMOVE, 0, (LPARAM)-1);
|
|
} else if (!ISDDCLOSEDISABLED(dwBandID) && _pdtobj)
|
|
{
|
|
// we've moved out of the bounds of the rebar.. switch to ole drag
|
|
f = TRUE;
|
|
SetCapture(NULL);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
case WM_LBUTTONDOWN:
|
|
case WM_MBUTTONUP:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_RBUTTONUP:
|
|
case WM_RBUTTONDOWN:
|
|
// bail on any mouse button action
|
|
SetCapture(NULL);
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
switch (msg.wParam)
|
|
{
|
|
case VK_ESCAPE:
|
|
SetCapture(NULL);
|
|
break;
|
|
}
|
|
// fall through
|
|
|
|
default:
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ISDDCLOSEDISABLED(dwBandID) || !_IsBandDeleteable(dwBandID))
|
|
{
|
|
/// if don't allow close, never return true for ole drag.
|
|
f = FALSE;
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
void CBandSite::_DoDragDrop()
|
|
{
|
|
DWORD dwBandID = _IndexToBandID(_uDragBand);
|
|
DWORD dwEffect = DROPEFFECT_MOVE;
|
|
|
|
_fDragSource = TRUE;
|
|
|
|
SendMessage(_hwnd, RB_BEGINDRAG, _uDragBand, (LPARAM)-2);
|
|
|
|
HRESULT hres = S_OK;
|
|
|
|
// first check to see if we even need to go into Ole drag, or if
|
|
// it can all be contained within the rebar
|
|
if (_PreDragDrop())
|
|
{
|
|
SHLoadOLE(SHELLNOTIFY_OLELOADED); // Browser Only - our shell32 doesn't know ole has been loaded
|
|
hres = SHDoDragDrop(_hwnd, _pdtobj, NULL, dwEffect, &dwEffect);
|
|
}
|
|
else
|
|
{
|
|
// if we kept it all within win32 dragging, then set no drop effect
|
|
dwEffect = DROPEFFECT_NONE;
|
|
}
|
|
|
|
SendMessage(_hwnd, RB_ENDDRAG, 0, 0);
|
|
_fDragSource = FALSE;
|
|
if (dwEffect & DROPEFFECT_MOVE)
|
|
{
|
|
RemoveBand(dwBandID);
|
|
}
|
|
else if (!dwEffect && hres == DRAGDROP_S_DROP)
|
|
{
|
|
// if the drop was done, but the target didn't allow
|
|
// then we float the band.
|
|
}
|
|
|
|
ATOMICRELEASE(_pdtobj);
|
|
}
|
|
|
|
HMENU CBandSite::_LoadContextMenu()
|
|
{
|
|
return LoadMenuPopup_PrivateNoMungeW(MENU_BANDSITE1);
|
|
}
|
|
|
|
HRESULT CBandSite::_OnBSCommand(int idCmd, DWORD idBandActive, CBandItemData *pbid)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (idCmd)
|
|
{
|
|
case BSIDM_CLOSEBAND:
|
|
_OnCloseBand(idBandActive);
|
|
break;
|
|
|
|
case BSIDM_SHOWTITLEBAND:
|
|
ASSERT(idBandActive != (DWORD)-1 && pbid);
|
|
if (pbid)
|
|
{
|
|
pbid->fNoTitle = !pbid->fNoTitle;
|
|
_UpdateBandInfo(pbid, FALSE);
|
|
}
|
|
break;
|
|
|
|
case BSIDM_IEAK_DISABLE_MOVE:
|
|
case BSIDM_IEAK_DISABLE_DDCLOSE:
|
|
ASSERT(idBandActive != (DWORD)-1);
|
|
if (idBandActive != (DWORD)-1)
|
|
{
|
|
static const int idCmds[] = { BSIDM_IEAK_DISABLE_MOVE, BSIDM_IEAK_DISABLE_DDCLOSE };
|
|
static const int idFlags[] = { BAND_ADMIN_NOMOVE, BAND_ADMIN_NODDCLOSE };
|
|
|
|
DWORD dwFlag = SHSearchMapInt(idCmds, idFlags, ARRAYSIZE(idCmds), idCmd);
|
|
DWORD dwAdminSettings = _GetAdminSettings(idBandActive);
|
|
|
|
// Toggle Setting.
|
|
ToggleFlag(dwAdminSettings, dwFlag);
|
|
|
|
// Set Menu Item Check Mark appropriately.
|
|
_SetAdminSettings(idBandActive, dwAdminSettings);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// returns the index of the band hit by lParam using context menu semantics (lParam == -1 for keyboard)
|
|
int CBandSite::_ContextMenuHittest(LPARAM lParam, POINT* ppt)
|
|
{
|
|
int iBandIndex;
|
|
|
|
if (lParam == (LPARAM) -1)
|
|
{
|
|
// Keyboard activation. Use active band.
|
|
DWORD dwBandID = _BandIDFromPunk(_ptbActive);
|
|
iBandIndex = _BandIDToIndex(dwBandID);
|
|
|
|
CBandItemData *pbid = _GetBandItem(iBandIndex);
|
|
if (pbid)
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(pbid->hwnd, &rc);
|
|
ppt->x = rc.left;
|
|
ppt->y = rc.top;
|
|
pbid->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Mouse activation. Figure out which band got clicked.
|
|
RBHITTESTINFO rbht;
|
|
|
|
ppt->x = GET_X_LPARAM(lParam);
|
|
ppt->y = GET_Y_LPARAM(lParam);
|
|
rbht.pt = *ppt;
|
|
ScreenToClient(_hwnd, &rbht.pt);
|
|
SendMessage(_hwnd, RB_HITTEST, 0, (LPARAM)&rbht);
|
|
iBandIndex = rbht.iBand;
|
|
}
|
|
|
|
return iBandIndex;
|
|
}
|
|
|
|
HRESULT CBandSite::_OnContextMenu(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
HMENU hmenu = CreatePopupMenu();
|
|
|
|
if (hmenu)
|
|
{
|
|
HRESULT hresT;
|
|
int idCmd = 1;
|
|
IContextMenu *pcm, *pcmParent = NULL, *pcmChild = NULL;
|
|
|
|
POINT pt;
|
|
int iBandIndex = _ContextMenuHittest(lParam, &pt);
|
|
|
|
// map rebar index to band id
|
|
// get band info for that band id
|
|
DWORD idBandActive = _IndexToBandID(iBandIndex);
|
|
CBandItemData *pbid = _GetBandItemDataStructByID(idBandActive);
|
|
|
|
//
|
|
// self (top)
|
|
//
|
|
int idCmdBS1 = idCmd;
|
|
|
|
HMENU hmenuMe = _LoadContextMenu();
|
|
if (hmenuMe)
|
|
{
|
|
BOOL fDeleteShowTitle = TRUE;
|
|
if (pbid && !(_dwStyle & BSIS_LOCKED))
|
|
{
|
|
DESKBANDINFO dbi;
|
|
|
|
CheckMenuItem(hmenuMe, BSIDM_SHOWTITLEBAND,
|
|
pbid->fNoTitle ? MF_BYCOMMAND|MF_UNCHECKED : MF_BYCOMMAND|MF_CHECKED);
|
|
dbi.dwMask = 0; // paranoia (and needed for taskband!)
|
|
_GetBandInfo(pbid, &dbi);
|
|
// make sure pbid in sync
|
|
ASSERT((dbi.dwMask & DBIM_TITLE) || pbid->fNoTitle);
|
|
if ((dbi.dwMask & DBIM_TITLE) && _IsEnableTitle(pbid))
|
|
{
|
|
fDeleteShowTitle = FALSE;
|
|
}
|
|
}
|
|
|
|
if (fDeleteShowTitle)
|
|
{
|
|
DeleteMenu(hmenuMe, BSIDM_SHOWTITLEBAND, MF_BYCOMMAND);
|
|
}
|
|
|
|
idCmd += Shell_MergeMenus(hmenu, hmenuMe, 0, idCmd, 0x7fff, 0) - (idCmd);
|
|
DestroyMenu(hmenuMe);
|
|
}
|
|
|
|
//
|
|
// child
|
|
//
|
|
int idCmdChild = idCmd;
|
|
|
|
if (pbid && pbid->pdb)
|
|
{
|
|
// merge in band's menu (at front)
|
|
hresT = pbid->pdb->QueryInterface(IID_PPV_ARG(IContextMenu, &pcmChild));
|
|
if (SUCCEEDED(hresT))
|
|
{
|
|
// 0=at front
|
|
hresT = pcmChild->QueryContextMenu(hmenu, 0, idCmd, 0x7fff, 0);
|
|
if (SUCCEEDED(hresT))
|
|
idCmd += HRESULT_CODE(hresT);
|
|
}
|
|
}
|
|
|
|
//
|
|
// self (bottom)
|
|
//
|
|
int idCmdBS2 = idCmd;
|
|
|
|
if (!(_dwStyle & BSIS_NOCONTEXTMENU))
|
|
{
|
|
hmenuMe = LoadMenuPopup_PrivateNoMungeW(MENU_BANDSITE2);
|
|
if (hmenuMe)
|
|
{
|
|
// disable 'Close Band' if it's marked undeleteable
|
|
// nash:17821: don't disable when 0 bands (so user can easily
|
|
// get out of toasted mode)
|
|
if ((idBandActive == (DWORD)-1) || // if mouse not over a band, delete close menu item
|
|
(!_IsBandDeleteable(idBandActive) ||
|
|
ISDDCLOSEDISABLED(idBandActive)) ||
|
|
(_dwStyle & BSIS_LOCKED))
|
|
{
|
|
DeleteMenu(hmenuMe, BSIDM_CLOSEBAND, MF_BYCOMMAND);
|
|
}
|
|
|
|
if (!_fIEAKInstalled)
|
|
{
|
|
DeleteMenu(hmenuMe, BSIDM_IEAK_DISABLE_DDCLOSE, MF_BYCOMMAND);
|
|
DeleteMenu(hmenuMe, BSIDM_IEAK_DISABLE_MOVE, MF_BYCOMMAND);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwAdminSettings = _GetAdminSettings(idBandActive);
|
|
|
|
if (IsFlagSet(dwAdminSettings, BAND_ADMIN_NODDCLOSE))
|
|
_CheckMenuItem(hmenuMe, BSIDM_IEAK_DISABLE_DDCLOSE, TRUE);
|
|
|
|
if (IsFlagSet(dwAdminSettings, BAND_ADMIN_NOMOVE))
|
|
_CheckMenuItem(hmenuMe, BSIDM_IEAK_DISABLE_MOVE, TRUE);
|
|
}
|
|
|
|
idCmd += Shell_MergeMenus(hmenu, hmenuMe, (UINT) -1, idCmd, 0x7fff, 0) - (idCmd);
|
|
DestroyMenu(hmenuMe);
|
|
}
|
|
}
|
|
|
|
//
|
|
// parent
|
|
//
|
|
int idCmdParent = idCmd;
|
|
|
|
if (_punkSite)
|
|
{
|
|
UINT uFlags = 0;
|
|
ASSERT(_pcm3Parent == NULL);
|
|
if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IContextMenu3, &_pcm3Parent))))
|
|
{
|
|
uFlags |= CMF_ICM3;
|
|
}
|
|
|
|
hresT = _punkSite->QueryInterface(IID_PPV_ARG(IContextMenu, &pcmParent));
|
|
if (SUCCEEDED(hresT))
|
|
{
|
|
// APPCOMPAT: fix parents and kids to handle...
|
|
// we'd like to pass in -1 but not everyone handles that.
|
|
// workaround: use _FixMenuIndex...
|
|
hresT = pcmParent->QueryContextMenu(hmenu, _FixMenuIndex(hmenu, -1), idCmd, 0x7fff, uFlags);
|
|
|
|
ASSERT(SUCCEEDED(hresT));
|
|
idCmd += HRESULT_CODE(hresT);
|
|
}
|
|
}
|
|
|
|
//
|
|
// do it
|
|
//
|
|
{
|
|
HWND hwndParent = GetParent(_hwnd);
|
|
if (!hwndParent)
|
|
hwndParent = _hwnd;
|
|
idCmd = TrackPopupMenu(hmenu,
|
|
TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
|
|
pt.x, pt.y, 0, hwndParent, NULL);
|
|
}
|
|
|
|
if (idCmd)
|
|
{
|
|
// must test from smallest to largest
|
|
ASSERT(idCmdBS1 <= idCmdChild);
|
|
ASSERT(idCmdChild <= idCmdBS2); // o.w. test in wrong order
|
|
ASSERT(idCmdBS2 <= idCmdParent);
|
|
|
|
if ((idCmd>= idCmdBS1) && (idCmd < idCmdChild))
|
|
{
|
|
idCmd -= idCmdBS1;
|
|
hres = _OnBSCommand(idCmd, idBandActive, pbid);
|
|
}
|
|
else if ((idCmd>= idCmdBS2) && (idCmd < idCmdParent))
|
|
{
|
|
idCmd -= idCmdBS2;
|
|
hres = _OnBSCommand(idCmd, idBandActive, pbid);
|
|
}
|
|
else
|
|
{
|
|
// A parent or child command
|
|
if (idCmd < idCmdParent)
|
|
{
|
|
pcm = pcmChild;
|
|
idCmd -= idCmdChild;
|
|
}
|
|
else
|
|
{
|
|
pcm = pcmParent;
|
|
idCmd -= idCmdParent;
|
|
}
|
|
|
|
ASSERT(pcm);
|
|
|
|
//
|
|
// Call InvokeCommand
|
|
//
|
|
CMINVOKECOMMANDINFOEX ici =
|
|
{
|
|
sizeof(CMINVOKECOMMANDINFOEX),
|
|
0L,
|
|
_hwnd,
|
|
(LPSTR)MAKEINTRESOURCE(idCmd),
|
|
NULL, NULL,
|
|
SW_NORMAL,
|
|
};
|
|
|
|
hres = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
|
|
}
|
|
}
|
|
|
|
if (pbid)
|
|
pbid->Release();
|
|
|
|
ATOMICRELEASE(_pcm3Parent);
|
|
|
|
if (pcmParent)
|
|
pcmParent->Release();
|
|
if (pcmChild)
|
|
pcmChild->Release();
|
|
|
|
DestroyMenu(hmenu);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IWinEventHandler::OnWinEvent
|
|
|
|
Processes messages passed on from the bar. Forward
|
|
messages to the bands as appropriate.
|
|
|
|
*/
|
|
HRESULT CBandSite::OnWinEvent(HWND h, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
HWND hwnd = HWND_BROADCAST;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_WININICHANGE:
|
|
_UpdateAllBands(FALSE, FALSE);
|
|
goto L_WM_SYSCOLORCHANGE;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
case WM_PALETTECHANGED:
|
|
L_WM_SYSCOLORCHANGE:
|
|
// propagate to rebar
|
|
if (_hwnd)
|
|
SendMessage(_hwnd, uMsg, wParam, lParam);
|
|
|
|
// by not returning here, it will get forwarded to the bands also...
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
// if it came from the keyboard, wParam is somewhat useless. it's always out hwnd
|
|
if (IS_WM_CONTEXTMENU_KEYBOARD(lParam))
|
|
hwnd = GetFocus();
|
|
else
|
|
hwnd = (HWND)wParam;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
if (lParam)
|
|
hwnd = ((LPNMHDR)lParam)->hwndFrom;
|
|
break;
|
|
|
|
case WM_INITMENUPOPUP:
|
|
case WM_MEASUREITEM:
|
|
case WM_DRAWITEM:
|
|
case WM_MENUCHAR:
|
|
if (_pcm3Parent)
|
|
{
|
|
//
|
|
// If _pcm3Parent, then we've got a context menu up and
|
|
// an ICM3 client who might care about this message.
|
|
//
|
|
hwnd = _hwnd;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
|
|
LRESULT lres = 0;
|
|
|
|
if (hwnd)
|
|
{
|
|
if (_hwnd == hwnd)
|
|
{
|
|
// a message for us
|
|
switch (uMsg)
|
|
{
|
|
case WM_NOTIFY:
|
|
lres = _OnNotify((LPNMHDR)lParam);
|
|
hres = S_OK;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_CMD(wParam, lParam))
|
|
{
|
|
case IDM_DRAGDROP:
|
|
_DoDragDrop();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_INITMENUPOPUP:
|
|
case WM_MEASUREITEM:
|
|
case WM_DRAWITEM:
|
|
case WM_MENUCHAR:
|
|
ASSERT(_pcm3Parent);
|
|
hres = _pcm3Parent->HandleMenuMsg2(uMsg, wParam, lParam, &lres);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_SendToToolband(hwnd, uMsg, wParam, lParam, &lres))
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_WININICHANGE:
|
|
SendMessage(_hwnd, WM_SIZE, 0, 0);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
if (!lres)
|
|
return _OnContextMenu(wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
if (plres)
|
|
*plres = lres;
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CBandSite_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
|
|
{
|
|
CBandSite *pbs = new CBandSite(pUnkOuter);
|
|
if (pbs)
|
|
{
|
|
*ppunk = pbs->_GetInner();
|
|
return S_OK;
|
|
}
|
|
*ppunk = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//*** CBandSite::IPersistStream*::* {
|
|
//
|
|
|
|
HRESULT CBandSite::GetClassID(CLSID *pClassID)
|
|
{
|
|
*pClassID = CLSID_RebarBandSite;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CBandSite::IsDirty(void)
|
|
{
|
|
ASSERT(0);
|
|
return S_FALSE; // FEATURE: never be dirty?
|
|
}
|
|
|
|
HRESULT CBandSite::_AddBand(IUnknown* punk)
|
|
{
|
|
if (_pbsOuter)
|
|
{
|
|
// Give the outer guy first crack
|
|
return _pbsOuter->AddBand(punk);
|
|
}
|
|
else
|
|
{
|
|
return AddBand(punk);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Persisted CBandSite, use types that have fixes sizes
|
|
//
|
|
struct SBandSite
|
|
{
|
|
DWORD cbSize;
|
|
DWORD cbVersion;
|
|
DWORD cBands;
|
|
// ...followed by length-preceded bands
|
|
};
|
|
|
|
#define SBS_WOADMIN_VERSION 3 // Before we added admin settings.
|
|
#define SBS_VERSION 8
|
|
|
|
//*** CBandSite::Load, Save --
|
|
// DESCRIPTION
|
|
// for each band...
|
|
// Load Read (i); OLFS(obj)+AddBand; Read (rbbi); RB_SBI
|
|
// Save RB_GBI; Write(i); OSTS(obj)+nil ; Write(rbbi)
|
|
// NOTES
|
|
// FEATURE: needs error recovery
|
|
// WARNING: we might have done a CreateBand w/o an AddBand; if so our
|
|
// assumption about the rebar bands and the iunknowns being 'parallel'
|
|
// is bogus.
|
|
|
|
HRESULT CBandSite::Load(IStream *pstm)
|
|
{
|
|
HRESULT hres;
|
|
SBandSite sfoo;
|
|
|
|
hres = IStream_Read(pstm, &sfoo, sizeof(sfoo)); // pstm->Read
|
|
if (hres == S_OK)
|
|
{
|
|
if (!(sfoo.cbSize == sizeof(SBandSite) &&
|
|
(sfoo.cbVersion == SBS_VERSION || sfoo.cbVersion == SBS_WOADMIN_VERSION)))
|
|
{
|
|
hres = E_FAIL;
|
|
}
|
|
|
|
IBandSiteHelper *pbsh;
|
|
hres = QueryInterface(IID_PPV_ARG(IBandSiteHelper, &pbsh)); // QI self for aggregation stuff?
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
|
|
for (DWORD i = 0; i < sfoo.cBands && SUCCEEDED(hres); ++i)
|
|
{
|
|
DWORD j;
|
|
hres = IStream_Read(pstm, &j, sizeof(j)); // pstm->Read
|
|
if (hres == S_OK)
|
|
{
|
|
if (j == i) // for sanity check
|
|
{
|
|
IUnknown* punk;
|
|
hres = pbsh->LoadFromStreamBS(pstm, IID_PPV_ARG(IUnknown, &punk));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = _AddBand(punk);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = _LoadBandInfo(pstm, i, sfoo.cbVersion);
|
|
}
|
|
punk->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
|
|
pbsh->Release();
|
|
}
|
|
_UpdateAllBands(FALSE, TRUE); // force refresh
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CBandSite::Save(IStream *pstm, BOOL fClearDirty)
|
|
{
|
|
HRESULT hres;
|
|
SBandSite sfoo;
|
|
|
|
TraceMsg(DM_PERSIST, "cbs.s enter(this=%x pstm=%x) tell()=%x", this, pstm, DbStreamTell(pstm));
|
|
|
|
sfoo.cbSize = sizeof(SBandSite);
|
|
sfoo.cbVersion = SBS_VERSION;
|
|
sfoo.cBands = _GetBandItemCount();
|
|
TraceMsg(DM_PERSIST, "cdb.s: cbands=%d", sfoo.cBands);
|
|
|
|
hres = pstm->Write(&sfoo, sizeof(sfoo), NULL);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
for (DWORD i = 0; i < sfoo.cBands; i++)
|
|
{
|
|
// FEATURE: put seek ptr so can resync after bogus streams
|
|
hres = pstm->Write(&i, sizeof(i), NULL); // for sanity check
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
if (pbid->pdb)
|
|
{
|
|
IBandSiteHelper *pbsh;
|
|
hres = QueryInterface(IID_PPV_ARG(IBandSiteHelper, &pbsh));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pbsh->SaveToStreamBS(SAFECAST(pbid->pdb, IUnknown*), pstm);
|
|
pbsh->Release();
|
|
}
|
|
}
|
|
pbid->Release();
|
|
}
|
|
|
|
hres = _SaveBandInfo(pstm, i);
|
|
ASSERT(SUCCEEDED(hres));
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceMsg(DM_PERSIST, "cbs.s leave tell()=%x", DbStreamTell(pstm));
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CBandSite::GetSizeMax(ULARGE_INTEGER *pcbSize)
|
|
{
|
|
// this is supposed to be an UPPER bound but we're returning a lower bound...
|
|
static const ULARGE_INTEGER cbMax = { sizeof(SBandSite), 0 };
|
|
*pcbSize = cbMax;
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL CBandSite::_IsHeightReasonable(UINT cy)
|
|
{
|
|
static UINT s_cyMon = 0;
|
|
if (s_cyMon == 0)
|
|
{
|
|
HMONITOR hmon = MonitorFromWindow(_hwnd, MONITOR_DEFAULTTONEAREST);
|
|
if (hmon)
|
|
{
|
|
RECT rc;
|
|
if (GetMonitorRect(hmon, &rc))
|
|
{
|
|
s_cyMon = RECTHEIGHT(rc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (s_cyMon != 0) ? (cy < 4 * s_cyMon) : TRUE;
|
|
}
|
|
|
|
// returns: IStream::Read() semantics, S_OK means complete read
|
|
|
|
HRESULT CBandSite::_LoadBandInfo(IStream *pstm, int i, DWORD dwVersion)
|
|
{
|
|
PERSISTBANDINFO bi;
|
|
HRESULT hres;
|
|
DWORD dwSize = sizeof(bi);
|
|
bi.dwAdminSettings = BAND_ADMIN_NORMAL; // Assume Normal since it's not specified
|
|
|
|
COMPILETIME_ASSERT(sizeof(PERSISTBANDINFO_V3) <= sizeof(PERSISTBANDINFO));
|
|
if (SBS_WOADMIN_VERSION == dwVersion)
|
|
dwSize = sizeof(PERSISTBANDINFO_V3);
|
|
|
|
hres = IStream_Read(pstm, &bi, dwSize); // pstm->Read
|
|
if (hres == S_OK)
|
|
{
|
|
//
|
|
// Sanity-check the height specified by PERSISTBANDINFO before proceeding.
|
|
// Some people are hitting a stress scenario where a bad height gets
|
|
// persisted out. If the height is not reasonable, then just discard
|
|
// the sizing values (leaving the defaults in place).
|
|
//
|
|
if (_IsHeightReasonable(bi.cyChild))
|
|
{
|
|
REBARBANDINFO rbbi = { 0 };
|
|
|
|
rbbi.cbSize = sizeof(rbbi);
|
|
rbbi.fMask = RBBIM_XPERSIST;
|
|
rbbi.cx = bi.cx;
|
|
rbbi.fStyle = bi.fStyle;
|
|
|
|
// these things can change from instantiation to instantiation.
|
|
// we want to restore the visual state, not the sizing rules.
|
|
// the sizing rules re retreived each time in getbandinfo
|
|
rbbi.cyMinChild = -1;
|
|
rbbi.cyMaxChild = -1;
|
|
rbbi.cyIntegral = -1;
|
|
rbbi.cxMinChild = -1;
|
|
|
|
if (rbbi.fStyle & RBBS_VARIABLEHEIGHT)
|
|
{
|
|
rbbi.cyChild = bi.cyChild;
|
|
}
|
|
else
|
|
{
|
|
rbbi.cyMinChild = bi.cyMinChild;
|
|
}
|
|
|
|
SendMessage(_hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi);
|
|
}
|
|
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
pbid->dwAdminSettings = bi.dwAdminSettings;
|
|
pbid->fNoTitle = bi.fNoTitle;
|
|
pbid->Release();
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CBandSite::_SaveBandInfo(IStream *pstm, int i)
|
|
{
|
|
REBARBANDINFO rbbi = {0};
|
|
PERSISTBANDINFO bi = {0};
|
|
|
|
rbbi.cbSize = sizeof(rbbi);
|
|
rbbi.fMask = RBBIM_XPERSIST;
|
|
SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi);
|
|
|
|
ASSERT((rbbi.fMask & RBBIM_XPERSIST) == RBBIM_XPERSIST);
|
|
|
|
bi.cx = rbbi.cx;
|
|
bi.fStyle = rbbi.fStyle;
|
|
bi.cyMinChild = rbbi.cyMinChild;
|
|
bi.cyChild = rbbi.cyChild;
|
|
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
bi.dwAdminSettings = pbid->dwAdminSettings;
|
|
bi.fNoTitle = pbid->fNoTitle;
|
|
pbid->Release();
|
|
}
|
|
|
|
return pstm->Write(&bi, sizeof(bi), NULL);
|
|
}
|
|
|
|
void CBandSite::_CacheActiveBand(IUnknown *ptb)
|
|
{
|
|
if (ptb == _ptbActive)
|
|
return;
|
|
|
|
if (SHIsSameObject(ptb, _ptbActive))
|
|
return;
|
|
|
|
ATOMICRELEASE(_ptbActive);
|
|
|
|
if (ptb != NULL)
|
|
{
|
|
#ifdef DEBUG
|
|
// better be an IInputObject or else why did you call us?
|
|
IInputObject *pio;
|
|
if (EVAL(SUCCEEDED(ptb->QueryInterface(IID_PPV_ARG(IInputObject, &pio)))))
|
|
pio->Release();
|
|
|
|
// overly strict, but in our case it's true...
|
|
IDeskBand *pdb;
|
|
if (EVAL(SUCCEEDED(ptb->QueryInterface(IID_PPV_ARG(IDeskBand, &pdb)))))
|
|
pdb->Release();
|
|
#endif
|
|
_ptbActive = ptb;
|
|
_ptbActive->AddRef();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
DWORD CBandSite::_BandIDFromPunk(IUnknown* punk)
|
|
{
|
|
DWORD dwBandID = -1;
|
|
DWORD dwBandIDTest;
|
|
int cBands = EnumBands(-1, NULL);
|
|
IUnknown* punkTest;
|
|
|
|
if (punk)
|
|
{
|
|
for (int i = 0; i < cBands; i++)
|
|
{
|
|
if (SUCCEEDED(EnumBands(i, &dwBandIDTest)))
|
|
{
|
|
if (SUCCEEDED(GetBandObject(dwBandIDTest, IID_PPV_ARG(IUnknown, &punkTest))))
|
|
{
|
|
BOOL fEq = SHIsSameObject(punk, punkTest);
|
|
|
|
punkTest->Release();
|
|
|
|
if (fEq)
|
|
{
|
|
dwBandID = dwBandIDTest;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwBandID;
|
|
}
|
|
|
|
//*** IInputObjectSite methods ***
|
|
|
|
HRESULT CBandSite::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
|
|
{
|
|
if (_ptbActive)
|
|
{
|
|
if (!SHIsSameObject(_ptbActive, punk))
|
|
{
|
|
// Deactivate current band since the current band is
|
|
// not the caller
|
|
TraceMsg(TF_ACCESSIBILITY, "CBandSite::OnFocusChangeIS (hwnd=0x%08X) deactivate band", _hwnd);
|
|
UIActivateIO(FALSE, NULL);
|
|
}
|
|
}
|
|
|
|
if (fSetFocus)
|
|
_CacheActiveBand(punk);
|
|
|
|
return IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), fSetFocus);
|
|
}
|
|
|
|
|
|
//*** IInputObject methods ***
|
|
|
|
HRESULT CBandSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
TraceMsg(TF_ACCESSIBILITY, "CBandSite::UIActivateIO (hwnd=0x%08X) fActivate=%d", _hwnd, fActivate);
|
|
ASSERT(NULL == lpMsg || IS_VALID_WRITE_PTR(lpMsg, MSG));
|
|
|
|
if (_ptbActive)
|
|
{
|
|
hres = IUnknown_UIActivateIO(_ptbActive, fActivate, lpMsg);
|
|
}
|
|
else
|
|
{
|
|
hres = OnFocusChangeIS(NULL, fActivate);
|
|
}
|
|
|
|
if (fActivate)
|
|
{
|
|
if (!_ptbActive)
|
|
{
|
|
if (IsVK_TABCycler(lpMsg))
|
|
hres = _CycleFocusBS(lpMsg);
|
|
else
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_CacheActiveBand(NULL);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CBandSite::HasFocusIO()
|
|
{
|
|
// Rebar should never get focus
|
|
// NT #288832 Is one case where (GetFocus() == _hwnd)
|
|
// which is caused when the "Folder Bar" disappears.
|
|
// CExplorerBand::ShowDW() calls ShowWindow(hwndTreeView, SW_HIDE)
|
|
// which by default sets focus to the parent (us).
|
|
// This is ok because when this function is called,
|
|
// it will return E_FAIL which the caller will treat
|
|
// as S_FALSE and give the focus to the next deserving
|
|
// dude in line.
|
|
return IUnknown_HasFocusIO(_ptbActive);
|
|
}
|
|
|
|
HRESULT CBandSite::TranslateAcceleratorIO(LPMSG lpMsg)
|
|
{
|
|
TraceMsg(TF_ACCESSIBILITY, "CBandSite::TranslateAcceleratorIO (hwnd=0x%08X) key=%d", _hwnd, lpMsg->wParam);
|
|
if (IUnknown_TranslateAcceleratorIO(_ptbActive, lpMsg) == S_OK)
|
|
{
|
|
TraceMsg(TF_ACCESSIBILITY, "CBandSite::TranslateAcceleratorIO (hwnd=0x%08X) key=%d; handled by active band", _hwnd, lpMsg->wParam);
|
|
// active band handled it
|
|
return S_OK;
|
|
}
|
|
else if (IsVK_TABCycler(lpMsg))
|
|
{
|
|
TraceMsg(TF_ACCESSIBILITY, "CBandSite::TranslateAcceleratorIO (hwnd=0x%08X) cycle focus", _hwnd);
|
|
// it's a tab; cycle focus
|
|
return _CycleFocusBS(lpMsg);
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
int CBandSite::_BandIndexFromPunk(IUnknown *punk)
|
|
{
|
|
for (int i = 0; i < _GetBandItemCount(); i++)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
BOOL fSame = SHIsSameObject(pbid->pdb, punk);
|
|
pbid->Release();
|
|
if (fSame)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
BOOL CBandSite::_IsBandTabstop(CBandItemData *pbid)
|
|
{
|
|
// A band is a tabstop if it is visible and has WS_TABSTOP
|
|
|
|
if (pbid->fShow && pbid->hwnd && IsWindowVisible(pbid->hwnd))
|
|
{
|
|
if (WS_TABSTOP & GetWindowStyle(pbid->hwnd))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#define INCDEC(i, fDec) (fDec ? i - 1 : i + 1)
|
|
|
|
IUnknown* CBandSite::_GetNextTabstopBand(IUnknown* ptb, BOOL fBackwards)
|
|
{
|
|
// Find the first tabstop candidate
|
|
int iBandCount = _GetBandItemCount();
|
|
int iBand = _BandIndexFromPunk(ptb);
|
|
|
|
if (iBand == -1)
|
|
{
|
|
// Start at the end/beginning
|
|
if (fBackwards)
|
|
iBand = iBandCount - 1;
|
|
else
|
|
iBand = 0;
|
|
}
|
|
else
|
|
{
|
|
// Start one off the current band
|
|
iBand = INCDEC(iBand, fBackwards);
|
|
}
|
|
|
|
IUnknown *punkRet = NULL;
|
|
BOOL fDone = FALSE;
|
|
// Loop til we find a tabstop band or we run off the end
|
|
while (!fDone && 0 <= iBand && iBand < iBandCount)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(iBand);
|
|
if (pbid)
|
|
{
|
|
if (_IsBandTabstop(pbid))
|
|
{
|
|
punkRet = pbid->pdb;
|
|
fDone = TRUE;
|
|
}
|
|
pbid->Release();
|
|
}
|
|
|
|
// Try the next band
|
|
iBand = INCDEC(iBand, fBackwards);
|
|
}
|
|
|
|
return punkRet;
|
|
}
|
|
|
|
HRESULT CBandSite::_CycleFocusBS(LPMSG lpMsg)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
IUnknown* ptbSave = NULL;
|
|
|
|
if (_ptbActive)
|
|
{
|
|
// Save off the active band in ptbSave
|
|
ptbSave = _ptbActive;
|
|
ptbSave->AddRef();
|
|
|
|
// Deactivate active band and clear cache
|
|
IUnknown_UIActivateIO(_ptbActive, FALSE, NULL);
|
|
_CacheActiveBand(NULL);
|
|
}
|
|
|
|
if (ptbSave && IsVK_CtlTABCycler(lpMsg))
|
|
{
|
|
// If ctl-tab and a band was active, then reject focus
|
|
ASSERT(hr == S_FALSE);
|
|
}
|
|
else
|
|
{
|
|
BOOL fShift = (GetKeyState(VK_SHIFT) < 0);
|
|
|
|
// Loop til we find a tabstop and successfully activate it
|
|
// or til we run out of bands.
|
|
|
|
// FEATURE: todo -- call SetFocus if UIActivateIO fails?
|
|
|
|
IUnknown* ptbNext = ptbSave;
|
|
while (ptbNext = _GetNextTabstopBand(ptbNext, fShift))
|
|
{
|
|
if (IUnknown_UIActivateIO(ptbNext, TRUE, lpMsg) == S_OK)
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ATOMICRELEASE(ptbSave);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//*** CBandSite::IBandSiteHelper::* {
|
|
|
|
// stuff to make it possible to overload the OleLoad/Save stuff so the
|
|
// taskbar band does not have to be CoCreat able. kinda a hack...
|
|
|
|
HRESULT CBandSite::LoadFromStreamBS(IStream *pstm, REFIID riid, void **ppv)
|
|
{
|
|
return OleLoadFromStream(pstm, riid, ppv);
|
|
}
|
|
|
|
HRESULT CBandSite::SaveToStreamBS(IUnknown *punk, IStream *pstm)
|
|
{
|
|
IPersistStream *ppstm;
|
|
HRESULT hres = punk->QueryInterface(IID_PPV_ARG(IPersistStream, &ppstm));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = OleSaveToStream(ppstm, pstm);
|
|
ppstm->Release();
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
// }
|
|
|
|
|
|
// *** IDropTarget *** {
|
|
|
|
HRESULT CBandSite::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
|
{
|
|
TraceMsg(TF_BANDDD, "CBandSite::DragEnter %d %d", pt.x, pt.y);
|
|
|
|
if (!_fDragSource)
|
|
{
|
|
FORMATETC fmte = {g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
|
|
_dwDropEffect = DROPEFFECT_NONE;
|
|
|
|
if (pdtobj->QueryGetData(&fmte) == S_OK)
|
|
{
|
|
_dwDropEffect = DROPEFFECT_MOVE;
|
|
}
|
|
else
|
|
{
|
|
|
|
LPITEMIDLIST pidl;
|
|
|
|
if (SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
|
|
{
|
|
ASSERT(pidl && IS_VALID_PIDL(pidl));
|
|
|
|
DWORD dwAttrib = SFGAO_FOLDER | SFGAO_BROWSABLE;
|
|
IEGetAttributesOf(pidl, &dwAttrib);
|
|
ILFree(pidl);
|
|
|
|
DWORD dwRAction;
|
|
|
|
if (FAILED(IUnknown_HandleIRestrict(_punkSite, &RID_RDeskBars, RA_DROP, NULL, &dwRAction)))
|
|
dwRAction = RR_ALLOW;
|
|
|
|
if (dwRAction == RR_DISALLOW)
|
|
_dwDropEffect = DROPEFFECT_NONE;
|
|
else
|
|
{
|
|
// if it's not a folder nor a browseable object, we can't host it.
|
|
if ((dwAttrib & SFGAO_FOLDER) ||
|
|
(dwAttrib & SFGAO_BROWSABLE) && (grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
|
|
_dwDropEffect = DROPEFFECT_LINK | DROPEFFECT_COPY;
|
|
|
|
_dwDropEffect |= GetPreferedDropEffect(pdtobj);
|
|
}
|
|
}
|
|
}
|
|
*pdwEffect &= _dwDropEffect;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CBandSite::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
|
|
{
|
|
TraceMsg(TF_BANDDD, "CBandSite::DragOver %d %d", ptl.x, ptl.y);
|
|
if (_fDragSource)
|
|
{
|
|
RECT rc;
|
|
POINT pt;
|
|
pt.x = ptl.x;
|
|
pt.y = ptl.y;
|
|
GetWindowRect(_hwnd, &rc);
|
|
if (PtInRect(&rc, pt))
|
|
SendMessage(_hwnd, RB_DRAGMOVE, 0, (LPARAM)-1);
|
|
}
|
|
else
|
|
{
|
|
*pdwEffect &= _dwDropEffect;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CBandSite::DragLeave(void)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CBandSite::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
TraceMsg(TF_BANDDD, "CBandSite::Drop");
|
|
if (_fDragSource)
|
|
{
|
|
SendMessage(_hwnd, RB_ENDDRAG, 0, 0);
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
FORMATETC fmte = {g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
|
|
STGMEDIUM stg;
|
|
IUnknown *punk = NULL;
|
|
LPITEMIDLIST pidl;
|
|
|
|
// if it was an object of our type, create it!
|
|
if ((*pdwEffect & DROPEFFECT_MOVE) &&
|
|
SUCCEEDED(pdtobj->GetData(&fmte, &stg)))
|
|
{
|
|
|
|
hres = OleLoadFromStream(stg.pstm, IID_PPV_ARG(IUnknown, &punk));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
*pdwEffect = DROPEFFECT_MOVE;
|
|
}
|
|
|
|
ReleaseStgMedium(&stg);
|
|
}
|
|
else if ((*pdwEffect & (DROPEFFECT_COPY | DROPEFFECT_LINK)) &&
|
|
SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
|
|
{
|
|
|
|
hres = SHCreateBandForPidl(pidl, &punk, (grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT));
|
|
ILFree(pidl);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (*pdwEffect & DROPEFFECT_LINK)
|
|
*pdwEffect = DROPEFFECT_LINK;
|
|
else
|
|
*pdwEffect = DROPEFFECT_COPY;
|
|
}
|
|
}
|
|
|
|
if (punk)
|
|
{
|
|
hres = _AddBand(punk);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
DWORD dwState;
|
|
|
|
dwState = IDataObject_GetDeskBandState(pdtobj);
|
|
SetBandState(ShortFromResult(hres), BSSF_NOTITLE, dwState & BSSF_NOTITLE);
|
|
}
|
|
|
|
punk->Release();
|
|
}
|
|
}
|
|
|
|
if (FAILED(hres))
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
return hres;
|
|
}
|
|
|
|
// }
|
|
|
|
//*** ::_MergeBS -- merge two bandsites into one
|
|
// ENTRY/EXIT
|
|
// pdtDst [INOUT] destination DropTarget (always from bandsite)
|
|
// pbsSrc [INOUT] source bandsite; deleted if all bands moved successfully
|
|
// ret S_OK if all bands moved; S_FALSE if some moved; E_* o.w.
|
|
// NOTES
|
|
// note that if all the bands are moved successfully, pbsSrc will be deleted
|
|
// as a side-effect.
|
|
// pdtDst is assumed to accept multiple drops (bandsite does).
|
|
// pdtDst may be from marshal/unmarshal (tray bandsite).
|
|
HRESULT _MergeBS(IDropTarget *pdtDst, IBandSite *pbsSrc)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
DWORD idBand;
|
|
|
|
pbsSrc->AddRef(); // don't go away until we're all done!
|
|
|
|
// drag each band in turn
|
|
while (SUCCEEDED(pbsSrc->EnumBands(0, &idBand)))
|
|
{
|
|
// note our (bogus?) assumption that bands which can't be
|
|
// dragged will percolate down to a contiguous range of
|
|
// iBands 0..n. if that's bogus i'm not sure how we can
|
|
// keep track of where we are.
|
|
|
|
IDataObject *pdoSrc;
|
|
hres = pbsSrc->GetBandObject(idBand, IID_PPV_ARG(IDataObject, &pdoSrc));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
DWORD dwEffect = DROPEFFECT_MOVE | DROPEFFECT_COPY;
|
|
hres = SHSimulateDrop(pdtDst, pdoSrc, 0, NULL, &dwEffect);
|
|
pdoSrc->Release();
|
|
|
|
if (SUCCEEDED(hres) && (dwEffect & DROPEFFECT_MOVE))
|
|
{
|
|
hres = pbsSrc->RemoveBand(idBand);
|
|
ASSERT(SUCCEEDED(hres));
|
|
}
|
|
}
|
|
|
|
// we failed to move the band, bail
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
pbsSrc->Release();
|
|
|
|
TraceMsg(DM_DRAG, "dba.ms: ret hres=%x", hres);
|
|
return hres;
|
|
}
|
|
|
|
|
|
void CBandSite::_BandItemEnumCallback(int dincr, PFNBANDITEMENUMCALLBACK pfnCB, void *pv)
|
|
{
|
|
UINT iFirst = 0;
|
|
|
|
ASSERT(dincr == 1 || dincr == -1);
|
|
if (dincr < 0)
|
|
{
|
|
iFirst = _GetBandItemCount() - 1; // start from last
|
|
}
|
|
|
|
for (UINT i = iFirst; i < (UINT) _GetBandItemCount(); i += dincr)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
if (pbid)
|
|
{
|
|
BOOL fStop = !pfnCB(pbid, pv);
|
|
pbid->Release();
|
|
if (fStop)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CBandSite::_DeleteAllBandItems()
|
|
{
|
|
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
|
|
{
|
|
CBandItemData *pbid = _GetBandItem(i);
|
|
|
|
// Release the banditem data first, while it can still
|
|
// receive cleanup notifications from its control. *Then*
|
|
// delete the band item.
|
|
if (pbid)
|
|
{
|
|
_ReleaseBandItemData(pbid, i);
|
|
pbid->Release();
|
|
}
|
|
|
|
// REARCHITECT: chrisfra 5/13/97 if you skip deleting, rebar can
|
|
// rearrange on delete, moving a band so that it is never seen
|
|
// and consequently we leak BrandBand and much else
|
|
_DeleteBandItem(i); // unhook from host (rebar)
|
|
}
|
|
}
|
|
|
|
CBandItemData *CBandSite::_GetBandItem(int i)
|
|
{
|
|
REBARBANDINFO rbbi = { 0 };
|
|
rbbi.cbSize = sizeof(rbbi);
|
|
rbbi.fMask = RBBIM_LPARAM;
|
|
rbbi.lParam = NULL; // in case of failure below
|
|
|
|
if (_hwnd)
|
|
SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi);
|
|
|
|
CBandItemData *pbid = (CBandItemData *)rbbi.lParam;
|
|
if (pbid)
|
|
{
|
|
pbid->AddRef();
|
|
}
|
|
return pbid;
|
|
}
|
|
|
|
int CBandSite::_GetBandItemCount()
|
|
{
|
|
int cel = 0;
|
|
|
|
if (_hwnd)
|
|
{
|
|
ASSERT(IS_VALID_HANDLE(_hwnd, WND));
|
|
|
|
cel = (int)SendMessage(_hwnd, RB_GETBANDCOUNT, 0, 0);
|
|
}
|
|
return cel;
|
|
}
|
|
|
|
void CBandSite::_GetBandInfo(CBandItemData *pbid, DESKBANDINFO *pdbi)
|
|
{
|
|
pdbi->dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
|
|
|
|
pdbi->ptMinSize = pbid->ptMinSize;
|
|
pdbi->ptMaxSize = pbid->ptMaxSize;
|
|
pdbi->ptIntegral = pbid->ptIntegral;
|
|
pdbi->ptActual = pbid->ptActual;
|
|
StrCpyNW(pdbi->wszTitle, pbid->szTitle, ARRAYSIZE(pdbi->wszTitle));
|
|
pdbi->dwModeFlags = pbid->dwModeFlags;
|
|
pdbi->crBkgnd = pbid->crBkgnd;
|
|
|
|
if (pbid->pdb)
|
|
{
|
|
pbid->pdb->GetBandInfo(pbid->dwBandID, _dwMode, pdbi);
|
|
}
|
|
if (pdbi->wszTitle[0] == 0)
|
|
{
|
|
pdbi->dwMask &= ~DBIM_TITLE;
|
|
}
|
|
|
|
pbid->ptMinSize = pdbi->ptMinSize;
|
|
pbid->ptMaxSize = pdbi->ptMaxSize;
|
|
pbid->ptIntegral = pdbi->ptIntegral;
|
|
pbid->ptActual = pdbi->ptActual;
|
|
StrCpyNW(pbid->szTitle, pdbi->wszTitle, ARRAYSIZE(pbid->szTitle));
|
|
pbid->dwModeFlags = pdbi->dwModeFlags;
|
|
pbid->crBkgnd = pdbi->crBkgnd;
|
|
|
|
if (!(pdbi->dwMask & DBIM_TITLE)) // title not supported
|
|
pbid->fNoTitle = TRUE;
|
|
|
|
ASSERT(pdbi->dwModeFlags & DBIMF_VARIABLEHEIGHT ? pbid->ptIntegral.y : TRUE);
|
|
}
|
|
|
|
void CBandSite::_BandInfoFromBandItem(REBARBANDINFO *prbbi, CBandItemData *pbid, BOOL fBSOnly)
|
|
{
|
|
// REVIEW: could be optimized more
|
|
DESKBANDINFO dbi;
|
|
|
|
if (!fBSOnly)
|
|
_GetBandInfo(/*INOUT*/ pbid, &dbi);
|
|
|
|
// now add the view as a band in the rebar
|
|
// add links band
|
|
prbbi->fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_IDEALSIZE | RBBIM_TEXT;
|
|
if (fBSOnly)
|
|
prbbi->fMask = RBBIM_STYLE|RBBIM_TEXT;
|
|
|
|
// clear the bits the are band settable
|
|
prbbi->fStyle |= RBBS_FIXEDBMP;
|
|
prbbi->fStyle &= ~(RBBS_NOGRIPPER | RBBS_GRIPPERALWAYS | RBBS_VARIABLEHEIGHT | RBBS_USECHEVRON);
|
|
|
|
if (_dwStyle & BSIS_NOGRIPPER)
|
|
prbbi->fStyle |= RBBS_NOGRIPPER;
|
|
else if (_dwStyle & BSIS_ALWAYSGRIPPER)
|
|
prbbi->fStyle |= RBBS_GRIPPERALWAYS;
|
|
else
|
|
{
|
|
// BSIS_AUTOGRIPPER...
|
|
if (!(prbbi->fStyle & RBBS_FIXEDSIZE) &&
|
|
!(_dwMode & DBIF_VIEWMODE_FLOATING))
|
|
prbbi->fStyle |= RBBS_GRIPPERALWAYS;
|
|
}
|
|
|
|
if (pbid->dwModeFlags & DBIMF_VARIABLEHEIGHT)
|
|
prbbi->fStyle |= RBBS_VARIABLEHEIGHT;
|
|
|
|
if (pbid->dwModeFlags & DBIMF_USECHEVRON)
|
|
prbbi->fStyle |= RBBS_USECHEVRON;
|
|
|
|
if (pbid->dwModeFlags & DBIMF_BREAK)
|
|
prbbi->fStyle |= RBBS_BREAK;
|
|
|
|
if (pbid->dwModeFlags & DBIMF_TOPALIGN)
|
|
prbbi->fStyle |= RBBS_TOPALIGN;
|
|
|
|
if (!fBSOnly)
|
|
{
|
|
prbbi->hwndChild = pbid->hwnd;
|
|
prbbi->wID = pbid->dwBandID;
|
|
|
|
// set up the geometries
|
|
prbbi->cxMinChild = pbid->ptMinSize.x;
|
|
prbbi->cyMinChild = pbid->ptMinSize.y;
|
|
prbbi->cyMaxChild = pbid->ptMaxSize.y;
|
|
prbbi->cyIntegral = pbid->ptIntegral.y;
|
|
|
|
if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
|
|
{
|
|
// after we're up, it's the "ideal" point
|
|
prbbi->cxIdeal = pbid->ptActual.y;
|
|
}
|
|
else
|
|
{
|
|
// after we're up, it's the "ideal" point
|
|
prbbi->cxIdeal = pbid->ptActual.x;
|
|
}
|
|
|
|
if (prbbi->cxIdeal == (UINT)-1)
|
|
prbbi->cxIdeal = 0;
|
|
|
|
if (pbid->dwModeFlags & DBIMF_BKCOLOR)
|
|
{
|
|
if (dbi.dwMask & DBIM_BKCOLOR)
|
|
{
|
|
prbbi->fMask |= RBBIM_COLORS;
|
|
prbbi->clrFore = CLR_DEFAULT;
|
|
prbbi->clrBack = dbi.crBkgnd;
|
|
}
|
|
}
|
|
ASSERT(pbid->fNoTitle || (dbi.dwMask & DBIM_TITLE)); // pbid in sync?
|
|
}
|
|
|
|
SHUnicodeToTChar(pbid->szTitle, prbbi->lpText, prbbi->cch);
|
|
if (!pbid->fNoTitle && _IsEnableTitle(pbid) && !(_dwStyle & BSIS_NOCAPTION))
|
|
{
|
|
prbbi->fStyle &= ~RBBS_HIDETITLE;
|
|
}
|
|
else
|
|
{
|
|
// No text please
|
|
prbbi->fStyle |= RBBS_HIDETITLE;
|
|
}
|
|
|
|
|
|
// Make this band a tabstop. Itbar will override v_SetTabstop
|
|
// since for the browser we don't want every band to be a tabstop.
|
|
v_SetTabstop(prbbi);
|
|
}
|
|
|
|
void CBandSite::v_SetTabstop(LPREBARBANDINFO prbbi)
|
|
{
|
|
// We specify that a band should be a tabstop by setting the WS_TABSTOP
|
|
// bit. Never make RBBS_FIXEDSIZE bands (i.e., the brand) tabstops.
|
|
if (prbbi && prbbi->hwndChild && !(prbbi->fStyle & RBBS_FIXEDSIZE))
|
|
SHSetWindowBits(prbbi->hwndChild, GWL_STYLE, WS_TABSTOP, WS_TABSTOP);
|
|
}
|
|
|
|
//*** cbs::_IsEnableTitle -- should we enable (ungray) title
|
|
// DESCRIPTION
|
|
// used for handing back title and for enabling menu
|
|
// NOTES
|
|
// pbid unused...
|
|
//
|
|
#ifndef UNIX
|
|
_inline
|
|
#endif
|
|
BOOL CBandSite::_IsEnableTitle(CBandItemData *pbid)
|
|
{
|
|
ASSERT(pbid);
|
|
return (/*pbid && !pbid->fNoTitle &&*/
|
|
!((_dwMode & DBIF_VIEWMODE_FLOATING) && _GetBandItemCount() <= 1));
|
|
}
|
|
|
|
BOOL CBandSite::_UpdateBandInfo(CBandItemData *pbid, BOOL fBSOnly)
|
|
{
|
|
REBARBANDINFO rbbi = {sizeof(rbbi)};
|
|
int iRB = _BandIDToIndex(pbid->dwBandID);
|
|
|
|
// now update the info
|
|
rbbi.fMask = RBBIM_ID | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
|
|
if (fBSOnly)
|
|
rbbi.fMask = RBBIM_STYLE;
|
|
|
|
SendMessage(_hwnd, RB_GETBANDINFO, iRB, (LPARAM)&rbbi);
|
|
|
|
if (!fBSOnly)
|
|
{
|
|
if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
|
|
{
|
|
pbid->ptActual.x = rbbi.cyChild;
|
|
pbid->ptActual.y = rbbi.cxIdeal;
|
|
}
|
|
else
|
|
{
|
|
pbid->ptActual.x = rbbi.cxIdeal;
|
|
pbid->ptActual.y = rbbi.cyChild;
|
|
}
|
|
pbid->ptMinSize.x = rbbi.cxMinChild;
|
|
pbid->ptMinSize.y = rbbi.cyMinChild;
|
|
pbid->ptMaxSize.y = rbbi.cyMaxChild;
|
|
}
|
|
|
|
TCHAR szBand[40];
|
|
rbbi.lpText = szBand;
|
|
rbbi.cch = ARRAYSIZE(szBand);
|
|
|
|
_BandInfoFromBandItem(&rbbi, pbid, fBSOnly);
|
|
|
|
return BOOLFROMPTR(SendMessage(_hwnd, RB_SETBANDINFO, (UINT)iRB, (LPARAM)&rbbi));
|
|
}
|
|
|
|
BOOL CBandSite::_AddBandItem(CBandItemData *pbid)
|
|
{
|
|
REBARBANDINFO rbbi = {sizeof(rbbi)};
|
|
|
|
pbid->ptActual.x = -1;
|
|
pbid->ptActual.y = -1;
|
|
|
|
TCHAR szBand[40];
|
|
rbbi.lpText = szBand;
|
|
rbbi.cch = ARRAYSIZE(szBand);
|
|
|
|
_BandInfoFromBandItem(&rbbi, pbid, FALSE);
|
|
|
|
rbbi.cyChild = pbid->ptActual.y;
|
|
rbbi.fMask |= RBBIM_LPARAM;
|
|
rbbi.lParam = (LPARAM)pbid;
|
|
|
|
ASSERT(rbbi.fMask & RBBIM_ID);
|
|
|
|
return BOOLFROMPTR(SendMessage(_hwnd, RB_INSERTBAND, (UINT) (pbid->dwModeFlags & DBIMF_ADDTOFRONT) ? 0 : -1, (LPARAM)&rbbi));
|
|
}
|
|
|
|
void CBandSite::_DeleteBandItem(int i)
|
|
{
|
|
SendMessage(_hwnd, RB_DELETEBAND, i, 0);
|
|
}
|
|
|
|
DWORD CBandSite::_IndexToBandID(int i)
|
|
{
|
|
REBARBANDINFO rbbi = {sizeof(rbbi)};
|
|
rbbi.fMask = RBBIM_ID;
|
|
|
|
if (SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi))
|
|
return rbbi.wID;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Given the band ID, returns the internal band index.
|
|
|
|
*/
|
|
int CBandSite::_BandIDToIndex(DWORD dwBandID)
|
|
{
|
|
int nRet = -1;
|
|
|
|
if (_hwnd)
|
|
nRet = (int)SendMessage(_hwnd, RB_IDTOINDEX, (WPARAM) dwBandID, (LPARAM) 0);
|
|
return nRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: The Parent Site may want to override what the admin
|
|
specified.
|
|
|
|
Return Values:
|
|
S_OK: Do lock band.
|
|
S_FALSE: Do NOT Lock band.
|
|
|
|
*/
|
|
HRESULT CBandSite::_IsRestricted(DWORD dwBandID, DWORD dwRestrictAction, DWORD dwBandFlags)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwRestrictionAction;
|
|
|
|
hr = IUnknown_HandleIRestrict(_punkSite, &RID_RDeskBars, dwRestrictAction, NULL, &dwRestrictionAction);
|
|
if (RR_NOCHANGE == dwRestrictionAction) // If our parent didn't handle it, we will.
|
|
dwRestrictionAction = IsFlagSet(_GetAdminSettings(dwBandID), dwBandFlags) ? RR_DISALLOW : RR_ALLOW;
|
|
|
|
if (RR_DISALLOW == dwRestrictionAction)
|
|
hr = S_OK;
|
|
else
|
|
hr = S_FALSE;
|
|
|
|
ASSERT(SUCCEEDED(hr)); // FAIL(hr) other than hr == E_NOTIMPLE; is not good.
|
|
return hr;
|
|
}
|
|
|
|
BOOL ConfirmRemoveBand(HWND hwnd, UINT uID, LPCTSTR pszName)
|
|
{
|
|
TCHAR szTemp[1024], szTitle[80];
|
|
BOOL bRet = TRUE;
|
|
|
|
MLLoadString(IDS_CONFIRMCLOSETITLE, szTitle, ARRAYSIZE(szTitle));
|
|
|
|
// Calling FormatMessage with FORMAT_MESSAGE_FROM_HMODULE fails
|
|
MLLoadString(uID, szTemp, ARRAYSIZE(szTemp));
|
|
|
|
DWORD cchLen = lstrlen(szTemp) + lstrlen(pszName) + 1;
|
|
LPTSTR pszTemp2 = (TCHAR *)LocalAlloc(LPTR, cchLen * sizeof(TCHAR));
|
|
if (pszTemp2 != NULL)
|
|
{
|
|
_FormatMessage(szTemp, pszTemp2, cchLen, pszName);
|
|
|
|
MLLoadString(IDS_CONFIRMCLOSETEXT, szTemp, ARRAYSIZE(szTemp));
|
|
|
|
cchLen = lstrlen(szTemp) + lstrlen(pszTemp2) + 1;
|
|
LPTSTR pszStr = (TCHAR *)LocalAlloc(LPTR, cchLen * sizeof(TCHAR));
|
|
if (pszStr != NULL)
|
|
{
|
|
_FormatMessage(szTemp, pszStr, cchLen, pszTemp2);
|
|
|
|
bRet = (IDOK == SHMessageBoxCheck(hwnd, pszStr, szTitle, MB_OKCANCEL, IDOK, TEXT("WarnBeforeCloseBand")));
|
|
|
|
LocalFree(pszStr);
|
|
}
|
|
|
|
LocalFree(pszTemp2);
|
|
}
|
|
|
|
return bRet;
|
|
}
|