00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
#include "precomp.h"
00014
#pragma hdrstop
00015
00016 #define RECT_ONLEFT 0
00017 #define RECT_ONTOP 1
00018 #define RECT_ONRIGHT 2
00019 #define RECT_ONBOTTOM 3
00020 #define RECT_ORG 4
00021
00022
BOOL TryRect(
00023 UINT wRect,
00024
int x,
00025
int y,
00026
int cx,
00027
int cy,
00028 LPRECT prcExclude,
00029 LPPOINT ppt,
00030
PMONITOR pMonitor);
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 int xxxTrackPopupMenuEx(
00053
PMENU pMenu,
00054 UINT dwFlags,
00055
int x,
00056
int y,
00057
PWND pwndOwner,
00058 CONST TPMPARAMS *lpTpm)
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
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
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
00108
00109
00110
00111
00112
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
00126
00127
MNAnimate(ptiCurrent->
pMenuState,
FALSE);
00128
00129
00130
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
00142
00143
00144
if (!ptiCurrent->
pMenuState->
fModelessMenu) {
00145 ptiCurrent->
pq->
QF_flags &= ~
QF_CAPTURELOCKED;
00146 }
00147 }
else {
00148
00149
00150
00151 RIPERR0(ERROR_POPUP_ALREADY_ACTIVE, RIP_VERBOSE,
"");
00152
return FALSE;
00153 }
00154 }
00155
00156
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
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
00190
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
00215
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
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 pMenuState =
xxxMNAllocMenuState(ptiCurrent, ptiOwner, ppopupMenuHierarchy);
00238
if (pMenuState ==
NULL) {
00239
00240
00241
00242
dwFlags |= TPM_NONOTIFY;
00243
goto AbortTrackPopupMenuEx;
00244 }
00245
00246
00247
00248
00249
00250
00251
if (!ppopupMenuHierarchy->
fNoNotify)
00252
xxxSendMessage(pwndOwner, WM_ENTERMENULOOP,
00253 (ppopupMenuHierarchy->
fIsSysMenu ?
FALSE :
TRUE), 0);
00254
00255
00256
00257
00258
if (!
xxxMNStartMenu(ppopupMenuHierarchy,
MOUSEHOLD)) {
00259
00260
00261
00262
goto AbortTrackPopupMenuEx;
00263 }
00264
00265
00266
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
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
00295
00296
xxxMNReleaseCapture();
00297
00298
00299
00300
00301
00302
if (!(
dwFlags & TPM_NONOTIFY))
00303
xxxSendMessage(pwndOwner, WM_EXITMENULOOP, ((
dwFlags & TPM_SYSMENU) ?
00304
FALSE :
TRUE), 0
L);
00305
00306
00307
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
00321
00322 cxPopup = LOWORD(sizeHierarchy) + 2*
SYSMET(CXFIXEDFRAME);
00323 cyPopup = HIWORD(sizeHierarchy) + 2*
SYSMET(CYFIXEDFRAME);
00324
00325
00326
00327
00328
00329
00330 pt.x = x;
00331 pt.y = y;
00332 pMonitor =
_MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
00333
00334
00335
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
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
00376
00377
if (
dwFlags & TPM_ANIMATIONBITS) {
00378 ppopupMenuHierarchy->
iDropDir = ((
dwFlags >> TPM_FIRSTANIBITPOS) & (
PAS_VERT |
PAS_HORZ));
00379 }
00380
00381
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
00401
00402
00403
if ((ppopupMenuHierarchy->
iDropDir != 0) && !(
dwFlags & TPM_NOANIMATION)) {
00404 ppopupMenuHierarchy->
iDropDir |=
PAS_OUT;
00405 }
00406
00407
00408
00409
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
00423
00424
00425
00426
00427
00428
00429
00430 pMenuState->
fButtonDown = fButtonDown;
00431
00432 cmd =
xxxMNLoop(ppopupMenuHierarchy, pMenuState, 0,
FALSE);
00433
00434
00435
00436
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
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 }
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 LONG
00496 FindBestPos(
00497
int x,
00498
int y,
00499
int cx,
00500
int cy,
00501 LPRECT prcExclude,
00502 UINT wFlags,
00503
PPOPUPMENU ppopupmenu,
00504
PMONITOR pMonitor)
00505 {
00506
int iRect;
00507
int iT;
00508
UINT awRect[4];
00509 POINT ptT;
00510 RECT rcExclude;
00511
00512
00513
00514
00515
00516
if (prcExclude!=
NULL) {
00517
00518
CopyRect(&rcExclude, prcExclude);
00519
IntersectRect(&rcExclude, &rcExclude, &pMonitor->
rcMonitor);
00520 }
else {
00521
SetRect(&rcExclude, x, y, x, y);
00522 }
00523
00524
00525
00526
00527
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
00582
00583
if (
TryRect(
RECT_ORG, x, y, cx,
cy, &rcExclude, &ptT, pMonitor))
00584
goto FOUND;
00585
00586
00587
00588
00589 iRect = (wFlags & TPM_VERTICAL) ? 2 : 0;
00590
00591
00592
00593
00594
00595
00596
00597
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
00606
00607
00608
00609
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
00618
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 }
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
BOOL
00661 TryRect(
00662 UINT wRect,
00663
int x,
00664
int y,
00665
int cx,
00666
int cy,
00667 LPRECT prcExclude,
00668 LPPOINT ppt,
00669
PMONITOR pMonitor)
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
00700
00701
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 }