-- v2: win32u: Track mouse events based on last mouse message data. win32u: Move mouse tracking info into per-thread data. win32u: Use internal message to hanlde NtUserTrackMouseEvent() for other thread window. user32/tests: Add test for (no) messages during TrackMouseEvent() call.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/user32/tests/msg.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index c8a12a6f998..2b54e5087ec 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -111,6 +111,7 @@ typedef struct static BOOL test_DestroyWindow_flag; static BOOL test_context_menu; static BOOL ignore_mouse_messages = TRUE; +static BOOL ignore_WM_NCHITTEST = TRUE; static HWINEVENTHOOK hEvent_hook; static HHOOK hKBD_hook; static HHOOK hCBT_hook; @@ -10935,7 +10936,9 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
/* test_accelerators() depends on this */ case WM_NCHITTEST: - return HTCLIENT; + if (ignore_WM_NCHITTEST) + return HTCLIENT; + break;
case WM_USER+10: { @@ -14933,6 +14936,12 @@ static const struct message WmMouseLeaveSeq[] = { 0 } };
+static const struct message TrackMouseEventCallSeq[] = +{ + { WM_NCHITTEST, sent | wine_only, 0, 0 }, + { 0 } +}; + static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move) { MSG msg; @@ -15157,6 +15166,31 @@ static void test_TrackMouseEvent(void)
DestroyWindow(hwnd);
+ /* Test that TrackMouseEvent() tracking doesn't produce WM_NCHITTEST */ + hwnd2 = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, + 0, NULL, NULL, 0); + ok(!!hwnd2, "Failed to create window, error %lu.\n", GetLastError()); + + GetCursorPos(&old_pt); + SetCursorPos(150, 150); + + flush_events(); + flush_sequence(); + + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hwnd2; + tme.dwHoverTime = HOVER_DEFAULT; + SetLastError(0xdeadbeef); + ignore_WM_NCHITTEST = FALSE; + ret = pTrackMouseEvent(&tme); + ok(ret, "TrackMouseEvent(TME_LEAVE) failed, error %ld\n", GetLastError()); + flush_events(); + ignore_WM_NCHITTEST = TRUE; + ok_sequence(TrackMouseEventCallSeq, "TrackMouseEventCallSeq", FALSE); + SetCursorPos(old_pt.x, old_pt.y); + DestroyWindow(hwnd2); + /* Test that tracking a new window with TME_LEAVE and when the cursor is not in the new window, * WM_MOUSELEAVE is immediately posted to the window */ hwnd = CreateWindowA("static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100,
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/input.c | 4 ++++ dlls/win32u/message.c | 10 ++++++++++ include/ntuser.h | 1 + 3 files changed, 15 insertions(+)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index c718bd1cbbc..9250cd8df46 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1794,6 +1794,10 @@ BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info ) return FALSE; }
+ if (!is_current_thread_window( info->hwndTrack )) + return NtUserMessageCall( info->hwndTrack, WM_WINE_TRACKMOUSEEVENT, info->dwFlags, info->dwHoverTime, + NULL, NtUserSendNotifyMessage, FALSE ); + hover_time = (info->dwFlags & TME_HOVER) ? info->dwHoverTime : HOVER_DEFAULT;
if (hover_time == HOVER_DEFAULT || hover_time == 0) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index df64e059177..3a587199d13 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2236,6 +2236,16 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR case WM_WINE_UPDATEWINDOWSTATE: update_window_state( hwnd ); return 0; + case WM_WINE_TRACKMOUSEEVENT: + { + TRACKMOUSEEVENT info; + + info.cbSize = sizeof(info); + info.hwndTrack = hwnd; + info.dwFlags = wparam; + info.dwHoverTime = lparam; + return NtUserTrackMouseEvent( &info ); + } default: if (msg >= WM_WINE_FIRST_DRIVER_MSG && msg <= WM_WINE_LAST_DRIVER_MSG) return user_driver->pWindowMessage( hwnd, msg, wparam, lparam ); diff --git a/include/ntuser.h b/include/ntuser.h index ef09d7e97bb..0cf257d4d07 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -638,6 +638,7 @@ enum wine_internal_message WM_WINE_IME_NOTIFY, WM_WINE_WINDOW_STATE_CHANGED, WM_WINE_UPDATEWINDOWSTATE, + WM_WINE_TRACKMOUSEEVENT, WM_WINE_FIRST_DRIVER_MSG = 0x80001000, /* range of messages reserved for the USER driver */ WM_WINE_CLIPCURSOR = 0x80001ff0, /* internal driver notification messages */ WM_WINE_SETCURSOR,
From: Paul Gofman pgofman@codeweavers.com
--- dlls/user32/tests/msg.c | 21 ++++++- dlls/win32u/input.c | 111 ++++++++++++++++++----------------- dlls/win32u/ntuser_private.h | 7 +++ dlls/win32u/sysparams.c | 1 + 4 files changed, 84 insertions(+), 56 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 2b54e5087ec..cdae4c7d37a 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -14986,6 +14986,22 @@ static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move) } while (start_ticks + timeout >= end_ticks); }
+static DWORD WINAPI track_mouse_event_query_thread( void *context ) +{ + TRACKMOUSEEVENT tme; + BOOL ret; + + memset( &tme, 0xcc, sizeof(tme) ); + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_QUERY; + ret = pTrackMouseEvent( &tme ); + ok( ret, "TrackMouseEvent(TME_QUERY) error %ld\n", GetLastError() ); + ok( !tme.hwndTrack, "got %p.\n", tme.hwndTrack ); + ok( !tme.dwHoverTime, "got %lu.\n", tme.dwHoverTime ); + ok( !tme.dwFlags, "got %#lx.\n", tme.dwFlags ); + return 0; +} + static void test_TrackMouseEvent(void) { TRACKMOUSEEVENT tme; @@ -14994,6 +15010,7 @@ static void test_TrackMouseEvent(void) RECT rc_parent, rc_child; UINT default_hover_time, hover_width = 0, hover_height = 0; POINT old_pt; + HANDLE thread;
#define track_hover(track_hwnd, track_hover_time) \ tme.cbSize = sizeof(tme); \ @@ -15018,7 +15035,9 @@ static void test_TrackMouseEvent(void) ok(tme.hwndTrack == (expected_track_hwnd), \ "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \ ok(tme.dwHoverTime == (expected_hover_time), \ - "wrong tme.dwHoverTime %lu, expected %u\n", tme.dwHoverTime, (expected_hover_time)) + "wrong tme.dwHoverTime %lu, expected %u\n", tme.dwHoverTime, (expected_hover_time)); \ + thread = CreateThread( NULL, 0, track_mouse_event_query_thread, &tme, 0, NULL ); \ + WaitForSingleObject( thread, INFINITE )
#define track_hover_cancel(track_hwnd) \ tme.cbSize = sizeof(tme); \ diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 9250cd8df46..178e823d43b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1655,42 +1655,41 @@ static WORD get_key_state(void) return ret; }
-struct tracking_list +static struct mouse_tracking_info *get_mouse_tracking_info(void) { - TRACKMOUSEEVENT info; - POINT pos; /* center of hover rectangle */ -}; - -/* FIXME: move tracking stuff into per-thread data */ -static struct tracking_list tracking_info; + struct user_thread_info *thread_info = get_user_thread_info(); + if (!thread_info->mouse_tracking_info) + thread_info->mouse_tracking_info = calloc(1, sizeof(*thread_info->mouse_tracking_info)); + return thread_info->mouse_tracking_info; +}
-static void check_mouse_leave( HWND hwnd, int hittest ) +static void check_mouse_leave( HWND hwnd, int hittest, struct mouse_tracking_info *tracking ) { - if (tracking_info.info.hwndTrack != hwnd) + if (tracking->info.hwndTrack != hwnd) { - if (tracking_info.info.dwFlags & TME_NONCLIENT) - NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 ); + if (tracking->info.dwFlags & TME_NONCLIENT) + NtUserPostMessage( tracking->info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 ); else - NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSELEAVE, 0, 0 ); + NtUserPostMessage( tracking->info.hwndTrack, WM_MOUSELEAVE, 0, 0 );
- tracking_info.info.dwFlags &= ~TME_LEAVE; + tracking->info.dwFlags &= ~TME_LEAVE; } else { if (hittest == HTCLIENT) { - if (tracking_info.info.dwFlags & TME_NONCLIENT) + if (tracking->info.dwFlags & TME_NONCLIENT) { - NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 ); - tracking_info.info.dwFlags &= ~TME_LEAVE; + NtUserPostMessage( tracking->info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 ); + tracking->info.dwFlags &= ~TME_LEAVE; } } else { - if (!(tracking_info.info.dwFlags & TME_NONCLIENT)) + if (!(tracking->info.dwFlags & TME_NONCLIENT)) { - NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSELEAVE, 0, 0 ); - tracking_info.info.dwFlags &= ~TME_LEAVE; + NtUserPostMessage( tracking->info.hwndTrack, WM_MOUSELEAVE, 0, 0 ); + tracking->info.dwFlags &= ~TME_LEAVE; } } } @@ -1698,6 +1697,7 @@ static void check_mouse_leave( HWND hwnd, int hittest )
void update_mouse_tracking_info( HWND hwnd ) { + struct mouse_tracking_info *tracking = get_mouse_tracking_info(); int hover_width = 0, hover_height = 0, hittest; POINT pos;
@@ -1712,22 +1712,22 @@ void update_mouse_tracking_info( HWND hwnd ) 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), + wine_dbgstr_point(&tracking->pos), wine_dbgstr_point(&pos), hover_width, hover_height );
- if (tracking_info.info.dwFlags & TME_LEAVE) - check_mouse_leave( hwnd, hittest ); + if (tracking->info.dwFlags & TME_LEAVE) + check_mouse_leave( hwnd, hittest, tracking );
- if (tracking_info.info.hwndTrack != hwnd) - tracking_info.info.dwFlags &= ~TME_HOVER; + if (tracking->info.hwndTrack != hwnd) + tracking->info.dwFlags &= ~TME_HOVER;
- if (tracking_info.info.dwFlags & TME_HOVER) + if (tracking->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))) + if ((abs( pos.x - tracking->pos.x ) > (hover_width / 2)) || + (abs( pos.y - tracking->pos.y ) > (hover_height / 2))) { - tracking_info.pos = pos; + tracking->pos = pos; } else { @@ -1736,28 +1736,28 @@ void update_mouse_tracking_info( HWND hwnd ) screen_to_client(hwnd, &pos); TRACE( "client cursor pos %s\n", wine_dbgstr_point(&pos) );
- NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSEHOVER, + NtUserPostMessage( tracking->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, + if (tracking->info.dwFlags & TME_NONCLIENT) + NtUserPostMessage( tracking->info.hwndTrack, WM_NCMOUSEHOVER, hittest, MAKELPARAM( pos.x, pos.y ) ); }
/* stop tracking mouse hover */ - tracking_info.info.dwFlags &= ~TME_HOVER; + tracking->info.dwFlags &= ~TME_HOVER; } }
/* stop the timer if the tracking list is empty */ - if (!(tracking_info.info.dwFlags & (TME_HOVER | TME_LEAVE))) + if (!(tracking->info.dwFlags & (TME_HOVER | TME_LEAVE))) { - NtUserKillSystemTimer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE ); - tracking_info.info.hwndTrack = 0; - tracking_info.info.dwFlags = 0; - tracking_info.info.dwHoverTime = 0; + NtUserKillSystemTimer( tracking->info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE ); + tracking->info.hwndTrack = 0; + tracking->info.dwFlags = 0; + tracking->info.dwHoverTime = 0; } }
@@ -1766,6 +1766,7 @@ void update_mouse_tracking_info( HWND hwnd ) */ BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info ) { + struct mouse_tracking_info *tracking = get_mouse_tracking_info(); DWORD hover_time; int hittest; HWND hwnd; @@ -1783,7 +1784,7 @@ BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info )
if (info->dwFlags & TME_QUERY) { - *info = tracking_info.info; + *info = tracking->info; info->cbSize = sizeof(TRACKMOUSEEVENT); return TRUE; } @@ -1812,17 +1813,17 @@ BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info )
if (info->dwFlags & TME_CANCEL) { - if (tracking_info.info.hwndTrack == info->hwndTrack) + if (tracking->info.hwndTrack == info->hwndTrack) { - tracking_info.info.dwFlags &= ~(info->dwFlags & ~TME_CANCEL); + tracking->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))) + if (!(tracking->info.dwFlags & (TME_HOVER | TME_LEAVE))) { - NtUserKillSystemTimer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE ); - tracking_info.info.hwndTrack = 0; - tracking_info.info.dwFlags = 0; - tracking_info.info.dwHoverTime = 0; + NtUserKillSystemTimer( tracking->info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE ); + tracking->info.hwndTrack = 0; + tracking->info.dwFlags = 0; + tracking->info.dwHoverTime = 0; } } } @@ -1842,24 +1843,24 @@ BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info ) /* 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); + if ((tracking->info.dwFlags & TME_LEAVE) && tracking->info.hwndTrack != NULL) + check_mouse_leave( hwnd, hittest, tracking );
- NtUserKillSystemTimer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE ); - tracking_info.info.hwndTrack = 0; - tracking_info.info.dwFlags = 0; - tracking_info.info.dwHoverTime = 0; + NtUserKillSystemTimer( tracking->info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE ); + tracking->info.hwndTrack = 0; + tracking->info.dwFlags = 0; + tracking->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; + tracking->info = *info; + tracking->info.dwHoverTime = hover_time;
/* Initialize HoverInfo variables even if not hover tracking */ - tracking_info.pos = pos; + tracking->pos = pos;
- NtUserSetSystemTimer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE, hover_time ); + NtUserSetSystemTimer( tracking->info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE, hover_time ); } }
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 2de11465f87..03a4e43f949 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -96,6 +96,12 @@ static inline BOOL is_broadcast( HWND hwnd ) return hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST; }
+struct mouse_tracking_info +{ + TRACKMOUSEEVENT info; + POINT pos; /* center of hover rectangle */ +}; + /* this is the structure stored in TEB->Win32ClientInfo */ /* no attempt is made to keep the layout compatible with the Windows one */ struct user_thread_info @@ -115,6 +121,7 @@ struct user_thread_info BOOL clipping_cursor; /* thread is currently clipping */ DWORD clipping_reset; /* time when clipping was last reset */ struct session_thread_data *session_data; /* shared session thread data */ + struct mouse_tracking_info *mouse_tracking_info; /* Data related to NtUserTrackMouseEvent handling */ };
C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 3a0fbe4f87b..59e816b0ee6 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -7056,6 +7056,7 @@ static void thread_detach(void) cleanup_imm_thread(); NtClose( thread_info->server_queue ); free( thread_info->session_data ); + free( thread_info->mouse_tracking_info );
exiting_thread_id = 0; }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/user32/tests/msg.c | 8 +------- dlls/win32u/input.c | 38 ++++++++++++++++++++++++++++++------ dlls/win32u/message.c | 5 +++-- dlls/win32u/ntuser_private.h | 3 +++ dlls/win32u/win32u_private.h | 3 ++- dlls/win32u/window.c | 6 +++--- 6 files changed, 44 insertions(+), 19 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index cdae4c7d37a..a5124d96a3e 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -14936,12 +14936,6 @@ static const struct message WmMouseLeaveSeq[] = { 0 } };
-static const struct message TrackMouseEventCallSeq[] = -{ - { WM_NCHITTEST, sent | wine_only, 0, 0 }, - { 0 } -}; - static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move) { MSG msg; @@ -15206,7 +15200,7 @@ static void test_TrackMouseEvent(void) ok(ret, "TrackMouseEvent(TME_LEAVE) failed, error %ld\n", GetLastError()); flush_events(); ignore_WM_NCHITTEST = TRUE; - ok_sequence(TrackMouseEventCallSeq, "TrackMouseEventCallSeq", FALSE); + ok_sequence(WmEmptySeq, "TrackMouseEventCallSeq", FALSE); SetCursorPos(old_pt.x, old_pt.y); DestroyWindow(hwnd2);
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 178e823d43b..b6dd83218a0 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1663,6 +1663,15 @@ static struct mouse_tracking_info *get_mouse_tracking_info(void) return thread_info->mouse_tracking_info; }
+void update_current_mouse_window( HWND hwnd, INT hittest, POINT pos ) +{ + struct mouse_tracking_info *tracking = get_mouse_tracking_info(); + + tracking->last_mouse_message_hwnd = hwnd; + tracking->last_mouse_message_hittest = hittest; + tracking->last_mouse_message_pos = pos; +} + static void check_mouse_leave( HWND hwnd, int hittest, struct mouse_tracking_info *tracking ) { if (tracking->info.hwndTrack != hwnd) @@ -1695,6 +1704,27 @@ static void check_mouse_leave( HWND hwnd, int hittest, struct mouse_tracking_inf } }
+static HWND get_mouse_window( HWND hwnd, INT *hittest, POINT *ret_pos, struct mouse_tracking_info *tracking ) +{ + POINT pos; + HWND ret; + + NtUserGetCursorPos( &pos ); + ret = window_from_point( hwnd, pos, hittest, FALSE ); + if (ret && ret == tracking->last_mouse_message_hwnd) + { + *hittest = tracking->last_mouse_message_hittest; + *ret_pos = tracking->last_mouse_message_pos; + } + else + { + tracking->last_mouse_message_hwnd = NULL; + *ret_pos = pos; + } + TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), ret, *hittest ); + return ret; +} + void update_mouse_tracking_info( HWND hwnd ) { struct mouse_tracking_info *tracking = get_mouse_tracking_info(); @@ -1703,10 +1733,7 @@ void update_mouse_tracking_info( HWND hwnd )
TRACE( "hwnd %p\n", hwnd );
- NtUserGetCursorPos( &pos ); - hwnd = window_from_point( hwnd, pos, &hittest ); - - TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest ); + hwnd = get_mouse_window( hwnd, &hittest, &pos, tracking );
NtUserSystemParametersInfo( SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0 ); NtUserSystemParametersInfo( SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0 ); @@ -1804,8 +1831,7 @@ BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info ) if (hover_time == HOVER_DEFAULT || hover_time == 0) NtUserSystemParametersInfo( SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0 );
- NtUserGetCursorPos( &pos ); - hwnd = window_from_point( info->hwndTrack, pos, &hittest ); + hwnd = get_mouse_window( info->hwndTrack, &hittest, &pos, tracking ); 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)) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 3a587199d13..3b93b4c97b2 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2565,14 +2565,14 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H { HWND orig = msg->hwnd;
- msg->hwnd = window_from_point( msg->hwnd, msg->pt, &hittest ); + msg->hwnd = window_from_point( msg->hwnd, msg->pt, &hittest, TRUE ); if (!msg->hwnd) /* As a heuristic, try the next window if it's the owner of orig */ { HWND next = get_window_relative( orig, GW_HWNDNEXT );
if (next && get_window_relative( orig, GW_OWNER ) == next && is_current_thread_window( next )) - msg->hwnd = window_from_point( next, msg->pt, &hittest ); + msg->hwnd = window_from_point( next, msg->pt, &hittest, TRUE ); } }
@@ -2581,6 +2581,7 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H accept_hardware_message( hw_id ); return FALSE; } + update_current_mouse_window( msg->hwnd, hittest, msg->pt );
msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); set_thread_dpi_awareness_context( get_window_dpi_awareness_context( msg->hwnd )); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 03a4e43f949..481816729b7 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -100,6 +100,9 @@ struct mouse_tracking_info { TRACKMOUSEEVENT info; POINT pos; /* center of hover rectangle */ + HWND last_mouse_message_hwnd; + int last_mouse_message_hittest; + POINT last_mouse_message_pos; };
/* this is the structure stored in TEB->Win32ClientInfo */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 69d7b5b5257..a9b39de6471 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -100,6 +100,7 @@ extern BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus, DW extern BOOL set_ime_composition_rect( HWND hwnd, RECT rect ); extern void toggle_caret( HWND hwnd ); extern void update_mouse_tracking_info( HWND hwnd ); +extern void update_current_mouse_window( HWND hwnd, INT hittest, POINT pos ); extern BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ); extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ); extern USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout ); @@ -282,7 +283,7 @@ extern LONG_PTR set_window_long( HWND hwnd, INT offset, UINT size, LONG_PTR newv extern BOOL set_window_pos( WINDOWPOS *winpos, int parent_x, int parent_y ); extern UINT set_window_style_bits( HWND hwnd, UINT set_bits, UINT clear_bits ); extern void update_window_state( HWND hwnd ); -extern HWND window_from_point( HWND hwnd, POINT pt, INT *hittest ); +extern HWND window_from_point( HWND hwnd, POINT pt, INT *hittest, BOOL send_nchittest ); extern HWND get_shell_window(void); extern HWND get_progman_window(void); extern HWND get_taskman_window(void); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 0363a00541f..07d53339a5e 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2628,7 +2628,7 @@ static HWND *list_children_from_point( HWND hwnd, POINT pt, UINT dpi ) * * Find the window and hittest for a given point. */ -HWND window_from_point( HWND hwnd, POINT pt, INT *hittest ) +HWND window_from_point( HWND hwnd, POINT pt, INT *hittest, BOOL send_nchittest ) { int i, res; HWND ret, *list; @@ -2655,7 +2655,7 @@ HWND window_from_point( HWND hwnd, POINT pt, INT *hittest ) break; } /* Send WM_NCCHITTEST (if same thread) */ - if (!is_current_thread_window( list[i] )) + if (!send_nchittest || !is_current_thread_window( list[i] )) { *hittest = HTCLIENT; break; @@ -2682,7 +2682,7 @@ HWND WINAPI NtUserWindowFromPoint( LONG x, LONG y ) { POINT pt = { .x = x, .y = y }; INT hittest; - return window_from_point( 0, pt, &hittest ); + return window_from_point( 0, pt, &hittest, TRUE ); }
/*******************************************************************
v2: - add patches to track mouse event per thread; - track mouse window per thread.
Rémi Bernon (@rbernon) commented about dlls/win32u/input.c:
return FALSE; }
- if (!is_current_thread_window( info->hwndTrack ))
return NtUserMessageCall( info->hwndTrack, WM_WINE_TRACKMOUSEEVENT, info->dwFlags, info->dwHoverTime,
NULL, NtUserSendNotifyMessage, FALSE );
I think win32u usually directly uses its internal helpers.
```suggestion:-1+0 return send_notify_message( info->hwndTrack, WM_WINE_TRACKMOUSEEVENT, info->dwFlags, info->dwHoverTime, FALSE ); ```
This merge request was approved by Rémi Bernon.