aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_seat.h13
-rw-r--r--types/seat/wlr_seat_pointer.c48
2 files changed, 59 insertions, 2 deletions
diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h
index 8c1d4661..d1984449 100644
--- a/include/wlr/types/wlr_seat.h
+++ b/include/wlr/types/wlr_seat.h
@@ -54,6 +54,19 @@ struct wlr_seat_client {
// for use by wlr_seat_client_{next_serial,validate_event_serial}
struct wlr_serial_ringset serials;
bool needs_touch_frame;
+
+ // When the client doesn't support high-resolution scroll, accumulate deltas
+ // until we can notify a discrete event.
+ // Some mice have a free spinning wheel, making possible to lock the wheel
+ // when the accumulator value is not 0. To avoid synchronization issues
+ // between the mouse wheel and the accumulators, store the last delta and
+ // when the scroll direction changes, reset the accumulator.
+ // Indexed by wlr_axis_orientation.
+ struct {
+ int32_t acc_discrete[2];
+ int32_t last_discrete[2];
+ double acc_axis[2];
+ } value120;
};
struct wlr_touch_point {
diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c
index 1ddc1467..7d37fb12 100644
--- a/types/seat/wlr_seat_pointer.c
+++ b/types/seat/wlr_seat_pointer.c
@@ -269,6 +269,48 @@ uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time,
return serial;
}
+static bool should_reset_value120_accumulators(int32_t current, int32_t last) {
+ if (last == 0) {
+ return true;
+ }
+
+ return (current < 0 && last > 0) || (current > 0 && last < 0);
+}
+
+static void update_value120_accumulators(struct wlr_seat_client *client,
+ enum wlr_axis_orientation orientation,
+ double value, int32_t value_discrete) {
+ int32_t *acc_discrete = &client->value120.acc_discrete[orientation];
+ int32_t *last_discrete = &client->value120.last_discrete[orientation];
+ double *acc_axis = &client->value120.acc_axis[orientation];
+ if (should_reset_value120_accumulators(value_discrete, *last_discrete)) {
+ *acc_discrete = 0;
+ *acc_axis = 0;
+ }
+ *acc_discrete += value_discrete;
+ *last_discrete = value_discrete;
+ *acc_axis += value;
+}
+
+static void send_axis_discrete(struct wlr_seat_client *client,
+ struct wl_resource *resource, uint32_t time,
+ enum wlr_axis_orientation orientation, double value,
+ int32_t value_discrete) {
+ int32_t *acc_discrete = &client->value120.acc_discrete[orientation];
+ double *acc_axis = &client->value120.acc_axis[orientation];
+
+ if (abs(*acc_discrete) < WLR_POINTER_AXIS_DISCRETE_STEP) {
+ return;
+ }
+
+ wl_pointer_send_axis_discrete(resource, orientation,
+ *acc_discrete / WLR_POINTER_AXIS_DISCRETE_STEP);
+ wl_pointer_send_axis(resource, time, orientation,
+ wl_fixed_from_double(*acc_axis));
+ *acc_discrete %= WLR_POINTER_AXIS_DISCRETE_STEP;
+ *acc_axis = 0;
+}
+
static void send_axis_value120(struct wl_resource *resource, uint32_t time,
enum wlr_axis_orientation orientation, double value,
int32_t value_discrete) {
@@ -294,6 +336,8 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time,
send_source = true;
}
+ update_value120_accumulators(client, orientation, value, value_discrete);
+
struct wl_resource *resource;
wl_resource_for_each(resource, &client->pointers) {
if (wlr_seat_client_from_pointer_resource(resource) == NULL) {
@@ -311,8 +355,8 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time,
send_axis_value120(resource, time, orientation, value,
value_discrete);
} else if (version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) {
- wl_pointer_send_axis_discrete(resource, orientation,
- value_discrete / WLR_POINTER_AXIS_DISCRETE_STEP);
+ send_axis_discrete(client, resource, time, orientation,
+ value, value_discrete);
}
} else {
wl_pointer_send_axis(resource, time, orientation,