[PATCH weston] Support axis source, axis discreet, axis frame and axis stop events

Jonas Ã…dahl jadahl at gmail.com
Mon Oct 19 18:19:59 PDT 2015


On Mon, Oct 19, 2015 at 06:17:31PM -0700, Bryce Harrington wrote:
> On Fri, Oct 16, 2015 at 12:39:22PM +1000, Peter Hutterer wrote:
> > Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> > ---
> > The client-side is the simplest implementation here, and I went the easy
> > route since most clients won't care to register a multitude of handlers for
> > axis events.
> > 
> > The eventdemo client merely prints the events, it doesn't accumulate them as
> > they should be. That'd be the job of a slightly more sophisticated toolkit.
> > 
> > Possibly contentious: there's no notify_axis_stop(), it's folded into
> > notify_axis(). Easy fix if needed.
> > 
> > Also, I recommend not merging this one until we have a test implementation
> > in mutter + GTK to make sure the protocol is sane enough to use from complex
> > clients.
> 
> Thanks for resending these patches.  Since the main goal here is
> assuring the protocol is right, should we also hold off on landing the
> wayland piece until there's consensus around this one too, or is the
> protocol part ok to land?

I'm planning to do a second review of the protocol patches, and there
will at least be minor changes needed, so please don't merge anything
yet. Will try to get that done as soon as possible.


Jonas

> 
> Bryce
> 
> >  clients/eventdemo.c      | 55 ++++++++++++++++++++++++++++-
> >  clients/window.c         | 91 +++++++++++++++++++++++++++++++++++++++++++++++-
> >  clients/window.h         | 28 +++++++++++++++
> >  src/compositor-wayland.c | 39 +++++++++++++++++++++
> >  src/compositor-x11.c     | 16 ++++++---
> >  src/compositor.h         | 10 ++++++
> >  src/input.c              | 74 ++++++++++++++++++++++++++++++++++-----
> >  src/libinput-device.c    | 63 +++++++++++++++++++++++++++++++--
> >  8 files changed, 360 insertions(+), 16 deletions(-)
> > 
> > diff --git a/clients/eventdemo.c b/clients/eventdemo.c
> > index bdad6fd..f520233 100644
> > --- a/clients/eventdemo.c
> > +++ b/clients/eventdemo.c
> > @@ -259,6 +259,54 @@ axis_handler(struct widget *widget, struct input *input, uint32_t time,
> >  	       wl_fixed_to_double(value));
> >  }
> >  
> > +static void
> > +axis_frame_handler(struct widget *widget, struct input *input, void *data)
> > +{
> > +	printf("axis frame\n");
> > +}
> > +
> > +static void
> > +axis_source_handler(struct widget *widget, struct input *input,
> > +		    uint32_t source, void *data)
> > +{
> > +	const char *axis_source;
> > +
> > +	switch (source) {
> > +	case WL_POINTER_AXIS_SOURCE_WHEEL:
> > +		axis_source = "wheel";
> > +		break;
> > +	case WL_POINTER_AXIS_SOURCE_FINGER:
> > +		axis_source = "finger";
> > +		break;
> > +	case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
> > +		axis_source = "continuous";
> > +		break;
> > +	default:
> > +		axis_source = "<invalid source value>";
> > +		break;
> > +	}
> > +
> > +	printf("axis source: %s\n", axis_source);
> > +}
> > +
> > +static void
> > +axis_stop_handler(struct widget *widget, struct input *input,
> > +		  uint32_t time, uint32_t axis,
> > +		  void *data)
> > +{
> > +	printf("axis stop time: %d, axis: %s\n",
> > +	       time,
> > +	       axis == WL_POINTER_AXIS_VERTICAL_SCROLL ? "vertical" :
> > +							 "horizontal");
> > +}
> > +
> > +static void
> > +axis_discrete_handler(struct widget *widget, struct input *input,
> > +		      int32_t discrete, void *data)
> > +{
> > +	printf("axis discrete value: %d\n", discrete);
> > +}
> > +
> >  /**
> >   * \brief CALLBACK function, Waylands informs about pointer motion
> >   * \param widget widget
> > @@ -348,7 +396,12 @@ eventdemo_create(struct display *d)
> >  	widget_set_motion_handler(e->widget, motion_handler);
> >  
> >  	/* Set the callback axis handler for the window */
> > -	widget_set_axis_handler(e->widget, axis_handler);
> > +	widget_set_axis_handlers(e->widget,
> > +				 axis_handler,
> > +				 axis_frame_handler,
> > +				 axis_source_handler,
> > +				 axis_stop_handler,
> > +				 axis_discrete_handler);
> >  
> >  	/* Initial drawing of the window */
> >  	window_schedule_resize(e->window, width, height);
> > diff --git a/clients/window.c b/clients/window.c
> > index 6d3e944..121037b 100644
> > --- a/clients/window.c
> > +++ b/clients/window.c
> > @@ -288,6 +288,10 @@ struct widget {
> >  	widget_touch_frame_handler_t touch_frame_handler;
> >  	widget_touch_cancel_handler_t touch_cancel_handler;
> >  	widget_axis_handler_t axis_handler;
> > +	widget_axis_frame_handler_t axis_frame_handler;
> > +	widget_axis_source_handler_t axis_source_handler;
> > +	widget_axis_stop_handler_t axis_stop_handler;
> > +	widget_axis_discrete_handler_t axis_discrete_handler;
> >  	void *user_data;
> >  	int opaque;
> >  	int tooltip_count;
> > @@ -1935,6 +1939,21 @@ widget_set_axis_handler(struct widget *widget,
> >  	widget->axis_handler = handler;
> >  }
> >  
> > +void
> > +widget_set_axis_handlers(struct widget *widget,
> > +			widget_axis_handler_t axis_handler,
> > +			widget_axis_frame_handler_t axis_frame_handler,
> > +			widget_axis_source_handler_t axis_source_handler,
> > +			widget_axis_stop_handler_t axis_stop_handler,
> > +			widget_axis_discrete_handler_t axis_discrete_handler)
> > +{
> > +	widget->axis_handler = axis_handler;
> > +	widget->axis_frame_handler = axis_frame_handler;
> > +	widget->axis_source_handler = axis_source_handler;
> > +	widget->axis_stop_handler = axis_stop_handler;
> > +	widget->axis_discrete_handler = axis_discrete_handler;
> > +}
> > +
> >  static void
> >  window_schedule_redraw_task(struct window *window);
> >  
> > @@ -2816,12 +2835,82 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
> >  					widget->user_data);
> >  }
> >  
> > +static void
> > +pointer_handle_axis_frame(void *data, struct wl_pointer *pointer)
> > +{
> > +	struct input *input = data;
> > +	struct widget *widget;
> > +
> > +	widget = input->focus_widget;
> > +	if (input->grab)
> > +		widget = input->grab;
> > +	if (widget && widget->axis_frame_handler)
> > +		(*widget->axis_frame_handler)(widget,
> > +					      input,
> > +					      widget->user_data);
> > +}
> > +
> > +static void
> > +pointer_handle_axis_source(void *data, struct wl_pointer *pointer,
> > +			   uint32_t source)
> > +{
> > +	struct input *input = data;
> > +	struct widget *widget;
> > +
> > +	widget = input->focus_widget;
> > +	if (input->grab)
> > +		widget = input->grab;
> > +	if (widget && widget->axis_source_handler)
> > +		(*widget->axis_source_handler)(widget,
> > +					       input,
> > +					       source,
> > +					       widget->user_data);
> > +}
> > +
> > +static void
> > +pointer_handle_axis_stop(void *data, struct wl_pointer *pointer,
> > +			 uint32_t time, uint32_t axis)
> > +{
> > +	struct input *input = data;
> > +	struct widget *widget;
> > +
> > +	widget = input->focus_widget;
> > +	if (input->grab)
> > +		widget = input->grab;
> > +	if (widget && widget->axis_stop_handler)
> > +		(*widget->axis_stop_handler)(widget,
> > +					     input, time,
> > +					     axis,
> > +					     widget->user_data);
> > +}
> > +
> > +static void
> > +pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer,
> > +			     int32_t discrete)
> > +{
> > +	struct input *input = data;
> > +	struct widget *widget;
> > +
> > +	widget = input->focus_widget;
> > +	if (input->grab)
> > +		widget = input->grab;
> > +	if (widget && widget->axis_discrete_handler)
> > +		(*widget->axis_discrete_handler)(widget,
> > +						 input,
> > +						 discrete,
> > +						 widget->user_data);
> > +}
> > +
> >  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_axis_frame,
> > +	pointer_handle_axis_source,
> > +	pointer_handle_axis_stop,
> > +	pointer_handle_axis_discrete,
> >  };
> >  
> >  static void
> > @@ -5225,7 +5314,7 @@ display_add_input(struct display *d, uint32_t id)
> >  	input = xzalloc(sizeof *input);
> >  	input->display = d;
> >  	input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface,
> > -				       MIN(d->seat_version, 4));
> > +				       MIN(d->seat_version, 5));
> >  	input->touch_focus = NULL;
> >  	input->pointer_focus = NULL;
> >  	input->keyboard_focus = NULL;
> > diff --git a/clients/window.h b/clients/window.h
> > index b61a62a..c52ed6b 100644
> > --- a/clients/window.h
> > +++ b/clients/window.h
> > @@ -267,6 +267,26 @@ typedef void (*widget_axis_handler_t)(struct widget *widget,
> >  				      wl_fixed_t value,
> >  				      void *data);
> >  
> > +typedef void (*widget_axis_frame_handler_t)(struct widget *widget,
> > +					    struct input *input,
> > +					    void *data);
> > +
> > +typedef void (*widget_axis_source_handler_t)(struct widget *widget,
> > +					     struct input *input,
> > +					     uint32_t source,
> > +					     void *data);
> > +
> > +typedef void (*widget_axis_stop_handler_t)(struct widget *widget,
> > +					   struct input *input,
> > +					   uint32_t time,
> > +					   uint32_t axis,
> > +					   void *data);
> > +
> > +typedef void (*widget_axis_discrete_handler_t)(struct widget *widget,
> > +					       struct input *input,
> > +					       int32_t discrete,
> > +					       void *data);
> > +
> >  struct window *
> >  window_create(struct display *display);
> >  struct window *
> > @@ -520,6 +540,14 @@ void
> >  widget_set_axis_handler(struct widget *widget,
> >  			widget_axis_handler_t handler);
> >  void
> > +widget_set_axis_handlers(struct widget *widget,
> > +			widget_axis_handler_t axis_handler,
> > +			widget_axis_frame_handler_t axis_frame_handler,
> > +			widget_axis_source_handler_t axis_source_handler,
> > +			widget_axis_stop_handler_t axis_stop_handler,
> > +			widget_axis_discrete_handler_t axis_discrete_handler);
> > +
> > +void
> >  widget_schedule_redraw(struct widget *widget);
> >  void
> >  widget_set_use_cairo(struct widget *widget, int use_cairo);
> > diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
> > index 7b11ae4..d3bbcf8 100644
> > --- a/src/compositor-wayland.c
> > +++ b/src/compositor-wayland.c
> > @@ -1429,12 +1429,51 @@ input_handle_axis(void *data, struct wl_pointer *pointer,
> >  	notify_axis(&input->base, time, axis, value);
> >  }
> >  
> > +static void
> > +input_handle_axis_frame(void *data, struct wl_pointer *pointer)
> > +{
> > +	struct wayland_input *input = data;
> > +
> > +	notify_axis_frame(&input->base);
> > +}
> > +
> > +static void
> > +input_handle_axis_source(void *data, struct wl_pointer *pointer,
> > +			 uint32_t source)
> > +{
> > +	struct wayland_input *input = data;
> > +
> > +	notify_axis_source(&input->base, source);
> > +}
> > +
> > +static void
> > +input_handle_axis_stop(void *data, struct wl_pointer *pointer,
> > +		       uint32_t time, uint32_t axis)
> > +{
> > +	struct wayland_input *input = data;
> > +
> > +	notify_axis(&input->base, time, axis, 0);
> > +}
> > +
> > +static void
> > +input_handle_axis_discrete(void *data, struct wl_pointer *pointer,
> > +			   int32_t discrete)
> > +{
> > +	struct wayland_input *input = data;
> > +
> > +	notify_axis_discrete(&input->base, discrete);
> > +}
> > +
> >  static const struct wl_pointer_listener pointer_listener = {
> >  	input_handle_pointer_enter,
> >  	input_handle_pointer_leave,
> >  	input_handle_motion,
> >  	input_handle_button,
> >  	input_handle_axis,
> > +	input_handle_axis_frame,
> > +	input_handle_axis_source,
> > +	input_handle_axis_stop,
> > +	input_handle_axis_discrete,
> >  };
> >  
> >  static void
> > diff --git a/src/compositor-x11.c b/src/compositor-x11.c
> > index 9a23996..4b5499d 100644
> > --- a/src/compositor-x11.c
> > +++ b/src/compositor-x11.c
> > @@ -1082,32 +1082,40 @@ x11_backend_deliver_button_event(struct x11_backend *b,
> >  	case 4:
> >  		/* Axis are measured in pixels, but the xcb events are discrete
> >  		 * steps. Therefore move the axis by some pixels every step. */
> > -		if (state)
> > +		if (state) {
> > +			notify_axis_discrete(&b->core_seat, -1);
> >  			notify_axis(&b->core_seat,
> >  				    weston_compositor_get_time(),
> >  				    WL_POINTER_AXIS_VERTICAL_SCROLL,
> >  				    -DEFAULT_AXIS_STEP_DISTANCE);
> > +		}
> >  		return;
> >  	case 5:
> > -		if (state)
> > +		if (state) {
> > +			notify_axis_discrete(&b->core_seat, 1);
> >  			notify_axis(&b->core_seat,
> >  				    weston_compositor_get_time(),
> >  				    WL_POINTER_AXIS_VERTICAL_SCROLL,
> >  				    DEFAULT_AXIS_STEP_DISTANCE);
> > +		}
> >  		return;
> >  	case 6:
> > -		if (state)
> > +		if (state) {
> > +			notify_axis_discrete(&b->core_seat, -1);
> >  			notify_axis(&b->core_seat,
> >  				    weston_compositor_get_time(),
> >  				    WL_POINTER_AXIS_HORIZONTAL_SCROLL,
> >  				    -DEFAULT_AXIS_STEP_DISTANCE);
> > +		}
> >  		return;
> >  	case 7:
> > -		if (state)
> > +		if (state) {
> > +			notify_axis_discrete(&b->core_seat, 1);
> >  			notify_axis(&b->core_seat,
> >  				    weston_compositor_get_time(),
> >  				    WL_POINTER_AXIS_HORIZONTAL_SCROLL,
> >  				    DEFAULT_AXIS_STEP_DISTANCE);
> > +		}
> >  		return;
> >  	default:
> >  		button = button_event->detail + BTN_SIDE - 8;
> > diff --git a/src/compositor.h b/src/compositor.h
> > index 2e2a185..1e518e1 100644
> > --- a/src/compositor.h
> > +++ b/src/compositor.h
> > @@ -1075,6 +1075,16 @@ notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
> >  void
> >  notify_axis(struct weston_seat *seat, uint32_t time, uint32_t axis,
> >  	    wl_fixed_t value);
> > +
> > +void
> > +notify_axis_discrete(struct weston_seat *seat, int32_t discrete);
> > +
> > +void
> > +notify_axis_source(struct weston_seat *seat, uint32_t source);
> > +
> > +void
> > +notify_axis_frame(struct weston_seat *seat);
> > +
> >  void
> >  notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
> >  	   enum wl_keyboard_key_state state,
> > diff --git a/src/input.c b/src/input.c
> > index 500c39a..4d7ac2b 100644
> > --- a/src/input.c
> > +++ b/src/input.c
> > @@ -1089,17 +1089,75 @@ notify_axis(struct weston_seat *seat, uint32_t time, uint32_t axis,
> >  
> >  	weston_compositor_wake(compositor);
> >  
> > -	if (!value)
> > -		return;
> > -
> >  	if (weston_compositor_run_axis_binding(compositor, pointer,
> >  					       time, axis, value))
> >  		return;
> >  
> >  	resource_list = &pointer->focus_resource_list;
> > -	wl_resource_for_each(resource, resource_list)
> > -		wl_pointer_send_axis(resource, time, axis,
> > -				     value);
> > +	wl_resource_for_each(resource, resource_list) {
> > +		if (value)
> > +			wl_pointer_send_axis(resource, time, axis, value);
> > +		else if (wl_resource_get_version(resource) >=
> > +			 WL_POINTER_AXIS_STOP_SINCE_VERSION)
> > +			wl_pointer_send_axis_stop(resource, time, axis);
> > +	}
> > +}
> > +
> > +WL_EXPORT void
> > +notify_axis_discrete(struct weston_seat *seat, int32_t discrete)
> > +{
> > +	struct weston_compositor *compositor = seat->compositor;
> > +	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
> > +	struct wl_resource *resource;
> > +	struct wl_list *resource_list;
> > +
> > +	weston_compositor_wake(compositor);
> > +
> > +	resource_list = &pointer->focus_resource_list;
> > +	wl_resource_for_each(resource, resource_list) {
> > +		if (wl_resource_get_version(resource) >=
> > +		    WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) {
> > +			wl_pointer_send_axis_discrete(resource, discrete);
> > +		}
> > +	}
> > +}
> > +
> > +WL_EXPORT void
> > +notify_axis_source(struct weston_seat *seat, uint32_t source)
> > +{
> > +	struct weston_compositor *compositor = seat->compositor;
> > +	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
> > +	struct wl_resource *resource;
> > +	struct wl_list *resource_list;
> > +
> > +	weston_compositor_wake(compositor);
> > +
> > +	resource_list = &pointer->focus_resource_list;
> > +	wl_resource_for_each(resource, resource_list) {
> > +		if (wl_resource_get_version(resource) >=
> > +		    WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
> > +			wl_pointer_send_axis_source(resource, source);
> > +		}
> > +	}
> > +}
> > +
> > +WL_EXPORT void
> > +notify_axis_frame(struct weston_seat *seat)
> > +{
> > +	struct weston_compositor *compositor = seat->compositor;
> > +	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
> > +	struct wl_resource *resource;
> > +	struct wl_list *resource_list;
> > +
> > +	weston_compositor_wake(compositor);
> > +
> > +	resource_list = &pointer->focus_resource_list;
> > +	wl_resource_for_each(resource, resource_list) {
> > +		if (wl_resource_get_version(resource) >=
> > +		    WL_POINTER_AXIS_FRAME_SINCE_VERSION) {
> > +			wl_pointer_send_axis_frame(resource);
> > +		}
> > +	}
> >  }
> >  
> >  WL_EXPORT int
> > @@ -1958,7 +2016,7 @@ bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
> >  	enum wl_seat_capability caps = 0;
> >  
> >  	resource = wl_resource_create(client,
> > -				      &wl_seat_interface, MIN(version, 4), id);
> > +				      &wl_seat_interface, MIN(version, 5), id);
> >  	wl_list_insert(&seat->base_resource_list, wl_resource_get_link(resource));
> >  	wl_resource_set_implementation(resource, &seat_interface, data,
> >  				       unbind_resource);
> > @@ -2361,7 +2419,7 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
> >  	wl_signal_init(&seat->destroy_signal);
> >  	wl_signal_init(&seat->updated_caps_signal);
> >  
> > -	seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 4,
> > +	seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 5,
> >  					seat, bind_seat);
> >  
> >  	seat->compositor = ec;
> > diff --git a/src/libinput-device.c b/src/libinput-device.c
> > index 2cbfb88..f7f2eef 100644
> > --- a/src/libinput-device.c
> > +++ b/src/libinput-device.c
> > @@ -161,6 +161,7 @@ normalize_scroll(struct libinput_event_pointer *pointer_event,
> >  	double value;
> >  
> >  	source = libinput_event_pointer_get_axis_source(pointer_event);
> > +
> >  	/* libinput < 0.8 sent wheel click events with value 10. Since 0.8
> >  	   the value is the angle of the click in degrees. To keep
> >  	   backwards-compat with existing clients, we just send multiples of
> > @@ -180,8 +181,7 @@ normalize_scroll(struct libinput_event_pointer *pointer_event,
> >  	default:
> >  		value = 0;
> >  		if (warned < 5) {
> > -			weston_log("Unknown scroll source %d. Event discarded\n",
> > -				   source);
> > +			weston_log("Unknown scroll source %d.\n", source);
> >  			warned++;
> >  		}
> >  		break;
> > @@ -190,6 +190,23 @@ normalize_scroll(struct libinput_event_pointer *pointer_event,
> >  	return value;
> >  }
> >  
> > +static bool
> > +fetch_axis_discrete(struct libinput_event_pointer *pointer_event,
> > +		    enum libinput_pointer_axis axis,
> > +		    int32_t *discrete)
> > +{
> > +	enum libinput_pointer_axis_source source;
> > +
> > +	source = libinput_event_pointer_get_axis_source(pointer_event);
> > +
> > +	if (source != LIBINPUT_POINTER_AXIS_SOURCE_WHEEL)
> > +		return false;
> > +
> > +	*discrete = libinput_event_pointer_get_axis_value_discrete(
> > +						   pointer_event, axis);
> > +	return true;
> > +}
> > +
> >  static void
> >  handle_pointer_axis(struct libinput_device *libinput_device,
> >  		    struct libinput_event_pointer *pointer_event)
> > @@ -197,10 +214,46 @@ handle_pointer_axis(struct libinput_device *libinput_device,
> >  	struct evdev_device *device =
> >  		libinput_device_get_user_data(libinput_device);
> >  	double value;
> > +	int32_t value_discrete;
> >  	enum libinput_pointer_axis axis;
> > +	enum libinput_pointer_axis_source source;
> > +	uint32_t wl_axis_source;
> > +	bool need_axis_source_event = true;
> > +	bool has_vert, has_horiz;
> > +
> > +	has_vert = libinput_event_pointer_has_axis(pointer_event,
> > +				   LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
> > +	has_horiz = libinput_event_pointer_has_axis(pointer_event,
> > +				   LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
> > +
> > +	if (!has_vert && !has_horiz)
> > +		return;
> > +
> > +	source = libinput_event_pointer_get_axis_source(pointer_event);
> > +	switch (source) {
> > +	case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
> > +		wl_axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
> > +		break;
> > +	case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
> > +		wl_axis_source = WL_POINTER_AXIS_SOURCE_FINGER;
> > +		break;
> > +	case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
> > +		wl_axis_source = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
> > +		break;
> > +	default:
> > +		need_axis_source_event = false;
> > +		break;
> > +	}
> > +
> > +	if (need_axis_source_event)
> > +		notify_axis_source(device->seat, wl_axis_source);
> >  
> >  	axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
> >  	if (libinput_event_pointer_has_axis(pointer_event, axis)) {
> > +		if (fetch_axis_discrete(pointer_event, axis,
> > +					&value_discrete))
> > +		    notify_axis_discrete(device->seat, value_discrete);
> > +
> >  		value = normalize_scroll(pointer_event, axis);
> >  		notify_axis(device->seat,
> >  			    libinput_event_pointer_get_time(pointer_event),
> > @@ -210,12 +263,18 @@ handle_pointer_axis(struct libinput_device *libinput_device,
> >  
> >  	axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
> >  	if (libinput_event_pointer_has_axis(pointer_event, axis)) {
> > +		if (fetch_axis_discrete(pointer_event, axis,
> > +					&value_discrete))
> > +		    notify_axis_discrete(device->seat, value_discrete);
> > +
> >  		value = normalize_scroll(pointer_event, axis);
> >  		notify_axis(device->seat,
> >  			    libinput_event_pointer_get_time(pointer_event),
> >  			    WL_POINTER_AXIS_HORIZONTAL_SCROLL,
> >  			    wl_fixed_from_double(value));
> >  	}
> > +
> > +	notify_axis_frame(device->seat);
> >  }
> >  
> >  static void
> > -- 
> > 2.4.3


More information about the wayland-devel mailing list