diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 031962ec..7a544eb6 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -79,6 +79,7 @@ video tutorials. - Jason Francis - Gerald Franz - Mário Freitas + - Friz64 - GeO4d - Marcus Geelnard - Gegy diff --git a/README.md b/README.md index 518d31cb..ab346ae6 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,8 @@ information on what to include when reporting a bug. compositors without `pointer-constraints-unstable-v1` - [Wayland] Bugfix: Key repeat did not function on very old compositors - [Wayland] Bugfix: The `libwayland-client` library was not unloaded at termination + - [Wayland] Bugfix: Scroll events were sent twice on some versions of GNOME (#2494) + - [Wayland] Bugfix: Two-dimensional scroll input was emitted as separate axes - [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631) - [X11] Bugfix: Occasional crash when an idle display awakes (#2766) - [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale diff --git a/src/wl_init.c b/src/wl_init.c index b2fd6a88..1e527649 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -135,7 +135,7 @@ static void registryHandleGlobal(void* userData, { _glfw.wl.seat = wl_registry_bind(registry, name, &wl_seat_interface, - _glfw_min(4, version)); + _glfw_min(5, version)); _glfwAddSeatListenerWayland(_glfw.wl.seat); } } diff --git a/src/wl_platform.h b/src/wl_platform.h index c2ddb732..c9d1c251 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -414,7 +414,8 @@ typedef struct _GLFWwindowWayland GLFWbool decorations; struct wl_buffer* buffer; _GLFWfallbackEdgeWayland top, left, right, bottom; - wl_fixed_t pointerX, pointerY; + double pointerX, pointerY; + uint32_t buttonPressSerial; const char* cursorName; } fallback; } _GLFWwindowWayland; @@ -472,6 +473,17 @@ typedef struct _GLFWlibraryWayland short int scancodes[GLFW_KEY_LAST + 1]; char keynames[GLFW_KEY_LAST + 1][5]; + struct { + struct wl_surface* pointerSurface; + unsigned int events; + double pointerX; + double pointerY; + double scrollX; + double scrollY; + int button; + int action; + } pending; + struct { void* handle; struct xkb_context* context; diff --git a/src/wl_window.c b/src/wl_window.c index 1efb7256..f089f243 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -55,6 +55,11 @@ #define GLFW_BORDER_SIZE 4 #define GLFW_CAPTION_HEIGHT 24 +#define GLFW_PENDING_SURFACE 1 +#define GLFW_PENDING_BUTTON 2 +#define GLFW_PENDING_MOTION 4 +#define GLFW_PENDING_SCROLL 8 + static int createTmpfileCloexec(char* tmpname) { int fd; @@ -278,15 +283,11 @@ static void destroyFallbackDecorations(_GLFWwindow* window) destroyFallbackEdge(&window->wl.fallback.bottom); } -static void updateFallbackDecorationCursor(_GLFWwindow* window, - wl_fixed_t sx, - wl_fixed_t sy) +static void updateFallbackDecorationCursor(_GLFWwindow* window, double xpos, double ypos) { - window->wl.fallback.pointerX = sx; - window->wl.fallback.pointerY = sy; + window->wl.fallback.pointerX = xpos; + window->wl.fallback.pointerY = ypos; - const double xpos = wl_fixed_to_double(sx); - const double ypos = wl_fixed_to_double(sy); const char* cursorName = "left_ptr"; if (window->resizable) @@ -361,18 +362,16 @@ static void updateFallbackDecorationCursor(_GLFWwindow* window, } } -static void handleFallbackDecorationButton(_GLFWwindow* window, - uint32_t serial, - uint32_t button, - uint32_t state) +static void handleFallbackDecorationButton(_GLFWwindow* window, int button, int action) { - if (state != WL_POINTER_BUTTON_STATE_PRESSED) + if (action != GLFW_PRESS) return; - const double xpos = wl_fixed_to_double(window->wl.fallback.pointerX); - const double ypos = wl_fixed_to_double(window->wl.fallback.pointerY); + const double xpos = window->wl.fallback.pointerX; + const double ypos = window->wl.fallback.pointerY; + const uint32_t serial = window->wl.fallback.buttonPressSerial; - if (button == BTN_LEFT) + if (button == GLFW_MOUSE_BUTTON_LEFT) { uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE; @@ -410,7 +409,7 @@ static void handleFallbackDecorationButton(_GLFWwindow* window, if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE) xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, serial, edges); } - else if (button == BTN_RIGHT) + else if (button == GLFW_MOUSE_BUTTON_RIGHT) { if (!window->wl.xdg.toplevel) return; @@ -421,10 +420,8 @@ static void handleFallbackDecorationButton(_GLFWwindow* window, if (ypos < GLFW_BORDER_SIZE) return; - xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, - _glfw.wl.seat, serial, - xpos, - ypos - GLFW_CAPTION_HEIGHT - GLFW_BORDER_SIZE); + xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, _glfw.wl.seat, serial, + xpos, ypos - GLFW_CAPTION_HEIGHT - GLFW_BORDER_SIZE); } } @@ -1538,25 +1535,39 @@ static void pointerHandleEnter(void* userData, _glfw.wl.serial = serial; _glfw.wl.pointerEnterSerial = serial; - _glfw.wl.pointerSurface = surface; _GLFWwindow* window = wl_surface_get_user_data(surface); - if (window->wl.surface == surface) - { - _glfwSetCursorWayland(window, window->cursor); - _glfwInputCursorEnter(window, GLFW_TRUE); + const double xpos = wl_fixed_to_double(sx); + const double ypos = wl_fixed_to_double(sy); - if (window->cursorMode != GLFW_CURSOR_DISABLED) - { - window->wl.cursorPosX = wl_fixed_to_double(sx); - window->wl.cursorPosY = wl_fixed_to_double(sy); - _glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY); - } + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) + { + _glfw.wl.pending.events |= (GLFW_PENDING_SURFACE | GLFW_PENDING_MOTION); + _glfw.wl.pending.pointerSurface = surface; + _glfw.wl.pending.pointerX = xpos; + _glfw.wl.pending.pointerY = ypos; } else { - if (window->wl.fallback.decorations) - updateFallbackDecorationCursor(window, sx, sy); + _glfw.wl.pointerSurface = surface; + + if (window->wl.surface == _glfw.wl.pointerSurface) + { + _glfwSetCursorWayland(window, window->cursor); + _glfwInputCursorEnter(window, GLFW_TRUE); + + if (window->cursorMode != GLFW_CURSOR_DISABLED) + { + window->wl.cursorPosX = xpos; + window->wl.cursorPosY = ypos; + _glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY); + } + } + else + { + if (window->wl.fallback.decorations) + updateFallbackDecorationCursor(window, xpos, ypos); + } } } @@ -1572,15 +1583,25 @@ static void pointerHandleLeave(void* userData, return; _glfw.wl.serial = serial; - _glfw.wl.pointerSurface = NULL; _GLFWwindow* window = wl_surface_get_user_data(surface); - if (window->wl.surface == surface) - _glfwInputCursorEnter(window, GLFW_FALSE); + + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) + { + _glfw.wl.pending.events |= GLFW_PENDING_SURFACE; + _glfw.wl.pending.pointerSurface = NULL; + } else { - if (window->wl.fallback.decorations) - window->wl.fallback.cursorName = NULL; + _glfw.wl.pointerSurface = NULL; + + if (window->wl.surface == surface) + _glfwInputCursorEnter(window, GLFW_FALSE); + else + { + if (window->wl.fallback.decorations) + window->wl.fallback.cursorName = NULL; + } } } @@ -1594,20 +1615,28 @@ static void pointerHandleMotion(void* userData, return; _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); - if (window->cursorMode == GLFW_CURSOR_DISABLED) return; - if (window->wl.surface == _glfw.wl.pointerSurface) + const double xpos = wl_fixed_to_double(sx); + const double ypos = wl_fixed_to_double(sy); + + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) { - window->wl.cursorPosX = wl_fixed_to_double(sx); - window->wl.cursorPosY = wl_fixed_to_double(sy); - _glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY); + _glfw.wl.pending.events |= GLFW_PENDING_MOTION; + _glfw.wl.pending.pointerX = xpos; + _glfw.wl.pending.pointerY = ypos; } else { - if (window->wl.fallback.decorations) - updateFallbackDecorationCursor(window, sx, sy); + if (window->wl.surface == _glfw.wl.pointerSurface) + { + window->wl.cursorPosX = xpos; + window->wl.cursorPosY = ypos; + _glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY); + } + else + updateFallbackDecorationCursor(window, xpos, ypos); } } @@ -1615,27 +1644,39 @@ static void pointerHandleButton(void* userData, struct wl_pointer* pointer, uint32_t serial, uint32_t time, - uint32_t button, + uint32_t buttonID, uint32_t state) { if (!_glfw.wl.pointerSurface) return; + _glfw.wl.serial = serial; + _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + const int button = buttonID - BTN_LEFT; + const int action = (state == WL_POINTER_BUTTON_STATE_PRESSED); - if (window->wl.surface == _glfw.wl.pointerSurface) + if (window->wl.fallback.decorations) { - _glfw.wl.serial = serial; + if (action == GLFW_PRESS) + window->wl.fallback.buttonPressSerial = serial; + } - _glfwInputMouseClick(window, - button - BTN_LEFT, - state == WL_POINTER_BUTTON_STATE_PRESSED, - _glfw.wl.xkb.modifiers); + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) + { + _glfw.wl.pending.events |= GLFW_PENDING_BUTTON; + _glfw.wl.pending.button = button; + _glfw.wl.pending.action = action; } else { - if (window->wl.fallback.decorations) - handleFallbackDecorationButton(window, serial, button, state); + if (window->wl.surface == _glfw.wl.pointerSurface) + _glfwInputMouseClick(window, button, action, _glfw.wl.xkb.modifiers); + else + { + if (window->wl.fallback.decorations) + handleFallbackDecorationButton(window, button, action); + } } } @@ -1649,8 +1690,18 @@ static void pointerHandleAxis(void* userData, return; _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + if (window->wl.surface != _glfw.wl.pointerSurface) + return; - if (window->wl.surface == _glfw.wl.pointerSurface) + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) + { + _glfw.wl.pending.events |= GLFW_PENDING_SCROLL; + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) + _glfw.wl.pending.scrollX = -wl_fixed_to_double(value) / 10.0; + else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + _glfw.wl.pending.scrollY = -wl_fixed_to_double(value) / 10.0; + } + else { // NOTE: 10 units of motion per mouse wheel step seems to be a common ratio if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) @@ -1660,6 +1711,109 @@ static void pointerHandleAxis(void* userData, } } +static void pointerHandleFrame(void* userData, struct wl_pointer* pointer) +{ + if (_glfw.wl.pending.events & GLFW_PENDING_SURFACE) + { + if (_glfw.wl.pointerSurface) + { + _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + if (window->wl.surface == _glfw.wl.pointerSurface) + _glfwInputCursorEnter(window, GLFW_FALSE); + else + { + if (window->wl.fallback.decorations) + window->wl.fallback.cursorName = NULL; + } + } + + _glfw.wl.pointerSurface = _glfw.wl.pending.pointerSurface; + + if (_glfw.wl.pointerSurface) + { + _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + if (window->wl.surface == _glfw.wl.pointerSurface) + { + _glfwSetCursorWayland(window, window->cursor); + _glfwInputCursorEnter(window, GLFW_TRUE); + } + } + } + + if (!_glfw.wl.pointerSurface) + return; + + _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + + if (_glfw.wl.pending.events & GLFW_PENDING_MOTION) + { + if (window->wl.surface == _glfw.wl.pointerSurface) + { + window->wl.cursorPosX = _glfw.wl.pending.pointerX; + window->wl.cursorPosY = _glfw.wl.pending.pointerY; + _glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY); + } + else + { + updateFallbackDecorationCursor(window, + _glfw.wl.pending.pointerX, + _glfw.wl.pending.pointerY); + } + } + + if (_glfw.wl.pending.events & GLFW_PENDING_BUTTON) + { + if (window->wl.surface == _glfw.wl.pointerSurface) + { + _glfwInputMouseClick(window, + _glfw.wl.pending.button, + _glfw.wl.pending.action, + _glfw.wl.xkb.modifiers); + } + else + { + if (window->wl.fallback.decorations) + { + handleFallbackDecorationButton(window, + _glfw.wl.pending.button, + _glfw.wl.pending.action); + } + } + } + + if (_glfw.wl.pending.events & GLFW_PENDING_SCROLL) + { + if (window->wl.surface == _glfw.wl.pointerSurface) + { + _glfwInputScroll(window, + _glfw.wl.pending.scrollX, + _glfw.wl.pending.scrollY); + } + } + + memset(&_glfw.wl.pending, 0, sizeof(_glfw.wl.pending)); +} + +static void pointerHandleAxisSource(void* userData, + struct wl_pointer* pointer, + uint32_t axisSource) +{ +} + +static void pointerHandleAxisStop(void* userData, + struct wl_pointer* pointer, + uint32_t time, + uint32_t axis) +{ +} + +static void pointerHandleAxisDiscrete(void* userData, + struct wl_pointer* pointer, + uint32_t axis, + int32_t discrete) +{ +} + static const struct wl_pointer_listener pointerListener = { pointerHandleEnter, @@ -1667,6 +1821,10 @@ static const struct wl_pointer_listener pointerListener = pointerHandleMotion, pointerHandleButton, pointerHandleAxis, + pointerHandleFrame, + pointerHandleAxisSource, + pointerHandleAxisStop, + pointerHandleAxisDiscrete }; static void keyboardHandleKeymap(void* userData,