[PATCH 1/4] win32u: Move NtUserTrackMouseEvent() implementation from user32.

Zebediah Figura zfigura at codeweavers.com
Mon Apr 25 13:44:33 CDT 2022


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/user32/input.c          | 254 -----------------------------------
 dlls/user32/scroll.c         |   8 +-
 dlls/user32/user32.spec      |   2 +-
 dlls/user32/user_main.c      |   1 -
 dlls/user32/user_private.h   |   1 -
 dlls/win32u/gdiobj.c         |   1 +
 dlls/win32u/input.c          | 218 ++++++++++++++++++++++++++++++
 dlls/win32u/message.c        |   3 +-
 dlls/win32u/ntuser_private.h |   1 -
 dlls/win32u/win32u.spec      |   2 +-
 dlls/win32u/win32u_private.h |   2 +
 dlls/win32u/wrappers.c       |   6 +
 include/ntuser.h             |   1 +
 13 files changed, 235 insertions(+), 265 deletions(-)

diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index 4ef33ab2838..dcb46df22b5 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -49,32 +49,6 @@
 WINE_DEFAULT_DEBUG_CHANNEL(win);
 WINE_DECLARE_DEBUG_CHANNEL(keyboard);
 
-/***********************************************************************
- *           get_key_state
- */
-static WORD get_key_state(void)
-{
-    WORD ret = 0;
-
-    if (GetSystemMetrics( SM_SWAPBUTTON ))
-    {
-        if (NtUserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_LBUTTON;
-        if (NtUserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_RBUTTON;
-    }
-    else
-    {
-        if (NtUserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_LBUTTON;
-        if (NtUserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_RBUTTON;
-    }
-    if (NtUserGetAsyncKeyState(VK_MBUTTON) & 0x80)  ret |= MK_MBUTTON;
-    if (NtUserGetAsyncKeyState(VK_SHIFT) & 0x80)    ret |= MK_SHIFT;
-    if (NtUserGetAsyncKeyState(VK_CONTROL) & 0x80)  ret |= MK_CONTROL;
-    if (NtUserGetAsyncKeyState(VK_XBUTTON1) & 0x80) ret |= MK_XBUTTON1;
-    if (NtUserGetAsyncKeyState(VK_XBUTTON2) & 0x80) ret |= MK_XBUTTON2;
-    return ret;
-}
-
-
 /***********************************************************************
  *           get_locale_kbd_layout
  */
@@ -520,234 +494,6 @@ BOOL WINAPI UnloadKeyboardLayout( HKL layout )
     return FALSE;
 }
 
-typedef struct __TRACKINGLIST {
-    TRACKMOUSEEVENT tme;
-    POINT pos; /* center of hover rectangle */
-} _TRACKINGLIST;
-
-/* FIXME: move tracking stuff into a per thread data */
-static _TRACKINGLIST tracking_info;
-
-static void check_mouse_leave(HWND hwnd, int hittest)
-{
-    if (tracking_info.tme.hwndTrack != hwnd)
-    {
-        if (tracking_info.tme.dwFlags & TME_NONCLIENT)
-            PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0);
-        else
-            PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
-
-        /* remove the TME_LEAVE flag */
-        tracking_info.tme.dwFlags &= ~TME_LEAVE;
-    }
-    else
-    {
-        if (hittest == HTCLIENT)
-        {
-            if (tracking_info.tme.dwFlags & TME_NONCLIENT)
-            {
-                PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0);
-                /* remove the TME_LEAVE flag */
-                tracking_info.tme.dwFlags &= ~TME_LEAVE;
-            }
-        }
-        else
-        {
-            if (!(tracking_info.tme.dwFlags & TME_NONCLIENT))
-            {
-                PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
-                /* remove the TME_LEAVE flag */
-                tracking_info.tme.dwFlags &= ~TME_LEAVE;
-            }
-        }
-    }
-}
-
-void CDECL update_mouse_tracking_info( HWND hwnd )
-{
-    POINT pos;
-    INT hoverwidth = 0, hoverheight = 0, hittest;
-
-    TRACE( "hwnd %p\n", hwnd );
-
-    GetCursorPos(&pos);
-    hwnd = WINPOS_WindowFromPoint(hwnd, pos, &hittest);
-
-    TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest);
-
-    SystemParametersInfoW(SPI_GETMOUSEHOVERWIDTH, 0, &hoverwidth, 0);
-    SystemParametersInfoW(SPI_GETMOUSEHOVERHEIGHT, 0, &hoverheight, 0);
-
-    TRACE("tracked pos %s, current pos %s, hover width %d, hover height %d\n",
-           wine_dbgstr_point(&tracking_info.pos), wine_dbgstr_point(&pos),
-           hoverwidth, hoverheight);
-
-    /* see if this tracking event is looking for TME_LEAVE and that the */
-    /* mouse has left the window */
-    if (tracking_info.tme.dwFlags & TME_LEAVE)
-    {
-        check_mouse_leave(hwnd, hittest);
-    }
-
-    if (tracking_info.tme.hwndTrack != hwnd)
-    {
-        /* mouse is gone, stop tracking mouse hover */
-        tracking_info.tme.dwFlags &= ~TME_HOVER;
-    }
-
-    /* see if we are tracking hovering for this hwnd */
-    if (tracking_info.tme.dwFlags & TME_HOVER)
-    {
-        /* has the cursor moved outside the rectangle centered around pos? */
-        if ((abs(pos.x - tracking_info.pos.x) > (hoverwidth / 2)) ||
-            (abs(pos.y - tracking_info.pos.y) > (hoverheight / 2)))
-        {
-            /* record this new position as the current position */
-            tracking_info.pos = pos;
-        }
-        else
-        {
-            if (hittest == HTCLIENT)
-            {
-                ScreenToClient(hwnd, &pos);
-                TRACE("client cursor pos %s\n", wine_dbgstr_point(&pos));
-
-                PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSEHOVER,
-                             get_key_state(), MAKELPARAM( pos.x, pos.y ));
-            }
-            else
-            {
-                if (tracking_info.tme.dwFlags & TME_NONCLIENT)
-                    PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSEHOVER,
-                                 hittest, MAKELPARAM( pos.x, pos.y ));
-            }
-
-            /* stop tracking mouse hover */
-            tracking_info.tme.dwFlags &= ~TME_HOVER;
-        }
-    }
-
-    /* stop the timer if the tracking list is empty */
-    if (!(tracking_info.tme.dwFlags & (TME_HOVER | TME_LEAVE)))
-    {
-        KillSystemTimer( tracking_info.tme.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
-        tracking_info.tme.hwndTrack = 0;
-        tracking_info.tme.dwFlags = 0;
-        tracking_info.tme.dwHoverTime = 0;
-    }
-}
-
-
-/***********************************************************************
- * TrackMouseEvent [USER32]
- *
- * Requests notification of mouse events
- *
- * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
- * to the hwnd specified in the ptme structure.  After the event message
- * is posted to the hwnd, the entry in the queue is removed.
- *
- * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
- * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
- * immediately and the TME_LEAVE flag being ignored.
- *
- * PARAMS
- *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
- *
- * RETURNS
- *     Success: non-zero
- *     Failure: zero
- *
- */
-
-BOOL WINAPI
-TrackMouseEvent (TRACKMOUSEEVENT *ptme)
-{
-    HWND hwnd;
-    POINT pos;
-    DWORD hover_time;
-    INT hittest;
-
-    TRACE("%x, %x, %p, %u\n", ptme->cbSize, ptme->dwFlags, ptme->hwndTrack, ptme->dwHoverTime);
-
-    if (ptme->cbSize != sizeof(TRACKMOUSEEVENT)) {
-        WARN("wrong TRACKMOUSEEVENT size from app\n");
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
-    /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
-    if (ptme->dwFlags & TME_QUERY )
-    {
-        *ptme = tracking_info.tme;
-        /* set cbSize in the case it's not initialized yet */
-        ptme->cbSize = sizeof(TRACKMOUSEEVENT);
-
-        return TRUE; /* return here, TME_QUERY is retrieving information */
-    }
-
-    if (!IsWindow(ptme->hwndTrack))
-    {
-        SetLastError(ERROR_INVALID_WINDOW_HANDLE);
-        return FALSE;
-    }
-
-    hover_time = (ptme->dwFlags & TME_HOVER) ? ptme->dwHoverTime : HOVER_DEFAULT;
-
-    /* if HOVER_DEFAULT was specified replace this with the system's current value.
-     * TME_LEAVE doesn't need to specify hover time so use default */
-    if (hover_time == HOVER_DEFAULT || hover_time == 0)
-        SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0);
-
-    GetCursorPos(&pos);
-    hwnd = WINPOS_WindowFromPoint(ptme->hwndTrack, pos, &hittest);
-    TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest);
-
-    if (ptme->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT))
-        FIXME("Unknown flag(s) %08x\n", ptme->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT));
-
-    if (ptme->dwFlags & TME_CANCEL)
-    {
-        if (tracking_info.tme.hwndTrack == ptme->hwndTrack)
-        {
-            tracking_info.tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL);
-
-            /* if we aren't tracking on hover or leave remove this entry */
-            if (!(tracking_info.tme.dwFlags & (TME_HOVER | TME_LEAVE)))
-            {
-                KillSystemTimer( tracking_info.tme.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
-                tracking_info.tme.hwndTrack = 0;
-                tracking_info.tme.dwFlags = 0;
-                tracking_info.tme.dwHoverTime = 0;
-            }
-        }
-    } else {
-        /* In our implementation it's possible that another window will receive a
-         * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
-         * called. In such a situation post the WM_MOUSELEAVE now */
-        if (tracking_info.tme.dwFlags & TME_LEAVE && tracking_info.tme.hwndTrack != NULL)
-            check_mouse_leave(hwnd, hittest);
-
-        KillSystemTimer( tracking_info.tme.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
-        tracking_info.tme.hwndTrack = 0;
-        tracking_info.tme.dwFlags = 0;
-        tracking_info.tme.dwHoverTime = 0;
-
-        if (ptme->hwndTrack == hwnd)
-        {
-            /* Adding new mouse event to the tracking list */
-            tracking_info.tme = *ptme;
-            tracking_info.tme.dwHoverTime = hover_time;
-
-            /* Initialize HoverInfo variables even if not hover tracking */
-            tracking_info.pos = pos;
-
-            NtUserSetSystemTimer( tracking_info.tme.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE, hover_time );
-        }
-    }
-
-    return TRUE;
-}
 
 /***********************************************************************
  *		EnableMouseInPointer (USER32.@)
diff --git a/dlls/user32/scroll.c b/dlls/user32/scroll.c
index 45980b75b2c..8f085364dab 100644
--- a/dlls/user32/scroll.c
+++ b/dlls/user32/scroll.c
@@ -864,12 +864,12 @@ void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt )
 
           tme.cbSize = sizeof(tme);
           tme.dwFlags = TME_QUERY;
-          TrackMouseEvent( &tme );
+          NtUserTrackMouseEvent( &tme );
           if (!(tme.dwFlags & TME_LEAVE) || tme.hwndTrack != hwnd)
           {
               tme.dwFlags = TME_LEAVE;
               tme.hwndTrack = hwnd;
-              TrackMouseEvent( &tme );
+              NtUserTrackMouseEvent( &tme );
           }
 
           break;
@@ -883,12 +883,12 @@ void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt )
 
           tme.cbSize = sizeof(tme);
           tme.dwFlags = TME_QUERY;
-          TrackMouseEvent( &tme );
+          NtUserTrackMouseEvent( &tme );
           if (((tme.dwFlags & (TME_NONCLIENT | TME_LEAVE)) != (TME_NONCLIENT | TME_LEAVE)) || tme.hwndTrack != hwnd)
           {
               tme.dwFlags = TME_NONCLIENT | TME_LEAVE;
               tme.hwndTrack = hwnd;
-              TrackMouseEvent( &tme );
+              NtUserTrackMouseEvent( &tme );
           }
 
           break;
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec
index a7b2f7e0681..f7f41621812 100644
--- a/dlls/user32/user32.spec
+++ b/dlls/user32/user32.spec
@@ -762,7 +762,7 @@
 @ stdcall ToAsciiEx(long long ptr ptr long long)
 @ stdcall ToUnicode(long long ptr ptr long long)
 @ stdcall ToUnicodeEx(long long ptr ptr long long long) NtUserToUnicodeEx
-@ stdcall TrackMouseEvent(ptr)
+@ stdcall TrackMouseEvent(ptr) NtUserTrackMouseEvent
 @ stdcall TrackPopupMenu(long long long long long long ptr)
 @ stdcall TrackPopupMenuEx(long long long long long ptr)
 @ stdcall TranslateAccelerator(long long ptr) TranslateAcceleratorA
diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c
index 08f2833ee3f..6e0722e4750 100644
--- a/dlls/user32/user_main.c
+++ b/dlls/user32/user_main.c
@@ -179,7 +179,6 @@ static const struct user_callbacks user_funcs =
     SCROLL_SetStandardScrollPainted,
     toggle_caret,
     unpack_dde_message,
-    update_mouse_tracking_info,
     register_imm,
     unregister_imm,
 };
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index 54b11f2a8ef..96c47a71753 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -100,7 +100,6 @@ extern void SYSPARAMS_Init(void) DECLSPEC_HIDDEN;
 extern void USER_CheckNotLock(void) DECLSPEC_HIDDEN;
 extern BOOL USER_IsExitingThread( DWORD tid ) DECLSPEC_HIDDEN;
 extern void CDECL toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN;
-extern void CDECL update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN;
 
 typedef LRESULT (*winproc_callback_t)( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
                                        LRESULT *result, void *arg );
diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c
index fbaf61a52f6..ed483d8f205 100644
--- a/dlls/win32u/gdiobj.c
+++ b/dlls/win32u/gdiobj.c
@@ -1213,6 +1213,7 @@ static struct unix_funcs unix_funcs =
     NtUserSystemParametersInfo,
     NtUserSystemParametersInfoForDpi,
     NtUserToUnicodeEx,
+    NtUserTrackMouseEvent,
     NtUserTranslateMessage,
     NtUserUnregisterClass,
     NtUserUnregisterHotKey,
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c
index dd28170b1f0..61de034d7c8 100644
--- a/dlls/win32u/input.c
+++ b/dlls/win32u/input.c
@@ -1171,6 +1171,224 @@ int WINAPI NtUserGetMouseMovePointsEx( UINT size, MOUSEMOVEPOINT *ptin, MOUSEMOV
     return copied;
 }
 
+static WORD get_key_state(void)
+{
+    WORD ret = 0;
+
+    if (get_system_metrics( SM_SWAPBUTTON ))
+    {
+        if (NtUserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_LBUTTON;
+        if (NtUserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_RBUTTON;
+    }
+    else
+    {
+        if (NtUserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_LBUTTON;
+        if (NtUserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_RBUTTON;
+    }
+    if (NtUserGetAsyncKeyState(VK_MBUTTON) & 0x80)  ret |= MK_MBUTTON;
+    if (NtUserGetAsyncKeyState(VK_SHIFT) & 0x80)    ret |= MK_SHIFT;
+    if (NtUserGetAsyncKeyState(VK_CONTROL) & 0x80)  ret |= MK_CONTROL;
+    if (NtUserGetAsyncKeyState(VK_XBUTTON1) & 0x80) ret |= MK_XBUTTON1;
+    if (NtUserGetAsyncKeyState(VK_XBUTTON2) & 0x80) ret |= MK_XBUTTON2;
+    return ret;
+}
+
+struct tracking_list
+{
+    TRACKMOUSEEVENT info;
+    POINT pos; /* center of hover rectangle */
+};
+
+/* FIXME: move tracking stuff into per-thread data */
+static struct tracking_list tracking_info;
+
+static void check_mouse_leave( HWND hwnd, int hittest )
+{
+    if (tracking_info.info.hwndTrack != hwnd)
+    {
+        if (tracking_info.info.dwFlags & TME_NONCLIENT)
+            NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 );
+        else
+            NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSELEAVE, 0, 0 );
+
+        tracking_info.info.dwFlags &= ~TME_LEAVE;
+    }
+    else
+    {
+        if (hittest == HTCLIENT)
+        {
+            if (tracking_info.info.dwFlags & TME_NONCLIENT)
+            {
+                NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 );
+                tracking_info.info.dwFlags &= ~TME_LEAVE;
+            }
+        }
+        else
+        {
+            if (!(tracking_info.info.dwFlags & TME_NONCLIENT))
+            {
+                NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSELEAVE, 0, 0 );
+                tracking_info.info.dwFlags &= ~TME_LEAVE;
+            }
+        }
+    }
+}
+
+void update_mouse_tracking_info( HWND hwnd )
+{
+    int hover_width = 0, hover_height = 0, hittest;
+    POINT pos;
+
+    TRACE( "hwnd %p\n", hwnd );
+
+    get_cursor_pos( &pos );
+    hwnd = window_from_point( hwnd, pos, &hittest );
+
+    TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest );
+
+    NtUserSystemParametersInfo( SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0 );
+    NtUserSystemParametersInfo( SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0 );
+
+    TRACE( "tracked pos %s, current pos %s, hover width %d, hover height %d\n",
+           wine_dbgstr_point(&tracking_info.pos), wine_dbgstr_point(&pos),
+           hover_width, hover_height );
+
+    if (tracking_info.info.dwFlags & TME_LEAVE)
+        check_mouse_leave(hwnd, hittest);
+
+    if (tracking_info.info.hwndTrack != hwnd)
+        tracking_info.info.dwFlags &= ~TME_HOVER;
+
+    if (tracking_info.info.dwFlags & TME_HOVER)
+    {
+        /* has the cursor moved outside the rectangle centered around pos? */
+        if ((abs( pos.x - tracking_info.pos.x ) > (hover_width / 2)) ||
+            (abs( pos.y - tracking_info.pos.y ) > (hover_height / 2)))
+        {
+            tracking_info.pos = pos;
+        }
+        else
+        {
+            if (hittest == HTCLIENT)
+            {
+                screen_to_client(hwnd, &pos);
+                TRACE( "client cursor pos %s\n", wine_dbgstr_point(&pos) );
+
+                NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSEHOVER,
+                                   get_key_state(), MAKELPARAM( pos.x, pos.y ) );
+            }
+            else
+            {
+                if (tracking_info.info.dwFlags & TME_NONCLIENT)
+                    NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSEHOVER,
+                                       hittest, MAKELPARAM( pos.x, pos.y ) );
+            }
+
+            /* stop tracking mouse hover */
+            tracking_info.info.dwFlags &= ~TME_HOVER;
+        }
+    }
+
+    /* stop the timer if the tracking list is empty */
+    if (!(tracking_info.info.dwFlags & (TME_HOVER | TME_LEAVE)))
+    {
+        kill_system_timer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
+        tracking_info.info.hwndTrack = 0;
+        tracking_info.info.dwFlags = 0;
+        tracking_info.info.dwHoverTime = 0;
+    }
+}
+
+/***********************************************************************
+ *           NtUserTrackMouseEvent    (win32u.@)
+ */
+BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info )
+{
+    DWORD hover_time;
+    int hittest;
+    HWND hwnd;
+    POINT pos;
+
+    TRACE( "size %u, flags %#x, hwnd %p, time %u\n",
+           info->cbSize, info->dwFlags, info->hwndTrack, info->dwHoverTime );
+
+    if (info->cbSize != sizeof(TRACKMOUSEEVENT))
+    {
+        WARN( "wrong size %u\n", info->cbSize );
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+
+    if (info->dwFlags & TME_QUERY)
+    {
+        *info = tracking_info.info;
+        info->cbSize = sizeof(TRACKMOUSEEVENT);
+        return TRUE;
+    }
+
+    if (!is_window( info->hwndTrack ))
+    {
+        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
+        return FALSE;
+    }
+
+    hover_time = (info->dwFlags & TME_HOVER) ? info->dwHoverTime : HOVER_DEFAULT;
+
+    if (hover_time == HOVER_DEFAULT || hover_time == 0)
+        NtUserSystemParametersInfo( SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0 );
+
+    get_cursor_pos( &pos );
+    hwnd = window_from_point( info->hwndTrack, pos, &hittest );
+    TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest );
+
+    if (info->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT))
+        FIXME( "ignoring flags %#x\n", info->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT) );
+
+    if (info->dwFlags & TME_CANCEL)
+    {
+        if (tracking_info.info.hwndTrack == info->hwndTrack)
+        {
+            tracking_info.info.dwFlags &= ~(info->dwFlags & ~TME_CANCEL);
+
+            /* if we aren't tracking on hover or leave remove this entry */
+            if (!(tracking_info.info.dwFlags & (TME_HOVER | TME_LEAVE)))
+            {
+                kill_system_timer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
+                tracking_info.info.hwndTrack = 0;
+                tracking_info.info.dwFlags = 0;
+                tracking_info.info.dwHoverTime = 0;
+            }
+        }
+    }
+    else
+    {
+        /* In our implementation, it's possible that another window will receive
+         * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
+         * called. In such a situation, post the WM_MOUSELEAVE now. */
+        if ((tracking_info.info.dwFlags & TME_LEAVE) && tracking_info.info.hwndTrack != NULL)
+            check_mouse_leave(hwnd, hittest);
+
+        kill_system_timer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
+        tracking_info.info.hwndTrack = 0;
+        tracking_info.info.dwFlags = 0;
+        tracking_info.info.dwHoverTime = 0;
+
+        if (info->hwndTrack == hwnd)
+        {
+            /* Adding new mouse event to the tracking list */
+            tracking_info.info = *info;
+            tracking_info.info.dwHoverTime = hover_time;
+
+            /* Initialize HoverInfo variables even if not hover tracking */
+            tracking_info.pos = pos;
+
+            NtUserSetSystemTimer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE, hover_time );
+        }
+    }
+
+    return TRUE;
+}
+
 /**********************************************************************
  *		set_capture_window
  */
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c
index 02644e71929..8ad4a0271b3 100644
--- a/dlls/win32u/message.c
+++ b/dlls/win32u/message.c
@@ -2479,8 +2479,7 @@ LRESULT dispatch_message( const MSG *msg, BOOL ansi )
                 return 0;
 
             case SYSTEM_TIMER_TRACK_MOUSE:
-                if (!user_callbacks) break;
-                user_callbacks->update_mouse_tracking_info( msg->hwnd );
+                update_mouse_tracking_info( msg->hwnd );
                 return 0;
         }
     }
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h
index 604817708c7..cad038dbff6 100644
--- a/dlls/win32u/ntuser_private.h
+++ b/dlls/win32u/ntuser_private.h
@@ -54,7 +54,6 @@ struct user_callbacks
     void (CDECL *toggle_caret)( HWND hwnd );
     BOOL (CDECL *unpack_dde_message)( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
                                       void **buffer, size_t size );
-    void (CDECL *update_mouse_tracking_info)( HWND hwnd );
     BOOL (WINAPI *register_imm)( HWND hwnd );
     void (WINAPI *unregister_imm)( HWND hwnd );
 };
diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec
index aa40be5f652..265e2ca808b 100644
--- a/dlls/win32u/win32u.spec
+++ b/dlls/win32u/win32u.spec
@@ -1277,7 +1277,7 @@
 @ stdcall -syscall NtUserThunkedMenuInfo(long ptr)
 @ stub NtUserThunkedMenuItemInfo
 @ stdcall NtUserToUnicodeEx(long long ptr ptr long long long)
-@ stub NtUserTrackMouseEvent
+@ stdcall NtUserTrackMouseEvent(ptr)
 @ stub NtUserTrackPopupMenuEx
 @ stub NtUserTransformPoint
 @ stub NtUserTransformRect
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h
index 4c1b0a7b45b..d13958e8449 100644
--- a/dlls/win32u/win32u_private.h
+++ b/dlls/win32u/win32u_private.h
@@ -287,6 +287,7 @@ struct unix_funcs
                                                          UINT winini, UINT dpi );
     INT      (WINAPI *pNtUserToUnicodeEx)( UINT virt, UINT scan, const BYTE *state,
                                            WCHAR *str, int size, UINT flags, HKL layout );
+    BOOL     (WINAPI *pNtUserTrackMouseEvent)( TRACKMOUSEEVENT *info );
     BOOL     (WINAPI *pNtUserTranslateMessage)( const MSG *msg, UINT flags );
     BOOL     (WINAPI *pNtUserUnregisterClass)( UNICODE_STRING *name, HINSTANCE instance,
                                                struct client_menu_name *client_menu_name );
@@ -357,6 +358,7 @@ extern DWORD get_input_state(void) DECLSPEC_HIDDEN;
 extern BOOL WINAPI release_capture(void) DECLSPEC_HIDDEN;
 extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN;
 extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN;
+extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN;
 
 /* menu.c */
 extern HMENU create_menu( BOOL is_popup ) DECLSPEC_HIDDEN;
diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c
index d3497d29f03..8ac82139dd0 100644
--- a/dlls/win32u/wrappers.c
+++ b/dlls/win32u/wrappers.c
@@ -1210,6 +1210,12 @@ INT WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state,
     return unix_funcs->pNtUserToUnicodeEx( virt, scan, state, str, size, flags, layout );
 }
 
+BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info )
+{
+    if (!unix_funcs) return FALSE;
+    return unix_funcs->pNtUserTrackMouseEvent( info );
+}
+
 BOOL WINAPI NtUserTranslateMessage( const MSG *msg, UINT flags )
 {
     if (!unix_funcs) return 0;
diff --git a/include/ntuser.h b/include/ntuser.h
index d06b76ab605..aa2683fc451 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -586,6 +586,7 @@ BOOL    WINAPI NtUserSystemParametersInfoForDpi( UINT action, UINT val, PVOID pt
 BOOL    WINAPI NtUserThunkedMenuInfo( HMENU menu, const MENUINFO *info );
 INT     WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state,
                                   WCHAR *str, int size, UINT flags, HKL layout );
+BOOL    WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info );
 INT     WINAPI NtUserTranslateAccelerator( HWND hwnd, HACCEL accel, MSG *msg );
 BOOL    WINAPI NtUserTranslateMessage( const MSG *msg, UINT flags );
 BOOL    WINAPI NtUserUnhookWinEvent( HWINEVENTHOOK hEventHook );
-- 
2.35.1




More information about the wine-devel mailing list