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

mnloop.c File Reference

#include "precomp.h"

Go to the source code of this file.

Functions

BOOL xxxMNRemoveMessage (UINT message1, UINT message2)
BOOL xxxHandleMenuMessages (LPMSG lpmsg, PMENUSTATE pMenuState, PPOPUPMENU ppopupmenu)
void xxxEndMenuLoop (PMENUSTATE pMenuState, PPOPUPMENU ppopupmenu)
int xxxMNLoop (PPOPUPMENU ppopupmenu, PMENUSTATE pMenuState, LPARAM lParam, BOOL fDblClk)


Function Documentation

void xxxEndMenuLoop PMENUSTATE  pMenuState,
PPOPUPMENU  ppopupmenu
 

Definition at line 584 of file mnloop.c.

References BOOL, FALSE, tagPOPUPMENU::fInCancel, tagMENUSTATE::fInEndMenu, tagPOPUPMENU::fIsTrackPopup, tagMENUSTATE::fModelessMenu, tagMENUSTATE::fUnderline, GETPTI, gpqForeground, HRGN_FULL, IsRootPopupMenu(), NCA_ACTIVE, NCA_FORCEFRAMEOFF, NULL, tagTHREADINFO::pq, tagQ::spwndActive, tagPOPUPMENU::spwndNotify, TestWF, ThreadLock, ThreadLockAlways, ThreadUnlock, WFFRAMEON, xxxDrawMenuBarUnderlines(), xxxDWP_DoNCActivate(), xxxEndMenu(), and xxxMNDismiss().

Referenced by xxxCallHandleMenuMessages(), xxxDestroyThreadInfo(), xxxMenuWindowProc(), and xxxMNLoop().

00585 { 00586 00587 UserAssert(IsRootPopupMenu(ppopupmenu)); 00588 00589 if (ppopupmenu->fIsTrackPopup) { 00590 if (!ppopupmenu->fInCancel) { 00591 xxxMNDismiss(pMenuState); 00592 } 00593 } else { 00594 if (pMenuState->fUnderline) { 00595 TL tlpwnd; 00596 ThreadLock(ppopupmenu->spwndNotify, &tlpwnd); 00597 xxxDrawMenuBarUnderlines(ppopupmenu->spwndNotify, FALSE); 00598 ThreadUnlock(&tlpwnd); 00599 } 00600 if (!pMenuState->fInEndMenu) { 00601 xxxEndMenu(pMenuState); 00602 } 00603 } 00604 /* 00605 * If this is a modeless menu, make sure that the notification 00606 * window caption is drawn in the proper state 00607 */ 00608 if (pMenuState->fModelessMenu && (ppopupmenu->spwndNotify != NULL)) { 00609 PWND pwndNotify = ppopupmenu->spwndNotify; 00610 PTHREADINFO pti = GETPTI(pwndNotify); 00611 BOOL fFrameOn = (pti->pq == gpqForeground) 00612 && (pti->pq->spwndActive == pwndNotify); 00613 TL tlpwndNotify; 00614 00615 if (fFrameOn ^ !!TestWF(pwndNotify, WFFRAMEON)) { 00616 ThreadLockAlways(pwndNotify, &tlpwndNotify); 00617 xxxDWP_DoNCActivate(pwndNotify, 00618 (fFrameOn ? NCA_ACTIVE : NCA_FORCEFRAMEOFF), 00619 HRGN_FULL); 00620 ThreadUnlock(&tlpwndNotify); 00621 00622 } 00623 } 00624 }

BOOL xxxHandleMenuMessages LPMSG  lpmsg,
PMENUSTATE  pMenuState,
PPOPUPMENU  ppopupmenu
 

Definition at line 43 of file mnloop.c.

References _PostMessage(), BOOL, DWORD, ExitMenuLoop(), FALSE, tagMENUSTATE::fButtonAlwaysDown, tagMENUSTATE::fButtonDown, tagMENUSTATE::fDragAndDrop, tagMENUSTATE::fDragging, tagPOPUPMENU::fFirstClick, tagPOPUPMENU::fHasMenuBar, tagMENUSTATE::fIgnoreButtonUp, tagMENUSTATE::fInDoDragDrop, tagPOPUPMENU::fIsMenuBar, tagPOPUPMENU::fIsSysMenu, tagMENUSTATE::fModelessMenu, tagPOPUPMENU::fNoNotify, tagPOPUPMENU::fRightButton, tagPOPUPMENU::fToggle, GET_X_LPARAM, GET_Y_LPARAM, GetMenuStateWindow(), gwinOldAppHackoMaticFlags, InflateRect(), IsMFMWFPWindow(), KEYBDHOLD, L, LockMFMWFPWindow(), MFMWFP_ALTMENU, MFMWFP_NOITEM, MFMWFP_OFFMENU, tagMENUSTATE::mnFocus, MNIsItemSelected(), MOUSEHOLD, NULL, tagPOPUPMENU::posSelectedItem, tagMENUSTATE::ptButtonDown, PtiCurrent, PtInRect(), tagMENUSTATE::ptMouseLast, PtoH, QF_CAPTURELOCKED, tagPOPUPMENU::spmenu, tagPOPUPMENU::spwndActivePopup, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, SYSMET, ThreadLock, ThreadLockAlways, ThreadUnlock, TRUE, tagMENUSTATE::uButtonDownHitArea, tagMENUSTATE::uButtonDownIndex, UINT, Unlock, UnlockMFMWFPWindow(), tagMENUSTATE::vkButtonDown, WM_SYSTIMER, WOAHACK_CHECKALTKEYSTATE, WOAHACK_IGNOREALTKEYDOWN, xxxMNButtonDown(), xxxMNButtonUp(), xxxMNChar(), xxxMNDismiss(), xxxMNDoubleClick(), xxxMNFindWindowFromPoint(), xxxMNKeyDown(), xxxMNMouseMove(), xxxMNRemoveMessage(), xxxMNSwitchToAlternateMenu(), xxxSendMessage(), and xxxTranslateMessage().

Referenced by xxxCallHandleMenuMessages(), and xxxMNLoop().

00047 { 00048 DWORD ch; 00049 ULONG_PTR cmdHitArea; 00050 UINT cmdItem; 00051 LPARAM lParam; 00052 BOOL fThreadLock = FALSE; 00053 TL tlpwndHitArea; 00054 TL tlpwndT; 00055 POINT pt; 00056 PWND pwnd; 00057 RECT rc; 00058 00059 /* 00060 * Paranoia. Let's bail up front if we don't have a menu. 00061 * Some code checks for NULL spmenu, other parts assume it's always not NULL 00062 * Use RIP_ERROR for a while to make sure this is OK 00063 */ 00064 if (ppopupmenu->spmenu == NULL) { 00065 RIPMSG2(RIP_ERROR, "xxxHandleMenuMessages NULL spmenu. pMenuSate:%p ppopupmenu:%p", 00066 pMenuState, ppopupmenu); 00067 return FALSE; 00068 } 00069 /* 00070 * Get things out of the structure so that we can access them quicker. 00071 */ 00072 ch = (DWORD)lpmsg->wParam; 00073 lParam = lpmsg->lParam; 00074 00075 /* 00076 * In this switch statement, we only look at messages we want to handle and 00077 * swallow. Messages we don't understand will get translated and 00078 * dispatched. 00079 */ 00080 switch (lpmsg->message) { 00081 case WM_RBUTTONDOWN: 00082 case WM_NCRBUTTONDOWN: 00083 00084 if (ppopupmenu->fRightButton) { 00085 goto HandleButtonDown; 00086 } 00087 /* 00088 * Fall through 00089 */ 00090 case WM_RBUTTONDBLCLK: 00091 case WM_NCRBUTTONDBLCLK: 00092 /* 00093 * Right click outside the menu dismisses the menu 00094 * (we didn't use to do this for single right clicks on 4.0) 00095 */ 00096 pMenuState->mnFocus = MOUSEHOLD; 00097 cmdHitArea = xxxMNFindWindowFromPoint(ppopupmenu, &cmdItem, MAKEPOINTS(lParam)); 00098 if (cmdHitArea == MFMWFP_OFFMENU) { 00099 xxxMNDismiss(pMenuState); 00100 return TRUE; 00101 } 00102 /* 00103 * Do nothing on right clicks on the menu 00104 */ 00105 if (!pMenuState->fModelessMenu) { 00106 xxxMNRemoveMessage(lpmsg->message, 0); 00107 } 00108 return TRUE; 00109 00110 case WM_LBUTTONDOWN: 00111 case WM_NCLBUTTONDOWN: 00112 // Commented out due to TandyT whinings... 00113 // if ((ppopupmenu->trackPopupMenuFlags & TPM_RIGHTBUTTON)) 00114 // break; 00115 00116 HandleButtonDown: 00117 00118 /* 00119 * Find out where this mouse down occurred. 00120 */ 00121 pMenuState->mnFocus = MOUSEHOLD; 00122 pMenuState->ptMouseLast.x = GET_X_LPARAM(lParam); 00123 pMenuState->ptMouseLast.y = GET_Y_LPARAM(lParam); 00124 cmdHitArea = xxxMNFindWindowFromPoint(ppopupmenu, &cmdItem, MAKEPOINTS(lParam)); 00125 00126 00127 /* 00128 * Thread lock this if it is a pwnd. This certainly isn't the way 00129 * you'd implement this if you had locking to begin with. 00130 */ 00131 fThreadLock = IsMFMWFPWindow(cmdHitArea); 00132 if (fThreadLock) { 00133 ThreadLock((PWND)cmdHitArea, &tlpwndHitArea); 00134 } 00135 00136 /* 00137 * If this is a drag and drop menu, remember the mouse 00138 * position and the hit test results. 00139 */ 00140 if (pMenuState->fDragAndDrop) { 00141 pMenuState->ptButtonDown = pMenuState->ptMouseLast; 00142 pMenuState->uButtonDownIndex = cmdItem; 00143 LockMFMWFPWindow(&pMenuState->uButtonDownHitArea, cmdHitArea); 00144 } 00145 00146 /* 00147 * Modeless menus don't capture the mouse so we might not see 00148 * the button up. We also release capture when sending the 00149 * WM_MENUDODRAGDROP message. So we want to remember what 00150 * mouse button went down. 00151 */ 00152 if (pMenuState->fDragAndDrop || pMenuState->fModelessMenu) { 00153 if (ch & MK_RBUTTON) { 00154 pMenuState->vkButtonDown = VK_RBUTTON; 00155 } else { 00156 pMenuState->vkButtonDown = VK_LBUTTON; 00157 } 00158 } 00159 00160 00161 if ((cmdHitArea == MFMWFP_OFFMENU) && (cmdItem == 0)) { 00162 // 00163 // Clicked in middle of nowhere, so terminate menus, and 00164 // let button pass through. 00165 CancelOut: 00166 xxxMNDismiss(pMenuState); 00167 goto Unlock; 00168 } else if (ppopupmenu->fHasMenuBar && (cmdHitArea == MFMWFP_ALTMENU)) { 00169 // 00170 // Switching between menu bar & popup 00171 // 00172 xxxMNSwitchToAlternateMenu(ppopupmenu); 00173 cmdHitArea = MFMWFP_NOITEM; 00174 } 00175 00176 if (cmdHitArea == MFMWFP_NOITEM) { 00177 // 00178 // On menu bar (system or main) 00179 // 00180 xxxMNButtonDown(ppopupmenu, pMenuState, cmdItem, TRUE); 00181 } else { 00182 // On popup window menu 00183 UserAssert(cmdHitArea); 00184 xxxSendMessage((PWND)cmdHitArea, MN_BUTTONDOWN, cmdItem, 0L); 00185 } 00186 00187 /* 00188 * Swallow the message since we handled it. 00189 */ 00190 /* 00191 * The excel guys change a wm_rbuttondown to a wm_lbuttondown message 00192 * in their message filter hook. Remove the message here or we'll 00193 * get in a nasty loop. 00194 * 00195 * We need to swallow msg32.message ONLY. It is possible for 00196 * the LBUTTONDOWN to not be at the head of the input queue. 00197 * If not, we will swallow a WM_MOUSEMOVE or something else like 00198 * that. The reason Peek() doesn't need to check the range 00199 * is because we've already Peek(PM_NOYIELD'ed) before, which 00200 * locked the sys queue. 00201 */ 00202 if (!pMenuState->fModelessMenu) { 00203 xxxMNRemoveMessage(lpmsg->message, WM_RBUTTONDOWN); 00204 } 00205 goto Unlock; 00206 00207 case WM_MOUSEMOVE: 00208 case WM_NCMOUSEMOVE: 00209 00210 /* 00211 * Is the user starting to drag? 00212 */ 00213 if (pMenuState->fDragAndDrop 00214 && pMenuState->fButtonDown 00215 && !pMenuState->fDragging 00216 && !pMenuState->fButtonAlwaysDown 00217 && (pMenuState->uButtonDownHitArea != MFMWFP_OFFMENU)) { 00218 00219 /* 00220 * We expect the mouse to go down on a menu item before a drag can start 00221 */ 00222 UserAssert(!ppopupmenu->fFirstClick); 00223 00224 /* 00225 * Calculate drag detect rectangle using the position the mouse went 00226 * down on 00227 */ 00228 *(LPPOINT)&rc.left = pMenuState->ptButtonDown; 00229 *(LPPOINT)&rc.right = pMenuState->ptButtonDown; 00230 InflateRect(&rc, SYSMET(CXDRAG), SYSMET(CYDRAG)); 00231 00232 pt.x = GET_X_LPARAM(lParam); 00233 pt.y = GET_Y_LPARAM(lParam); 00234 00235 /* 00236 * If we've moved outside the drag rect, then the user is dragging 00237 */ 00238 if (!PtInRect(&rc, pt)) { 00239 /* 00240 * Post a message so we'll finish processing this message 00241 * and get out of here before telling the app that the user 00242 * is dragging 00243 */ 00244 pwnd = GetMenuStateWindow(pMenuState); 00245 if (pwnd != NULL) { 00246 pMenuState->fDragging = TRUE; 00247 _PostMessage(pwnd, MN_DODRAGDROP, 0, 0); 00248 } else { 00249 RIPMSG0(RIP_ERROR, "xxxMNMouseMove. Unble to post MN_DODGRAGDROP"); 00250 } 00251 } 00252 } /* if (pMenuState->fDragAndDrop */ 00253 00254 xxxMNMouseMove(ppopupmenu, pMenuState, MAKEPOINTS(lParam)); 00255 return TRUE; 00256 00257 case WM_RBUTTONUP: 00258 case WM_NCRBUTTONUP: 00259 if (ppopupmenu->fRightButton) { 00260 goto HandleButtonUp; 00261 } 00262 /* 00263 * If the button is down, simply swallow this message 00264 */ 00265 if (pMenuState->fButtonDown) { 00266 if (!pMenuState->fModelessMenu) { 00267 xxxMNRemoveMessage(lpmsg->message, 0); 00268 } 00269 return TRUE; 00270 } 00271 // New feature for shell start menu -- notify when a right click 00272 // occurs on a menu item, and open a window of opportunity for 00273 // menus to recurse, allowing them to popup a context-sensitive 00274 // menu for that item. (jeffbog 9/28/95) 00275 // 00276 // BUGBUG: need to add check for Nashville+ app 00277 if ((lpmsg->message == WM_RBUTTONUP) && !ppopupmenu->fNoNotify) { 00278 PPOPUPMENU ppopupActive; 00279 00280 if ((ppopupmenu->spwndActivePopup != NULL) 00281 && (ppopupActive = ((PMENUWND)(ppopupmenu->spwndActivePopup))->ppopupmenu) 00282 && MNIsItemSelected(ppopupActive)) 00283 { 00284 TL tlpwndNotify; 00285 ThreadLock( ppopupActive->spwndNotify, &tlpwndNotify ); 00286 xxxSendMessage(ppopupActive->spwndNotify, WM_MENURBUTTONUP, 00287 ppopupActive->posSelectedItem, (LPARAM)PtoH(ppopupActive->spmenu)); 00288 ThreadUnlock( &tlpwndNotify ); 00289 } 00290 } 00291 break; 00292 00293 case WM_LBUTTONUP: 00294 case WM_NCLBUTTONUP: 00295 // Commented out due to TandyT whinings... 00296 // if ((ppopupmenu->trackPopupMenuFlags & TPM_RIGHTBUTTON)) 00297 // break; 00298 00299 HandleButtonUp: 00300 if (!pMenuState->fButtonDown) { 00301 00302 /* 00303 * Don't care about this mouse up since we never saw the button 00304 * down for some reason. 00305 */ 00306 return TRUE; 00307 } 00308 00309 /* 00310 * Cancel the dragging state, if any. 00311 */ 00312 if (pMenuState->fDragAndDrop) { 00313 00314 UnlockMFMWFPWindow(&pMenuState->uButtonDownHitArea); 00315 pMenuState->fDragging = FALSE; 00316 00317 if (pMenuState->fIgnoreButtonUp) { 00318 pMenuState->fButtonDown = 00319 pMenuState->fIgnoreButtonUp = FALSE; 00320 return TRUE; 00321 } 00322 } 00323 00324 /* 00325 * Find out where this mouse up occurred. 00326 */ 00327 pMenuState->ptMouseLast.x = GET_X_LPARAM(lParam); 00328 pMenuState->ptMouseLast.y = GET_Y_LPARAM(lParam); 00329 cmdHitArea = xxxMNFindWindowFromPoint(ppopupmenu, &cmdItem, MAKEPOINTS(lParam)); 00330 00331 00332 /* 00333 * If this is not true, some the code below won't work right. 00334 */ 00335 UserAssert((cmdHitArea != MFMWFP_OFFMENU) || (cmdItem == 0)); 00336 UserAssert(cmdHitArea != 0x0000FFFF); 00337 00338 /* 00339 * Thread lock this if it is a pwnd. This certainly isn't the way 00340 * you'd implement this if you had locking to begin with. 00341 */ 00342 fThreadLock = IsMFMWFPWindow(cmdHitArea); 00343 if (fThreadLock) { 00344 ThreadLock((PWND)cmdHitArea, &tlpwndHitArea); 00345 } 00346 00347 00348 if (ppopupmenu->fHasMenuBar) { 00349 if (((cmdHitArea == MFMWFP_OFFMENU) && (cmdItem == 0)) || 00350 ((cmdHitArea == MFMWFP_NOITEM) && ppopupmenu->fIsSysMenu && ppopupmenu->fToggle)) 00351 // Button up occurred in some random spot. Terminate 00352 // menus and swallow the message. 00353 goto CancelOut; 00354 } else { 00355 if ((cmdHitArea == MFMWFP_OFFMENU) && (cmdItem == 0)) { 00356 if (!ppopupmenu->fFirstClick) { 00357 // 00358 // User upclicked in some random spot. Terminate 00359 // menus and don't swallow the message. 00360 // 00361 00362 // 00363 // Don't do anything with HWND here cuz the window is 00364 // destroyed after this SendMessage(). 00365 // 00366 // DONTREVALIDATE(); 00367 ThreadLock(ppopupmenu->spwndPopupMenu, &tlpwndT); 00368 xxxSendMessage(ppopupmenu->spwndPopupMenu, MN_CANCELMENUS, 0, 0); 00369 ThreadUnlock(&tlpwndT); 00370 goto Unlock; 00371 } 00372 } 00373 00374 ppopupmenu->fFirstClick = FALSE; 00375 } 00376 00377 if (cmdHitArea == MFMWFP_NOITEM) { 00378 // 00379 // This is a system menu or a menu bar and the button up 00380 // occurred on the system menu or on a menu bar item. 00381 // 00382 xxxMNButtonUp(ppopupmenu, pMenuState, cmdItem, 0); 00383 } else if ((cmdHitArea != MFMWFP_OFFMENU) && (cmdHitArea != MFMWFP_ALTMENU)) { 00384 // 00385 // Warning: It's common for the popup to go away during the 00386 // processing of this message, so don't add any code that 00387 // messes with hwnd after this call! 00388 // 00389 // DONTREVALIDATE(); 00390 00391 // 00392 // We send lParam (that has the mouse co-ords ) for the app 00393 // to get it in its SC_RESTORE/SC_MINIMIZE messages 3.0 00394 // compat 00395 // 00396 xxxSendMessage((PWND)cmdHitArea, MN_BUTTONUP, (DWORD)cmdItem, lParam); 00397 } else { 00398 pMenuState->fButtonDown = 00399 pMenuState->fButtonAlwaysDown = FALSE; 00400 } 00401 Unlock: 00402 if (fThreadLock) 00403 ThreadUnlock(&tlpwndHitArea); 00404 return TRUE; 00405 00406 00407 case WM_LBUTTONDBLCLK: 00408 case WM_NCLBUTTONDBLCLK: 00409 00410 // Commented out due to TandyT whinings... 00411 // if (ppopup->fRightButton) 00412 // break; 00413 pMenuState->mnFocus = MOUSEHOLD; 00414 cmdHitArea = xxxMNFindWindowFromPoint(ppopupmenu, &cmdItem, MAKEPOINTS(lParam)); 00415 if ((cmdHitArea == MFMWFP_OFFMENU) && (cmdItem == 0)) { 00416 // Dbl-clicked in middle of nowhere, so terminate menus, and 00417 // let button pass through. 00418 xxxMNDismiss(pMenuState); 00419 return TRUE; 00420 } else if (ppopupmenu->fHasMenuBar && (cmdHitArea == MFMWFP_ALTMENU)) { 00421 // 00422 // BOGUS 00423 // TREAT LIKE BUTTON DOWN since we didn't dblclk on same item. 00424 // 00425 xxxMNSwitchToAlternateMenu(ppopupmenu); 00426 cmdHitArea = MFMWFP_NOITEM; 00427 } 00428 00429 if (cmdHitArea == MFMWFP_NOITEM) 00430 xxxMNDoubleClick(pMenuState, ppopupmenu, cmdItem); 00431 else { 00432 UserAssert(cmdHitArea); 00433 00434 ThreadLock((PWND)cmdHitArea, &tlpwndHitArea); 00435 xxxSendMessage((PWND)cmdHitArea, MN_DBLCLK, 00436 (DWORD)cmdItem, 0L); 00437 ThreadUnlock(&tlpwndHitArea); 00438 } 00439 return TRUE; 00440 00441 case WM_KEYDOWN: 00442 case WM_SYSKEYDOWN: 00443 00444 /* 00445 * If mouse button is down, ignore keyboard input (fix #3899, IanJa) 00446 */ 00447 if (pMenuState->fButtonDown && (ch != VK_F1)) { 00448 00449 /* 00450 * Check if the user wants to cancel dragging. 00451 */ 00452 if (pMenuState->fDragging && (ch == VK_ESCAPE)) { 00453 RIPMSG0(RIP_WARNING, "xxxHandleMenuMessages: ESC while dragging"); 00454 pMenuState->fIgnoreButtonUp = TRUE; 00455 } 00456 00457 return TRUE; 00458 } 00459 pMenuState->mnFocus = KEYBDHOLD; 00460 switch (ch) { 00461 case VK_UP: 00462 case VK_DOWN: 00463 case VK_LEFT: 00464 case VK_RIGHT: 00465 case VK_RETURN: 00466 case VK_CANCEL: 00467 case VK_ESCAPE: 00468 case VK_MENU: 00469 case VK_F10: 00470 case VK_F1: 00471 if (ppopupmenu->spwndActivePopup) { 00472 ThreadLockAlways(ppopupmenu->spwndActivePopup, &tlpwndT); 00473 xxxSendMessage(ppopupmenu->spwndActivePopup, lpmsg->message, 00474 ch, 0L); 00475 ThreadUnlock(&tlpwndT); 00476 } else { 00477 xxxMNKeyDown(ppopupmenu, pMenuState, (UINT)ch); 00478 } 00479 break; 00480 00481 case VK_TAB: 00482 /* 00483 * People hit the ALT key now just to turn underlines ON in dialogs. 00484 * This throws them into "invisible menu mode". If they hit any char 00485 * at that point, we'll bail in xxxMNChar. But not so if they hit ctrl-tab, 00486 * which is used to navigate property sheets. So let's help them out. 00487 */ 00488 if (ppopupmenu->fIsMenuBar && (ppopupmenu->spwndActivePopup == NULL)) { 00489 xxxMNDismiss(pMenuState); 00490 return TRUE; 00491 } 00492 /* 00493 * Fall through 00494 */ 00495 00496 default: 00497 TranslateKey: 00498 if (!pMenuState->fModelessMenu) { 00499 xxxTranslateMessage(lpmsg, 0); 00500 } 00501 break; 00502 } 00503 return TRUE; 00504 00505 case WM_CHAR: 00506 case WM_SYSCHAR: 00507 if (ppopupmenu->spwndActivePopup) { 00508 ThreadLockAlways(ppopupmenu->spwndActivePopup, &tlpwndT); 00509 xxxSendMessage(ppopupmenu->spwndActivePopup, lpmsg->message, 00510 ch, 0L); 00511 ThreadUnlock(&tlpwndT); 00512 } else { 00513 xxxMNChar(ppopupmenu, pMenuState, (UINT)ch); 00514 } 00515 return TRUE; 00516 00517 case WM_SYSKEYUP: 00518 00519 /* 00520 * Ignore ALT and F10 keyup messages since they are handled on 00521 * the KEYDOWN message. 00522 */ 00523 if (ch == VK_MENU || ch == VK_F10) { 00524 if (gwinOldAppHackoMaticFlags & WOAHACK_CHECKALTKEYSTATE) { 00525 if (gwinOldAppHackoMaticFlags & WOAHACK_IGNOREALTKEYDOWN) { 00526 gwinOldAppHackoMaticFlags &= ~WOAHACK_IGNOREALTKEYDOWN; 00527 gwinOldAppHackoMaticFlags &= ~WOAHACK_CHECKALTKEYSTATE; 00528 } else 00529 gwinOldAppHackoMaticFlags |= WOAHACK_IGNOREALTKEYDOWN; 00530 } 00531 00532 return TRUE; 00533 } 00534 00535 /* 00536 ** fall thru ** 00537 */ 00538 00539 case WM_KEYUP: 00540 00541 /* 00542 * Do RETURNs on the up transition only 00543 */ 00544 goto TranslateKey; 00545 00546 case WM_SYSTIMER: 00547 00548 /* 00549 * Prevent the caret from flashing by eating all WM_SYSTIMER messages. 00550 */ 00551 return TRUE; 00552 00553 default: 00554 break; 00555 } 00556 00557 #if DBG 00558 /* 00559 * Nobody should be able to steal capture from modal menus. 00560 */ 00561 if (!pMenuState->fModelessMenu 00562 && !pMenuState->fInDoDragDrop 00563 && !ExitMenuLoop (pMenuState, ppopupmenu) ) { 00564 00565 UserAssert(PtiCurrent()->pq->QF_flags & QF_CAPTURELOCKED); 00566 UserAssert(PtiCurrent()->pq->spwndCapture == ppopupmenu->spwndNotify); 00567 } 00568 #endif 00569 00570 /* 00571 * We didn't handle this message 00572 */ 00573 return FALSE; 00574 }

int xxxMNLoop PPOPUPMENU  ppopupmenu,
PMENUSTATE  pMenuState,
LPARAM  lParam,
BOOL  fDblClk
 

Definition at line 635 of file mnloop.c.

References _CallMsgFilter(), _GetKeyState(), _GetMenuState(), _IsChild(), _PostMessage(), BOOL, tagMENUSTATE::cmdLast, DBGDecModalMenuCount, DecSFWLockCount(), DWORD, ExitMenuLoop(), FALSE, tagPOPUPMENU::fFlushDelayedFree, FindNCHit(), tagMENUSTATE::fInDoDragDrop, tagMENUSTATE::fInsideMenuLoop, tagPOPUPMENU::fIsMenuBar, tagPOPUPMENU::fIsSysMenu, tagPOPUPMENU::fIsTrackPopup, tagMENUSTATE::fMenuStarted, tagMENUSTATE::fModelessMenu, tagPOPUPMENU::fNoNotify, tagPOPUPMENU::fRightButton, tagMENUSTATE::hdcWndAni, HW, IsRootPopupMenu(), MNFlushDestroyedPopups(), MOUSEHOLD, msg, NULL, tagTHREADINFO::pq, PtiCurrent, tagTHREADINFO::ptLast, tagMENUSTATE::ptMouseLast, QF_ACTIVATIONCHANGE, QF_CAPTURELOCKED, tagQ::QF_flags, tagQ::spwndActive, tagPOPUPMENU::spwndActivePopup, tagQ::spwndCapture, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, TestWF, ThreadLock, ThreadLockAlways, ThreadUnlock, tagTHREADINFO::TIF_flags, TIF_IGNOREPLAYBACKDELAY, TRUE, Validateppopupmenu, WFVISIBLE, WM_SYSTIMER, xxxDispatchMessage(), xxxEndMenuLoop(), xxxGetSysMenuHandle(), xxxHandleMenuMessages(), xxxMNReleaseCapture(), xxxMNStartMenu(), xxxPeekMessage, xxxSendMessage(), xxxSendNotifyMessage(), xxxSleepThread(), and xxxTranslateMessage().

Referenced by xxxMNKeyFilter(), xxxSysCommand(), and xxxTrackPopupMenuEx().

00640 { 00641 int hit; 00642 MSG msg; 00643 BOOL fSendIdle = TRUE; 00644 BOOL fInQueue = FALSE; 00645 DWORD menuState; 00646 PTHREADINFO pti; 00647 TL tlpwndT; 00648 00649 UserAssert(IsRootPopupMenu(ppopupmenu)); 00650 00651 pMenuState->fInsideMenuLoop = TRUE; 00652 pMenuState->cmdLast = 0; 00653 00654 pti = PtiCurrent(); 00655 00656 pMenuState->ptMouseLast.x = pti->ptLast.x; 00657 pMenuState->ptMouseLast.y = pti->ptLast.y; 00658 00659 /* 00660 * Set flag to false, so that we can track if windows have 00661 * been activated since entering this loop. 00662 */ 00663 pti->pq->QF_flags &= ~QF_ACTIVATIONCHANGE; 00664 00665 /* 00666 * Were we called from xxxMenuKeyFilter? If not, simulate a LBUTTONDOWN 00667 * message to bring up the popup. 00668 */ 00669 if (!pMenuState->fMenuStarted) { 00670 if (_GetKeyState(((ppopupmenu->fRightButton) ? 00671 VK_RBUTTON : VK_LBUTTON)) >= 0) { 00672 00673 /* 00674 * We think the mouse button should be down but the call to get key 00675 * state says different so we need to get outta menu mode. This 00676 * happens if clicking on the menu causes a sys modal message box to 00677 * come up before we can enter this stuff. For example, run 00678 * winfile, click on drive a: to see its tree. Activate some other 00679 * app, then open drive a: and activate winfile by clicking on the 00680 * menu. This causes a sys modal msg box to come up just before 00681 * entering menu mode. The user may have the mouse button up but 00682 * menu mode code thinks it is down... 00683 */ 00684 00685 /* 00686 * Need to notify the app we are exiting menu mode because we told 00687 * it we were entering menu mode just before entering this function 00688 * in xxxSysCommand()... 00689 */ 00690 if (!ppopupmenu->fNoNotify) { 00691 ThreadLock(ppopupmenu->spwndNotify, &tlpwndT); 00692 xxxSendNotifyMessage(ppopupmenu->spwndNotify, WM_EXITMENULOOP, 00693 ((ppopupmenu->fIsTrackPopup && !ppopupmenu->fIsSysMenu) ? TRUE : FALSE), 0); 00694 ThreadUnlock(&tlpwndT); 00695 } 00696 goto ExitMenuLoop; 00697 } 00698 00699 /* 00700 * Simulate a WM_LBUTTONDOWN message. 00701 */ 00702 if (!ppopupmenu->fIsTrackPopup) { 00703 00704 /* 00705 * For TrackPopupMenus, we do it in the TrackPopupMenu function 00706 * itself so we don't want to do it again. 00707 */ 00708 if (!xxxMNStartMenu(ppopupmenu, MOUSEHOLD)) { 00709 goto ExitMenuLoop; 00710 } 00711 } 00712 00713 if ((ppopupmenu->fRightButton)) { 00714 msg.message = (fDblClk ? WM_RBUTTONDBLCLK : WM_RBUTTONDOWN); 00715 msg.wParam = MK_RBUTTON; 00716 } else { 00717 msg.message = (fDblClk ? WM_LBUTTONDBLCLK : WM_LBUTTONDOWN); 00718 msg.wParam = MK_LBUTTON; 00719 } 00720 msg.lParam = lParam; 00721 msg.hwnd = HW(ppopupmenu->spwndPopupMenu); 00722 xxxHandleMenuMessages(&msg, pMenuState, ppopupmenu); 00723 } 00724 00725 /* 00726 * If this is a modeless menu, release capture, mark it in the menu state 00727 * and return. Decrement foreground lock count. 00728 */ 00729 if (pMenuState->fModelessMenu) { 00730 xxxMNReleaseCapture(); 00731 00732 DecSFWLockCount(); 00733 DBGDecModalMenuCount(); 00734 return 0; 00735 } 00736 00737 while (pMenuState->fInsideMenuLoop) { 00738 00739 /* 00740 * Is a message waiting for us? 00741 */ 00742 BOOL fPeek = xxxPeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_NOREMOVE); 00743 00744 Validateppopupmenu(ppopupmenu); 00745 00746 if (fPeek) { 00747 /* 00748 * Bail if we have been forced out of menu loop 00749 */ 00750 if (ExitMenuLoop (pMenuState, ppopupmenu)) { 00751 goto ExitMenuLoop; 00752 } 00753 00754 /* 00755 * Since we could have blocked in xxxWaitMessage (see last line 00756 * of loop) or xxxPeekMessage, reset the cached copy of 00757 * ptiCurrent()->pq: It could have changed if someone did a 00758 * DetachThreadInput() while we were away. 00759 */ 00760 if ((!ppopupmenu->fIsTrackPopup && 00761 pti->pq->spwndActive != ppopupmenu->spwndNotify && 00762 ((pti->pq->spwndActive == NULL) || !_IsChild(pti->pq->spwndActive, ppopupmenu->spwndNotify)))) { 00763 00764 /* 00765 * End menu processing if we are no longer the active window. 00766 * This is needed in case a system modal dialog box pops up 00767 * while we are tracking the menu code for example. It also 00768 * helps out Tracer if a macro is executed while a menu is down. 00769 */ 00770 00771 /* 00772 * Also, end menu processing if we think the mouse button is 00773 * down but it really isn't. (Happens if a sys modal dialog int 00774 * time dlg box comes up while we are in menu mode.) 00775 */ 00776 00777 goto ExitMenuLoop; 00778 } 00779 00780 if (ppopupmenu->fIsMenuBar && msg.message == WM_LBUTTONDBLCLK) { 00781 00782 /* 00783 * Was the double click on the system menu or caption? 00784 */ 00785 hit = FindNCHit(ppopupmenu->spwndNotify, (LONG)msg.lParam); 00786 if (hit == HTCAPTION) { 00787 PWND pwnd; 00788 PMENU pmenu; 00789 00790 /* 00791 * Get the message out of the queue since we're gonna 00792 * process it. 00793 */ 00794 xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE); 00795 if (ExitMenuLoop (pMenuState, ppopupmenu)) { 00796 goto ExitMenuLoop; 00797 } else { 00798 pwnd = ppopupmenu->spwndNotify; 00799 ThreadLockAlways(pwnd, &tlpwndT); 00800 pmenu = xxxGetSysMenuHandle(pwnd); 00801 UserAssert(pwnd == ppopupmenu->spwndNotify); 00802 00803 menuState = _GetMenuState(pmenu, SC_RESTORE & 0x0000FFF0, 00804 MF_BYCOMMAND); 00805 00806 /* 00807 * Only send the sys command if the item is valid. If 00808 * the item doesn't exist or is disabled, then don't 00809 * post the syscommand. Note that for win2 apps, we 00810 * always send the sys command if it is a child window. 00811 * This is so hosebag apps can change the sys menu. 00812 */ 00813 if (!(menuState & MFS_GRAYED)) { 00814 _PostMessage(pwnd, WM_SYSCOMMAND, SC_RESTORE, 0); 00815 } 00816 00817 /* 00818 * Get out of menu mode. 00819 */ 00820 ThreadUnlock(&tlpwndT); 00821 goto ExitMenuLoop; 00822 } 00823 } 00824 } 00825 00826 fInQueue = (msg.message == WM_LBUTTONDOWN || 00827 msg.message == WM_RBUTTONDOWN || 00828 msg.message == WM_NCLBUTTONDOWN || 00829 msg.message == WM_NCRBUTTONDOWN); 00830 00831 if (!fInQueue) { 00832 00833 /* 00834 * Note that we call xxxPeekMessage() with the filter 00835 * set to the message we got from xxxPeekMessage() rather 00836 * than simply 0, 0. This prevents problems when 00837 * xxxPeekMessage() returns something like a WM_TIMER, 00838 * and after we get here to remove it a WM_LBUTTONDOWN, 00839 * or some higher-priority input message, gets in the 00840 * queue and gets removed accidently. Basically we want 00841 * to be sure we remove the right message in this case. 00842 * NT bug 3852 was caused by this problem. 00843 * Set the TIF_IGNOREPLAYBACKDELAY bit in case journal playback 00844 * is happening: this allows us to proceed even if the hookproc 00845 * incorrectly returns a delay now. The bit will be cleared if 00846 * this happens, so we can see why the Peek-Remove below fails. 00847 * Lotus' Freelance Graphics tutorial does such bad journalling 00848 */ 00849 00850 pti->TIF_flags |= TIF_IGNOREPLAYBACKDELAY; 00851 if (!xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE)) { 00852 if (pti->TIF_flags & TIF_IGNOREPLAYBACKDELAY) { 00853 pti->TIF_flags &= ~TIF_IGNOREPLAYBACKDELAY; 00854 /* 00855 * It wasn't a bad journal playback: something else 00856 * made the previously peeked message disappear before 00857 * we could peek it again to remove it. 00858 */ 00859 RIPMSG1(RIP_WARNING, "Disappearing msg 0x%08lx", msg.message); 00860 goto NoMsg; 00861 } 00862 } 00863 pti->TIF_flags &= ~TIF_IGNOREPLAYBACKDELAY; 00864 } 00865 00866 if (!_CallMsgFilter(&msg, MSGF_MENU)) { 00867 if (!xxxHandleMenuMessages(&msg, pMenuState, ppopupmenu)) { 00868 xxxTranslateMessage(&msg, 0); 00869 xxxDispatchMessage(&msg); 00870 } 00871 00872 Validateppopupmenu(ppopupmenu); 00873 00874 if (ExitMenuLoop (pMenuState, ppopupmenu)) { 00875 goto ExitMenuLoop; 00876 } 00877 00878 if (pti->pq->QF_flags & QF_ACTIVATIONCHANGE) { 00879 00880 /* 00881 * Run away and exit menu mode if another window has become 00882 * active while a menu was up. 00883 */ 00884 RIPMSG0(RIP_WARNING, "Exiting menu mode: another window activated"); 00885 goto ExitMenuLoop; 00886 } 00887 00888 #if DBG 00889 /* 00890 * Nobody should be able to still capture from us. 00891 */ 00892 if (!pMenuState->fInDoDragDrop) { 00893 UserAssert(pti->pq->QF_flags & QF_CAPTURELOCKED); 00894 UserAssert(pti->pq->spwndCapture == ppopupmenu->spwndNotify); 00895 } 00896 #endif 00897 00898 /* 00899 * If we get a system timer, then it's like we're idle 00900 */ 00901 if (msg.message == WM_SYSTIMER) { 00902 goto NoMsg; 00903 } 00904 00905 /* 00906 * Don't set fSendIdle if we got these messages 00907 */ 00908 if ((msg.message == WM_TIMER) || (msg.message == WM_PAINT)) { 00909 continue; 00910 } 00911 00912 } else { 00913 if (fInQueue) 00914 xxxPeekMessage(&msg, NULL, msg.message, msg.message, 00915 PM_REMOVE); 00916 } 00917 00918 /* 00919 * Reenable WM_ENTERIDLE messages. 00920 */ 00921 fSendIdle = TRUE; 00922 00923 } else { 00924 NoMsg: 00925 /* 00926 * Bail if we have been forced out of menu loop 00927 */ 00928 if (ExitMenuLoop (pMenuState, ppopupmenu)) { 00929 goto ExitMenuLoop; 00930 } 00931 00932 UserAssert((ppopupmenu->spwndActivePopup == NULL) 00933 || (TestWF(ppopupmenu->spwndActivePopup, WFVISIBLE))); 00934 00935 00936 /* 00937 * If a hierarchical popup has been destroyed, this is a 00938 * good time to flush ppmDelayedFree 00939 */ 00940 if (ppopupmenu->fFlushDelayedFree) { 00941 MNFlushDestroyedPopups (ppopupmenu, FALSE); 00942 ppopupmenu->fFlushDelayedFree = FALSE; 00943 } 00944 00945 /* 00946 * We need to send the WM_ENTERIDLE message only the first time 00947 * there are no messages for us to process. Subsequent times we 00948 * need to yield via WaitMessage(). This will allow other tasks to 00949 * get some time while we have a menu down. 00950 */ 00951 if (fSendIdle) { 00952 if (ppopupmenu->spwndNotify != NULL) { 00953 ThreadLockAlways(ppopupmenu->spwndNotify, &tlpwndT); 00954 xxxSendMessage(ppopupmenu->spwndNotify, WM_ENTERIDLE, MSGF_MENU, 00955 (LPARAM)HW(ppopupmenu->spwndActivePopup)); 00956 ThreadUnlock(&tlpwndT); 00957 } 00958 fSendIdle = FALSE; 00959 } else { 00960 /* 00961 * If we're animating, sleep only 1 ms to reduce the chance 00962 * of jerky animation. 00963 * When not animating, this is the same as a xxxWaitMessage call 00964 */ 00965 xxxSleepThread(QS_ALLINPUT | QS_EVENT, (pMenuState->hdcWndAni != NULL), TRUE); 00966 } 00967 00968 } /* if (PeekMessage(&msg, NULL, 0, 0, PM_NOYIELD)) else */ 00969 00970 } /* end while (fInsideMenuLoop) */ 00971 00972 00973 00974 ExitMenuLoop: 00975 pMenuState->fInsideMenuLoop = FALSE; 00976 pMenuState->fModelessMenu = FALSE; 00977 00978 /* 00979 * Make sure that the menu has been ended/canceled 00980 */ 00981 xxxEndMenuLoop (pMenuState, ppopupmenu); 00982 00983 xxxMNReleaseCapture(); 00984 00985 // Throw in an extra peek here when we exit the menu loop to ensure that the input queue 00986 // for this thread gets unlocked if there is no more input left for him. 00987 xxxPeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOYIELD | PM_NOREMOVE); 00988 return(pMenuState->cmdLast); 00989 } /* xxxMenuLoop() */

BOOL xxxMNRemoveMessage UINT  message1,
UINT  message2
 

Definition at line 22 of file mnloop.c.

References BOOL, FALSE, msg, NULL, TRUE, and xxxPeekMessage.

Referenced by xxxHandleMenuMessages().

00023 { 00024 MSG msg; 00025 if (!xxxPeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_NOREMOVE)) { 00026 return FALSE; 00027 } 00028 00029 if ((msg.message == message1) || (msg.message == message2)) { 00030 UserAssert(msg.message != 0); 00031 xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE); 00032 return TRUE; 00033 } else { 00034 return FALSE; 00035 } 00036 }


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