Another try at pointer frame support on Wayland

This time I think I got the wheel handling correct. At least works with
my wheel mouse.
This commit is contained in:
Kovid Goyal
2024-04-08 18:45:38 +05:30
parent b48b53fce9
commit ac4eef7eb3
2 changed files with 125 additions and 78 deletions

176
glfw/wl_init.c vendored
View File

@@ -35,7 +35,6 @@
#include "wl_text_input.h" #include "wl_text_input.h"
#include "wayland-text-input-unstable-v3-client-protocol.h" #include "wayland-text-input-unstable-v3-client-protocol.h"
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -152,94 +151,121 @@ static void pointerHandleButton(void* data UNUSED,
#undef x #undef x
#undef y #undef y
static void pointerHandleAxis(void* data UNUSED, #define info (window->wl.pointer_curr_axis_info)
struct wl_pointer* pointer UNUSED,
uint32_t time UNUSED, static void
uint32_t axis, pointer_handle_axis_common(enum _GLFWWaylandAxisEvent type, uint32_t axis, wl_fixed_t value) {
wl_fixed_t value)
{
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
double x = 0.0, y = 0.0;
if (!window || window->wl.decorations.focus != CENTRAL_WINDOW) return; if (!window || window->wl.decorations.focus != CENTRAL_WINDOW) return;
float fval = (float) wl_fixed_to_double(value);
assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL || #define CASE(type, type_const, axis, fval) \
axis == WL_POINTER_AXIS_VERTICAL_SCROLL); case type_const: \
if (info.type.axis##_axis_type == AXIS_EVENT_UNKNOWN) { \
info.type.axis##_axis_type = type_const; info.type.axis = 0.f; } \
info.type.axis += fval; break;
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { if (window) {
if (window->wl.axis_discrete_count.x) { switch ((enum wl_pointer_axis)axis) {
window->wl.axis_discrete_count.x--; case WL_POINTER_AXIS_VERTICAL_SCROLL:
return; switch (type) {
case AXIS_EVENT_UNKNOWN: break;
CASE(discrete, AXIS_EVENT_DISCRETE, y, -fval); // wheel event
CASE(discrete, AXIS_EVENT_VALUE120, y, -fval); // wheel event higher res than plain discrete
CASE(continuous, AXIS_EVENT_CONTINUOUS, y, -fval); // touchpad, etc. high res
}
break;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
switch (type) {
case AXIS_EVENT_UNKNOWN: break;
CASE(discrete, AXIS_EVENT_DISCRETE, x, fval); // wheel event
CASE(discrete, AXIS_EVENT_VALUE120, x, fval); // wheel event higher res than plain discrete
CASE(continuous, AXIS_EVENT_CONTINUOUS, x, fval); // touchpad, etc. high res
}
break;
} }
x = -wl_fixed_to_double(value) * _glfwWaylandWindowScale(window);
} }
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { #undef CASE
if (window->wl.axis_discrete_count.y) {
window->wl.axis_discrete_count.y--;
return;
}
y = -wl_fixed_to_double(value) * _glfwWaylandWindowScale(window);
}
_glfwInputScroll(window, x, y, 1, _glfw.wl.xkb.states.modifiers);
} }
static void pointerHandleFrame(void* data UNUSED, static void
struct wl_pointer* pointer UNUSED) pointer_handle_axis(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t time, uint32_t axis, wl_fixed_t value) {
{
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
if (!window || window->wl.decorations.focus != CENTRAL_WINDOW) return; if (!window) return;
window->wl.axis_discrete_count.x = 0; if (!info.timestamp_ns) info.timestamp_ns = ms_to_monotonic_t(time);
window->wl.axis_discrete_count.y = 0; pointer_handle_axis_common(AXIS_EVENT_CONTINUOUS, axis, value);
} }
static void pointerHandleAxisSource(void* data UNUSED, static void
struct wl_pointer* pointer UNUSED, pointer_handle_frame(void *data UNUSED, struct wl_pointer *pointer UNUSED) {
uint32_t source UNUSED)
{
}
static void pointerHandleAxisStop(void *data UNUSED,
struct wl_pointer *wl_pointer UNUSED,
uint32_t time UNUSED,
uint32_t axis UNUSED)
{
}
static void pointerHandleAxisDiscrete(void *data UNUSED,
struct wl_pointer *wl_pointer UNUSED,
uint32_t axis,
int32_t discrete)
{
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
double x = 0.0, y = 0.0; if (!window) return;
if (!window || window->wl.decorations.focus != CENTRAL_WINDOW) return; float x = 0, y = 0;
int highres = 0;
assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL || if (info.discrete.y_axis_type != AXIS_EVENT_UNKNOWN) {
axis == WL_POINTER_AXIS_VERTICAL_SCROLL); y = info.discrete.y;
if (info.discrete.y_axis_type == AXIS_EVENT_VALUE120) y /= 120.f;
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { } else if (info.continuous.y_axis_type != AXIS_EVENT_UNKNOWN) {
x = -discrete; highres = 1;
window->wl.axis_discrete_count.x++; y = info.continuous.y;
}
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
y = -discrete;
window->wl.axis_discrete_count.y++;
} }
_glfwInputScroll(window, x, y, 0, _glfw.wl.xkb.states.modifiers); if (info.discrete.x_axis_type != AXIS_EVENT_UNKNOWN) {
x = info.discrete.x;
if (info.discrete.x_axis_type == AXIS_EVENT_VALUE120) x /= 120.f;
} else if (info.continuous.x_axis_type != AXIS_EVENT_UNKNOWN) {
highres = 1;
x = info.continuous.x;
}
/* clear pointer_curr_axis_info for next frame */
memset(&info, 0, sizeof(info));
if (x != 0.0f || y != 0.0f) {
float scale = _glfwWaylandWindowScale(window);
y *= scale; x *= scale;
_glfwInputScroll(window, x, y, highres, _glfw.wl.xkb.states.modifiers);
}
} }
static void
pointer_handle_axis_source(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t source UNUSED) { }
static void
pointer_handle_axis_stop(void *data UNUSED, struct wl_pointer *wl_pointer UNUSED, uint32_t time UNUSED, uint32_t axis UNUSED) { }
static void
pointer_handle_axis_discrete(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t axis, int32_t discrete) {
pointer_handle_axis_common(AXIS_EVENT_DISCRETE, axis, wl_fixed_from_int(discrete));
}
static void
pointer_handle_axis_value120(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t axis, int32_t value120) {
pointer_handle_axis_common(AXIS_EVENT_VALUE120, axis, wl_fixed_from_int(value120));
}
static void
pointer_handle_axis_relative_direction(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t axis UNUSED, uint32_t axis_relative_direction UNUSED) { }
#undef info
static const struct wl_pointer_listener pointerListener = { static const struct wl_pointer_listener pointerListener = {
pointerHandleEnter, .enter = pointerHandleEnter,
pointerHandleLeave, .leave = pointerHandleLeave,
pointerHandleMotion, .motion = pointerHandleMotion,
pointerHandleButton, .button = pointerHandleButton,
pointerHandleAxis,
pointerHandleFrame, .axis = pointer_handle_axis,
pointerHandleAxisSource, .frame = pointer_handle_frame,
pointerHandleAxisStop, .axis_source = pointer_handle_axis_source,
pointerHandleAxisDiscrete, .axis_stop = pointer_handle_axis_stop,
.axis_discrete = pointer_handle_axis_discrete,
#ifdef WL_POINTER_AXIS_VALUE120_SINCE_VERSION
.axis_value120 = pointer_handle_axis_value120,
#endif
#ifdef WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION
.axis_relative_direction = pointer_handle_axis_relative_direction,
#endif
}; };
static void keyboardHandleKeymap(void* data UNUSED, static void keyboardHandleKeymap(void* data UNUSED,
@@ -473,7 +499,13 @@ static void registryHandleGlobal(void* data UNUSED,
{ {
if (!_glfw.wl.seat) if (!_glfw.wl.seat)
{ {
_glfw.wl.seatVersion = MIN(5u, version); #ifdef WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION
_glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION, (int)version);
#elif defined(WL_POINTER_AXIS_VALUE120_SINCE_VERSION)
_glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_VALUE120_SINCE_VERSION, (int)version);
#else
_glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_DISCRETE_SINCE_VERSION, version);
#endif
_glfw.wl.seat = _glfw.wl.seat =
wl_registry_bind(registry, name, &wl_seat_interface, wl_registry_bind(registry, name, &wl_seat_interface,
_glfw.wl.seatVersion); _glfw.wl.seatVersion);

27
glfw/wl_platform.h vendored
View File

@@ -146,6 +146,13 @@ enum WaylandWindowPendingState {
PENDING_STATE_DECORATION = 2 PENDING_STATE_DECORATION = 2
}; };
enum _GLFWWaylandAxisEvent {
AXIS_EVENT_UNKNOWN = 0,
AXIS_EVENT_CONTINUOUS = 1,
AXIS_EVENT_DISCRETE = 2,
AXIS_EVENT_VALUE120 = 3
};
// Wayland-specific per-window data // Wayland-specific per-window data
// //
typedef struct _GLFWwindowWayland typedef struct _GLFWwindowWayland
@@ -178,6 +185,20 @@ typedef struct _GLFWwindowWayland
struct zwlr_layer_surface_v1* zwlr_layer_surface_v1; struct zwlr_layer_surface_v1* zwlr_layer_surface_v1;
} layer_shell; } layer_shell;
/* information about axis events on current frame */
struct
{
struct {
enum _GLFWWaylandAxisEvent x_axis_type;
float x;
enum _GLFWWaylandAxisEvent y_axis_type;
float y;
} discrete, continuous;
/* Event timestamp in nanoseconds */
monotonic_t timestamp_ns;
} pointer_curr_axis_info;
_GLFWcursor* currentCursor; _GLFWcursor* currentCursor;
double cursorPosX, cursorPosY, allCursorPosX, allCursorPosY; double cursorPosX, cursorPosY, allCursorPosX, allCursorPosY;
@@ -255,12 +276,6 @@ typedef struct _GLFWwindowWayland
bool maximize_on_first_show; bool maximize_on_first_show;
// counters for ignoring axis events following axis_discrete events in the
// same frame along the same axis
struct {
unsigned int x, y;
} axis_discrete_count;
uint32_t pending_state; uint32_t pending_state;
struct { struct {
int width, height; int width, height;