diff --git a/src/win32_platform.h b/src/win32_platform.h index c2158943..82b34bb9 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -452,6 +452,8 @@ typedef struct _GLFWlibraryWin32 double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active _GLFWwindow* disabledCursorWindow; + // The window the cursor is captured in + _GLFWwindow* capturedCursorWindow; RAWINPUT* rawInput; int rawInputSize; UINT mouseTrailSize; diff --git a/src/win32_window.c b/src/win32_window.c index 168529e2..4cf25640 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -249,20 +249,24 @@ static void updateCursorImage(_GLFWwindow* window) SetCursor(NULL); } -// Updates the cursor clip rect +// Sets the cursor clip rect to the window content area // -static void updateClipRect(_GLFWwindow* window) +static void captureCursor(_GLFWwindow* window) { - if (window) - { - RECT clipRect; - GetClientRect(window->win32.handle, &clipRect); - ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); - ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); - ClipCursor(&clipRect); - } - else - ClipCursor(NULL); + RECT clipRect; + GetClientRect(window->win32.handle, &clipRect); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); + ClipCursor(&clipRect); + _glfw.win32.capturedCursorWindow = window; +} + +// Disabled clip cursor +// +static void releaseCursor(void) +{ + ClipCursor(NULL); + _glfw.win32.capturedCursorWindow = NULL; } // Enables WM_INPUT messages for the mouse for the specified window @@ -301,7 +305,7 @@ static void disableCursor(_GLFWwindow* window) &_glfw.win32.restoreCursorPosY); updateCursorImage(window); _glfwCenterCursorInContentArea(window); - updateClipRect(window); + captureCursor(window); if (window->rawMouseMotion) enableRawMouseMotion(window); @@ -315,7 +319,7 @@ static void enableCursor(_GLFWwindow* window) disableRawMouseMotion(window); _glfw.win32.disabledCursorWindow = NULL; - updateClipRect(NULL); + releaseCursor(); _glfwSetCursorPosWin32(window, _glfw.win32.restoreCursorPosX, _glfw.win32.restoreCursorPosY); @@ -1004,8 +1008,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l (window->win32.maximized && wParam != SIZE_RESTORED); - if (_glfw.win32.disabledCursorWindow == window) - updateClipRect(window); + if (_glfw.win32.capturedCursorWindow == window) + captureCursor(window); if (window->win32.iconified != iconified) _glfwInputWindowIconify(window, iconified); @@ -1040,8 +1044,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l case WM_MOVE: { - if (_glfw.win32.disabledCursorWindow == window) - updateClipRect(window); + if (_glfw.win32.capturedCursorWindow == window) + captureCursor(window); // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as // those macros do not handle negative window positions correctly @@ -1495,7 +1499,10 @@ void _glfwDestroyWindowWin32(_GLFWwindow* window) window->context.destroy(window); if (_glfw.win32.disabledCursorWindow == window) - _glfw.win32.disabledCursorWindow = NULL; + enableCursor(window); + + if (_glfw.win32.capturedCursorWindow == window) + releaseCursor(); if (window->win32.handle) { @@ -2142,14 +2149,40 @@ void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos) void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode) { - if (mode == GLFW_CURSOR_DISABLED) + if (_glfwWindowFocusedWin32(window)) { - if (_glfwWindowFocusedWin32(window)) - disableCursor(window); + if (mode == GLFW_CURSOR_DISABLED) + { + _glfwGetCursorPosWin32(window, + &_glfw.win32.restoreCursorPosX, + &_glfw.win32.restoreCursorPosY); + _glfwCenterCursorInContentArea(window); + if (window->rawMouseMotion) + enableRawMouseMotion(window); + } + else if (_glfw.win32.disabledCursorWindow == window) + { + if (window->rawMouseMotion) + disableRawMouseMotion(window); + } + + if (mode == GLFW_CURSOR_DISABLED) + captureCursor(window); + else + releaseCursor(); + + if (mode == GLFW_CURSOR_DISABLED) + _glfw.win32.disabledCursorWindow = window; + else if (_glfw.win32.disabledCursorWindow == window) + { + _glfw.win32.disabledCursorWindow = NULL; + _glfwSetCursorPosWin32(window, + _glfw.win32.restoreCursorPosX, + _glfw.win32.restoreCursorPosY); + } } - else if (_glfw.win32.disabledCursorWindow == window) - enableCursor(window); - else if (cursorInContentArea(window)) + + if (cursorInContentArea(window)) updateCursorImage(window); } diff --git a/src/wl_window.c b/src/wl_window.c index ef346655..b4b49b94 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -2556,7 +2556,8 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor) if (!window->wl.lockedPointer) lockPointer(window); } - else + else if (window->cursorMode == GLFW_CURSOR_NORMAL || + window->cursorMode == GLFW_CURSOR_HIDDEN) { if (window->wl.lockedPointer) unlockPointer(window); @@ -2597,8 +2598,11 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor) setCursorImage(window, &cursorWayland); } } - else + else if (window->cursorMode == GLFW_CURSOR_HIDDEN || + window->cursorMode == GLFW_CURSOR_DISABLED) + { wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, NULL, 0, 0); + } } static void dataSourceHandleTarget(void* userData, diff --git a/src/x11_window.c b/src/x11_window.c index 98f990b2..f323db6c 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -470,6 +470,25 @@ static void updateCursorImage(_GLFWwindow* window) } } +// Grabs the cursor and confines it to the window +// +static void captureCursor(_GLFWwindow* window) +{ + XGrabPointer(_glfw.x11.display, window->x11.handle, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + window->x11.handle, + None, + CurrentTime); +} + +// Ungrabs the cursor +// +static void releaseCursor(void) +{ + XUngrabPointer(_glfw.x11.display, CurrentTime); +} + // Enable XI2 raw mouse motion events // static void enableRawMouseMotion(_GLFWwindow* window) @@ -512,12 +531,7 @@ static void disableCursor(_GLFWwindow* window) &_glfw.x11.restoreCursorPosY); updateCursorImage(window); _glfwCenterCursorInContentArea(window); - XGrabPointer(_glfw.x11.display, window->x11.handle, True, - ButtonPressMask | ButtonReleaseMask | PointerMotionMask, - GrabModeAsync, GrabModeAsync, - window->x11.handle, - _glfw.x11.hiddenCursorHandle, - CurrentTime); + captureCursor(window); } // Exit disabled cursor mode for the specified window @@ -528,7 +542,7 @@ static void enableCursor(_GLFWwindow* window) disableRawMouseMotion(window); _glfw.x11.disabledCursorWindow = NULL; - XUngrabPointer(_glfw.x11.display, CurrentTime); + releaseCursor(); _glfwSetCursorPosX11(window, _glfw.x11.restoreCursorPosX, _glfw.x11.restoreCursorPosY); @@ -1986,7 +2000,7 @@ GLFWbool _glfwCreateWindowX11(_GLFWwindow* window, void _glfwDestroyWindowX11(_GLFWwindow* window) { if (_glfw.x11.disabledCursorWindow == window) - _glfw.x11.disabledCursorWindow = NULL; + enableCursor(window); if (window->monitor) releaseMonitor(window); @@ -2800,16 +2814,40 @@ void _glfwSetCursorPosX11(_GLFWwindow* window, double x, double y) void _glfwSetCursorModeX11(_GLFWwindow* window, int mode) { - if (mode == GLFW_CURSOR_DISABLED) + if (_glfwWindowFocusedX11(window)) { - if (_glfwWindowFocusedX11(window)) - disableCursor(window); - } - else if (_glfw.x11.disabledCursorWindow == window) - enableCursor(window); - else - updateCursorImage(window); + if (mode == GLFW_CURSOR_DISABLED) + { + _glfwGetCursorPosX11(window, + &_glfw.x11.restoreCursorPosX, + &_glfw.x11.restoreCursorPosY); + _glfwCenterCursorInContentArea(window); + if (window->rawMouseMotion) + enableRawMouseMotion(window); + } + else if (_glfw.x11.disabledCursorWindow == window) + { + if (window->rawMouseMotion) + disableRawMouseMotion(window); + } + if (mode == GLFW_CURSOR_DISABLED) + captureCursor(window); + else + releaseCursor(); + + if (mode == GLFW_CURSOR_DISABLED) + _glfw.x11.disabledCursorWindow = window; + else if (_glfw.x11.disabledCursorWindow == window) + { + _glfw.x11.disabledCursorWindow = NULL; + _glfwSetCursorPosX11(window, + _glfw.x11.restoreCursorPosX, + _glfw.x11.restoreCursorPosY); + } + } + + updateCursorImage(window); XFlush(_glfw.x11.display); }