winex11.drv: Retry last ClipCursor when grab is released.
As we ignore these NotifyGrab / NotifyUngrab w.r.t focus decisions, some applications are unaware of mouse grabs being lost and sometimes cursor clipping is lost. We have to keep the last clip rectangle and restore it when grab is released. This has been squashed with the foreground window check from Zhiyi Zhang <zzhang@codeweavers.com> to fix an issue that happens when switching from a fullscreen window - because there's some additional focus events involved - but in general, if the window that is getting focus cannot be activated: When FocusIn/NotifyWhileGrabbed is received, SetForegroundWindow is not called if the window cannot be activated. When the FocusIn/NotifyUngrab event arrives for the same window, we have to check the foreground window before restoring cursor clipping rectangle. For reference, the event sequence when pressing Alt-Tab - for WMs that grab the keyboard - is the following: 1. FocusOut/NotifyGrab, when WM grabs the keyboard. 2. FocusOut/NotifyWhileGrabbed, while WM switches windows, this calls SetForegroundWindow(GetDesktopWindow()). The event sequence for normal windows ends here, but for fullscreen windows, there may be these additional events: 3. FocusIn/NotifyWhileGrabbed, which may not change Wine foreground window if it cannot be activated. 4. FocusIn/NotifyUnGrab, when WM releases the keyboard while switching windows, this is ignored but it should not retry to grab the cursor, because window is not foreground. 5. FocusOut/NotifyNormal, when WM finishes switching the windows. Signed-off-by: Rémi Bernon <rbernon@codeweavers.com> Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
54f8077c41
commit
92177b0b16
|
@ -788,6 +788,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
|
||||||
break;
|
break;
|
||||||
case NotifyUngrab:
|
case NotifyUngrab:
|
||||||
keyboard_grabbed = FALSE;
|
keyboard_grabbed = FALSE;
|
||||||
|
retry_grab_clipping_window();
|
||||||
return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
|
return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,6 +889,13 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev )
|
||||||
break;
|
break;
|
||||||
case NotifyGrab:
|
case NotifyGrab:
|
||||||
keyboard_grabbed = TRUE;
|
keyboard_grabbed = TRUE;
|
||||||
|
|
||||||
|
/* This will do nothing due to keyboard_grabbed == TRUE, but it
|
||||||
|
* will save the current clipping rect so we can restore it on
|
||||||
|
* FocusIn with NotifyUngrab mode.
|
||||||
|
*/
|
||||||
|
retry_grab_clipping_window();
|
||||||
|
|
||||||
return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
|
return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,9 @@ XContext cursor_context = 0;
|
||||||
static HWND cursor_window;
|
static HWND cursor_window;
|
||||||
static HCURSOR last_cursor;
|
static HCURSOR last_cursor;
|
||||||
static DWORD last_cursor_change;
|
static DWORD last_cursor_change;
|
||||||
|
static RECT last_clip_rect;
|
||||||
|
static HWND last_clip_foreground_window;
|
||||||
|
static BOOL last_clip_refused;
|
||||||
static RECT clip_rect;
|
static RECT clip_rect;
|
||||||
static Cursor create_cursor( HANDLE handle );
|
static Cursor create_cursor( HANDLE handle );
|
||||||
|
|
||||||
|
@ -395,8 +398,15 @@ static BOOL grab_clipping_window( const RECT *clip )
|
||||||
if (keyboard_grabbed)
|
if (keyboard_grabbed)
|
||||||
{
|
{
|
||||||
WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) );
|
WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) );
|
||||||
|
last_clip_refused = TRUE;
|
||||||
|
last_clip_foreground_window = GetForegroundWindow();
|
||||||
|
last_clip_rect = *clip;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last_clip_refused = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* enable XInput2 unless we are already clipping */
|
/* enable XInput2 unless we are already clipping */
|
||||||
if (!data->clip_hwnd) enable_xinput2();
|
if (!data->clip_hwnd) enable_xinput2();
|
||||||
|
@ -470,6 +480,20 @@ void reset_clipping_window(void)
|
||||||
ClipCursor( NULL ); /* make sure the clip rectangle is reset too */
|
ClipCursor( NULL ); /* make sure the clip rectangle is reset too */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* retry_grab_clipping_window
|
||||||
|
*
|
||||||
|
* Restore the current clip rectangle or retry the last one if it has
|
||||||
|
* been refused because of an active keyboard grab.
|
||||||
|
*/
|
||||||
|
void retry_grab_clipping_window(void)
|
||||||
|
{
|
||||||
|
if (clipping_cursor)
|
||||||
|
ClipCursor( &clip_rect );
|
||||||
|
else if (last_clip_refused && GetForegroundWindow() == last_clip_foreground_window)
|
||||||
|
ClipCursor( &last_clip_rect );
|
||||||
|
}
|
||||||
|
|
||||||
BOOL CDECL X11DRV_ClipCursor( const RECT *clip );
|
BOOL CDECL X11DRV_ClipCursor( const RECT *clip );
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
|
@ -624,6 +624,7 @@ extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN;
|
||||||
extern LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN;
|
extern LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN;
|
||||||
extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN;
|
extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN;
|
||||||
extern void reset_clipping_window(void) DECLSPEC_HIDDEN;
|
extern void reset_clipping_window(void) DECLSPEC_HIDDEN;
|
||||||
|
extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN;
|
||||||
extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN;
|
extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN;
|
||||||
extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN;
|
extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN;
|
||||||
extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN;
|
extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN;
|
||||||
|
|
Loading…
Reference in New Issue