Leaked source code of windows server 2003
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.
 
 
 
 
 
 

830 lines
25 KiB

/**************************** Module Header ********************************\
* Module Name: mnstate.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Menu State Routines
*
* History:
* 10-10-90 JimA Cleanup.
* 03-18-91 IanJa Windowrevalidation added
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
PMENU xxxGetInitMenuParam(PWND pwndMenu, BOOL *lpfSystem);
/***************************************************************************\
* MNPositionSysMenu
*
* History:
* 4-25-91 Mikehar Port for 3.1 merge
\***************************************************************************/
VOID MNPositionSysMenu(
PWND pwnd,
PMENU pmenusys)
{
RECT rc;
PITEM pItem;
if (pmenusys == NULL) {
RIPERR0(ERROR_INVALID_HANDLE,
RIP_WARNING,
"Invalid menu handle pmenusys (NULL) to MNPositionSysMenu");
return;
}
/*
* Whoever positions the menu becomes the owner
*/
if (pwnd != pmenusys->spwndNotify) {
Lock(&pmenusys->spwndNotify, pwnd);
}
/*
* Setup the SysMenu hit rectangle.
*/
rc.top = rc.left = 0;
if (TestWF(pwnd, WEFTOOLWINDOW)) {
rc.right = SYSMET(CXSMSIZE);
rc.bottom = SYSMET(CYSMSIZE);
} else {
rc.right = SYSMET(CXSIZE);
rc.bottom = SYSMET(CYSIZE);
}
if (!TestWF(pwnd, WFMINIMIZED)) {
int cBorders;
cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE);
OffsetRect(&rc, cBorders*SYSMET(CXBORDER), cBorders*SYSMET(CYBORDER));
}
/*
* Offset the System popup menu.
*/
if (!TestMF(pmenusys, MF_POPUP) && (pmenusys->cItems > 0)) {
pItem = pmenusys->rgItems;
if (pItem) {
pItem->yItem = rc.top;
pItem->xItem = rc.left;
pItem->cyItem = rc.bottom - rc.top;
pItem->cxItem = rc.right - rc.left;
}
} else {
// BOGUS -- MF_POPUP should never be set on a MENU -- only a MENU ITEM
RIPMSG1(RIP_ERROR, "pmenu %#p has MF_POPUP set or 0 items", pmenusys);
}
}
/***************************************************************************\
* MNFlushDestroyedPopups
*
* Walk the ppmDelayedFree list freeing those marked as destroyed.
*
* 05-14-96 GerardoB Created
\***************************************************************************/
VOID MNFlushDestroyedPopups(
PPOPUPMENU ppopupmenu,
BOOL fUnlock)
{
PPOPUPMENU ppmDestroyed, ppmFree;
UserAssert(IsRootPopupMenu(ppopupmenu));
/*
* Walk ppmDelayedFree
*/
ppmDestroyed = ppopupmenu;
while (ppmDestroyed->ppmDelayedFree != NULL) {
/*
* If it's marked as destroyed, unlink it and free it
*/
if (ppmDestroyed->ppmDelayedFree->fDestroyed) {
ppmFree = ppmDestroyed->ppmDelayedFree;
ppmDestroyed->ppmDelayedFree = ppmFree->ppmDelayedFree;
UserAssert(ppmFree != ppmFree->ppopupmenuRoot);
MNFreePopup(ppmFree);
} else {
/*
* fUnlock is TRUE if the root popup is being destroyed; if
* so, reset fDelayedFree and unlink it.
*/
if (fUnlock) {
/*
* This means that the root popup is going away before
* some of the hierarchical popups have been destroyed.
*
* This can happen if someone destroys one of the menu
* windows breaking the spwndNextPopup chain.
*/
ppmDestroyed->ppmDelayedFree->fDelayedFree = FALSE;
/*
* Stop here so we can figure how this happened.
*/
UserAssert(ppmDestroyed->ppmDelayedFree->fDelayedFree);
ppmDestroyed->ppmDelayedFree = ppmDestroyed->ppmDelayedFree->ppmDelayedFree;
} else {
/*
* Not fDestroyed so move to the next one.
*/
ppmDestroyed = ppmDestroyed->ppmDelayedFree;
}
}
}
}
/***************************************************************************\
* MNAllocPopup
*
\***************************************************************************/
PPOPUPMENU MNAllocPopup(
BOOL fForceAlloc)
{
PPOPUPMENU ppm;
if (!fForceAlloc && !TEST_PUDF(PUDF_POPUPINUSE)) {
SET_PUDF(PUDF_POPUPINUSE);
ppm = &gpopupMenu;
} else {
ppm = (PPOPUPMENU)UserAllocPoolWithQuota(sizeof(POPUPMENU), TAG_POPUPMENU);
}
if (ppm) {
RtlZeroMemory(ppm, sizeof(POPUPMENU));
}
return ppm;
}
/***************************************************************************\
* MNFreePopup
*
\***************************************************************************/
VOID MNFreePopup(
PPOPUPMENU ppopupmenu)
{
Validateppopupmenu(ppopupmenu);
if (IsRootPopupMenu(ppopupmenu)) {
MNFlushDestroyedPopups(ppopupmenu, TRUE);
}
if (ppopupmenu->spwndPopupMenu &&
GETFNID(ppopupmenu->spwndPopupMenu) == FNID_MENU &&
ppopupmenu != &gpopupMenu) {
((PMENUWND)ppopupmenu->spwndPopupMenu)->ppopupmenu = NULL;
}
Unlock(&ppopupmenu->spwndPopupMenu);
/*
* If spwndNextPopup is not NULL, we're breaking the chain and spwndNext
* won't get closed. I won't remove the unlock since it has always been
* there.
*/
UserAssert(ppopupmenu->spwndNextPopup == NULL);
Unlock(&ppopupmenu->spwndNextPopup);
Unlock(&ppopupmenu->spwndPrevPopup);
UnlockPopupMenu(ppopupmenu, &ppopupmenu->spmenu);
UnlockPopupMenu(ppopupmenu, &ppopupmenu->spmenuAlternate);
Unlock(&ppopupmenu->spwndNotify);
Unlock(&ppopupmenu->spwndActivePopup);
#if DBG
ppopupmenu->fFreed = TRUE;
#endif
if (ppopupmenu == &gpopupMenu) {
UserAssert(TEST_PUDF(PUDF_POPUPINUSE));
CLEAR_PUDF(PUDF_POPUPINUSE);
} else {
UserFreePool(ppopupmenu);
}
}
/***************************************************************************\
* MNEndMenuStateNotify
*
* spwndNotify might have been created by a thread other than the one
* the menu mode is running on. If this is the case, this function
* NULLs out pMenuState for the thread that owns spwndNotify.
*
* It returns TRUE if the menu state owner doesn't own the notification
* window (multiple threads involved).
*
* 05-21-96 GerardoB Created
\***************************************************************************/
BOOL MNEndMenuStateNotify(
PMENUSTATE pMenuState)
{
PTHREADINFO ptiNotify;
if (pMenuState->pGlobalPopupMenu->spwndNotify != NULL) {
ptiNotify = GETPTI(pMenuState->pGlobalPopupMenu->spwndNotify);
if (ptiNotify != pMenuState->ptiMenuStateOwner) {
/*
* Later5.0 GerardoB. xxxMNStartMenuState no longer allows this.
* This is dead code that I'll remove eventually
*/
UserAssert(ptiNotify == pMenuState->ptiMenuStateOwner);
UserAssert(ptiNotify->pMenuState == pMenuState);
UserAssert(pMenuState->pmnsPrev == NULL);
ptiNotify->pMenuState = NULL;
return TRUE;
}
}
return FALSE;
}
/***************************************************************************\
* xxxMNEndMenuState
*
* This funtion must be called to clean up pMenuState after getting out
* of menu mode. It must be called by the same thread that initialized
* pMenuState either manually or by calling xxxMNStartMenuState.
*
* 05-20-96 GerardoB Created
\***************************************************************************/
VOID xxxMNEndMenuState(
BOOL fFreePopup)
{
PTHREADINFO ptiCurrent = PtiCurrent();
PMENUSTATE pMenuState;
pMenuState = ptiCurrent->pMenuState;
UserAssert(ptiCurrent->pMenuState != NULL);
UserAssert(ptiCurrent == pMenuState->ptiMenuStateOwner);
/*
* If the menu is locked, someone doesn't want it to go just yet.
*/
if (pMenuState->dwLockCount != 0) {
RIPMSG1(RIP_WARNING, "xxxMNEndMenuState Locked:%#p", pMenuState);
return;
}
MNEndMenuStateNotify(pMenuState);
/*
* pMenuState->pGlobalPopupMenu could be NULL if xxxMNAllocMenuState failed
*/
if (pMenuState->pGlobalPopupMenu != NULL) {
if (fFreePopup) {
UserAssert(pMenuState->pGlobalPopupMenu->fIsMenuBar || pMenuState->pGlobalPopupMenu->fDestroyed);
MNFreePopup(pMenuState->pGlobalPopupMenu);
} else {
/*
* This means that we're ending the menustate but the popup menu
* window is still around. This can happen when called from
* xxxDestroyThreadInfo.
*/
UserAssert(pMenuState->pGlobalPopupMenu->fIsTrackPopup);
pMenuState->pGlobalPopupMenu->fDelayedFree = FALSE;
}
}
/*
* Unlock MFMWFP windows.
*/
UnlockMFMWFPWindow(&pMenuState->uButtonDownHitArea);
UnlockMFMWFPWindow(&pMenuState->uDraggingHitArea);
/*
* Restore the previous state, if any
*/
ptiCurrent->pMenuState = pMenuState->pmnsPrev;
/*
* This (modal) menu mode is off
*/
if (!pMenuState->fModelessMenu) {
DecSFWLockCount();
DBGDecModalMenuCount();
}
if (pMenuState->hbmAni != NULL) {
MNDestroyAnimationBitmap(pMenuState);
}
/*
* Free the menu state
*/
if (pMenuState == &gMenuState) {
UserAssert(TEST_PUDF(PUDF_MENUSTATEINUSE));
CLEAR_PUDF(PUDF_MENUSTATEINUSE);
GreSetDCOwner(gMenuState.hdcAni, OBJECT_OWNER_PUBLIC);
} else {
if (pMenuState->hdcAni != NULL) {
GreDeleteDC(pMenuState->hdcAni);
}
UserFreePool(pMenuState);
}
/*
* If returning to a modeless menu, make sure we have activation.
* If returning to a modal menu, make sure we have capture.
*/
if (ptiCurrent->pMenuState != NULL) {
if (ptiCurrent->pMenuState->fModelessMenu) {
xxxActivateThisWindow(ptiCurrent->pMenuState->pGlobalPopupMenu->spwndActivePopup,
0, 0);
} else {
xxxMNSetCapture(ptiCurrent->pMenuState->pGlobalPopupMenu);
}
}
#if DBG
/*
* No pti should point to this pMenuState anymore.
* If guModalMenuStateCount is zero, all pMenuState must be NULL or
* modeless.
*/
{
PLIST_ENTRY pHead, pEntry;
PTHREADINFO ptiT;
pHead = &(ptiCurrent->rpdesk->PtiList);
for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) {
ptiT = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink);
UserAssert(ptiT->pMenuState != pMenuState);
if (guModalMenuStateCount == 0) {
UserAssert(ptiT->pMenuState == NULL || ptiT->pMenuState->fModelessMenu);
}
}
}
#endif
}
/***************************************************************************\
* MNCreateAnimationBitmap
*
\***************************************************************************/
BOOL MNCreateAnimationBitmap(
PMENUSTATE pMenuState,
UINT cx,
UINT cy)
{
HBITMAP hbm = GreCreateCompatibleBitmap(gpDispInfo->hdcScreen, cx, cy);
if (hbm == NULL) {
RIPMSG0(RIP_WARNING, "MNSetupAnimationBitmap: Failed to create hbmAni");
return FALSE;
}
#if DBG
if (pMenuState->hdcAni == NULL) {
RIPMSG0(RIP_WARNING, "MNCreateAnimationBitmap: hdcAni is NULL");
}
if (pMenuState->hbmAni != NULL) {
RIPMSG0(RIP_WARNING, "MNCreateAnimationBitmap: hbmAni already exists");
}
#endif // DBG
GreSelectBitmap(pMenuState->hdcAni, hbm);
pMenuState->hbmAni = hbm;
return TRUE;
}
/***************************************************************************\
* MNDestroyAnimationBitmap
*
\***************************************************************************/
VOID MNDestroyAnimationBitmap(
PMENUSTATE pMenuState)
{
GreSelectBitmap(pMenuState->hdcAni, GreGetStockObject(PRIV_STOCK_BITMAP));
UserVerify(GreDeleteObject(pMenuState->hbmAni));
pMenuState->hbmAni = NULL;
}
/***************************************************************************\
* MNSetupAnimationDC
*
* 9/20/96 GerardoB Created
\***************************************************************************/
BOOL MNSetupAnimationDC(
PMENUSTATE pMenuState)
{
pMenuState->hdcAni = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
if (pMenuState->hdcAni == NULL) {
RIPMSG0(RIP_WARNING, "MNSetupAnimationDC: Failed to create hdcAnimate");
UserAssert(pMenuState != &gMenuState);
return FALSE;
}
GreSelectFont(pMenuState->hdcAni, ghMenuFont);
return TRUE;
}
/***************************************************************************\
* xxxUnlockMenuState
*
* 11/24/96 GerardoB Created
\***************************************************************************/
BOOL xxxUnlockMenuState(
PMENUSTATE pMenuState)
{
UserAssert(pMenuState->dwLockCount != 0);
(pMenuState->dwLockCount)--;
if ((pMenuState->dwLockCount == 0) && ExitMenuLoop(pMenuState, pMenuState->pGlobalPopupMenu)) {
xxxMNEndMenuState(TRUE);
return TRUE;
}
return FALSE;
}
/***************************************************************************\
* xxxMNAllocMenuState
*
* Allocates and initializes a pMenuState.
*
* 5-21-96 GerardoB Created
\***************************************************************************/
PMENUSTATE xxxMNAllocMenuState(
PTHREADINFO ptiCurrent,
PTHREADINFO ptiNotify,
PPOPUPMENU ppopupmenuRoot)
{
BOOL fAllocate;
PMENUSTATE pMenuState;
UserAssert(PtiCurrent() == ptiCurrent);
UserAssert(ptiCurrent->rpdesk == ptiNotify->rpdesk);
/*
* If gMenuState is already taken, allocate one.
*/
fAllocate = TEST_PUDF(PUDF_MENUSTATEINUSE);
if (fAllocate) {
pMenuState = (PMENUSTATE)UserAllocPoolWithQuota(sizeof(MENUSTATE), TAG_MENUSTATE);
if (pMenuState == NULL) {
return NULL;
}
} else {
/*
* Use chache global which already has the animation DC setup
*/
SET_PUDF(PUDF_MENUSTATEINUSE);
pMenuState = &gMenuState;
UserAssert(gMenuState.hdcAni != NULL);
GreSetDCOwner(gMenuState.hdcAni, OBJECT_OWNER_CURRENT);
}
/*
* Prevent anyone from changing the foreground while this menu is active
*/
IncSFWLockCount();
DBGIncModalMenuCount();
/*
* Initialize pMenuState.
* Animation DC stuff is already setup so don't zero init it.
*/
RtlZeroMemory(pMenuState, sizeof(MENUSTATE) - sizeof(MENUANIDC));
pMenuState->pGlobalPopupMenu = ppopupmenuRoot;
pMenuState->ptiMenuStateOwner = ptiCurrent;
/*
* Save previous state, if any. Then set new state.
*/
pMenuState->pmnsPrev = ptiCurrent->pMenuState;
ptiCurrent->pMenuState = pMenuState;
if (ptiNotify != ptiCurrent) {
UserAssert(ptiNotify->pMenuState == NULL);
ptiNotify->pMenuState = pMenuState;
}
/*
* If the menustate was allocated, set up animation stuff.
* This is done here because in case of failure, MNEndMenuState
* will find ptiCurrent->pMenuState properly.
*/
if (fAllocate) {
RtlZeroMemory((PBYTE)pMenuState + sizeof(MENUSTATE) -
sizeof(MENUANIDC), sizeof(MENUANIDC));
if (!MNSetupAnimationDC(pMenuState)) {
xxxMNEndMenuState(TRUE);
return NULL;
}
}
return pMenuState;
}
/***************************************************************************\
* xxxMNStartMenuState
*
* This function is called when the menu bar is about to be activated (the
* app's main menu). It makes sure that the threads involved are not in
* menu mode already, finds the owner/notification window, initializes
* pMenuState and sends the WM_ENTERMENULOOP message.
* It successful, it returns a pointer to a pMenuState. If so, the caller
* must call MNEndMenuState when done.
*
* History:
* 4-25-91 Mikehar Port for 3.1 merge
* 5-20-96 GerardoB Renamed and changed (Old name: xxxMNGetPopup)
\***************************************************************************/
PMENUSTATE xxxMNStartMenuState(
PWND pwnd,
DWORD cmd,
LPARAM lParam)
{
PPOPUPMENU ppopupmenu;
PTHREADINFO ptiCurrent, ptiNotify;
PMENUSTATE pMenuState;
TL tlpwnd;
PWND pwndT;
CheckLock(pwnd);
/*
* Bail if the current thread is already in menu mode
*/
ptiCurrent = PtiCurrent();
if (ptiCurrent->pMenuState != NULL) {
return NULL;
}
/*
* If pwnd is not owned by ptiCurrent, the _PostMessage call below might
* send us in a loop
*/
UserAssert(ptiCurrent == GETPTI(pwnd));
/*
* If this is not a child window, use the active window on its queue
*/
if (!TestwndChild(pwnd)) {
pwnd = GETPTI(pwnd)->pq->spwndActive;
} else {
/*
* Search up the parents for a window with a System Menu.
*/
while (TestwndChild(pwnd)) {
if (TestWF(pwnd, WFSYSMENU)) {
break;
}
pwnd = pwnd->spwndParent;
}
}
if (pwnd == NULL) {
return NULL;
}
if (!TestwndChild(pwnd) && (pwnd->spmenu != NULL)) {
goto hasmenu;
}
if (!TestWF(pwnd, WFSYSMENU)) {
return NULL;
}
hasmenu:
/*
* If the owner/notification window was created by another thread,
* make sure that it's not in menu mode already
* This can happen if PtiCurrent() is attached to other threads, one of
* which created pwnd.
*/
ptiNotify = GETPTI(pwnd);
if (ptiNotify->pMenuState != NULL) {
return NULL;
}
/*
* If the notification window is owned by another thread,
* then the menu loop wouldn't get any keyboard or mouse
* messages because we set capture to the notification window.
* So we pass the WM_SYSCOMMAND to that thread and bail
*/
if (ptiNotify != ptiCurrent) {
RIPMSG2(RIP_WARNING, "Passing WM_SYSCOMMAND SC_*MENU from thread %#p to %#p", ptiCurrent, ptiNotify);
_PostMessage(pwnd, WM_SYSCOMMAND, cmd, lParam);
return NULL;
}
/*
* Allocate ppoupmenu and pMenuState.
*/
ppopupmenu = MNAllocPopup(FALSE);
if (ppopupmenu == NULL) {
return NULL;
}
pMenuState = xxxMNAllocMenuState(ptiCurrent, ptiNotify, ppopupmenu);
if (pMenuState == NULL) {
MNFreePopup(ppopupmenu);
return NULL;
}
ppopupmenu->fIsMenuBar = TRUE;
ppopupmenu->fHasMenuBar = TRUE;
Lock(&(ppopupmenu->spwndNotify), pwnd);
ppopupmenu->posSelectedItem = MFMWFP_NOITEM;
Lock(&(ppopupmenu->spwndPopupMenu), pwnd);
ppopupmenu->ppopupmenuRoot = ppopupmenu;
pwndT = pwnd;
while(TestwndChild(pwndT))
pwndT = pwndT->spwndParent;
if (pwndT->spmenu) {
ppopupmenu->fRtoL = TestMF(pwndT->spmenu, MFRTL) ?TRUE:FALSE;
} else {
//
// No way to know, no menu, but there is a system menu. Thus arrow
// keys are really not important. However lets take the next best
// thing just to be safe.
//
ppopupmenu->fRtoL = TestWF(pwnd, WEFRTLREADING) ?TRUE :FALSE;
}
/*
* Notify the app we are entering menu mode. wParam is always 0 since this
* procedure will only be called for menu bar menus not TrackPopupMenu
* menus.
*/
ThreadLockAlways(pwnd, &tlpwnd);
xxxSendMessage(pwnd, WM_ENTERMENULOOP, 0, 0);
ThreadUnlock(&tlpwnd);
return pMenuState;
}
/***************************************************************************\
* xxxMNStartMenu
*
* Note that this function calls back many times so we might be forced
* out of menu mode at any time. We don't want to check this after
* each callback so we lock what we need and go on. Be careful.
*
* History:
* 4-25-91 Mikehar Port for 3.1 merge
\***************************************************************************/
BOOL xxxMNStartMenu(
PPOPUPMENU ppopupmenu,
int mn)
{
PWND pwndMenu;
PMENU pMenu;
PMENUSTATE pMenuState;
TL tlpwndMenu;
TL tlpMenu;
UserAssert(IsRootPopupMenu(ppopupmenu));
if (ppopupmenu->fDestroyed) {
return FALSE;
}
pwndMenu = ppopupmenu->spwndNotify;
ThreadLock(pwndMenu, &tlpwndMenu);
pMenuState = GetpMenuState(pwndMenu);
if (pMenuState == NULL) {
RIPMSG0(RIP_ERROR, "xxxMNStartMenu: pMenuState == NULL");
ThreadUnlock(&tlpwndMenu);
return FALSE;
}
pMenuState->mnFocus = mn;
pMenuState->fMenuStarted = TRUE;
pMenuState->fButtonDown =
pMenuState->fButtonAlwaysDown = ((_GetKeyState(VK_LBUTTON) & 0x8000) != 0);
xxxMNSetCapture(ppopupmenu);
xxxSendMessage(pwndMenu, WM_SETCURSOR, (WPARAM)HWq(pwndMenu),
MAKELONG(MSGF_MENU, 0));
if (ppopupmenu->fIsMenuBar) {
BOOL fSystemMenu;
pMenu = xxxGetInitMenuParam(pwndMenu, &fSystemMenu);
if (pMenu == NULL) {
pMenuState->fMenuStarted = FALSE;
xxxMNReleaseCapture();
ThreadUnlock(&tlpwndMenu);
return FALSE;
}
LockPopupMenu(ppopupmenu, &ppopupmenu->spmenu, pMenu);
ppopupmenu->fIsSysMenu = (fSystemMenu != 0);
if (!fSystemMenu) {
pMenu = xxxGetSysMenu(pwndMenu, FALSE);
LockPopupMenu(ppopupmenu, &ppopupmenu->spmenuAlternate, pMenu);
}
}
pMenuState->fIsSysMenu = (ppopupmenu->fIsSysMenu != 0);
if (!ppopupmenu->fNoNotify) {
if (ppopupmenu->fIsTrackPopup && ppopupmenu->fIsSysMenu) {
pMenu = xxxGetInitMenuParam(pwndMenu, NULL);
} else {
pMenu = ppopupmenu->spmenu;
}
xxxSendMessage(pwndMenu, WM_INITMENU, (WPARAM)PtoH(pMenu), 0L);
}
if (!ppopupmenu->fIsTrackPopup) {
if (ppopupmenu->fIsSysMenu) {
MNPositionSysMenu(pwndMenu, ppopupmenu->spmenu);
} else if (ppopupmenu->fIsMenuBar) {
ThreadLockMenuNoModify(ppopupmenu->spmenu, &tlpMenu);
xxxMNRecomputeBarIfNeeded(pwndMenu, ppopupmenu->spmenu);
ThreadUnlockMenuNoModify(&tlpMenu);
MNPositionSysMenu(pwndMenu, ppopupmenu->spmenuAlternate);
}
}
/*
* If returning TRUE, set menu style in pMenuState
*/
if (!ppopupmenu->fDestroyed) {
if (TestMF(ppopupmenu->spmenu, MNS_MODELESS)) {
pMenuState->fModelessMenu = TRUE;
}
if (TestMF(ppopupmenu->spmenu, MNS_DRAGDROP)) {
if (NT_SUCCESS(xxxClientLoadOLE())) {
pMenuState->fDragAndDrop = TRUE;
}
}
if (TestMF(ppopupmenu->spmenu, MNS_AUTODISMISS)) {
pMenuState->fAutoDismiss = TRUE;
}
if (TestMF(ppopupmenu->spmenu, MNS_NOTIFYBYPOS)) {
pMenuState->fNotifyByPos = TRUE;
}
}
/*
* Bogus! We don't always know that this is the system menu. We
* will frequently pass on an OBJID_MENU even when you hit Alt+Space.
*
* Hence, MNSwitchToAlternate will send a EVENT_SYSTEM_MENUEND for the
* menu bar and an EVENT_SYSTEM_MENUSTART for the sysmenu when we "switch".
*/
xxxWindowEvent(EVENT_SYSTEM_MENUSTART, pwndMenu,
(ppopupmenu->fIsSysMenu ? OBJID_SYSMENU : (ppopupmenu->fIsMenuBar ? OBJID_MENU : OBJID_WINDOW)),
INDEXID_CONTAINER, 0);
ThreadUnlock(&tlpwndMenu);
return !ppopupmenu->fDestroyed;
}
/***************************************************************************\
* xxxGetInitMenuParam
*
* Gets the HMENU sent as the wParam of WM_INITMENU, and for menu bars, is
* the actual menu to be interacted with.
*
* History:
* ????
\***************************************************************************/
PMENU xxxGetInitMenuParam(
PWND pwndMenu,
BOOL *lpfSystem)
{
//
// Find out what menu we should be sending in WM_INITMENU:
// If minimized/child/empty menubar, use system menu
//
CheckLock(pwndMenu);
if (TestWF(pwndMenu, WFMINIMIZED) ||
TestwndChild(pwndMenu) ||
(pwndMenu->spmenu == NULL) ||
!pwndMenu->spmenu->cItems) {
if (lpfSystem != NULL)
*lpfSystem = TRUE;
return xxxGetSysMenu(pwndMenu, FALSE);
} else {
if (lpfSystem != NULL) {
*lpfSystem = FALSE;
}
return pwndMenu->spmenu;
}
}