From 95b76f510164ec8fbfe0f5ea9b1ed7df64f41e5d Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Sat, 11 Jun 2022 02:14:02 +0200 Subject: [PATCH] win32u: Move NtUserMenuItemFromPoint implementation from user32. Signed-off-by: Jacek Caban --- dlls/user32/menu.c | 14 +----- dlls/win32u/menu.c | 101 +++++++++++++++++++++++++++++++++++++--- dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 10 ++++ include/ntuser.h | 1 + 7 files changed, 110 insertions(+), 20 deletions(-) diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 73aee6b849d..a06ef21c634 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -4321,19 +4321,9 @@ DWORD WINAPI GetMenuContextHelpId( HMENU menu ) /********************************************************************** * MenuItemFromPoint (USER32.@) */ -INT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen) +INT WINAPI MenuItemFromPoint( HWND hwnd, HMENU menu, POINT pt ) { - POPUPMENU *menu = grab_menu_ptr(hMenu); - UINT pos; - - /*FIXME: Do we have to handle hWnd here? */ - if (!menu) return -1; - - if (MENU_FindItemByCoords( menu, ptScreen, &pos ) != ht_item) - pos = -1; - - release_menu_ptr(menu); - return pos; + return NtUserMenuItemFromPoint( hwnd, menu, pt.x, pt.y ); } diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c index 8367af32395..d84af186da9 100644 --- a/dlls/win32u/menu.c +++ b/dlls/win32u/menu.c @@ -40,6 +40,15 @@ struct accelerator ACCEL table[1]; }; +enum hittest +{ + ht_nowhere, /* outside the menu */ + ht_border, /* anywhere that's not an item or a scroll arrow */ + ht_item, /* a menu item */ + ht_scroll_up, /* scroll up arrow */ + ht_scroll_down /* scroll down arrow */ +}; + /* maximum allowed depth of any branch in the menu tree. * This value is slightly larger than in windows (25) to * stay on the safe side. */ @@ -424,6 +433,76 @@ static UINT find_submenu( HMENU *handle_ptr, HMENU target ) return NO_SELECTED_ITEM; } +/* Adjust menu item rectangle according to scrolling state */ +static void adjust_menu_item_rect( const POPUPMENU *menu, RECT *rect ) +{ + INT scroll_offset = menu->bScrolling ? menu->nScrollPos : 0; + OffsetRect( rect, menu->items_rect.left, menu->items_rect.top - scroll_offset ); +} + +/*********************************************************************** + * find_item_by_coords + * + * Find the item at the specified coordinates (screen coords). Does + * not work for child windows and therefore should not be called for + * an arbitrary system menu. + * + * Returns a hittest code. *pos will contain the position of the + * item or NO_SELECTED_ITEM. If the hittest code is ht_scroll_up + * or ht_scroll_down then *pos will contain the position of the + * item that's just outside the items_rect - ie, the one that would + * be scrolled completely into view. + */ +static enum hittest find_item_by_coords( const POPUPMENU *menu, POINT pt, UINT *pos ) +{ + enum hittest ht = ht_border; + MENUITEM *item; + RECT rect; + UINT i; + + *pos = NO_SELECTED_ITEM; + + if (!get_window_rect( menu->hWnd, &rect, get_thread_dpi() ) || !PtInRect( &rect, pt )) + return ht_nowhere; + + if (get_window_long( menu->hWnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) pt.x = rect.right - 1 - pt.x; + else pt.x -= rect.left; + pt.y -= rect.top; + + if (!PtInRect( &menu->items_rect, pt )) + { + if (!menu->bScrolling || pt.x < menu->items_rect.left || pt.x >= menu->items_rect.right) + return ht_border; + + /* On a scroll arrow. Update pt so that it points to the item just outside items_rect */ + if (pt.y < menu->items_rect.top) + { + ht = ht_scroll_up; + pt.y = menu->items_rect.top - 1; + } + else + { + ht = ht_scroll_down; + pt.y = menu->items_rect.bottom; + } + } + + item = menu->items; + for (i = 0; i < menu->nItems; i++, item++) + { + rect = item->rect; + adjust_menu_item_rect( menu, &rect ); + if (PtInRect( &rect, pt )) + { + *pos = i; + if (ht != ht_scroll_up && ht != ht_scroll_down) ht = ht_item; + break; + } + } + + return ht; +} + /* see GetMenu */ HMENU get_menu( HWND hwnd ) { @@ -1040,6 +1119,21 @@ static HMENU get_sub_menu( HMENU handle, INT pos ) return submenu; } +/********************************************************************** + * NtUserMenuItemFromPoint (win32u.@) + */ +INT WINAPI NtUserMenuItemFromPoint( HWND hwnd, HMENU handle, int x, int y ) +{ + POINT pt = { .x = x, .y = y }; + POPUPMENU *menu; + UINT pos; + + if (!(menu = grab_menu_ptr(handle))) return -1; + if (find_item_by_coords( menu, pt, &pos ) != ht_item) pos = -1; + release_menu_ptr(menu); + return pos; +} + /********************************************************************** * NtUserGetSystemMenu (win32u.@) */ @@ -1823,13 +1917,6 @@ got_bitmap: NtGdiDeleteObjectApp( mem_hdc ); } -/* Adjust menu item rectangle according to scrolling state */ -static void adjust_menu_item_rect( const POPUPMENU *menu, RECT *rect ) -{ - INT scroll_offset = menu->bScrolling ? menu->nScrollPos : 0; - OffsetRect( rect, menu->items_rect.left, menu->items_rect.top - scroll_offset ); -} - /* Draw a single menu item */ static void draw_menu_item( HWND hwnd, POPUPMENU *menu, HWND owner, HDC hdc, MENUITEM *item, BOOL menu_bar, UINT odaction ) diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index ac13580308d..a926049f0ed 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -151,6 +151,7 @@ static void * const syscalls[] = NtUserInternalGetWindowText, NtUserKillTimer, NtUserLockWindowUpdate, + NtUserMenuItemFromPoint, NtUserNotifyWinEvent, NtUserOpenDesktop, NtUserOpenInputDesktop, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 4dfebaa9d2d..f296f162fff 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1078,7 +1078,7 @@ @ stub NtUserMapPointsByVisualIdentifier @ stdcall NtUserMapVirtualKeyEx(long long long) @ stub NtUserMarkWindowForRawMouse -@ stub NtUserMenuItemFromPoint +@ stdcall -syscall NtUserMenuItemFromPoint(long long long long) @ stdcall NtUserMessageCall(long long long long long long long) @ stub NtUserMinInitialize @ stub NtUserMinMaximize diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index e30d367cda7..7c9627a6121 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -138,6 +138,7 @@ SYSCALL_ENTRY( NtUserInternalGetWindowText ) \ SYSCALL_ENTRY( NtUserKillTimer ) \ SYSCALL_ENTRY( NtUserLockWindowUpdate ) \ + SYSCALL_ENTRY( NtUserMenuItemFromPoint ) \ SYSCALL_ENTRY( NtUserNotifyWinEvent ) \ SYSCALL_ENTRY( NtUserOpenDesktop ) \ SYSCALL_ENTRY( NtUserOpenInputDesktop ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index c2d134626f1..51c0a5d0ed8 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -736,6 +736,16 @@ NTSTATUS WINAPI wow64_NtUserGetMenuItemRect( UINT *args ) return NtUserGetMenuItemRect( hwnd, handle, item, rect ); } +NTSTATUS WINAPI wow64_NtUserMenuItemFromPoint( UINT *args ) +{ + HWND hwnd = get_handle( &args ); + HMENU handle = get_handle( &args ); + int x = get_ulong( &args ); + int y = get_ulong( &args ); + + return NtUserMenuItemFromPoint( hwnd, handle, x, y ); +} + NTSTATUS WINAPI wow64_NtUserSetMenuContextHelpId( UINT *args ) { HMENU menu = get_handle( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index 5f744c24906..0415ba076a5 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -620,6 +620,7 @@ BOOL WINAPI NtUserIsClipboardFormatAvailable( UINT format ); BOOL WINAPI NtUserKillTimer( HWND hwnd, UINT_PTR id ); BOOL WINAPI NtUserLockWindowUpdate( HWND hwnd ); UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ); +INT WINAPI NtUserMenuItemFromPoint( HWND hwnd, HMENU handle, int x, int y ); LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void *result_info, DWORD type, BOOL ansi ); BOOL WINAPI NtUserMoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy, BOOL repaint );