@@ -2860,16 +2860,103 @@ static BOOL MENU_InitPopup( PWND pWndOwner, PMENU menu, UINT flags )
2860
2860
return TRUE;
2861
2861
}
2862
2862
2863
+
2864
+ #define SHOW_DEBUGRECT 0
2865
+
2866
+ #if SHOW_DEBUGRECT
2867
+ static void DebugRect (const RECT * rectl , COLORREF color )
2868
+ {
2869
+ HBRUSH brush ;
2870
+ RECT rr ;
2871
+ HDC hdc ;
2872
+
2873
+ if (!rectl )
2874
+ return ;
2875
+
2876
+ hdc = UserGetDCEx (NULL , 0 , DCX_USESTYLE );
2877
+
2878
+ brush = IntGdiCreateSolidBrush (color );
2879
+
2880
+ rr = * rectl ;
2881
+ RECTL_vInflateRect (& rr , 1 , 1 );
2882
+ FrameRect (hdc , rectl , brush );
2883
+ FrameRect (hdc , & rr , brush );
2884
+
2885
+ NtGdiDeleteObjectApp (brush );
2886
+ UserReleaseDC (NULL , hdc , TRUE);
2887
+ }
2888
+
2889
+ static void DebugPoint (INT x , INT y , COLORREF color )
2890
+ {
2891
+ RECT rr = {x , y , x , y };
2892
+ DebugRect (& rr , color );
2893
+ }
2894
+ #endif
2895
+
2896
+ static BOOL RECTL_Intersect (const RECT * pRect , INT x , INT y , UINT width , UINT height )
2897
+ {
2898
+ RECT other = {x , y , x + width , y + height };
2899
+ RECT dum ;
2900
+
2901
+ return RECTL_bIntersectRect (& dum , pRect , & other );
2902
+ }
2903
+
2904
+ static BOOL MENU_MoveRect (UINT flags , INT * x , INT * y , INT width , INT height , const RECT * pExclude , PMONITOR monitor )
2905
+ {
2906
+ /* Figure out if we should move vertical or horizontal */
2907
+ if (flags & TPM_VERTICAL )
2908
+ {
2909
+ /* Move in the vertical direction: TPM_BOTTOMALIGN means drop it above, otherways drop it below */
2910
+ if (flags & TPM_BOTTOMALIGN )
2911
+ {
2912
+ if (pExclude -> top - height >= monitor -> rcMonitor .top )
2913
+ {
2914
+ * y = pExclude -> top - height ;
2915
+ return TRUE;
2916
+ }
2917
+ }
2918
+ else
2919
+ {
2920
+ if (pExclude -> bottom + height < monitor -> rcMonitor .bottom )
2921
+ {
2922
+ * y = pExclude -> bottom ;
2923
+ return TRUE;
2924
+ }
2925
+ }
2926
+ }
2927
+ else
2928
+ {
2929
+ /* Move in the horizontal direction: TPM_RIGHTALIGN means drop it to the left, otherways go right */
2930
+ if (flags & TPM_RIGHTALIGN )
2931
+ {
2932
+ if (pExclude -> left - width >= monitor -> rcMonitor .left )
2933
+ {
2934
+ * x = pExclude -> left - width ;
2935
+ return TRUE;
2936
+ }
2937
+ }
2938
+ else
2939
+ {
2940
+ if (pExclude -> right + width < monitor -> rcMonitor .right )
2941
+ {
2942
+ * x = pExclude -> right ;
2943
+ return TRUE;
2944
+ }
2945
+ }
2946
+ }
2947
+ return FALSE;
2948
+ }
2949
+
2863
2950
/***********************************************************************
2864
2951
* MenuShowPopup
2865
2952
*
2866
2953
* Display a popup menu.
2867
2954
*/
2868
2955
static BOOL FASTCALL MENU_ShowPopup (PWND pwndOwner , PMENU menu , UINT id , UINT flags ,
2869
- INT x , INT y )
2956
+ INT x , INT y , const RECT * pExclude )
2870
2957
{
2871
2958
UINT width , height ;
2872
- POINT pt ;
2959
+ POINT ptx ;
2873
2960
PMONITOR monitor ;
2874
2961
PWND pWnd ;
2875
2962
USER_REFERENCE_ENTRY Ref ;
@@ -2884,6 +2971,11 @@ static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT fl
2884
2971
menu -> iItem = NO_SELECTED_ITEM ;
2885
2972
}
2886
2973
2974
+ #if SHOW_DEBUGRECT
2975
+ if (pExclude )
2976
+ DebugRect (pExclude , RGB (255 , 0 , 0 ));
2977
+ #endif
2978
+
2887
2979
menu -> dwArrowsOn = 0 ;
2888
2980
MENU_PopupMenuCalcSize (menu , pwndOwner );
2889
2981
@@ -2892,61 +2984,102 @@ static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT fl
2892
2984
width = menu -> cxMenu + UserGetSystemMetrics (SM_CXBORDER );
2893
2985
height = menu -> cyMenu + UserGetSystemMetrics (SM_CYBORDER );
2894
2986
2895
- /* FIXME: should use item rect */
2896
- pt .x = x ;
2897
- pt .y = y ;
2898
- monitor = UserMonitorFromPoint ( pt , MONITOR_DEFAULTTONEAREST );
2899
-
2900
2987
if (flags & TPM_LAYOUTRTL )
2901
2988
flags ^= TPM_RIGHTALIGN ;
2902
2989
2903
- if ( flags & TPM_RIGHTALIGN ) x -= width ;
2904
- if ( flags & TPM_CENTERALIGN ) x -= width / 2 ;
2990
+ if (flags & TPM_RIGHTALIGN )
2991
+ x -= width ;
2992
+ if (flags & TPM_CENTERALIGN )
2993
+ x -= width / 2 ;
2905
2994
2906
- if ( flags & TPM_BOTTOMALIGN ) y -= height ;
2907
- if ( flags & TPM_VCENTERALIGN ) y -= height / 2 ;
2995
+ if (flags & TPM_BOTTOMALIGN )
2996
+ y -= height ;
2997
+ if (flags & TPM_VCENTERALIGN )
2998
+ y -= height / 2 ;
2908
2999
2909
- if ( x + width > monitor -> rcMonitor .right )
3000
+ /* FIXME: should use item rect */
3001
+ ptx .x = x ;
3002
+ ptx .y = y ;
3003
+ #if SHOW_DEBUGRECT
3004
+ DebugPoint (x , y , RGB (0 , 0 , 255 ));
3005
+ #endif
3006
+ monitor = UserMonitorFromPoint ( ptx , MONITOR_DEFAULTTONEAREST );
3007
+
3008
+ /* We are off the right side of the screen */
3009
+ if (x + width > monitor -> rcMonitor .right )
2910
3010
{
2911
- if ( x + width > monitor -> rcMonitor .right )
2912
- {
2913
- /* If we would flip around our origin, would we go off screen on the other side?
2914
- Or is our origin itself too far to the right already? */
2915
- if (!bIsPopup || x - width < monitor -> rcMonitor .left || x > monitor -> rcMonitor .right )
2916
- x = monitor -> rcMonitor .right - width ;
2917
- else
2918
- x -= width ;
2919
- }
3011
+ if ((x - width ) < monitor -> rcMonitor .left || x >= monitor -> rcMonitor .right )
3012
+ x = monitor -> rcMonitor .right - width ;
3013
+ else
3014
+ x -= width ;
2920
3015
}
2921
- if ( x < monitor -> rcMonitor .left )
3016
+
3017
+ /* We are off the left side of the screen */
3018
+ if (x < monitor -> rcMonitor .left )
2922
3019
{
2923
- /* If we would flip around our origin, would we go off screen on the other side? */
2924
- if (!bIsPopup || x + width > monitor -> rcMonitor .right )
3020
+ /* Re-orient the menu around the x-axis */
3021
+ x += width ;
3022
+
3023
+ if (x < monitor -> rcMonitor .left || x >= monitor -> rcMonitor .right || bIsPopup )
2925
3024
x = monitor -> rcMonitor .left ;
3025
+ }
3026
+
3027
+ /* Same here, but then the top */
3028
+ if (y < monitor -> rcMonitor .top )
3029
+ {
3030
+ y += height ;
3031
+
3032
+ if (y < monitor -> rcMonitor .top || y >= monitor -> rcMonitor .bottom || bIsPopup )
3033
+ y = monitor -> rcMonitor .top ;
3034
+ }
3035
+
3036
+ /* And the bottom */
3037
+ if (y + height > monitor -> rcMonitor .bottom )
3038
+ {
3039
+ if ((y - height ) < monitor -> rcMonitor .top || y >= monitor -> rcMonitor .bottom || bIsPopup )
3040
+ y = monitor -> rcMonitor .bottom - height ;
2926
3041
else
2927
- x += width ;
3042
+ y -= height ;
2928
3043
}
2929
3044
2930
- if ( y + height > monitor -> rcMonitor . bottom )
3045
+ if ( pExclude )
2931
3046
{
2932
- if ( y + height > monitor -> rcMonitor .bottom )
3047
+ RECT Cleaned ;
3048
+
3049
+ if (RECTL_bIntersectRect (& Cleaned , pExclude , & monitor -> rcMonitor ) &&
3050
+ RECTL_Intersect (& Cleaned , x , y , width , height ))
2933
3051
{
2934
- /* If we would flip around our origin, would we go off screen on the other side?
2935
- Or is our origin itself too far to the bottom already? */
2936
- if (!bIsPopup || y - height < monitor -> rcMonitor .top || y > monitor -> rcMonitor .bottom )
2937
- y = monitor -> rcMonitor .bottom - height ;
2938
- else
2939
- y -= height ;
3052
+ UINT flag_mods [] = {
3053
+ 0 , /* First try the 'normal' way */
3054
+ TPM_BOTTOMALIGN | TPM_RIGHTALIGN , /* Then try the opposite side */
3055
+ TPM_VERTICAL , /* Then swap horizontal / vertical */
3056
+ TPM_BOTTOMALIGN | TPM_RIGHTALIGN | TPM_VERTICAL , /* Then the other side again (still swapped hor/ver) */
3057
+ };
3058
+ UINT n ;
3059
+ for (n = 0 ; n < RTL_NUMBER_OF (flag_mods ); ++ n )
3060
+ {
3061
+ INT tx = x ;
3062
+ INT ty = y ;
3063
+
3064
+ /* Try to move a bit around */
3065
+ if (MENU_MoveRect (flags ^ flag_mods [n ], & tx , & ty , width , height , & Cleaned , monitor ) &&
3066
+ !RECTL_Intersect (& Cleaned , tx , ty , width , height ))
3067
+ {
3068
+ x = tx ;
3069
+ y = ty ;
3070
+ break ;
3071
+ }
3072
+ }
3073
+ /* If none worked, we go with the original x/y */
2940
3074
}
2941
3075
}
2942
- if ( y < monitor -> rcMonitor .top )
3076
+
3077
+ #if SHOW_DEBUGRECT
2943
3078
{
2944
- /* If we would flip around our origin, would we go off screen on the other side? */
2945
- if (!bIsPopup || y + height > monitor -> rcMonitor .bottom )
2946
- y = monitor -> rcMonitor .top ;
2947
- else
2948
- y += height ;
3079
+ RECT rr = {x , y , x + width , y + height };
3080
+ DebugRect (& rr , RGB (0 , 255 , 0 ));
2949
3081
}
3082
+ #endif
2950
3083
2951
3084
pWnd = ValidateHwndNoErr ( menu -> hWnd );
2952
3085
@@ -3194,7 +3327,7 @@ static void FASTCALL MENU_HideSubPopups(PWND pWndOwner, PMENU Menu,
3194
3327
*/
3195
3328
static PMENU FASTCALL MENU_ShowSubPopup (PWND WndOwner , PMENU Menu , BOOL SelectFirst , UINT Flags )
3196
3329
{
3197
- RECT Rect ;
3330
+ RECT Rect , ParentRect ;
3198
3331
ITEM * Item ;
3199
3332
HDC Dc ;
3200
3333
PWND pWnd ;
@@ -3229,6 +3362,13 @@ static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFi
3229
3362
3230
3363
pWnd = ValidateHwndNoErr (Menu -> hWnd );
3231
3364
3365
+ /* Grab the rect of our (entire) parent menu, so we can try to not overlap it */
3366
+ if (!IntGetWindowRect (pWnd , & ParentRect ))
3367
+ {
3368
+ ERR ("No pWnd\n" );
3369
+ ParentRect = Rect ;
3370
+ }
3371
+
3232
3372
/* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3233
3373
if (!(Item -> fState & MF_HILITE ))
3234
3374
{
@@ -3305,7 +3445,7 @@ static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFi
3305
3445
MENU_InitPopup ( WndOwner , Item -> spSubMenu , Flags );
3306
3446
3307
3447
MENU_ShowPopup ( WndOwner , Item -> spSubMenu , Menu -> iItem , Flags ,
3308
- Rect .left , Rect .top );
3448
+ Rect .left , Rect .top , & ParentRect );
3309
3449
if (SelectFirst )
3310
3450
{
3311
3451
MENU_MoveSelection (WndOwner , Item -> spSubMenu , ITEM_NEXT );
@@ -3905,7 +4045,7 @@ static void FASTCALL MENU_KeyRight(MTRACKER *pmt, UINT Flags, UINT msg)
3905
4045
* Menu tracking code.
3906
4046
*/
3907
4047
static INT FASTCALL MENU_TrackMenu (PMENU pmenu , UINT wFlags , INT x , INT y ,
3908
- PWND pwnd , const RECT * lprect )
4048
+ PWND pwnd )
3909
4049
{
3910
4050
MSG msg ;
3911
4051
BOOL fRemove ;
@@ -3928,9 +4068,8 @@ static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x, INT y,
3928
4068
mt .Pt .x = x ;
3929
4069
mt .Pt .y = y ;
3930
4070
3931
- TRACE ("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n" ,
3932
- UserHMGetHandle (pmenu ), wFlags , x , y , UserHMGetHandle (pwnd ), lprect ? lprect -> left : 0 , lprect ? lprect -> top : 0 ,
3933
- lprect ? lprect -> right : 0 , lprect ? lprect -> bottom : 0 );
4071
+ TRACE ("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x\n" ,
4072
+ UserHMGetHandle (pmenu ), wFlags , x , y , UserHMGetHandle (pwnd ));
3934
4073
3935
4074
pti -> MessageQueue -> QF_flags &= ~QF_ACTIVATIONCHANGE ;
3936
4075
@@ -4341,7 +4480,7 @@ VOID MENU_TrackMouseMenuBar( PWND pWnd, ULONG ht, POINT pt)
4341
4480
MENU_InitTracking (pWnd , pMenu , FALSE, wFlags );
4342
4481
/* fetch the window menu again, it may have changed */
4343
4482
pMenu = (ht == HTSYSMENU ) ? get_win_sys_menu ( UserHMGetHandle (pWnd ) ) : IntGetMenu ( UserHMGetHandle (pWnd ) );
4344
- MENU_TrackMenu (pMenu , wFlags , pt .x , pt .y , pWnd , NULL );
4483
+ MENU_TrackMenu (pMenu , wFlags , pt .x , pt .y , pWnd );
4345
4484
MENU_ExitTracking (pWnd , FALSE, wFlags );
4346
4485
}
4347
4486
}
@@ -4405,7 +4544,7 @@ VOID MENU_TrackKbdMenuBar(PWND pwnd, UINT wParam, WCHAR wChar)
4405
4544
}
4406
4545
4407
4546
track_menu :
4408
- MENU_TrackMenu ( TrackMenu , wFlags , 0 , 0 , pwnd , NULL );
4547
+ MENU_TrackMenu ( TrackMenu , wFlags , 0 , 0 , pwnd );
4409
4548
MENU_ExitTracking ( pwnd , FALSE, wFlags );
4410
4549
}
4411
4550
@@ -4447,9 +4586,8 @@ BOOL WINAPI IntTrackPopupMenuEx( PMENU menu, UINT wFlags, int x, int y,
4447
4586
if (menu -> fFlags & MNF_SYSMENU )
4448
4587
MENU_InitSysMenuPopup ( menu , pWnd -> style , pWnd -> pcls -> style , HTSYSMENU );
4449
4588
4450
- if (MENU_ShowPopup (pWnd , menu , 0 , wFlags | TPM_POPUPMENU , x , y ))
4451
- ret = MENU_TrackMenu ( menu , wFlags | TPM_POPUPMENU , 0 , 0 , pWnd ,
4452
- lpTpm ? & lpTpm -> rcExclude : NULL );
4589
+ if (MENU_ShowPopup (pWnd , menu , 0 , wFlags | TPM_POPUPMENU , x , y , lpTpm ? & lpTpm -> rcExclude : NULL ))
4590
+ ret = MENU_TrackMenu ( menu , wFlags | TPM_POPUPMENU , 0 , 0 , pWnd );
4453
4591
else
4454
4592
{
4455
4593
MsqSetStateWindow (pti , MSQ_STATE_MENUOWNER , NULL );
0 commit comments