test: mnpopup.c File Reference

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

# mnpopup.c File Reference

`#include "precomp.h"`

Go to the source code of this file.

## Defines

#define | RECT_ONLEFT 0
#define | RECT_ONTOP 1
#define | RECT_ONRIGHT 2
#define | RECT_ONBOTTOM 3
#define | RECT_ORG 4

## Functions

BOOL | TryRect (UINT wRect, int x, int y, int cx, int cy, LPRECT prcExclude, LPPOINT ppt, PMONITOR pMonitor)
int | xxxTrackPopupMenuEx (PMENU pMenu, UINT dwFlags, int x, int y, PWND pwndOwner, CONST TPMPARAMS *lpTpm)
LONG | FindBestPos (int x, int y, int cx, int cy, LPRECT prcExclude, UINT wFlags, PPOPUPMENU ppopupmenu, PMONITOR pMonitor)

## Define Documentation

#define RECT_ONBOTTOM 3

| Definition at line 19 of file mnpopup.c. Referenced by FindBestPos(), and TryRect().

#define RECT_ONLEFT 0

| Definition at line 16 of file mnpopup.c. Referenced by FindBestPos(), and TryRect().

#define RECT_ONRIGHT 2

| Definition at line 18 of file mnpopup.c. Referenced by FindBestPos(), and TryRect().

#define RECT_ONTOP 1

| Definition at line 17 of file mnpopup.c. Referenced by FindBestPos(), and TryRect().

#define RECT_ORG 4

| Definition at line 20 of file mnpopup.c. Referenced by FindBestPos().

## Function Documentation

LONG FindBestPos | ( | int | x,
|  | int | y,
|  | int | cx,
|  | int | cy,
|  | LPRECT | prcExclude,
|  | UINT | wFlags,
|  | PPOPUPMENU | ppopupmenu,
|  | PMONITOR | pMonitor
| ) |

Definition at line 496 of file mnpopup.c.

References COPY_FLAG, CopyRect, cy, tagPOPUPMENU::iDropDir, IntersectRect(), NULL, PAS_DOWN, PAS_HORZ, PAS_LEFT, PAS_RIGHT, PAS_UP, PAS_VERT, tagMONITOR::rcMonitor, RECT_ONBOTTOM, RECT_ONLEFT, RECT_ONRIGHT, RECT_ONTOP, RECT_ORG, SetRect(), TryRect(), and UINT.

Referenced by xxxMenuWindowProc(), and xxxTrackPopupMenuEx().

    00505 {
    00506     int iRect;
    00507     int iT;
    00508     UINT awRect[4];
    00509     POINT ptT;
    00510     RECT rcExclude;
    00511     //
    00512     // Clip our coords on screen first.  We use the same algorithm to clip
    00513     // as in Win3.1 for dudes with no exclude rect.
    00514     //
    00515
    00516     if (prcExclude!=NULL) {
    00517         // Clip exclude rect to monitor!
    00518         CopyRect(&rcExclude, prcExclude);
    00519         IntersectRect(&rcExclude, &rcExclude, &pMonitor->rcMonitor);
    00520     } else {
    00521         SetRect(&rcExclude, x, y, x, y);
    00522     }
    00523
    00524
    00525     /*
    00526      * Make sure popup fits completely on the screen
    00527      * At least the x,y point will be on the screen.
    00528      */
    00529     if (x + cx > pMonitor->rcMonitor.right) {
    00530         if ((wFlags & TPM_CENTERALIGN)
    00531                 || (x - cx < pMonitor->rcMonitor.left)
    00532                 || (x >= pMonitor->rcMonitor.right)) {
    00533             x = pMonitor->rcMonitor.right - cx;
    00534         } else {
    00535             x -= cx;
    00536         }
    00537         if (ppopupmenu->iDropDir & PAS_HORZ) {
    00538             COPY_FLAG(ppopupmenu->iDropDir, PAS_LEFT, PAS_HORZ);
    00539         }
    00540     }
    00541
    00542     if (x < pMonitor->rcMonitor.left) {
    00543         x += cx;
    00544         if ((wFlags & TPM_CENTERALIGN)
    00545                 || (x >= pMonitor->rcMonitor.right)
    00546                 || (x < pMonitor->rcMonitor.left)) {
    00547             x = pMonitor->rcMonitor.left;
    00548         }
    00549         if (ppopupmenu->iDropDir & PAS_HORZ) {
    00550             COPY_FLAG(ppopupmenu->iDropDir, PAS_RIGHT, PAS_HORZ);
    00551         }
    00552     }
    00553
    00554
    00555     if (y + cy > pMonitor->rcMonitor.bottom) {
    00556         if ((wFlags & TPM_VCENTERALIGN)
    00557                 || (y - cy < pMonitor->rcMonitor.top)
    00558                 || (y >= pMonitor->rcMonitor.bottom)) {
    00559             y = pMonitor->rcMonitor.bottom - cy;
    00560         } else {
    00561             y -= cy;
    00562         }
    00563         if (ppopupmenu->iDropDir & PAS_VERT) {
    00564             COPY_FLAG(ppopupmenu->iDropDir, PAS_UP, PAS_VERT);
    00565         }
    00566     }
    00567
    00568     if (y < pMonitor->rcMonitor.top) {
    00569         y += cy;
    00570         if ((wFlags & TPM_VCENTERALIGN)
    00571                 || (y >= pMonitor->rcMonitor.bottom)
    00572                 || (y < pMonitor->rcMonitor.top)) {
    00573             y = pMonitor->rcMonitor.top;
    00574         }
    00575         if (ppopupmenu->iDropDir & PAS_VERT) {
    00576             COPY_FLAG(ppopupmenu->iDropDir, PAS_DOWN, PAS_VERT);
    00577         }
    00578     }
    00579
    00580     //
    00581     // Try first point
    00582     //
    00583     if (TryRect(RECT_ORG, x, y, cx, cy, &rcExclude, &ptT, pMonitor))
    00584         goto FOUND;
    00585
    00586     //
    00587     // Sort possibilities.  Get offset of horizontal rects.
    00588     //
    00589     iRect = (wFlags & TPM_VERTICAL) ? 2 : 0;
    00590
    00591     //
    00592     // Sort horizontally.  Note that we treat TPM_CENTERALIGN like
    00593     // TPM_LEFTALIGN.
    00594     //
    00595     //
    00596     // If we're right-aligned, try to right-align on left side first.
    00597     // Otherwise, try to left-align on right side first.
    00598     //
    00599     iT = (wFlags & TPM_RIGHTALIGN) ? 0 : 2;
    00600
    00601     awRect[0 + iRect] = RECT_ONLEFT + iT;
    00602     awRect[1 + iRect] = RECT_ONRIGHT - iT;
    00603
    00604     //
    00605     // Sort vertically.  Note that we treat TPM_VCENTERALIGN like
    00606     // TPM_TOPALIGN.
    00607     //
    00608     // If we're bottom-aligned, try to bottom-align with top of rect
    00609     // first.  Otherwise, try to top-align with bottom of exclusion first.
    00610     //
    00611     iT = (wFlags & TPM_BOTTOMALIGN) ? 0 : 2;
    00612
    00613     awRect[2 - iRect] = RECT_ONTOP + iT;
    00614     awRect[3 - iRect] = RECT_ONBOTTOM - iT;
    00615
    00616     //
    00617     // Loop through sorted alternatives.  Note that TryRect fails immediately
    00618     // if an exclusion coordinate is too close to screen edge.
    00619     //
    00620
    00621     for (iRect = 0; iRect < 4; iRect++) {
    00622         if (TryRect(awRect[iRect], x, y, cx, cy, &rcExclude, &ptT, pMonitor)) {
    00623             switch (awRect[iRect])
    00624             {
    00625                 case RECT_ONTOP:
    00626                     ppopupmenu->iDropDir = PAS_UP;
    00627                     break;
    00628                 case RECT_ONLEFT:
    00629                     ppopupmenu->iDropDir = PAS_LEFT;
    00630                     break;
    00631                 case RECT_ONBOTTOM:
    00632                     ppopupmenu->iDropDir = PAS_DOWN;
    00633                     break;
    00634                 case RECT_ONRIGHT:
    00635                     ppopupmenu->iDropDir = PAS_RIGHT;
    00636                     break;
    00637             }
    00638
    00639             x = ptT.x;
    00640             y = ptT.y;
    00641             break;
    00642         }
    00643     }
    00644
    00645 FOUND:
    00646     return MAKELONG(x, y);
    00647 }

BOOL TryRect | ( | UINT | wRect,
|  | int | x,
|  | int | y,
|  | int | cx,
|  | int | cy,
|  | LPRECT | prcExclude,
|  | LPPOINT | ppt,
|  | PMONITOR | pMonitor
| ) |

Definition at line 661 of file mnpopup.c.

References cy, FALSE, IntersectRect(), tagMONITOR::rcMonitor, RECT_ONBOTTOM, RECT_ONLEFT, RECT_ONRIGHT, and RECT_ONTOP.

Referenced by FindBestPos().

    00670 {
    00671     RECT rcTry;
    00672
    00673     switch (wRect) {
    00674         case RECT_ONRIGHT:
    00675             x = prcExclude->right;
    00676             if (x + cx > pMonitor->rcMonitor.right)
    00677                 return FALSE;
    00678             break;
    00679
    00680         case RECT_ONBOTTOM:
    00681             y = prcExclude->bottom;
    00682             if (y + cy > pMonitor->rcMonitor.bottom)
    00683                 return FALSE;
    00684             break;
    00685
    00686         case RECT_ONLEFT:
    00687             x = prcExclude->left - cx;
    00688             if (x < pMonitor->rcMonitor.left)
    00689                 return FALSE;
    00690             break;
    00691
    00692         case RECT_ONTOP:
    00693             y = prcExclude->top - cy;
    00694             if (y < pMonitor->rcMonitor.top)
    00695                 return FALSE;
    00696             break;
    00697
    00698         //
    00699         // case RECT_ORG:
    00700         //      NOP;
    00701         //      break;
    00702         //
    00703     }
    00704
    00705     ppt->x = x;
    00706     ppt->y = y;
    00707
    00708     rcTry.left      = x;
    00709     rcTry.top       = y;
    00710     rcTry.right     = x + cx;
    00711     rcTry.bottom    = y + cy;
    00712
    00713     return(!IntersectRect(&rcTry, &rcTry, prcExclude));
    00714 }

int xxxTrackPopupMenuEx | ( | PMENU | pMenu,
|  | UINT | dwFlags,
|  | int | x,
|  | int | y,
|  | PWND | pwndOwner,
|  | CONST TPMPARAMS * | lpTpm
| ) |

Definition at line 52 of file mnpopup.c.

References _GetKeyState(), _KillTimer(), _MonitorFromPoint(), BOOL, CheckLock, ClrWF, dwFlags, tagLASTINPUT::dwFlags, ExitMenuLoop(), FALSE, tagMENUSTATE::fButtonDown, tagPOPUPMENU::fDelayedFree, tagMENUSTATE::fDragAndDrop, tagPOPUPMENU::fDroppedLeft, tagPOPUPMENU::fFirstClick, FindBestPos(), tagPOPUPMENU::fIsSysMenu, tagPOPUPMENU::fIsTrackPopup, tagMENUSTATE::fModelessMenu, tagPOPUPMENU::fNoNotify, tagPOPUPMENU::fRightButton, tagPOPUPMENU::fSendUninit, tagPOPUPMENU::fShowTimer, tagPOPUPMENU::fSynchronous, tagMENUSTATE::fUnderline, FWINABLE, GET_X_LPARAM, GET_Y_LPARAM, GETPTI, glinp, HW, tagPOPUPMENU::iDropDir, IDSYS_MNSHOW, L, LINP_KEYBOARD, Lock, LockPopupMenu(), MENUCLASS, MFRTL, MFUNDERLINE, MNAnimate(), MNSW_SIZE, MOUSEHOLD, NULL, PAS_DOWN, PAS_HORZ, PAS_LEFT, PAS_OUT, PAS_RIGHT, PAS_UP, PAS_VERT, tagMENUSTATE::pGlobalPopupMenu, PlayEventSound(), tagTHREADINFO::pMenuState, tagPOPUPMENU::ppopupmenuRoot, tagTHREADINFO::pq, PtiCurrent, tagMENUSTATE::ptiMenuStateOwner, PtoHq, PWND_TOP, PWND_TOPMOST, QF_CAPTURELOCKED, tagQ::QF_flags, SetMF, SetWF, tagPOPUPMENU::spmenu, tagPOPUPMENU::spwndActivePopup, tagPOPUPMENU::spwndNotify, tagPOPUPMENU::spwndPopupMenu, SYSMET, TestMF, TestWF, ThreadLock, ThreadLockAlways, ThreadUnlock, TRUE, USER_SOUND_MENUPOPUP, WFDESTROYED, WFOLDUI, xxxClientRegisterDragDrop(), xxxCreateWindowEx(), xxxDestroyWindow(), xxxMNAllocMenuState(), xxxMNEndMenuState(), xxxMNLoop(), xxxMNReleaseCapture(), xxxMNStartMenu(), xxxSendMessage(), xxxSetWindowPos(), and xxxWindowEvent().

Referenced by NtUserTrackPopupMenuEx(), xxxDefWindowProc(), and xxxDoScrollMenu().

    00059 {
    00060     PMENUSTATE      pMenuState;
    00061     PWND            pwndHierarchy;
    00062     PPOPUPMENU      ppopupMenuHierarchy;
    00063     LONG            sizeHierarchy;
    00064     int             cxPopup,
    00065                     cyPopup;
    00066     BOOL            fSync;
    00067     int             cmd;
    00068     BOOL            fButtonDown;
    00069     TL              tlpwndHierarchy;
    00070     TL              tlpwndT;
    00071     RECT            rcExclude;
    00072     PTHREADINFO     ptiCurrent,
    00073                     ptiOwner;
    00074     PMONITOR        pMonitor;
    00075     POINT           pt;
    00076
    00077     CheckLock(pMenu);
    00078     CheckLock(pwndOwner);
    00079
    00080     /*
    00081      * Capture the things we care about in case lpTpm goes away.
    00082      */
    00083     if (lpTpm != NULL) {
    00084         if (lpTpm->cbSize != sizeof(TPMPARAMS)) {
    00085             RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "TrackPopupMenuEx: cbSize is invalid");
    00086             return(FALSE);
    00087         }
    00088         rcExclude = lpTpm->rcExclude;
    00089     }
    00090
    00091     ptiCurrent = PtiCurrent();
    00092     ptiOwner = GETPTI(pwndOwner);
    00093
    00094     /*
    00095      * Win95 compatibility: pwndOwner must be owned by ptiCurrent.
    00096      */
    00097     if (ptiCurrent != ptiOwner) {
    00098         RIPMSG0(RIP_WARNING, "xxxTrackPopupMenuEx: pwndOwner not owned by ptiCurrent");
    00099         return FALSE;
    00100     }
    00101
    00102     UserAssert(pMenu != NULL);
    00103     if (ptiCurrent->pMenuState != NULL) {
    00104
    00105         if (dwFlags & TPM_RECURSE) {
    00106             /*
    00107              * Only allow recursion if:
    00108              *  -The current menu mode is not about to exit
    00109              *  -Both menus notify the same window
    00110              *  -Only one thread is involved in the current menu mode
    00111              * This will prevent us from getting into some random
    00112              *  scenarios we don't want to deal with
    00113              */
    00114            ppopupMenuHierarchy = ptiCurrent->pMenuState->pGlobalPopupMenu;
    00115            pwndHierarchy = ppopupMenuHierarchy->spwndNotify;
    00116            if (ExitMenuLoop(ptiCurrent->pMenuState, ppopupMenuHierarchy)
    00117                 || (pwndHierarchy == NULL)
    00118                 || (pwndHierarchy != pwndOwner)
    00119                 || (ptiCurrent->pMenuState->ptiMenuStateOwner != GETPTI(pwndHierarchy))) {
    00120
    00121                RIPMSG0(RIP_WARNING, "xxxTrackPopupMenuEx: Failing TPM_RECURSE request");
    00122                return FALSE;
    00123            }
    00124            /*
    00125             * Terminate any animation
    00126             */
    00127             MNAnimate(ptiCurrent->pMenuState, FALSE);
    00128            /*
    00129             * Cancel pending show timer if any. ie, the app wants to
    00130             *  pop up a context menu on a popup before we drop it.
    00131             */
    00132            ppopupMenuHierarchy = ((ppopupMenuHierarchy->spwndActivePopup != NULL)
    00133                                   ? ((PMENUWND)(ppopupMenuHierarchy->spwndActivePopup))->ppopupmenu
    00134                                   : NULL);
    00135            if ((ppopupMenuHierarchy != NULL) && ppopupMenuHierarchy->fShowTimer) {
    00136
    00137                 _KillTimer(ppopupMenuHierarchy->spwndPopupMenu, IDSYS_MNSHOW);
    00138                 ppopupMenuHierarchy->fShowTimer = FALSE;
    00139            }
    00140            /*
    00141             * If we're currently on a modal menu, let's unlock the capture
    00142             *  so the recursive menu can get it.
    00143             */
    00144            if (!ptiCurrent->pMenuState->fModelessMenu) {
    00145                ptiCurrent->pq->QF_flags &= ~QF_CAPTURELOCKED;
    00146            }
    00147         } else {
    00148             /*
    00149              * Allow only one guy to have a popup menu up at a time...
    00150              */
    00151             RIPERR0(ERROR_POPUP_ALREADY_ACTIVE, RIP_VERBOSE, "");
    00152             return FALSE;
    00153        }
    00154    }
    00155
    00156     // Is button down?
    00157
    00158     if (dwFlags & TPM_RIGHTBUTTON)
    00159     {
    00160         fButtonDown = (_GetKeyState(VK_RBUTTON) & 0x8000) != 0;
    00161     } else {
    00162         fButtonDown = (_GetKeyState(VK_LBUTTON) & 0x8000) != 0;
    00163     }
    00164
    00165     /*
    00166      * Create the menu window.
    00167      */
    00168     pwndHierarchy = xxxCreateWindowEx(
    00169             WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE,
    00170             (PLARGE_STRING)MENUCLASS,
    00171             NULL,
    00172             WS_POPUP | WS_BORDER,
    00173             x, y, 100, 100,
    00174             TestMF(pMenu, MNS_MODELESS) ? pwndOwner : NULL,
    00175             NULL, (HANDLE)pwndOwner->hModule,
    00176             NULL,
    00177             WINVER);
    00178
    00179     if (pwndHierarchy == NULL) {
    00180         return FALSE;
    00181     }
    00182
    00183 #ifdef USE_MIRRORING
    00184     if (TestWF(pwndOwner, WEFLAYOUTRTL))
    00185         SetWF(pwndHierarchy, WEFLAYOUTRTL);
    00186 #endif
    00187
    00188     //
    00189     // Do this so that old apps don't get weird borders on tracked popups due
    00190     // to the app hack used in CreateWindowEx32.
    00191     //
    00192     ClrWF(pwndHierarchy, WFOLDUI);
    00193
    00194     ThreadLockAlways(pwndHierarchy, &tlpwndHierarchy);
    00195
    00196 #ifdef HAVE_MN_GETPPOPUPMENU
    00197     ppopupMenuHierarchy = (PPOPUPMENU)xxxSendMessage(pwndHierarchy,
    00198                                                 MN_GETPPOPUPMENU, 0, 0);
    00199 #else
    00200     ppopupMenuHierarchy = ((PMENUWND)pwndHierarchy)->ppopupmenu;
    00201 #endif
    00202
    00203
    00204     ppopupMenuHierarchy->fDelayedFree = TRUE;
    00205     Lock(&(ppopupMenuHierarchy->spwndNotify), pwndOwner);
    00206     LockPopupMenu(ppopupMenuHierarchy, &ppopupMenuHierarchy->spmenu, pMenu);
    00207     Lock(&(ppopupMenuHierarchy->spwndActivePopup), pwndHierarchy);
    00208     ppopupMenuHierarchy->ppopupmenuRoot = ppopupMenuHierarchy;
    00209     ppopupMenuHierarchy->fIsTrackPopup  = TRUE;
    00210     ppopupMenuHierarchy->fFirstClick = fButtonDown;
    00211     ppopupMenuHierarchy->fRightButton   = ((dwFlags & TPM_RIGHTBUTTON) != 0);
    00212     if (SYSMET(MENUDROPALIGNMENT) || TestMF(pMenu, MFRTL)) {
    00213        //
    00214        // popup's below this one need to follow the same direction as
    00215        // the other menu's on the desktop.
    00216        //
    00217        ppopupMenuHierarchy->fDroppedLeft = TRUE;
    00218     }
    00219     ppopupMenuHierarchy->fNoNotify      = ((dwFlags & TPM_NONOTIFY) != 0);
    00220
    00221     if (fSync = (dwFlags & TPM_RETURNCMD))
    00222         ppopupMenuHierarchy->fSynchronous = TRUE;
    00223
    00224     ppopupMenuHierarchy->fIsSysMenu =  ((dwFlags & TPM_SYSMENU) != 0);
    00225
    00226     // Set the GlobalPopupMenu variable so that EndMenu works for popupmenus so
    00227     // that WinWart II people can continue to abuse undocumented functions.
    00228     // This is nulled out in MNCancel.
    00229     /*
    00230      * This is actually needed for cleanup in case this thread ends
    00231      *  execution before we can free the popup. (See xxxDestroyThreadInfo)
    00232      *
    00233      * Note that one thread might own pwndOwner and another one might call
    00234      *  TrackPopupMenu (pretty normal if the two threads are attached). So
    00235      *  properly setting (and initializing) pMenuState is a must here.
    00236      */
    00237     pMenuState = xxxMNAllocMenuState(ptiCurrent, ptiOwner, ppopupMenuHierarchy);
    00238     if (pMenuState == NULL) {
    00239         /*
    00240          * Get out. The app never knew we were here so don't notify it
    00241          */
    00242         dwFlags |= TPM_NONOTIFY;
    00243         goto AbortTrackPopupMenuEx;
    00244     }
    00245
    00246     /*
    00247      * Notify the app we are entering menu mode.  wParam is 1 since this is a
    00248      * TrackPopupMenu.
    00249      */
    00250
    00251     if (!ppopupMenuHierarchy->fNoNotify)
    00252         xxxSendMessage(pwndOwner, WM_ENTERMENULOOP,
    00253             (ppopupMenuHierarchy->fIsSysMenu ? FALSE : TRUE), 0);
    00254
    00255     /*
    00256      * Send off the WM_INITMENU, set ourselves up for menu mode etc...
    00257      */
    00258     if (!xxxMNStartMenu(ppopupMenuHierarchy, MOUSEHOLD)) {
    00259         /*
    00260          * ppopupMenuHierarchy has been destroyed already; let's bail
    00261          */
    00262         goto AbortTrackPopupMenuEx;
    00263     }
    00264
    00265     /*
    00266      * If drag and drop, register the window as a target.
    00267      */
    00268     if (pMenuState->fDragAndDrop) {
    00269         if (!SUCCEEDED(xxxClientRegisterDragDrop(HW(pwndHierarchy)))) {
    00270             RIPMSG0(RIP_ERROR, "xxxTrackPopupMenuEx: xxxClientRegisterDragDrop failed");
    00271         }
    00272     }
    00273
    00274     if (!ppopupMenuHierarchy->fNoNotify) {
    00275         ThreadLock(ppopupMenuHierarchy->spwndNotify, &tlpwndT);
    00276         xxxSendMessage(ppopupMenuHierarchy->spwndNotify, WM_INITMENUPOPUP,
    00277             (WPARAM)PtoHq(pMenu), MAKELONG(0, (ppopupMenuHierarchy->fIsSysMenu ? 1: 0)));
    00278         ThreadUnlock(&tlpwndT);
    00279         ppopupMenuHierarchy->fSendUninit = TRUE;
    00280     }
    00281
    00282     /*
    00283      * Size the menu window if needed...
    00284      */
    00285     sizeHierarchy = (LONG)xxxSendMessage(pwndHierarchy, MN_SIZEWINDOW, MNSW_SIZE, 0);
    00286
    00287     if (!sizeHierarchy) {
    00288
    00289 AbortTrackPopupMenuEx:
    00290         if (FWINABLE()) {
    00291             xxxWindowEvent(EVENT_SYSTEM_MENUEND, pwndOwner, OBJID_WINDOW, INDEXID_CONTAINER, 0);
    00292         }
    00293         /*
    00294          * Release the mouse capture we set when we called StartMenuState...
    00295          */
    00296         xxxMNReleaseCapture();
    00297
    00298         /* Notify the app we have exited menu mode.  wParam is 1 for real
    00299          * tracked popups, not sys menu.  Check wFlags since ppopupHierarchy
    00300          * will be gone.
    00301          */
    00302         if (!(dwFlags & TPM_NONOTIFY))
    00303             xxxSendMessage(pwndOwner, WM_EXITMENULOOP, ((dwFlags & TPM_SYSMENU) ?
    00304                 FALSE : TRUE), 0L);
    00305
    00306         /*
    00307          * Make sure we return failure
    00308          */
    00309         fSync = TRUE;
    00310         cmd = FALSE;
    00311         goto CleanupTrackPopupMenuEx;
    00312     }
    00313
    00314     if (glinp.dwFlags & LINP_KEYBOARD) {
    00315         pMenuState->fUnderline = TRUE;
    00316         SetMF(pMenu, MFUNDERLINE);
    00317     }
    00318
    00319     //
    00320     // Setup popup window dimensions
    00321     //
    00322     cxPopup = LOWORD(sizeHierarchy) + 2*SYSMET(CXFIXEDFRAME);
    00323     cyPopup = HIWORD(sizeHierarchy) + 2*SYSMET(CYFIXEDFRAME);
    00324
    00325     //
    00326     // Calculate the monitor BEFORE we adjust the point.  Otherwise, we might
    00327     // move the point offscreen.  In which case, we will end up pinning the
    00328     // popup to the primary display, which is wrong.
    00329     //
    00330     pt.x = x;
    00331     pt.y = y;
    00332     pMonitor = _MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
    00333
    00334     //
    00335     // Horizontal alignment
    00336     //
    00337 #ifdef USE_MIRRORING
    00338     if (TestWF(pwndOwner, WEFLAYOUTRTL) && !(dwFlags & TPM_CENTERALIGN)) {
    00339         dwFlags = dwFlags ^ TPM_RIGHTALIGN;
    00340     }
    00341 #endif
    00342     if (dwFlags & TPM_RIGHTALIGN) {
    00343 #if DBG
    00344         if (dwFlags & TPM_CENTERALIGN) {
    00345             RIPMSG0(RIP_WARNING, "TrackPopupMenuEx:  TPM_CENTERALIGN ignored");
    00346         }
    00347 #endif // DBG
    00348
    00349         x -= cxPopup;
    00350         ppopupMenuHierarchy->iDropDir = PAS_LEFT;
    00351     } else if (dwFlags & TPM_CENTERALIGN) {
    00352         x -= (cxPopup / 2);
    00353     } else {
    00354         ppopupMenuHierarchy->iDropDir = (ppopupMenuHierarchy->fDroppedLeft ? PAS_LEFT : PAS_RIGHT);
    00355     }
    00356
    00357     //
    00358     // Vertical alignment
    00359     //
    00360     if (dwFlags & TPM_BOTTOMALIGN) {
    00361 #if DBG
    00362         if (dwFlags & TPM_VCENTERALIGN) {
    00363             RIPMSG0(RIP_WARNING, "TrackPopupMenuEx:  TPM_VCENTERALIGN ignored");
    00364         }
    00365 #endif // DBG
    00366
    00367         y -= cyPopup;
    00368         ppopupMenuHierarchy->iDropDir |= PAS_UP;
    00369     } else if (dwFlags & TPM_VCENTERALIGN) {
    00370         y -= (cyPopup / 2);
    00371     } else {
    00372         ppopupMenuHierarchy->iDropDir |= PAS_DOWN;
    00373     }
    00374     /*
    00375      * If the caller provided an animation direction, use that instead
    00376      */
    00377     if (dwFlags & TPM_ANIMATIONBITS) {
    00378         ppopupMenuHierarchy->iDropDir = ((dwFlags >> TPM_FIRSTANIBITPOS) & (PAS_VERT | PAS_HORZ));
    00379     }
    00380     //
    00381     // Get coords to move to.
    00382     //
    00383     sizeHierarchy = FindBestPos(
    00384             x,
    00385             y,
    00386             cxPopup,
    00387             cyPopup,
    00388             ((lpTpm != NULL) ? &rcExclude : NULL),
    00389             dwFlags,
    00390             ppopupMenuHierarchy,
    00391             pMonitor);
    00392
    00393 #ifdef USE_MIRRORING
    00394     if (TestWF(pwndOwner, WEFLAYOUTRTL) && (ppopupMenuHierarchy->iDropDir & PAS_HORZ)) {
    00395         ppopupMenuHierarchy->iDropDir ^= PAS_HORZ;
    00396     }
    00397 #endif
    00398
    00399     /*
    00400      * If we have an animation direction and the caller wants animation,
    00401      *  set the bit to get it going.
    00402      */
    00403     if ((ppopupMenuHierarchy->iDropDir != 0) && !(dwFlags & TPM_NOANIMATION)) {
    00404         ppopupMenuHierarchy->iDropDir |= PAS_OUT;
    00405     }
    00406
    00407     /*
    00408      * Show the window. Modeless menus are not topmost and get activated.
    00409      *  Modal menus are topmost but don't get activated.
    00410      */
    00411     PlayEventSound(USER_SOUND_MENUPOPUP);
    00412     xxxSetWindowPos(pwndHierarchy,
    00413             (pMenuState->fModelessMenu ? PWND_TOP : PWND_TOPMOST),
    00414             GET_X_LPARAM(sizeHierarchy), GET_Y_LPARAM(sizeHierarchy), 0, 0,
    00415             SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOOWNERZORDER
    00416             | (pMenuState->fModelessMenu ? 0 : SWP_NOACTIVATE));
    00417
    00418     if (FWINABLE()) {
    00419         xxxWindowEvent(EVENT_SYSTEM_MENUPOPUPSTART, pwndHierarchy, OBJID_CLIENT, INDEXID_CONTAINER, 0);
    00420     }
    00421     //
    00422     // We need to return TRUE for compatibility w/ async TrackPopupMenu().
    00423     // It is conceivable that a menu ID could have ID 0, in which case just
    00424     // returning the cmd chosen would return FALSE instead of TRUE.
    00425     //
    00426
    00427     //
    00428     // If mouse is in client of popup, act like clicked down
    00429     //
    00430     pMenuState->fButtonDown = fButtonDown;
    00431
    00432     cmd = xxxMNLoop(ppopupMenuHierarchy, pMenuState, 0, FALSE);
    00433
    00434     /*
    00435      * If this is a modeless menu, return without clenning up because
    00436      *  the menu is up.
    00437      */
    00438     if (pMenuState->fModelessMenu) {
    00439         ThreadUnlock(&tlpwndHierarchy);
    00440         goto ReturnCmdOrTrue;
    00441     }
    00442
    00443 CleanupTrackPopupMenuEx:
    00444
    00445     if (ThreadUnlock(&tlpwndHierarchy)) {
    00446         if (!TestWF(pwndHierarchy, WFDESTROYED)) {
    00447             xxxDestroyWindow(pwndHierarchy);
    00448         }
    00449     }
    00450
    00451     if (pMenuState != NULL) {
    00452         xxxMNEndMenuState (TRUE);
    00453     }
    00454
    00455     /*
    00456      * Capture must be unlocked if no menu is active.
    00457      */
    00458     UserAssert(!(ptiCurrent->pq->QF_flags & QF_CAPTURELOCKED)
    00459             || ((ptiCurrent->pMenuState != NULL)
    00460                 && !ptiCurrent->pMenuState->fModelessMenu));
    00461
    00462
    00463 ReturnCmdOrTrue:
    00464     return(fSync ? cmd : TRUE);
    00465 }