[PATCH 1/8] win32u: Move NtUserMenuItemFromPoint implementation from user32.

Jacek Caban wine at gitlab.winehq.org
Wed Jun 15 06:44:32 CDT 2022


From: Jacek Caban <jacek at codeweavers.com>

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
---
 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 );
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/250



More information about the wine-devel mailing list