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

mnstate.c

Go to the documentation of this file.
00001 /**************************** Module Header ********************************\ 00002 * Module Name: mnstate.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Menu State Routines 00007 * 00008 * History: 00009 * 10-10-90 JimA Cleanup. 00010 * 03-18-91 IanJa Windowrevalidation added 00011 \***************************************************************************/ 00012 00013 #include "precomp.h" 00014 #pragma hdrstop 00015 00016 PMENU xxxGetInitMenuParam(PWND pwndMenu, BOOL * lpfSystem); 00017 /***************************************************************************\ 00018 * void PositionSysMenu(pwnd, hSysMenu) 00019 * 00020 * 00021 * History: 00022 * 4-25-91 Mikehar Port for 3.1 merge 00023 \***************************************************************************/ 00024 00025 void MNPositionSysMenu( 00026 PWND pwnd, 00027 PMENU pmenusys) 00028 { 00029 RECT rc; 00030 PITEM pItem; 00031 00032 if (pmenusys == NULL) { 00033 RIPERR0(ERROR_INVALID_HANDLE, 00034 RIP_WARNING, 00035 "Invalid menu handle pmenusys (NULL) to MNPositionSysMenu"); 00036 00037 return; 00038 } 00039 00040 /* 00041 * Whoever positions the menu becomes the owner 00042 */ 00043 if (pwnd != pmenusys->spwndNotify) { 00044 Lock(&pmenusys->spwndNotify, pwnd); 00045 } 00046 00047 /* 00048 * Setup the SysMenu hit rectangle. 00049 */ 00050 rc.top = rc.left = 0; 00051 00052 if (TestWF(pwnd, WEFTOOLWINDOW)) { 00053 rc.right = SYSMET(CXSMSIZE); 00054 rc.bottom = SYSMET(CYSMSIZE); 00055 } else { 00056 rc.right = SYSMET(CXSIZE); 00057 rc.bottom = SYSMET(CYSIZE); 00058 } 00059 00060 if (!TestWF(pwnd, WFMINIMIZED)) { 00061 int cBorders; 00062 00063 cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); 00064 OffsetRect(&rc, cBorders*SYSMET(CXBORDER), cBorders*SYSMET(CYBORDER)); 00065 } 00066 00067 /* 00068 * Offset the System popup menu. 00069 */ 00070 if (!TestMF(pmenusys, MF_POPUP) && (pmenusys->cItems > 0)) { 00071 pItem = pmenusys->rgItems; 00072 if (pItem) { 00073 pItem->yItem = rc.top; 00074 pItem->xItem = rc.left; 00075 pItem->cyItem = rc.bottom - rc.top; 00076 pItem->cxItem = rc.right - rc.left; 00077 } 00078 } 00079 else 00080 // BOGUS -- MF_POPUP should never be set on a MENU -- only a MENU ITEM 00081 UserAssert(FALSE); 00082 } 00083 00084 /***************************************************************************\ 00085 * MNFlushDestroyedPopups 00086 * 00087 * Walk the ppmDelayedFree list freeing those marked as destroyed. 00088 * 00089 * 05-14-96 GerardoB Created 00090 \***************************************************************************/ 00091 void MNFlushDestroyedPopups (PPOPUPMENU ppopupmenu, BOOL fUnlock) 00092 { 00093 PPOPUPMENU ppmDestroyed, ppmFree; 00094 00095 UserAssert(IsRootPopupMenu(ppopupmenu)); 00096 00097 /* 00098 * Walk ppmDelayedFree 00099 */ 00100 ppmDestroyed = ppopupmenu; 00101 while (ppmDestroyed->ppmDelayedFree != NULL) { 00102 /* 00103 * If it's marked as destroyed, unlink it and free it 00104 */ 00105 if (ppmDestroyed->ppmDelayedFree->fDestroyed) { 00106 ppmFree = ppmDestroyed->ppmDelayedFree; 00107 ppmDestroyed->ppmDelayedFree = ppmFree->ppmDelayedFree; 00108 UserAssert(ppmFree != ppmFree->ppopupmenuRoot); 00109 MNFreePopup(ppmFree); 00110 } else { 00111 /* 00112 * fUnlock is TRUE if the root popup is being destroyed; if 00113 * so, reset fDelayedFree and unlink it 00114 */ 00115 if (fUnlock) { 00116 /* 00117 * This means that the root popup is going away before 00118 * some of the hierarchical popups have been destroyed. 00119 * This can happen if someone destroys one of the menu 00120 * windows breaking the spwndNextPopup chain. 00121 */ 00122 ppmDestroyed->ppmDelayedFree->fDelayedFree = FALSE; 00123 /* 00124 * Stop here so we can figure how this happened. 00125 */ 00126 UserAssert(ppmDestroyed->ppmDelayedFree->fDelayedFree); 00127 ppmDestroyed->ppmDelayedFree = ppmDestroyed->ppmDelayedFree->ppmDelayedFree; 00128 } else { 00129 /* 00130 * Not fDestroyed so move to the next one. 00131 */ 00132 ppmDestroyed = ppmDestroyed->ppmDelayedFree; 00133 } /* fUnlock */ 00134 } /* fDestroyed */ 00135 } /* while ppmDelayedFree */ 00136 00137 } 00138 00139 /***************************************************************************\ 00140 * MNAllocPopup 00141 * 00142 \***************************************************************************/ 00143 PPOPUPMENU MNAllocPopup(BOOL fForceAlloc) 00144 { 00145 PPOPUPMENU ppm; 00146 if (!fForceAlloc && !TEST_PUDF(PUDF_POPUPINUSE)) { 00147 SET_PUDF(PUDF_POPUPINUSE); 00148 00149 ppm = &gpopupMenu; 00150 } else { 00151 ppm = (PPOPUPMENU)UserAllocPoolWithQuota(sizeof(POPUPMENU), TAG_POPUPMENU); 00152 } 00153 00154 if (ppm) { 00155 RtlZeroMemory(ppm, sizeof(POPUPMENU)); 00156 } 00157 00158 return (ppm); 00159 } 00160 00161 /***************************************************************************\ 00162 * MNFreePopup 00163 * 00164 \***************************************************************************/ 00165 VOID MNFreePopup( 00166 PPOPUPMENU ppopupmenu) 00167 { 00168 00169 Validateppopupmenu(ppopupmenu); 00170 00171 if (IsRootPopupMenu(ppopupmenu)) { 00172 MNFlushDestroyedPopups (ppopupmenu, TRUE); 00173 } 00174 #if DBG 00175 /* 00176 * If this is not a cached menu and it corresponds to a menu window, 00177 * then the reference to the popup must be cleared at this point since 00178 * we're going to free this popup 00179 */ 00180 if (ppopupmenu->spwndPopupMenu != NULL) { 00181 if (!ppopupmenu->fDesktopMenu && !ppopupmenu->fIsMenuBar) { 00182 UserAssert(GETFNID(ppopupmenu->spwndPopupMenu) == FNID_MENU); 00183 UserAssert(((PMENUWND)ppopupmenu->spwndPopupMenu)->ppopupmenu == NULL); 00184 } 00185 } 00186 #endif 00187 Unlock(&ppopupmenu->spwndPopupMenu); 00188 /* 00189 * if spwndNextPopup is not NULL, we're breaking the chain and spwndNext won't 00190 * get closed. I won't remove the unlock since it has 00191 * always been there. 00192 */ 00193 UserAssert(ppopupmenu->spwndNextPopup == NULL); 00194 Unlock(&ppopupmenu->spwndNextPopup); 00195 00196 Unlock(&ppopupmenu->spwndPrevPopup); 00197 UnlockPopupMenu(ppopupmenu, &ppopupmenu->spmenu); 00198 UnlockPopupMenu(ppopupmenu, &ppopupmenu->spmenuAlternate); 00199 Unlock(&ppopupmenu->spwndNotify); 00200 Unlock(&ppopupmenu->spwndActivePopup); 00201 00202 #if DBG 00203 if (!ppopupmenu->fDesktopMenu) { 00204 ppopupmenu->fFreed = TRUE; 00205 } else { 00206 PDESKTOP pdesk = PtiCurrent()->rpdesk; 00207 UserAssert(pdesk->dwDTFlags & DF_MENUINUSE); 00208 UserAssert(((PMENUWND)pdesk->spwndMenu)->ppopupmenu == ppopupmenu); 00209 } 00210 #endif 00211 00212 if (ppopupmenu->fDesktopMenu) { 00213 PtiCurrent()->rpdesk->dwDTFlags &= ~DF_MENUINUSE; 00214 /* The desktop menu window points to this popup so don't leave bogus stuff in it */ 00215 ppopupmenu->ppopupmenuRoot = NULL; 00216 } else if (ppopupmenu == &gpopupMenu) { 00217 UserAssert(TEST_PUDF(PUDF_POPUPINUSE)); 00218 CLEAR_PUDF(PUDF_POPUPINUSE); 00219 } else { 00220 UserFreePool(ppopupmenu); 00221 } 00222 } 00223 /***************************************************************************\ 00224 * MNEndMenuStateNotify 00225 * 00226 * spwndNotify might have been created by a thread other than the one 00227 * the menu mode is running on. If this is the case, this function 00228 * NULLs out pMenuState for the thread that owns spwndNotify. 00229 * It returns TRUE if the menu state owner doesn't own the notification 00230 * window (multiple threads involved) 00231 * 00232 * 05-21-96 GerardoB Created 00233 \***************************************************************************/ 00234 BOOL MNEndMenuStateNotify (PMENUSTATE pMenuState) 00235 { 00236 PTHREADINFO ptiNotify; 00237 00238 if (pMenuState->pGlobalPopupMenu->spwndNotify != NULL) { 00239 ptiNotify = GETPTI(pMenuState->pGlobalPopupMenu->spwndNotify); 00240 if (ptiNotify != pMenuState->ptiMenuStateOwner) { 00241 /* 00242 * Later5.0 GerardoB. xxxMNStartMenuState no longer allows this. 00243 * This is dead code that I'll remove eventually 00244 */ 00245 UserAssert(ptiNotify == pMenuState->ptiMenuStateOwner); 00246 00247 UserAssert(ptiNotify->pMenuState == pMenuState); 00248 UserAssert(pMenuState->pmnsPrev == NULL); 00249 ptiNotify->pMenuState = NULL; 00250 return TRUE; 00251 } 00252 } 00253 00254 return FALSE; 00255 } 00256 /***************************************************************************\ 00257 * xxxMNEndMenuState 00258 * 00259 * This funtion must be called to clean up pMenuState after getting out 00260 * of menu mode. It must be called by the same thread that initialized 00261 * pMenuState either manually or by calling xxxMNStartMenuState. 00262 * 00263 * 05-20-96 GerardoB Created 00264 \***************************************************************************/ 00265 void xxxMNEndMenuState (BOOL fFreePopup) 00266 { 00267 PTHREADINFO ptiCurrent = PtiCurrent(); 00268 PMENUSTATE pMenuState; 00269 pMenuState = ptiCurrent->pMenuState; 00270 UserAssert(ptiCurrent->pMenuState != NULL); 00271 UserAssert(ptiCurrent == pMenuState->ptiMenuStateOwner); 00272 00273 /* 00274 * If the menu is locked, someone doesn't want it to go just yet. 00275 */ 00276 if (pMenuState->dwLockCount != 0) { 00277 RIPMSG1(RIP_WARNING, "xxxMNEndMenuState Locked:%#p", pMenuState); 00278 return; 00279 } 00280 00281 MNEndMenuStateNotify(pMenuState); 00282 00283 /* 00284 * pMenuState->pGlobalPopupMenu could be NULL if xxxMNAllocMenuState failed 00285 */ 00286 if (pMenuState->pGlobalPopupMenu != NULL) { 00287 if (fFreePopup) { 00288 UserAssert(pMenuState->pGlobalPopupMenu->fIsMenuBar || pMenuState->pGlobalPopupMenu->fDestroyed); 00289 00290 MNFreePopup(pMenuState->pGlobalPopupMenu); 00291 } else { 00292 /* 00293 * This means that we're ending the menustate but the popup menu 00294 * window is still around. This can happen when called from 00295 * xxxDestroyThreadInfo. 00296 */ 00297 UserAssert(pMenuState->pGlobalPopupMenu->fIsTrackPopup); 00298 pMenuState->pGlobalPopupMenu->fDelayedFree = FALSE; 00299 } 00300 } 00301 00302 /* 00303 * Unlock MFMWFP windows. 00304 */ 00305 UnlockMFMWFPWindow(&pMenuState->uButtonDownHitArea); 00306 UnlockMFMWFPWindow(&pMenuState->uDraggingHitArea); 00307 00308 /* 00309 * Restore the previous state, if any 00310 */ 00311 ptiCurrent->pMenuState = pMenuState->pmnsPrev; 00312 00313 /* 00314 * This (modal) menu mode is off 00315 */ 00316 if (!pMenuState->fModelessMenu) { 00317 DecSFWLockCount(); 00318 DBGDecModalMenuCount(); 00319 } 00320 00321 if (pMenuState->hbmAni != NULL) { 00322 MNDestroyAnimationBitmap(pMenuState); 00323 } 00324 00325 /* 00326 * Free the menu state 00327 */ 00328 if (pMenuState == &gMenuState) { 00329 UserAssert(TEST_PUDF(PUDF_MENUSTATEINUSE)); 00330 CLEAR_PUDF(PUDF_MENUSTATEINUSE); 00331 GreSetDCOwner(gMenuState.hdcAni, OBJECT_OWNER_PUBLIC); 00332 } else { 00333 if (pMenuState->hdcAni != NULL) { 00334 GreDeleteDC(pMenuState->hdcAni); 00335 } 00336 UserFreePool(pMenuState); 00337 } 00338 00339 /* 00340 * If returning to a modeless menu, make sure have activation 00341 * If returning to a modal menu, make sure we have capture 00342 */ 00343 if (ptiCurrent->pMenuState != NULL) { 00344 if (ptiCurrent->pMenuState->fModelessMenu) { 00345 xxxActivateThisWindow(ptiCurrent->pMenuState->pGlobalPopupMenu->spwndActivePopup, 00346 0, 0); 00347 } else { 00348 xxxMNSetCapture(ptiCurrent->pMenuState->pGlobalPopupMenu); 00349 } 00350 } 00351 00352 #if DBG 00353 /* 00354 * If this thread is not in menu mode anymore, it must not be using 00355 * the desktop menu 00356 */ 00357 if ((ptiCurrent->pMenuState == NULL) && (ptiCurrent->rpdesk->spwndMenu != NULL)) { 00358 UserAssert(ptiCurrent != GETPTI(ptiCurrent->rpdesk->spwndMenu)); 00359 } 00360 /* 00361 * If someone is using the menu window, it must be in menu mode 00362 */ 00363 if (ptiCurrent->rpdesk->dwDTFlags & DF_MENUINUSE) { 00364 UserAssert(GetpMenuState(ptiCurrent->rpdesk->spwndMenu) != NULL); 00365 } 00366 /* 00367 * No pti should point to this pMenuState anymore 00368 * If guModalMenuStateCount is zero, all pMenuState must be NULL or modeless 00369 */ 00370 { 00371 PLIST_ENTRY pHead, pEntry; 00372 PTHREADINFO ptiT; 00373 00374 pHead = &(ptiCurrent->rpdesk->PtiList); 00375 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { 00376 ptiT = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink); 00377 UserAssert(ptiT->pMenuState != pMenuState); 00378 if (guModalMenuStateCount == 0) { 00379 UserAssert(ptiT->pMenuState == NULL || ptiT->pMenuState->fModelessMenu); 00380 } 00381 } 00382 } 00383 #endif 00384 } 00385 /***************************************************************************\ 00386 * MNCreateAnimationBitmap 00387 * 00388 \***************************************************************************/ 00389 BOOL MNCreateAnimationBitmap(PMENUSTATE pMenuState, UINT cx, UINT cy) 00390 { 00391 HBITMAP hbm = GreCreateCompatibleBitmap(gpDispInfo->hdcScreen, cx, cy); 00392 if (hbm == NULL) { 00393 RIPMSG0(RIP_WARNING, "MNSetupAnimationBitmap: Failed to create hbmAni"); 00394 return FALSE; 00395 } 00396 00397 #if DBG 00398 if (pMenuState->hdcAni == NULL) { 00399 RIPMSG0(RIP_WARNING, "MNCreateAnimationBitmap: hdcAni is NULL"); 00400 } 00401 if (pMenuState->hbmAni != NULL) { 00402 RIPMSG0(RIP_WARNING, "MNCreateAnimationBitmap: hbmAni already exists"); 00403 } 00404 #endif 00405 00406 GreSelectBitmap(pMenuState->hdcAni, hbm); 00407 pMenuState->hbmAni = hbm; 00408 return TRUE; 00409 } 00410 /***************************************************************************\ 00411 * MNDestroyAnimationBitmap 00412 * 00413 \***************************************************************************/ 00414 void MNDestroyAnimationBitmap(PMENUSTATE pMenuState) 00415 { 00416 GreSelectBitmap(pMenuState->hdcAni, GreGetStockObject(PRIV_STOCK_BITMAP)); 00417 UserVerify(GreDeleteObject(pMenuState->hbmAni)); 00418 pMenuState->hbmAni = NULL; 00419 } 00420 /***************************************************************************\ 00421 * MNSetupAnimationDC 00422 * 00423 * 9/20/96 GerardoB Created 00424 \***************************************************************************/ 00425 BOOL MNSetupAnimationDC (PMENUSTATE pMenuState) 00426 { 00427 pMenuState->hdcAni = GreCreateCompatibleDC(gpDispInfo->hdcScreen); 00428 if (pMenuState->hdcAni == NULL) { 00429 RIPMSG0(RIP_WARNING, "MNSetupAnimationDC: Failed to create hdcAnimate"); 00430 UserAssert(pMenuState != &gMenuState); 00431 return FALSE; 00432 } 00433 GreSelectFont(pMenuState->hdcAni, ghMenuFont); 00434 return TRUE; 00435 } 00436 /***************************************************************************\ 00437 * xxxUnlockMenuState 00438 * 00439 * 11/24/96 GerardoB Created 00440 \***************************************************************************/ 00441 BOOL xxxUnlockMenuState (PMENUSTATE pMenuState) 00442 { 00443 UserAssert(pMenuState->dwLockCount != 0); 00444 (pMenuState->dwLockCount)--; 00445 if ((pMenuState->dwLockCount == 0) && ExitMenuLoop(pMenuState, pMenuState->pGlobalPopupMenu)) { 00446 xxxMNEndMenuState(TRUE); 00447 return TRUE; 00448 } 00449 return FALSE; 00450 } 00451 /***************************************************************************\ 00452 * xxxMNAllocMenuState 00453 * 00454 * Allocates and initializes a pMenuState 00455 * 00456 * 5-21-96 GerardoB Created 00457 \***************************************************************************/ 00458 PMENUSTATE xxxMNAllocMenuState(PTHREADINFO ptiCurrent, PTHREADINFO ptiNotify, PPOPUPMENU ppopupmenuRoot) 00459 { 00460 BOOL fAllocate; 00461 PMENUSTATE pMenuState; 00462 00463 UserAssert(PtiCurrent() == ptiCurrent); 00464 UserAssert(ptiCurrent->rpdesk == ptiNotify->rpdesk); 00465 00466 /* 00467 * If gMenuState is already taken, allocate one. 00468 */ 00469 fAllocate = TEST_PUDF(PUDF_MENUSTATEINUSE); 00470 if (fAllocate) { 00471 pMenuState = (PMENUSTATE)UserAllocPoolWithQuota(sizeof(MENUSTATE), TAG_MENUSTATE); 00472 if (pMenuState == NULL) { 00473 return NULL; 00474 } 00475 } else { 00476 /* 00477 * Use chache global which already has the animation DC setup 00478 */ 00479 SET_PUDF(PUDF_MENUSTATEINUSE); 00480 pMenuState = &gMenuState; 00481 UserAssert(gMenuState.hdcAni != NULL); 00482 GreSetDCOwner(gMenuState.hdcAni, OBJECT_OWNER_CURRENT); 00483 } 00484 00485 /* 00486 * Prevent anyone from changing the foreground while this menu is active 00487 */ 00488 IncSFWLockCount(); 00489 DBGIncModalMenuCount(); 00490 00491 /* 00492 * Initialize pMenuState. 00493 * Animation DC stuff is already setup so don't zero init it. 00494 */ 00495 RtlZeroMemory(pMenuState, sizeof(MENUSTATE) - sizeof(MENUANIDC)); 00496 pMenuState->pGlobalPopupMenu = ppopupmenuRoot; 00497 pMenuState->ptiMenuStateOwner = ptiCurrent; 00498 00499 /* 00500 * Save previous state, if any. Then set new state 00501 */ 00502 pMenuState->pmnsPrev = ptiCurrent->pMenuState; 00503 ptiCurrent->pMenuState = pMenuState; 00504 00505 if (ptiNotify != ptiCurrent) { 00506 UserAssert(ptiNotify->pMenuState == NULL); 00507 ptiNotify->pMenuState = pMenuState; 00508 } 00509 00510 /* 00511 * If the menustate was allocated, set up animation stuff. 00512 * This is done here because in case of failure, MNEndMenuState 00513 * will find ptiCurrent->pMenuState properly. 00514 */ 00515 if (fAllocate) { 00516 RtlZeroMemory((PBYTE)pMenuState + sizeof(MENUSTATE) - 00517 sizeof(MENUANIDC), sizeof(MENUANIDC)); 00518 if (!MNSetupAnimationDC(pMenuState)) { 00519 xxxMNEndMenuState(TRUE); 00520 return NULL; 00521 } 00522 } 00523 00524 return pMenuState; 00525 } 00526 /***************************************************************************\ 00527 * xxxMNStartMenuState 00528 * 00529 * This function is called when the menu bar is about to be activated (the 00530 * app's main menu). It makes sure that the threads involved are not in 00531 * menu mode already, finds the owner/notification window, initializes 00532 * pMenuState and sends the WM_ENTERMENULOOP message. 00533 * It successful, it returns a pointer to a pMenuState. If so, the caller 00534 * must call MNEndMenuState when done. 00535 * 00536 * History: 00537 * 4-25-91 Mikehar Port for 3.1 merge 00538 * 5-20-96 GerardoB Renamed and changed (Old name: xxxMNGetPopup) 00539 \***************************************************************************/ 00540 PMENUSTATE xxxMNStartMenuState(PWND pwnd, DWORD cmd, LPARAM lParam) 00541 { 00542 PPOPUPMENU ppopupmenu; 00543 PTHREADINFO ptiCurrent, ptiNotify; 00544 PMENUSTATE pMenuState; 00545 TL tlpwnd; 00546 PWND pwndT; 00547 00548 CheckLock(pwnd); 00549 00550 /* 00551 * Bail if the current thread is already in menu mode 00552 */ 00553 ptiCurrent = PtiCurrent(); 00554 if (ptiCurrent->pMenuState != NULL) { 00555 return NULL; 00556 } 00557 00558 /* 00559 * If pwnd is not owned by ptiCurrent, the _PostMessage call below might 00560 * send us in a loop 00561 */ 00562 UserAssert(ptiCurrent == GETPTI(pwnd)); 00563 00564 /* 00565 * If this is not a child window, use the active window on its queue 00566 */ 00567 if (!TestwndChild(pwnd)) { 00568 pwnd = GETPTI(pwnd)->pq->spwndActive; 00569 } else { 00570 /* 00571 * Search up the parents for a window with a System Menu. 00572 */ 00573 while (TestwndChild(pwnd)) { 00574 if (TestWF(pwnd, WFSYSMENU)) { 00575 break; 00576 } 00577 pwnd = pwnd->spwndParent; 00578 } 00579 } 00580 00581 if (pwnd == NULL) { 00582 return NULL; 00583 } 00584 00585 if (!TestwndChild(pwnd) && (pwnd->spmenu != NULL)) { 00586 goto hasmenu; 00587 } 00588 00589 if (!TestWF(pwnd, WFSYSMENU)) { 00590 return NULL; 00591 } 00592 00593 hasmenu: 00594 00595 /* 00596 * If the owner/notification window was created by another thread, 00597 * make sure that it's not in menu mode already 00598 * This can happen if PtiCurrent() is attached to other threads, one of 00599 * which created pwnd. 00600 */ 00601 ptiNotify = GETPTI(pwnd); 00602 if (ptiNotify->pMenuState != NULL) { 00603 return NULL; 00604 } 00605 00606 /* 00607 * If the notification window is owned by another thread, 00608 * then the menu loop wouldn't get any keyboard or mouse 00609 * messages because we set capture to the notification window. 00610 * So we pass the WM_SYSCOMMAND to that thread and bail 00611 */ 00612 if (ptiNotify != ptiCurrent) { 00613 RIPMSG2(RIP_WARNING, "Passing WM_SYSCOMMAND SC_*MENU from thread %#p to %#p", ptiCurrent, ptiNotify); 00614 _PostMessage(pwnd, WM_SYSCOMMAND, cmd, lParam); 00615 return NULL; 00616 } 00617 00618 /* 00619 * Allocate ppoupmenu and pMenuState 00620 */ 00621 ppopupmenu = MNAllocPopup(FALSE); 00622 if (ppopupmenu == NULL) { 00623 return NULL; 00624 } 00625 00626 pMenuState = xxxMNAllocMenuState(ptiCurrent, ptiNotify, ppopupmenu); 00627 if (pMenuState == NULL) { 00628 MNFreePopup(ppopupmenu); 00629 return NULL; 00630 } 00631 00632 ppopupmenu->fIsMenuBar = TRUE; 00633 ppopupmenu->fHasMenuBar = TRUE; 00634 Lock(&(ppopupmenu->spwndNotify), pwnd); 00635 ppopupmenu->posSelectedItem = MFMWFP_NOITEM; 00636 Lock(&(ppopupmenu->spwndPopupMenu), pwnd); 00637 ppopupmenu->ppopupmenuRoot = ppopupmenu; 00638 00639 pwndT = pwnd; 00640 while( TestwndChild(pwndT) ) 00641 pwndT = pwndT->spwndParent; 00642 00643 if (pwndT->spmenu) 00644 ppopupmenu->fRtoL = TestMF(pwndT->spmenu, MFRTL) ?TRUE:FALSE; 00645 else { 00646 // 00647 // no way to know, no menu, but there is a system menu. Thus arrow 00648 // keys are really not important. however lets take the next best 00649 // thing just to be safe 00650 // 00651 ppopupmenu->fRtoL = TestWF(pwnd, WEFRTLREADING) ?TRUE :FALSE; 00652 } 00653 /* 00654 * Notify the app we are entering menu mode. wParam is always 0 since this 00655 * procedure will only be called for menu bar menus not TrackPopupMenu 00656 * menus. 00657 */ 00658 ThreadLockAlways(pwnd, &tlpwnd); 00659 xxxSendMessage(pwnd, WM_ENTERMENULOOP, 0, 0L); 00660 ThreadUnlock(&tlpwnd); 00661 00662 return pMenuState; 00663 } 00664 00665 00666 /***************************************************************************\ 00667 * xxxStartMenu 00668 * 00669 * Note that this function calls back many times so we might be forced 00670 * out of menu mode at any time. We don't want to check this after 00671 * each callback so we lock what we need and go on. Be careful. 00672 * 00673 * History: 00674 * 4-25-91 Mikehar Port for 3.1 merge 00675 \***************************************************************************/ 00676 00677 BOOL xxxMNStartMenu( 00678 PPOPUPMENU ppopupmenu, 00679 int mn) 00680 { 00681 PWND pwndMenu; 00682 PMENU pMenu; 00683 PMENUSTATE pMenuState; 00684 TL tlpwndMenu; 00685 TL tlpmenu; 00686 00687 UserAssert(IsRootPopupMenu(ppopupmenu)); 00688 00689 if (ppopupmenu->fDestroyed) { 00690 return FALSE; 00691 } 00692 00693 pwndMenu = ppopupmenu->spwndNotify; 00694 ThreadLock(pwndMenu, &tlpwndMenu); 00695 00696 pMenuState = GetpMenuState(pwndMenu); 00697 if (pMenuState == NULL) { 00698 RIPMSG0(RIP_ERROR, "xxxMNStartMenu: pMenuState == NULL"); 00699 ThreadUnlock(&tlpwndMenu); 00700 return FALSE; 00701 } 00702 pMenuState->mnFocus = mn; 00703 pMenuState->fMenuStarted = TRUE; 00704 pMenuState->fButtonDown = 00705 pMenuState->fButtonAlwaysDown = ((_GetKeyState(VK_LBUTTON) & 0x8000) != 0); 00706 00707 xxxMNSetCapture(ppopupmenu); 00708 00709 xxxSendMessage(pwndMenu, WM_SETCURSOR, (WPARAM)HWq(pwndMenu), 00710 MAKELONG(MSGF_MENU, 0)); 00711 00712 if (ppopupmenu->fIsMenuBar) { 00713 BOOL fSystemMenu; 00714 00715 00716 pMenu = xxxGetInitMenuParam(pwndMenu, &fSystemMenu); 00717 00718 if (pMenu == NULL) { 00719 pMenuState->fMenuStarted = FALSE; 00720 xxxMNReleaseCapture(); 00721 ThreadUnlock(&tlpwndMenu); 00722 return(FALSE); 00723 } 00724 00725 LockPopupMenu(ppopupmenu, &ppopupmenu->spmenu, pMenu); 00726 00727 ppopupmenu->fIsSysMenu = (fSystemMenu != 0); 00728 if (!fSystemMenu) { 00729 pMenu = xxxGetSysMenu(pwndMenu, FALSE); 00730 LockPopupMenu(ppopupmenu, &ppopupmenu->spmenuAlternate, pMenu); 00731 } 00732 } 00733 00734 pMenuState->fIsSysMenu = (ppopupmenu->fIsSysMenu != 0); 00735 00736 if (!ppopupmenu->fNoNotify) { 00737 00738 if (ppopupmenu->fIsTrackPopup && ppopupmenu->fIsSysMenu) { 00739 pMenu = xxxGetInitMenuParam(pwndMenu, NULL); 00740 } else { 00741 pMenu = ppopupmenu->spmenu; 00742 } 00743 00744 xxxSendMessage(pwndMenu, WM_INITMENU, (WPARAM)PtoH(pMenu), 0L); 00745 } 00746 00747 if (!ppopupmenu->fIsTrackPopup) { 00748 if (ppopupmenu->fIsSysMenu) { 00749 MNPositionSysMenu(pwndMenu, ppopupmenu->spmenu); 00750 } else if (ppopupmenu->fIsMenuBar) { 00751 ThreadLock(ppopupmenu->spmenu, &tlpmenu); 00752 xxxMNRecomputeBarIfNeeded(pwndMenu, ppopupmenu->spmenu); 00753 ThreadUnlock(&tlpmenu); 00754 MNPositionSysMenu(pwndMenu, ppopupmenu->spmenuAlternate); 00755 } 00756 } 00757 00758 /* 00759 * If returning TRUE, set menu style in pMenuState 00760 */ 00761 if (!ppopupmenu->fDestroyed) { 00762 if (TestMF(ppopupmenu->spmenu, MNS_MODELESS)) { 00763 pMenuState->fModelessMenu = TRUE; 00764 } 00765 00766 if (TestMF(ppopupmenu->spmenu, MNS_DRAGDROP)) { 00767 if (NT_SUCCESS(xxxClientLoadOLE())) { 00768 pMenuState->fDragAndDrop = TRUE; 00769 } 00770 } 00771 00772 if (TestMF(ppopupmenu->spmenu, MNS_AUTODISMISS)) { 00773 pMenuState->fAutoDismiss = TRUE; 00774 } 00775 00776 if (TestMF(ppopupmenu->spmenu, MNS_NOTIFYBYPOS)) { 00777 pMenuState->fNotifyByPos = TRUE; 00778 } 00779 00780 } 00781 00782 /* 00783 * Bogus! We don't always know that this is the system menu. We 00784 * will frequently pass on an OBJID_MENU even when you hit Alt+Space. 00785 * 00786 * Hence, MNSwitchToAlternate will send a EVENT_SYSTEM_MENUEND for the 00787 * menu bar and an EVENT_SYSTEM_MENUSTART for the sysmenu when we "switch". 00788 */ 00789 if (FWINABLE()) { 00790 xxxWindowEvent(EVENT_SYSTEM_MENUSTART, pwndMenu, 00791 (ppopupmenu->fIsSysMenu ? OBJID_SYSMENU : (ppopupmenu->fIsMenuBar ? OBJID_MENU : OBJID_WINDOW)), 00792 INDEXID_CONTAINER, 0); 00793 } 00794 00795 ThreadUnlock(&tlpwndMenu); 00796 00797 return !ppopupmenu->fDestroyed; 00798 } 00799 00800 // -------------------------------------------------------------------------- 00801 // 00802 // GetInitMenuParam() 00803 // 00804 // Gets the HMENU sent as the wParam of WM_INITMENU, and for menu bars, is 00805 // the actual menu to be interacted with. 00806 // 00807 // -------------------------------------------------------------------------- 00808 PMENU xxxGetInitMenuParam(PWND pwndMenu, BOOL * lpfSystem) 00809 { 00810 // 00811 // Find out what menu we should be sending in WM_INITMENU: 00812 // If minimized/child/empty menubar, use system menu 00813 // 00814 CheckLock(pwndMenu); 00815 00816 if (TestWF(pwndMenu, WFMINIMIZED) || 00817 TestwndChild(pwndMenu) || 00818 (pwndMenu->spmenu == NULL) || 00819 !pwndMenu->spmenu->cItems) 00820 { 00821 if (lpfSystem != NULL) 00822 *lpfSystem = TRUE; 00823 00824 return(xxxGetSysMenu(pwndMenu, FALSE)); 00825 } 00826 else 00827 { 00828 if (lpfSystem != NULL) 00829 *lpfSystem = FALSE; 00830 00831 return(pwndMenu->spmenu); 00832 } 00833 }

Generated on Sat May 15 19:40:52 2004 for test by doxygen 1.3.7