Wayland: Add support for pointer frame events. Code taken with thanks from SDL

This commit is contained in:
Kovid Goyal 2024-03-28 15:32:59 +05:30
parent d38c986c82
commit 506be129e1
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 208 additions and 89 deletions

1
glfw/glfw3.h vendored
View file

@ -316,6 +316,7 @@ extern "C" {
#define GLFW_HAT_RIGHT_DOWN (GLFW_HAT_RIGHT | GLFW_HAT_DOWN)
#define GLFW_HAT_LEFT_UP (GLFW_HAT_LEFT | GLFW_HAT_UP)
#define GLFW_HAT_LEFT_DOWN (GLFW_HAT_LEFT | GLFW_HAT_DOWN)
#define GLFW_WAYLAND_WHEEL_AXIS_UNIT 10
/*! @} */
/*! @defgroup keys Keyboard keys

271
glfw/wl_init.c vendored
View file

@ -80,7 +80,7 @@ findWindowFromDecorationSurface(struct wl_surface* surface, _GLFWdecorationSideW
return window;
}
static void pointerHandleEnter(void* data UNUSED,
static void pointer_handle_enter(void* data UNUSED,
struct wl_pointer* pointer UNUSED,
uint32_t serial,
struct wl_surface* surface,
@ -109,7 +109,7 @@ static void pointerHandleEnter(void* data UNUSED,
_glfwInputCursorEnter(window, true);
}
static void pointerHandleLeave(void* data UNUSED,
static void pointer_handle_leave(void* data UNUSED,
struct wl_pointer* pointer UNUSED,
uint32_t serial,
struct wl_surface* surface UNUSED)
@ -171,7 +171,7 @@ static void setCursor(GLFWCursorShape shape, _GLFWwindow* window)
#define x window->wl.allCursorPosX
#define y window->wl.allCursorPosY
static void pointerHandleMotion(void* data UNUSED,
static void pointer_handle_motion(void* data UNUSED,
struct wl_pointer* pointer UNUSED,
uint32_t time UNUSED,
wl_fixed_t sx,
@ -229,7 +229,7 @@ static void pointerHandleMotion(void* data UNUSED,
setCursor(cursorShape, window);
}
static void pointerHandleButton(void* data UNUSED,
static void pointer_handle_button(void* data UNUSED,
struct wl_pointer* pointer UNUSED,
uint32_t serial,
uint32_t time UNUSED,
@ -328,97 +328,200 @@ static void pointerHandleButton(void* data UNUSED,
#undef x
#undef y
static void pointerHandleAxis(void* data UNUSED,
struct wl_pointer* pointer UNUSED,
uint32_t time UNUSED,
uint32_t axis,
wl_fixed_t value)
{
static void
pointer_handle_axis_common(enum _GLFWWaylandAxisEvent type, uint32_t axis, wl_fixed_t value) {
enum wl_pointer_axis a = axis;
_GLFWwindow* window = _glfw.wl.pointerFocus;
double x = 0.0, y = 0.0;
if (!window)
return;
#define input (&window->wl)
assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
if (window->wl.axis_discrete_count.x) {
window->wl.axis_discrete_count.x--;
return;
}
x = -wl_fixed_to_double(value) * _glfwWaylandWindowScale(window);
}
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
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,
struct wl_pointer* pointer UNUSED)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
if (window) {
window->wl.axis_discrete_count.x = 0;
window->wl.axis_discrete_count.y = 0;
switch (a) {
case WL_POINTER_AXIS_VERTICAL_SCROLL:
switch (type) {
case AXIS_EVENT_VALUE120:
/*
* High resolution scroll event. The spec doesn't state that axis_value120
* events are limited to one per frame, so the values are accumulated.
*/
if (input->pointer_curr_axis_info.y_axis_type != AXIS_EVENT_VALUE120) {
input->pointer_curr_axis_info.y_axis_type = AXIS_EVENT_VALUE120;
input->pointer_curr_axis_info.y = 0.0f;
}
input->pointer_curr_axis_info.y += 0 - (float)wl_fixed_to_double(value);
break;
case AXIS_EVENT_DISCRETE:
/*
* This is a discrete axis event, so we process it and set the
* flag to ignore future continuous axis events in this frame.
*/
if (input->pointer_curr_axis_info.y_axis_type != AXIS_EVENT_DISCRETE) {
input->pointer_curr_axis_info.y_axis_type = AXIS_EVENT_DISCRETE;
input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
}
break;
case AXIS_EVENT_CONTINUOUS:
/* Only process continuous events if no discrete events have been received. */
if (input->pointer_curr_axis_info.y_axis_type == AXIS_EVENT_CONTINUOUS) {
input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
}
break;
}
break;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
switch (type) {
case AXIS_EVENT_VALUE120:
/*
* High resolution scroll event. The spec doesn't state that axis_value120
* events are limited to one per frame, so the values are accumulated.
*/
if (input->pointer_curr_axis_info.x_axis_type != AXIS_EVENT_VALUE120) {
input->pointer_curr_axis_info.x_axis_type = AXIS_EVENT_VALUE120;
input->pointer_curr_axis_info.x = 0.0f;
}
input->pointer_curr_axis_info.x += (float)wl_fixed_to_double(value);
break;
case AXIS_EVENT_DISCRETE:
/*
* This is a discrete axis event, so we process it and set the
* flag to ignore future continuous axis events in this frame.
*/
if (input->pointer_curr_axis_info.x_axis_type != AXIS_EVENT_DISCRETE) {
input->pointer_curr_axis_info.x_axis_type = AXIS_EVENT_DISCRETE;
input->pointer_curr_axis_info.x = (float)wl_fixed_to_double(value);
}
break;
case AXIS_EVENT_CONTINUOUS:
/* Only process continuous events if no discrete events have been received. */
if (input->pointer_curr_axis_info.x_axis_type == AXIS_EVENT_CONTINUOUS) {
input->pointer_curr_axis_info.x = (float)wl_fixed_to_double(value);
}
break;
}
break;
}
}
}
static void pointerHandleAxisSource(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)
{
static void
pointer_handle_axis_common_v1(uint32_t time UNUSED, uint32_t axis, wl_fixed_t value) {
_GLFWwindow* window = _glfw.wl.pointerFocus;
double x = 0.0, y = 0.0;
if (!window)
return;
enum wl_pointer_axis a = axis;
float x, y;
assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
if (window) {
switch (a) {
case WL_POINTER_AXIS_VERTICAL_SCROLL:
x = 0;
y = 0 - (float)wl_fixed_to_double(value);
break;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
x = (float)wl_fixed_to_double(value);
y = 0;
break;
default:
return;
}
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
x = -discrete;
window->wl.axis_discrete_count.x++;
x /= GLFW_WAYLAND_WHEEL_AXIS_UNIT;
y /= GLFW_WAYLAND_WHEEL_AXIS_UNIT;
_glfwInputScroll(window, x, y, 0, _glfw.wl.xkb.states.modifiers);
}
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);
}
static const struct wl_pointer_listener pointerListener = {
pointerHandleEnter,
pointerHandleLeave,
pointerHandleMotion,
pointerHandleButton,
pointerHandleAxis,
pointerHandleFrame,
pointerHandleAxisSource,
pointerHandleAxisStop,
pointerHandleAxisDiscrete,
static void
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;
if (!window) return;
if (_glfw.wl.seatVersion >= WL_POINTER_FRAME_SINCE_VERSION) {
if (!input->pointer_curr_axis_info.timestamp_ns) input->pointer_curr_axis_info.timestamp_ns = ms_to_monotonic_t(time);
pointer_handle_axis_common(AXIS_EVENT_CONTINUOUS, axis, value);
} else {
pointer_handle_axis_common_v1(time, axis, value);
}
}
static void
pointer_handle_frame(void *data UNUSED, struct wl_pointer *pointer UNUSED) {
_GLFWwindow* window = _glfw.wl.pointerFocus;
if (!window) return;
float x, y;
switch (input->pointer_curr_axis_info.x_axis_type) {
case AXIS_EVENT_CONTINUOUS:
x = input->pointer_curr_axis_info.x;
break;
case AXIS_EVENT_DISCRETE:
x = input->pointer_curr_axis_info.x;
break;
case AXIS_EVENT_VALUE120:
x = input->pointer_curr_axis_info.x / 120.0f;
break;
default:
x = 0.0f;
break;
}
switch (input->pointer_curr_axis_info.y_axis_type) {
case AXIS_EVENT_CONTINUOUS:
y = input->pointer_curr_axis_info.y;
break;
case AXIS_EVENT_DISCRETE:
y = input->pointer_curr_axis_info.y;
break;
case AXIS_EVENT_VALUE120:
y = input->pointer_curr_axis_info.y / 120.0f;
break;
default:
y = 0.0f;
break;
}
/* clear pointer_curr_axis_info for next frame */
memset(&input->pointer_curr_axis_info, 0, sizeof(input->pointer_curr_axis_info));
if (x != 0.0f || y != 0.0f) {
float scale = _glfwWaylandWindowScale(window);
y *= scale; x *= scale;
_glfwInputScroll(window, x, y, 1, _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 input
static const struct wl_pointer_listener pointer_listener = {
pointer_handle_enter,
pointer_handle_leave,
pointer_handle_motion,
pointer_handle_button,
pointer_handle_axis,
pointer_handle_frame, /* Version 5 */
pointer_handle_axis_source, /* Version 5 */
pointer_handle_axis_stop, /* Version 5 */
pointer_handle_axis_discrete, /* Version 5 */
pointer_handle_axis_value120, /* Version 8 */
pointer_handle_axis_relative_direction /* Version 9 */
};
static void keyboardHandleKeymap(void* data UNUSED,
@ -572,7 +675,7 @@ static void seatHandleCapabilities(void* data UNUSED,
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)
{
_glfw.wl.pointer = wl_seat_get_pointer(seat);
wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);
wl_pointer_add_listener(_glfw.wl.pointer, &pointer_listener, NULL);
if (_glfw.wl.wp_cursor_shape_manager_v1) {
if (_glfw.wl.wp_cursor_shape_device_v1) wp_cursor_shape_device_v1_destroy(_glfw.wl.wp_cursor_shape_device_v1);
_glfw.wl.wp_cursor_shape_device_v1 = NULL;

24
glfw/wl_platform.h vendored
View file

@ -147,6 +147,12 @@ enum WaylandWindowPendingState {
PENDING_STATE_DECORATION = 2
};
enum _GLFWWaylandAxisEvent {
AXIS_EVENT_CONTINUOUS = 0,
AXIS_EVENT_DISCRETE,
AXIS_EVENT_VALUE120
};
// Wayland-specific per-window data
//
typedef struct _GLFWwindowWayland
@ -178,6 +184,19 @@ typedef struct _GLFWwindowWayland
struct zwlr_layer_surface_v1* zwlr_layer_surface_v1;
} layer_shell;
/* information about axis events on current frame */
struct
{
enum _GLFWWaylandAxisEvent x_axis_type;
float x;
enum _GLFWWaylandAxisEvent y_axis_type;
float y;
/* Event timestamp in nanoseconds */
monotonic_t timestamp_ns;
} pointer_curr_axis_info;
_GLFWcursor* currentCursor;
double cursorPosX, cursorPosY, allCursorPosX, allCursorPosY;
@ -242,11 +261,6 @@ typedef struct _GLFWwindowWayland
} user_requested_content_size;
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;
struct {

1
kitty/glfw-wrapper.h generated
View file

@ -54,6 +54,7 @@
#define GLFW_HAT_RIGHT_DOWN (GLFW_HAT_RIGHT | GLFW_HAT_DOWN)
#define GLFW_HAT_LEFT_UP (GLFW_HAT_LEFT | GLFW_HAT_UP)
#define GLFW_HAT_LEFT_DOWN (GLFW_HAT_LEFT | GLFW_HAT_DOWN)
#define GLFW_WAYLAND_WHEEL_AXIS_UNIT 10
/*! @} */
/*! @defgroup keys Keyboard keys