diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 54c892d296e..829177793ef 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -1055,17 +1055,46 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind int32_t x_new = x_screen; int32_t y_new = y_screen; int32_t x_accum, y_accum; - GHOST_Rect bounds; - /* Fallback to window bounds. */ - if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) { - window->getClientBounds(bounds); + /* Warp within bounds. */ + { + GHOST_Rect bounds; + int32_t bounds_margin = 0; + GHOST_TAxisFlag bounds_axis = GHOST_kAxisNone; + + if (window->getCursorGrabMode() == GHOST_kGrabHide) { + window->getClientBounds(bounds); + + /* WARNING(@campbellbarton): The current warping logic fails to warp on every event, + * so the box needs to small enough not to let the cursor escape the window but large + * enough that the cursor isn't being warped every time. + * If this was not the case it would be less trouble to simply warp the cursor to the + * center of the screen on every motion, see: T102346. */ + const int32_t subregion_div = 4; /* One quarter of the region. */ + const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()}; + const int center[2] = {(bounds.m_l + bounds.m_r) / 2, (bounds.m_t + bounds.m_b) / 2}; + /* Shrink the box to prevent the cursor escaping. */ + bounds.m_l = center[0] - (size[0] / (subregion_div * 2)); + bounds.m_r = center[0] + (size[0] / (subregion_div * 2)); + bounds.m_t = center[1] - (size[1] / (subregion_div * 2)); + bounds.m_b = center[1] + (size[1] / (subregion_div * 2)); + bounds_margin = 0; + bounds_axis = GHOST_TAxisFlag(GHOST_kAxisX | GHOST_kAxisY); + } + else { + /* Fallback to window bounds. */ + if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) { + window->getClientBounds(bounds); + } + bounds_margin = 2; + bounds_axis = window->getCursorGrabAxis(); + } + + /* Could also clamp to screen bounds wrap with a window outside the view will + * fail at the moment. Use inset in case the window is at screen bounds. */ + bounds.wrapPoint(x_new, y_new, bounds_margin, bounds_axis); } - /* Could also clamp to screen bounds wrap with a window outside the view will - * fail at the moment. Use inset in case the window is at screen bounds. */ - bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis()); - window->getCursorGrabAccum(x_accum, y_accum); if (x_new != x_screen || y_new != y_screen) { system->setCursorPosition(x_new, y_new); /* wrap */ diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 5c89febe97c..9e424015d0c 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -934,17 +934,45 @@ void GHOST_SystemX11::processEvent(XEvent *xe) int32_t x_new = xme.x_root; int32_t y_new = xme.y_root; int32_t x_accum, y_accum; - GHOST_Rect bounds; - /* fallback to window bounds */ - if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) { - window->getClientBounds(bounds); + /* Warp within bounds. */ + { + GHOST_Rect bounds; + int32_t bounds_margin = 0; + GHOST_TAxisFlag bounds_axis = GHOST_kAxisNone; + + if (window->getCursorGrabMode() == GHOST_kGrabHide) { + window->getClientBounds(bounds); + + /* TODO(@campbellbarton): warp the cursor to `window->getCursorGrabInitPos`, + * on every motion event, see: T102346. */ + const int32_t subregion_div = 4; /* One quarter of the region. */ + const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()}; + const int center[2] = {(bounds.m_l + bounds.m_r) / 2, (bounds.m_t + bounds.m_b) / 2}; + /* Shrink the box to prevent the cursor escaping. */ + bounds.m_l = center[0] - (size[0] / (subregion_div * 2)); + bounds.m_r = center[0] + (size[0] / (subregion_div * 2)); + bounds.m_t = center[1] - (size[1] / (subregion_div * 2)); + bounds.m_b = center[1] + (size[1] / (subregion_div * 2)); + bounds_margin = 0; + bounds_axis = GHOST_TAxisFlag(GHOST_kAxisX | GHOST_kAxisY); + } + else { + /* Fallback to window bounds. */ + if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) { + window->getClientBounds(bounds); + } + /* Could also clamp to screen bounds wrap with a window outside the view will + * fail at the moment. Use offset of 8 in case the window is at screen bounds. */ + bounds_margin = 8; + bounds_axis = window->getCursorGrabAxis(); + } + + /* Could also clamp to screen bounds wrap with a window outside the view will + * fail at the moment. Use inset in case the window is at screen bounds. */ + bounds.wrapPoint(x_new, y_new, bounds_margin, bounds_axis); } - /* Could also clamp to screen bounds wrap with a window outside the view will - * fail at the moment. Use offset of 8 in case the window is at screen bounds. */ - bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis()); - window->getCursorGrabAccum(x_accum, y_accum); if (x_new != xme.x_root || y_new != xme.y_root) {