1602 lines
45 KiB
C++
1602 lines
45 KiB
C++
#include "shellprv.h"
|
|
#include "clsobj.h"
|
|
#include "basebar.h"
|
|
#include "bands.h"
|
|
#include "menubar.h"
|
|
#include "menuband.h"
|
|
#include "isfband.h"
|
|
#include "util.h"
|
|
#include "apithk.h"
|
|
|
|
#undef WINEVENT_VALID //It's tripping on this...
|
|
#include "winable.h"
|
|
#include "oleacc.h"
|
|
|
|
#ifdef UNIX
|
|
#include "unixstuff.h"
|
|
#endif
|
|
|
|
#define THISCLASS CMenuDeskBar
|
|
#define SUPERCLASS CBaseBar
|
|
|
|
|
|
// Don't fade the menu if it's larger than this magical number. Based on experiments
|
|
// on a Pentium II - 233
|
|
#define MAGICAL_NO_FADE_HEIGHT 600
|
|
|
|
// For TraceMsg
|
|
#define DM_POPUP DM_TRACE
|
|
|
|
#define UP 0
|
|
#define DOWN 1
|
|
#define LEFT 2
|
|
#define RIGHT 3
|
|
|
|
#ifdef ENABLE_CHANNELS
|
|
IDeskBand * ChannelBand_Create(LPCITEMIDLIST pidl);
|
|
#endif // ENABLE_CHANNELS
|
|
|
|
STDAPI CMenuDeskBar_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv)
|
|
{
|
|
// aggregation checking is handled in class factory
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
CMenuDeskBar *pwbar = new CMenuDeskBar();
|
|
if (pwbar)
|
|
{
|
|
hr = pwbar->QueryInterface(riid, ppv);
|
|
pwbar->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
CMenuDeskBar::CMenuDeskBar() : SUPERCLASS()
|
|
{
|
|
_dwMode = DBIF_VIEWMODE_VERTICAL;
|
|
|
|
_iIconSize = BMICON_SMALL;
|
|
}
|
|
|
|
CMenuDeskBar::~CMenuDeskBar()
|
|
{
|
|
SetSite(NULL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CMenuDeskBar::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
HRESULT hres;
|
|
static const QITAB qit[] = {
|
|
QITABENT(THISCLASS, IMenuPopup),
|
|
QITABENT(THISCLASS, IObjectWithSite),
|
|
QITABENT(THISCLASS, IBanneredBar),
|
|
QITABENT(THISCLASS, IInitializeObject),
|
|
{ 0 },
|
|
};
|
|
|
|
hres = QISearch(this, (LPCQITAB)qit, riid, ppvObj);
|
|
if (FAILED(hres))
|
|
hres = SUPERCLASS::QueryInterface(riid, ppvObj);
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IMenuPopup::SetSubmenu method
|
|
|
|
*/
|
|
STDMETHODIMP CMenuDeskBar::SetSubMenu(IMenuPopup* pmp, BOOL fSet)
|
|
{
|
|
if (fSet)
|
|
{
|
|
if (_pmpChild)
|
|
_pmpChild->Release();
|
|
|
|
_pmpChild = pmp;
|
|
_pmpChild->AddRef();
|
|
}
|
|
else
|
|
{
|
|
if (_pmpChild && SHIsSameObject(pmp, _pmpChild))
|
|
{
|
|
_pmpChild->Release();
|
|
_pmpChild = NULL;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
void CMenuDeskBar::_PopDown()
|
|
{
|
|
DAD_ShowDragImage(FALSE);
|
|
if (_pmpChild)
|
|
_pmpChild->OnSelect(MPOS_CANCELLEVEL);
|
|
|
|
// ShowWindow(_hwnd, SW_HIDE);
|
|
SetWindowPos(_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
|
|
ShowDW(FALSE);
|
|
if (_pmpParent)
|
|
{
|
|
_pmpParent->SetSubMenu(this, FALSE);
|
|
}
|
|
UIActivateIO(FALSE, NULL);
|
|
_fActive = FALSE;
|
|
DAD_ShowDragImage(TRUE);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IMenuPopup::OnSelect method
|
|
|
|
*/
|
|
STDMETHODIMP CMenuDeskBar::OnSelect(DWORD dwSelectType)
|
|
{
|
|
switch (dwSelectType)
|
|
{
|
|
case MPOS_CHILDTRACKING:
|
|
if (_pmpParent)
|
|
_pmpParent->OnSelect(dwSelectType);
|
|
break;
|
|
|
|
case MPOS_SELECTRIGHT:
|
|
case MPOS_SELECTLEFT:
|
|
if (_pmpParent)
|
|
_pmpParent->OnSelect(dwSelectType);
|
|
break;
|
|
|
|
case MPOS_EXECUTE:
|
|
case MPOS_FULLCANCEL:
|
|
_PopDown();
|
|
if (_pmpParent)
|
|
_pmpParent->OnSelect(dwSelectType);
|
|
break;
|
|
|
|
case MPOS_CANCELLEVEL:
|
|
_PopDown();
|
|
break;
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void SetExpandedBorder(HWND hwnd, BOOL fExpanded)
|
|
{
|
|
#ifdef MAINWIN
|
|
// IEUNIX : WS_DLGFRAME implementaion looks ugly on UNIX.
|
|
fExpanded = TRUE;
|
|
#endif
|
|
|
|
DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
|
|
DWORD dwExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
|
|
|
if (fExpanded)
|
|
{
|
|
dwStyle |= WS_BORDER;
|
|
dwStyle &= ~WS_DLGFRAME;
|
|
}
|
|
else
|
|
{
|
|
dwStyle &= ~WS_BORDER;
|
|
dwStyle |= WS_DLGFRAME;
|
|
}
|
|
|
|
SetWindowLong(hwnd, GWL_STYLE, dwStyle);
|
|
SetWindowLong(hwnd, GWL_EXSTYLE, dwExStyle);
|
|
|
|
SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
|
|
SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
|
|
UpdateWindow(hwnd);
|
|
}
|
|
|
|
void CMenuDeskBar::_OnCreate()
|
|
{
|
|
if (!_fFlatMenuMode)
|
|
SetExpandedBorder(_hwnd, _fExpanded);
|
|
}
|
|
|
|
|
|
DWORD CMenuDeskBar::_GetClassStyle()
|
|
{
|
|
DWORD dwStyle = CS_SAVEBITS; // Faster repaint for menus when they go away
|
|
|
|
if (IsOS(OS_WHISTLERORGREATER))
|
|
{
|
|
dwStyle |= CS_DROPSHADOW; // Cool dropshadow effect on whistler....
|
|
}
|
|
|
|
return dwStyle;
|
|
}
|
|
|
|
DWORD CMenuDeskBar::_GetExStyle()
|
|
{
|
|
#ifndef MAINWIN
|
|
return WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
|
|
#else
|
|
return WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_MW_UNMANAGED_WINDOW;
|
|
#endif
|
|
}
|
|
|
|
// We use the following structure to pass a whole bunch of information from
|
|
// the GetPopupWindowPosition to WillFit function. We have WillFit function
|
|
// to cut the amount of duplicate code in getpopup window position. The order
|
|
// in which different the sides are checked is the only difference for popping
|
|
// up a window on a particular side.
|
|
//
|
|
// Having this function helps us to do that check by means of a parameter instead
|
|
// of repeating portions of code again and again.
|
|
|
|
typedef struct {
|
|
RECT rcAvail; // Available dimensions b/t monitor edge and exclude edge
|
|
SIZE sizeAdjust; // Size of menu edge
|
|
int cyMonitor; // Size of monitor
|
|
int cxMonitor;
|
|
int cx; // Size of menu
|
|
int cy;
|
|
int cyExtendDiff; // Difference b/t calc'd size and available size
|
|
RECT *prcResult;
|
|
RECT *prcExclude; // Exclude rect
|
|
RECT *prcMonitor;
|
|
} PopupInfo;
|
|
|
|
#define TOP 0
|
|
#define BOTTOM 1
|
|
#define LEFT 2
|
|
#define RIGHT 3
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Attempt to fit and position a menu in the given direction
|
|
relative to an exclude rect.
|
|
|
|
Setting fForce to TRUE will cause the menu size to be adjusted
|
|
to fit, if necessary.
|
|
|
|
This function only sets the top and left coords, not the bottom
|
|
and right coords.
|
|
|
|
Returns TRUE if the desired direction can be accomplished.
|
|
|
|
*/
|
|
BOOL WillFit(PopupInfo * pinfo, int side, BOOL fForce)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
LPRECT prcResult = pinfo->prcResult;
|
|
|
|
pinfo->cyExtendDiff = 0;
|
|
|
|
switch(side)
|
|
{
|
|
case TOP:
|
|
pinfo->cyExtendDiff = pinfo->cy - pinfo->rcAvail.top;
|
|
if (fForce)
|
|
{
|
|
// Doesn't make sense to subtract a negative value
|
|
ASSERT(pinfo->cyExtendDiff >= 0);
|
|
|
|
// +2 for some breathing room at the edge of the screen
|
|
pinfo->cy -= pinfo->cyExtendDiff + 2;
|
|
}
|
|
|
|
// Can the menu be positioned above?
|
|
if (pinfo->cy <= pinfo->rcAvail.top)
|
|
{
|
|
// Yes
|
|
prcResult->top = pinfo->prcExclude->top - pinfo->cy;
|
|
|
|
goto AdjustHorzPos;
|
|
}
|
|
break;
|
|
|
|
case BOTTOM:
|
|
pinfo->cyExtendDiff = pinfo->cy - pinfo->rcAvail.bottom;
|
|
if (fForce)
|
|
{
|
|
// Doesn't make sense to subtract a negative value
|
|
ASSERT(pinfo->cyExtendDiff >= 0);
|
|
|
|
// +2 for some breathing room at the edge of the screen
|
|
pinfo->cy -= pinfo->cyExtendDiff + 2;
|
|
}
|
|
|
|
// Can the menu be positioned below?
|
|
if (pinfo->cy <= pinfo->rcAvail.bottom)
|
|
{
|
|
// Yes
|
|
prcResult->top = pinfo->prcExclude->bottom;
|
|
|
|
AdjustHorzPos:
|
|
prcResult->left = max(pinfo->prcExclude->left, pinfo->prcMonitor->left);
|
|
|
|
// Can the menu be positioned relative to its left edge (hanging right)?
|
|
if (prcResult->left + pinfo->cx >= pinfo->prcMonitor->right)
|
|
{
|
|
// No; move it in so it is on the screen
|
|
// (cx has already been adjusted to fit inside the monitor dimensions)
|
|
prcResult->left = pinfo->prcMonitor->right - pinfo->cx - 1;
|
|
}
|
|
bRet = TRUE;
|
|
}
|
|
break;
|
|
|
|
case LEFT:
|
|
// Can the menu be positioned to the left?
|
|
if (pinfo->cx <= pinfo->rcAvail.left || fForce)
|
|
{
|
|
// Yes
|
|
|
|
// When cascading left, the menu does not overlap. Also align
|
|
// so the client rect is vertically aligned with the exclude top.
|
|
prcResult->left = pinfo->prcExclude->left - pinfo->cx - 1;
|
|
|
|
goto AdjustVerticalPos;
|
|
}
|
|
break;
|
|
|
|
case RIGHT:
|
|
// Can the menu be positioned to the right?
|
|
if (pinfo->cx <= pinfo->rcAvail.right || fForce)
|
|
{
|
|
// Yes
|
|
|
|
// Adjust the menu to slightly overlap the parent menu. Also align
|
|
// so the client rect is vertically aligned with the exclude top.
|
|
prcResult->left = pinfo->prcExclude->right - pinfo->sizeAdjust.cx;
|
|
|
|
AdjustVerticalPos:
|
|
prcResult->top = pinfo->prcExclude->top - pinfo->sizeAdjust.cy;
|
|
|
|
// Can the menu be positioned relative to its top edge (hanging down)?
|
|
if (prcResult->top + pinfo->cy >= pinfo->prcMonitor->bottom)
|
|
{
|
|
// No; can it be positioned relative to its bottom edge (hanging up)?
|
|
prcResult->top = pinfo->prcExclude->bottom + pinfo->sizeAdjust.cy - pinfo->cy;
|
|
|
|
if (prcResult->top < pinfo->prcMonitor->top)
|
|
{
|
|
// No; move the menu so it fits, but isn't vertically snapped.
|
|
// (cy has already been adjusted to fit inside the monitor
|
|
// dimensions)
|
|
prcResult->top = pinfo->prcMonitor->bottom - pinfo->cy - 1;
|
|
}
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
}
|
|
break;
|
|
}
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
void CMenuDeskBar::_GetPopupWindowPosition(RECT* prcDesired, RECT* prcExclude,
|
|
RECT *prcResult, SIZE * psizeAdjust, UINT uSide)
|
|
{
|
|
PopupInfo info;
|
|
MONITORINFO mi;
|
|
HMONITOR hMonitor;
|
|
RECT rcMonitor;
|
|
int cyExtendDiff = 0;
|
|
|
|
// Is this going to display the banner bitmap?
|
|
if (_iIconSize == BMICON_LARGE)
|
|
{
|
|
// Yes; add that to the dimensions
|
|
prcDesired->right += _sizeBmp.cx;
|
|
}
|
|
|
|
// First get the monitor information
|
|
hMonitor = MonitorFromRect(prcExclude, MONITOR_DEFAULTTONEAREST);
|
|
mi.cbSize = sizeof(mi);
|
|
if (GetMonitorInfo(hMonitor, &mi))
|
|
{
|
|
rcMonitor = mi.rcMonitor;
|
|
|
|
// Set the result rectangle same as the desired window
|
|
prcResult->left = prcDesired->left;
|
|
prcResult->top = prcDesired->top;
|
|
|
|
// Calculate some sizes needed for calculation
|
|
info.rcAvail.left = prcExclude->left - rcMonitor.left;
|
|
info.rcAvail.right = rcMonitor.right - prcExclude->right;
|
|
info.rcAvail.top = prcExclude->top - rcMonitor.top;
|
|
info.rcAvail.bottom = rcMonitor.bottom - prcExclude->bottom;
|
|
|
|
info.sizeAdjust = *psizeAdjust;
|
|
|
|
info.cyMonitor = RECTHEIGHT(rcMonitor);
|
|
info.cxMonitor = RECTWIDTH(rcMonitor);
|
|
|
|
info.cx = RECTWIDTH(*prcDesired);
|
|
info.cy = RECTHEIGHT(*prcDesired);
|
|
|
|
// If the desired rect is bigger than monitor then clip it to the monitor size
|
|
if (info.cy > info.cyMonitor)
|
|
info.cy = info.cyMonitor;
|
|
|
|
if (info.cx > info.cxMonitor)
|
|
info.cx = info.cxMonitor;
|
|
|
|
info.prcResult = prcResult;
|
|
info.prcExclude = prcExclude;
|
|
info.prcMonitor = &rcMonitor;
|
|
|
|
//Now Adjust the rectangle for the correct position
|
|
switch(uSide)
|
|
{
|
|
int iSide;
|
|
|
|
case MENUBAR_TOP:
|
|
|
|
if (WillFit(&info, TOP, FALSE))
|
|
{
|
|
_uSide = MENUBAR_TOP;
|
|
}
|
|
else
|
|
{
|
|
// We couldn't fit it above, how badly did we fall short?
|
|
cyExtendDiff = info.cyExtendDiff;
|
|
if (WillFit(&info, BOTTOM, FALSE))
|
|
_uSide = MENUBAR_BOTTOM;
|
|
// We can't fit it below either, which dir was closest?
|
|
// If they are equal, default to requested direction
|
|
else if (info.cyExtendDiff < cyExtendDiff)
|
|
{
|
|
_uSide = MENUBAR_BOTTOM;
|
|
WillFit(&info, BOTTOM, TRUE);
|
|
}
|
|
else
|
|
{
|
|
_uSide = MENUBAR_TOP;
|
|
WillFit(&info, TOP, TRUE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MENUBAR_BOTTOM:
|
|
|
|
if (WillFit(&info, BOTTOM, FALSE))
|
|
{
|
|
_uSide = MENUBAR_BOTTOM;
|
|
}
|
|
else
|
|
{
|
|
// We couldn't fit it below, how badly did we fall short?
|
|
cyExtendDiff = info.cyExtendDiff;
|
|
if (WillFit(&info, TOP, FALSE))
|
|
_uSide = MENUBAR_TOP;
|
|
|
|
// We can't fit it above either, which dir was closest?
|
|
// If they are equal, default to requested direction
|
|
else if (info.cyExtendDiff < cyExtendDiff)
|
|
{
|
|
_uSide = MENUBAR_TOP;
|
|
WillFit(&info, TOP, TRUE);
|
|
}
|
|
else
|
|
{
|
|
_uSide = MENUBAR_BOTTOM;
|
|
WillFit(&info, BOTTOM, TRUE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MENUBAR_LEFT:
|
|
|
|
if (WillFit(&info, LEFT, FALSE))
|
|
{
|
|
_uSide = MENUBAR_LEFT;
|
|
}
|
|
else if (WillFit(&info, RIGHT, FALSE))
|
|
{
|
|
_uSide = MENUBAR_RIGHT;
|
|
}
|
|
else
|
|
{
|
|
// fit where have most room and can show most of menu.
|
|
|
|
if ((info.cx - (info.prcExclude)->right) > (info.prcExclude)->left)
|
|
{
|
|
_uSide = MENUBAR_RIGHT;
|
|
iSide = RIGHT;
|
|
}
|
|
else
|
|
{
|
|
_uSide = MENUBAR_LEFT;
|
|
iSide = LEFT;
|
|
}
|
|
WillFit(&info, iSide, TRUE);
|
|
}
|
|
break;
|
|
|
|
case MENUBAR_RIGHT:
|
|
|
|
if (WillFit(&info, RIGHT, FALSE))
|
|
{
|
|
_uSide = MENUBAR_RIGHT;
|
|
}
|
|
else if (WillFit(&info, LEFT, FALSE))
|
|
{
|
|
_uSide = MENUBAR_LEFT;
|
|
}
|
|
else
|
|
{
|
|
// fit where have most room and can show most of menu.
|
|
|
|
if ((info.cx - (info.prcExclude)->right) >= (info.prcExclude)->left)
|
|
{
|
|
_uSide = MENUBAR_RIGHT;
|
|
iSide = RIGHT;
|
|
}
|
|
else
|
|
{
|
|
_uSide = MENUBAR_LEFT;
|
|
iSide = LEFT;
|
|
}
|
|
WillFit(&info, iSide, TRUE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Finally set the bottom and right
|
|
|
|
if (prcResult->top < rcMonitor.top)
|
|
prcResult->top = rcMonitor.top;
|
|
if (prcResult->left < rcMonitor.left)
|
|
prcResult->left = rcMonitor.left;
|
|
|
|
prcResult->bottom = prcResult->top + info.cy;
|
|
prcResult->right = prcResult->left + info.cx;
|
|
|
|
if (prcResult->bottom > rcMonitor.bottom)
|
|
{
|
|
// -2 for some breathing room at the edge of the screen
|
|
prcResult->bottom = rcMonitor.bottom - 2;
|
|
prcResult->top = prcResult->bottom - info.cy;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SlideAnimate(HWND hwnd, RECT* prc, UINT uFlags, UINT uSide)
|
|
{
|
|
DWORD dwAnimateFlags = AW_CENTER;
|
|
switch(uSide)
|
|
{
|
|
case MENUBAR_LEFT: dwAnimateFlags = AW_HOR_NEGATIVE;
|
|
break;
|
|
case MENUBAR_RIGHT: dwAnimateFlags = AW_HOR_POSITIVE;
|
|
break;
|
|
case MENUBAR_TOP: dwAnimateFlags = AW_VER_NEGATIVE;
|
|
break;
|
|
case MENUBAR_BOTTOM: dwAnimateFlags = AW_VER_POSITIVE;
|
|
break;
|
|
}
|
|
AnimateWindow(hwnd, 120, dwAnimateFlags | AW_SLIDE);
|
|
}
|
|
|
|
void AnimateSetMenuPos(HWND hwnd, RECT* prc, UINT uFlags, UINT uSide, BOOL fNoAnimate)
|
|
{
|
|
// simple check to see if we're too big for animatewindow, based on menu area.
|
|
// this is because it has to read from video mem to do the alpha and thats slow, maybe
|
|
// let it back if we get hardware acceleration in a future release.
|
|
BOOL fPerfBad = (RECTWIDTH(*prc) * RECTHEIGHT(*prc) > 600 * 200);
|
|
if (!fNoAnimate && !fPerfBad)
|
|
{
|
|
BOOL fAnimate = FALSE;
|
|
SystemParametersInfo(SPI_GETMENUANIMATION, 0, &fAnimate, 0);
|
|
if (fAnimate)
|
|
{
|
|
SetWindowPos(hwnd, HWND_TOPMOST, prc->left, prc->top,
|
|
RECTWIDTH(*prc), RECTHEIGHT(*prc), uFlags);
|
|
|
|
fAnimate = FALSE;
|
|
SystemParametersInfo(SPI_GETMENUFADE, 0, &fAnimate, 0);
|
|
if (fAnimate)
|
|
{
|
|
AnimateWindow(hwnd, 175, AW_BLEND);
|
|
}
|
|
else
|
|
{
|
|
SlideAnimate(hwnd, prc, uFlags, uSide);
|
|
}
|
|
}
|
|
else
|
|
goto UseSetWindowPos;
|
|
}
|
|
else
|
|
{
|
|
UseSetWindowPos:
|
|
// Enable the show window so that it gets displayed.
|
|
uFlags |= SWP_SHOWWINDOW;
|
|
|
|
SetWindowPos(hwnd, HWND_TOPMOST, prc->left, prc->top, RECTWIDTH(*prc), RECTHEIGHT(*prc),
|
|
uFlags);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HRESULT CMenuDeskBar::_PositionWindow(POINTL *ppt, RECTL* prcExclude, DWORD dwFlags)
|
|
{
|
|
ASSERT(IS_VALID_READ_PTR(ppt, POINTL));
|
|
ASSERT(NULL == prcExclude || IS_VALID_READ_PTR(prcExclude, RECTL));
|
|
|
|
BOOL bSetFocus = (dwFlags & MPPF_SETFOCUS);
|
|
RECT rcDesired;
|
|
RECT rcExclude;
|
|
RECT rc;
|
|
SIZE sizeAdjust;
|
|
UINT uAnimateSide;
|
|
|
|
BOOL bMirroredWindow=IS_WINDOW_RTL_MIRRORED(_hwnd);
|
|
|
|
static const iPosition[] = {MENUBAR_TOP, MENUBAR_LEFT, MENUBAR_RIGHT, MENUBAR_BOTTOM};
|
|
|
|
if (dwFlags & MPPF_POS_MASK)
|
|
{
|
|
UINT uPosIndex = ((dwFlags & MPPF_POS_MASK) >> 29) - 1;
|
|
ASSERT(uPosIndex < 4);
|
|
_uSide = iPosition[uPosIndex];
|
|
}
|
|
|
|
if (bSetFocus)
|
|
SetForegroundWindow(_hwnd);
|
|
|
|
_pt = *(POINT*)ppt;
|
|
|
|
// Get the size of the ideal client rect of the child
|
|
RECT rcChild = {0};
|
|
|
|
// (scotth): This only sets the bottom and the right values
|
|
_pDBC->GetSize(DBC_GS_IDEAL, &rcChild);
|
|
|
|
DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
|
|
DWORD dwExStyle = GetWindowLong(_hwnd, GWL_EXSTYLE);
|
|
|
|
// Adjust for the window border style
|
|
rcDesired = rcChild; // use rcDesired as a temp variable
|
|
if (!_fNoBorder)
|
|
{
|
|
AdjustWindowRectEx(&rcChild, dwStyle, FALSE, dwExStyle);
|
|
}
|
|
|
|
// Calculate the edge of the menu border, and add a fudge factor so
|
|
// left/right-cascaded menus overlap the parent menu a bit and are
|
|
// correctly aligned vertically.
|
|
|
|
sizeAdjust.cx = (RECTWIDTH(rcChild) - RECTWIDTH(rcDesired)) / 2;
|
|
sizeAdjust.cy = (RECTHEIGHT(rcChild) - RECTHEIGHT(rcDesired)) / 2;
|
|
|
|
if (prcExclude)
|
|
{
|
|
CopyRect(&rcExclude, (RECT*)prcExclude);
|
|
|
|
//
|
|
// If mirroring is enabled, let's mirror this guy
|
|
// by simulating a different mirrored rect. This is
|
|
// only for dropdown menus. [samera]
|
|
//
|
|
if (bMirroredWindow)
|
|
{
|
|
if ((_uSide != MENUBAR_LEFT) &&
|
|
(_uSide != MENUBAR_RIGHT) )
|
|
{
|
|
int x;
|
|
int iW = rcExclude.right-rcExclude.left;
|
|
int icW = (rcChild.right-rcChild.left);
|
|
|
|
|
|
if( icW > iW )
|
|
{
|
|
x = icW - iW;
|
|
rcExclude.left -= x ;
|
|
rcExclude.right -= x ;
|
|
}
|
|
else
|
|
{
|
|
x = iW - icW;
|
|
rcExclude.left += x;
|
|
rcExclude.right += x;
|
|
}
|
|
|
|
ppt->x = rcExclude.left;
|
|
}
|
|
|
|
}
|
|
|
|
TraceMsg(DM_POPUP, "Parent Side is %d ", _uSide);
|
|
switch(_uSide)
|
|
{
|
|
case MENUBAR_LEFT :
|
|
rcDesired.left = rcExclude.left - rcChild.right; // right is width
|
|
rcDesired.top = rcExclude.top;
|
|
break;
|
|
|
|
case MENUBAR_RIGHT :
|
|
rcDesired.left = rcExclude.right;
|
|
rcDesired.top = rcExclude.top;
|
|
break;
|
|
|
|
case MENUBAR_TOP:
|
|
rcDesired.left = rcExclude.left;
|
|
rcDesired.top = rcExclude.top - rcChild.bottom; // bottom is height
|
|
break;
|
|
|
|
case MENUBAR_BOTTOM:
|
|
rcDesired.left = rcExclude.left;
|
|
rcDesired.top = rcExclude.bottom;
|
|
break;
|
|
|
|
default:
|
|
rcDesired.left = _pt.x;
|
|
rcDesired.top = _pt.y;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetRectEmpty(&rcExclude);
|
|
|
|
rcDesired.left = _pt.x;
|
|
rcDesired.top = _pt.y;
|
|
}
|
|
|
|
rcDesired.right = rcDesired.left + RECTWIDTH(rcChild);
|
|
rcDesired.bottom = rcDesired.top + RECTHEIGHT(rcChild);
|
|
|
|
_GetPopupWindowPosition(&rcDesired, &rcExclude, &rc, &sizeAdjust, _uSide);
|
|
|
|
UINT uFlags = SWP_NOOWNERZORDER;
|
|
if (!bSetFocus)
|
|
uFlags |= SWP_NOACTIVATE;
|
|
|
|
//
|
|
// Open the menus properly. In case of a RTL mirrored window,
|
|
// flip the animation side. [samera]
|
|
//
|
|
if( bMirroredWindow )
|
|
{
|
|
switch( _uSide )
|
|
{
|
|
case MENUBAR_LEFT:
|
|
uAnimateSide = MENUBAR_RIGHT;
|
|
break;
|
|
case MENUBAR_RIGHT:
|
|
uAnimateSide = MENUBAR_LEFT;
|
|
break;
|
|
default:
|
|
uAnimateSide = _uSide;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uAnimateSide = _uSide;
|
|
}
|
|
|
|
TraceMsg(TF_MENUBAND, "CMenuBar::_PositionWindow (%d,%d,%d,%d)",
|
|
rc.left, rc.top, rc.right, rc.bottom);
|
|
|
|
// Last minuite tweak. Since we're in large icon, we need to add this
|
|
// so that the bitmap is painted correctly.
|
|
if(_iIconSize == BMICON_LARGE && _fExpanded)
|
|
rc.right += 1;
|
|
|
|
// We _DO_ want to do a Z-Order position when this flag is specified. This is
|
|
// for full repositioning where we need to preserve the overlap state of all bands.
|
|
// Otherwize we just want to size the bar without changing it's z-order.
|
|
if (!(dwFlags & MPPF_FORCEZORDER) &&
|
|
(S_OK == IUnknown_QueryServiceExec(_punkChild, SID_SMenuBandChild,
|
|
&CGID_MenuBand, MBANDCID_ISINSUBMENU, 0, NULL, NULL)))
|
|
{
|
|
uFlags |= SWP_NOZORDER;
|
|
}
|
|
|
|
// If it's bigger than this magical number, then we don't animate. change to taste
|
|
|
|
if (RECTHEIGHT(rc) > MAGICAL_NO_FADE_HEIGHT)
|
|
dwFlags |= MPPF_NOANIMATE;
|
|
|
|
AnimateSetMenuPos(_hwnd, &rc, uFlags, uAnimateSide, dwFlags & MPPF_NOANIMATE);
|
|
|
|
// Save information so we can later resize this window
|
|
// We already have: _pt, _uSide
|
|
if (prcExclude)
|
|
{
|
|
_fExcludeRect = TRUE;
|
|
CopyRect(&_rcExclude, (RECT*)prcExclude);
|
|
}
|
|
else
|
|
_fExcludeRect = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IMenuPopup::Popup method
|
|
|
|
*/
|
|
STDMETHODIMP CMenuDeskBar::Popup(POINTL* ppt, RECTL* prcExclude, DWORD dwFlags)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Is the caller telling us to reposition?
|
|
if (dwFlags & MPPF_REPOSITION)
|
|
{
|
|
if (ppt == NULL)
|
|
ppt = (POINTL*)&_pt;
|
|
|
|
if (prcExclude == NULL)
|
|
prcExclude = (RECTL*)&_rcExclude;
|
|
|
|
// Yes; Then we don't need to do any First show stuff.
|
|
_PositionWindow(ppt, prcExclude, dwFlags);
|
|
return S_OK;
|
|
}
|
|
|
|
ASSERT(IS_VALID_READ_PTR(ppt, POINTL));
|
|
ASSERT(NULL == prcExclude || IS_VALID_READ_PTR(prcExclude, RECTL));
|
|
|
|
if (_pmpParent)
|
|
{
|
|
_pmpParent->SetSubMenu(this, TRUE);
|
|
}
|
|
|
|
IOleCommandTarget* poct;
|
|
hr = IUnknown_QueryService(_punkChild, SID_SMenuBandChild, IID_PPV_ARG(IOleCommandTarget, &poct));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// We need to do this before the ShowDW. This saves us from doing the setting twice
|
|
// Because in the ShowDW of MenuBand, we actually go an initialize the toolbar with
|
|
// the current default setting which should be "No Keyboard Cues." If we set the state
|
|
// here, then the state will be "Show keyboard cues." Then we will update the toolbar.
|
|
if (dwFlags & MPPF_KEYBOARD)
|
|
poct->Exec(&CGID_MenuBand, MBANDCID_KEYBOARD, 0, NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(poct == NULL);
|
|
}
|
|
|
|
_NotifyModeChange(_dwMode);
|
|
hr = ShowDW(TRUE);
|
|
|
|
if (SUCCEEDED(hr) && _pmpParent)
|
|
{
|
|
VARIANT varg;
|
|
// If this Exec fails, don't panic; it just means we use the default side
|
|
if (SUCCEEDED(IUnknown_Exec(_pmpParent, &CGID_MENUDESKBAR, MBCID_GETSIDE, 0, NULL, &varg)))
|
|
{
|
|
if (varg.vt == VT_I4)
|
|
{
|
|
_uSide = (UINT) varg.lVal;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SHPlaySound(TEXT("MenuPopup"));
|
|
|
|
_PositionWindow(ppt, prcExclude, dwFlags);
|
|
|
|
// Set focus
|
|
UIActivateIO(TRUE, NULL);
|
|
|
|
_fActive = TRUE;
|
|
|
|
// Select the first/last item?
|
|
if ((dwFlags & (MPPF_INITIALSELECT | MPPF_FINALSELECT)) && poct)
|
|
{
|
|
DWORD nCmd = (dwFlags & MPPF_INITIALSELECT) ? MBSI_FIRSTITEM : MBSI_LASTITEM;
|
|
poct->Exec(&CGID_MenuBand, MBANDCID_SELECTITEM, nCmd, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
ATOMICRELEASE(poct);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IInputObjectSite::OnFocusChangeIS
|
|
|
|
Returns:
|
|
Cond: --
|
|
*/
|
|
HRESULT CMenuDeskBar::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IObjectWithSite::SetSite method
|
|
|
|
*/
|
|
STDMETHODIMP CMenuDeskBar::SetSite(IUnknown* punkSite)
|
|
{
|
|
ASSERT(NULL == punkSite || IS_VALID_CODE_PTR(punkSite, IUnknown));
|
|
|
|
if (_fShow)
|
|
_PopDown();
|
|
|
|
ATOMICRELEASE(_punkSite);
|
|
ATOMICRELEASE(_pmpParent);
|
|
|
|
_punkSite = punkSite;
|
|
|
|
if (_punkSite)
|
|
{
|
|
_punkSite->AddRef();
|
|
IUnknown_QueryService(_punkSite, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &_pmpParent));
|
|
}
|
|
else
|
|
{
|
|
CloseDW(0);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IObjectWithSite::GetSite method
|
|
|
|
*/
|
|
STDMETHODIMP CMenuDeskBar::GetSite(REFIID riid, LPVOID* ppvSite)
|
|
{
|
|
if (_punkSite)
|
|
{
|
|
return _punkSite->QueryInterface(riid, ppvSite);
|
|
}
|
|
|
|
*ppvSite = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
void CMenuDeskBar::AdjustForTheme()
|
|
{
|
|
if (_fFlatMenuMode)
|
|
{
|
|
SHSetWindowBits(_hwnd, GWL_STYLE, WS_CLIPCHILDREN | WS_DLGFRAME | WS_BORDER, WS_BORDER);
|
|
}
|
|
else if (!_fExpanded)
|
|
{
|
|
SHSetWindowBits(_hwnd, GWL_STYLE, WS_CLIPCHILDREN | WS_DLGFRAME | WS_BORDER, WS_CLIPCHILDREN | WS_DLGFRAME);
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IOleCommandTarget::Exec method
|
|
|
|
*/
|
|
STDMETHODIMP CMenuDeskBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
|
|
VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
|
|
{
|
|
if (pguidCmdGroup == NULL)
|
|
{
|
|
|
|
}
|
|
else if (IsEqualGUID(CGID_DeskBarClient, *pguidCmdGroup))
|
|
{
|
|
switch (nCmdID)
|
|
{
|
|
case DBCID_EMPTY:
|
|
// if we have no bands left, close
|
|
OnSelect(MPOS_FULLCANCEL);
|
|
return S_OK;
|
|
|
|
default:
|
|
return OLECMDERR_E_NOTSUPPORTED;
|
|
}
|
|
}
|
|
|
|
else if (IsEqualGUID(CGID_MENUDESKBAR, *pguidCmdGroup))
|
|
{
|
|
switch(nCmdID)
|
|
{
|
|
case MBCID_GETSIDE :
|
|
pvarargOut->vt = VT_I4;
|
|
pvarargOut->lVal = _GetSide();
|
|
return S_OK;
|
|
|
|
case MBCID_RESIZE:
|
|
if (_fActive)
|
|
{
|
|
if (_fExcludeRect)
|
|
_PositionWindow((POINTL *)&_pt, (RECTL *)&_rcExclude, 0);
|
|
else
|
|
_PositionWindow((POINTL *)&_pt, NULL, 0);
|
|
}
|
|
return S_OK;
|
|
|
|
case MBCID_SETEXPAND:
|
|
if ((BOOL)_fExpanded != (BOOL)nCmdexecopt && !_fFlatMenuMode)
|
|
{
|
|
_fExpanded = nCmdexecopt;
|
|
|
|
SetExpandedBorder(_hwnd, _fExpanded);
|
|
}
|
|
return S_OK;
|
|
|
|
case MBCID_SETFLAT:
|
|
{
|
|
_fFlatMenuMode = BOOLIFY(nCmdexecopt);
|
|
AdjustForTheme();
|
|
}
|
|
break;
|
|
|
|
case MBCID_NOBORDER:
|
|
{
|
|
_fNoBorder = BOOLIFY(nCmdexecopt);
|
|
SetWindowPos(_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
|
|
}
|
|
break;
|
|
|
|
default :
|
|
return OLECMDERR_E_NOTSUPPORTED;
|
|
|
|
}
|
|
}
|
|
|
|
return SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IServiceProvider::QueryService method
|
|
|
|
*/
|
|
STDMETHODIMP CMenuDeskBar::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
|
|
{
|
|
if (IsEqualGUID(guidService, SID_SMenuPopup))
|
|
{
|
|
return QueryInterface(riid, ppvObj);
|
|
}
|
|
else if (IsEqualIID(guidService, SID_SMenuBandBottom) ||
|
|
IsEqualIID(guidService, SID_SMenuBandBottomSelected)||
|
|
IsEqualIID(guidService, SID_SMenuBandChild))
|
|
{
|
|
// SID_SMenuBandBottom queries down
|
|
return IUnknown_QueryService(_punkChild, guidService, riid, ppvObj);
|
|
}
|
|
else
|
|
{
|
|
HRESULT hres = SUPERCLASS::QueryService(guidService, riid, ppvObj);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
hres = IUnknown_QueryService(_punkSite, guidService, riid, ppvObj);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IServiceProvider::QueryService method
|
|
|
|
*/
|
|
STDMETHODIMP CMenuDeskBar::SetIconSize(DWORD iIcon)
|
|
{
|
|
HRESULT hres;
|
|
|
|
_iIconSize = iIcon;
|
|
|
|
hres = IUnknown_QueryServiceExec(_punkChild, SID_SMenuBandChild, &CGID_MenuBand,
|
|
MBANDCID_SETICONSIZE, iIcon == BMICON_SMALL? ISFBVIEWMODE_SMALLICONS: ISFBVIEWMODE_LARGEICONS, NULL, NULL);
|
|
|
|
|
|
return hres;
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IServiceProvider::QueryService method
|
|
|
|
*/
|
|
STDMETHODIMP CMenuDeskBar::SetBitmap(HBITMAP hBitmap)
|
|
{
|
|
ASSERT(hBitmap);
|
|
BITMAP bm;
|
|
_hbmp = hBitmap;
|
|
|
|
if (_hbmp)
|
|
{
|
|
if(!GetObject(_hbmp, sizeof(bm), &bm))
|
|
return E_FAIL;
|
|
_sizeBmp.cx = bm.bmWidth;
|
|
_sizeBmp.cy = bm.bmHeight;
|
|
|
|
// Hack to get color
|
|
HDC hdc = GetDC(_hwnd);
|
|
if (hdc)
|
|
{
|
|
HDC hdcMem = CreateCompatibleDC(hdc);
|
|
if (hdcMem)
|
|
{
|
|
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, _hbmp);
|
|
_rgb = GetPixel(hdcMem, 0, 0);
|
|
SelectObject(hdcMem, hbmpOld);
|
|
DeleteDC(hdcMem);
|
|
}
|
|
ReleaseDC(_hwnd, hdc);
|
|
}
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void CMenuDeskBar::_OnSize()
|
|
{
|
|
RECT rc;
|
|
|
|
if (!_hwndChild)
|
|
return;
|
|
|
|
GetClientRect(_hwnd, &rc);
|
|
|
|
if(_iIconSize == BMICON_LARGE)
|
|
{
|
|
rc.left += _sizeBmp.cx;
|
|
if (_fExpanded)
|
|
rc.left++;
|
|
}
|
|
|
|
SetWindowPos(_hwndChild, 0,
|
|
rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc),
|
|
SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED);
|
|
|
|
rc.right = rc.left;
|
|
rc.left -= _sizeBmp.cx;
|
|
if (_fShow)
|
|
InvalidateRect(_hwnd, &rc, TRUE);
|
|
}
|
|
|
|
LRESULT CMenuDeskBar::_DoPaint(HWND hwnd, HDC hdc, DWORD dwFlags)
|
|
{
|
|
HDC hdcmem;
|
|
HBITMAP hbmpOld;
|
|
RECT rc;
|
|
HBRUSH hbrush;
|
|
int iDC = SaveDC(hdc);
|
|
|
|
GetClientRect(hwnd, &rc);
|
|
|
|
//Create a compatable DC
|
|
hdcmem = CreateCompatibleDC(hdc);
|
|
if(hdcmem)
|
|
{
|
|
// Offset the stuff we're paining if we're expanded
|
|
BYTE bOffset = 0;
|
|
// Store this for the Bar fill cycle
|
|
int cyBitmap = 0;
|
|
|
|
if (!_fFlatMenuMode)
|
|
{
|
|
bOffset = _fExpanded? 1 : 0;
|
|
}
|
|
|
|
if (_sizeBmp.cy <= RECTHEIGHT(rc) + 1)
|
|
{
|
|
//Select the bitmap into the memory DC
|
|
hbmpOld = (HBITMAP)SelectObject(hdcmem, _hbmp);
|
|
|
|
//Blit to the window
|
|
BitBlt(hdc, bOffset, rc.bottom - _sizeBmp.cy - bOffset, _sizeBmp.cx, _sizeBmp.cy, hdcmem, 0, 0, SRCCOPY);
|
|
|
|
// Ok, We need to subtract this value to see how much we need to paint for the banner.
|
|
cyBitmap = _sizeBmp.cy;
|
|
|
|
//Restore the DC
|
|
SelectObject(hdcmem, hbmpOld);
|
|
}
|
|
|
|
rc.right = _sizeBmp.cx + bOffset;
|
|
|
|
if (_fExpanded && !_fFlatMenuMode && !_fNoBorder)
|
|
DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_LEFT | BF_TOP | BF_BOTTOM);
|
|
|
|
//Paint the rest
|
|
hbrush = CreateSolidBrush(_rgb);
|
|
if(hbrush)
|
|
{
|
|
rc.bottom -= cyBitmap + bOffset;
|
|
|
|
if (_fExpanded)
|
|
{
|
|
rc.left += bOffset;
|
|
rc.top += bOffset;
|
|
}
|
|
|
|
FillRect(hdc, &rc, hbrush);
|
|
DeleteObject(hbrush);
|
|
}
|
|
|
|
|
|
//Delete the DC.
|
|
DeleteDC(hdcmem);
|
|
}
|
|
|
|
RestoreDC(hdc, iDC);
|
|
return 0;
|
|
}
|
|
|
|
void CMenuDeskBar::_DoNCPaint(HWND hwnd, HDC hdc)
|
|
{
|
|
if (!_fNoBorder)
|
|
{
|
|
RECT rc;
|
|
|
|
// Since we need to paint the border, we get the window rect
|
|
GetWindowRect(hwnd, &rc);
|
|
// then change the rect so that it represents values relative to
|
|
// the origin.
|
|
OffsetRect(&rc, -rc.left, -rc.top);
|
|
|
|
if (hdc)
|
|
{
|
|
if (_fFlatMenuMode)
|
|
{
|
|
SHOutlineRect(hdc, &rc, GetSysColor(COLOR_3DSHADOW));
|
|
}
|
|
else
|
|
DrawEdge(hdc, &rc, BDR_RAISEDOUTER, BF_RECT);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
LRESULT CMenuDeskBar::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
|
|
LRESULT lres;
|
|
|
|
switch (uMsg)
|
|
{
|
|
#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;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case WM_GETOBJECT:
|
|
if (lParam == OBJID_MENU)
|
|
{
|
|
IAccessible* pacc;
|
|
if (SUCCEEDED(QueryService(SID_SMenuBandChild, IID_PPV_ARG(IAccessible, &pacc))))
|
|
{
|
|
lres = LresultFromObject(IID_IAccessible, wParam, SAFECAST(pacc, IAccessible*));
|
|
pacc->Release();
|
|
|
|
return lres;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_NCCREATE:
|
|
//
|
|
// Since this is a mirrored menu, then open it
|
|
// on the left (mirrored) edge if possible. WillFit(...) will
|
|
// ensure this for us [samera]
|
|
//
|
|
// Mirror the menu initially if its window is mirrored
|
|
//
|
|
ASSERT(_uSide == 0);
|
|
if (IS_WINDOW_RTL_MIRRORED(_hwnd))
|
|
_uSide = MENUBAR_LEFT;
|
|
else
|
|
_uSide = MENUBAR_RIGHT;
|
|
break;
|
|
|
|
case WM_ACTIVATE:
|
|
if (LOWORD(wParam) == WA_INACTIVE)
|
|
{
|
|
if (_fActive && !_pmpChild)
|
|
{
|
|
|
|
// if we were active, and the thing going active now
|
|
// is not one of our parent menubars, then cancel everything.
|
|
|
|
// if it's a parent of ours going active, assume that
|
|
// they will tell us to die when they want us to...
|
|
if (!_IsMyParent((HWND)lParam))
|
|
OnSelect(MPOS_FULLCANCEL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_pmpChild)
|
|
{
|
|
// if we're becoming active, and we have a child, that child should go away
|
|
_pmpChild->OnSelect(MPOS_CANCELLEVEL);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_PRINTCLIENT:
|
|
if (_iIconSize == BMICON_LARGE)
|
|
{
|
|
_DoPaint(hwnd, (HDC)wParam, (DWORD)lParam);
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
// Paint the banner if we're in showing large icons
|
|
if (_iIconSize == BMICON_LARGE)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
BeginPaint(hwnd, &ps);
|
|
_DoPaint(hwnd, ps.hdc, 0);
|
|
EndPaint(hwnd, &ps);
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_PRINT:
|
|
if ((_fFlatMenuMode || _fExpanded) && PRF_NONCLIENT & lParam)
|
|
{
|
|
HDC hdc = (HDC)wParam;
|
|
|
|
DefWindowProcWrap(hwnd, WM_PRINT, wParam, lParam);
|
|
|
|
// Do this after so that we look right...
|
|
_DoNCPaint(hwnd, hdc);
|
|
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
case WM_NCCALCSIZE:
|
|
if (_fNoBorder)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return SUPERCLASS::v_WndProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
case WM_NCPAINT:
|
|
if (_fNoBorder)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (_fExpanded || _fFlatMenuMode)
|
|
{
|
|
HDC hdc;
|
|
hdc = GetWindowDC(hwnd);
|
|
if (hdc)
|
|
{
|
|
_DoNCPaint(hwnd, hdc);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
case WM_NCHITTEST:
|
|
lres = SUPERCLASS::v_WndProc(hwnd, uMsg, wParam, lParam);
|
|
|
|
switch (lres)
|
|
{
|
|
case HTBOTTOM:
|
|
case HTBOTTOMLEFT:
|
|
case HTBOTTOMRIGHT:
|
|
case HTLEFT:
|
|
case HTRIGHT:
|
|
case HTTOP:
|
|
case HTTOPLEFT:
|
|
case HTTOPRIGHT:
|
|
// Don't allow the window to be resized
|
|
lres = HTBORDER;
|
|
break;
|
|
|
|
case HTTRANSPARENT:
|
|
// Don't let a click go thru to the window underneath
|
|
lres = HTCLIENT;
|
|
break;
|
|
|
|
}
|
|
return lres;
|
|
|
|
// HACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACK
|
|
// (lamadio) 1.25.99
|
|
// This hack is here to fix a problem on down level Windows with Integrated
|
|
// IE4.01, IE5 and Office 2000.
|
|
// The bug revolves around Start Menu not being destroyed when Explorer.exe shuts
|
|
// down. Start Menu unregisters itself at CloseDW, but since the menubar never gets
|
|
// destroyed, Start Menu never deregisters itself.
|
|
// When an System service, such as MSTASK.dll keeps shell32 alive in the background,
|
|
// it leaves an outstanding reference to a change notify. When a new user logs in,
|
|
// O2k and IE5 fire up group conv, generating more than 10 change notify events in the
|
|
// start menu. This causes the batching code to be fired up: Which does not really
|
|
// work without the shell started. GroupConv also adds these events using memory
|
|
// alloced from it's process heap. Since there is an outstanding change notify handler
|
|
// these pidls get forced to be handled. Shell32 then faults derefing a bad pidl.
|
|
// By detecting an Endsession, we can eliminate this problem. Doing a SetClient(NULL)
|
|
// cause Menubar to free it's references to MenuSite. Menusite, calls CloseDW on menuband
|
|
// menuband then causes MNFolder to unregister itself. Since no one is listening any more
|
|
// the crash is avoided.
|
|
|
|
case WM_ENDSESSION:
|
|
if (wParam != 0)
|
|
{
|
|
SetClient(NULL);
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
return SUPERCLASS::v_WndProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
IMenuPopup* CMenuDeskBar::_GetMenuBarParent(IUnknown* punk)
|
|
{
|
|
IMenuPopup *pmp = NULL;
|
|
IObjectWithSite* pows;
|
|
punk->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pows));
|
|
|
|
if (pows)
|
|
{
|
|
IServiceProvider* psp;
|
|
pows->GetSite(IID_PPV_ARG(IServiceProvider, &psp));
|
|
|
|
if (psp)
|
|
{
|
|
psp->QueryService(SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp));
|
|
psp->Release();
|
|
}
|
|
|
|
pows->Release();
|
|
}
|
|
|
|
return pmp;
|
|
}
|
|
|
|
|
|
// this assumes that hwnd is a toplevel window and that the menudeskbars are also
|
|
// the only hosts and are themselves toplevel
|
|
BOOL CMenuDeskBar::_IsMyParent(HWND hwnd)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
if (hwnd)
|
|
{
|
|
HWND hwndMenu;
|
|
|
|
IMenuPopup *pmpParent = _pmpParent;
|
|
if (pmpParent)
|
|
pmpParent->AddRef();
|
|
|
|
while (pmpParent && !fRet &&
|
|
SUCCEEDED(IUnknown_GetWindow(pmpParent, &hwndMenu)))
|
|
{
|
|
if (hwndMenu == hwnd)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
|
|
IMenuPopup* pmpNext = _GetMenuBarParent(pmpParent);
|
|
pmpParent->Release();
|
|
pmpParent = pmpNext;
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
IMenuPopup* CreateMenuPopup(IMenuPopup* pmpParent, IShellFolder* psf, LPCITEMIDLIST pidl,
|
|
BANDINFOSFB * pbi, BOOL bMenuBand)
|
|
{
|
|
return CreateMenuPopup2(pmpParent, NULL, psf, pidl, pbi, bMenuBand);
|
|
}
|
|
|
|
IMenuPopup* CreateMenuPopup2(IMenuPopup* pmpParent, IMenuBand* pmb, IShellFolder* psf, LPCITEMIDLIST pidl,
|
|
BANDINFOSFB * pbi, BOOL bMenuBand)
|
|
{
|
|
|
|
ASSERT(pmb == NULL || IS_VALID_CODE_PTR(pmb, IMenuBand));
|
|
ASSERT(psf == NULL || IS_VALID_CODE_PTR(psf, IShellFolder));
|
|
ASSERT(pmpParent == NULL || IS_VALID_CODE_PTR(pmpParent, IMenuPopup));
|
|
ASSERT(pidl && IS_VALID_PIDL(pidl));
|
|
ASSERT(pbi == NULL || IS_VALID_READ_PTR(pbi, BANDINFOSFB));
|
|
|
|
IMenuPopup* pmp = NULL;
|
|
IDeskBand *pdb = NULL;
|
|
IBandSite *pbs = NULL;
|
|
HRESULT hres = E_FAIL;
|
|
|
|
if (!pdb)
|
|
{
|
|
TraceMsg(TF_MENUBAND, "CreateMenuPopup2 : Did not find a this (0x%x) band.", pidl);
|
|
|
|
if (bMenuBand)
|
|
{
|
|
pdb = CMenuBand_Create(psf, pidl, FALSE);
|
|
}
|
|
else
|
|
{
|
|
CISFBand_CreateEx(psf, pidl, IID_PPV_ARG(IDeskBand, &pdb));
|
|
}
|
|
|
|
if (pdb)
|
|
{
|
|
if (pbi)
|
|
{
|
|
IShellFolderBand *pisfBand;
|
|
if (SUCCEEDED(pdb->QueryInterface(IID_IShellFolderBand, (LPVOID*)&pisfBand)))
|
|
{
|
|
pisfBand->SetBandInfoSFB(pbi);
|
|
pisfBand->Release();
|
|
}
|
|
}
|
|
|
|
if (!pmpParent)
|
|
{
|
|
const CLSID * pclsid;
|
|
|
|
if (bMenuBand)
|
|
pclsid = &CLSID_MenuBandSite;
|
|
else
|
|
pclsid = &CLSID_RebarBandSite;
|
|
|
|
CoCreateInstance(*pclsid, NULL, CLSCTX_INPROC_SERVER, IID_IBandSite, (LPVOID*)&pbs);
|
|
|
|
if (pbs)
|
|
{
|
|
|
|
if (bMenuBand)
|
|
{
|
|
BANDSITEINFO bsinfo;
|
|
|
|
// Don't show the gripper for vertical menubands
|
|
bsinfo.dwMask = BSIM_STYLE;
|
|
bsinfo.dwStyle = BSIS_NOGRIPPER | BSIS_NODROPTARGET;
|
|
pbs->SetBandSiteInfo(&bsinfo);
|
|
}
|
|
|
|
CMenuDeskBar *pcmdb = new CMenuDeskBar();
|
|
if (pcmdb)
|
|
{
|
|
if (SUCCEEDED(pcmdb->SetClient(pbs)))
|
|
pcmdb->QueryInterface(IID_IMenuPopup, (LPVOID *)&pmp);
|
|
|
|
pcmdb->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pbs)
|
|
{
|
|
pbs->AddBand(pdb);
|
|
}
|
|
}
|
|
}
|
|
|
|
ATOMICRELEASE(pdb);
|
|
ATOMICRELEASE(pbs);
|
|
if (!pmp)
|
|
IUnknown_Set((IUnknown**) &pmp, pmpParent);
|
|
|
|
|
|
return pmp;
|
|
}
|