Merge branch 'jx/hi-res-scrolling' into 'main'

High-resolution scroll wheel support

See merge request GNOME/gtk!3839
This commit is contained in:
Matthias Clasen 2022-08-10 16:51:55 +00:00
commit bbd6fdaa04
8 changed files with 235 additions and 62 deletions

View File

@ -21,7 +21,7 @@ stages:
# Common variables
variables:
COMMON_MESON_FLAGS: "-Dwerror=true -Dglib:werror=false -Dpango:werror=false -Dgtk-doc:werror=false -Dwayland-protocols:werror=false -Dsysprof:werror=false"
COMMON_MESON_FLAGS: "-Dwerror=true -Dglib:werror=false -Dpango:werror=false -Dgtk-doc:werror=false -Dwayland-protocols:werror=false -Dsysprof:werror=false -Dwayland:werror=false"
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled"
MESON_TEST_TIMEOUT_MULTIPLIER: 3

View File

@ -2368,10 +2368,75 @@ gdk_scroll_event_new_discrete (GdkSurface *surface,
GdkScrollDirection direction)
{
GdkScrollEvent *self = gdk_event_alloc (GDK_SCROLL, surface, device, time);
double delta_x = 0, delta_y = 0;
switch (direction)
{
case GDK_SCROLL_UP:
delta_y = -1;
break;
case GDK_SCROLL_DOWN:
delta_y = 1;
break;
case GDK_SCROLL_LEFT:
delta_x = -1;
break;
case GDK_SCROLL_RIGHT:
delta_x = 1;
break;
case GDK_SCROLL_SMOOTH:
default:
g_assert_not_reached ();
break;
}
self->tool = tool != NULL ? g_object_ref (tool) : NULL;
self->state = state;
self->direction = direction;
self->delta_x = delta_x;
self->delta_y = delta_y;
self->unit = GDK_SCROLL_UNIT_WHEEL;
return (GdkEvent *) self;
}
/*< private >
* gtk_scroll_event_new_value120:
* @surface: the `GdkSurface` of the event
* @device: the `GdkDevice` of the event
* @tool: (nullable): the tool that generated to event
* @time: the event serial
* @state: Flags to indicate the state of modifier keys and mouse buttons
* in events.
* @direction: scroll direction.
* @delta_x: delta on the X axis in the 120.0 scale
* @delta_x: delta on the Y axis in the 120.0 scale
*
* Creates a new discrete GdkScrollEvent for high resolution mouse wheels.
*
* Both axes send data in fractions of 120 where each multiple of 120
* amounts to one logical scroll event. Fractions of 120 indicate a wheel
* movement less than one detent.
*
* Returns: the newly created scroll event
*/
GdkEvent *
gdk_scroll_event_new_value120 (GdkSurface *surface,
GdkDevice *device,
GdkDeviceTool *tool,
guint32 time,
GdkModifierType state,
GdkScrollDirection direction,
double delta_x,
double delta_y)
{
GdkScrollEvent *self = gdk_event_alloc (GDK_SCROLL, surface, device, time);
self->tool = tool != NULL ? g_object_ref (tool) : NULL;
self->state = state;
self->direction = direction;
self->delta_x = delta_x / 120.0;
self->delta_y = delta_y / 120.0;
self->unit = GDK_SCROLL_UNIT_WHEEL;
return (GdkEvent *) self;

View File

@ -495,6 +495,15 @@ GdkEvent * gdk_scroll_event_new_discrete (GdkSurface *surface,
GdkModifierType state,
GdkScrollDirection direction);
GdkEvent * gdk_scroll_event_new_value120 (GdkSurface *surface,
GdkDevice *device,
GdkDeviceTool *tool,
guint32 time,
GdkModifierType state,
GdkScrollDirection direction,
double delta_x,
double delta_y);
GdkEvent * gdk_touch_event_new (GdkEventType type,
GdkEventSequence *sequence,
GdkSurface *surface,

View File

@ -112,7 +112,7 @@ struct _GdkWaylandPointerFrameData
/* Specific to the scroll event */
double delta_x, delta_y;
int32_t discrete_x, discrete_y;
int32_t value120_x, value120_y;
gint8 is_scroll_stop;
enum wl_pointer_axis_source source;
};
@ -1383,20 +1383,54 @@ static GdkDevice * get_scroll_device (GdkWaylandSeat *seat,
static void
flush_discrete_scroll_event (GdkWaylandSeat *seat,
GdkScrollDirection direction)
gint value120_x,
gint value120_y)
{
GdkEvent *event;
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
GdkEvent *event = NULL;
GdkDevice *source;
GdkScrollDirection direction;
if (value120_x > 0)
direction = GDK_SCROLL_LEFT;
else if (value120_x < 0)
direction = GDK_SCROLL_RIGHT;
else if (value120_y > 0)
direction = GDK_SCROLL_DOWN;
else
direction = GDK_SCROLL_UP;
source = get_scroll_device (seat, seat->pointer_info.frame.source);
event = gdk_scroll_event_new_discrete (seat->pointer_info.focus,
source,
NULL,
seat->pointer_info.time,
device_get_modifiers (seat->logical_pointer),
direction);
_gdk_wayland_display_deliver_event (seat->display, event);
if (display_wayland->seat_version >= WL_POINTER_AXIS_VALUE120_SINCE_VERSION)
{
event = gdk_scroll_event_new_value120 (seat->pointer_info.focus,
source,
NULL,
seat->pointer_info.time,
device_get_modifiers (seat->logical_pointer),
direction,
value120_x,
value120_y);
}
else
{
gint discrete_x = value120_x / 120;
gint discrete_y = value120_y / 120;
if (discrete_x != 0 || discrete_y != 0)
{
event = gdk_scroll_event_new_discrete (seat->pointer_info.focus,
source,
NULL,
seat->pointer_info.time,
device_get_modifiers (seat->logical_pointer),
direction);
}
}
if (event)
_gdk_wayland_display_deliver_event (seat->display, event);
}
static void
@ -1427,22 +1461,13 @@ flush_scroll_event (GdkWaylandSeat *seat,
{
gboolean is_stop = FALSE;
if (pointer_frame->discrete_x || pointer_frame->discrete_y)
if (pointer_frame->value120_x || pointer_frame->value120_y)
{
GdkScrollDirection direction;
if (pointer_frame->discrete_x > 0)
direction = GDK_SCROLL_LEFT;
else if (pointer_frame->discrete_x < 0)
direction = GDK_SCROLL_RIGHT;
else if (pointer_frame->discrete_y > 0)
direction = GDK_SCROLL_DOWN;
else
direction = GDK_SCROLL_UP;
flush_discrete_scroll_event (seat, direction);
pointer_frame->discrete_x = 0;
pointer_frame->discrete_y = 0;
flush_discrete_scroll_event (seat,
pointer_frame->value120_x,
pointer_frame->value120_y);
pointer_frame->value120_x = 0;
pointer_frame->value120_y = 0;
}
else if (pointer_frame->is_scroll_stop ||
pointer_frame->delta_x != 0 ||
@ -1462,8 +1487,8 @@ flush_scroll_event (GdkWaylandSeat *seat,
is_stop);
}
pointer_frame->discrete_x = 0;
pointer_frame->discrete_y = 0;
pointer_frame->value120_x = 0;
pointer_frame->value120_y = 0;
pointer_frame->delta_x = 0;
pointer_frame->delta_y = 0;
pointer_frame->is_scroll_stop = FALSE;
@ -1862,10 +1887,10 @@ pointer_handle_axis_discrete (void *data,
switch (axis)
{
case WL_POINTER_AXIS_VERTICAL_SCROLL:
pointer_frame->discrete_y = value;
pointer_frame->value120_y = value * 120;
break;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
pointer_frame->discrete_x = value;
pointer_frame->value120_x = value * 120;
break;
default:
g_return_if_reached ();
@ -1876,6 +1901,35 @@ pointer_handle_axis_discrete (void *data,
get_axis_name (axis), value, seat));
}
static void
pointer_handle_axis_value120 (void *data,
struct wl_pointer *pointer,
uint32_t axis,
int32_t value)
{
GdkWaylandSeat *seat = data;
GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame;
if (!seat->pointer_info.focus)
return;
switch (axis)
{
case WL_POINTER_AXIS_VERTICAL_SCROLL:
pointer_frame->value120_y = value;
break;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
pointer_frame->value120_x = value;
break;
default:
g_return_if_reached ();
}
GDK_SEAT_NOTE (seat, EVENTS,
g_message ("value120 scroll, axis %s, value %d, seat %p",
get_axis_name (axis), value, seat));
}
static int
get_active_layout (GdkKeymap *keymap)
{
@ -3070,6 +3124,7 @@ static const struct wl_pointer_listener pointer_listener = {
pointer_handle_axis_source,
pointer_handle_axis_stop,
pointer_handle_axis_discrete,
pointer_handle_axis_value120,
};
static const struct wl_keyboard_listener keyboard_listener = {

View File

@ -232,7 +232,7 @@ _gdk_wayland_display_add_seat (GdkWaylandDisplay *display_wayland,
{
struct wl_seat *seat;
display_wayland->seat_version = MIN (version, 7);
display_wayland->seat_version = MIN (version, 8);
seat = wl_registry_bind (display_wayland->wl_registry,
id, &wl_seat_interface,
display_wayland->seat_version);

View File

@ -1729,6 +1729,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
&xev->valuators, &delta_x, &delta_y))
{
GdkModifierType state;
GdkScrollDirection direction;
GDK_DISPLAY_NOTE (display, EVENTS,
g_message ("smooth scroll: \n\tdevice: %u\n\tsource device: %u\n\twindow %ld\n\tdeltas: %f %f",
@ -1737,21 +1738,19 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
if (delta_x > 0)
direction = GDK_SCROLL_RIGHT;
else if (delta_x < 0)
direction = GDK_SCROLL_LEFT;
else if (delta_y > 0)
direction = GDK_SCROLL_DOWN;
else
direction = GDK_SCROLL_UP;
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHPAD &&
((delta_x == 0.0 && ABS (delta_y) == 1.0) ||
(ABS (delta_x) == 1.0 && delta_y == 0.0)))
{
GdkScrollDirection direction;
if (delta_x > 0)
direction = GDK_SCROLL_RIGHT;
else if (delta_x < 0)
direction = GDK_SCROLL_LEFT;
else if (delta_y > 0)
direction = GDK_SCROLL_DOWN;
else
direction = GDK_SCROLL_UP;
event = gdk_scroll_event_new_discrete (surface,
device,
NULL,
@ -1759,6 +1758,17 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
state,
direction);
}
else if (gdk_device_get_source (source_device) == GDK_SOURCE_MOUSE)
{
event = gdk_scroll_event_new_value120 (surface,
device,
NULL,
xev->time,
state,
direction,
delta_x * 120.0,
delta_y * 120.0);
}
else
{
event = gdk_scroll_event_new (surface,

View File

@ -85,6 +85,8 @@ struct _GtkEventControllerScroll
/* For discrete event coalescing */
double cur_dx;
double cur_dy;
double last_cur_dx;
double last_cur_dy;
GdkScrollUnit cur_unit;
@ -337,6 +339,17 @@ gtk_event_controller_scroll_handle_hold_event (GtkEventController *controller,
return GDK_EVENT_PROPAGATE;
}
static gboolean
should_reset_discrete_acc (double current_delta,
double last_delta)
{
if (last_delta == 0)
return TRUE;
return (current_delta < 0 && last_delta > 0) ||
(current_delta > 0 && last_delta < 0);
}
static gboolean
gtk_event_controller_scroll_handle_event (GtkEventController *controller,
GdkEvent *event,
@ -416,30 +429,51 @@ gtk_event_controller_scroll_handle_event (GtkEventController *controller,
}
else
{
switch (direction)
{
case GDK_SCROLL_UP:
dy -= 1;
break;
case GDK_SCROLL_DOWN:
dy += 1;
break;
case GDK_SCROLL_LEFT:
dx -= 1;
break;
case GDK_SCROLL_RIGHT:
dx += 1;
break;
case GDK_SCROLL_SMOOTH:
default:
g_assert_not_reached ();
break;
}
gdk_scroll_event_get_deltas (event, &dx, &dy);
if ((scroll->flags & GTK_EVENT_CONTROLLER_SCROLL_VERTICAL) == 0)
dy = 0;
if ((scroll->flags & GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL) == 0)
dx = 0;
if (scroll->flags & GTK_EVENT_CONTROLLER_SCROLL_DISCRETE)
{
int steps;
if (dx != 0)
{
if (should_reset_discrete_acc (dx, scroll->last_cur_dx))
scroll->cur_dx = 0;
scroll->last_cur_dx = dx;
}
if (dy != 0)
{
if (should_reset_discrete_acc (dy, scroll->last_cur_dy))
scroll->cur_dy = 0;
scroll->last_cur_dy = dy;
}
scroll->cur_dx += dx;
scroll->cur_dy += dy;
dx = dy = 0;
if (ABS (scroll->cur_dx) >= 1)
{
steps = trunc (scroll->cur_dx);
scroll->cur_dx -= steps;
dx = steps;
}
if (ABS (scroll->cur_dy) >= 1)
{
steps = trunc (scroll->cur_dy);
scroll->cur_dy -= steps;
dy = steps;
}
}
}
scroll->cur_unit = scroll_unit;

View File

@ -18,7 +18,7 @@ cairo_req = '>= 1.14.0'
gdk_pixbuf_req = '>= 2.30.0'
introspection_req = '>= 1.39.0'
wayland_proto_req = '>= 1.25'
wayland_req = '>= 1.20.0'
wayland_req = '>= 1.21.0'
graphene_req = '>= 1.9.1'
epoxy_req = '>= 1.4'
cloudproviders_req = '>= 0.3.1'