Based on a patch from Gabriel Ivăncescu gabrielopcode@gmail.com. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46309
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This patch has been in staging and proton for a while and been sent already but it silently dropped off the patch list.
It's causing conflicts with some other patches I have that deal with __wine_send_input and that I'd like to send too, and so I cleaned it up a bit and I'm now sending it with Gabriel's blessing.
I can reproduce the issue with Winamp, but not on my regular desktop. The issue is however pretty easy to reproduce when there's lag between Wine and X11, such as when using a remote X11 server.
dlls/winex11.drv/mouse.c | 46 +++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 17 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index dd25f8b172c..8a379e5a3b7 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -587,6 +587,34 @@ static BOOL is_old_motion_event( unsigned long serial ) }
+/*********************************************************************** + * map_event_coords + * + * Map the input event coordinates so they're relative to the desktop. + */ +static POINT map_event_coords( HWND hwnd, Window window, struct x11drv_win_data *data, const INPUT *input ) +{ + POINT pt = { input->u.mi.dx, input->u.mi.dy }; + + TRACE( "hwnd %p, window %lx, data %p, input %p\n", hwnd, window, data, input ); + + if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y ); + if (window == data->whole_window) + { + pt.x += data->whole_rect.left - data->client_rect.left; + pt.y += data->whole_rect.top - data->client_rect.top; + } + + if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) + pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x; + MapWindowPoints( hwnd, 0, &pt, 1 ); + + TRACE( "mapped %s to %s\n", wine_dbgstr_point( (POINT *)&input->u.mi.dx ), wine_dbgstr_point( &pt ) ); + + return pt; +} + + /*********************************************************************** * send_mouse_input * @@ -618,24 +646,8 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU return; }
- if (window != root_window) - { - pt.x = input->u.mi.dx; - pt.y = input->u.mi.dy; - } - else pt = root_to_virtual_screen( input->u.mi.dx, input->u.mi.dy ); - if (!(data = get_win_data( hwnd ))) return; - - if (window == data->whole_window) - { - pt.x += data->whole_rect.left - data->client_rect.left; - pt.y += data->whole_rect.top - data->client_rect.top; - } - - if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) - pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x; - MapWindowPoints( hwnd, 0, &pt, 1 ); + pt = map_event_coords( hwnd, window, data, input );
if (InterlockedExchangePointer( (void **)&cursor_window, hwnd ) != hwnd || input->u.mi.time - last_cursor_change > 100)
Based on a patch from Gabriel Ivăncescu gabrielopcode@gmail.com. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46309
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/mouse.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 8a379e5a3b7..8b39458fd37 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -592,7 +592,7 @@ static BOOL is_old_motion_event( unsigned long serial ) * * Map the input event coordinates so they're relative to the desktop. */ -static POINT map_event_coords( HWND hwnd, Window window, struct x11drv_win_data *data, const INPUT *input ) +static void map_event_coords( HWND hwnd, Window window, struct x11drv_win_data *data, INPUT *input ) { POINT pt = { input->u.mi.dx, input->u.mi.dy };
@@ -611,7 +611,8 @@ static POINT map_event_coords( HWND hwnd, Window window, struct x11drv_win_data
TRACE( "mapped %s to %s\n", wine_dbgstr_point( (POINT *)&input->u.mi.dx ), wine_dbgstr_point( &pt ) );
- return pt; + input->u.mi.dx = pt.x; + input->u.mi.dy = pt.y; }
@@ -623,7 +624,6 @@ static POINT map_event_coords( HWND hwnd, Window window, struct x11drv_win_data static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPUT *input ) { struct x11drv_win_data *data; - POINT pt;
input->type = INPUT_MOUSE;
@@ -647,7 +647,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU }
if (!(data = get_win_data( hwnd ))) return; - pt = map_event_coords( hwnd, window, data, input ); + map_event_coords( hwnd, window, data, input );
if (InterlockedExchangePointer( (void **)&cursor_window, hwnd ) != hwnd || input->u.mi.time - last_cursor_change > 100) @@ -670,8 +670,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU /* ignore event if a button is pressed, since the mouse is then grabbed too */ !(state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask|Button6Mask|Button7Mask))) { - RECT rect; - SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 ); + RECT rect = { input->u.mi.dx, input->u.mi.dy, input->u.mi.dx + 1, input->u.mi.dy + 1 };
SERVER_START_REQ( update_window_zorder ) { @@ -685,8 +684,6 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU SERVER_END_REQ; }
- input->u.mi.dx = pt.x; - input->u.mi.dy = pt.y; __wine_send_input( hwnd, input ); }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
We already converted coordinates from root to virtual screen, we shouldn't need to remap them.
Based on a patch from Gabriel Ivăncescu gabrielopcode@gmail.com. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46309
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/mouse.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 8b39458fd37..fedf70c7dad 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -599,15 +599,15 @@ static void map_event_coords( HWND hwnd, Window window, struct x11drv_win_data * TRACE( "hwnd %p, window %lx, data %p, input %p\n", hwnd, window, data, input );
if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y ); - if (window == data->whole_window) + else if (window == data->whole_window) { pt.x += data->whole_rect.left - data->client_rect.left; pt.y += data->whole_rect.top - data->client_rect.top; - }
- if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) - pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x; - MapWindowPoints( hwnd, 0, &pt, 1 ); + if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) + pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x; + MapWindowPoints( hwnd, 0, &pt, 1 ); + }
TRACE( "mapped %s to %s\n", wine_dbgstr_point( (POINT *)&input->u.mi.dx ), wine_dbgstr_point( &pt ) );
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
Rémi Bernon rbernon@codeweavers.com writes:
@@ -599,15 +599,15 @@ static void map_event_coords( HWND hwnd, Window window, struct x11drv_win_data * TRACE( "hwnd %p, window %lx, data %p, input %p\n", hwnd, window, data, input );
if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y );
- if (window == data->whole_window)
- else if (window == data->whole_window) { pt.x += data->whole_rect.left - data->client_rect.left; pt.y += data->whole_rect.top - data->client_rect.top;
}
if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x;
MapWindowPoints( hwnd, 0, &pt, 1 );
if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x;
MapWindowPoints( hwnd, 0, &pt, 1 );
- }
This is wrong, you'd still need to map them for the client window.
On 3/31/21 7:52 PM, Alexandre Julliard wrote:
Rémi Bernon rbernon@codeweavers.com writes:
@@ -599,15 +599,15 @@ static void map_event_coords( HWND hwnd, Window window, struct x11drv_win_data * TRACE( "hwnd %p, window %lx, data %p, input %p\n", hwnd, window, data, input );
if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y );
- if (window == data->whole_window)
- else if (window == data->whole_window) { pt.x += data->whole_rect.left - data->client_rect.left; pt.y += data->whole_rect.top - data->client_rect.top;
}
if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x;
MapWindowPoints( hwnd, 0, &pt, 1 );
if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x;
MapWindowPoints( hwnd, 0, &pt, 1 );
- }
This is wrong, you'd still need to map them for the client window.
Can this happen? I don't think we register input for the client windows.
As far as I can see the event's window is always the whole_window, for which we selected pointer motion events, and that received input.
Rémi Bernon rbernon@codeweavers.com writes:
On 3/31/21 7:52 PM, Alexandre Julliard wrote:
Rémi Bernon rbernon@codeweavers.com writes:
@@ -599,15 +599,15 @@ static void map_event_coords( HWND hwnd, Window window, struct x11drv_win_data * TRACE( "hwnd %p, window %lx, data %p, input %p\n", hwnd, window, data, input ); if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y );
- if (window == data->whole_window)
- else if (window == data->whole_window) { pt.x += data->whole_rect.left - data->client_rect.left; pt.y += data->whole_rect.top - data->client_rect.top;
- }
- if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x;
- MapWindowPoints( hwnd, 0, &pt, 1 );
if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x;
MapWindowPoints( hwnd, 0, &pt, 1 );
- }
This is wrong, you'd still need to map them for the client window.
Can this happen? I don't think we register input for the client windows.
As far as I can see the event's window is always the whole_window, for which we selected pointer motion events, and that received input.
It was happening at some point. I think we might as well keep the check in case we change things and get client window events again, but otherwise the if() should be removed.
Based on a patch from Gabriel Ivăncescu gabrielopcode@gmail.com. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46309
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/mouse.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index fedf70c7dad..66d7d423a62 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -592,13 +592,24 @@ static BOOL is_old_motion_event( unsigned long serial ) * * Map the input event coordinates so they're relative to the desktop. */ -static void map_event_coords( HWND hwnd, Window window, struct x11drv_win_data *data, INPUT *input ) +static void map_event_coords( HWND hwnd, Window window, INPUT *input ) { + struct x11drv_thread_data *thread_data; + struct x11drv_win_data *data = NULL; POINT pt = { input->u.mi.dx, input->u.mi.dy };
- TRACE( "hwnd %p, window %lx, data %p, input %p\n", hwnd, window, data, input ); + TRACE( "hwnd %p, window %lx, input %p\n", hwnd, window, input );
- if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y ); + if (!hwnd) + { + thread_data = x11drv_thread_data(); + if (!thread_data->clip_hwnd) return; + if (thread_data->clip_window != window) return; + pt.x += clip_rect.left; + pt.y += clip_rect.top; + } + else if (!(data = get_win_data( hwnd ))) return; + else if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y ); else if (window == data->whole_window) { pt.x += data->whole_rect.left - data->client_rect.left; @@ -608,6 +619,7 @@ static void map_event_coords( HWND hwnd, Window window, struct x11drv_win_data * pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x; MapWindowPoints( hwnd, 0, &pt, 1 ); } + if (data) release_win_data( data );
TRACE( "mapped %s to %s\n", wine_dbgstr_point( (POINT *)&input->u.mi.dx ), wine_dbgstr_point( &pt ) );
@@ -640,15 +652,11 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU sync_window_cursor( window ); last_cursor_change = input->u.mi.time; } - input->u.mi.dx += clip_rect.left; - input->u.mi.dy += clip_rect.top; __wine_send_input( hwnd, input ); return; }
if (!(data = get_win_data( hwnd ))) return; - map_event_coords( hwnd, window, data, input ); - if (InterlockedExchangePointer( (void **)&cursor_window, hwnd ) != hwnd || input->u.mi.time - last_cursor_change > 100) { @@ -1696,6 +1704,7 @@ BOOL X11DRV_ButtonPress( HWND hwnd, XEvent *xev ) input.u.mi.dwExtraInfo = 0;
update_user_time( event->time ); + map_event_coords( hwnd, event->window, &input ); send_mouse_input( hwnd, event->window, event->state, &input ); return TRUE; } @@ -1721,6 +1730,7 @@ BOOL X11DRV_ButtonRelease( HWND hwnd, XEvent *xev ) input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); input.u.mi.dwExtraInfo = 0;
+ map_event_coords( hwnd, event->window, &input ); send_mouse_input( hwnd, event->window, event->state, &input ); return TRUE; } @@ -1749,6 +1759,7 @@ BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *xev ) TRACE( "pos %d,%d old serial %lu, ignoring\n", input.u.mi.dx, input.u.mi.dy, event->serial ); return FALSE; } + map_event_coords( hwnd, event->window, &input ); send_mouse_input( hwnd, event->window, event->state, &input ); return TRUE; } @@ -1780,6 +1791,7 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev ) TRACE( "pos %d,%d old serial %lu, ignoring\n", input.u.mi.dx, input.u.mi.dy, event->serial ); return FALSE; } + map_event_coords( hwnd, event->window, &input ); send_mouse_input( hwnd, event->window, event->state, &input ); return TRUE; }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Since whole_rect / client_rect are updated asynchronously, there may be a small lag between X11 and Wine regarding the expected window position.
Then, as events' x and y fields are reported relative to the X11 window position, this lag can cause inconsistencies when we compute absolute mouse positions.
Also, applications that control their own position while being moved cause additional whole_rect / client_rect updates, before X11 knows about it.
This can make applications like Winamp go nuts when they are being moved and move all over the place "randomly".
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46309 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/mouse.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 66d7d423a62..57cf0725cdd 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -592,13 +592,14 @@ static BOOL is_old_motion_event( unsigned long serial ) * * Map the input event coordinates so they're relative to the desktop. */ -static void map_event_coords( HWND hwnd, Window window, INPUT *input ) +static void map_event_coords( HWND hwnd, Window window, Window event_root, int x_root, int y_root, INPUT *input ) { struct x11drv_thread_data *thread_data; struct x11drv_win_data *data = NULL; POINT pt = { input->u.mi.dx, input->u.mi.dy };
- TRACE( "hwnd %p, window %lx, input %p\n", hwnd, window, input ); + TRACE( "hwnd %p, window %lx, event_root %lx, x_root %d, y_root %d, input %p\n", hwnd, window, event_root, + x_root, y_root, input );
if (!hwnd) { @@ -610,6 +611,7 @@ static void map_event_coords( HWND hwnd, Window window, INPUT *input ) } else if (!(data = get_win_data( hwnd ))) return; else if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y ); + else if (event_root == root_window) pt = root_to_virtual_screen( x_root, y_root ); else if (window == data->whole_window) { pt.x += data->whole_rect.left - data->client_rect.left; @@ -1704,7 +1706,7 @@ BOOL X11DRV_ButtonPress( HWND hwnd, XEvent *xev ) input.u.mi.dwExtraInfo = 0;
update_user_time( event->time ); - map_event_coords( hwnd, event->window, &input ); + map_event_coords( hwnd, event->window, event->root, event->x_root, event->y_root, &input ); send_mouse_input( hwnd, event->window, event->state, &input ); return TRUE; } @@ -1730,7 +1732,7 @@ BOOL X11DRV_ButtonRelease( HWND hwnd, XEvent *xev ) input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); input.u.mi.dwExtraInfo = 0;
- map_event_coords( hwnd, event->window, &input ); + map_event_coords( hwnd, event->window, event->root, event->x_root, event->y_root, &input ); send_mouse_input( hwnd, event->window, event->state, &input ); return TRUE; } @@ -1759,7 +1761,7 @@ BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *xev ) TRACE( "pos %d,%d old serial %lu, ignoring\n", input.u.mi.dx, input.u.mi.dy, event->serial ); return FALSE; } - map_event_coords( hwnd, event->window, &input ); + map_event_coords( hwnd, event->window, event->root, event->x_root, event->y_root, &input ); send_mouse_input( hwnd, event->window, event->state, &input ); return TRUE; } @@ -1791,7 +1793,7 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev ) TRACE( "pos %d,%d old serial %lu, ignoring\n", input.u.mi.dx, input.u.mi.dy, event->serial ); return FALSE; } - map_event_coords( hwnd, event->window, &input ); + map_event_coords( hwnd, event->window, event->root, event->x_root, event->y_root, &input ); send_mouse_input( hwnd, event->window, event->state, &input ); return TRUE; }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com