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; }