Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1076 lines
31 KiB

/**************************** Module Header ********************************\
* Module Name: mnchange.c
*
* Copyright 1985-90, Microsoft Corporation
*
* Change Menu Routine
*
* History:
* 10-10-90 JimA Cleanup.
* 03-18-91 IanJa Window revalidation added (none required)
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#ifdef DEBUG
extern BOOL gfTrackLocks;
#endif
/*
* Allocation/deallocation increments. Make them
* different to avoid possible thrashing when an item
* is repeatedly added and removed.
*/
#define CMENUITEMALLOC 8
#define CMENUITEMDEALLOC 10
#ifdef MEMPHIS_MENUS
BOOL xxxSetLPITEMInfo(PMENU pMenu, PITEM pItem,
LPMENUITEMINFOW lpmii, PUNICODE_STRING pstr);
void xxxMNUpdateShownMenu(PPOPUPMENU, LPITEM, BOOL);
PPOPUPMENU MNCheckMenuUp(PMENU);
#else // MEMPHIS_MENUS
BOOL SetLPITEMInfo(PMENU pMenu, PITEM pItem,
LPMENUITEMINFOW lpmii, PUNICODE_STRING pstr);
#endif //MEMPHIS_MENUS
typedef BOOL (*MENUAPIFN)(PMENU, UINT, BOOL, LPMENUITEMINFOW);
#ifdef DEBUG
VOID RelocateMenuLockRecords(
PITEM pItem,
int cItem,
int cbMove)
{
while (cItem > 0) {
if (pItem->spSubMenu != NULL) {
HMRelocateLockRecord(&(pItem->spSubMenu), cbMove);
}
pItem++;
cItem--;
}
}
#endif
/**********************************************
* Global Insert/Append/Set client/server interface
*
* 01-13-94 FritzS Created
***********************************************/
#ifdef MEMPHIS_MENUS
BOOL xxxSetMenuItemInfo(
#else // MEMPHIS_MENUS
BOOL _SetMenuItemInfo(
#endif //MEMPHIS_MENUS
PMENU pMenu,
UINT wIndex,
BOOL fByPosition,
LPMENUITEMINFOW lpmii,
PUNICODE_STRING pstrItem)
{
PITEM pItem;
#ifdef MEMPHIS_MENUS
CheckLock(pMenu);
#endif // MEMPHIS_MENUS
pItem = MNLookUpItem(pMenu, wIndex, fByPosition,NULL);
if (pItem == NULL) {
/*
* Word doesn't like not finding SC_TASKLIST -- so it that's what
* they're looking for, let's pretend we changed it.
*/
if (!fByPosition && (wIndex == SC_TASKLIST))
return TRUE;
/*
* Item not found. Return false.
*/
RIPERR0(ERROR_MENU_ITEM_NOT_FOUND, RIP_WARNING, "ModifyMenu: Menu item not found");
return FALSE;
}
#ifdef MEMPHIS_MENUS
return xxxSetLPITEMInfo(pMenu, pItem, lpmii, pstrItem);
#else // MEMPHIS_MENUS
return SetLPITEMInfo(pMenu, pItem, lpmii, pstrItem);
#endif // MEMPHIS_MENUS
}
#ifdef MEMPHIS_MENU_WATERMARKS
/***************************************************************************\
* xxxSetMenuInfo (API)
*
*
* History:
* 12-Feb-1996 JudeJ Ported from Memphis
\***************************************************************************/
BOOL APIENTRY xxxSetMenuInfo(PMENU pMenu, LPCMENUINFO lpmi)
{
PPOPUPMENU ppopup;
BOOL fRecompute = FALSE;
BOOL fRedraw = FALSE;
CheckLock(pMenu);
if (lpmi->fMask & MIM_STYLE) {
if (lpmi->dwStyle & MNS_NOCHECK)
SetMF(pMenu, MFNOCHECK);
else
ClearMF(pMenu, MFNOCHECK);
fRecompute = TRUE;
}
// if (lpmi->fMask & MIM_MAXHEIGHT) {
// pMenu->cyMax = LOWORD(lpmi->cyMax);
// fRecompute = TRUE;
// }
if (lpmi->fMask & MIM_BACKGROUND) {
pMenu->hbrBack = lpmi->hbrBack;
fRedraw = TRUE;
}
// if (lpmi->fMask & MIM_HELPID) {
// pMenu->dwContextHelpID = lpmi->dwContextHelpID;
// }
// if (lpmi->fMask & MIM_MENUDATA) {
// pMenu->dwMenuData = lpmi->dwMenuData;
// }
if (fRecompute) {
// Set the size of this menu to be 0 so that it gets recomputed with this
// new item...
pMenu->cyMenu = pMenu->cxMenu = 0;
Redraw:
if (ppopup = MNCheckMenuUp(pMenu)) {
// this menu is currently being displayed -- redisplay the menu,
// recomputing if necessary
xxxMNUpdateShownMenu(ppopup, NULL, FALSE);
}
} else if (fRedraw) {
goto Redraw;
}
return(TRUE);
}
#endif // MEMPHIS_MENU_WATERMARKS
#ifdef MEMPHIS_MENUS
BOOL xxxInsertMenuItem(
#else
BOOL _InsertMenuItem(
#endif // MEMPHIS_MENUS
PMENU pMenu,
UINT wIndex,
BOOL fByPosition,
LPMENUITEMINFOW lpmii,
PUNICODE_STRING pstrItem)
{
PITEM pItem;
PMENU pMenuItemIsOn;
PITEM pNewItems;
#ifdef MEMPHIS_MENUS
PPOPUPMENU ppopup;
TL tlMenu;
CheckLock(pMenu);
#endif // MEMPHIS_MENUS
// Find out where the item we are inserting should go.
if (wIndex != MFMWFP_NOITEM) {
pItem = MNLookUpItem(pMenu, wIndex, fByPosition, &pMenuItemIsOn);
if (pItem != NULL)
pMenu = pMenuItemIsOn;
else {
wIndex = MFMWFP_NOITEM;
}
} else
pItem = NULL;
#ifdef MEMPHIS_MENUS
if (pMenu->cItems && (!(lpmii->fMask & MIIM_BITMAP) || (lpmii->hbmpItem >= (HBITMAP)MENUHBM_MAX)))
#else // MEMPHIS_MENUS
if (pMenu->cItems && (!(lpmii->fType & MFT_BITMAP) || (lpmii->dwTypeData >= (LPWSTR)MENUHBM_MAX)))
#endif // MEMPHIS_MENUS
{
// keep normal menu items between the MDI system bitmap items
UINT wSave, w;
PITEM pItemWalk;
wSave = w = wIndex;
if (pItem && !fByPosition)
w = ((PBYTE)pItem - (PBYTE)(pMenu->rgItems)) / sizeof(ITEM);
if (!w)
{
pItemWalk = pMenu->rgItems;
#ifdef MEMPHIS_MENUS
if ((pItemWalk->hbmp == (HBITMAP)MENUHBM_SYSTEM))
#else // MEMPHIS_MENUS
if ((pItemWalk->fType & MFT_BITMAP) && (pItemWalk->hTypeData == (HANDLE)MENUHBM_SYSTEM))
#endif //MEMPHIS_MENUS
wIndex = 1;
}
else
{
if (w == MFMWFP_NOITEM)
w = pMenu->cItems;
w--;
pItemWalk = pMenu->rgItems + w;
#ifdef MEMPHIS_MENUS
while (w && (pItemWalk->hbmp) && (pItemWalk->hbmp < (HBITMAP)MENUHBM_MAX))
#else // MEMPHIS_MENUS
while (w && (pItemWalk->fType & MFT_BITMAP) && (pItemWalk->hTypeData < (HANDLE)MENUHBM_MAX))
#endif // MEMPHIS_MENUS
{
wIndex = w--;
pItemWalk--;
}
}
if (wIndex != wSave)
pItem = pMenu->rgItems + wIndex;
}
// LATER -- we currently realloc every 10 items. investigate the
// performance hit/gain we get from this and adjust accordingly.
if (pMenu->cItems >= pMenu->cAlloced) {
if (pMenu->rgItems) {
pNewItems = (PITEM)DesktopAlloc(pMenu->head.rpdesk->hheapDesktop,
(pMenu->cAlloced + CMENUITEMALLOC) * sizeof(ITEM));
if (pNewItems) {
RtlCopyMemory(pNewItems, pMenu->rgItems,
pMenu->cAlloced * sizeof(ITEM));
#ifdef DEBUG
if (gfTrackLocks) {
RelocateMenuLockRecords(pNewItems, pMenu->cItems,
((PBYTE)pNewItems) - (PBYTE)(pMenu->rgItems));
}
#endif
DesktopFree(pMenu->head.rpdesk->hheapDesktop, pMenu->rgItems);
}
} else {
pNewItems = (PITEM)DesktopAlloc(pMenu->head.rpdesk->hheapDesktop,
sizeof(ITEM) * CMENUITEMALLOC);
}
if (pNewItems == NULL)
return(FALSE);
pMenu->cAlloced += CMENUITEMALLOC;
pMenu->rgItems = pNewItems;
/*
* Now look up the item again since it probably moved when we realloced the
* memory.
*/
if (wIndex != MFMWFP_NOITEM)
pItem = MNLookUpItem(pMenu, wIndex, fByPosition, &pMenuItemIsOn);
}
pMenu->cItems++;
if (pItem != NULL) {
// Move this item up to make room for the one we want to insert.
memmove(pItem + 1, pItem, (pMenu->cItems - 1) *
sizeof(ITEM) - ((char *)pItem - (char *)pMenu->rgItems));
#ifdef DEBUG
if (gfTrackLocks) {
RelocateMenuLockRecords(pItem + 1,
&(pMenu->rgItems[pMenu->cItems]) - (pItem + 1),
sizeof(ITEM));
}
#endif
} else {
// If lpItem is null, we will be inserting the item at the end of the
// menu.
pItem = pMenu->rgItems + pMenu->cItems - 1;
}
// Need to zero these fields in case we are inserting this item in the
// middle of the item list.
pItem->fType = 0;
pItem->fState = 0;
pItem->wID = 0;
pItem->spSubMenu = NULL;
pItem->hbmpChecked = NULL;
pItem->hbmpUnchecked = NULL;
pItem->hTypeData = NULL;
pItem->cch = 0;
pItem->dwItemData = 0;
pItem->xItem = 0;
pItem->yItem = 0;
pItem->cxItem = 0;
pItem->cyItem = 0;
#ifdef MEMPHIS_MENUS
pItem->hbmp = NULL;
pItem->cxBmp = -1;
pItem->cyBmp = -1;
pItem->lpstr = NULL;
if (ppopup = MNCheckMenuUp(pMenu))
{
// this menu is currently being displayed -- increment the selection
// pos if it is after the point of insertion
if (ppopup->posSelectedItem >=
(int) ((pItem - pMenu->rgItems) / sizeof(ITEM)) )
ppopup->posSelectedItem++;
}
ThreadLock(pMenu, &tlMenu);
if (!xxxSetLPITEMInfo(pMenu, pItem, lpmii, pstrItem)) {
#else
if (!SetLPITEMInfo(pMenu, pItem, lpmii, pstrItem)) {
#endif // MEMPHIS_MENUS
MNFreeItem(pMenu, pItem, TRUE);
// Move things up since we removed/deleted the item
memmove(pItem, pItem + 1, pMenu->cItems * (UINT)sizeof(ITEM) +
(UINT)((char *)&pMenu->rgItems[0] - (char *)(pItem + 1)));
#ifdef DEBUG
if (gfTrackLocks) {
RelocateMenuLockRecords(pItem,
&(pMenu->rgItems[pMenu->cItems - 1]) - pItem,
-(int)sizeof(ITEM));
}
#endif
pMenu->cItems--;
#ifdef MEMPHIS_MENUS
ThreadUnlock(&tlMenu);
#endif // MEMPHIS_MENUS
return(FALSE);
}
#ifdef MEMPHIS_MENUS
ThreadUnlock(&tlMenu);
#endif // MEMPHIS_MENUS
return(TRUE);
}
void _SetMenuItemInfoStruct(
UINT wFlags,
UINT wIDNew,
LPCWSTR lpszNew,
LPMENUITEMINFO pmii,
PUNICODE_STRING pstr)
{
#ifdef MEMPHIS_MENUS
pmii->fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE;
#else // MEMPHIS_MENUS
pmii->fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
#endif // MEMPHIS_MENUS
if (wFlags & MF_POPUP) {
pmii->fMask |= MIIM_SUBMENU;
pmii->hSubMenu = (HMENU)wIDNew;
}
if (wFlags & MF_OWNERDRAW) {
pmii->fMask |= MIIM_DATA;
pmii->dwItemData = (DWORD) lpszNew;
}
pmii->fState = wFlags & MFS_OLDAPI_MASK;
pmii->fType = wFlags & MFT_OLDAPI_MASK;
pmii->wID = wIDNew;
pmii->dwTypeData = (LPWSTR) lpszNew;
#ifdef MEMPHIS_MENUS
if (wFlags & MIIM_STRING)
#else // MEMPHIS_MENUS
if (!(pmii->fType & MFT_NONSTRING))
#endif // MEMPHIS_MENUS
RtlInitUnicodeString(pstr, lpszNew);
}
#ifndef MEMPHIS_MENUS
void FreeTypeData(PMENU pMenu, PITEM pItem)
{
// Free up hItem unless it's a bitmap handle or nonexistent.
// Apps are responsible for freeing their bitmaps.
if (!TestMFT(pItem, MFT_NONSTRING) && (pItem->hTypeData != NULL))
DesktopFree(pMenu->head.rpdesk->hheapDesktop, pItem->hTypeData);
if (TestMFT(pItem, MFT_BITMAP)) {
/*
* Assign ownership of the bitmap to the process that is
* destroying the menu to ensure that bitmap will
* eventually be destroyed.
*/
GreSetBitmapOwner((HBITMAP)(pItem->hTypeData), OBJECT_OWNER_CURRENT);
}
// Zap this pointer in case we try to free or reference it again
pItem->hTypeData = NULL;
}
#else // MEMPHIS_MENUS
void FreeItemBitmap(PMENU pMenu, PITEM pItem)
{
// Free up hItem unless it's a bitmap handle or nonexistent.
// Apps are responsible for freeing their bitmaps.
if (pItem->hbmp) {
/*
* Assign ownership of the bitmap to the process that is
* destroying the menu to ensure that bitmap will
* eventually be destroyed.
*/
GreSetBitmapOwner((HBITMAP)(pItem->hbmp), OBJECT_OWNER_CURRENT);
}
// Zap this pointer in case we try to free or reference it again
pItem->hbmp = NULL;
}
void FreeItemString(PMENU pMenu, PITEM pItem)
{
// Free up Item's string
if ((pItem->lpstr != NULL)) {
DesktopFree(pMenu->head.rpdesk->hheapDesktop, pItem->lpstr);
}
// Zap this pointer in case we try to free or reference it again
pItem->lpstr = NULL;
}
#endif // MEMPHIS_MENUS
void NEAR FreePopup(PITEM pItem)
{
if (pItem->spSubMenu != NULL) {
_DestroyMenu(pItem->spSubMenu);
}
}
/***************************************************************************\
* FreeItem
*
* Free a menu item and its associated resources.
*
* History:
* 10-11-90 JimA Translated from ASM
\***************************************************************************/
void MNFreeItem(
PMENU pMenu,
PITEM pItem,
BOOL fFreeItemPopup)
{
#ifdef MEMPHIS_MENUS
FreeItemBitmap(pMenu, pItem);
FreeItemString(pMenu, pItem);
#else // MEMPHIS_MENUS
FreeTypeData(pMenu, pItem);
#endif //MEMPHIS_MENUS
if (fFreeItemPopup)
FreePopup(pItem);
/*
* This'll work: the item didn't go away if it was locked.
*/
Unlock(&pItem->spSubMenu);
}
/***************************************************************************\
* RemoveDeleteMenuHelper
*
* This removes the menu item from the given menu. If
* fDeleteMenuItem, the memory associted with the popup menu associated with
* the item being removed is freed and recovered.
*
* History:
\***************************************************************************/
#ifdef MEMPHIS_MENUS
BOOL xxxRemoveDeleteMenuHelper(
#else
BOOL RemoveDeleteMenuHelper(
#endif // MEMPHIS_MENUS
PMENU pMenu,
UINT nPosition,
DWORD wFlags,
BOOL fDeleteMenu)
{
PITEM pItem;
PITEM pNewItems;
PMENU pMenuSave;
#ifdef MEMPHIS_MENUS
PPOPUPMENU ppopup;
UINT uiPos = 0;
CheckLock(pMenu);
#endif // MEMPHIS_MENUS
pMenuSave = pMenu;
pItem = MNLookUpItem(pMenu, nPosition, (BOOL) (wFlags & MF_BYPOSITION), &pMenu);
if (pItem == NULL) {
/*
* Hack for apps written for Win95. In Win95 the prototype for
* this function was with 'WORD nPosition' and because of this
* the HIWORD(nPosition) got set to 0.
* We are doing this just for system menu commands.
*/
if (nPosition >= 0xFFFFF000 && !(wFlags & MF_BYPOSITION)) {
nPosition &= 0x0000FFFF;
pMenu = pMenuSave;
pItem = MNLookUpItem(pMenu, nPosition, FALSE, &pMenu);
if (pItem == NULL)
return FALSE;
} else
return FALSE;
}
#ifdef MEMPHIS_MENUS
if (ppopup = MNCheckMenuUp(pMenu))
{
// this menu is currently being displayed -- decrement the selection
// pos if it is after the point of deletion; clear selection pos if it
// is AT the point of deletion
uiPos = ((pItem - pMenu->rgItems) / sizeof(ITEM));
if (ppopup->posSelectedItem == uiPos)
ppopup->posSelectedItem = 0xffff;// MI_NONE;
else if (ppopup->posSelectedItem > uiPos)
ppopup->posSelectedItem--;
}
#endif // MEMPHIS_MENUS
MNFreeItem(pMenu, pItem, fDeleteMenu);
/*
* Reset the menu size so that it gets recomputed next time.
*/
pMenu->cyMenu = pMenu->cxMenu = 0;
/*
* Chicago removed the counterpart to this line (hMenu->hwndNotify = 0)
* We probably still need for deref
*/
Unlock(&pMenu->spwndNotify);
if (pMenu->cItems == 1) {
DesktopFree(pMenu->head.rpdesk->hheapDesktop, pMenu->rgItems);
pMenu->cAlloced = 0;
pNewItems = NULL;
} else {
/*
* Move things up since we removed/deleted the item
*/
memmove(pItem, pItem + 1, pMenu->cItems * (UINT)sizeof(ITEM) +
(UINT)((char *)&pMenu->rgItems[0] - (char *)(pItem + 1)));
#ifdef DEBUG
if (gfTrackLocks) {
RelocateMenuLockRecords(pItem,
&(pMenu->rgItems[pMenu->cItems - 1]) - pItem,
-(int)sizeof(ITEM));
}
#endif
/*
* We're shrinking so if localalloc fails, just leave the mem as is.
*/
if (pMenu->cItems <= (pMenu->cAlloced - CMENUITEMDEALLOC + 1)) {
pNewItems = (PITEM)DesktopAlloc(pMenu->head.rpdesk->hheapDesktop,
(pMenu->cAlloced - CMENUITEMDEALLOC) * sizeof(ITEM));
if (pNewItems != NULL) {
RtlCopyMemory(pNewItems, pMenu->rgItems,
(pMenu->cAlloced - CMENUITEMDEALLOC) * sizeof(ITEM));
#ifdef DEBUG
if (gfTrackLocks) {
RelocateMenuLockRecords(pNewItems, pMenu->cItems - 1,
((PBYTE)pNewItems) - (PBYTE)(pMenu->rgItems));
}
#endif
DesktopFree(pMenu->head.rpdesk->hheapDesktop, pMenu->rgItems);
pMenu->cAlloced -= CMENUITEMDEALLOC;
} else
pNewItems = pMenu->rgItems;
} else
pNewItems = pMenu->rgItems;
}
pMenu->rgItems = pNewItems;
pMenu->cItems--;
#ifdef MEMPHIS_MENUS
if (ppopup) {
// this menu is currently being displayed -- redisplay the menu with
// this item removed
xxxMNUpdateShownMenu(ppopup, pMenu->rgItems + uiPos, TRUE);
}
#endif // MEMPHIS_MENUS
return TRUE;
}
/***************************************************************************\
* RemoveMenu
*
* Removes and item but doesn't delete it. Only useful for items with
* an associated popup since this will remove the item from the menu with
* destroying the popup menu handle.
*
* History:
\***************************************************************************/
#ifdef MEMPHIS_MENUS
BOOL xxxRemoveMenu(
#else
BOOL _RemoveMenu(
#endif // MEMPHIS_MENUS
PMENU pMenu,
UINT nPosition,
UINT wFlags)
{
#ifdef MEMPHIS_MENUS
TL tlpMenu;
BOOL fReturn = FALSE;
CheckLock(pMenu);
ThreadLock(pMenu, &tlpMenu);
fReturn = xxxRemoveDeleteMenuHelper(pMenu, nPosition, wFlags, FALSE);
ThreadUnlock(&tlpMenu);
return fReturn;
#else
return RemoveDeleteMenuHelper(pMenu, nPosition, wFlags, FALSE);
#endif // MEMPHIS_MENUS
}
/***************************************************************************\
* DeleteMenu
*
* Deletes an item. ie. Removes it and recovers the memory used by it.
*
* History:
\***************************************************************************/
#ifdef MEMPHIS_MENUS
BOOL xxxDeleteMenu(
#else
BOOL _DeleteMenu(
#endif // MEMPHIS_MENUS
PMENU pMenu,
UINT nPosition,
UINT wFlags)
{
PMENU pSystemMenu;
#ifdef MEMPHIS_MENUS
CheckLock(pMenu);
#endif // MEMPHIS_MENUS
// Nasty Hack to fix MSVC 1.5, they remove the close item
// from their system menu, so we prevent them from doing
// this and act like nothing happened ( ie return TRUE )
// Bug#8154, [t-arthb]
if ( nPosition == 6 &&
(wFlags & MF_BYPOSITION) &&
(pMenu->spwndNotify) &&
! TestWF( pMenu->spwndNotify, WFWIN40COMPAT ) &&
TestWF( pMenu->spwndNotify, WEFMDICHILD ) &&
(pSystemMenu = GetSysMenuHandle(pMenu->spwndNotify)) &&
(pSystemMenu->rgItems[0].spSubMenu == pMenu) )
{
return TRUE;
}
#ifdef MEMPHIS_MENUS
return xxxRemoveDeleteMenuHelper(pMenu, nPosition, wFlags, TRUE);
#else
return RemoveDeleteMenuHelper(pMenu, nPosition, wFlags, TRUE);
#endif // MEMPHIS_MENUS
}
#ifdef MEMPHIS_MENUS
BOOL NEAR xxxSetLPITEMInfo(
PMENU pMenu,
PITEM pItem,
LPMENUITEMINFOW lpmii,
PUNICODE_STRING pstrItem)
{
HANDLE hstr;
UINT cch;
BOOL fRecompute = FALSE;
BOOL fRedraw = FALSE;
PPOPUPMENU ppopup;
// TL tlpwndNotify;
CheckLock(pMenu);
if ( lpmii->fMask & MIIM_FTYPE ) {
UINT fType = lpmii->fType;
pItem->fType &= ~MFT_MASK;
pItem->fType |= fType;
if ( fType& MFT_SEPARATOR ) {
pItem->fState |= MFS_DISABLED ;
}
fRecompute = TRUE;
}
if ( lpmii->fMask & MIIM_STRING ) {
if (pstrItem->Length != 0) {
hstr = (HANDLE)DesktopAlloc(pMenu->head.rpdesk->hheapDesktop,
pstrItem->MaximumLength);
if (hstr == NULL)
return FALSE;
try {
RtlCopyMemory(hstr, pstrItem->Buffer, pstrItem->MaximumLength);
} except (EXCEPTION_EXECUTE_HANDLER) {
DesktopFree(pMenu->head.rpdesk->hheapDesktop, hstr);
return FALSE;
}
cch = pstrItem->Length / sizeof(WCHAR);
} else {
cch = 0;
hstr = NULL;
}
FreeItemString(pMenu,pItem);
pItem->cch = cch;
pItem->lpstr = hstr;
fRecompute = TRUE;
fRedraw = TRUE;
}
if ( lpmii->fMask & MIIM_BITMAP ) {
FreeItemBitmap(pMenu, pItem);
pItem->hbmp = lpmii->hbmpItem;
pItem->cxBmp =-1;
pItem->cyBmp =-1;
fRecompute = TRUE;
fRedraw = TRUE;
}
if (lpmii->fMask & MIIM_ID)
pItem->wID = lpmii->wID;
if (lpmii->fMask & MIIM_DATA)
pItem->dwItemData = lpmii->dwItemData;
if (lpmii->fMask & MIIM_STATE) {
pItem->fState = lpmii->fState | (pItem->fState & (MFS_HILITE | MFS_DEFAULT));
if (pItem->fType & MFT_SEPARATOR)
pItem->fState |= MFS_DISABLED;
fRedraw = TRUE;
}
if (lpmii->fMask & MIIM_CHECKMARKS) {
pItem->hbmpChecked = lpmii->hbmpChecked;
pItem->hbmpUnchecked = lpmii->hbmpUnchecked;
fRedraw = TRUE;
}
if (lpmii->fMask & MIIM_SUBMENU) {
PMENU pSubMenu = NULL;
if (lpmii->hSubMenu != NULL)
pSubMenu = ValidateHmenu(lpmii->hSubMenu);
// Free the popup associated with this item, if any and if needed.
if (pItem->spSubMenu != pSubMenu) {
if (pItem->spSubMenu != NULL) {
FreePopup(pItem);
}
if (pSubMenu!=NULL) {
Lock(&(pItem->spSubMenu), pSubMenu);
SetMF(pItem->spSubMenu, MFISPOPUP);
} else
Unlock(&(pItem->spSubMenu));
fRedraw = TRUE;
}
}
// For support of the old way of defining a separator i.e. if it is not a string
// or a bitmap or a ownerdraw, then it must be a separator.
// This should prpbably be moved to MIIOneWayConvert -jjk
if ( !(pItem->fType & (MFT_OWNERDRAW | MFT_SEPARATOR))
&& !pItem->lpstr && !pItem->hbmp ){
pItem->fType = MFT_SEPARATOR;
pItem->fState|=MFS_DISABLED;
}
if ( fRecompute ) {
pItem->dxTab = 0;
pItem->ulX = UNDERLINE_RECALC;
pItem->ulWidth = 0;
// Set the size of this menu to be 0 so that it gets recomputed with this
// new item...
pMenu->cyMenu = pMenu->cxMenu = 0;
/*
* Chicago removed the counterpart to this line (hMenu->hwndNotify = 0)
* We probably still need for deref
*/
if ( fRedraw ) {
if (ppopup = MNCheckMenuUp(pMenu)) {
// this menu is currently being displayed -- redisplay the menu,
// recomputing if necessary
xxxMNUpdateShownMenu(ppopup, pItem, FALSE);
}
}
//Unlock(&pMenu->spwndNotify);
}
return(TRUE);
}
#else // MEMPHIS_MENUS
BOOL NEAR SetLPITEMInfo(
PMENU pMenu,
PITEM pItem,
LPMENUITEMINFOW lpmii,
PUNICODE_STRING pstrItem)
{
if (lpmii->fMask & MIIM_TYPE) {
HANDLE hstr;
UINT cch;
UINT fType = lpmii->fType;
if (!(fType & MFT_NONSTRING)) {
if (lpmii->dwTypeData == 0)
fType = MFT_SEPARATOR;
else if (pstrItem->Length != 0) {
hstr = (HANDLE)DesktopAlloc(pMenu->head.rpdesk->hheapDesktop,
pstrItem->MaximumLength);
if (hstr == NULL)
return FALSE;
try {
RtlCopyMemory(hstr, pstrItem->Buffer, pstrItem->MaximumLength);
} except (EXCEPTION_EXECUTE_HANDLER) {
DesktopFree(pMenu->head.rpdesk->hheapDesktop, hstr);
return FALSE;
}
cch = pstrItem->Length / sizeof(WCHAR);
} else {
cch = 0;
hstr = NULL;
}
}
FreeTypeData(pMenu, pItem);
pItem->fType &= ~MFT_MASK;
pItem->fType |= fType;
if (fType & MFT_NONSTRING) {
if (fType & MFT_BITMAP)
pItem->hTypeData = lpmii->dwTypeData;
else {
if (fType & MFT_SEPARATOR)
pItem->fState |= MFS_DISABLED;
// if MFT_OWNERDRAW, LEAVE lpItem->dwTypeData ALONE !!
if ( !(fType & MFT_OWNERDRAW ) )
pItem->hTypeData = NULL;
}
pItem->cch = 0;
} else {
pItem->cch = cch;
pItem->hTypeData = hstr;
}
pItem->dxTab = 0;
pItem->ulX = UNDERLINE_RECALC;
pItem->ulWidth = 0;
// Set the size of this menu to be 0 so that it gets recomputed with this
// new item...
pMenu->cyMenu = pMenu->cxMenu = 0;
/*
* Chicago removed the counterpart to this line (hMenu->hwndNotify = 0)
* We probably still need for deref
*/
Unlock(&pMenu->spwndNotify);
}
if (lpmii->fMask & MIIM_ID)
pItem->wID = lpmii->wID;
if (lpmii->fMask & MIIM_DATA)
pItem->dwItemData = lpmii->dwItemData;
if (lpmii->fMask & MIIM_STATE) {
pItem->fState = lpmii->fState | (pItem->fState & (MFS_HILITE | MFS_DEFAULT));
if (pItem->fType & MFT_SEPARATOR)
pItem->fState |= MFS_DISABLED;
}
if (lpmii->fMask & MIIM_CHECKMARKS) {
pItem->hbmpChecked = lpmii->hbmpChecked;
pItem->hbmpUnchecked = lpmii->hbmpUnchecked;
}
if (lpmii->fMask & MIIM_SUBMENU) {
PMENU pSubMenu = NULL;
if (lpmii->hSubMenu != NULL)
pSubMenu = ValidateHmenu(lpmii->hSubMenu);
// Free the popup associated with this item, if any and if needed.
if (pItem->spSubMenu != pSubMenu) {
if (pItem->spSubMenu != NULL) {
FreePopup(pItem);
}
if (pSubMenu!=NULL) {
Lock(&(pItem->spSubMenu), pSubMenu);
SetMF(pItem->spSubMenu, MFISPOPUP);
} else
Unlock(&(pItem->spSubMenu));
}
}
return(TRUE);
}
#endif // MEMPHIS_MENUS
BOOL _SetMenuContextHelpId(PMENU pMenu, DWORD dwContextHelpId)
{
// Set the new context help Id;
pMenu->dwContextHelpId = dwContextHelpId;
return(TRUE); // Success!
}
#ifdef MEMPHIS_MENUS
// ----------------------------------------------------------------------------
//
// MNCheckMenuUp(PMENU)
//
// checks to see if the given hMenu is currently being shown in a popup.
// returns the PPOPUPMENU associated with this hMenu if it is being shown;
// NULL if the hMenu is not currently being shown
//
// ----------------------------------------------------------------------------
PPOPUPMENU MNCheckMenuUp(PMENU pMenu)
{
PTHREADINFO pti = NULL;
PWND pwnd = NULL;
PPOPUPMENU ppopup = NULL;
// check the hwndNotify's queue to see if it is currently in menu mode.
// If so, initialize the start condition for the popup search
// If not, we're not in menu mode, so bail.
if (!(pMenu->spwndNotify) ||
!(pti = pMenu->spwndNotify->head.pti) ||
!pti->MenuState.fInsideMenuLoop ||
!(ppopup = pti->MenuState.pGlobalPopupMenu->ppopupmenuRoot))
return(NULL);
while (TRUE)
{
if (ppopup->spmenu == pMenu)
// matching ppopup found -- return it
return(ppopup);
else if (!(pwnd = ppopup->spwndNextPopup))
// no more ppopup's found -- no match found -- return NULL
return(NULL);
// set up for next iteration to search next ppopup
ppopup = (PPOPUPMENU) ((PMENUWND)pwnd)->ppopupmenu;
}
}
// ----------------------------------------------------------------------------
//
// xxxMNUpdateShownMenu(PPOPUPMENU, LPITEM)
//
// updates a given ppopup menu window to reflect the inserting, deleting,
// or altering of the given lpItem.
//
// ----------------------------------------------------------------------------
void xxxMNUpdateShownMenu(PPOPUPMENU ppopup, PITEM pItem, BOOL fDelete)
{
RECT rc;
PWND pwnd = ppopup->spwndPopupMenu;
PMENU pMenu = ppopup->spmenu;
TL tlpwnd;
CopyRect( &rc, &(pwnd->rcClient) );
if (!pMenu->cxMenu) {
RECT rcScroll = rc;
int cySave = rc.bottom;
int cxSave = rc.right;
DWORD dwSize;
WORD fArrowFlags = 0;
/****** Activate after porting scrollable menus
// necessary evil -- compiler freaks out when I try to do this a bit
// more directly (i.e. fArrowsOld ^ hMenu->fArrowsOn) -- so I had to
// use this approach -- can cleanup in port to NT -- jeffbog 11/02/95
if (pMenu->fArrowsOn)
fArrowFlags = 1; */
ThreadLock(pwnd, &tlpwnd);
dwSize = xxxSendMessage(pwnd, MN_SIZEWINDOW, 1, 0L);
ThreadUnlock(&tlpwnd);
/*
if (hMenu->fArrowsOn)
fArrowFlags |= 2;
if ((fArrowFlags == 1) || (fArrowFlags == 2)) {
// scroll arrows appeared or disappeared -- redraw entire client
InvalidateRect(hwnd, NULL, TRUE);
return;
}
*/
rc.right = LOWORD(dwSize);
if (pItem) {
if (rc.right != cxSave) {
// width changed, redraw everything
// BUGBUG -- this could be tuned to just redraw items with
// submenus and/or accelerator fields
ThreadLock( pwnd, &tlpwnd);
xxxInvalidateRect(pwnd, NULL, TRUE);
ThreadUnlock( &tlpwnd );
}
/* Activate after scrollable menus
else {
rc.bottom = pMenu->cyMenu;
if (hMenu->fArrowsOn) {
if (rc.bottom <= cySave) {
rc.top = lpItem->yItem - MNTopItem(hMenu)->yItem;
goto InvalidateRest;
}
GetClientRect(hwnd, &rcScroll);
}
rc.top = rcScroll.top = lpItem->yItem - MNTopItem(hMenu)->yItem;
if ((rc.top >= 0) && (rc.top < hMenu->cyMenu))
ScrollWindowEx(hwnd, 0, rc.bottom - cySave, &rcScroll, &rc, NULL, NULL, SW_INVALIDATE | SW_ERASE);
}
*/
}
}
if ( pItem && !fDelete) {
// if the item is not being deleted, then we need to redraw it
// rc.top = pItem->yItem - MNTopItem(hMenu)->yItem;
rc.top = pItem->yItem - pMenu->rgItems->yItem;
rc.bottom = rc.top + pItem->cyItem;
//InvalidateRest:
if ((rc.top >= 0) && (rc.top < (LONG)pMenu->cyMenu)) {
ThreadLock( pwnd, &tlpwnd);
xxxInvalidateRect(pwnd, &rc, TRUE);
ThreadUnlock( &tlpwnd );
}
}
if ( !pItem && !fDelete) {
ThreadLock( pwnd, &tlpwnd);
xxxInvalidateRect(pwnd, NULL, TRUE);
ThreadUnlock( &tlpwnd );
}
}
#endif // MEMPHIS_MENUS