Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

menu.c File Reference

#include "precomp.h"

Go to the source code of this file.

Defines

#define pmenuNext   (((PMENUWND)ppopupmenu->spwndNextPopup)->ppopupmenu->spmenu)

Functions

void xxxMNDismiss (PMENUSTATE pMenuState)
BOOL MNFadeSelection (PMENU pmenu, PITEM pitem)
void xxxMNDismissWithNotify (PMENUSTATE pMenuState, PMENU pmenu, PITEM pitem, UINT uPos, LPARAM lParam)
PITEM MNGetpItem (PPOPUPMENU ppopup, UINT uIndex)
void xxxMNSetCapture (PPOPUPMENU ppopup)
void xxxMNReleaseCapture (void)
void MNCheckButtonDownState (PMENUSTATE pMenuState)
PWND GetMenuStateWindow (PMENUSTATE pMenuState)
void UnlockPopupMenuWindow (PMENU pmenu, PWND pwnd)
PVOID LockPopupMenu (PPOPUPMENU ppopup, PMENU *pspmenu, PMENU pmenu)
PVOID UnlockPopupMenu (PPOPUPMENU ppopup, PMENU *pspmenu)
PVOID LockWndMenu (PWND pwnd, PMENU *pspmenu, PMENU pmenu)
PVOID UnlockWndMenu (PWND pwnd, PMENU *pspmenu)
BOOL xxxMNSetTop (PPOPUPMENU ppopup, int iNewTop)
BOOL xxxMNDoScroll (PPOPUPMENU ppopup, UINT uArrow, BOOL fSetTimer)
int MNCheckScroll (PMENU pMenu, PMONITOR pMonitor)
BOOL MNIsPopupItem (ITEM *lpItem)
BOOL xxxMNSwitchToAlternateMenu (PPOPUPMENU ppopupmenu)
void xxxMNDestroyHandler (PPOPUPMENU ppopupmenu)
void xxxMNChar (PPOPUPMENU ppopupmenu, PMENUSTATE pMenuState, UINT character)
DWORD GetMenuInheritedContextHelpId (PPOPUPMENU ppopup)
void xxxMNKeyDown (PPOPUPMENU ppopupmenu, PMENUSTATE pMenuState, UINT key)
UINT xxxMNPositionHierarchy (PPOPUPMENU ppopup, PITEM pitem, int cx, int cy, int *px, int *py, PMONITOR *ppMonitor)
void xxxCleanupDesktopMenu (PWND pwndDeskMenu, PDESKTOP pdesk)
PWND xxxMNOpenHierarchy (PPOPUPMENU ppopupmenu, PMENUSTATE pMenuState)
BOOL xxxMNHideNextHierarchy (PPOPUPMENU ppopup)
void xxxMNCloseHierarchy (PPOPUPMENU ppopupmenu, PMENUSTATE pMenuState)
BOOL xxxMNDoubleClick (PMENUSTATE pMenuState, PPOPUPMENU ppopup, int idxItem)
PITEM xxxMNSelectItem (PPOPUPMENU ppopupmenu, PMENUSTATE pMenuState, UINT itemPos)
UINT MNItemHitTest (PMENU pMenu, PWND pwnd, POINT pt)
void LockMFMWFPWindow (PULONG_PTR puHitArea, ULONG_PTR uNewHitArea)
void UnlockMFMWFPWindow (PULONG_PTR puHitArea)
BOOL IsMFMWFPWindow (ULONG_PTR uHitArea)
LONG_PTR xxxMNFindWindowFromPoint (PPOPUPMENU ppopupmenu, PUINT pIndex, POINTS screenPt)
void xxxMNCancel (PMENUSTATE pMenuState, UINT uMsg, UINT cmd, LPARAM lParam)
void xxxMNButtonDown (PPOPUPMENU ppopupmenu, PMENUSTATE pMenuState, UINT posItemHit, BOOL fClick)
void MNSetTimerToAutoDismiss (PMENUSTATE pMenuState, PWND pwnd)
void xxxMNMouseMove (PPOPUPMENU ppopup, PMENUSTATE pMenuState, POINTS ptScreen)
void xxxMNButtonUp (PPOPUPMENU ppopup, PMENUSTATE pMenuState, UINT posItemHit, LPARAM lParam)
UINT MNSetTimerToOpenHierarchy (PPOPUPMENU ppopup)
UINT MNSetTimerToCloseHierarchy (PPOPUPMENU ppopup)
BOOL xxxCallHandleMenuMessages (PMENUSTATE pMenuState, PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam)
LRESULT xxxMenuWindowProc (PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam)


Define Documentation

#define pmenuNext   (((PMENUWND)ppopupmenu->spwndNextPopup)->ppopupmenu->spmenu)
 

Referenced by xxxMenuWindowProc().


Function Documentation

DWORD GetMenuInheritedContextHelpId PPOPUPMENU  ppopup  ) 
 

Definition at line 1196 of file ntuser/kernel/menu.c.

References tagMENU::dwContextHelpId, DWORD, tagPOPUPMENU::fHasMenuBar, tagPOPUPMENU::fIsMenuBar, NULL, tagPOPUPMENU::spmenu, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPrevPopup, and TRUE.

Referenced by xxxMNKeyDown().

01197 { 01198 PWND pWnd; 01199 01200 /* 01201 * If we are already at the menubar, simply return it's ContextHelpId 01202 */ 01203 UserAssert(ppopup != NULL); 01204 if (ppopup->fIsMenuBar) 01205 goto Exit_GMI; 01206 01207 while(TRUE) { 01208 UserAssert(ppopup != NULL); 01209 01210 /* 01211 * See if the given popup has a context help id. 01212 */ 01213 if (ppopup->spmenu->dwContextHelpId) { 01214 /* Found the context Id */ 01215 break; 01216 } 01217 01218 /* 01219 * Get the previous popup menu; 01220 * Check if the previous menu is the menu bar. 01221 */ 01222 if ( (ppopup->fHasMenuBar) && 01223 (ppopup->spwndPrevPopup == ppopup->spwndNotify)) { 01224 01225 ppopup = ppopup -> ppopupmenuRoot; 01226 break; 01227 } else { 01228 /* 01229 * See if this has a valid prevPopup; (it could be TrackPopup menu) 01230 */ 01231 if ((pWnd = ppopup -> spwndPrevPopup) == NULL) { 01232 return ((DWORD)0); 01233 } 01234 01235 ppopup = ((PMENUWND)pWnd)->ppopupmenu; 01236 } 01237 } 01238 01239 Exit_GMI: 01240 return(ppopup->spmenu->dwContextHelpId); 01241 }

PWND GetMenuStateWindow PMENUSTATE  pMenuState  ) 
 

Definition at line 232 of file ntuser/kernel/menu.c.

References tagPOPUPMENU::fIsTrackPopup, NULL, tagMENUSTATE::pGlobalPopupMenu, tagPOPUPMENU::spwndActivePopup, tagPOPUPMENU::spwndNextPopup, and tagPOPUPMENU::spwndPopupMenu.

Referenced by NtUserEndMenu(), xxxHandleMenuMessages(), and xxxMNDragOver().

00233 { 00234 if (pMenuState == NULL) { 00235 return NULL; 00236 } else if (pMenuState->pGlobalPopupMenu->fIsTrackPopup) { 00237 return pMenuState->pGlobalPopupMenu->spwndPopupMenu; 00238 } else if (pMenuState->pGlobalPopupMenu->spwndNextPopup != NULL) { 00239 return pMenuState->pGlobalPopupMenu->spwndNextPopup; 00240 } else { 00241 return pMenuState->pGlobalPopupMenu->spwndActivePopup; 00242 } 00243 }

BOOL IsMFMWFPWindow ULONG_PTR  uHitArea  ) 
 

Definition at line 3145 of file ntuser/kernel/menu.c.

References BOOL, FALSE, MFMWFP_ALTMENU, MFMWFP_NOITEM, MFMWFP_OFFMENU, and TRUE.

Referenced by LockMFMWFPWindow(), UnlockMFMWFPWindow(), xxxHandleMenuMessages(), xxxMenuWindowProc(), xxxMNFindWindowFromPoint(), xxxMNSetGapState(), and xxxMNUpdateDraggingInfo().

03146 { 03147 switch(uHitArea) { 03148 case MFMWFP_OFFMENU: 03149 case MFMWFP_NOITEM: 03150 case MFMWFP_ALTMENU: 03151 return FALSE; 03152 03153 default: 03154 return TRUE; 03155 } 03156 }

void LockMFMWFPWindow PULONG_PTR  puHitArea,
ULONG_PTR  uNewHitArea
 

Definition at line 3097 of file ntuser/kernel/menu.c.

References IsMFMWFPWindow(), Lock, and UnlockMFMWFPWindow().

Referenced by xxxHandleMenuMessages(), and xxxMNUpdateDraggingInfo().

03098 { 03099 /* 03100 * Bail if there is nothing to do. 03101 */ 03102 if (*puHitArea == uNewHitArea) { 03103 return; 03104 } 03105 03106 /* 03107 * Unlock current hit area 03108 */ 03109 UnlockMFMWFPWindow(puHitArea); 03110 03111 /* 03112 * Lock new hit area 03113 */ 03114 if (IsMFMWFPWindow(uNewHitArea)) { 03115 Lock(puHitArea, (PWND)uNewHitArea); 03116 } else { 03117 *puHitArea = uNewHitArea; 03118 } 03119 }

PVOID LockPopupMenu PPOPUPMENU  ppopup,
PMENU pspmenu,
PMENU  pmenu
 

Definition at line 296 of file ntuser/kernel/menu.c.

References tagWND::head, Lock, NULL, tagPOPUPMENU::spmenu, tagPOPUPMENU::spmenuAlternate, tagPOPUPMENU::spwndNotify, tagMENU::spwndNotify, UnlockPopupMenuWindow(), and Validateppopupmenu.

Referenced by xxxMenuWindowProc(), xxxMNKeyDown(), xxxMNOpenHierarchy(), xxxMNStartMenu(), and xxxTrackPopupMenuEx().

00297 { 00298 /* 00299 * If you hit this assertion, you're probably not passing the right thing 00300 */ 00301 UserAssert((pspmenu == &ppopup->spmenu) || (pspmenu == &ppopup->spmenuAlternate)); 00302 Validateppopupmenu(ppopup); 00303 /* 00304 * This won't work properly if the popup hasn't locked the notification 00305 * window. 00306 */ 00307 UserAssert(ppopup->spwndNotify != NULL); 00308 00309 /* 00310 * When using modeless menus, menus can be shared by several active popups. 00311 * If the menu has owner draw items, the app better knows how to draw them 00312 * correctly. This shouldn't happen with modal menus though 00313 */ 00314 #if DBG 00315 if ((*pspmenu != NULL) 00316 && ((*pspmenu)->spwndNotify != NULL) 00317 && ((*pspmenu)->spwndNotify != ppopup->spwndNotify)) { 00318 00319 RIPMSG3(RIP_WARNING, "LockPopupMenu: Current Menu %#p shared by %#p and %#p", 00320 *pspmenu, (*pspmenu)->spwndNotify, ppopup->spwndNotify); 00321 } 00322 #endif 00323 00324 /* 00325 * Unlock the current's menu spwndNotify if needed 00326 */ 00327 UnlockPopupMenuWindow(*pspmenu, ppopup->spwndNotify); 00328 00329 /* 00330 * Lock the notification window into the menu structure 00331 */ 00332 if (pmenu != NULL) { 00333 00334 /* 00335 * Display a warning if this menu is being shared 00336 */ 00337 #if DBG 00338 if ((pmenu->spwndNotify != NULL) 00339 && (pmenu->spwndNotify != ppopup->spwndNotify) 00340 && (pmenu != pmenu->spwndNotify->head.rpdesk->spmenuDialogSys)) { 00341 00342 RIPMSG3(RIP_WARNING, "LockPopupMenu: New Menu %#p shared by %#p and %#p", 00343 pmenu, pmenu->spwndNotify, ppopup->spwndNotify); 00344 } 00345 #endif 00346 00347 /* 00348 * spwndNotify "owns" this menu now. 00349 */ 00350 Lock(&pmenu->spwndNotify, ppopup->spwndNotify); 00351 } 00352 00353 /* 00354 * Lock the menu into the popup structure (unlock the previous one) 00355 */ 00356 return Lock(pspmenu, pmenu); 00357 }

PVOID LockWndMenu PWND  pwnd,
PMENU pspmenu,
PMENU  pmenu
 

Definition at line 422 of file ntuser/kernel/menu.c.

References Lock, NULL, tagWND::spmenu, tagWND::spmenuSys, tagMENU::spwndNotify, and Unlock.

Referenced by xxxCreateWindowEx(), xxxGetSystemMenu(), xxxSetDialogSystemMenu(), xxxSetMenu(), xxxSetSystemMenu(), and xxxSetWindowData().

00423 { 00424 /* 00425 * If you hit this assertion, you're probably not passing the right thing 00426 */ 00427 UserAssert((pspmenu == &pwnd->spmenu) || (pspmenu == &pwnd->spmenuSys)); 00428 00429 /* 00430 * If the current menu is owned by this window, unlock it 00431 */ 00432 if ((*pspmenu != NULL) && ((*pspmenu)->spwndNotify == pwnd)) { 00433 Unlock(&((*pspmenu)->spwndNotify)); 00434 } 00435 00436 /* 00437 * If nobody owns the new menu, make this window the owner 00438 */ 00439 if ((pmenu != NULL) && (pmenu->spwndNotify == NULL)) { 00440 Lock(&pmenu->spwndNotify, pwnd); 00441 } 00442 00443 /* 00444 * Lock the menu into the window structure (unlock the previous menu) 00445 */ 00446 return Lock(pspmenu, pmenu); 00447 00448 }

void MNCheckButtonDownState PMENUSTATE  pMenuState  ) 
 

Definition at line 206 of file ntuser/kernel/menu.c.

References _GetKeyState(), FALSE, tagMENUSTATE::fButtonDown, tagMENUSTATE::fDragAndDrop, tagMENUSTATE::fDragging, tagMENUSTATE::fIgnoreButtonUp, tagMENUSTATE::fModelessMenu, tagMENUSTATE::uButtonDownHitArea, UnlockMFMWFPWindow(), and tagMENUSTATE::vkButtonDown.

Referenced by xxxCallHandleMenuMessages(), and xxxMenuWindowProc().

00207 { 00208 /* 00209 * Modeless menus don't capture the mouse so when a mouse down 00210 * goes off the window, we need to keep watching its state. 00211 * We also might not see the button up when going on DoDragDrop loop 00212 */ 00213 UserAssert(pMenuState->fDragAndDrop || pMenuState->fModelessMenu); 00214 pMenuState->fButtonDown = ((_GetKeyState(pMenuState->vkButtonDown) & 0x8000) != 0); 00215 if (!pMenuState->fButtonDown) { 00216 pMenuState->fDragging = 00217 pMenuState->fIgnoreButtonUp = FALSE; 00218 UnlockMFMWFPWindow(&pMenuState->uButtonDownHitArea); 00219 } 00220 }

int MNCheckScroll PMENU  pMenu,
PMONITOR  pMonitor
 

Definition at line 627 of file ntuser/kernel/menu.c.

References tagMENU::cItems, tagITEM::cxItem, tagMENU::cxMenu, tagITEM::cyItem, tagMENU::cyMax, tagMENU::cyMenu, tagMENU::dwArrowsOn, gcyMenuScrollArrow, tagMENU::iMaxTop, tagMENU::iTop, MSA_ATBOTTOM, MSA_ATTOP, MSA_OFF, MSA_ON, tagMONITOR::rcMonitor, tagMENU::rgItems, SYSMET, UINT, and tagITEM::yItem.

Referenced by xxxMenuWindowProc().

00628 { 00629 int i; 00630 UINT cyMax; 00631 PITEM pItem; 00632 00633 /* 00634 * Max height that fits on the monitor 00635 */ 00636 cyMax = (pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top); 00637 00638 /* 00639 * If the menu has a valid max height, use it 00640 */ 00641 if ((pMenu->cyMax != 0) && (pMenu->cyMax < cyMax)) { 00642 cyMax = pMenu->cyMax; 00643 } 00644 00645 /* 00646 * Bail if menu is either empty, multicolumn, or able to fit 00647 * without scrolling 00648 */ 00649 if ((pMenu->rgItems == 0) 00650 || (pMenu->rgItems->cxItem != pMenu->cxMenu) 00651 || (pMenu->cyMenu + (2 * SYSMET(CYFIXEDFRAME)) <= cyMax)) { 00652 00653 pMenu->dwArrowsOn = MSA_OFF; 00654 pMenu->iTop = 0; 00655 pMenu->iMaxTop = 0; 00656 return pMenu->cyMenu; 00657 } 00658 00659 /* 00660 * Max client height 00661 */ 00662 cyMax -= 2 * (SYSMET(CYFIXEDFRAME) + gcyMenuScrollArrow); 00663 00664 /* 00665 * Determine the menu height 00666 * Find the first item that won't fit. 00667 */ 00668 pItem = pMenu->rgItems; 00669 for (i = 0; i < (int)pMenu->cItems; i++, pItem++) { 00670 if (pItem->yItem > (UINT)cyMax) { 00671 break; 00672 } 00673 } 00674 if (i != 0) { 00675 pItem--; 00676 } 00677 pMenu->cyMenu = pItem->yItem; 00678 00679 /* 00680 * compute the last possible top item when all remaining items are fully 00681 * visible 00682 */ 00683 cyMax = 0; 00684 i = pMenu->cItems - 1; 00685 pItem = pMenu->rgItems + i; 00686 for (; i >= 0; i--, pItem--) { 00687 cyMax += pItem->cyItem; 00688 if (cyMax > pMenu->cyMenu) { 00689 break; 00690 } 00691 } 00692 if ((UINT)i != pMenu->cItems - 1) { 00693 i++; 00694 } 00695 pMenu->iMaxTop = i; 00696 00697 /* 00698 * Update top item and scroll state 00699 */ 00700 if (pMenu->iTop > i) { 00701 pMenu->iTop = i; 00702 } 00703 00704 if (pMenu->iTop == i) { 00705 pMenu->dwArrowsOn = MSA_ATBOTTOM; 00706 } else if (pMenu->iTop == 0) { 00707 pMenu->dwArrowsOn = MSA_ATTOP; 00708 } else { 00709 pMenu->dwArrowsOn = MSA_ON; 00710 } 00711 00712 /* 00713 * This is funtion is called by MN_SIZEWINDOW which doesn't check 00714 * if the scroll bars are present but simply adds (2 * SYSMET(CYFIXEDFRAME)) 00715 * to calculate the window height. So we add the scrollbars height 00716 * here. (I believe MN_SIZEWINDOW is a private-but-publicly-known message) 00717 */ 00718 return (pMenu->cyMenu + (2 * gcyMenuScrollArrow)); 00719 }

BOOL MNFadeSelection PMENU  pmenu,
PITEM  pitem
 

Definition at line 47 of file ntuser/kernel/menu.c.

References BOOL, CMS_SELECTIONFADE, CreateFade(), tagITEM::cxItem, tagITEM::cyItem, FALSE, gpDispInfo, tagDISPLAYINFO::hdcScreen, MNGetPopupFromMenu(), NULL, tagWND::rcClient, ShowFade(), tagPOPUPMENU::spwndPopupMenu, TestALPHA, TRUE, tagITEM::xItem, and tagITEM::yItem.

Referenced by xxxMNDismissWithNotify().

00048 { 00049 PWND pwnd; 00050 HDC hdc; 00051 RECT rc; 00052 PPOPUPMENU ppopup; 00053 00054 if (!TestALPHA(SELECTIONFADE)) 00055 return FALSE; 00056 00057 /* 00058 * Get the window for the currently active popup menu. 00059 */ 00060 if ((ppopup = MNGetPopupFromMenu(pmenu, NULL)) == NULL) 00061 return FALSE; 00062 00063 if ((pwnd = ppopup->spwndPopupMenu) == NULL) 00064 return FALSE; 00065 00066 rc.left = pwnd->rcClient.left + pitem->xItem; 00067 rc.top = pwnd->rcClient.top + pitem->yItem; 00068 rc.right = rc.left + pitem->cxItem; 00069 rc.bottom = rc.top + pitem->cyItem; 00070 00071 /* 00072 * Initialize the fade animation and get the DC to draw the selection into. 00073 */ 00074 if ((hdc = CreateFade(NULL, &rc, CMS_SELECTIONFADE, 0)) == NULL) 00075 return FALSE; 00076 00077 /* 00078 * Read the current menu selection right from the screen, since the menu 00079 * is still visible and it's always on top. In the worst case we could 00080 * offset the origin of the DC and call xxxDrawMenuItem, but just reading 00081 * from the screen is much faster. 00082 */ 00083 GreBitBlt(hdc, 0, 0, pitem->cxItem, pitem->cyItem, gpDispInfo->hdcScreen, 00084 rc.left, rc.top, SRCCOPY, 0); 00085 00086 ShowFade(); 00087 00088 return TRUE; 00089 }

PITEM MNGetpItem PPOPUPMENU  ppopup,
UINT  uIndex
 

Definition at line 136 of file ntuser/kernel/menu.c.

References tagMENU::cItems, NULL, tagMENU::rgItems, and tagPOPUPMENU::spmenu.

Referenced by xxxMenuWindowProc(), xxxMNSetGapState(), and xxxMNUpdateDraggingInfo().

00137 { 00138 if ((ppopup == NULL) 00139 || (uIndex >= ppopup->spmenu->cItems)) { 00140 00141 return NULL; 00142 } 00143 00144 return ppopup->spmenu->rgItems + uIndex; 00145 }

BOOL MNIsPopupItem ITEM lpItem  ) 
 

Definition at line 727 of file ntuser/kernel/menu.c.

References BOOL, ITEM, tagITEM::spSubMenu, and TestMFS.

Referenced by xxxMNButtonDown().

00728 { 00729 return((lpItem) && (lpItem->spSubMenu) && 00730 !TestMFS(lpItem, MFS_GRAYED)); 00731 }

UINT MNItemHitTest PMENU  pMenu,
PWND  pwnd,
POINT  pt
 

Definition at line 2983 of file ntuser/kernel/menu.c.

References tagMENU::cItems, tagQ::codeCapture, CopyInflateRect(), tagITEM::cxItem, tagITEM::cyItem, tagMENU::cyMenu, tagMENU::dwArrowsOn, tagMENU::iTop, MFISPOPUP, MFMWFP_DOWNARROW, MFMWFP_NOITEM, MFMWFP_UPARROW, MNGetToppItem(), MSA_OFF, NO_CAP_SYS, tagTHREADINFO::pq, PtiCurrent, PtInRect(), tagWND::rcClient, tagWND::rcWindow, tagMENU::rgItems, SCREEN_CAPTURE, SYSMET, TestMF, TestWF, and UINT.

Referenced by FindNCHitEx(), xxxMenuItemFromPoint(), and xxxMNFindWindowFromPoint().

02984 { 02985 PITEM pItem; 02986 UINT iItem; 02987 RECT rect; 02988 02989 PTHREADINFO ptiCurrent = PtiCurrent(); 02990 02991 if (pMenu->cItems == 0) 02992 return MFMWFP_NOITEM; 02993 02994 02995 /* 02996 * This point is screen-relative. Menu bar coordinates relative 02997 * to the window. But popup menu coordinates are relative to the client. 02998 */ 02999 if (TestMF(pMenu, MFISPOPUP)) { 03000 03001 /* 03002 * Bail if it's outside rcWindow 03003 */ 03004 CopyInflateRect(&rect, &(pwnd->rcWindow), 03005 -SYSMET(CXFIXEDFRAME), -SYSMET(CYFIXEDFRAME)); 03006 03007 if (!PtInRect(&rect, pt)) { 03008 return MFMWFP_NOITEM; 03009 } 03010 03011 /* ScreenToClient */ 03012 #ifdef USE_MIRRORING 03013 if (TestWF(pwnd, WEFLAYOUTRTL)) { 03014 pt.x = pwnd->rcClient.right - pt.x; 03015 } else 03016 #endif 03017 { 03018 pt.x -= pwnd->rcClient.left; 03019 } 03020 pt.y -= pwnd->rcClient.top; 03021 03022 /* 03023 * If on the non client area, then it's on the scroll arrows 03024 */ 03025 if (pt.y < 0) { 03026 return MFMWFP_UPARROW; 03027 } else if (pt.y > (int)pMenu->cyMenu) { 03028 return MFMWFP_DOWNARROW; 03029 } 03030 03031 } else { 03032 /* ScreenToWindow */ 03033 #ifdef USE_MIRRORING 03034 if (TestWF(pwnd, WEFLAYOUTRTL) && 03035 ( 03036 (ptiCurrent->pq->codeCapture == SCREEN_CAPTURE) || (ptiCurrent->pq->codeCapture == NO_CAP_SYS) 03037 ) 03038 ) { 03039 pt.x = pwnd->rcWindow.right - pt.x; 03040 } else 03041 #endif 03042 { 03043 pt.x -= pwnd->rcWindow.left; 03044 } 03045 pt.y -= pwnd->rcWindow.top; 03046 } 03047 03048 /* 03049 * Step through all the items in the menu. 03050 * If scrollable menu 03051 */ 03052 if (pMenu->dwArrowsOn != MSA_OFF) { 03053 UserAssert(TestMF(pMenu, MFISPOPUP)); 03054 pItem = MNGetToppItem(pMenu); 03055 rect.left = rect.top = 0; 03056 rect.right = pItem->cxItem; 03057 rect.bottom = pItem->cyItem; 03058 for (iItem = pMenu->iTop; (iItem < (int)pMenu->cItems) && (rect.top < (int)pMenu->cyMenu); iItem++) { 03059 03060 if (PtInRect(&rect, pt)) { 03061 return iItem; 03062 } 03063 03064 pItem++; 03065 rect.top = rect.bottom; 03066 rect.bottom += pItem->cyItem; 03067 } 03068 } else { 03069 /* 03070 * No scroll bars. 03071 */ 03072 for (iItem = 0, pItem = pMenu->rgItems; iItem < pMenu->cItems; iItem++, pItem++) { 03073 /* Is the mouse inside this item's rectangle? */ 03074 rect.left = pItem->xItem; 03075 rect.top = pItem->yItem; 03076 rect.right = pItem->xItem + pItem->cxItem; 03077 rect.bottom = pItem->yItem + pItem->cyItem; 03078 03079 if (PtInRect(&rect, pt)) { 03080 return(iItem); 03081 } 03082 } 03083 } 03084 03085 03086 return(MFMWFP_NOITEM); 03087 }

void MNSetTimerToAutoDismiss PMENUSTATE  pMenuState,
PWND  pwnd
 

Definition at line 3600 of file ntuser/kernel/menu.c.

References _SetTimer(), tagMENUSTATE::fAboutToAutoDismiss, tagMENUSTATE::fAutoDismiss, gdtMNDropDown, IDSYS_MNAUTODISMISS, NULL, and TRUE.

Referenced by xxxMenuWindowProc(), and xxxMNMouseMove().

03601 { 03602 if (pMenuState->fAutoDismiss && !pMenuState->fAboutToAutoDismiss) { 03603 if (_SetTimer(pwnd, IDSYS_MNAUTODISMISS, 16 * gdtMNDropDown, NULL)) { 03604 pMenuState->fAboutToAutoDismiss = TRUE; 03605 } else { 03606 RIPMSG0(RIP_WARNING, "xxxMNMouseMove: Failed to set autodismiss timer"); 03607 } 03608 } 03609 }

UINT MNSetTimerToCloseHierarchy PPOPUPMENU  ppopup  ) 
 

Definition at line 3917 of file ntuser/kernel/menu.c.

References _SetTimer(), tagPOPUPMENU::fAboutToHide, tagPOPUPMENU::fHideTimer, tagPOPUPMENU::fHierarchyDropped, gdtMNDropDown, IDSYS_MNHIDE, NULL, tagPOPUPMENU::spwndNextPopup, tagPOPUPMENU::spwndPopupMenu, TRUE, and UINT.

Referenced by xxxMNSelectItem().

03918 { 03919 03920 if (!ppopup->fHierarchyDropped) 03921 return(0); 03922 03923 if (ppopup->fHideTimer) 03924 return(1); 03925 03926 if (!_SetTimer(ppopup->spwndPopupMenu, IDSYS_MNHIDE, gdtMNDropDown, NULL)) 03927 return((UINT) -1); 03928 03929 ppopup->fHideTimer = TRUE; 03930 03931 ppopup = ((PMENUWND)(ppopup->spwndNextPopup))->ppopupmenu; 03932 ppopup->fAboutToHide = TRUE; 03933 03934 return(1); 03935 }

UINT MNSetTimerToOpenHierarchy PPOPUPMENU  ppopup  ) 
 

Definition at line 3870 of file ntuser/kernel/menu.c.

References _SetTimer(), tagMENU::cItems, tagPOPUPMENU::fHierarchyDropped, tagPOPUPMENU::fShowTimer, tagITEM::fState, gdtMNDropDown, IDSYS_MNSHOW, MFMWFP_NOITEM, NULL, tagPOPUPMENU::posDropped, tagPOPUPMENU::posSelectedItem, tagMENU::rgItems, tagPOPUPMENU::spmenu, tagITEM::spSubMenu, tagPOPUPMENU::spwndPopupMenu, TRUE, and UINT.

Referenced by xxxMenuWindowProc().

03872 { 03873 PITEM pItem; 03874 03875 /* 03876 * No selection so fail 03877 */ 03878 if (ppopup->posSelectedItem == MFMWFP_NOITEM) 03879 return(0); 03880 03881 if (ppopup->posSelectedItem >= ppopup->spmenu->cItems) 03882 return(0); 03883 03884 /* 03885 * Is item an enabled popup? 03886 * Get a pointer to the currently selected item in this menu. 03887 */ 03888 pItem = ppopup->spmenu->rgItems + ppopup->posSelectedItem; 03889 if ((pItem->spSubMenu == NULL) || (pItem->fState & MFS_GRAYED)) 03890 return(0); 03891 03892 if (ppopup->fShowTimer 03893 || (ppopup->fHierarchyDropped 03894 && (ppopup->posSelectedItem == ppopup->posDropped))) { 03895 03896 /* 03897 * A timer is already set or the hierarchy is already opened. 03898 */ 03899 return 1; 03900 } 03901 03902 if (!_SetTimer(ppopup->spwndPopupMenu, IDSYS_MNSHOW, gdtMNDropDown, NULL)) 03903 return (UINT)-1; 03904 03905 ppopup->fShowTimer = TRUE; 03906 03907 return 1; 03908 }

void UnlockMFMWFPWindow PULONG_PTR  puHitArea  ) 
 

Definition at line 3128 of file ntuser/kernel/menu.c.

References IsMFMWFPWindow(), MFMWFP_OFFMENU, and Unlock.

Referenced by LockMFMWFPWindow(), MNCheckButtonDownState(), xxxHandleMenuMessages(), xxxMNDragLeave(), and xxxMNEndMenuState().

03129 { 03130 if (IsMFMWFPWindow(*puHitArea)) { 03131 Unlock(puHitArea); 03132 } else { 03133 *puHitArea = MFMWFP_OFFMENU; 03134 } 03135 }

PVOID UnlockPopupMenu PPOPUPMENU  ppopup,
PMENU pspmenu
 

Definition at line 367 of file ntuser/kernel/menu.c.

References IsRootPopupMenu(), NULL, tagPOPUPMENU::spmenu, tagPOPUPMENU::spmenuAlternate, tagPOPUPMENU::spwndNotify, Unlock, and UnlockPopupMenuWindow().

Referenced by MNFreePopup(), and xxxMNKeyDown().

00368 { 00369 /* 00370 * If you hit this assertion, you're probably not passing the right thing 00371 */ 00372 UserAssert((pspmenu == &ppopup->spmenu) || (pspmenu == &ppopup->spmenuAlternate)); 00373 /* 00374 * If nothing is locked, bail. 00375 */ 00376 if (*pspmenu == NULL) { 00377 return NULL; 00378 } 00379 00380 /* 00381 * This won't work properly if the popup already unlocked the notification 00382 * window. However, this can happen with the root popup if the 00383 * notification window gets destroyed while in menu mode. 00384 */ 00385 UserAssert((ppopup->spwndNotify != NULL) || IsRootPopupMenu(ppopup)); 00386 00387 /* 00388 * When using modeless menus, menus can be shared by several active 00389 * popups/notification windows. If the menu has owner draw items, 00390 * the app better knows how to paint them right. It shouldn't 00391 * happen with modal menus though. 00392 */ 00393 #if DBG 00394 if (((*pspmenu)->spwndNotify != NULL) 00395 && (ppopup->spwndNotify != NULL) 00396 && (ppopup->spwndNotify != (*pspmenu)->spwndNotify)) { 00397 00398 RIPMSG3(RIP_WARNING, "UnlockPopupMenu: Menu %#p shared by %#p and %#p", 00399 *pspmenu, (*pspmenu)->spwndNotify, ppopup->spwndNotify); 00400 } 00401 #endif 00402 00403 /* 00404 * Unlock the menu's spwndNotify if needed 00405 */ 00406 UnlockPopupMenuWindow(*pspmenu, ppopup->spwndNotify); 00407 00408 /* 00409 * Unlock the menu from the popup structure 00410 */ 00411 return Unlock(pspmenu); 00412 }

void UnlockPopupMenuWindow PMENU  pmenu,
PWND  pwnd
 

Definition at line 258 of file ntuser/kernel/menu.c.

References NULL, tagWND::spmenu, tagWND::spmenuSys, tagMENU::spwndNotify, TestWF, Unlock, and WFDESTROYED.

Referenced by LockPopupMenu(), and UnlockPopupMenu().

00259 { 00260 /* 00261 * Bail if there's nothing to unlock 00262 */ 00263 if ((pmenu == NULL) 00264 || (pmenu->spwndNotify == NULL)) { 00265 return; 00266 } 00267 /* 00268 * if pmenu->spwndNotify owns the menu, bail 00269 */ 00270 if ((pmenu == pmenu->spwndNotify->spmenu) 00271 || (pmenu == pmenu->spwndNotify->spmenuSys)) { 00272 return; 00273 } 00274 /* 00275 * If pwnd doesn't own the menu, and pmenu->spwndNotify is not destroyed, bail 00276 */ 00277 if ((pwnd != pmenu->spwndNotify) 00278 && !TestWF(pmenu->spwndNotify, WFDESTROYED)) { 00279 return; 00280 } 00281 /* 00282 * Unlock it 00283 */ 00284 Unlock(&pmenu->spwndNotify); 00285 return; 00286 }

PVOID UnlockWndMenu PWND  pwnd,
PMENU pspmenu
 

Definition at line 458 of file ntuser/kernel/menu.c.

References NULL, tagWND::spmenu, tagWND::spmenuSys, and Unlock.

Referenced by xxxFreeWindow(), xxxGetSystemMenu(), xxxSetWindowData(), and xxxSetWindowStyle().

00459 { 00460 /* 00461 * If you hit this assertion, you're probably not passing the right thing 00462 */ 00463 UserAssert((pspmenu == &pwnd->spmenu) || (pspmenu == &pwnd->spmenuSys)); 00464 00465 /* 00466 * If nothing is locked, bail 00467 */ 00468 if (*pspmenu == NULL) { 00469 return NULL; 00470 } 00471 00472 /* 00473 * If this window owns the menu, unlock it from the menu strucutre 00474 */ 00475 if (pwnd == (*pspmenu)->spwndNotify) { 00476 Unlock(&((*pspmenu)->spwndNotify)); 00477 } 00478 00479 /* 00480 * Unlock the menu from the window structure 00481 */ 00482 return Unlock(pspmenu); 00483 }

BOOL xxxCallHandleMenuMessages PMENUSTATE  pMenuState,
PWND  pwnd,
UINT  message,
WPARAM  wParam,
LPARAM  lParam
 

Definition at line 3951 of file ntuser/kernel/menu.c.

References BOOL, CheckLock, ExitMenuLoop(), FALSE, tagMENUSTATE::fButtonDown, tagMENUSTATE::fInCallHandleMenuMessages, tagMENUSTATE::fInDoDragDrop, tagMENUSTATE::fModelessMenu, tagMENUSTATE::fMouseOffMenu, GET_X_LPARAM, GET_Y_LPARAM, HW, MNCheckButtonDownState(), msg, NULL, tagMENUSTATE::pGlobalPopupMenu, tagWND::rcClient, TRUE, xxxEndMenuLoop(), xxxHandleMenuMessages(), and xxxMNEndMenuState().

Referenced by xxxMenuWindowProc(), xxxMNDragOver(), and xxxScanSysQueue().

03952 { 03953 BOOL fHandled; 03954 MSG msg; 03955 03956 CheckLock(pwnd); 03957 03958 UserAssert(pMenuState->fModelessMenu || pMenuState->fInDoDragDrop); 03959 03960 /* 03961 * Since modeless menus don't capture the mouse, then we need to 03962 * keep checking on the mouse button when the mouse is off the 03963 * menu. 03964 * Note that we do not set fMouseOffMenu if fInDoDragDrop is set 03965 */ 03966 if (pMenuState->fMouseOffMenu && pMenuState->fButtonDown) { 03967 UserAssert(!pMenuState->fInDoDragDrop && pMenuState->fModelessMenu); 03968 MNCheckButtonDownState(pMenuState); 03969 } 03970 03971 /* 03972 * Setup the msg structure 03973 */ 03974 msg.hwnd = HW(pwnd); 03975 msg.message = message; 03976 msg.wParam = wParam; 03977 03978 /* 03979 * xxxHandleMenuMessages expects screen coordinates 03980 */ 03981 if ((message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST)) { 03982 msg.lParam = MAKELONG(GET_X_LPARAM(lParam) + pwnd->rcClient.left, 03983 GET_Y_LPARAM(lParam) + pwnd->rcClient.top); 03984 } else { 03985 msg.lParam = lParam; 03986 } 03987 03988 /* 03989 * Not used by xxxHandleMenuMessages 03990 */ 03991 msg.time = 0; 03992 msg.pt.x = msg.pt.x = 0; 03993 03994 03995 UserAssert(pMenuState->pGlobalPopupMenu != NULL); 03996 03997 pMenuState->fInCallHandleMenuMessages = TRUE; 03998 fHandled = xxxHandleMenuMessages(&msg, pMenuState, pMenuState->pGlobalPopupMenu); 03999 pMenuState->fInCallHandleMenuMessages = FALSE; 04000 04001 /* 04002 * If the message was handled and this is a modeless menu, 04003 * check to see if it's time to go. 04004 */ 04005 if (fHandled 04006 && pMenuState->fModelessMenu 04007 && ExitMenuLoop (pMenuState, pMenuState->pGlobalPopupMenu)) { 04008 04009 xxxEndMenuLoop (pMenuState, pMenuState->pGlobalPopupMenu); 04010 xxxMNEndMenuState(TRUE); 04011 } 04012 04013 return fHandled; 04014 }

void xxxCleanupDesktopMenu PWND  pwndDeskMenu,
PDESKTOP  pdesk
 

Definition at line 1908 of file ntuser/kernel/menu.c.

References _GetDesktopWindow, CheckLock, tagWND::head, tagDESKTOP::pDeskInfo, tagDESKTOPINFO::spwnd, tagDESKTOP::spwndMessage, tagWND::spwndOwner, tagWND::spwndParent, ThreadLockAlways, ThreadUnlock, Unlock, and xxxSetParent().

Referenced by xxxMNCloseHierarchy(), and xxxMNOpenHierarchy().

01909 { 01910 TL tlpwnd; 01911 CheckLock(pwndDeskMenu); 01912 /* 01913 * Put it on the message window tree so it is out of the way. 01914 */ 01915 UserAssert(pwndDeskMenu->spwndParent == _GetDesktopWindow()); 01916 ThreadLockAlways(pdesk->spwndMessage, &tlpwnd); 01917 xxxSetParent(pwndDeskMenu, pdesk->spwndMessage); 01918 ThreadUnlock(&tlpwnd); 01919 01920 /* 01921 * Give ownershipe back to the desktop thread 01922 */ 01923 pwndDeskMenu->head.pti = pdesk->pDeskInfo->spwnd->head.pti; 01924 Unlock(&pwndDeskMenu->spwndOwner); 01925 }

LRESULT xxxMenuWindowProc PWND  pwnd,
UINT  message,
WPARAM  wParam,
LPARAM  lParam
 

Definition at line 4022 of file ntuser/kernel/menu.c.

References _GetDCEx(), _KillTimer(), _MonitorFromWindow(), _PostMessage(), _ReleaseDC(), _SetTimer(), ATW_SETFOCUS, AW_SKIP2, BOOL, CheckLock, tagMENU::cItems, ClearMF, CMS_MENUFADE, CreateFade(), tagMENUSTATE::cxAni, tagMENU::cxMenu, cy, tagMENUSTATE::cyAni, tagMENUSTATE::dwAniStartTime, tagMENU::dwArrowsOn, dwFlags, DWORD, tagMENUSTATE::fAboutToAutoDismiss, tagMENUSTATE::fActiveNoForeground, FADE_MENU, FADE_SHOW, FALSE, FBadWindow(), tagMENUSTATE::fButtonDown, tagMENUSTATE::fDragAndDrop, tagMENUSTATE::fDragging, tagMENUSTATE::fIgnoreButtonUp, tagMENUSTATE::fInCallHandleMenuMessages, tagPOPUPMENU::fInCancel, FindBestPos(), tagMENUSTATE::fInDoDragDrop, tagMENUSTATE::fModelessMenu, tagMENUSTATE::fMouseOffMenu, FNID_MENU, tagITEM::fState, tagPOPUPMENU::fToggle, tagPOPUPMENU::fTrackMouseEvent, gcyMenuScrollArrow, GET_X_LPARAM, GET_Y_LPARAM, GetAppCompatFlags2(), GETFNID, GetpMenuState(), GETPTI, gpqForeground, gpqForegroundPrev, tagMENU::hbrBack, tagMENUSTATE::hdcWndAni, tagWND::head, HRGN_FULL, HW, tagMENUSTATE::iAniDropDir, tagPOPUPMENU::iDropDir, IDSYS_MNANIMATE, IDSYS_MNAUTODISMISS, IDSYS_MNDOWN, IDSYS_MNHIDE, IDSYS_MNSHOW, IDSYS_MNUP, InflateRect(), Is500Compat, ISAMENU, IsMFMWFPWindow(), IsRecursedMenuState(), tagMENUSTATE::ixAni, tagMENUSTATE::iyAni, L, Lock, LockMenuState(), LockPopupMenu(), MFMWFP_MINVALID, MFMWFP_NOITEM, MFWINDOWDC, MNAllocPopup(), MNAnimate(), MNCheckButtonDownState(), MNCheckScroll(), MNCreateAnimationBitmap(), MNDrawFullNC(), MNEraseBackground(), MNFindNextValidItem(), MNGetpItem(), MNSetTimerToAutoDismiss(), MNSetTimerToOpenHierarchy(), MNSW_DRAWFRAME, MNSW_RETURNSIZE, MNXBORDER, MNYBORDER, MSA_OFF, NCA_ACTIVE, NCA_FORCEFRAMEOFF, NextTopWindow(), NtGetTickCount(), NULL, PAS_HORZ, PAS_OUT, PAS_VERT, tagMENUSTATE::pGlobalPopupMenu, PlayEventSound(), pmenuNext, tagMENUSTATE::pmnsPrev, tagPOPUPMENU::posDropped, tagPOPUPMENU::posSelectedItem, tagPOPUPMENU::ppopupmenuRoot, tagTHREADINFO::pq, PtiCurrent, PtInRect(), PtoH, PUINT, PWND_TOP, QF_CAPTURELOCKED, tagWND::rcClient, tagWND::rcWindow, RevalidateHwnd, SetMF, ShowFade(), tagPOPUPMENU::spmenu, tagITEM::spSubMenu, tagPOPUPMENU::spwndActivePopup, tagQ::spwndActivePrev, tagWND::spwndLastActive, tagPOPUPMENU::spwndNextPopup, tagPOPUPMENU::spwndNotify, tagMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, StartFade(), SYSMET, TestALPHA, TestEffectUP, TestFadeFlags(), TestWF, ThreadLock, ThreadLockAlways, ThreadLockAlwaysWithPti, ThreadUnlock, TRUE, tagMENUSTATE::uButtonDownHitArea, tagMENUSTATE::uButtonDownIndex, UINT, USER_SOUND_MENUPOPUP, VALIDATECLASSANDSIZE, ValidateHmenu(), Validateppopupmenu, VER40, WFVISIBLE, xxxActivateThisWindow(), xxxActivateWindow(), xxxBeginPaint(), xxxCallHandleMenuMessages(), xxxClientRevokeDragDrop(), xxxDefWindowProc(), xxxDWP_DoNCActivate(), xxxEndMenuLoop(), xxxEndPaint(), xxxMenuDraw(), xxxMNButtonDown(), xxxMNButtonUp(), xxxMNCancel(), xxxMNChar(), xxxMNCloseHierarchy(), xxxMNCompute(), xxxMNDestroyHandler(), xxxMNDoScroll(), xxxMNDoubleClick(), xxxMNEndMenuState(), xxxMNFindWindowFromPoint(), xxxMNKeyDown(), xxxMNMouseMove(), xxxMNOpenHierarchy(), xxxMNPositionHierarchy(), xxxMNSelectItem(), xxxMNSetCapture(), xxxSendMessage(), xxxSetForegroundWindow(), xxxSetWindowPos(), xxxShowWindow(), xxxUnlockMenuState(), and xxxValidateRect().

Referenced by InitFunctionTables(), InitializeClientPfnArrays(), and LW_RegisterWindows().

04027 { 04028 BOOL fIsRecursedMenu; 04029 LRESULT lRet; 04030 PAINTSTRUCT ps; 04031 PPOPUPMENU ppopupmenu; 04032 PMENUSTATE pMenuState; 04033 PMENU pmenu; 04034 PITEM pItem; 04035 TL tlpmenu; 04036 TL tlpwndNotify; 04037 PDESKTOP pdesk = pwnd->head.rpdesk; 04038 POINT ptOrg; 04039 HDC hdcAni; 04040 04041 CheckLock(pwnd); 04042 04043 VALIDATECLASSANDSIZE(pwnd, message, wParam, lParam, FNID_MENU, WM_NCCREATE); 04044 04045 /* 04046 * If we're not in menu mode or this window is just being created, 04047 * there are only few messages we care about. 04048 */ 04049 pMenuState = GetpMenuState(pwnd); 04050 ppopupmenu = ((PMENUWND)pwnd)->ppopupmenu; 04051 pmenu = (ppopupmenu != NULL ? ppopupmenu->spmenu : NULL); 04052 if ((pMenuState == NULL) || (pmenu == NULL)) { 04053 switch (message) { 04054 case WM_NCCREATE: 04055 case WM_FINALDESTROY: 04056 break; 04057 04058 case MN_SETHMENU: 04059 if (ppopupmenu != NULL) { 04060 break; 04061 } else { 04062 return 0; 04063 } 04064 04065 default: 04066 goto CallDWP; 04067 } 04068 } else { 04069 /* 04070 * TPM_RECURSE support: make sure we grab the proper pMenuState. 04071 */ 04072 fIsRecursedMenu = ((ppopupmenu->ppopupmenuRoot != NULL) 04073 && IsRecursedMenuState(pMenuState, ppopupmenu)); 04074 if (fIsRecursedMenu) { 04075 while (IsRecursedMenuState(pMenuState, ppopupmenu) 04076 && (pMenuState->pmnsPrev != NULL)) { 04077 pMenuState = pMenuState->pmnsPrev; 04078 } 04079 UserAssert(pMenuState->pGlobalPopupMenu == ppopupmenu->ppopupmenuRoot); 04080 } 04081 04082 Validateppopupmenu(ppopupmenu); 04083 04084 /* 04085 * If this is a modeless menu, give xxxHandleMenuMessages the first 04086 * shot at the message 04087 */ 04088 if (pMenuState->fModelessMenu && !pMenuState->fInCallHandleMenuMessages) { 04089 /* 04090 * If this is a recursed menu, we don't want to process any 04091 * input for it until the current menu goes away. 04092 */ 04093 if (fIsRecursedMenu) { 04094 if (((message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST)) 04095 || ((message >= WM_KEYFIRST) && (message <= WM_KEYLAST)) 04096 || ((message >= WM_NCMOUSEFIRST) && (message <= WM_NCMOUSELAST))) { 04097 04098 goto CallDWP; 04099 } 04100 } else { 04101 if (xxxCallHandleMenuMessages(pMenuState, pwnd, message, wParam, lParam)) { 04102 return 0; 04103 } 04104 } 04105 } 04106 } /* else of if ((pMenuState == NULL) || (ppopupmenu == NULL)) */ 04107 04108 switch (message) { 04109 case WM_NCCREATE: 04110 /* 04111 * Ignore evil messages to prevent leaks. 04112 * Use RIP_ERROR for a while to make sure to see if we're getting here 04113 */ 04114 if (((PMENUWND)pwnd)->ppopupmenu != NULL) { 04115 RIPMSG1(RIP_ERROR, "xxxMenuWindowProc: evil WM_NCCREATE. already initialized. pwnd:%p", pwnd); 04116 return FALSE; 04117 } 04118 ppopupmenu = MNAllocPopup(TRUE); 04119 if (ppopupmenu == NULL) { 04120 return FALSE; 04121 } 04122 04123 ((PMENUWND)pwnd)->ppopupmenu = ppopupmenu; 04124 ppopupmenu->posSelectedItem = MFMWFP_NOITEM; 04125 Lock(&(ppopupmenu->spwndPopupMenu), pwnd); 04126 return TRUE; 04127 04128 case WM_NCCALCSIZE: 04129 xxxDefWindowProc(pwnd, message, wParam, lParam); 04130 if (pmenu->dwArrowsOn != MSA_OFF) { 04131 InflateRect((PRECT)lParam, 0, -gcyMenuScrollArrow); 04132 } 04133 break; 04134 04135 case WM_ERASEBKGND: 04136 if (pmenu->hbrBack != NULL) { 04137 MNEraseBackground ((HDC) wParam, pmenu, 04138 0, 0, 04139 pwnd->rcClient.right - pwnd->rcClient.left, 04140 pwnd->rcClient.bottom - pwnd->rcClient.top); 04141 return TRUE; 04142 } else { 04143 goto CallDWP; 04144 } 04145 break; 04146 04147 case WM_PRINT: 04148 /* 04149 * default processing of WM_PRINT does not handle custom non- 04150 * client painting -- which scrollable menus have -- so take 04151 * care of drawing nonclient area and then let DefWindowProc 04152 * handle the rest 04153 */ 04154 if ((lParam & PRF_NONCLIENT) && (pmenu->dwArrowsOn != MSA_OFF)) { 04155 04156 MNDrawFullNC(pwnd, (HDC)wParam, ppopupmenu); 04157 GreGetWindowOrg((HDC)wParam, &ptOrg); 04158 GreSetWindowOrg((HDC)wParam, 04159 ptOrg.x - MNXBORDER, 04160 ptOrg.y - MNYBORDER - gcyMenuScrollArrow, 04161 NULL); 04162 xxxDefWindowProc(pwnd, message, wParam, lParam & ~PRF_NONCLIENT); 04163 GreSetWindowOrg((HDC)wParam, ptOrg.x, ptOrg.y, NULL); 04164 04165 } else { 04166 goto CallDWP; 04167 } 04168 break; 04169 04170 case WM_WINDOWPOSCHANGING: 04171 if (!(((LPWINDOWPOS)lParam)->flags & SWP_SHOWWINDOW)) 04172 goto CallDWP; 04173 04174 if (!TestEffectUP(MENUANIMATION) || !(ppopupmenu->iDropDir & PAS_OUT) 04175 || (GetAppCompatFlags2(VER40) & GACF2_ANIMATIONOFF)) { 04176 NoAnimation: 04177 ppopupmenu->iDropDir &= ~PAS_OUT; 04178 goto CallDWP; 04179 } 04180 04181 /* 04182 * Create the animation bitmap. 04183 */ 04184 pMenuState->cxAni = pwnd->rcWindow.right - pwnd->rcWindow.left; 04185 pMenuState->cyAni = pwnd->rcWindow.bottom - pwnd->rcWindow.top; 04186 04187 if (TestALPHA(MENUFADE)) { 04188 if ((hdcAni = CreateFade(pwnd, NULL, CMS_MENUFADE, 04189 FADE_SHOW | FADE_MENU)) == NULL) { 04190 goto NoAnimation; 04191 } 04192 } else { 04193 04194 if (!MNCreateAnimationBitmap(pMenuState, pMenuState->cxAni, 04195 pMenuState->cyAni)) { 04196 goto NoAnimation; 04197 } 04198 04199 /* 04200 * We shouldn't be animating at this time. 04201 */ 04202 UserAssert(pMenuState->hdcWndAni == NULL); 04203 04204 /* 04205 * This window must be the active popup 04206 */ 04207 UserAssert(pMenuState->pGlobalPopupMenu->spwndActivePopup == pwnd); 04208 04209 /* 04210 * Initialize animation info 04211 */ 04212 pMenuState->hdcWndAni = _GetDCEx(pwnd, HRGN_FULL, DCX_WINDOW | DCX_USESTYLE | DCX_INTERSECTRGN); 04213 pMenuState->iAniDropDir = ppopupmenu->iDropDir; 04214 pMenuState->ixAni = (pMenuState->iAniDropDir & PAS_HORZ) ? 0 : pMenuState->cxAni; 04215 pMenuState->iyAni = (pMenuState->iAniDropDir & PAS_VERT) ? 0 : pMenuState->cyAni; 04216 hdcAni = pMenuState->hdcAni; 04217 } 04218 04219 /* 04220 * MFWINDOWDC is used by MNEraseBackground to determine where the 04221 * brush org should be set. 04222 */ 04223 SetMF(pmenu, MFWINDOWDC); 04224 04225 xxxSendMessage(pwnd, WM_PRINT, (WPARAM)hdcAni, PRF_CLIENT | PRF_NONCLIENT | PRF_ERASEBKGND); 04226 04227 ClearMF(pmenu, MFWINDOWDC); 04228 04229 /* 04230 *If owner draw, we just passed hdcAni to the client side. 04231 * The app might have deleted it (??); no blue screen seems to 04232 * happen but only painting on that DC will fail from 04233 * now on. I won't waste time handling this unless it turns 04234 * out to be a problem (it's unlikely an app would do so). 04235 */ 04236 UserAssert(GreValidateServerHandle(hdcAni, DC_TYPE)); 04237 04238 /* 04239 * While the window is still hidden, load the first fade animation 04240 * frame to avoid flicker when the window is actually shown. 04241 * 04242 * There would still be flicker with slide animations, though. It 04243 * could be fixed by using the window region, similar to 04244 * AnimateWindow. For now, too many functions would become xxx, so 04245 * let's not do it, unless it becomes a big issue. 04246 */ 04247 if (TestFadeFlags(FADE_MENU)) { 04248 ShowFade(); 04249 } 04250 goto CallDWP; 04251 04252 case WM_WINDOWPOSCHANGED: 04253 if (!(((LPWINDOWPOS)lParam)->flags & SWP_SHOWWINDOW)) 04254 goto CallDWP; 04255 04256 /* 04257 * If not animating, nothing else to do here. 04258 */ 04259 if (!(ppopupmenu->iDropDir & PAS_OUT)) 04260 goto CallDWP; 04261 04262 /* 04263 * Start the animation cycle now. 04264 */ 04265 if (TestFadeFlags(FADE_MENU)) { 04266 StartFade(); 04267 } else { 04268 pMenuState->dwAniStartTime = NtGetTickCount(); 04269 _SetTimer(pwnd, IDSYS_MNANIMATE, 1, NULL); 04270 } 04271 ppopupmenu->iDropDir &= ~PAS_OUT; 04272 goto CallDWP; 04273 04274 case WM_NCPAINT: 04275 04276 if (ppopupmenu->iDropDir & PAS_OUT) { 04277 04278 /* 04279 * When animating, validate itself to ensure no further drawing 04280 * that is not related to the animation. 04281 */ 04282 xxxValidateRect(pwnd, NULL); 04283 } else { 04284 04285 /* 04286 * If we have scroll bars, draw them 04287 */ 04288 if (pmenu->dwArrowsOn != MSA_OFF) { 04289 04290 HDC hdc = _GetDCEx(pwnd, (HRGN)wParam, 04291 DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN | DCX_NODELETERGN | DCX_LOCKWINDOWUPDATE); 04292 MNDrawFullNC(pwnd, hdc, ppopupmenu); 04293 _ReleaseDC(hdc); 04294 } else { 04295 goto CallDWP; 04296 } 04297 } 04298 break; 04299 04300 case WM_PRINTCLIENT: 04301 ThreadLock(pmenu, &tlpmenu); 04302 xxxMenuDraw((HDC)wParam, pmenu); 04303 ThreadUnlock(&tlpmenu); 04304 break; 04305 04306 case WM_FINALDESTROY: 04307 /* 04308 * If we're animating, we must haved been killed in a rude way.... 04309 */ 04310 UserAssert((pMenuState == NULL) || (pMenuState->hdcWndAni == NULL)); 04311 04312 /* 04313 * If this is a drag and drop menu, then call RevokeDragDrop. 04314 */ 04315 if ((pMenuState != NULL) && pMenuState->fDragAndDrop) { 04316 if (!SUCCEEDED(xxxClientRevokeDragDrop(HW(pwnd)))) { 04317 RIPMSG1(RIP_ERROR, "xxxMenuWindowProc: xxxClientRevokeRegisterDragDrop failed:%#p", pwnd); 04318 } 04319 } 04320 04321 xxxMNDestroyHandler(ppopupmenu); 04322 return 0; 04323 04324 04325 case WM_PAINT: 04326 ThreadLock(pmenu, &tlpmenu); 04327 xxxBeginPaint(pwnd, &ps); 04328 xxxMenuDraw(ps.hdc, pmenu); 04329 xxxEndPaint(pwnd, &ps); 04330 ThreadUnlock(&tlpmenu); 04331 break; 04332 04333 case WM_CHAR: 04334 case WM_SYSCHAR: 04335 xxxMNChar(ppopupmenu, pMenuState, (UINT)wParam); 04336 break; 04337 04338 case WM_KEYDOWN: 04339 case WM_SYSKEYDOWN: 04340 xxxMNKeyDown(ppopupmenu, pMenuState, (UINT)wParam); 04341 break; 04342 04343 case WM_TIMER: 04344 switch (wParam) { 04345 case IDSYS_MNSHOW: 04346 /* 04347 * Open the window and kill the show timer. 04348 * 04349 * Cancel any toggle state we might have. We don't 04350 * want to dismiss this on button up if shown from 04351 * button down. 04352 */ 04353 ppopupmenu->fToggle = FALSE; 04354 xxxMNOpenHierarchy(ppopupmenu, pMenuState); 04355 break; 04356 04357 case IDSYS_MNHIDE: 04358 ppopupmenu->fToggle = FALSE; 04359 xxxMNCloseHierarchy(ppopupmenu,pMenuState); 04360 break; 04361 04362 case IDSYS_MNUP: 04363 case IDSYS_MNDOWN: 04364 if (pMenuState->fButtonDown) { 04365 xxxMNDoScroll(ppopupmenu, (UINT)wParam, FALSE); 04366 } else { 04367 _KillTimer(pwnd, (UINT)wParam); 04368 } 04369 break; 04370 04371 case IDSYS_MNANIMATE: 04372 if (pMenuState->hdcWndAni != NULL) { 04373 MNAnimate(pMenuState, TRUE); 04374 } else { 04375 /* 04376 * This timer shouldn't be set. Left over in msg queue? 04377 */ 04378 UserAssert(pMenuState->hdcWndAni != NULL); 04379 } 04380 break; 04381 04382 case IDSYS_MNAUTODISMISS: 04383 /* 04384 * This is a one shot timer, so kill it. 04385 * Dismiss the popup if the flag hasn't been reset. 04386 */ 04387 _KillTimer(pwnd, IDSYS_MNAUTODISMISS); 04388 if (pMenuState->fAboutToAutoDismiss) { 04389 goto EndMenu; 04390 } 04391 } 04392 break; 04393 04394 /* 04395 * Menu messages. 04396 */ 04397 case MN_SETHMENU: 04398 04399 /* 04400 * wParam - new hmenu to associate with this menu window 04401 * Don't let them set the spmenu to NULL of we have to deal with 04402 * that all over. Use RIP_ERROR for a while to make sure this is OK 04403 */ 04404 if (wParam != 0) { 04405 if ((wParam = (WPARAM)ValidateHmenu((HMENU)wParam)) == 0) { 04406 break; 04407 } 04408 LockPopupMenu(ppopupmenu, &(ppopupmenu->spmenu), (PMENU)wParam); 04409 } else { 04410 RIPMSG1(RIP_ERROR, "xxxMenuWindowProc: MN_SETHMENU ignoring NULL wParam. pwnd:%p", pwnd); 04411 } 04412 break; 04413 04414 case MN_GETHMENU: 04415 04416 /* 04417 * returns the hmenu associated with this menu window 04418 */ 04419 return (LRESULT)PtoH(pmenu); 04420 04421 case MN_SIZEWINDOW: 04422 { 04423 04424 /* 04425 * Computes the size of the menu associated with this window and resizes 04426 * it if needed. Size is returned x in loword, y in highword. wParam 04427 * is 0 to just return new size. wParam is non zero if we should also resize 04428 * window. 04429 * When called by xxxMNUpdateShownMenu, we might need to redraw the 04430 * frame (i.e, the scrollbars). So we check for MNSW_DRAWFRAME in wParam. 04431 * If some app is sending this message and that bit is set, then we'll 04432 * do some extra work, but I think everything should be cool. 04433 */ 04434 int cx, cy; 04435 PMONITOR pMonitor; 04436 04437 /* 04438 * Call menucomputeHelper directly since this is the entry point for 04439 * non toplevel menu bars. 04440 */ 04441 if (pmenu == NULL) 04442 break; 04443 04444 ThreadLockAlways(pmenu, &tlpmenu); 04445 ThreadLock(ppopupmenu->spwndNotify, &tlpwndNotify); 04446 UserAssert(pmenu->spwndNotify == ppopupmenu->spwndNotify); 04447 xxxMNCompute(pmenu, ppopupmenu->spwndNotify, 0, 0, 0, 0); 04448 ThreadUnlock(&tlpwndNotify); 04449 ThreadUnlock(&tlpmenu); 04450 04451 pMonitor = _MonitorFromWindow(pwnd, MONITOR_DEFAULTTOPRIMARY); 04452 cx = pmenu->cxMenu; 04453 cy = MNCheckScroll(pmenu, pMonitor); 04454 04455 /* 04456 * Size the window? 04457 */ 04458 if (wParam != 0) { 04459 LONG lPos; 04460 int x, y; 04461 DWORD dwFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER; 04462 04463 /* 04464 * Need to redraw the frame? 04465 */ 04466 if (wParam & MNSW_DRAWFRAME) { 04467 dwFlags |= SWP_DRAWFRAME; 04468 } 04469 04470 /* 04471 * If the window is visible, it's being resized while 04472 * shown. So make sure that it still fits on the screen 04473 * (i.e, move it to the best pos). 04474 */ 04475 if (TestWF(pwnd, WFVISIBLE)) { 04476 lPos = FindBestPos( 04477 pwnd->rcWindow.left, 04478 pwnd->rcWindow.top, 04479 cx, 04480 cy, 04481 NULL, 04482 0, 04483 ppopupmenu, 04484 pMonitor); 04485 04486 x = GET_X_LPARAM(lPos); 04487 y = GET_Y_LPARAM(lPos); 04488 } else { 04489 dwFlags |= SWP_NOMOVE; 04490 } 04491 04492 xxxSetWindowPos( 04493 pwnd, 04494 PWND_TOP, 04495 x, 04496 y, 04497 cx + 2*SYSMET(CXFIXEDFRAME), /* For shadow */ 04498 cy + 2*SYSMET(CYFIXEDFRAME), /* For shadow */ 04499 dwFlags); 04500 04501 } 04502 04503 return MAKELONG(cx, cy); 04504 } 04505 04506 case MN_OPENHIERARCHY: 04507 { 04508 PWND pwndT; 04509 /* 04510 * Opens one level of the hierarchy at the selected item, if 04511 * present. Return 0 if error, else hwnd of opened hierarchy. 04512 */ 04513 pwndT = xxxMNOpenHierarchy(ppopupmenu, pMenuState); 04514 return (LRESULT)HW(pwndT); 04515 } 04516 04517 case MN_CLOSEHIERARCHY: 04518 xxxMNCloseHierarchy(ppopupmenu, pMenuState); 04519 break; 04520 04521 case MN_SELECTITEM: 04522 /* 04523 * wParam - the item to select. Must be a valid 04524 * Returns the item flags of the wParam (0 if failure) 04525 */ 04526 if ((wParam >= pmenu->cItems) && (wParam < MFMWFP_MINVALID)) { 04527 UserAssertMsg1(FALSE, "Bad wParam %x for MN_SELECTITEM", wParam); 04528 break; 04529 } 04530 04531 pItem = xxxMNSelectItem(ppopupmenu, pMenuState, (UINT)wParam); 04532 if (pItem != NULL) { 04533 return((LONG)(DWORD)(WORD)(pItem->fState | 04534 ((pItem->spSubMenu != NULL) ? MF_POPUP : 0))); 04535 } 04536 04537 break; 04538 04539 case MN_SELECTFIRSTVALIDITEM: { 04540 UINT item; 04541 04542 item = MNFindNextValidItem(pmenu, -1, 1, TRUE); 04543 xxxSendMessage(pwnd, MN_SELECTITEM, item, 0L); 04544 return (LONG)item; 04545 } 04546 04547 case MN_CANCELMENUS: 04548 04549 /* 04550 * Cancels all menus, unselects everything, destroys windows, and cleans 04551 * everything up for this hierarchy. wParam is the command to send and 04552 * lParam says if it is valid or not. 04553 */ 04554 xxxMNCancel(pMenuState, (UINT)wParam, (BOOL)LOWORD(lParam), 0); 04555 break; 04556 04557 case MN_FINDMENUWINDOWFROMPOINT: 04558 /* 04559 * lParam is point to search for from this hierarchy down. 04560 * returns MFMWFP_* value or a pwnd. 04561 */ 04562 lRet = xxxMNFindWindowFromPoint(ppopupmenu, (PUINT)wParam, MAKEPOINTS(lParam)); 04563 04564 /* 04565 * Convert return value to a handle. 04566 */ 04567 if (IsMFMWFPWindow(lRet)) { 04568 return (LRESULT)HW((PWND)lRet); 04569 } else { 04570 return lRet; 04571 } 04572 04573 04574 case MN_SHOWPOPUPWINDOW: 04575 /* 04576 * Forces the dropped down popup to be visible and if modeless, also active. 04577 */ 04578 PlayEventSound(USER_SOUND_MENUPOPUP); 04579 xxxShowWindow(pwnd, (pMenuState->fModelessMenu ? SW_SHOW : SW_SHOWNOACTIVATE)); 04580 break; 04581 04582 case MN_ACTIVATEPOPUP: 04583 /* 04584 * Activates a popup. This messages is posted in response to WM_ACTIVATEAPP 04585 * or WM_ACTIVATE 04586 */ 04587 UserAssert(pMenuState->fModelessMenu); 04588 xxxActivateThisWindow(pwnd, 0, 0); 04589 break; 04590 04591 case MN_ENDMENU: 04592 /* 04593 * End the menu. This message is posted to avoid ending the menu 04594 * at randmom moments. By posting the message, the request is 04595 * queued after any pending/current processing. 04596 */ 04597 EndMenu: 04598 xxxEndMenuLoop(pMenuState, pMenuState->pGlobalPopupMenu); 04599 if (pMenuState->fModelessMenu) { 04600 UserAssert(!pMenuState->fInCallHandleMenuMessages); 04601 xxxMNEndMenuState(TRUE); 04602 } 04603 return 0; 04604 04605 case MN_DODRAGDROP: 04606 /* 04607 * Let the app know that the user is dragging. 04608 */ 04609 if (pMenuState->fDragging 04610 && (ppopupmenu->spwndNotify != NULL) 04611 && IsMFMWFPWindow(pMenuState->uButtonDownHitArea)) { 04612 /* 04613 * Get the pmenu that contains the item being dragged 04614 */ 04615 pmenu = (((PMENUWND)pMenuState->uButtonDownHitArea)->ppopupmenu)->spmenu; 04616 /* 04617 * If this is a modal menu, release the capture lock so 04618 * DoDragDrop (if called) can get it. 04619 */ 04620 if (!pMenuState->fModelessMenu) { 04621 UserAssert(PtiCurrent()->pq->QF_flags & QF_CAPTURELOCKED); 04622 PtiCurrent()->pq->QF_flags &= ~QF_CAPTURELOCKED; 04623 } 04624 04625 LockMenuState(pMenuState); 04626 ThreadLockAlways(ppopupmenu->spwndNotify, &tlpwndNotify); 04627 04628 /* 04629 * Give them a chance to call DoDragDrop 04630 */ 04631 pMenuState->fInDoDragDrop = TRUE; 04632 lRet = xxxSendMessage(ppopupmenu->spwndNotify, WM_MENUDRAG, 04633 pMenuState->uButtonDownIndex, (LPARAM)PtoH(pmenu)); 04634 pMenuState->fInDoDragDrop = FALSE; 04635 04636 if (lRet == MND_ENDMENU) { 04637 /* 04638 * Go away. 04639 */ 04640 ThreadUnlock(&tlpwndNotify); 04641 if (!xxxUnlockMenuState(pMenuState)) { 04642 goto EndMenu; 04643 } else { 04644 return 0; 04645 } 04646 break; 04647 } else { 04648 /* 04649 * If the user starts dragging, we always 04650 * ignore the following button up 04651 */ 04652 pMenuState->fIgnoreButtonUp = TRUE; 04653 } 04654 04655 /* 04656 * Check the button state since we might have not seen the button up 04657 * If so, this will cancel the dragging state 04658 */ 04659 MNCheckButtonDownState(pMenuState); 04660 04661 /* 04662 * If this is a modal menu, make sure we recover capture 04663 */ 04664 if (!pMenuState->fModelessMenu) { 04665 xxxMNSetCapture(ppopupmenu); 04666 } 04667 04668 ThreadUnlock(&tlpwndNotify); 04669 xxxUnlockMenuState(pMenuState); 04670 } 04671 return 0; 04672 04673 case MN_BUTTONDOWN: 04674 04675 /* 04676 * wParam is position (index) of item the button was clicked on. 04677 * Must be a valid 04678 */ 04679 if ((wParam >= pmenu->cItems) && (wParam < MFMWFP_MINVALID)) { 04680 UserAssertMsg1(FALSE, "Bad wParam %x for MN_BUTTONDOWN", wParam); 04681 break; 04682 } 04683 xxxMNButtonDown(ppopupmenu, pMenuState, (UINT)wParam, TRUE); 04684 break; 04685 04686 case MN_MOUSEMOVE: 04687 04688 /* 04689 * lParam is mouse move coordinate wrt screen. 04690 */ 04691 xxxMNMouseMove(ppopupmenu, pMenuState, MAKEPOINTS(lParam)); 04692 break; 04693 04694 case MN_BUTTONUP: 04695 04696 /* 04697 * wParam is position (index) of item the button was up clicked on. 04698 */ 04699 if ((wParam >= pmenu->cItems) && (wParam < MFMWFP_MINVALID)) { 04700 UserAssertMsg1(FALSE, "Bad wParam %x for MN_BUTTONUP", wParam); 04701 break; 04702 } 04703 xxxMNButtonUp(ppopupmenu, pMenuState, (UINT)wParam, lParam); 04704 break; 04705 04706 case MN_SETTIMERTOOPENHIERARCHY: 04707 04708 /* 04709 * Given the current selection, set a timer to show this hierarchy if 04710 * valid else return 0. 04711 */ 04712 return (LONG)(WORD)MNSetTimerToOpenHierarchy(ppopupmenu); 04713 04714 case MN_DBLCLK: 04715 // 04716 // User double-clicked on item. wParamLo is the item. 04717 // 04718 xxxMNDoubleClick(pMenuState, ppopupmenu, (int)wParam); 04719 break; 04720 04721 case WM_MOUSELEAVE: 04722 UserAssert(pMenuState->fModelessMenu); 04723 /* 04724 * If we're in DoDragDrop loop, we don't track the mouse 04725 * when it goes off the menu window 04726 */ 04727 pMenuState->fMouseOffMenu = !pMenuState->fInDoDragDrop; 04728 ppopupmenu->fTrackMouseEvent = FALSE; 04729 /* 04730 * See if we need to set the timer to autodismiss 04731 */ 04732 MNSetTimerToAutoDismiss(pMenuState, pwnd); 04733 /* 04734 * If we left the active popup, remove the selection 04735 */ 04736 if (ppopupmenu->spwndPopupMenu == pMenuState->pGlobalPopupMenu->spwndActivePopup) { 04737 xxxMNSelectItem(ppopupmenu, pMenuState, MFMWFP_NOITEM); 04738 } 04739 break; 04740 04741 case WM_ACTIVATEAPP: 04742 if (pMenuState->fModelessMenu 04743 && (pwnd == pMenuState->pGlobalPopupMenu->spwndActivePopup)) { 04744 /* 04745 * If the application is getting activated, we post a message 04746 * to let the dust settle and then re-activate spwndPopupActive 04747 */ 04748 if (wParam) { 04749 _PostMessage(pwnd, MN_ACTIVATEPOPUP, 0, 0); 04750 /* 04751 * If we're not in the foregruond queue, we want to keep 04752 * the frame off. 04753 * This flag will also tell us that if we lose activation 04754 * while coming to the foregrund (later), we don't want 04755 * to dismiss the menu. 04756 */ 04757 pMenuState->fActiveNoForeground = (gpqForeground != PtiCurrent()->pq); 04758 } 04759 04760 /* 04761 * Make the notification window frame show that we're active/inactive. 04762 * If the application is inactive but the user moves the mouse 04763 * over the menu, then we can get this message when the first 04764 * window in the app gets activated (i.e., the move causes a popup to 04765 * be closed/opened). So turn on the frame only if we're in 04766 * the foreground. 04767 */ 04768 if (ppopupmenu->spwndNotify != NULL) { 04769 ThreadLockAlways(ppopupmenu->spwndNotify, &tlpwndNotify); 04770 xxxDWP_DoNCActivate(ppopupmenu->spwndNotify, 04771 ((wParam && !pMenuState->fActiveNoForeground) ? NCA_ACTIVE : NCA_FORCEFRAMEOFF), 04772 HRGN_FULL); 04773 ThreadUnlock(&tlpwndNotify); 04774 } 04775 } 04776 break; 04777 04778 case WM_ACTIVATE: 04779 if (pMenuState->fModelessMenu) { 04780 /* 04781 * If activation is NOT going to a menu window or 04782 * it's going to a recursed menu, bail 04783 */ 04784 if ((LOWORD(wParam) == WA_INACTIVE) 04785 && !pMenuState->fInCallHandleMenuMessages 04786 && !pMenuState->pGlobalPopupMenu->fInCancel) { 04787 04788 lParam = (LPARAM)RevalidateHwnd((HWND)lParam); 04789 if ((lParam != 0) 04790 && ((GETFNID((PWND)lParam) != FNID_MENU) 04791 || IsRecursedMenuState(pMenuState, ((PMENUWND)lParam)->ppopupmenu))) { 04792 /* 04793 * If we're just coming to the foreground, then 04794 * activate the popup later and stay up. 04795 */ 04796 if (pMenuState->fActiveNoForeground 04797 && (gpqForeground == PtiCurrent()->pq)) { 04798 04799 pMenuState->fActiveNoForeground = FALSE; 04800 _PostMessage(pwnd, MN_ACTIVATEPOPUP, 0, 0); 04801 } else { 04802 /* 04803 * Since the menu window is active, ending the menu 04804 * now would set a new active window, messing the 04805 * current activation that sent us this message. 04806 * so end the menu later. 04807 */ 04808 _PostMessage(pwnd, MN_ENDMENU, 0, 0); 04809 break; 04810 } 04811 } 04812 } 04813 goto CallDWP; 04814 } /* if (pMenuState->fModelessMenu) */ 04815 04816 /* 04817 * We must make sure that the menu window does not get activated. 04818 * Powerpoint 2.00e activates it deliberately and this causes problems. 04819 * We try to activate the previously active window in such a case. 04820 * Fix for Bug #13961 --SANKAR-- 09/26/91-- 04821 */ 04822 /* 04823 * In Win32, wParam has other information in the hi 16bits, so to 04824 * prevent infinite recursion, we need to mask off those bits 04825 * Fix for NT bug #13086 -- 23-Jun-1992 JonPa 04826 * 04827 */ 04828 04829 if (LOWORD(wParam)) { 04830 TL tlpwnd; 04831 /* 04832 * This is a super bogus hack. Let's start failing this for 5.0 apps. 04833 */ 04834 if (Is500Compat(PtiCurrent()->dwExpWinVer)) { 04835 RIPMSG1(RIP_ERROR, "xxxMenuWindowProc: Menu window activated:%#p", pwnd); 04836 _PostMessage(pwnd, MN_ENDMENU, 0, 0); 04837 break; 04838 } 04839 04840 #if 0 04841 /* 04842 * Activate the previously active wnd 04843 */ 04844 xxxActivateWindow(pwnd, AW_SKIP2); 04845 #else 04846 /* 04847 * Try the previously active window. 04848 */ 04849 if ((gpqForegroundPrev != NULL) && 04850 !FBadWindow(gpqForegroundPrev->spwndActivePrev) && 04851 !ISAMENU(gpqForegroundPrev->spwndActivePrev)) { 04852 pwnd = gpqForegroundPrev->spwndActivePrev; 04853 } else { 04854 04855 /* 04856 * Find a new active window from the top-level window list. 04857 * Bug 78131: Make sure we don't loop for ever. This is a pretty 04858 * unusual scenario (in addtion, normally we should not hit this code path) 04859 * So let's use a counter to rule out the possibility that another 04860 * weird window configuration is going to make us loop for ever 04861 */ 04862 PWND pwndMenu = pwnd; 04863 UINT uCounter = 0; 04864 do { 04865 pwnd = NextTopWindow(PtiCurrent(), pwnd, NULL, 0); 04866 if (pwnd && !FBadWindow(pwnd->spwndLastActive) && 04867 !ISAMENU(pwnd->spwndLastActive)) { 04868 pwnd = pwnd->spwndLastActive; 04869 uCounter = 0; 04870 break; 04871 } 04872 } while ((pwnd != NULL) && (uCounter++ < 255)); 04873 /* 04874 * If we couldn't find a window, just bail. 04875 */ 04876 if (uCounter != 0) { 04877 RIPMSG0(RIP_ERROR, "xxxMenuWindowProc: couldn't fix active window"); 04878 _PostMessage(pwndMenu, MN_ENDMENU, 0, 0); 04879 break; 04880 } 04881 } 04882 04883 if (pwnd != NULL) { 04884 PTHREADINFO pti = PtiCurrent(); 04885 ThreadLockAlwaysWithPti(pti, pwnd, &tlpwnd); 04886 04887 /* 04888 * If GETPTI(pwnd) isn't pqCurrent this is a AW_SKIP* activation 04889 * we'll want to a do a xxxSetForegroundWindow(). 04890 */ 04891 if (GETPTI(pwnd)->pq != pti->pq) { 04892 04893 /* 04894 * Only allow this if we're on the current foreground queue. 04895 */ 04896 if (gpqForeground == pti->pq) { 04897 xxxSetForegroundWindow(pwnd, FALSE); 04898 } 04899 } else { 04900 xxxActivateThisWindow(pwnd, 0, ATW_SETFOCUS); 04901 } 04902 04903 ThreadUnlock(&tlpwnd); 04904 } 04905 #endif 04906 } 04907 break; 04908 04909 case WM_SIZE: 04910 case WM_MOVE: 04911 /* 04912 * When a popup has been sized/moved, we need to make 04913 * sure any dropped hierarchy is moved accordingly. 04914 */ 04915 if (ppopupmenu->spwndNextPopup != NULL) { 04916 pItem = MNGetpItem(ppopupmenu, ppopupmenu->posDropped); 04917 if (pItem != NULL) { 04918 int x, y; 04919 PMONITOR pMonitorDummy; 04920 04921 /* 04922 * If the dropped hierarchy needs to be recomputed, do it 04923 */ 04924 #define pmenuNext (((PMENUWND)ppopupmenu->spwndNextPopup)->ppopupmenu->spmenu) 04925 if (pmenuNext->cxMenu == 0) { 04926 xxxSendMessage(ppopupmenu->spwndNextPopup, MN_SIZEWINDOW, MNSW_RETURNSIZE, 0L); 04927 } 04928 04929 /* 04930 * Find out the new position 04931 */ 04932 xxxMNPositionHierarchy(ppopupmenu, pItem, 04933 pmenuNext->cxMenu + (2 * SYSMET(CXFIXEDFRAME)), 04934 pmenuNext->cyMenu + (2 * SYSMET(CXFIXEDFRAME)), 04935 &x, &y, &pMonitorDummy); 04936 04937 /* 04938 * Move it 04939 */ 04940 ThreadLockAlways(ppopupmenu->spwndNextPopup, &tlpwndNotify); 04941 xxxSetWindowPos(ppopupmenu->spwndNextPopup, NULL, 04942 x, y, 0, 0, 04943 SWP_NOSIZE | SWP_NOZORDER | SWP_NOSENDCHANGING); 04944 ThreadUnlock(&tlpwndNotify); 04945 #undef pmenuNext 04946 } /* if (pItem != NULL) */ 04947 } /* if (ppopupmenu->spwndNextPopup != NULL) */ 04948 break; 04949 04950 case WM_NCHITTEST: 04951 /* 04952 * Since modeless menus don't capture the mouse, we 04953 * process this message to make sure that we always receive 04954 * a mouse move when the mouse in our window. 04955 * This also causes us to receive the WM_MOUSELEAVE only when 04956 * the mouse leaves the window and not just the client area. 04957 */ 04958 if (pMenuState->fModelessMenu) { 04959 ptOrg.x = GET_X_LPARAM(lParam); 04960 ptOrg.y = GET_Y_LPARAM(lParam); 04961 if (PtInRect(&pwnd->rcWindow, ptOrg)) { 04962 return HTCLIENT; 04963 } else { 04964 return HTNOWHERE; 04965 } 04966 } else { 04967 goto CallDWP; 04968 } 04969 04970 04971 default: 04972 CallDWP: 04973 return xxxDefWindowProc(pwnd, message, wParam, lParam); 04974 } 04975 04976 return 0; 04977 }

void xxxMNButtonDown PPOPUPMENU  ppopupmenu,
PMENUSTATE  pMenuState,
UINT  posItemHit,
BOOL  fClick
 

Definition at line 3533 of file ntuser/kernel/menu.c.

References BOOL, FALSE, tagMENUSTATE::fButtonDown, tagPOPUPMENU::fDropNextPopup, tagPOPUPMENU::fToggle, MNIsPopupItem(), tagPOPUPMENU::posSelectedItem, TRUE, xxxMNDoScroll(), xxxMNHideNextHierarchy(), xxxMNOpenHierarchy(), and xxxMNSelectItem().

Referenced by xxxHandleMenuMessages(), xxxMenuWindowProc(), and xxxMNMouseMove().

03537 { 03538 PITEM pItem; 03539 BOOL fOpenHierarchy; 03540 03541 /* 03542 * A different item was hit than is currently selected, so select it 03543 * and drop its menu if available. Make sure we toggle click state. 03544 */ 03545 if (ppopupmenu->posSelectedItem != posItemHit) { 03546 /* 03547 * We are clicking on a new item, not moving the mouse over to it. 03548 * So reset cancel toggle state. We don't want button up from 03549 * this button down to cancel. 03550 */ 03551 if (fClick) { 03552 fOpenHierarchy = TRUE; 03553 ppopupmenu->fToggle = FALSE; 03554 } 03555 else 03556 { 03557 fOpenHierarchy = (ppopupmenu->fDropNextPopup != 0); 03558 } 03559 03560 03561 /* 03562 * If the item has a popup and isn't disabled, open it. Note that 03563 * selecting this item will cancel any hierarchies associated with 03564 * the previously selected item. 03565 */ 03566 pItem = xxxMNSelectItem(ppopupmenu, pMenuState, posItemHit); 03567 if (MNIsPopupItem(pItem) && fOpenHierarchy) { 03568 /* Punt if menu was destroyed. */ 03569 if (xxxMNOpenHierarchy(ppopupmenu, pMenuState) == (PWND)-1) { 03570 return; 03571 } 03572 } 03573 } else { 03574 /* 03575 * We are moving over to the already-selected item. If we are 03576 * clicking for real, reset cancel toggle state. We want button 03577 * up to cancel if on same item. Otherwise, do nothing if just 03578 * moving... 03579 */ 03580 if (fClick) { 03581 ppopupmenu->fToggle = TRUE; 03582 } 03583 03584 if (!xxxMNHideNextHierarchy(ppopupmenu) && fClick && xxxMNOpenHierarchy(ppopupmenu, pMenuState)) 03585 ppopupmenu->fToggle = FALSE; 03586 } 03587 03588 if (fClick) { 03589 pMenuState->fButtonDown = TRUE; 03590 xxxMNDoScroll(ppopupmenu, posItemHit, TRUE); 03591 } 03592 }

void xxxMNButtonUp PPOPUPMENU  ppopup,
PMENUSTATE  pMenuState,
UINT  posItemHit,
LPARAM  lParam
 

Definition at line 3772 of file ntuser/kernel/menu.c.

References tagMENU::cItems, FALSE, tagMENUSTATE::fButtonAlwaysDown, tagMENUSTATE::fButtonDown, tagPOPUPMENU::fHierarchyDropped, tagPOPUPMENU::fIsMenuBar, tagPOPUPMENU::fShowTimer, tagITEM::fState, tagPOPUPMENU::fToggle, tagITEM::fType, MFMWFP_NOITEM, NULL, tagPOPUPMENU::posSelectedItem, tagMENU::rgItems, tagPOPUPMENU::spmenu, tagITEM::spSubMenu, xxxMNDismiss(), xxxMNDismissWithNotify(), and xxxMNOpenHierarchy().

Referenced by xxxHandleMenuMessages(), and xxxMenuWindowProc().

03777 { 03778 PITEM pItem; 03779 03780 if (!pMenuState->fButtonDown) { 03781 03782 /* 03783 * Ignore if button was never down... Really shouldn't happen... 03784 */ 03785 return; 03786 } 03787 03788 if (posItemHit == MFMWFP_NOITEM) { 03789 RIPMSG0(RIP_WARNING, "button up on no item"); 03790 goto ExitButtonUp; 03791 } 03792 03793 if (ppopup->posSelectedItem != posItemHit) { 03794 goto ExitButtonUp; 03795 } 03796 03797 if (ppopup->fIsMenuBar) { 03798 03799 /* 03800 * Handle button up in menubar specially. 03801 */ 03802 if (ppopup->fHierarchyDropped) { 03803 if (!ppopup->fToggle) { 03804 goto ExitButtonUp; 03805 } else { 03806 /* 03807 * Cancel menu now. 03808 */ 03809 ppopup->fToggle = FALSE; 03810 xxxMNDismiss(pMenuState); 03811 return; 03812 } 03813 } 03814 } else if (ppopup->fShowTimer) { 03815 ppopup->fToggle = FALSE; 03816 03817 /* 03818 * Open hierarchy on popup 03819 */ 03820 xxxMNOpenHierarchy(ppopup, pMenuState); 03821 03822 goto ExitButtonUp; 03823 } 03824 03825 /* 03826 * If nothing is selected, get out. This occurs mainly on unbalanced 03827 * multicolumn menus where one of the columns isn't completely full. 03828 */ 03829 if (ppopup->posSelectedItem == MFMWFP_NOITEM) 03830 goto ExitButtonUp; 03831 03832 if (ppopup->posSelectedItem >= ppopup->spmenu->cItems) 03833 goto ExitButtonUp; 03834 03835 /* 03836 * Get a pointer to the currently selected item in this menu. 03837 */ 03838 pItem = &(ppopup->spmenu->rgItems[ppopup->posSelectedItem]); 03839 03840 /* 03841 * Kick out of menu mode if user clicked on a non-separator, enabled, 03842 * non-hierarchical item. 03843 * 03844 * BOGUS 03845 * Why doesn't MFS_GRAYED check work for separators now? Find out later. 03846 */ 03847 if (!(pItem->fType & MFT_SEPARATOR) 03848 && !(pItem->fState & MFS_GRAYED) 03849 && (pItem->spSubMenu == NULL)) { 03850 03851 xxxMNDismissWithNotify(pMenuState, ppopup->spmenu, pItem, 03852 ppopup->posSelectedItem, lParam); 03853 return; 03854 } 03855 03856 ExitButtonUp: 03857 pMenuState->fButtonDown = 03858 pMenuState->fButtonAlwaysDown = FALSE; 03859 }

void xxxMNCancel PMENUSTATE  pMenuState,
UINT  uMsg,
UINT  cmd,
LPARAM  lParam
 

Definition at line 3395 of file ntuser/kernel/menu.c.

References _PostMessage(), BOOL, tagMENUSTATE::cmdLast, FALSE, tagMENUSTATE::fButtonDown, tagPOPUPMENU::fDestroyed, tagPOPUPMENU::fInCancel, tagMENUSTATE::fInsideMenuLoop, tagPOPUPMENU::fIsMenuBar, tagPOPUPMENU::fIsSysMenu, tagPOPUPMENU::fIsTrackPopup, tagMENUSTATE::fMenuStarted, tagPOPUPMENU::fNoNotify, tagPOPUPMENU::fSynchronous, FWINABLE, tagWND::head, MFMWFP_NOITEM, NULL, tagMENUSTATE::pGlobalPopupMenu, PlayEventSound(), PtiCurrent, tagMENUSTATE::ptiMenuStateOwner, SMS_NOMENU, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, TestWF, ThreadLock, ThreadUnlock, TRUE, USER_SOUND_MENUCOMMAND, Validateppopupmenu, WFWIN31COMPAT, xxxDestroyWindow(), xxxMNCloseHierarchy(), xxxMNReleaseCapture(), xxxMNSelectItem(), xxxSendMenuSelect(), xxxSendMessage(), and xxxWindowEvent().

Referenced by xxxMenuWindowProc(), xxxMNDismiss(), and xxxMNDismissWithNotify().

03400 { 03401 PPOPUPMENU ppopupmenu = pMenuState->pGlobalPopupMenu; 03402 BOOL fSynchronous = ppopupmenu->fSynchronous; 03403 BOOL fTrackFlagsSet = ppopupmenu->fIsTrackPopup; 03404 BOOL fIsSysMenu = ppopupmenu->fIsSysMenu; 03405 BOOL fIsMenuBar = ppopupmenu->fIsMenuBar; 03406 BOOL fNotify = !ppopupmenu->fNoNotify; 03407 PWND pwndT; 03408 TL tlpwndT; 03409 TL tlpwndPopupMenu; 03410 03411 Validateppopupmenu(ppopupmenu); 03412 03413 pMenuState->fInsideMenuLoop = FALSE; 03414 pMenuState->fButtonDown = FALSE; 03415 /* 03416 * Mark the popup as destroyed so people will not use it anymore. 03417 * This means that root popups can be marked as destroyed before 03418 * actually being destroyed (nice and confusing). 03419 */ 03420 ppopupmenu->fDestroyed = TRUE; 03421 03422 /* 03423 * Only the menu loop owner can destroy the menu windows (i.e, xxxMNCloseHierarchy) 03424 */ 03425 if (PtiCurrent() != pMenuState->ptiMenuStateOwner) { 03426 RIPMSG1(RIP_WARNING, "xxxMNCancel: Thread %#p doesn't own the menu loop", PtiCurrent()); 03427 return; 03428 } 03429 03430 /* 03431 * If the menu loop is running on a thread different than the thread 03432 * that owns spwndNotify, we can have two threads trying to cancel 03433 * this popup at the same time. 03434 */ 03435 if (ppopupmenu->fInCancel) { 03436 RIPMSG1(RIP_WARNING, "xxxMNCancel: already in cancel. ppopupmenu:%#p", ppopupmenu); 03437 return; 03438 } 03439 ppopupmenu->fInCancel = TRUE; 03440 03441 ThreadLock(ppopupmenu->spwndPopupMenu, &tlpwndPopupMenu); 03442 03443 /* 03444 * Close all hierarchies from this point down. 03445 */ 03446 xxxMNCloseHierarchy(ppopupmenu, pMenuState); 03447 03448 /* 03449 * Unselect any items on this top level window 03450 */ 03451 xxxMNSelectItem(ppopupmenu, pMenuState, MFMWFP_NOITEM); 03452 03453 pMenuState->fMenuStarted = FALSE; 03454 03455 pwndT = ppopupmenu->spwndNotify; 03456 03457 ThreadLock(pwndT, &tlpwndT); 03458 03459 xxxMNReleaseCapture(); 03460 03461 if (fTrackFlagsSet) { 03462 /* 03463 * Send a POPUPEND so people watching see them paired 03464 */ 03465 if (FWINABLE()) { 03466 xxxWindowEvent(EVENT_SYSTEM_MENUPOPUPEND, 03467 ppopupmenu->spwndPopupMenu, OBJID_CLIENT, 0, 0); 03468 } 03469 03470 UserAssert(ppopupmenu->spwndPopupMenu != ppopupmenu->spwndPopupMenu->head.rpdesk->spwndMenu); 03471 xxxDestroyWindow(ppopupmenu->spwndPopupMenu); 03472 } 03473 03474 if (pwndT == NULL) { 03475 ThreadUnlock(&tlpwndT); 03476 ThreadUnlock(&tlpwndPopupMenu); 03477 return; 03478 } 03479 03480 /* 03481 * SMS_NOMENU hack so we can send MenuSelect messages with 03482 * (loword(lparam) = -1) when 03483 * the menu pops back up for the CBT people. In 3.0, all WM_MENUSELECT 03484 * messages went through the message filter so go through the function 03485 * SendMenuSelect. We need to do this in 3.1 since WordDefect for Windows 03486 * depends on this. 03487 */ 03488 xxxSendMenuSelect(pwndT, NULL, SMS_NOMENU, MFMWFP_NOITEM); 03489 03490 if (FWINABLE()) { 03491 xxxWindowEvent(EVENT_SYSTEM_MENUEND, pwndT, (fIsSysMenu ? 03492 OBJID_SYSMENU : (fIsMenuBar ? OBJID_MENU : OBJID_WINDOW)), 03493 INDEXID_CONTAINER, 0); 03494 } 03495 03496 if (fNotify) { 03497 /* 03498 * Notify app we are exiting the menu loop. Mainly for WinOldApp 386. 03499 * wParam is 1 if a TrackPopupMenu else 0. 03500 */ 03501 xxxSendMessage(pwndT, WM_EXITMENULOOP, 03502 ((fTrackFlagsSet && !fIsSysMenu)? 1 : 0), 0); 03503 } 03504 03505 if (uMsg != 0) { 03506 PlayEventSound(USER_SOUND_MENUCOMMAND); 03507 pMenuState->cmdLast = cmd; 03508 if (!fSynchronous) { 03509 if (!fIsSysMenu && fTrackFlagsSet && !TestWF(pwndT, WFWIN31COMPAT)) { 03510 xxxSendMessage(pwndT, uMsg, cmd, lParam); 03511 } else { 03512 _PostMessage(pwndT, uMsg, cmd, lParam); 03513 } 03514 } 03515 } else 03516 pMenuState->cmdLast = 0; 03517 03518 ThreadUnlock(&tlpwndT); 03519 03520 ThreadUnlock(&tlpwndPopupMenu); 03521 03522 }

void xxxMNChar PPOPUPMENU  ppopupmenu,
PMENUSTATE  pMenuState,
UINT  character
 

Definition at line 1011 of file ntuser/kernel/menu.c.

References BOOL, tagMENU::cItems, FALSE, tagPOPUPMENU::fDestroyed, tagPOPUPMENU::fIsMenuBar, tagPOPUPMENU::fIsSysMenu, tagITEM::fState, INT, MFMWFP_NOITEM, NULL, tagPOPUPMENU::posSelectedItem, PtoH, tagMENU::rgItems, tagPOPUPMENU::spmenu, tagPOPUPMENU::spmenuAlternate, tagPOPUPMENU::spwndNotify, ThreadLock, ThreadUnlock, TRUE, UINT, Validateppopupmenu, xxxMessageBeep(), xxxMNDismiss(), xxxMNFindChar(), xxxMNKeyDown(), xxxMNSelectItem(), xxxMNSwitchToAlternateMenu(), and xxxSendMessage().

Referenced by xxxHandleMenuMessages(), xxxMenuWindowProc(), and xxxMNKeyFilter().

01015 { 01016 PMENU pMenu; 01017 UINT flags; 01018 LRESULT result; 01019 int item; 01020 INT matchType; 01021 BOOL fExecute = FALSE; 01022 TL tlpwndNotify; 01023 01024 pMenu = ppopupmenu->spmenu; 01025 01026 Validateppopupmenu(ppopupmenu); 01027 01028 /* 01029 * If this comes in with a NULL pMenu, then we could have problems. 01030 * This could happen if the xxxMNStartMenuState never gets called 01031 * because the fInsideMenuLoop is set. 01032 * 01033 * This is placed in here temporarily until we can discover why 01034 * this pMenu isn't set. We will prevent the system from crashing 01035 * in the meantime. 01036 * 01037 * HACK: ChrisWil 01038 */ 01039 if (pMenu == NULL) { 01040 UserAssert(pMenu); 01041 xxxMNDismiss(pMenuState); 01042 return; 01043 } 01044 01045 /* 01046 * If we're getting out of menu mode, bail 01047 */ 01048 if (ppopupmenu->fDestroyed) { 01049 return; 01050 } 01051 01052 item = xxxMNFindChar(pMenu, character, 01053 ppopupmenu->posSelectedItem, &matchType); 01054 if (item != MFMWFP_NOITEM) { 01055 int item1; 01056 int firstItem = item; 01057 01058 /* 01059 * Find first ENABLED menu item with the given mnemonic 'character' 01060 * !!! If none found, exit menu loop !!! 01061 */ 01062 while (pMenu->rgItems[item].fState & MFS_GRAYED) { 01063 item = xxxMNFindChar(pMenu, character, item, &matchType); 01064 if (item == firstItem) { 01065 xxxMNDismiss(pMenuState); 01066 return; 01067 } 01068 } 01069 item1 = item; 01070 01071 /* 01072 * Find next ENABLED menu item with the given mnemonic 'character' 01073 * This is to see if we have a DUPLICATE MNEMONIC situation 01074 */ 01075 do { 01076 item = xxxMNFindChar(pMenu, character, item, &matchType); 01077 } while ((pMenu->rgItems[item].fState & MFS_GRAYED) && (item != firstItem)); 01078 01079 if ((firstItem == item) || (item == item1)) 01080 fExecute = TRUE; 01081 01082 item = item1; 01083 } 01084 01085 if ((item == MFMWFP_NOITEM) && ppopupmenu->fIsMenuBar && (character == TEXT(' '))) { 01086 01087 /* 01088 * Handle the case of the user cruising through the top level menu bar 01089 * without any popups dropped. We need to handle switching to and from 01090 * the system menu. 01091 */ 01092 if (ppopupmenu->fIsSysMenu) { 01093 01094 /* 01095 * If we are on the system menu and user hits space, bring 01096 * down thesystem menu. 01097 */ 01098 item = 0; 01099 fExecute = TRUE; 01100 } else if (ppopupmenu->spmenuAlternate != NULL) { 01101 01102 /* 01103 * We are not currently on the system menu but one exists. So 01104 * switch to it and bring it down. 01105 */ 01106 item = 0; 01107 goto SwitchToAlternate; 01108 } 01109 } 01110 01111 if ((item == MFMWFP_NOITEM) && ppopupmenu->fIsMenuBar && ppopupmenu->spmenuAlternate) { 01112 01113 /* 01114 * No matching item found on this top level menu (could be either the 01115 * system menu or the menu bar). We need to check the other menu. 01116 */ 01117 item = xxxMNFindChar(ppopupmenu->spmenuAlternate, 01118 character, 0, &matchType); 01119 01120 if (item != MFMWFP_NOITEM) { 01121 SwitchToAlternate: 01122 if (xxxMNSwitchToAlternateMenu(ppopupmenu)) { 01123 xxxMNChar(ppopupmenu, pMenuState, character); 01124 } 01125 return; 01126 } 01127 } 01128 01129 if (item == MFMWFP_NOITEM) { 01130 flags = (ppopupmenu->fIsSysMenu) ? MF_SYSMENU : 0; 01131 01132 if (!ppopupmenu->fIsMenuBar) { 01133 flags |= MF_POPUP; 01134 } 01135 01136 ThreadLock(ppopupmenu->spwndNotify, &tlpwndNotify); 01137 result = xxxSendMessage(ppopupmenu->spwndNotify, WM_MENUCHAR, 01138 MAKELONG((WORD)character, (WORD)flags), 01139 (LPARAM)PtoH(ppopupmenu->spmenu)); 01140 ThreadUnlock(&tlpwndNotify); 01141 01142 switch (HIWORD(result)) { 01143 case MNC_IGNORE: 01144 xxxMessageBeep(0); 01145 /* 01146 * If we're on the menu bar, cancel menu mode (fall through). 01147 * We do this because you can really freak out an end user 01148 * who accidentally tapped the Alt key (causing us to go 01149 * into "invisible" menu mode) and now can't type anything! 01150 */ 01151 if (flags & MF_POPUP) { 01152 return; 01153 } 01154 /* 01155 * Fall through. 01156 */ 01157 01158 case MNC_CLOSE: 01159 xxxMNDismiss(pMenuState); 01160 return; 01161 01162 case MNC_EXECUTE: 01163 fExecute = TRUE; 01164 /* fall thru */ 01165 01166 case MNC_SELECT: 01167 item = (UINT)(short)LOWORD(result); 01168 if ((WORD) item >= ppopupmenu->spmenu->cItems) 01169 { 01170 RIPMSG1(RIP_WARNING, "Invalid item number returned from WM_MENUCHAR %#lx", result); 01171 return; 01172 } 01173 break; 01174 } 01175 } 01176 01177 if (item != MFMWFP_NOITEM) { 01178 xxxMNSelectItem(ppopupmenu, pMenuState, item); 01179 01180 if (fExecute) 01181 xxxMNKeyDown(ppopupmenu, pMenuState, VK_RETURN); 01182 } 01183 }

void xxxMNCloseHierarchy PPOPUPMENU  ppopupmenu,
PMENUSTATE  pMenuState
 

Definition at line 2517 of file ntuser/kernel/menu.c.

References _KillTimer(), DF_MENUINUSE, tagDESKTOP::dwDTFlags, FALSE, tagPOPUPMENU::fDesktopMenu, tagMENUSTATE::fDragAndDrop, tagPOPUPMENU::fHideTimer, tagPOPUPMENU::fHierarchyDropped, tagMENUSTATE::fInsideMenuLoop, tagPOPUPMENU::fIsMenuBar, tagMENUSTATE::fModelessMenu, FWINABLE, tagWND::head, HW, IDSYS_MNHIDE, L, Lock, MFMWFP_NOITEM, MNAnimate(), NT_SUCCESS, NULL, tagTHREADINFO::pMenuState, tagPOPUPMENU::posSelectedItem, tagPOPUPMENU::ppopupmenuRoot, PtiCurrent, PUDF_ANIMATE, tagTHREADINFO::rpdesk, SetVisible(), tagPOPUPMENU::spmenu, tagPOPUPMENU::spwndActivePopup, tagDESKTOP::spwndMenu, tagPOPUPMENU::spwndNextPopup, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, SV_UNSET, TEST_PUDF, TestWF, ThreadLockAlways, ThreadUnlock, TRUE, Unlock, Validateppopupmenu, WFVISIBLE, xxxActivateThisWindow(), xxxCleanupDesktopMenu(), xxxClientRevokeDragDrop(), xxxDestroyWindow(), xxxMNDestroyHandler(), xxxSendMenuSelect(), xxxSendMessage(), xxxShowWindow(), and xxxWindowEvent().

Referenced by xxxDestroyThreadInfo(), xxxEndMenu(), xxxMenuWindowProc(), xxxMNCancel(), xxxMNKeyDown(), xxxMNKeyFilter(), xxxMNOpenHierarchy(), and xxxMNSelectItem().

02519 { 02520 TL tlpwndNext; 02521 TL tlpwnd; 02522 TL tlpopup; 02523 PTHREADINFO ptiCurrent = PtiCurrent(); 02524 PDESKTOP pdesk; 02525 PWND pwndNext; 02526 02527 Validateppopupmenu(ppopupmenu); 02528 02529 /* 02530 * Terminate any animation 02531 */ 02532 MNAnimate(pMenuState, FALSE); 02533 02534 /* 02535 * If a hierarchy exists, close all childen below us. Do it in reversed 02536 * order so savebits work out. 02537 */ 02538 if (!ppopupmenu->fHierarchyDropped) { 02539 /* 02540 * Assert that there's no next or it might not get closed 02541 */ 02542 UserAssert(ppopupmenu->spwndNextPopup == NULL); 02543 return; 02544 } 02545 02546 if (ppopupmenu->fHideTimer) 02547 { 02548 _KillTimer(ppopupmenu->spwndPopupMenu, IDSYS_MNHIDE); 02549 ppopupmenu->fHideTimer = FALSE; 02550 } 02551 02552 pwndNext = ppopupmenu->spwndNextPopup; 02553 if (pwndNext != NULL) { 02554 02555 ThreadLockAlways(pwndNext, &tlpwndNext); 02556 xxxSendMessage(pwndNext, MN_CLOSEHIERARCHY, 0, 0); 02557 02558 /* 02559 * If modeless menu, activate the this popup since we're about 02560 * to destroy the current active one. We want to keep activation 02561 * on a menu window so we can get the keys. Also, modeless menus 02562 * are canceled when a non-menu window is activated in their queue 02563 */ 02564 if (pMenuState->fModelessMenu 02565 && pMenuState->fInsideMenuLoop 02566 && !ppopupmenu->fIsMenuBar) { 02567 02568 ThreadLockAlways(ppopupmenu->spwndPopupMenu, &tlpwnd); 02569 xxxActivateThisWindow(ppopupmenu->spwndPopupMenu, 0, 0); 02570 ThreadUnlock(&tlpwnd); 02571 } 02572 02573 if (FWINABLE()) { 02574 xxxWindowEvent(EVENT_SYSTEM_MENUPOPUPEND, pwndNext, OBJID_CLIENT, INDEXID_CONTAINER, 0); 02575 } 02576 02577 /* 02578 * If the current thread is not in the right pdesk, then that could 02579 * be the cause of the stuck menu bug. 02580 * In other words, are we nuking this menu out of context? 02581 */ 02582 UserAssert(ptiCurrent->pMenuState != NULL); 02583 pdesk = ptiCurrent->rpdesk; 02584 02585 if (pwndNext == pdesk->spwndMenu) { 02586 PPOPUPMENU ppopupmenuReal; 02587 02588 UserAssert(pdesk->dwDTFlags & DF_MENUINUSE); 02589 02590 /* 02591 * If this is our precreated real popup window, 02592 * initialize ourselves and just hide. 02593 */ 02594 xxxShowWindow(pwndNext, SW_HIDE | TEST_PUDF(PUDF_ANIMATE)); 02595 02596 /* 02597 * Its possible that during Logoff the above xxxShowWindow 02598 * won't get prossessed and because this window is a special 02599 * window that is owned by they desktop we have to manually mark 02600 * it as invisible. 02601 */ 02602 if (TestWF(pwndNext, WFVISIBLE)) { 02603 SetVisible(pwndNext, SV_UNSET); 02604 } 02605 02606 #ifdef HAVE_MN_GETPPOPUPMENU 02607 ppopupmenuReal = (PPOPUPMENU)xxxSendMessage(pwndNext, 02608 MN_GETPPOPUPMENU,0, 0L); 02609 #else 02610 ppopupmenuReal = ((PMENUWND)pwndNext)->ppopupmenu; 02611 #endif 02612 UserAssert(ppopupmenuReal->fDesktopMenu == TRUE); 02613 02614 /* 02615 * We don't want this window to be a drop target anymore. 02616 * Non cached menu windows revoke it on WM_FINALDESTROY. 02617 */ 02618 if (pMenuState->fDragAndDrop) { 02619 if (!NT_SUCCESS(xxxClientRevokeDragDrop(HW(pwndNext)))) { 02620 RIPMSG1(RIP_ERROR, "xxxMNCloseHierarchy: xxxClientRevokeRegisterDragDrop failed:%#p", pwndNext); 02621 } 02622 } 02623 02624 if (ppopupmenuReal != NULL) { 02625 xxxMNDestroyHandler(ppopupmenuReal); 02626 /* 02627 * We used to clear the popup contents here but the popup might be 02628 * still in use if this is happening during a callback. So we let 02629 * MNFreePopup do that. If it didn't happen during the call above, 02630 * it'll happen when MNFlushDestroyedPopups is executed. 02631 */ 02632 } 02633 02634 xxxCleanupDesktopMenu(pwndNext, pdesk); 02635 02636 ThreadUnlock(&tlpwndNext); 02637 } else if (ThreadUnlock(&tlpwndNext)) { 02638 /* 02639 * We know this is not the current thread's desktop menu window. 02640 * Let's assert that it's not the menu window of another desktop. 02641 */ 02642 UserAssert(pwndNext != pwndNext->head.rpdesk->spwndMenu); 02643 xxxDestroyWindow(pwndNext); 02644 } 02645 02646 Unlock(&ppopupmenu->spwndNextPopup); 02647 ppopupmenu->fHierarchyDropped = FALSE; 02648 02649 } 02650 02651 if (ppopupmenu->fIsMenuBar) { 02652 Unlock(&ppopupmenu->spwndActivePopup); 02653 } else { 02654 Lock(&(ppopupmenu->ppopupmenuRoot->spwndActivePopup), 02655 ppopupmenu->spwndPopupMenu); 02656 } 02657 02658 if (pMenuState->fInsideMenuLoop && 02659 (ppopupmenu->posSelectedItem != MFMWFP_NOITEM)) { 02660 /* 02661 * Send a menu select as if this item had just been selected. This 02662 * allows people to easily update their menu status bars when a 02663 * hierarchy from this item has been closed. 02664 */ 02665 PWND pwnd = ppopupmenu->ppopupmenuRoot->spwndNotify; 02666 if (pwnd) { 02667 ThreadLockAlways(pwnd, &tlpwnd); 02668 ThreadLockAlways(ppopupmenu->spwndPopupMenu, &tlpopup); 02669 xxxSendMenuSelect(pwnd, ppopupmenu->spwndPopupMenu, 02670 ppopupmenu->spmenu, ppopupmenu->posSelectedItem); 02671 ThreadUnlock(&tlpopup); 02672 ThreadUnlock(&tlpwnd); 02673 } 02674 } 02675 02676 }

void xxxMNDestroyHandler PPOPUPMENU  ppopupmenu  ) 
 

Definition at line 880 of file ntuser/kernel/menu.c.

References _KillTimer(), BOOL, tagMENU::cItems, FALSE, tagPOPUPMENU::fDelayedFree, tagPOPUPMENU::fDesktopMenu, tagPOPUPMENU::fDestroyed, tagPOPUPMENU::fFlushDelayedFree, tagPOPUPMENU::fHideTimer, tagPOPUPMENU::fIsSysMenu, tagPOPUPMENU::fSendUninit, tagPOPUPMENU::fShowTimer, tagITEM::fState, IDSYS_MNHIDE, IDSYS_MNSHOW, IsRootPopupMenu(), MNFreePopup(), MNIsItemSelected(), NULL, tagPOPUPMENU::posSelectedItem, tagPOPUPMENU::ppmDelayedFree, tagPOPUPMENU::ppopupmenuRoot, PtoH, tagMENU::rgItems, tagPOPUPMENU::spmenu, tagPOPUPMENU::spwndNextPopup, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, ThreadLockAlways, ThreadUnlock, TRUE, Validateppopupmenu, and xxxSendMessage().

Referenced by xxxMenuWindowProc(), xxxMNCloseHierarchy(), and xxxMNOpenHierarchy().

00882 { 00883 PITEM pItem; 00884 TL tlpwndT; 00885 00886 if (ppopupmenu == NULL) { 00887 /* 00888 * This can happen if WM_NCCREATE failed to allocate the ppopupmenu 00889 * in xxxMenuWindowProc. 00890 */ 00891 RIPMSG0(RIP_WARNING, "xxxMNDestroyHandler: NULL \"ppopupmenu\""); 00892 return; 00893 } 00894 00895 #if DBG 00896 /* 00897 * When destroying a desktop's spwndMenu that is not in use (i.e., the 00898 * desktop is going away), the ppopupmenu is not exactly valid (i.e., 00899 * we're not in menu mode) but it should be properly NULLed out so 00900 * everything should go smoothly 00901 */ 00902 Validateppopupmenu(ppopupmenu); 00903 #endif 00904 00905 if (ppopupmenu->spwndNextPopup != NULL) { 00906 /* 00907 * We used to send the message to spwndNextPopup here. The message should 00908 * go to the current popup so it'll close spwndNextPopup (not to the next 00909 * to close its next, if any). 00910 * I don't see how the current spwndPopupMenu can be NULL but we better 00911 * handle it since we never accessed it before. This menu code is tricky... 00912 */ 00913 PWND pwnd; 00914 UserAssert(ppopupmenu->spwndPopupMenu != NULL); 00915 pwnd = (ppopupmenu->spwndPopupMenu != NULL ? ppopupmenu->spwndPopupMenu : ppopupmenu->spwndNextPopup); 00916 ThreadLockAlways(pwnd, &tlpwndT); 00917 xxxSendMessage(pwnd, MN_CLOSEHIERARCHY, 0, 0); 00918 ThreadUnlock(&tlpwndT); 00919 } 00920 00921 if ((ppopupmenu->spmenu!=NULL) && MNIsItemSelected(ppopupmenu)) 00922 { 00923 /* 00924 * Unset the hilite bit on the hilited item. 00925 */ 00926 if (ppopupmenu->posSelectedItem < ppopupmenu->spmenu->cItems) { 00927 /* 00928 * this extra check saves Ambiente 1.02 -- they have a menu with 00929 * one item in it. When that command is chosen, the app proceeds 00930 * to remove that one item -- leaving us in the oh so strange state 00931 * of having a valid hMenu with a NULL rgItems. 00932 */ 00933 pItem = &(ppopupmenu->spmenu->rgItems[ppopupmenu->posSelectedItem]); 00934 pItem->fState &= ~MFS_HILITE; 00935 } 00936 } 00937 00938 if (ppopupmenu->fShowTimer) { 00939 _KillTimer(ppopupmenu->spwndPopupMenu, IDSYS_MNSHOW); 00940 } 00941 00942 if (ppopupmenu->fHideTimer) { 00943 _KillTimer(ppopupmenu->spwndPopupMenu, IDSYS_MNHIDE); 00944 } 00945 00946 /* 00947 * Send WM_UNINITMENUPOPUP so the menu owner can clean up. 00948 */ 00949 if (ppopupmenu->fSendUninit 00950 && (ppopupmenu->spwndNotify != NULL)) { 00951 00952 ThreadLockAlways(ppopupmenu->spwndNotify, &tlpwndT); 00953 xxxSendMessage(ppopupmenu->spwndNotify, WM_UNINITMENUPOPUP, 00954 (WPARAM)PtoH(ppopupmenu->spmenu), 00955 MAKELONG(0, (ppopupmenu->fIsSysMenu ? MF_SYSMENU: 0))); 00956 ThreadUnlock(&tlpwndT); 00957 } 00958 00959 ppopupmenu->fDestroyed = TRUE; 00960 if (!ppopupmenu->fDesktopMenu) { 00961 00962 if (ppopupmenu->spwndPopupMenu != NULL) { 00963 ((PMENUWND)(ppopupmenu->spwndPopupMenu))->ppopupmenu = NULL; 00964 } 00965 00966 } 00967 00968 if (!ppopupmenu->fDelayedFree) { 00969 MNFreePopup(ppopupmenu); 00970 } else if (ppopupmenu->ppopupmenuRoot != NULL) { 00971 ppopupmenu->ppopupmenuRoot->fFlushDelayedFree = TRUE; 00972 #if DBG 00973 { 00974 /* 00975 * If this is not the rootpopup, 00976 * assert that this popup is linked in the delayed free list 00977 */ 00978 if (!IsRootPopupMenu(ppopupmenu)) { 00979 BOOL fFound = FALSE; 00980 PPOPUPMENU ppm = ppopupmenu->ppopupmenuRoot; 00981 while (ppm->ppmDelayedFree != NULL) { 00982 if (ppm->ppmDelayedFree == ppopupmenu) { 00983 fFound = TRUE; 00984 break; 00985 } 00986 ppm = ppm->ppmDelayedFree; 00987 } 00988 UserAssert(fFound); 00989 } 00990 } 00991 #endif 00992 } else { 00993 UserAssertMsg1(FALSE, "Leaking ppopupmenu:%p?", ppopupmenu); 00994 } 00995 00996 }

void xxxMNDismiss PMENUSTATE  pMenuState  ) 
 

Definition at line 36 of file ntuser/kernel/menu.c.

References xxxMNCancel().

Referenced by xxxEndMenu(), xxxEndMenuLoop(), xxxHandleMenuMessages(), xxxMNButtonUp(), xxxMNChar(), xxxMNKeyDown(), and xxxMNKeyFilter().

00037 { 00038 xxxMNCancel(pMenuState, 0, 0, 0); 00039 }

void xxxMNDismissWithNotify PMENUSTATE  pMenuState,
PMENU  pmenu,
PITEM  pitem,
UINT  uPos,
LPARAM  lParam
 

Definition at line 98 of file ntuser/kernel/menu.c.

References tagPOPUPMENU::fIsSysMenu, tagMENUSTATE::fNotifyByPos, MNFadeSelection(), tagMENUSTATE::pGlobalPopupMenu, PtoHq, StartFade(), UINT, tagITEM::wID, and xxxMNCancel().

Referenced by xxxMNButtonUp(), xxxMNDoubleClick(), and xxxMNKeyDown().

00100 { 00101 UINT uMsg; 00102 UINT uCmd; 00103 00104 if (pMenuState->pGlobalPopupMenu->fIsSysMenu) { 00105 uMsg = WM_SYSCOMMAND; 00106 uCmd = pitem->wID; 00107 /* lParam set by caller */ 00108 } else if (pMenuState->fNotifyByPos) { 00109 uMsg = WM_MENUCOMMAND; 00110 uCmd = uPos; 00111 lParam = (LPARAM)PtoHq(pmenu); 00112 } else { 00113 uMsg = WM_COMMAND; 00114 uCmd = pitem->wID; 00115 lParam = 0; 00116 } 00117 00118 /* 00119 * The menu is about to go away, see if we want to fade out the selection. 00120 */ 00121 if (MNFadeSelection(pmenu, pitem)) { 00122 StartFade(); 00123 } 00124 00125 /* 00126 * Dismiss the menu. 00127 */ 00128 xxxMNCancel(pMenuState, uMsg, uCmd, lParam); 00129 }

BOOL xxxMNDoScroll PPOPUPMENU  ppopup,
UINT  uArrow,
BOOL  fSetTimer
 

Definition at line 591 of file ntuser/kernel/menu.c.

References _KillTimer(), _SetTimer(), BOOL, FALSE, gpsi, tagMENU::iTop, MFMWFP_DOWNARROW, MFMWFP_UPARROW, NULL, tagPOPUPMENU::spmenu, tagPOPUPMENU::spwndPopupMenu, TRUE, and xxxMNSetTop().

Referenced by xxxMenuWindowProc(), xxxMNButtonDown(), xxxMNDoubleClick(), and xxxMNSelectItem().

00592 { 00593 int iScrollTop = ppopup->spmenu->iTop; 00594 00595 if (uArrow == MFMWFP_UPARROW) { 00596 iScrollTop--; 00597 } else if (uArrow == MFMWFP_DOWNARROW) { 00598 iScrollTop++; 00599 } else { 00600 return FALSE; 00601 } 00602 00603 if (!xxxMNSetTop(ppopup, iScrollTop)) { 00604 if (!fSetTimer) { 00605 _KillTimer(ppopup->spwndPopupMenu, uArrow); 00606 } 00607 } else { 00608 /* 00609 * Set this timer just like we do in the scrollbar code: 00610 * the first time we wait a little longer. 00611 */ 00612 _SetTimer(ppopup->spwndPopupMenu, uArrow, 00613 (fSetTimer ? gpsi->dtScroll : gpsi->dtScroll / 4), NULL); 00614 } 00615 00616 return TRUE; 00617 }

BOOL xxxMNDoubleClick PMENUSTATE  pMenuState,
PPOPUPMENU  ppopup,
int  idxItem
 

Definition at line 2697 of file ntuser/kernel/menu.c.

References _GetMenuDefaultItem(), BOOL, tagMENU::cItems, FALSE, tagITEM::fState, msg, NULL, tagPOPUPMENU::posSelectedItem, tagPOPUPMENU::ppopupmenuRoot, tagMENU::rgItems, tagPOPUPMENU::spmenu, tagITEM::spSubMenu, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, TestWF, ThreadLock, ThreadUnlock, TRUE, UINT, WFWIN40COMPAT, xxxMNDismissWithNotify(), xxxMNDoScroll(), xxxPeekMessage, and xxxSendMenuSelect().

Referenced by xxxHandleMenuMessages(), and xxxMenuWindowProc().

02698 { 02699 PMENU pMenu; 02700 PITEM pItem; 02701 MSG msg; 02702 UINT uPos; 02703 02704 /* 02705 * This code to swallow double clicks isn't executed! MNLoop will 02706 * swallow all double clicks for us. Swallow the up button for the 02707 * double dude instead. Word will not be happy if they get a spurious 02708 * WM_LBUTTONUP on the menu bar if their code to close the MDI child 02709 * doesn't swallow it soon enough. 02710 */ 02711 02712 /* 02713 * Eat the click. 02714 */ 02715 if (xxxPeekMessage(&msg, NULL, 0, 0, PM_NOYIELD)) { 02716 if ((msg.message == WM_LBUTTONUP) || 02717 (msg.message == WM_NCLBUTTONUP)) { 02718 xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE); 02719 } 02720 #if DBG 02721 else if (msg.message == WM_LBUTTONDBLCLK || 02722 msg.message == WM_NCLBUTTONDBLCLK) 02723 { 02724 UserAssertMsg0(FALSE, "xxxMNDoubleClick found a double click"); 02725 } 02726 #endif 02727 } 02728 02729 /* 02730 * Get current item. 02731 */ 02732 pMenu = ppopup->spmenu; 02733 if ((pMenu==NULL) || ((UINT)idxItem >= pMenu->cItems)) { 02734 xxxMNDoScroll(ppopup, ppopup->posSelectedItem, FALSE); 02735 goto Done; 02736 } 02737 02738 pItem = pMenu->rgItems + idxItem; 02739 uPos = idxItem; 02740 02741 /* 02742 * Do nothing if item is disabled. 02743 */ 02744 if (pItem->fState & MFS_GRAYED) 02745 goto Done; 02746 02747 /* 02748 * Traverse the hierarchy down as far as possible. 02749 */ 02750 do 02751 { 02752 if (pItem->spSubMenu != NULL) { 02753 /* 02754 * The item is a popup menu, so continue traversing. 02755 */ 02756 pMenu = pItem->spSubMenu; 02757 idxItem = (UINT)_GetMenuDefaultItem(pMenu, MF_BYPOSITION, 0); 02758 02759 if (idxItem != -1) { 02760 pItem = pMenu->rgItems + idxItem; 02761 uPos = idxItem; 02762 continue; 02763 } else /* if (lpItem->wID == -1) How do we know this popup has an ID? */ 02764 break; 02765 } 02766 02767 /* 02768 * We've found a leaf node of some kind, either a MFS_DEFAULT popup 02769 * with a valid cmd ID that has no valid MFS_DEFAULT children, or 02770 * a real cmd with MFS_DEFAULT style. 02771 * 02772 * Exit menu mode and send command ID. 02773 */ 02774 02775 /* 02776 * For old apps we need to generate a WM_MENUSELECT message first. 02777 * Old apps, esp. Word 6.0, can't handle double-clicks on maximized 02778 * child sys menus because they never get a WM_MENUSELECT for the 02779 * item, unlike with normal keyboard/mouse choosing. We need to 02780 * fake it so they won't fault. Several VB apps have a similar 02781 * problem. 02782 */ 02783 if (!TestWF(ppopup->ppopupmenuRoot->spwndNotify, WFWIN40COMPAT)) 02784 { 02785 TL tlpwndNotify, tlpopup; 02786 02787 ThreadLock(ppopup->ppopupmenuRoot->spwndNotify, &tlpwndNotify); 02788 ThreadLock(ppopup->spwndPopupMenu, &tlpopup); 02789 xxxSendMenuSelect(ppopup->ppopupmenuRoot->spwndNotify, 02790 ppopup->spwndPopupMenu, pMenu, idxItem); 02791 ThreadUnlock(&tlpopup); 02792 ThreadUnlock(&tlpwndNotify); 02793 } 02794 02795 xxxMNDismissWithNotify(pMenuState, pMenu, pItem, uPos, 0); 02796 return TRUE; 02797 } 02798 while (TRUE); 02799 02800 Done: 02801 return(FALSE); 02802 }

LONG_PTR xxxMNFindWindowFromPoint PPOPUPMENU  ppopupmenu,
PUINT  pIndex,
POINTS  screenPt
 

Definition at line 3180 of file ntuser/kernel/menu.c.

References _HasCaptionIcon(), FALSE, tagPOPUPMENU::fIsMenuBar, tagPOPUPMENU::fIsSysMenu, GetWindowBorders(), IsMFMWFPWindow(), L, MFMWFP_ALTMENU, MFMWFP_NOITEM, MFMWFP_OFFMENU, MNItemHitTest(), NULL, OffsetRect(), PtInRect(), tagWND::rcWindow, RevalidateHwnd, tagPOPUPMENU::spmenu, tagPOPUPMENU::spmenuAlternate, tagPOPUPMENU::spwndNextPopup, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, SYSMET, TestWF, ThreadLockAlways, ThreadUnlock, TRUE, UINT, WFMINIMIZED, and xxxSendMessage().

Referenced by xxxHandleMenuMessages(), xxxMenuWindowProc(), and xxxMNMouseMove().

03184 { 03185 POINT pt; 03186 RECT rect; 03187 LONG_PTR longHit; 03188 UINT itemHit; 03189 PWND pwnd; 03190 TL tlpwndT; 03191 #ifdef USE_MIRRORING 03192 int cx; 03193 #endif 03194 03195 03196 *pIndex = 0; 03197 03198 if (ppopupmenu->spwndNextPopup) { 03199 03200 /* 03201 * Check if this point is on any of our children before checking if it 03202 * is on ourselves. 03203 */ 03204 ThreadLockAlways(ppopupmenu->spwndNextPopup, &tlpwndT); 03205 longHit = xxxSendMessage(ppopupmenu->spwndNextPopup, 03206 MN_FINDMENUWINDOWFROMPOINT, (WPARAM)&itemHit, 03207 MAKELONG(screenPt.x, screenPt.y)); 03208 ThreadUnlock(&tlpwndT); 03209 03210 /* 03211 * If return value is an hwnd, convert to pwnd. 03212 */ 03213 if (IsMFMWFPWindow(longHit)) { 03214 longHit = (LONG_PTR)RevalidateHwnd((HWND)longHit); 03215 } 03216 03217 if (longHit) { 03218 03219 /* 03220 * Hit occurred on one of our children. 03221 */ 03222 03223 *pIndex = itemHit; 03224 return longHit; 03225 } 03226 } 03227 03228 if (ppopupmenu->fIsMenuBar) { 03229 int cBorders; 03230 03231 /* 03232 * Check if this point is on the menu bar 03233 */ 03234 pwnd = ppopupmenu->spwndNotify; 03235 if (pwnd == NULL) { 03236 return MFMWFP_OFFMENU; 03237 } 03238 03239 pt.x = screenPt.x; 03240 pt.y = screenPt.y; 03241 03242 if (ppopupmenu->fIsSysMenu) { 03243 03244 if (!_HasCaptionIcon(pwnd)) { 03245 /* 03246 * no system menu rect to click in if it doesn't have an icon 03247 */ 03248 return(0L); 03249 } 03250 03251 /* 03252 * Check if this is a click on the system menu icon. 03253 */ 03254 if (TestWF(pwnd, WFMINIMIZED)) { 03255 03256 /* 03257 * If the window is minimized, then check if there was a hit in 03258 * the client area of the icon's window. 03259 */ 03260 03261 /* 03262 * Mikehar 5/27 03263 * Don't know how this ever worked. If we are the system menu of an icon 03264 * we want to punt the menus if the click occurs ANYWHERE outside of the 03265 * menu. 03266 * Johnc 03-Jun-1992 the next 4 lines were commented out for Mike's 03267 * problem above but that made clicking on a minimized window with 03268 * the system menu already up, bring down the menu and put it right 03269 * up again (bug 10951) because the mnloop wouldn't swallow the mouse 03270 * down click message. The problem Mike mentions no longer shows up. 03271 */ 03272 03273 if (PtInRect(&(pwnd->rcWindow), pt)) { 03274 return MFMWFP_NOITEM; 03275 } 03276 03277 /* 03278 * It's an iconic window, so can't be hitting anywhere else. 03279 */ 03280 return MFMWFP_OFFMENU; 03281 } 03282 03283 /* 03284 * Check if we are hitting on the system menu rectangle on the top 03285 * left of windows. 03286 */ 03287 rect.top = rect.left = 0; 03288 rect.right = SYSMET(CXSIZE); 03289 rect.bottom = SYSMET(CYSIZE); 03290 03291 cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); 03292 03293 OffsetRect(&rect, pwnd->rcWindow.left + cBorders*SYSMET(CXBORDER), 03294 pwnd->rcWindow.top + cBorders*SYSMET(CYBORDER)); 03295 #ifdef USE_MIRRORING 03296 //Mirror the rect because the buttons in the left hand side of the window if it mirrored 03297 if (TestWF(pwnd, WEFLAYOUTRTL)) { 03298 cx = rect.right - rect.left; 03299 rect.right = pwnd->rcWindow.right - (rect.left - pwnd->rcWindow.left); 03300 rect.left = rect.right - cx; 03301 } 03302 #endif 03303 if (PtInRect(&rect, pt)) { 03304 *pIndex = 0; 03305 return(MFMWFP_NOITEM); 03306 } 03307 /* 03308 * Check if we hit in the alternate menu if available. 03309 */ 03310 if (ppopupmenu->spmenuAlternate) { 03311 itemHit = MNItemHitTest(ppopupmenu->spmenuAlternate, pwnd, pt); 03312 if (itemHit != MFMWFP_NOITEM) { 03313 *pIndex = itemHit; 03314 return MFMWFP_ALTMENU; 03315 } 03316 } 03317 return MFMWFP_OFFMENU; 03318 } else { 03319 if (TestWF(ppopupmenu->spwndNotify, WFMINIMIZED)) { 03320 03321 /* 03322 * If we are minimized, we can't hit on the main menu bar. 03323 */ 03324 return MFMWFP_OFFMENU; 03325 } 03326 } 03327 } else { 03328 pwnd = ppopupmenu->spwndPopupMenu; 03329 03330 /* 03331 * else this is a popup window and we need to check if we are hitting 03332 * anywhere on this popup window. 03333 */ 03334 pt.x = screenPt.x; 03335 pt.y = screenPt.y; 03336 if (!PtInRect(&pwnd->rcWindow, pt)) { 03337 03338 /* 03339 * Point completely outside the popup menu window so return 0. 03340 */ 03341 return MFMWFP_OFFMENU; 03342 } 03343 } 03344 03345 pt.x = screenPt.x; 03346 pt.y = screenPt.y; 03347 03348 itemHit = MNItemHitTest(ppopupmenu->spmenu, pwnd, pt); 03349 03350 if (ppopupmenu->fIsMenuBar) { 03351 03352 /* 03353 * If hit is on menu bar but no item is there, treat it as if the user 03354 * hit nothing. 03355 */ 03356 if (itemHit == MFMWFP_NOITEM) { 03357 03358 /* 03359 * Check if we hit in the alternate menu if available. 03360 */ 03361 if (ppopupmenu->spmenuAlternate) { 03362 itemHit = MNItemHitTest(ppopupmenu->spmenuAlternate, pwnd, pt); 03363 if (itemHit != MFMWFP_NOITEM) { 03364 *pIndex = itemHit; 03365 return MFMWFP_ALTMENU; 03366 } 03367 } 03368 return MFMWFP_OFFMENU; 03369 } 03370 03371 *pIndex = itemHit; 03372 return MFMWFP_NOITEM; 03373 } else { 03374 03375 /* 03376 * If hit is on popup menu but no item is there, itemHit 03377 * will be MFMWFP_NOITEM 03378 */ 03379 *pIndex = itemHit; 03380 return (LONG_PTR)pwnd; 03381 } 03382 return MFMWFP_OFFMENU; 03383 }

BOOL xxxMNHideNextHierarchy PPOPUPMENU  ppopup  ) 
 

Definition at line 2492 of file ntuser/kernel/menu.c.

References BOOL, FALSE, L, NULL, tagPOPUPMENU::spwndActivePopup, tagPOPUPMENU::spwndNextPopup, ThreadLockAlways, ThreadUnlock, TRUE, and xxxSendMessage().

Referenced by xxxMNButtonDown(), and xxxMNMouseMove().

02493 { 02494 if (ppopup->spwndNextPopup != NULL) { 02495 TL tlpwndT; 02496 02497 ThreadLockAlways(ppopup->spwndNextPopup, &tlpwndT); 02498 if (ppopup->spwndNextPopup != ppopup->spwndActivePopup) 02499 xxxSendMessage(ppopup->spwndNextPopup, MN_CLOSEHIERARCHY, 0, 0L); 02500 02501 xxxSendMessage(ppopup->spwndNextPopup, MN_SELECTITEM, (WPARAM)-1, 0L); 02502 ThreadUnlock(&tlpwndT); 02503 return TRUE; 02504 } 02505 return FALSE; 02506 }

void xxxMNKeyDown PPOPUPMENU  ppopupmenu,
PMENUSTATE  pMenuState,
UINT  key
 

Definition at line 1251 of file ntuser/kernel/menu.c.

References _GetSubMenu(), _IsIconic, BOOL, dir(), FALSE, tagMENUSTATE::fButtonDown, tagMENUSTATE::fDragging, tagPOPUPMENU::fDropNextPopup, tagPOPUPMENU::fHasMenuBar, tagPOPUPMENU::fHierarchyDropped, tagMENUSTATE::fIgnoreButtonUp, tagPOPUPMENU::fIsMenuBar, tagMENUSTATE::fIsSysMenu, tagMENUSTATE::fModelessMenu, tagPOPUPMENU::fRtoL, tagITEM::fState, tagMENUSTATE::fUnderline, GetMenuInheritedContextHelpId(), GETPTI, gwinOldAppHackoMaticFlags, IsRootPopupMenu(), Lock, LockPopupMenu(), MFMWFP_NOITEM, MNFindItemInColumn(), MNFindNextValidItem(), NULL, tagPOPUPMENU::posSelectedItem, tagPOPUPMENU::ppopupmenuRoot, tagTHREADINFO::pq, PtiCurrent, PtoH, PtoHq, QF_CAPTURELOCKED, tagQ::QF_flags, RevalidateHmenu, RevalidateHwnd, tagPOPUPMENU::spmenu, tagWND::spmenu, tagWND::spmenuSys, tagITEM::spSubMenu, tagPOPUPMENU::spwndNextPopup, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, tagPOPUPMENU::spwndPrevPopup, TestWF, ThreadLock, ThreadUnlock, TRUE, UINT, UnlockPopupMenu(), WFCHILD, WFMINIMIZED, WFSYSMENU, tagITEM::wID, WOAHACK_CHECKALTKEYSTATE, WOAHACK_IGNOREALTKEYDOWN, xxxMNCloseHierarchy(), xxxMNDismiss(), xxxMNDismissWithNotify(), xxxMNOpenHierarchy(), xxxMNSelectItem(), xxxMNSetCapture(), xxxMNSwitchToAlternateMenu(), xxxSendHelpMessage(), and xxxSendMessage().

Referenced by xxxHandleMenuMessages(), xxxMenuWindowProc(), and xxxMNChar().

01255 { 01256 LRESULT dwMDIMenu; 01257 UINT item; 01258 BOOL fHierarchyWasDropped = FALSE; 01259 TL tlpwndT; 01260 PPOPUPMENU ppopupSave; 01261 BOOL bFakedKey; 01262 UINT keyOrig = key; 01263 01264 /* 01265 * Blow off keyboard if mouse down. 01266 */ 01267 if ((pMenuState->fButtonDown) && (key != VK_F1)) { 01268 /* 01269 * Check if the user wants to cancel dragging. 01270 */ 01271 if (pMenuState->fDragging && (key == VK_ESCAPE)) { 01272 RIPMSG0(RIP_WARNING, "xxxMNKeyDown: ESC while dragging"); 01273 pMenuState->fIgnoreButtonUp = TRUE; 01274 } 01275 01276 return; 01277 } 01278 01279 switch (key) { 01280 case VK_MENU: 01281 case VK_F10: 01282 { 01283 /* 01284 * Modeless don't go away when the menu key is hit. They just 01285 * ignore it. 01286 */ 01287 if (pMenuState->fModelessMenu) { 01288 return; 01289 } 01290 01291 if (gwinOldAppHackoMaticFlags & WOAHACK_CHECKALTKEYSTATE) { 01292 01293 /* 01294 * Winoldapp is telling us to put up/down the system menu. Due to 01295 * possible race conditions, we need to check the state of the alt 01296 * key before throwing away the menu. 01297 */ 01298 if (gwinOldAppHackoMaticFlags & WOAHACK_IGNOREALTKEYDOWN) { 01299 return; 01300 } 01301 } 01302 xxxMNDismiss(pMenuState); 01303 01304 /* 01305 * We're going to exit menu mode but the ALT key is down, so clear 01306 * pMenuState->fUnderline to cause xxxMNLoop not to erase the underlines 01307 */ 01308 if (key == VK_MENU) { 01309 pMenuState->fUnderline = FALSE; 01310 } 01311 } 01312 return; 01313 01314 case VK_ESCAPE: 01315 01316 /* 01317 * Escape key was hit. Get out of one level of menus. If no active 01318 * popups or we are minimized and there are no active popups below 01319 * this, we need to get out of menu mode. Otherwise, we popup up 01320 * one level in the hierarchy. 01321 */ 01322 if (ppopupmenu->fIsMenuBar || 01323 ppopupmenu == ppopupmenu->ppopupmenuRoot || 01324 TestWF(ppopupmenu->ppopupmenuRoot->spwndNotify, WFMINIMIZED)) { 01325 xxxMNDismiss(pMenuState); 01326 } else { 01327 /* 01328 * Pop back one level of menus. 01329 */ 01330 if (ppopupmenu->fHasMenuBar && 01331 ppopupmenu->spwndPrevPopup == ppopupmenu->spwndNotify) { 01332 01333 PPOPUPMENU ppopupmenuRoot = ppopupmenu->ppopupmenuRoot; 01334 01335 ppopupmenuRoot->fDropNextPopup = FALSE; 01336 01337 #if 0 01338 /* 01339 * We are on a menu bar hierarchy and there is only one popup 01340 * visible. We have to cancel this popup and put focus back on 01341 * the menu bar. 01342 */ 01343 if (_IsIconic(ppopupmenuRoot->spwndNotify)) { 01344 01345 /* 01346 * However, if we are iconic there really is no menu 01347 * bar so let's make it easier for users and get out 01348 * of menu mode completely. 01349 */ 01350 xxxMNDismiss(pMenuState); 01351 } else 01352 #endif 01353 /* 01354 * If the popup is closed, a modeless menu won't 01355 * have a window to get the keys. So modeless menu 01356 * cancel the menu at this point. Modal menus go 01357 * to the menu bar. 01358 */ 01359 if (pMenuState->fModelessMenu) { 01360 xxxMNDismiss(pMenuState); 01361 } else { 01362 xxxMNCloseHierarchy(ppopupmenuRoot, pMenuState); 01363 } 01364 } else { 01365 ThreadLock(ppopupmenu->spwndPrevPopup, &tlpwndT); 01366 xxxSendMessage(ppopupmenu->spwndPrevPopup, MN_CLOSEHIERARCHY, 01367 0, 0); 01368 ThreadUnlock(&tlpwndT); 01369 } 01370 } 01371 return; 01372 01373 case VK_UP: 01374 case VK_DOWN: 01375 if (ppopupmenu->fIsMenuBar) { 01376 01377 /* 01378 * If we are on the top level menu bar, try to open the popup if 01379 * possible. 01380 */ 01381 if (xxxMNOpenHierarchy(ppopupmenu, pMenuState) == (PWND)-1) 01382 return; 01383 } else { 01384 item = MNFindNextValidItem(ppopupmenu->spmenu, 01385 ppopupmenu->posSelectedItem, (key == VK_UP ? -1 : 1), 0); 01386 xxxMNSelectItem(ppopupmenu, pMenuState, item); 01387 } 01388 return; 01389 01390 case VK_LEFT: 01391 case VK_RIGHT: 01392 #ifdef USE_MIRRORING 01393 bFakedKey = (!!ppopupmenu->fRtoL) ^ (!!TestWF(ppopupmenu->spwndPopupMenu, WEFLAYOUTRTL)); 01394 #else 01395 bFakedKey = ppopupmenu->fRtoL; 01396 #endif 01397 if (bFakedKey) 01398 /* 01399 * turn the keys around, we drew the menu backwards. 01400 */ 01401 key = (key == VK_LEFT) ? VK_RIGHT : VK_LEFT; 01402 if (!ppopupmenu->fIsMenuBar && (key == VK_RIGHT) && 01403 !ppopupmenu->spwndNextPopup) { 01404 /* 01405 * Try to open the hierarchy at this item if there is one. 01406 */ 01407 if (xxxMNOpenHierarchy(ppopupmenu, pMenuState) == (PWND)-1) 01408 return; 01409 if (ppopupmenu->fHierarchyDropped) { 01410 return; 01411 } 01412 } 01413 01414 if (ppopupmenu->spwndNextPopup) { 01415 fHierarchyWasDropped = TRUE; 01416 if ((key == VK_LEFT) && !ppopupmenu->fIsMenuBar) { 01417 xxxMNCloseHierarchy(ppopupmenu, pMenuState); 01418 return; 01419 } 01420 } else if (ppopupmenu->fDropNextPopup) 01421 fHierarchyWasDropped = TRUE; 01422 01423 ppopupSave = ppopupmenu; 01424 01425 item = MNFindItemInColumn(ppopupmenu->spmenu, 01426 ppopupmenu->posSelectedItem, 01427 (key == VK_LEFT ? -1 : 1), 01428 (ppopupmenu->fHasMenuBar && 01429 ppopupmenu == ppopupmenu->ppopupmenuRoot)); 01430 01431 if (item == MFMWFP_NOITEM) { 01432 01433 /* 01434 * No valid item found in the given direction so send it up to our 01435 * parent to handle. 01436 */ 01437 if (ppopupmenu->fHasMenuBar && 01438 ppopupmenu->spwndPrevPopup == ppopupmenu->spwndNotify) { 01439 01440 /* 01441 * if we turned the key round, then turn it back again. 01442 */ 01443 if (bFakedKey) 01444 key = (key == VK_LEFT) ? VK_RIGHT : VK_LEFT; 01445 /* 01446 * Go to next/prev item in menu bar since a popup was down and 01447 * no item on the popup to go to. 01448 */ 01449 xxxMNKeyDown(ppopupmenu->ppopupmenuRoot, pMenuState, key); 01450 return; 01451 } 01452 01453 if (ppopupmenu == ppopupmenu->ppopupmenuRoot) { 01454 if (!ppopupmenu->fIsMenuBar) { 01455 01456 /* 01457 * No menu bar associated with this menu so do nothing. 01458 */ 01459 return; 01460 } 01461 } else { 01462 ThreadLock(ppopupmenu->spwndPrevPopup, &tlpwndT); 01463 xxxSendMessage(ppopupmenu->spwndPrevPopup, WM_KEYDOWN, keyOrig, 0); 01464 ThreadUnlock(&tlpwndT); 01465 return; 01466 } 01467 } 01468 01469 if (!ppopupmenu->fIsMenuBar) { 01470 if (item != MFMWFP_NOITEM) { 01471 xxxMNSelectItem(ppopupmenu, pMenuState, item); 01472 } 01473 return; 01474 01475 } else { 01476 01477 /* 01478 * Special handling if keydown occurred on a menu bar. 01479 */ 01480 if (item == MFMWFP_NOITEM) { 01481 01482 if (TestWF(ppopupmenu->spwndNotify, WFSYSMENU)) { 01483 PTHREADINFO ptiCurrent = PtiCurrent(); 01484 PWND pwndNextMenu; 01485 PMENU pmenuNextMenu, pmenuUse; 01486 MDINEXTMENU mnm; 01487 TL tlpmenuNextMenu; 01488 TL tlpwndNextMenu; 01489 01490 mnm.hmenuIn = (HMENU)0; 01491 mnm.hmenuNext = (HMENU)0; 01492 mnm.hwndNext = (HWND)0; 01493 01494 /* 01495 * We are in the menu bar and need to go up to the system menu 01496 * or go from the system menu to the menu bar. 01497 */ 01498 pmenuNextMenu = ppopupmenu->fIsSysMenu ? 01499 _GetSubMenu(ppopupmenu->spmenu, 0) : 01500 ppopupmenu->spmenu; 01501 mnm.hmenuIn = PtoH(pmenuNextMenu); 01502 ThreadLock(ppopupmenu->spwndNotify, &tlpwndT); 01503 dwMDIMenu = xxxSendMessage(ppopupmenu->spwndNotify, 01504 WM_NEXTMENU, (WPARAM)keyOrig, (LPARAM)&mnm); 01505 ThreadUnlock(&tlpwndT); 01506 01507 pwndNextMenu = RevalidateHwnd(mnm.hwndNext); 01508 if (pwndNextMenu == NULL) 01509 goto TryAlternate; 01510 01511 /* 01512 * If this window belongs to another thread, we cannot 01513 * use it. The menu loop won't get any messages 01514 * directed to that thread. 01515 */ 01516 if (GETPTI(pwndNextMenu) != ptiCurrent) { 01517 RIPMSG1(RIP_WARNING, "xxxMNKeyDown: Ignoring mnm.hwndNext bacause it belongs to another thread: %#p", pwndNextMenu); 01518 goto TryAlternate; 01519 } 01520 01521 01522 pmenuNextMenu = RevalidateHmenu(mnm.hmenuNext); 01523 if (pmenuNextMenu == NULL) 01524 goto TryAlternate; 01525 01526 ThreadLock(pmenuNextMenu, &tlpmenuNextMenu); 01527 ThreadLock(pwndNextMenu, &tlpwndNextMenu); 01528 01529 /* 01530 * If the system menu is for a minimized MDI child, 01531 * make sure the menu is dropped to give the user a 01532 * visual clue that they are in menu mode 01533 */ 01534 if (TestWF(pwndNextMenu, WFMINIMIZED)) 01535 fHierarchyWasDropped = TRUE; 01536 01537 xxxMNSelectItem(ppopupmenu, pMenuState, MFMWFP_NOITEM); 01538 01539 pMenuState->fIsSysMenu = TRUE; 01540 UnlockPopupMenu(ppopupmenu, &ppopupmenu->spmenuAlternate); 01541 ppopupmenu->fToggle = FALSE; 01542 /* 01543 * GetSystemMenu(pwnd, FALSE) and pwnd->spmenuSys are 01544 * NOT equivalent -- GetSystemMenu returns the 1st submenu 01545 * of pwnd->spmenuSys -- make up for that here 01546 */ 01547 pmenuUse = (((pwndNextMenu->spmenuSys != NULL) 01548 && (_GetSubMenu(pwndNextMenu->spmenuSys, 0) == pmenuNextMenu)) 01549 ? pwndNextMenu->spmenuSys 01550 : pmenuNextMenu); 01551 /* 01552 * We're going to change the notification window AND the menu. 01553 * LockPopupMenu needs to unlock the current pmenu-spwndNotify 01554 * but also lock the new pmenu-spwndNotify. Since we cannot 01555 * give it the current AND the new pair, we unlock the 01556 * current one first, switch the notification window and 01557 * then call LockPopupMenu to lock the new pmenu-spwndNotify. 01558 */ 01559 UserAssert(IsRootPopupMenu(ppopupmenu)); 01560 UnlockPopupMenu(ppopupmenu, &ppopupmenu->spmenu); 01561 Lock(&ppopupmenu->spwndNotify, pwndNextMenu); 01562 Lock(&ppopupmenu->spwndPopupMenu, pwndNextMenu); 01563 LockPopupMenu(ppopupmenu, &ppopupmenu->spmenu, pmenuUse); 01564 /* 01565 * We just switched to a new notification window so 01566 * we need to Adjust capture accordingly 01567 */ 01568 if (!pMenuState->fModelessMenu) { 01569 ptiCurrent->pq->QF_flags &= ~QF_CAPTURELOCKED; 01570 xxxMNSetCapture(ppopupmenu); 01571 } 01572 01573 01574 if (!TestWF(pwndNextMenu, WFCHILD) && 01575 ppopupmenu->spmenu != NULL) { 01576 01577 /* 01578 * This window has a system menu and a main menu bar 01579 * Set the alternate menu to the appropriate menu 01580 */ 01581 if (pwndNextMenu->spmenu == ppopupmenu->spmenu) { 01582 LockPopupMenu(ppopupmenu, &ppopupmenu->spmenuAlternate, 01583 pwndNextMenu->spmenuSys); 01584 pMenuState->fIsSysMenu = FALSE; 01585 } else { 01586 LockPopupMenu(ppopupmenu, &ppopupmenu->spmenuAlternate, 01587 pwndNextMenu->spmenu); 01588 } 01589 } 01590 01591 ThreadUnlock(&tlpwndNextMenu); 01592 ThreadUnlock(&tlpmenuNextMenu); 01593 01594 ppopupmenu->fIsSysMenu = pMenuState->fIsSysMenu; 01595 01596 item = 0; 01597 } else 01598 TryAlternate: 01599 if (xxxMNSwitchToAlternateMenu(ppopupmenu)) { 01600 /* 01601 * go to first or last menu item int ppopup->hMenu 01602 * based on 'key' 01603 */ 01604 int dir = (key == VK_RIGHT) ? 1 : -1; 01605 01606 item = MNFindNextValidItem(ppopupmenu->spmenu, MFMWFP_NOITEM, dir, 0); 01607 } 01608 } 01609 01610 if (item != MFMWFP_NOITEM) { 01611 /* 01612 * we found a new menu item to go to 01613 * 1) close up the previous menu if it was dropped 01614 * 2) select the new menu item to go to 01615 * 3) drop the new menu if the previous menu was dropped 01616 */ 01617 01618 if (ppopupSave->spwndNextPopup) 01619 xxxMNCloseHierarchy(ppopupSave, pMenuState); 01620 01621 xxxMNSelectItem(ppopupmenu, pMenuState, item); 01622 01623 if (fHierarchyWasDropped) { 01624 DropHierarchy: 01625 if (xxxMNOpenHierarchy(ppopupmenu, pMenuState) == (PWND)-1) { 01626 return; 01627 } 01628 } 01629 } 01630 } 01631 return; 01632 01633 case VK_RETURN: 01634 { 01635 BOOL fEnabled; 01636 PITEM pItem; 01637 01638 if (ppopupmenu->posSelectedItem >= ppopupmenu->spmenu->cItems) { 01639 xxxMNDismiss(pMenuState); 01640 return; 01641 } 01642 01643 pItem = ppopupmenu->spmenu->rgItems + ppopupmenu->posSelectedItem; 01644 fEnabled = !(pItem->fState & MFS_GRAYED); 01645 if ((pItem->spSubMenu != NULL) && fEnabled) 01646 goto DropHierarchy; 01647 01648 /* 01649 * If no item is selected, throw away menu and return. 01650 */ 01651 if (fEnabled) { 01652 xxxMNDismissWithNotify(pMenuState, ppopupmenu->spmenu, pItem, ppopupmenu->posSelectedItem, 0); 01653 } else { 01654 xxxMNDismiss(pMenuState); 01655 } 01656 return; 01657 } 01658 01659 case VK_F1: /* Provide context sensitive help. */ 01660 { 01661 PITEM pItem; 01662 01663 pItem = ppopupmenu->spmenu->rgItems + ppopupmenu->posSelectedItem; 01664 ThreadLock(ppopupmenu->spwndNotify, &tlpwndT); 01665 xxxSendHelpMessage(ppopupmenu->spwndNotify, HELPINFO_MENUITEM, pItem->wID, 01666 PtoHq(ppopupmenu->spmenu), 01667 GetMenuInheritedContextHelpId(ppopupmenu)); 01668 ThreadUnlock(&tlpwndT); 01669 break; 01670 } 01671 01672 } 01673 }

void xxxMNMouseMove PPOPUPMENU  ppopup,
PMENUSTATE  pMenuState,
POINTS  ptScreen
 

Definition at line 3618 of file ntuser/kernel/menu.c.

References FALSE, tagMENUSTATE::fButtonDown, tagMENUSTATE::fInDoDragDrop, tagMENUSTATE::fModelessMenu, tagPOPUPMENU::fTrackMouseEvent, HWq, IsRootPopupMenu(), KEYBDHOLD, L, MFMWFP_ALTMENU, MFMWFP_NOITEM, MFMWFP_OFFMENU, tagMENUSTATE::mnFocus, MNSetTimerToAutoDismiss(), MOUSEHOLD, NULL, tagMENUSTATE::ptMouseLast, PtoH, tagPOPUPMENU::spwndActivePopup, tagPOPUPMENU::spwndNotify, TestWF, ThreadLock, ThreadUnlock, TrackMouseEvent(), TRUE, UINT, WFMINIMIZED, WFVISIBLE, xxxMNButtonDown(), xxxMNFindWindowFromPoint(), xxxMNHideNextHierarchy(), xxxMNSelectItem(), xxxMNSwitchToAlternateMenu(), xxxMNUpdateDraggingInfo(), and xxxSendMessage().

Referenced by xxxHandleMenuMessages(), and xxxMenuWindowProc().

03622 { 03623 LONG_PTR cmdHitArea; 03624 UINT uFlags; 03625 UINT cmdItem; 03626 PWND pwnd; 03627 TL tlpwndT; 03628 03629 03630 if (!IsRootPopupMenu(ppopup)) { 03631 RIPMSG0(RIP_ERROR, 03632 "MenuMouseMoveHandler() called for a non top most menu"); 03633 return; 03634 } 03635 03636 /* 03637 * Ignore mouse moves that aren't really moves. MSTEST jiggles 03638 * the mouse for some reason. And windows coming and going will 03639 * force mouse moves, to reset the cursor. 03640 */ 03641 if ((ptScreen.x == pMenuState->ptMouseLast.x) && (ptScreen.y == pMenuState->ptMouseLast.y)) 03642 return; 03643 03644 pMenuState->ptMouseLast.x = ptScreen.x; 03645 pMenuState->ptMouseLast.y = ptScreen.y; 03646 03647 /* 03648 * Find out where this mouse move occurred. 03649 */ 03650 cmdHitArea = xxxMNFindWindowFromPoint(ppopup, &cmdItem, ptScreen); 03651 03652 /* 03653 * If coming from an IDropTarget call out, remember the hit test 03654 */ 03655 if (pMenuState->fInDoDragDrop) { 03656 xxxMNUpdateDraggingInfo(pMenuState, cmdHitArea, cmdItem); 03657 } 03658 03659 if (pMenuState->mnFocus == KEYBDHOLD) { 03660 /* 03661 * Ignore mouse moves when in keyboard mode if the mouse isn't over any 03662 * menu at all. Also ignore mouse moves if over minimized window, 03663 * because we pretend that its entire window is like system menu. 03664 */ 03665 if ((cmdHitArea == MFMWFP_OFFMENU) || 03666 ((cmdHitArea == MFMWFP_NOITEM) && TestWF(ppopup->spwndNotify, WFMINIMIZED))) { 03667 return; 03668 } 03669 03670 pMenuState->mnFocus = MOUSEHOLD; 03671 } 03672 03673 if (cmdHitArea == MFMWFP_ALTMENU) { 03674 /* 03675 * User clicked in the other menu so switch to it ONLY IF 03676 * MOUSE IS DOWN. Usability testing proves that people frequently 03677 * get kicked into the system menu accidentally when browsing the 03678 * menu bar. We support the Win3.1 behavior when the mouse is 03679 * down however. 03680 */ 03681 if (pMenuState->fButtonDown) { 03682 xxxMNSwitchToAlternateMenu(ppopup); 03683 cmdHitArea = MFMWFP_NOITEM; 03684 } else 03685 goto OverNothing; 03686 } 03687 03688 if (cmdHitArea == MFMWFP_NOITEM) { 03689 /* 03690 * Mouse move occurred to an item in the main menu bar. If the item 03691 * is different than the one already selected, close up the current 03692 * one, select the new one and drop its menu. But if the item is the 03693 * same as the one currently selected, we need to pull up any popups 03694 * if needed and just keep the current level visible. Hey, this is 03695 * the same as a mousedown so lets do that instead. 03696 */ 03697 xxxMNButtonDown(ppopup, pMenuState, cmdItem, FALSE); 03698 return; 03699 } else if (cmdHitArea != 0) { 03700 /* This is a popup window we moved onto. */ 03701 pwnd = (PWND)(cmdHitArea); 03702 ThreadLock(pwnd, &tlpwndT); 03703 03704 UserAssert(TestWF(pwnd, WFVISIBLE)); 03705 03706 /* 03707 * Modeless menus don't capture the mouse, so track it to know 03708 * when it leaves the popup. 03709 */ 03710 ppopup = ((PMENUWND)pwnd)->ppopupmenu; 03711 if (pMenuState->fModelessMenu 03712 && !pMenuState->fInDoDragDrop 03713 && !ppopup->fTrackMouseEvent) { 03714 03715 TRACKMOUSEEVENT tme; 03716 03717 /* tme.cbSize = sizeof(TRACKMOUSEEVENT); Not checked on kernel side */ 03718 tme.dwFlags = TME_LEAVE; 03719 tme.hwndTrack = PtoH(pwnd); 03720 TrackMouseEvent(&tme); 03721 ppopup->fTrackMouseEvent = TRUE; 03722 03723 /* 03724 * We just entered this window so make sure the cursor 03725 * is properly set. 03726 */ 03727 xxxSendMessage(pwnd, WM_SETCURSOR, (WPARAM)HWq(pwnd), MAKELONG(MSGF_MENU, 0)); 03728 03729 } 03730 03731 /* 03732 * Select the item. 03733 */ 03734 uFlags = (UINT)xxxSendMessage(pwnd, MN_SELECTITEM, (WPARAM)cmdItem, 0L); 03735 if ((uFlags & MF_POPUP) && !(uFlags & MFS_GRAYED)) { 03736 /* 03737 * User moved back onto an item with a hierarchy. Hide the 03738 * the dropped popup. 03739 */ 03740 if (!xxxSendMessage(pwnd, MN_SETTIMERTOOPENHIERARCHY, 0, 0L)) { 03741 xxxMNHideNextHierarchy(ppopup); 03742 } 03743 } 03744 ThreadUnlock(&tlpwndT); 03745 } else 03746 OverNothing: 03747 { 03748 /* We moved off all menu windows... */ 03749 if (ppopup->spwndActivePopup != NULL) { 03750 pwnd = ppopup->spwndActivePopup; 03751 03752 ThreadLock(pwnd, &tlpwndT); 03753 xxxSendMessage(pwnd, MN_SELECTITEM, MFMWFP_NOITEM, 0L); 03754 MNSetTimerToAutoDismiss(pMenuState, pwnd); 03755 ThreadUnlock(&tlpwndT); 03756 } else { 03757 xxxMNSelectItem(ppopup, pMenuState, MFMWFP_NOITEM); 03758 } 03759 03760 } 03761 }

PWND xxxMNOpenHierarchy PPOPUPMENU  ppopupmenu,
PMENUSTATE  pMenuState
 

Definition at line 1934 of file ntuser/kernel/menu.c.

References _GetAsyncKeyState(), _KillTimer(), BOOL, tagMENU::cItems, ClearMF, ClrWF, CopyOffsetRect(), tagITEM::cxItem, tagITEM::cyItem, DF_MENUINUSE, tagDESKTOP::dwDTFlags, DWORD, tagPOPUPMENU::fAboutToHide, FALSE, tagPOPUPMENU::fDelayedFree, tagPOPUPMENU::fDesktopMenu, tagMENUSTATE::fDragAndDrop, tagPOPUPMENU::fDropNextPopup, tagPOPUPMENU::fDroppedLeft, tagPOPUPMENU::fHasMenuBar, tagPOPUPMENU::fHideTimer, tagPOPUPMENU::fHierarchyDropped, tagMENUSTATE::fInsideMenuLoop, tagPOPUPMENU::fIsMenuBar, tagPOPUPMENU::fIsSysMenu, tagMENUSTATE::fModelessMenu, tagPOPUPMENU::fNoNotify, tagPOPUPMENU::fRtoL, tagPOPUPMENU::fSendUninit, tagPOPUPMENU::fShowTimer, tagMENUSTATE::fUnderline, FWINABLE, HANDLEF_DESTROY, tagWND::head, HMChangeOwnerThread(), hModuleWin, HMPheFromObject, HW, tagPOPUPMENU::iDropDir, IDSYS_MNSHOW, IntersectRect(), KEYBDHOLD, L, Lock, LockPopupMenu(), LPVOID, MENUCLASS, MFMWFP_NOITEM, MFUNDERLINE, tagMENUSTATE::mnFocus, MNSW_SIZE, NT_SUCCESS, NULL, PAS_LEFT, PAS_OUT, PAS_RIGHT, tagDESKTOP::pDeskInfo, PlayEventSound(), tagTHREADINFO::pMenuState, tagPOPUPMENU::posDropped, tagPOPUPMENU::posSelectedItem, tagTHREADINFO::ppi, tagPOPUPMENU::ppmDelayedFree, tagPOPUPMENU::ppopupmenuRoot, tagWINDOWSTATION::pTerm, PtiCurrent, tagTERMINAL::ptiDesktop, PtoHq, PWND_TOP, PWND_TOPMOST, tagMONITOR::rcMonitor, tagWND::rcWindow, tagMENU::rgItems, tagTHREADINFO::rpdesk, tagDESKTOP::rpwinstaParent, SetMF, SetWF, tagPOPUPMENU::spmenu, tagPOPUPMENU::spmenuAlternate, tagITEM::spSubMenu, tagDESKTOPINFO::spwnd, tagPOPUPMENU::spwndActivePopup, tagDESKTOP::spwndMenu, tagPOPUPMENU::spwndNextPopup, tagPOPUPMENU::spwndNotify, tagWND::spwndOwner, tagPOPUPMENU::spwndPopupMenu, tagPOPUPMENU::spwndPrevPopup, SYSMET, TestMFS, TestMFT, TestWF, ThreadLock, ThreadLockAlways, ThreadUnlock, TIF_DISABLEHOOKS, tagTHREADINFO::TIF_flags, TRUE, Unlock, USER_SOUND_MENUPOPUP, WEFTOPMOST, WFOLDUI, WFVISIBLE, tagITEM::xItem, xxxCleanupDesktopMenu(), xxxClientRegisterDragDrop(), xxxCreateWindowEx(), xxxDestroyWindow(), xxxMNCloseHierarchy(), xxxMNDestroyHandler(), xxxMNPositionHierarchy(), xxxSendMessage(), xxxSetParent(), xxxSetWindowPos(), xxxUpdateWindow(), xxxWindowEvent(), and tagITEM::yItem.

Referenced by xxxMenuWindowProc(), xxxMNButtonDown(), xxxMNButtonUp(), xxxMNKeyDown(), and xxxMNKeyFilter().

01936 { 01937 PWND ret = 0; 01938 PITEM pItem; 01939 PWND pwndHierarchy; 01940 PPOPUPMENU ppopupmenuHierarchy; 01941 LONG sizeHierarchy; 01942 int xLeft; 01943 int yTop; 01944 int cxPopup, cyPopup; 01945 TL tlpwndT; 01946 TL tlpwndHierarchy; 01947 PTHREADINFO ptiCurrent = PtiCurrent(); 01948 PDESKTOP pdesk = ptiCurrent->rpdesk; 01949 BOOL fSendUninit = FALSE; 01950 HMENU hmenuInit; 01951 PMONITOR pMonitor; 01952 01953 01954 if (ppopupmenu->posSelectedItem == MFMWFP_NOITEM) { 01955 /* 01956 * No selection so fail. 01957 */ 01958 return NULL; 01959 } 01960 01961 if (ppopupmenu->posSelectedItem >= ppopupmenu->spmenu->cItems) 01962 return NULL; 01963 01964 if (ppopupmenu->fHierarchyDropped) { 01965 if (ppopupmenu->fHideTimer) { 01966 xxxMNCloseHierarchy(ppopupmenu,pMenuState); 01967 } else { 01968 /* 01969 * Hierarchy already dropped. What are we doing here? 01970 */ 01971 UserAssert(!ppopupmenu->fHierarchyDropped); 01972 return NULL; 01973 } 01974 } 01975 01976 if (ppopupmenu->fShowTimer) { 01977 _KillTimer(ppopupmenu->spwndPopupMenu, IDSYS_MNSHOW); 01978 ppopupmenu->fShowTimer = FALSE; 01979 } 01980 01981 /* 01982 * Get a pointer to the currently selected item in this menu. 01983 */ 01984 pItem = &(ppopupmenu->spmenu->rgItems[ppopupmenu->posSelectedItem]); 01985 01986 if (pItem->spSubMenu == NULL) 01987 goto Exit; 01988 01989 /* 01990 * Send the initmenupopup message. 01991 */ 01992 if (!ppopupmenu->fNoNotify) { 01993 ThreadLock(ppopupmenu->spwndNotify, &tlpwndT); 01994 /* 01995 * WordPerfect's Grammatik app doesn't know that TRUE means NON-ZERO, 01996 * not 1. So we must use 0 & 1 explicitly for fIsSysMenu here 01997 * -- Win95B B#4947 -- 2/13/95 -- jeffbog 01998 */ 01999 hmenuInit = PtoHq(pItem->spSubMenu); 02000 xxxSendMessage(ppopupmenu->spwndNotify, WM_INITMENUPOPUP, 02001 (WPARAM)hmenuInit, MAKELONG(ppopupmenu->posSelectedItem, 02002 (ppopupmenu->fIsSysMenu ? 1: 0))); 02003 ThreadUnlock(&tlpwndT); 02004 fSendUninit = TRUE; 02005 } 02006 02007 02008 /* 02009 * B#1517 02010 * Check if we're still in menu loop 02011 */ 02012 if (!pMenuState->fInsideMenuLoop) { 02013 RIPMSG0(RIP_WARNING, "Menu loop ended unexpectedly by WM_INITMENUPOPUP"); 02014 ret = (PWND)-1; 02015 goto Exit; 02016 } 02017 02018 /* 02019 * The WM_INITMENUPOPUP message may have resulted in a change to the 02020 * menu. Make sure the selection is still valid. 02021 */ 02022 if (ppopupmenu->posSelectedItem >= ppopupmenu->spmenu->cItems) { 02023 /* 02024 * Selection is out of range, so fail. 02025 */ 02026 goto Exit; 02027 } 02028 02029 /* 02030 * Get a pointer to the currently selected item in this menu. 02031 * Bug #17867 - the call can cause this thing to change, so reload it. 02032 */ 02033 pItem = &(ppopupmenu->spmenu->rgItems[ppopupmenu->posSelectedItem]); 02034 02035 if (TestMFS(pItem, MFS_GRAYED) || (pItem->spSubMenu == NULL) || (pItem->spSubMenu->cItems == 0)) { 02036 /* 02037 * The item is disabled, no longer a popup, or empty so don't drop. 02038 */ 02039 /* 02040 * No items in menu. 02041 */ 02042 goto Exit; 02043 } 02044 02045 /* 02046 * Let's make sure that the current thread is in menu mode and 02047 * it uses this pMenuState. Otherwise the window we're about to 02048 * create (or set the thread to) will point to a different pMenuState 02049 */ 02050 UserAssert(ptiCurrent->pMenuState == pMenuState); 02051 02052 if (ppopupmenu->fIsMenuBar && (pdesk->spwndMenu != NULL) && 02053 (!(pdesk->dwDTFlags & DF_MENUINUSE)) && 02054 !TestWF(pdesk->spwndMenu, WFVISIBLE)) { 02055 02056 pdesk->dwDTFlags |= DF_MENUINUSE; 02057 02058 if (HMPheFromObject(pdesk->spwndMenu)->bFlags & HANDLEF_DESTROY) { 02059 PPROCESSINFO ppi = pdesk->rpwinstaParent->pTerm->ptiDesktop->ppi; 02060 PPROCESSINFO ppiSave; 02061 PWND pwndMenu; 02062 DWORD dwDisableHooks; 02063 02064 /* 02065 * the menu window is destroyed -- recreate it 02066 * 02067 * clear the desktopMenu flag so that the popup is 02068 * freed. 02069 */ 02070 UserAssert(ppopupmenu->fDesktopMenu); 02071 02072 ppopupmenu->fDesktopMenu = FALSE; 02073 ppopupmenu->fDelayedFree = FALSE; 02074 02075 Unlock(&pdesk->spwndMenu); 02076 ppiSave = ptiCurrent->ppi; 02077 ptiCurrent->ppi = ppi; 02078 02079 /* 02080 * HACK HACK HACK!!! (adams) In order to create the menu window 02081 * with the correct desktop, we set the desktop of the current thread 02082 * to the new desktop. But in so doing we allow hooks on the current 02083 * thread to also hook this new desktop. This is bad, because we don't 02084 * want the menu window to be hooked while it is created. So we 02085 * temporarily disable hooks of the current thread or desktop, 02086 * and reenable them after switching back to the original desktop. 02087 */ 02088 02089 dwDisableHooks = ptiCurrent->TIF_flags & TIF_DISABLEHOOKS; 02090 ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS; 02091 02092 pwndMenu = xxxCreateWindowEx( 02093 WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE, 02094 (PLARGE_STRING)MENUCLASS, 02095 NULL, 02096 WS_POPUP | WS_BORDER, 02097 0, 02098 0, 02099 100, 02100 100, 02101 NULL, 02102 NULL, 02103 hModuleWin, 02104 NULL, 02105 WINVER); 02106 02107 UserAssert(ptiCurrent->TIF_flags & TIF_DISABLEHOOKS); 02108 ptiCurrent->TIF_flags = (ptiCurrent->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks; 02109 02110 Lock(&(pdesk->spwndMenu), pwndMenu); 02111 02112 UserAssert(((PMENUWND)pwndMenu)->ppopupmenu != NULL); 02113 02114 /* 02115 * Set the desktopMenu flag to mark that this is the popup 02116 * allocated for pdesk->spwndMenu 02117 * Unlock spwndPopupMenu to avoid this special case in the common code path. 02118 */ 02119 ((PMENUWND)pwndMenu)->ppopupmenu->fDesktopMenu = TRUE; 02120 Unlock(&((PMENUWND)pwndMenu)->ppopupmenu->spwndPopupMenu); 02121 02122 ptiCurrent->ppi = ppiSave; 02123 02124 HMChangeOwnerThread(pdesk->spwndMenu, pdesk->rpwinstaParent->pTerm->ptiDesktop); 02125 } else { 02126 TL tlpwndDesk; 02127 02128 ThreadLockAlways(pdesk->spwndMenu, &tlpwndT); 02129 ThreadLockAlways(pdesk->pDeskInfo->spwnd, &tlpwndDesk); 02130 xxxSetParent(pdesk->spwndMenu, pdesk->pDeskInfo->spwnd); 02131 ThreadUnlock(&tlpwndDesk); 02132 ThreadUnlock(&tlpwndT); 02133 02134 } 02135 02136 02137 pwndHierarchy = pdesk->spwndMenu; 02138 Lock(&pwndHierarchy->spwndOwner, ppopupmenu->spwndNotify); 02139 pwndHierarchy->head.pti = ptiCurrent; 02140 02141 /* 02142 * Make the topmost state match the menu mode 02143 */ 02144 if ((TestWF(pdesk->spwndMenu, WEFTOPMOST) && pMenuState->fModelessMenu) 02145 || (!TestWF(pdesk->spwndMenu, WEFTOPMOST) && !pMenuState->fModelessMenu)) { 02146 02147 ThreadLock(pdesk->spwndMenu, &tlpwndHierarchy); 02148 xxxSetWindowPos(pdesk->spwndMenu, 02149 (pMenuState->fModelessMenu ? PWND_NOTOPMOST: PWND_TOPMOST), 02150 0,0,0,0, 02151 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING); 02152 ThreadUnlock(&tlpwndHierarchy); 02153 } 02154 02155 ppopupmenuHierarchy = ((PMENUWND)pwndHierarchy)->ppopupmenu; 02156 02157 UserAssert(ppopupmenuHierarchy->fDesktopMenu); 02158 /* 02159 * clear any leftover data from the last time we used it 02160 * Assert that we're not zapping any locks here 02161 */ 02162 UserAssert(ppopupmenuHierarchy->spwndPopupMenu == NULL); 02163 UserAssert(ppopupmenuHierarchy->spwndNextPopup == NULL); 02164 UserAssert(ppopupmenuHierarchy->spwndPrevPopup == NULL); 02165 UserAssert(ppopupmenuHierarchy->spmenu == NULL); 02166 UserAssert(ppopupmenuHierarchy->spmenuAlternate == NULL); 02167 UserAssert(ppopupmenuHierarchy->spwndNotify == NULL); 02168 UserAssert(ppopupmenuHierarchy->spwndActivePopup == NULL); 02169 02170 RtlZeroMemory((PVOID)ppopupmenuHierarchy, sizeof(POPUPMENU)); 02171 ppopupmenuHierarchy->fDesktopMenu = TRUE; 02172 02173 ppopupmenuHierarchy->posSelectedItem = MFMWFP_NOITEM; 02174 Lock(&ppopupmenuHierarchy->spwndPopupMenu, pdesk->spwndMenu); 02175 02176 Lock(&(ppopupmenuHierarchy->spwndNotify), ppopupmenu->spwndNotify); 02177 LockPopupMenu(ppopupmenuHierarchy, &ppopupmenuHierarchy->spmenu, pItem->spSubMenu); 02178 02179 } else { 02180 02181 ThreadLock(ppopupmenu->spwndNotify, &tlpwndT); 02182 02183 pwndHierarchy = xxxCreateWindowEx( 02184 WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE, 02185 (PLARGE_STRING)MENUCLASS, NULL, 02186 WS_POPUP | WS_BORDER, 0, 0, 100, 100, ppopupmenu->spwndNotify, 02187 NULL, (HANDLE)ppopupmenu->spwndNotify->hModule, 02188 (LPVOID)pItem->spSubMenu, WINVER); 02189 02190 ThreadUnlock(&tlpwndT); 02191 02192 if (!pwndHierarchy) 02193 goto Exit; 02194 02195 /* 02196 * Do this so old apps don't get weird borders on the popups of 02197 * hierarchical items! 02198 */ 02199 ClrWF(pwndHierarchy, WFOLDUI); 02200 02201 ppopupmenuHierarchy = ((PMENUWND)pwndHierarchy)->ppopupmenu; 02202 02203 } 02204 02205 /* 02206 * Mark this as fDelayedFree and link it 02207 */ 02208 ppopupmenuHierarchy->fDelayedFree = TRUE; 02209 ppopupmenuHierarchy->ppmDelayedFree = ppopupmenu->ppopupmenuRoot->ppmDelayedFree; 02210 ppopupmenu->ppopupmenuRoot->ppmDelayedFree = ppopupmenuHierarchy; 02211 02212 #ifdef USE_MIRRORING 02213 if (TestWF(ppopupmenu->spwndPopupMenu, WEFLAYOUTRTL)) { 02214 SetWF(pwndHierarchy, WEFLAYOUTRTL); 02215 } else { 02216 ClrWF(pwndHierarchy, WEFLAYOUTRTL); 02217 } 02218 #endif 02219 02220 02221 Lock(&(ppopupmenuHierarchy->spwndNotify), ppopupmenu->spwndNotify); 02222 #if DBG 02223 /* 02224 * We should associate ppopupmenuHierarchy to the same menu we sent the 02225 * WM_INITMsENUPOPUP message. Otherwise, the WM_UNINITMENUPOPUP 02226 * will go to the wrong window. It would be the app's fault... 02227 */ 02228 if (!ppopupmenu->fNoNotify && (hmenuInit != PtoHq(pItem->spSubMenu))) { 02229 RIPMSG2(RIP_WARNING, "xxxMNOpenHierarchy: bad app changed submenu from %#p to %#p", 02230 hmenuInit, PtoHq(pItem->spSubMenu)); 02231 } 02232 #endif 02233 LockPopupMenu(ppopupmenuHierarchy, &ppopupmenuHierarchy->spmenu, pItem->spSubMenu); 02234 Lock(&(ppopupmenu->spwndNextPopup), pwndHierarchy); 02235 ppopupmenu->posDropped = ppopupmenu->posSelectedItem; 02236 Lock(&(ppopupmenuHierarchy->spwndPrevPopup), ppopupmenu->spwndPopupMenu); 02237 ppopupmenuHierarchy->ppopupmenuRoot = ppopupmenu->ppopupmenuRoot; 02238 ppopupmenuHierarchy->fHasMenuBar = ppopupmenu->fHasMenuBar; 02239 ppopupmenuHierarchy->fIsSysMenu = ppopupmenu->fIsSysMenu; 02240 ppopupmenuHierarchy->fNoNotify = ppopupmenu->fNoNotify; 02241 ppopupmenuHierarchy->fSendUninit = TRUE; 02242 ppopupmenuHierarchy->fRtoL = ppopupmenu->fRtoL; 02243 02244 /* 02245 * The menu window has been created and intialized so if 02246 * something fails, the WM_UNINITMENUPOPUP message will 02247 * be sent from xxxMNDestroyHandler 02248 */ 02249 fSendUninit = FALSE; 02250 02251 /* 02252 * Set/clear the underline flag 02253 */ 02254 if (pMenuState->fUnderline) { 02255 SetMF(ppopupmenuHierarchy->spmenu, MFUNDERLINE); 02256 } else { 02257 ClearMF(ppopupmenuHierarchy->spmenu, MFUNDERLINE); 02258 } 02259 02260 ppopupmenuHierarchy->fAboutToHide = FALSE; 02261 02262 /* 02263 * Find the size of the menu window and actually size it (wParam = 1) 02264 */ 02265 ThreadLock(pwndHierarchy, &tlpwndHierarchy); 02266 sizeHierarchy = (LONG)xxxSendMessage(pwndHierarchy, MN_SIZEWINDOW, MNSW_SIZE, 0); 02267 02268 if (!sizeHierarchy) { 02269 /* 02270 * No size for this menu so zero it and blow off. 02271 */ 02272 UserAssert(ppopupmenuHierarchy->fDelayedFree); 02273 if (ppopupmenuHierarchy->fDesktopMenu) { 02274 xxxMNDestroyHandler(ppopupmenuHierarchy); 02275 xxxCleanupDesktopMenu(pwndHierarchy, pdesk); 02276 } 02277 02278 if (ThreadUnlock(&tlpwndHierarchy)) { 02279 if (!ppopupmenuHierarchy->fDesktopMenu) { 02280 xxxDestroyWindow(pwndHierarchy); 02281 } 02282 } 02283 02284 Unlock(&ppopupmenu->spwndNextPopup); 02285 goto Exit; 02286 } 02287 02288 cxPopup = LOWORD(sizeHierarchy) + 2*SYSMET(CXFIXEDFRAME); 02289 cyPopup = HIWORD(sizeHierarchy) + 2*SYSMET(CYFIXEDFRAME); 02290 02291 ppopupmenu->fHierarchyDropped = TRUE; 02292 02293 /* 02294 * Find out the x,y position to drop the hierarchy and the animation 02295 * direction 02296 */ 02297 ppopupmenuHierarchy->iDropDir = xxxMNPositionHierarchy( 02298 ppopupmenu, pItem, cxPopup, cyPopup, &xLeft, &yTop, &pMonitor); 02299 02300 if (ppopupmenu->fIsMenuBar && _GetAsyncKeyState(VK_LBUTTON) & 0x8000) { 02301 /* 02302 * If the menu had to be pinned to the bottom of the screen and 02303 * the mouse button is down, make sure the mouse isn't over the 02304 * menu rect. 02305 */ 02306 RECT rc; 02307 RECT rcParent; 02308 int xrightdrop; 02309 int xleftdrop; 02310 02311 /* 02312 * Get rect of hierarchical 02313 */ 02314 CopyOffsetRect( 02315 &rc, 02316 &pwndHierarchy->rcWindow, 02317 xLeft - pwndHierarchy->rcWindow.left, 02318 yTop - pwndHierarchy->rcWindow.top); 02319 02320 /* 02321 * Get the rect of the menu bar popup item 02322 */ 02323 rcParent.left = pItem->xItem + ppopupmenu->spwndPopupMenu->rcWindow.left; 02324 rcParent.top = pItem->yItem + ppopupmenu->spwndPopupMenu->rcWindow.top; 02325 rcParent.right = rcParent.left + pItem->cxItem; 02326 rcParent.bottom = rcParent.top + pItem->cyItem; 02327 02328 if (IntersectRect(&rc, &rc, &rcParent)) { 02329 02330 /* 02331 * Oh, oh... The cursor will sit right on top of a menu item. 02332 * If the user up clicks, a menu will be accidently selected. 02333 * 02334 * Calc x position of hierarchical if we dropped it to the 02335 * right/left of the menu bar item. 02336 */ 02337 xrightdrop = ppopupmenu->spwndPopupMenu->rcWindow.left + 02338 pItem->xItem + pItem->cxItem + cxPopup; 02339 02340 if (xrightdrop > pMonitor->rcMonitor.right) { 02341 xrightdrop = 0; 02342 } 02343 02344 xleftdrop = ppopupmenu->spwndPopupMenu->rcWindow.left + 02345 pItem->xItem - cxPopup; 02346 02347 if (xleftdrop < pMonitor->rcMonitor.left) { 02348 xleftdrop = 0; 02349 } 02350 02351 if (((SYSMET(MENUDROPALIGNMENT) || TestMFT(pItem, MFT_RIGHTORDER)) 02352 && xleftdrop) || !xrightdrop) { 02353 xLeft = ppopupmenu->spwndPopupMenu->rcWindow.left + 02354 pItem->xItem - cxPopup; 02355 ppopupmenuHierarchy->iDropDir = PAS_LEFT; 02356 } else if (xrightdrop) { 02357 xLeft = ppopupmenu->spwndPopupMenu->rcWindow.left + 02358 pItem->xItem + pItem->cxItem; 02359 ppopupmenuHierarchy->iDropDir = PAS_RIGHT; 02360 } 02361 } 02362 } 02363 02364 /* 02365 * Take care of fDropNextPopup (menu bar) or fDroppedLeft (popups) 02366 * Set animation flag 02367 */ 02368 if (ppopupmenu->fIsMenuBar) { 02369 /* 02370 * Only the first popup being dropped off the menu bar 02371 * is animated. 02372 */ 02373 if (!ppopupmenu->fDropNextPopup) { 02374 ppopupmenuHierarchy->iDropDir |= PAS_OUT; 02375 } 02376 02377 /* 02378 * Propagate right-to-left direction. 02379 */ 02380 if (ppopupmenu->fDroppedLeft || (ppopupmenuHierarchy->iDropDir == PAS_LEFT)) { 02381 ppopupmenuHierarchy->fDroppedLeft = TRUE; 02382 } 02383 /* 02384 * Once a popup is dropped from the menu bar, moving to the next 02385 * item on the menu bar should drop the popup. 02386 */ 02387 ppopupmenu->fDropNextPopup = TRUE; 02388 } else { 02389 /* 02390 * Submenus always animate. 02391 */ 02392 ppopupmenuHierarchy->iDropDir |= PAS_OUT; 02393 02394 /* 02395 * Is this popup a lefty? 02396 */ 02397 if (ppopupmenuHierarchy->iDropDir == PAS_LEFT) { 02398 ppopupmenuHierarchy->fDroppedLeft = TRUE; 02399 } 02400 } 02401 02402 /* 02403 * The previous active dude must be visible 02404 */ 02405 UserAssert((ppopupmenu->ppopupmenuRoot->spwndActivePopup == NULL) 02406 || TestWF(ppopupmenu->ppopupmenuRoot->spwndActivePopup, WFVISIBLE)); 02407 02408 /* 02409 * This is the new active popup 02410 */ 02411 Lock(&(ppopupmenu->ppopupmenuRoot->spwndActivePopup), pwndHierarchy); 02412 02413 /* 02414 * Paint the owner window before the popup menu comes up so that 02415 * the proper bits are saved. 02416 */ 02417 if (ppopupmenuHierarchy->spwndNotify != NULL) { 02418 ThreadLockAlways(ppopupmenuHierarchy->spwndNotify, &tlpwndT); 02419 xxxUpdateWindow(ppopupmenuHierarchy->spwndNotify); 02420 ThreadUnlock(&tlpwndT); 02421 } 02422 02423 /* 02424 * If this is a drag and drop menu, then we need to register the window 02425 * as a drop target. 02426 */ 02427 if (pMenuState->fDragAndDrop) { 02428 if (!NT_SUCCESS(xxxClientRegisterDragDrop(HW(pwndHierarchy)))) { 02429 RIPMSG1(RIP_ERROR, "xxxMNOpenHierarchy: xxxClientRegisterDragDrop failed:%#p", pwndHierarchy); 02430 } 02431 } 02432 02433 /* 02434 * Show the window. Modeless menus are not topmost and get activated. 02435 * Modal menus are topmost but don't get activated. 02436 */ 02437 PlayEventSound(USER_SOUND_MENUPOPUP); 02438 02439 xxxSetWindowPos(pwndHierarchy, 02440 (pMenuState->fModelessMenu ? PWND_TOP : PWND_TOPMOST), 02441 xLeft, yTop, 0, 0, 02442 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOOWNERZORDER 02443 | (pMenuState->fModelessMenu ? 0 : SWP_NOACTIVATE)); 02444 02445 if (FWINABLE()) { 02446 xxxWindowEvent(EVENT_SYSTEM_MENUPOPUPSTART, pwndHierarchy, OBJID_CLIENT, INDEXID_CONTAINER, 0); 02447 } 02448 02449 /* 02450 * Select the first item IFF we're in keyboard mode. This fixes a 02451 * surprising number of compatibility problems with keyboard macros, 02452 * scripts, etc. 02453 */ 02454 if (pMenuState->mnFocus == KEYBDHOLD) { 02455 xxxSendMessage(pwndHierarchy, MN_SELECTITEM, 0, 0L); 02456 } 02457 02458 /* 02459 * This is needed so that popup menus are properly drawn on sys 02460 * modal dialog boxes. 02461 */ 02462 xxxUpdateWindow(pwndHierarchy); 02463 02464 ret = pwndHierarchy; 02465 ThreadUnlock(&tlpwndHierarchy); 02466 02467 Exit: 02468 /* 02469 * send matching WM_UNINITMENUPOPUP if needed (i.e, something 02470 * failed). 02471 */ 02472 if (fSendUninit 02473 && (ppopupmenu->spwndNotify != NULL)) { 02474 02475 ThreadLockAlways(ppopupmenu->spwndNotify, &tlpwndT); 02476 xxxSendMessage(ppopupmenu->spwndNotify, WM_UNINITMENUPOPUP, 02477 (WPARAM)hmenuInit, 02478 MAKELONG(0, (ppopupmenu->fIsSysMenu ? MF_SYSMENU : 0))); 02479 ThreadUnlock(&tlpwndT); 02480 } 02481 02482 return ret; 02483 }

UINT xxxMNPositionHierarchy PPOPUPMENU  ppopup,
PITEM  pitem,
int  cx,
int  cy,
int *  px,
int *  py,
PMONITOR ppMonitor
 

Definition at line 1683 of file ntuser/kernel/menu.c.

References _MonitorFromRect(), _MonitorFromWindow(), BOOL, CopyRect, tagITEM::cxItem, cy, tagITEM::cyItem, tagMENU::dwArrowsOn, tagPOPUPMENU::fDroppedLeft, tagPOPUPMENU::fHierarchyDropped, tagPOPUPMENU::fIsMenuBar, gcyMenuScrollArrow, IsTrayWindow(), max, MFRTL, min, MNGetToppItem(), MSA_OFF, NULL, PAS_DOWN, PAS_HORZ, PAS_LEFT, PAS_RIGHT, PAS_UP, tagMONITOR::rcMonitor, tagWND::rcWindow, tagPOPUPMENU::spmenu, tagPOPUPMENU::spwndNextPopup, tagPOPUPMENU::spwndPopupMenu, SYSMET, TestMF, TestWF, TRUE, UINT, WFMINIMIZED, tagITEM::xItem, xxxSendMinRectMessages(), and tagITEM::yItem.

Referenced by xxxMenuWindowProc(), and xxxMNOpenHierarchy().

01691 { 01692 int x, y; 01693 UINT uPAS; 01694 PMONITOR pMonitor; 01695 01696 UserAssert(ppopup->fHierarchyDropped && (ppopup->spwndNextPopup != NULL)); 01697 01698 if (ppopup->fIsMenuBar) { 01699 /* 01700 * This is a menu being dropped from the top menu bar. We need to 01701 * position it differently than hierarchicals which are dropped from 01702 * another popup. 01703 */ 01704 01705 BOOL fIconic = (TestWF(ppopup->spwndPopupMenu, WFMINIMIZED) != 0); 01706 RECT rcWindow; 01707 01708 /* 01709 * Menu bar popups animate down. 01710 */ 01711 uPAS = PAS_DOWN; 01712 01713 CopyRect(&rcWindow, &ppopup->spwndPopupMenu->rcWindow); 01714 if (fIconic && IsTrayWindow(ppopup->spwndPopupMenu)) { 01715 xxxSendMinRectMessages(ppopup->spwndPopupMenu, &rcWindow); 01716 } 01717 01718 /* 01719 * x position 01720 */ 01721 if (!SYSMET(MENUDROPALIGNMENT) && !TestMF(ppopup->spmenu,MFRTL)) { 01722 if (fIconic) { 01723 x = rcWindow.left; 01724 } else { 01725 x = rcWindow.left + pitem->xItem; 01726 } 01727 } else { 01728 ppopup->fDroppedLeft = TRUE; 01729 if (fIconic) { 01730 x = rcWindow.right - cx; 01731 } else { 01732 x = rcWindow.left + pitem->xItem + pitem->cxItem - cx; 01733 } 01734 } 01735 01736 /* 01737 * For a menu bar dropdown, pin to the monitor that owns the 01738 * majority of the menu item. Otherwise, pin to the monitor that 01739 * owns the minimized window (the tray rect for min-to-tray dudes). 01740 */ 01741 if (!fIconic) 01742 { 01743 /* 01744 * Use rcWindow as scratch for the menu bar item rect. We want 01745 * to pin this menu on whatever monitor owns most of the menu 01746 * item clicked on. 01747 */ 01748 rcWindow.left += pitem->xItem; 01749 rcWindow.top += pitem->yItem; 01750 rcWindow.right = rcWindow.left + pitem->cxItem; 01751 rcWindow.bottom = rcWindow.top + pitem->cyItem; 01752 } 01753 01754 pMonitor = _MonitorFromRect(&rcWindow, MONITOR_DEFAULTTOPRIMARY); 01755 01756 /* 01757 * y position 01758 */ 01759 if (!fIconic) { 01760 y = rcWindow.bottom; 01761 } else { 01762 /* 01763 * If the window is iconic, pop the menu up. Since we're 01764 * minimized, the sysmenu button doesn't really exist. 01765 */ 01766 y = rcWindow.top - cy; 01767 if (y < pMonitor->rcMonitor.top) { 01768 y = rcWindow.bottom; 01769 } 01770 } 01771 01772 /* 01773 * Make sure the menu doesn't go off right side of monitor 01774 */ 01775 x = min(x, pMonitor->rcMonitor.right - cx); 01776 01777 #ifdef USE_MIRRORING 01778 if (TestWF(ppopup->spwndPopupMenu, WEFLAYOUTRTL)) { 01779 x = ppopup->spwndPopupMenu->rcWindow.right - x + ppopup->spwndPopupMenu->rcWindow.left - cx; 01780 } 01781 #endif 01782 01783 } else { /* if (ppopup->fIsMenuBar) */ 01784 01785 /* Now position the hierarchical menu window. 01786 * We want to overlap by the amount of the frame, to help in the 01787 * 3D illusion. 01788 */ 01789 01790 /* 01791 * By default, hierachical popups animate to the right 01792 */ 01793 uPAS = PAS_RIGHT; 01794 x = ppopup->spwndPopupMenu->rcWindow.left + pitem->xItem + pitem->cxItem; 01795 01796 /* Note that we DO want the selections in the item and its popup to 01797 * align horizontally. 01798 */ 01799 y = ppopup->spwndPopupMenu->rcWindow.top + pitem->yItem; 01800 if (ppopup->spmenu->dwArrowsOn != MSA_OFF) { 01801 y += gcyMenuScrollArrow - MNGetToppItem(ppopup->spmenu)->yItem; 01802 } 01803 01804 /* 01805 * Try to make sure the menu doesn't go off right side of the 01806 * monitor. If it does, drop it left, overlapping the checkmark 01807 * area. Unless it would cover the previous menu... 01808 * 01809 * Use the monitor that the parent menu is on to keep all hierarchicals 01810 * in the same place. 01811 */ 01812 pMonitor = _MonitorFromWindow( 01813 ppopup->spwndPopupMenu, MONITOR_DEFAULTTOPRIMARY); 01814 01815 #ifdef USE_MIRRORING 01816 if ((!!ppopup->fDroppedLeft) ^ (!!TestWF(ppopup->spwndPopupMenu, WEFLAYOUTRTL))) { 01817 #else 01818 if (ppopup->fDroppedLeft) { 01819 #endif 01820 int xTmp; 01821 01822 /* 01823 * If this menu has dropped left, see if our hierarchy can be made 01824 * to drop to the left also. 01825 */ 01826 xTmp = ppopup->spwndPopupMenu->rcWindow.left + SYSMET(CXFIXEDFRAME) - cx; 01827 if (xTmp >= pMonitor->rcMonitor.left) { 01828 x = xTmp; 01829 uPAS = PAS_LEFT; 01830 } 01831 } 01832 01833 /* 01834 * Make sure the menu doesn't go off right side of screen. Make it drop 01835 * left if it does. 01836 */ 01837 if (x + cx > pMonitor->rcMonitor.right) { 01838 x = ppopup->spwndPopupMenu->rcWindow.left + SYSMET(CXFIXEDFRAME) - cx; 01839 uPAS = PAS_LEFT; 01840 } 01841 #ifdef USE_MIRRORING 01842 if (TestWF(ppopup->spwndPopupMenu, WEFLAYOUTRTL)) { 01843 uPAS ^= PAS_HORZ; 01844 } 01845 #endif 01846 01847 } /* else if (ppopup->fIsMenuBar) */ 01848 01849 /* 01850 * Does the menu extend beyond bottom of monitor? 01851 */ 01852 UserAssert(pMonitor); 01853 if (y + cy > pMonitor->rcMonitor.bottom) { 01854 y -= cy; 01855 01856 /* 01857 * Try to pop above menu bar first 01858 */ 01859 if (ppopup->fIsMenuBar) { 01860 y -= SYSMET(CYMENUSIZE); 01861 if (y >= pMonitor->rcMonitor.top) { 01862 uPAS = PAS_UP; 01863 } 01864 } else { 01865 /* 01866 * Account for nonclient frame above & below 01867 */ 01868 y += pitem->cyItem + 2*SYSMET(CYFIXEDFRAME); 01869 } 01870 01871 /* 01872 * Make sure that starting point is on a monitor, and all of menu shows. 01873 */ 01874 if ( (y < pMonitor->rcMonitor.top) || 01875 (y + cy > pMonitor->rcMonitor.bottom)) 01876 /* 01877 * Pin it to the bottom. 01878 */ 01879 y = pMonitor->rcMonitor.bottom - cy; 01880 } 01881 01882 /* 01883 * Make sure Upper Left corner of menu is always visible. 01884 */ 01885 x = max(x, pMonitor->rcMonitor.left); 01886 y = max(y, pMonitor->rcMonitor.top); 01887 01888 /* 01889 * Propagate position 01890 */ 01891 *px = x; 01892 *py = y; 01893 *ppMonitor = pMonitor; 01894 01895 /* 01896 * Return animation direction 01897 */ 01898 return uPAS; 01899 }

void xxxMNReleaseCapture void   ) 
 

Definition at line 181 of file ntuser/kernel/menu.c.

References FALSE, tagMENUSTATE::fSetCapture, NULL, tagTHREADINFO::pMenuState, PtiCurrent, QF_CAPTURELOCKED, and xxxReleaseCapture().

Referenced by xxxEndMenu(), xxxMNCancel(), xxxMNLoop(), xxxMNStartMenu(), and xxxTrackPopupMenuEx().

00182 { 00183 PTHREADINFO ptiCurrent = PtiCurrent(); 00184 00185 /* 00186 * Bail if we didn't set capture 00187 */ 00188 if ((ptiCurrent->pMenuState == NULL) || 00189 (! ptiCurrent->pMenuState->fSetCapture)) { 00190 return; 00191 } 00192 ptiCurrent->pMenuState->fSetCapture = FALSE; 00193 00194 /* 00195 * Unlock capture and release it. 00196 */ 00197 PtiCurrent()->pq->QF_flags &= ~QF_CAPTURELOCKED; 00198 xxxReleaseCapture(); 00199 }

PITEM xxxMNSelectItem PPOPUPMENU  ppopupmenu,
PMENUSTATE  pMenuState,
UINT  itemPos
 

Definition at line 2818 of file ntuser/kernel/menu.c.

References _KillTimer(), tagMENU::cItems, tagMENUSTATE::fAboutToAutoDismiss, tagPOPUPMENU::fAboutToHide, FALSE, tagMENUSTATE::fButtonDown, tagPOPUPMENU::fHasMenuBar, tagPOPUPMENU::fHideTimer, tagPOPUPMENU::fIsMenuBar, tagPOPUPMENU::fIsSysMenu, tagMENUSTATE::fMouseOffMenu, tagPOPUPMENU::fShowTimer, FWINABLE, IDSYS_MNHIDE, IDSYS_MNSHOW, L, Lock, MFMWFP_NOITEM, MNAnimate(), MNIsItemSelected(), MNIsScrollArrowSelected(), MNSetTimerToCloseHierarchy(), NULL, tagPOPUPMENU::posDropped, tagPOPUPMENU::posSelectedItem, tagPOPUPMENU::ppopupmenuRoot, tagMENU::rgItems, tagPOPUPMENU::spmenu, tagPOPUPMENU::spwndActivePopup, tagPOPUPMENU::spwndNextPopup, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, tagPOPUPMENU::spwndPrevPopup, ThreadLock, ThreadUnlock, TRUE, xxxMNCloseHierarchy(), xxxMNDoScroll(), xxxMNInvertItem(), xxxSendMenuSelect(), xxxSendMessage(), and xxxWindowEvent().

Referenced by xxxMenuWindowProc(), xxxMNButtonDown(), xxxMNCancel(), xxxMNChar(), xxxMNKeyDown(), xxxMNKeyFilter(), xxxMNMouseMove(), and xxxMNSwitchToAlternateMenu().

02822 { 02823 PITEM pItem = NULL; 02824 TL tlpwndNotify; 02825 TL tlpwndPopup; 02826 TL tlpmenu; 02827 PWND pwndNotify; 02828 PMENU pmenu; 02829 02830 if (ppopupmenu->posSelectedItem == itemPos) { 02831 02832 /* 02833 * If this item is already selectected, just return its flags. 02834 */ 02835 if ((itemPos != MFMWFP_NOITEM) && (itemPos < ppopupmenu->spmenu->cItems)) { 02836 return &(ppopupmenu->spmenu->rgItems[itemPos]); 02837 } 02838 return NULL; 02839 } 02840 02841 /* 02842 * Terminate any animation 02843 */ 02844 MNAnimate(pMenuState, FALSE); 02845 02846 if (ppopupmenu->fShowTimer) { 02847 _KillTimer(ppopupmenu->spwndPopupMenu, IDSYS_MNSHOW); 02848 ppopupmenu->fShowTimer = FALSE; 02849 } 02850 02851 ThreadLock(pmenu = ppopupmenu->spmenu, &tlpmenu); 02852 ThreadLock(pwndNotify = ppopupmenu->spwndNotify, &tlpwndNotify); 02853 02854 if (ppopupmenu->fAboutToHide) 02855 { 02856 PPOPUPMENU ppopupPrev = ((PMENUWND)(ppopupmenu->spwndPrevPopup))->ppopupmenu; 02857 02858 _KillTimer(ppopupPrev->spwndPopupMenu, IDSYS_MNHIDE); 02859 ppopupPrev->fHideTimer = FALSE; 02860 if (ppopupPrev->fShowTimer) 02861 { 02862 _KillTimer(ppopupPrev->spwndPopupMenu, IDSYS_MNSHOW); 02863 ppopupPrev->fShowTimer = FALSE; 02864 } 02865 02866 if (ppopupPrev->posSelectedItem != ppopupPrev->posDropped) 02867 { 02868 TL tlpmenuPopupMenuPrev; 02869 ThreadLock(ppopupPrev->spmenu, &tlpmenuPopupMenuPrev); 02870 if (ppopupPrev->posSelectedItem != MFMWFP_NOITEM) { 02871 xxxMNInvertItem(ppopupPrev, ppopupPrev->spmenu, 02872 ppopupPrev->posSelectedItem, ppopupPrev->spwndNotify, FALSE); 02873 } 02874 02875 ppopupPrev->posSelectedItem = ppopupPrev->posDropped; 02876 02877 xxxMNInvertItem(ppopupPrev, ppopupPrev->spmenu, 02878 ppopupPrev->posDropped, ppopupPrev->spwndNotify, TRUE); 02879 ThreadUnlock(&tlpmenuPopupMenuPrev); 02880 } 02881 02882 ppopupmenu->fAboutToHide = FALSE; 02883 Lock(&ppopupmenu->ppopupmenuRoot->spwndActivePopup, ppopupmenu->spwndPopupMenu); 02884 } 02885 02886 if (MNIsItemSelected(ppopupmenu)) { 02887 /* 02888 * Something else is selected so we need to unselect it. 02889 */ 02890 if (ppopupmenu->spwndNextPopup) { 02891 if (ppopupmenu->fIsMenuBar) { 02892 xxxMNCloseHierarchy(ppopupmenu, pMenuState); 02893 } else { 02894 MNSetTimerToCloseHierarchy(ppopupmenu); 02895 } 02896 } 02897 02898 goto DeselectItem; 02899 } else if (MNIsScrollArrowSelected(ppopupmenu)) { 02900 _KillTimer(ppopupmenu->spwndPopupMenu, ppopupmenu->posSelectedItem); 02901 DeselectItem: 02902 02903 xxxMNInvertItem(ppopupmenu, pmenu, 02904 ppopupmenu->posSelectedItem, pwndNotify, FALSE); 02905 } 02906 02907 ppopupmenu->posSelectedItem = itemPos; 02908 02909 if (itemPos != MFMWFP_NOITEM) { 02910 /* 02911 * If an item is selected, no autodismiss plus this means 02912 * that the mouse is on the menu 02913 */ 02914 pMenuState->fAboutToAutoDismiss = 02915 pMenuState->fMouseOffMenu = FALSE; 02916 02917 if (pMenuState->fButtonDown) { 02918 xxxMNDoScroll(ppopupmenu, itemPos, TRUE); 02919 } 02920 02921 pItem = xxxMNInvertItem(ppopupmenu, pmenu, 02922 itemPos, pwndNotify, TRUE); 02923 ThreadUnlock(&tlpwndNotify); 02924 ThreadUnlock(&tlpmenu); 02925 return pItem; 02926 02927 } else if (FWINABLE()) { 02928 /* 02929 * Notify that nothing is now focused in this menu. 02930 */ 02931 xxxWindowEvent(EVENT_OBJECT_FOCUS, ppopupmenu->spwndPopupMenu, 02932 ((ppopupmenu->spwndNotify != ppopupmenu->spwndPopupMenu) ? OBJID_CLIENT : 02933 (ppopupmenu->fIsSysMenu ? OBJID_SYSMENU : OBJID_MENU)), 0, 0); 02934 } 02935 02936 ThreadUnlock(&tlpwndNotify); 02937 ThreadUnlock(&tlpmenu); 02938 02939 if (ppopupmenu->spwndPrevPopup != NULL) { 02940 PPOPUPMENU pp; 02941 02942 /* 02943 * Get the popupMenu data for the previous menu 02944 * Use the root popupMenu if the previous menu is the menu bar 02945 */ 02946 if (ppopupmenu->fHasMenuBar && (ppopupmenu->spwndPrevPopup == 02947 ppopupmenu->spwndNotify)) { 02948 pp = ppopupmenu->ppopupmenuRoot; 02949 } else { 02950 #ifdef HAVE_MN_GETPPOPUPMENU 02951 TL tlpwndPrevPopup; 02952 ThreadLock(ppopupmenu->spwndPrevPopup, &tlpwndPrevPopup); 02953 pp = (PPOPUPMENU)xxxSendMessage(ppopupmenu->spwndPrevPopup, 02954 MN_GETPPOPUPMENU, 0, 0L); 02955 ThreadUnlock(&tlpwndPrevPopup); 02956 #else 02957 pp = ((PMENUWND)ppopupmenu->spwndPrevPopup)->ppopupmenu; 02958 #endif 02959 } 02960 02961 /* 02962 * Generate a WM_MENUSELECT for the previous menu to re-establish 02963 * it's current item as the SELECTED item 02964 */ 02965 ThreadLock(pp->spwndNotify, &tlpwndNotify); 02966 ThreadLock(pp->spwndPopupMenu, &tlpwndPopup); 02967 xxxSendMenuSelect(pp->spwndNotify, pp->spwndPopupMenu, pp->spmenu, pp->posSelectedItem); 02968 ThreadUnlock(&tlpwndPopup); 02969 ThreadUnlock(&tlpwndNotify); 02970 } 02971 02972 return NULL; 02973 }

void xxxMNSetCapture PPOPUPMENU  ppopup  ) 
 

Definition at line 152 of file ntuser/kernel/menu.c.

References tagMENUSTATE::fSetCapture, gpqForeground, tagTHREADINFO::pMenuState, tagTHREADINFO::pq, PtiCurrent, QF_CAPTURELOCKED, tagQ::QF_flags, SCREEN_CAPTURE, tagQ::spwndCapture, tagPOPUPMENU::spwndNotify, TRUE, and xxxCapture().

Referenced by xxxMenuWindowProc(), xxxMNEndMenuState(), xxxMNKeyDown(), and xxxMNStartMenu().

00153 { 00154 PTHREADINFO ptiCurrent = PtiCurrent(); 00155 00156 /* 00157 * Set the capture and lock it so no one will be able to steal it 00158 * from us. 00159 */ 00160 xxxCapture(ptiCurrent, ppopup->spwndNotify, SCREEN_CAPTURE); 00161 UserAssert (ptiCurrent->pq->spwndCapture == ppopup->spwndNotify); 00162 ptiCurrent->pq->QF_flags |= QF_CAPTURELOCKED; 00163 ptiCurrent->pMenuState->fSetCapture = TRUE; 00164 #if DBG 00165 /* 00166 * Unless we're in the foreground, this menu mode won't go away 00167 * when the user clicks outside the menu. This is because only 00168 * the foreground queue capture sees clicks outside its windows. 00169 */ 00170 if (ptiCurrent->pq != gpqForeground) { 00171 RIPMSG0(RIP_WARNING, "xxxMNSetCapture: Menu mode is not in foreground queue"); 00172 } 00173 #endif 00174 }

BOOL xxxMNSetTop PPOPUPMENU  ppopup,
int  iNewTop
 

Definition at line 495 of file ntuser/kernel/menu.c.

References BOOL, tagMENU::cItems, tagITEM::cyItem, tagMENU::cyMax, tagMENU::cyMenu, tagMENU::dwArrowsOn, FALSE, tagMENU::hbrBack, tagMENU::iMaxTop, tagMENU::iTop, MFMWFP_DOWNARROW, MFMWFP_UPARROW, MNDrawArrow(), MNDrawFullNC(), MNGetToppItem(), MSA_ATBOTTOM, MSA_ATTOP, MSA_ON, NULL, tagMENU::rgItems, tagPOPUPMENU::spmenu, tagPOPUPMENU::spwndPopupMenu, TRUE, UINT, xxxInvalidateRect(), xxxScrollWindowEx(), and tagITEM::yItem.

Referenced by xxxMNDoScroll(), and xxxMNInvertItem().

00496 { 00497 PMENU pMenu = ppopup->spmenu; 00498 int dy; 00499 00500 if (iNewTop < 0) { 00501 iNewTop = 0; 00502 } else if (iNewTop > pMenu->iMaxTop) { 00503 iNewTop = pMenu->iMaxTop; 00504 } 00505 00506 /* 00507 * If no change, done 00508 */ 00509 if (iNewTop == pMenu->iTop) { 00510 return FALSE; 00511 } 00512 00513 #if DBG 00514 /* 00515 * We're going to scroll, so validate iMaxTop, cyMax and cyMenu 00516 */ 00517 UserAssert((pMenu->cyMax == 0) || (pMenu->cyMax >= pMenu->cyMenu)); 00518 if ((UINT)pMenu->iMaxTop < pMenu->cItems) { 00519 PITEM pitemLast = pMenu->rgItems + pMenu->cItems - 1; 00520 PITEM pitemMaxTop = pMenu->rgItems + pMenu->iMaxTop; 00521 UINT uHeight = pitemLast->yItem + pitemLast->cyItem - pitemMaxTop->yItem; 00522 UserAssert(uHeight <= pMenu->cyMenu); 00523 /* 00524 * Let's guess a max item height 00525 */ 00526 UserAssert(pMenu->cyMenu - uHeight <= 2 * pitemLast->cyItem); 00527 } else { 00528 UserAssert((UINT)pMenu->iMaxTop < pMenu->cItems); 00529 } 00530 #endif 00531 00532 00533 /* 00534 * if we've made it this far, the new iTop WILL change -- thus if the 00535 * current iTop is at the top it won't be after this change -- same goes 00536 * for iTop at the bottom 00537 */ 00538 if (pMenu->dwArrowsOn == MSA_ATTOP) { 00539 pMenu->dwArrowsOn = MSA_ON; 00540 if (pMenu->hbrBack == NULL) { 00541 MNDrawArrow(NULL, ppopup, MFMWFP_UPARROW); 00542 } 00543 } else if (pMenu->dwArrowsOn == MSA_ATBOTTOM) { 00544 pMenu->dwArrowsOn = MSA_ON; 00545 if (pMenu->hbrBack == NULL) { 00546 MNDrawArrow(NULL, ppopup, MFMWFP_DOWNARROW); 00547 } 00548 } 00549 00550 UserAssert((UINT)iNewTop < pMenu->cItems); 00551 dy = MNGetToppItem(pMenu)->yItem - (pMenu->rgItems + iNewTop)->yItem; 00552 00553 if ((dy > 0 ? dy : -dy) > (int)pMenu->cyMenu) { 00554 xxxInvalidateRect(ppopup->spwndPopupMenu, NULL, TRUE); 00555 } else { 00556 xxxScrollWindowEx(ppopup->spwndPopupMenu, 0, dy, NULL, NULL, NULL, NULL, SW_INVALIDATE | SW_ERASE); 00557 } 00558 00559 pMenu->iTop = iNewTop; 00560 00561 if (iNewTop == 0) { 00562 pMenu->dwArrowsOn = MSA_ATTOP; 00563 if (pMenu->hbrBack == NULL) { 00564 MNDrawArrow(NULL, ppopup, MFMWFP_UPARROW); 00565 } 00566 } else if (iNewTop == pMenu->iMaxTop) { 00567 pMenu->dwArrowsOn = MSA_ATBOTTOM; 00568 if (pMenu->hbrBack == NULL) { 00569 MNDrawArrow(NULL, ppopup, MFMWFP_DOWNARROW); 00570 } 00571 } 00572 00573 if (pMenu->hbrBack != NULL) { 00574 MNDrawFullNC(ppopup->spwndPopupMenu, NULL, ppopup); 00575 } 00576 00577 return TRUE; 00578 00579 }

BOOL xxxMNSwitchToAlternateMenu PPOPUPMENU  ppopupmenu  ) 
 

Definition at line 795 of file ntuser/kernel/menu.c.

References BOOL, FALSE, tagPOPUPMENU::fDestroyed, tagPOPUPMENU::fIsMenuBar, tagMENUSTATE::fIsSysMenu, tagPOPUPMENU::fIsSysMenu, FWINABLE, GetpMenuState(), Lock, MFMWFP_NOITEM, MFSYSMENU, NULL, tagPOPUPMENU::spmenu, tagPOPUPMENU::spmenuAlternate, tagWND::spmenuSys, tagMENU::spwndNotify, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, TestMF, TestWF, ThreadLock, ThreadUnlock, TRUE, Unlock, WFSYSMENU, xxxMNSelectItem(), and xxxWindowEvent().

Referenced by xxxHandleMenuMessages(), xxxMNChar(), xxxMNKeyDown(), xxxMNKeyFilter(), and xxxMNMouseMove().

00797 { 00798 PMENU pmenuSwap = NULL; 00799 PMENUSTATE pMenuState; 00800 TL tlpwndPopupMenu; 00801 00802 if (!ppopupmenu->fIsMenuBar || !ppopupmenu->spmenuAlternate) { 00803 /* 00804 * Do nothing if no menu or not top level menu bar. 00805 * ppopupmenu->spmenuAlternate can be NULL when an app has 00806 * either system menu or menu bar but not both. If that menu 00807 * has only one popup that it's not dropped, then hitting 00808 * VK_RIGHT or VK_LEFT causes xxxMNKeyDown to end up here. 00809 * ppopupmenu->fIsMenuBar can be false when you drop the 00810 * system menu of an app with no menu bar; then hit VK_RIGHT 00811 * on an item that doesn't have a popup and you'll get here 00812 * There might be some other situations like this; in any case 00813 * the assertion got to go 00814 */ 00815 return FALSE; 00816 } 00817 00818 /* 00819 * If we're getting out of menu mode, do nothing 00820 */ 00821 if (ppopupmenu->fDestroyed) { 00822 return FALSE; 00823 } 00824 00825 /* 00826 * Select no items in the current menu. 00827 */ 00828 ThreadLock(ppopupmenu->spwndPopupMenu, &tlpwndPopupMenu); 00829 UserAssert(ppopupmenu->spwndPopupMenu != NULL); 00830 pMenuState = GetpMenuState(ppopupmenu->spwndPopupMenu); 00831 if (pMenuState == NULL) { 00832 RIPMSG0(RIP_ERROR, "xxxMNSwitchToAlternateMenu: pMenuState == NULL"); 00833 ThreadUnlock(&tlpwndPopupMenu); 00834 return FALSE; 00835 } 00836 xxxMNSelectItem(ppopupmenu, pMenuState, MFMWFP_NOITEM); 00837 00838 00839 UserAssert(ppopupmenu->spmenu->spwndNotify == ppopupmenu->spmenuAlternate->spwndNotify); 00840 Lock(&pmenuSwap, ppopupmenu->spmenuAlternate); 00841 Lock(&ppopupmenu->spmenuAlternate, ppopupmenu->spmenu); 00842 Lock(&ppopupmenu->spmenu, pmenuSwap); 00843 Unlock(&pmenuSwap); 00844 00845 /* 00846 * Set this global because it is used in SendMenuSelect() 00847 */ 00848 if (!TestWF(ppopupmenu->spwndNotify, WFSYSMENU)) { 00849 pMenuState->fIsSysMenu = FALSE; 00850 } else if (ppopupmenu->spwndNotify->spmenuSys != NULL) { 00851 pMenuState->fIsSysMenu = (ppopupmenu->spwndNotify->spmenuSys == 00852 ppopupmenu->spmenu); 00853 } else { 00854 pMenuState->fIsSysMenu = !!TestMF(ppopupmenu->spmenu, MFSYSMENU); 00855 } 00856 00857 ppopupmenu->fIsSysMenu = pMenuState->fIsSysMenu; 00858 00859 if (FWINABLE()) { 00860 xxxWindowEvent(EVENT_SYSTEM_MENUEND, ppopupmenu->spwndNotify, 00861 (ppopupmenu->fIsSysMenu ? OBJID_MENU : OBJID_SYSMENU), INDEXID_CONTAINER, 0); 00862 xxxWindowEvent(EVENT_SYSTEM_MENUSTART, ppopupmenu->spwndNotify, 00863 (ppopupmenu->fIsSysMenu ? OBJID_SYSMENU : OBJID_MENU), INDEXID_CONTAINER, 0); 00864 } 00865 00866 ThreadUnlock(&tlpwndPopupMenu); 00867 00868 return TRUE; 00869 }


Generated on Sat May 15 19:44:38 2004 for test by doxygen 1.3.7