diff --git a/CMakeLists.txt b/CMakeLists.txt index b3a0dfa96eb..4492e9c2cb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,6 +285,7 @@ endif() if(WITH_X11) option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON) option(WITH_X11_XF86VMODE "Enable X11 video mode switching" ON) + option(WITH_X11_XFIXES "Enable X11 XWayland cursor warping workaround" ON) option(WITH_X11_ALPHA "Enable X11 transparent background" ON) endif() @@ -687,6 +688,7 @@ if(WITH_GHOST_SDL OR WITH_HEADLESS) set(WITH_X11 OFF) set(WITH_X11_XINPUT OFF) set(WITH_X11_XF86VMODE OFF) + set(WITH_X11_XFIXES OFF) set(WITH_X11_ALPHA OFF) set(WITH_GHOST_XDND OFF) set(WITH_INPUT_IME OFF) @@ -838,6 +840,14 @@ if(WITH_X11) endif() endif() + if(WITH_X11_XFIXES) + if(X11_Xfixes_LIB) + list(APPEND PLATFORM_LINKLIBS ${X11_Xfixes_LIB}) + else() + set(WITH_X11_XFIXES OFF) + endif() + endif() + if(WITH_X11_ALPHA) find_library(X11_Xrender_LIB Xrender ${X11_LIB_SEARCH_PATH}) mark_as_advanced(X11_Xrender_LIB) @@ -1707,6 +1717,7 @@ if(FIRST_RUN) info_cfg_option(WITH_INSTALL_PORTABLE) info_cfg_option(WITH_X11_ALPHA) info_cfg_option(WITH_X11_XF86VMODE) + info_cfg_option(WITH_X11_XFIXES) info_cfg_option(WITH_X11_XINPUT) info_cfg_option(WITH_MEM_JEMALLOC) info_cfg_option(WITH_MEM_VALGRIND) diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 31e92c94eed..5a97da28d17 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -219,6 +219,13 @@ elseif(WITH_X11) ) endif() + if(WITH_X11_XFIXES) + add_definitions(-DWITH_X11_XFIXES) + list(APPEND INC_SYS + ${X11_Xfixes_INCLUDE_PATH} + ) + endif() + if(WITH_X11_ALPHA) add_definitions(-DWITH_X11_ALPHA) endif() diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 8fff565338f..9b617a34e1a 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -61,6 +61,12 @@ #include #endif +#ifdef WITH_X11_XFIXES +# include +/* Workaround for XWayland grab glitch: T53004. */ +#define WITH_XWAYLAND_HACK +#endif + /* for XIWarpPointer */ #ifdef WITH_X11_XINPUT # include @@ -95,6 +101,10 @@ static GHOST_TKey convertXKey(KeySym key); static char *txt_cut_buffer = NULL; static char *txt_select_buffer = NULL; +#ifdef WITH_XWAYLAND_HACK +static bool use_xwayland_hack = false; +#endif + using namespace std; GHOST_SystemX11:: @@ -176,7 +186,11 @@ GHOST_SystemX11( if (use_xkb) { XkbSetDetectableAutoRepeat(m_display, true, NULL); } - + +#ifdef WITH_XWAYLAND_HACK + use_xwayland_hack = getenv("WAYLAND_DISPLAY") != NULL; +#endif + #ifdef WITH_X11_XINPUT /* detect if we have xinput (for reuse) */ { @@ -1472,23 +1486,21 @@ getButtons( return GHOST_kSuccess; } - -GHOST_TSuccess -GHOST_SystemX11:: -getCursorPosition( - GHOST_TInt32& x, - GHOST_TInt32& y) const +static GHOST_TSuccess getCursorPosition_impl( + Display *display, + GHOST_TInt32& x, + GHOST_TInt32& y, + Window *child_return) { - - Window root_return, child_return; int rx, ry, wx, wy; unsigned int mask_return; + Window root_return; if (XQueryPointer( - m_display, - RootWindow(m_display, DefaultScreen(m_display)), + display, + RootWindow(display, DefaultScreen(display)), &root_return, - &child_return, + child_return, &rx, &ry, &wx, &wy, &mask_return @@ -1498,10 +1510,20 @@ getCursorPosition( else { x = rx; y = ry; - } + } return GHOST_kSuccess; } +GHOST_TSuccess +GHOST_SystemX11:: +getCursorPosition( + GHOST_TInt32& x, + GHOST_TInt32& y) const +{ + Window child_return; + return getCursorPosition_impl(m_display, x, y, &child_return); +} + GHOST_TSuccess GHOST_SystemX11:: @@ -1515,13 +1537,29 @@ setCursorPosition( * current pointer position. */ int cx, cy; + +#ifdef WITH_XWAYLAND_HACK + Window child_return = None; + if (getCursorPosition_impl(m_display, cx, cy, &child_return) == GHOST_kFailure) { + return GHOST_kFailure; + } +#else if (getCursorPosition(cx, cy) == GHOST_kFailure) { return GHOST_kFailure; } +#endif int relx = x - cx; int rely = y - cy; +#ifdef WITH_XWAYLAND_HACK + if (use_xwayland_hack) { + if (child_return != None) { + XFixesHideCursor(m_display, child_return); + } + } +#endif + #ifdef WITH_X11_XINPUT if ((m_xinput_version.present) && (m_xinput_version.major_version >= 2)) @@ -1538,6 +1576,14 @@ setCursorPosition( XWarpPointer(m_display, None, None, 0, 0, 0, 0, relx, rely); } +#ifdef WITH_XWAYLAND_HACK + if (use_xwayland_hack) { + if (child_return != None) { + XFixesShowCursor(m_display, child_return); + } + } +#endif + XSync(m_display, 0); /* Sync to process all requests */ return GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 9e019b233f6..1abdec37403 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -1526,7 +1526,6 @@ setWindowCursorGrab( else { if (m_cursorGrab == GHOST_kGrabHide) { m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); - setWindowCursorVisibility(true); } if (m_cursorGrab != GHOST_kGrabNormal) { @@ -1550,6 +1549,11 @@ setWindowCursorGrab( } } + /* Perform this last so to workaround XWayland bug, see: T53004. */ + if (m_cursorGrab == GHOST_kGrabHide) { + setWindowCursorVisibility(true); + } + /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ setCursorGrabAccum(0, 0); m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */