https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a59df3858cb3718be710a…
commit a59df3858cb3718be710a8782209c6d3c8462913
Author: Mark Jansen <mark.jansen(a)reactos.org>
AuthorDate: Sat Jun 15 21:14:41 2019 +0200
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Tue Aug 6 21:17:35 2019 +0200
[WIN32SS] Rewrite MENU_ShowPopup to take the exclude rectangle into account
CORE-15863
---
win32ss/user/ntuser/menu.c | 195 +++++++++++++++++++++++++++++++++------------
1 file changed, 146 insertions(+), 49 deletions(-)
diff --git a/win32ss/user/ntuser/menu.c b/win32ss/user/ntuser/menu.c
index ccd4d8cc058..c73151427c6 100644
--- a/win32ss/user/ntuser/menu.c
+++ b/win32ss/user/ntuser/menu.c
@@ -2860,16 +2860,57 @@ static BOOL MENU_InitPopup( PWND pWndOwner, PMENU menu, UINT flags
)
return TRUE;
}
+
+#define SHOW_DEBUGRECT 0
+
+#if SHOW_DEBUGRECT
+static void DebugRect(const RECT* rectl, COLORREF color)
+{
+ HBRUSH brush;
+ RECT rr;
+ HDC hdc;
+
+ if (!rectl)
+ return;
+
+ hdc = UserGetDCEx(NULL, 0, DCX_USESTYLE);
+
+ brush = IntGdiCreateSolidBrush(color);
+
+ rr = *rectl;
+ RECTL_vInflateRect(&rr, 1, 1);
+ FrameRect(hdc, rectl, brush);
+ FrameRect(hdc, &rr, brush);
+
+ NtGdiDeleteObjectApp(brush);
+ UserReleaseDC(NULL, hdc, TRUE);
+}
+
+static void DebugPoint(INT x, INT y, COLORREF color)
+{
+ RECT rr = {x, y, x, y};
+ DebugRect(&rr, color);
+}
+#endif
+
+static BOOL RECTL_Intersect(const RECT* pRect, INT x, INT y, UINT width, UINT height)
+{
+ RECT other = {x, y, x + width, y + height};
+ RECT dum;
+
+ return RECTL_bIntersectRect(&dum, pRect, &other);
+}
+
/***********************************************************************
* MenuShowPopup
*
* Display a popup menu.
*/
static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT flags,
- INT x, INT y)
+ INT x, INT y, const RECT* pExclude)
{
UINT width, height;
- POINT pt;
+ POINT ptx;
PMONITOR monitor;
PWND pWnd;
USER_REFERENCE_ENTRY Ref;
@@ -2884,6 +2925,11 @@ static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu,
UINT id, UINT fl
menu->iItem = NO_SELECTED_ITEM;
}
+#if SHOW_DEBUGRECT
+ if (pExclude)
+ DebugRect(pExclude, RGB(255, 0, 0));
+#endif
+
menu->dwArrowsOn = 0;
MENU_PopupMenuCalcSize(menu, pwndOwner);
@@ -2892,61 +2938,106 @@ static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu,
UINT id, UINT fl
width = menu->cxMenu + UserGetSystemMetrics(SM_CXBORDER);
height = menu->cyMenu + UserGetSystemMetrics(SM_CYBORDER);
- /* FIXME: should use item rect */
- pt.x = x;
- pt.y = y;
- monitor = UserMonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
-
if (flags & TPM_LAYOUTRTL)
flags ^= TPM_RIGHTALIGN;
- if( flags & TPM_RIGHTALIGN ) x -= width;
- if( flags & TPM_CENTERALIGN ) x -= width / 2;
+ if (flags & TPM_RIGHTALIGN)
+ x -= width;
+ if (flags & TPM_CENTERALIGN)
+ x -= width / 2;
- if( flags & TPM_BOTTOMALIGN ) y -= height;
- if( flags & TPM_VCENTERALIGN ) y -= height / 2;
+ if (flags & TPM_BOTTOMALIGN)
+ y -= height;
+ if (flags & TPM_VCENTERALIGN)
+ y -= height / 2;
- if( x + width > monitor->rcMonitor.right)
+ /* FIXME: should use item rect */
+ ptx.x = x;
+ ptx.y = y;
+#if SHOW_DEBUGRECT
+ DebugPoint(x, y, RGB(0, 0, 255));
+#endif
+ monitor = UserMonitorFromPoint( ptx, MONITOR_DEFAULTTONEAREST );
+
+ /* We are off the right side of the screen */
+ if (x + width > monitor->rcMonitor.right)
{
- if( x + width > monitor->rcMonitor.right)
- {
- /* If we would flip around our origin, would we go off screen on the other
side?
- Or is our origin itself too far to the right already? */
- if (!bIsPopup || x - width < monitor->rcMonitor.left || x >
monitor->rcMonitor.right)
- x = monitor->rcMonitor.right - width;
- else
- x -= width;
- }
+ if ((x - width) < monitor->rcMonitor.left || x >=
monitor->rcMonitor.right || bIsPopup)
+ x = monitor->rcMonitor.right - width;
+ else
+ x -= width;
}
- if( x < monitor->rcMonitor.left )
+
+ /* We are off the left side of the screen */
+ if (x < monitor->rcMonitor.left)
{
- /* If we would flip around our origin, would we go off screen on the other side?
*/
- if (!bIsPopup || x + width > monitor->rcMonitor.right)
+ /* Re-orient the menu around the x-axis */
+ x += width;
+
+ if (x < monitor->rcMonitor.left || x >= monitor->rcMonitor.right ||
bIsPopup)
x = monitor->rcMonitor.left;
+ }
+
+ /* Same here, but then the top */
+ if (y < monitor->rcMonitor.top)
+ {
+ y += height;
+
+ if (y < monitor->rcMonitor.top || y >= monitor->rcMonitor.bottom ||
bIsPopup)
+ y = monitor->rcMonitor.top;
+ }
+
+ /* And the bottom */
+ if (y + height > monitor->rcMonitor.bottom)
+ {
+ if ((y - height) < monitor->rcMonitor.top || y >=
monitor->rcMonitor.bottom || bIsPopup)
+ y = monitor->rcMonitor.bottom - height;
else
- x += width;
+ y -= height;
}
- if( y + height > monitor->rcMonitor.bottom)
+ if (pExclude || bIsPopup)
{
- if( y + height > monitor->rcMonitor.bottom)
+ RECT PopupOrigin = {x-1, y-1, x+1, y+1};
+ RECT Cleaned;
+
+ if (RECTL_bIntersectRect(&Cleaned, pExclude ? pExclude : &PopupOrigin,
&monitor->rcMonitor) &&
+ RECTL_Intersect(&Cleaned, x, y, width, height))
{
- /* If we would flip around our origin, would we go off screen on the other
side?
- Or is our origin itself too far to the bottom already? */
- if (!bIsPopup || y - height < monitor->rcMonitor.top || y >
monitor->rcMonitor.bottom)
- y = monitor->rcMonitor.bottom - height;
+ /* Figure out if we should move vertical or horizontal */
+ if (flags & TPM_VERTICAL)
+ {
+ /* Move in the vertical direction: TPM_BOTTOMALIGN means drop it above,
otherways drop it below */
+ if (flags & TPM_BOTTOMALIGN)
+ {
+ y = Cleaned.top - height;
+ }
+ else
+ {
+ y = Cleaned.bottom;
+ }
+ }
else
- y -= height;
+ {
+ /* Move in the horizontal direction: TPM_RIGHTALIGN means drop it to the
left, otherways go right */
+ if (flags & TPM_RIGHTALIGN)
+ {
+ x = Cleaned.left - width;
+ }
+ else
+ {
+ x = Cleaned.right;
+ }
+ }
}
}
- if( y < monitor->rcMonitor.top )
+
+#if SHOW_DEBUGRECT
{
- /* If we would flip around our origin, would we go off screen on the other side?
*/
- if (!bIsPopup || y + height > monitor->rcMonitor.bottom)
- y = monitor->rcMonitor.top;
- else
- y += height;
+ RECT rr = {x, y, x + width, y + height};
+ DebugRect(&rr, RGB(0, 255, 0));
}
+#endif
pWnd = ValidateHwndNoErr( menu->hWnd );
@@ -3194,7 +3285,7 @@ static void FASTCALL MENU_HideSubPopups(PWND pWndOwner, PMENU Menu,
*/
static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFirst, UINT
Flags)
{
- RECT Rect;
+ RECT Rect, ParentRect;
ITEM *Item;
HDC Dc;
PWND pWnd;
@@ -3229,6 +3320,14 @@ static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu,
BOOL SelectFi
pWnd = ValidateHwndNoErr(Menu->hWnd);
+ ParentRect = Rect;
+ if (pWnd)
+ {
+ POINT pt = {0, 0};
+ IntClientToScreen(pWnd, &pt);
+ RECTL_vOffsetRect(&ParentRect, pt.x, pt.y);
+ }
+
/* correct item if modified as a reaction to WM_INITMENUPOPUP message */
if (!(Item->fState & MF_HILITE))
{
@@ -3305,7 +3404,7 @@ static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu,
BOOL SelectFi
MENU_InitPopup( WndOwner, Item->spSubMenu, Flags );
MENU_ShowPopup( WndOwner, Item->spSubMenu, Menu->iItem, Flags,
- Rect.left, Rect.top);
+ Rect.left, Rect.top, &ParentRect);
if (SelectFirst)
{
MENU_MoveSelection(WndOwner, Item->spSubMenu, ITEM_NEXT);
@@ -3905,7 +4004,7 @@ static void FASTCALL MENU_KeyRight(MTRACKER *pmt, UINT Flags, UINT
msg)
* Menu tracking code.
*/
static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x, INT y,
- PWND pwnd, const RECT *lprect )
+ PWND pwnd)
{
MSG msg;
BOOL fRemove;
@@ -3928,9 +4027,8 @@ static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x,
INT y,
mt.Pt.x = x;
mt.Pt.y = y;
- TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
- UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd), lprect ?
lprect->left : 0, lprect ? lprect->top : 0,
- lprect ? lprect->right : 0, lprect ? lprect->bottom : 0);
+ TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x\n",
+ UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd));
pti->MessageQueue->QF_flags &= ~QF_ACTIVATIONCHANGE;
@@ -4341,7 +4439,7 @@ VOID MENU_TrackMouseMenuBar( PWND pWnd, ULONG ht, POINT pt)
MENU_InitTracking(pWnd, pMenu, FALSE, wFlags);
/* fetch the window menu again, it may have changed */
pMenu = (ht == HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pWnd) ) :
IntGetMenu( UserHMGetHandle(pWnd) );
- MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd, NULL);
+ MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd);
MENU_ExitTracking(pWnd, FALSE, wFlags);
}
}
@@ -4405,7 +4503,7 @@ VOID MENU_TrackKbdMenuBar(PWND pwnd, UINT wParam, WCHAR wChar)
}
track_menu:
- MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd, NULL );
+ MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd );
MENU_ExitTracking( pwnd, FALSE, wFlags);
}
@@ -4447,9 +4545,8 @@ BOOL WINAPI IntTrackPopupMenuEx( PMENU menu, UINT wFlags, int x, int
y,
if (menu->fFlags & MNF_SYSMENU)
MENU_InitSysMenuPopup( menu, pWnd->style, pWnd->pcls->style,
HTSYSMENU);
- if (MENU_ShowPopup(pWnd, menu, 0, wFlags | TPM_POPUPMENU, x, y))
- ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd,
- lpTpm ? &lpTpm->rcExclude : NULL);
+ if (MENU_ShowPopup(pWnd, menu, 0, wFlags | TPM_POPUPMENU, x, y, lpTpm ?
&lpTpm->rcExclude : NULL))
+ ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd);
else
{
MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);