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

Peter Hutterer peter.hutterer at who-t.net
Sun Nov 15 20:50:19 PST 2015


Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
This one goes with v6 of the protocol, see
http://patchwork.freedesktop.org/patch/64871/

Changes to v1:
- revamped for wl_pointer.frame (instead of axis frame)
- added the hooks for the tests
- rebased on master, added the new pointer axis grab handling bits
- re-did the pointer event handling so the frame is only sent when we're
  sending at least one pointer event to the client

 clients/eventdemo.c               |  57 ++++++++++++++-
 clients/window.c                  |  97 +++++++++++++++++++++++++-
 clients/window.h                  |  31 +++++++++
 desktop-shell/exposay.c           |  19 +++++
 desktop-shell/shell.c             |  51 ++++++++++++++
 ivi-shell/hmi-controller.c        |  23 ++++++
 src/compositor-wayland.c          |  39 +++++++++++
 src/compositor-x11.c              |  29 ++++++--
 src/compositor.h                  |  24 +++++++
 src/data-device.c                 |  19 +++++
 src/input.c                       | 120 ++++++++++++++++++++++++++++++--
 src/libinput-device.c             | 142 +++++++++++++++++++++++++++++---------
 tests/weston-test-client-helper.c |  32 +++++++++
 13 files changed, 639 insertions(+), 44 deletions(-)

diff --git a/clients/eventdemo.c b/clients/eventdemo.c
index bdad6fd..e323aa5 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
+pointer_frame_handler(struct widget *widget, struct input *input, void *data)
+{
+	printf("pointer 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,
+		      uint32_t axis, int32_t discrete, void *data)
+{
+	printf("axis discrete axis: %d value: %d\n", axis, discrete);
+}
+
 /**
  * \brief CALLBACK function, Waylands informs about pointer motion
  * \param widget widget
@@ -347,8 +395,15 @@ eventdemo_create(struct display *d)
 	/* Set the callback motion handler for the window */
 	widget_set_motion_handler(e->widget, motion_handler);
 
+	/* Set the callback pointer frame handler for the window */
+	widget_set_pointer_frame_handler(e->widget, pointer_frame_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_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 47628de..5197e94 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -287,6 +287,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_pointer_frame_handler_t pointer_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,26 @@ widget_set_axis_handler(struct widget *widget,
 	widget->axis_handler = handler;
 }
 
+void
+widget_set_pointer_frame_handler(struct widget *widget,
+				 widget_pointer_frame_handler_t handler)
+{
+	widget->pointer_frame_handler = handler;
+}
+
+void
+widget_set_axis_handlers(struct widget *widget,
+			widget_axis_handler_t axis_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_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);
 
@@ -2819,12 +2843,83 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
 					widget->user_data);
 }
 
+static void
+pointer_handle_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->pointer_frame_handler)
+		(*widget->pointer_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,
+			     uint32_t axis, 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,
+						 axis,
+						 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_frame,
+	pointer_handle_axis_source,
+	pointer_handle_axis_stop,
+	pointer_handle_axis_discrete,
 };
 
 static void
@@ -5224,7 +5319,7 @@ static void
 display_add_input(struct display *d, uint32_t id, int display_seat_version)
 {
 	struct input *input;
-	int seat_version = MIN(display_seat_version, 4);
+	int seat_version = MIN(display_seat_version, 5);
 
 	input = xzalloc(sizeof *input);
 	input->display = d;
diff --git a/clients/window.h b/clients/window.h
index b61a62a..17bcd20 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -267,6 +267,27 @@ typedef void (*widget_axis_handler_t)(struct widget *widget,
 				      wl_fixed_t value,
 				      void *data);
 
+typedef void (*widget_pointer_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,
+					       uint32_t axis,
+					       int32_t discrete,
+					       void *data);
+
 struct window *
 window_create(struct display *display);
 struct window *
@@ -520,6 +541,16 @@ void
 widget_set_axis_handler(struct widget *widget,
 			widget_axis_handler_t handler);
 void
+widget_set_pointer_frame_handler(struct widget *widget,
+				 widget_pointer_frame_handler_t handler);
+void
+widget_set_axis_handlers(struct widget *widget,
+			widget_axis_handler_t axis_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/desktop-shell/exposay.c b/desktop-shell/exposay.c
index eb4070e..1bb6ebc 100644
--- a/desktop-shell/exposay.c
+++ b/desktop-shell/exposay.c
@@ -392,6 +392,22 @@ exposay_axis(struct weston_pointer_grab *grab,
 }
 
 static void
+exposay_axis_discrete(struct weston_pointer_grab *grab,
+		      uint32_t axis, wl_fixed_t value)
+{
+}
+
+static void
+exposay_axis_source(struct weston_pointer_grab *grab, uint32_t source)
+{
+}
+
+static void
+exposay_frame(struct weston_pointer_grab *grab)
+{
+}
+
+static void
 exposay_pointer_grab_cancel(struct weston_pointer_grab *grab)
 {
 	struct desktop_shell *shell =
@@ -405,6 +421,9 @@ static const struct weston_pointer_grab_interface exposay_ptr_grab = {
 	exposay_motion,
 	exposay_button,
 	exposay_axis,
+	exposay_axis_discrete,
+	exposay_axis_source,
+	exposay_frame,
 	exposay_pointer_grab_cancel,
 };
 
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 9968307..9075039 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -1707,6 +1707,23 @@ noop_grab_axis(struct weston_pointer_grab *grab,
 }
 
 static void
+noop_grab_axis_discrete(struct weston_pointer_grab *grab,
+			uint32_t axis, wl_fixed_t value)
+{
+}
+
+static void
+noop_grab_axis_source(struct weston_pointer_grab *grab,
+		      uint32_t source)
+{
+}
+
+static void
+noop_grab_frame(struct weston_pointer_grab *grab)
+{
+}
+
+static void
 constrain_position(struct weston_move_grab *move, int *cx, int *cy)
 {
 	struct shell_surface *shsurf = move->base.shsurf;
@@ -1789,6 +1806,9 @@ static const struct weston_pointer_grab_interface move_grab_interface = {
 	move_grab_motion,
 	move_grab_button,
 	noop_grab_axis,
+	noop_grab_axis_discrete,
+	noop_grab_axis_source,
+	noop_grab_frame,
 	move_grab_cancel,
 };
 
@@ -1953,6 +1973,9 @@ static const struct weston_pointer_grab_interface resize_grab_interface = {
 	resize_grab_motion,
 	resize_grab_button,
 	noop_grab_axis,
+	noop_grab_axis_discrete,
+	noop_grab_axis_source,
+	noop_grab_frame,
 	resize_grab_cancel,
 };
 
@@ -2118,6 +2141,9 @@ static const struct weston_pointer_grab_interface busy_cursor_grab_interface = {
 	busy_cursor_grab_motion,
 	busy_cursor_grab_button,
 	noop_grab_axis,
+	noop_grab_axis_discrete,
+	noop_grab_axis_source,
+	noop_grab_frame,
 	busy_cursor_grab_cancel,
 };
 
@@ -3307,6 +3333,25 @@ popup_grab_axis(struct weston_pointer_grab *grab,
 }
 
 static void
+popup_grab_axis_discrete(struct weston_pointer_grab *grab,
+			 uint32_t axis, int32_t value)
+{
+	weston_pointer_send_axis_discrete(grab->pointer, axis, value);
+}
+
+static void
+popup_grab_axis_source(struct weston_pointer_grab *grab, uint32_t source)
+{
+	weston_pointer_send_axis_source(grab->pointer, source);
+}
+
+static void
+popup_grab_frame(struct weston_pointer_grab *grab)
+{
+	weston_pointer_send_frame(grab->pointer);
+}
+
+static void
 popup_grab_cancel(struct weston_pointer_grab *grab)
 {
 	popup_grab_end(grab->pointer);
@@ -3317,6 +3362,9 @@ static const struct weston_pointer_grab_interface popup_grab_interface = {
 	popup_grab_motion,
 	popup_grab_button,
 	popup_grab_axis,
+	popup_grab_axis_discrete,
+	popup_grab_axis_source,
+	popup_grab_frame,
 	popup_grab_cancel,
 };
 
@@ -5018,6 +5066,9 @@ static const struct weston_pointer_grab_interface rotate_grab_interface = {
 	rotate_grab_motion,
 	rotate_grab_button,
 	noop_grab_axis,
+	noop_grab_axis_discrete,
+	noop_grab_axis_source,
+	noop_grab_frame,
 	rotate_grab_cancel,
 };
 
diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
index 633ea19..433caac 100644
--- a/ivi-shell/hmi-controller.c
+++ b/ivi-shell/hmi-controller.c
@@ -1330,6 +1330,26 @@ pointer_default_grab_axis(struct weston_pointer_grab *grab,
 }
 
 static void
+pointer_default_grab_axis_discrete(struct weston_pointer_grab *grab,
+				   uint32_t axis, int32_t value)
+{
+	weston_pointer_send_axis_discrete(grab->pointer, axis, value);
+}
+
+static void
+pointer_default_grab_axis_source(struct weston_pointer_grab *grab,
+				 uint32_t source)
+{
+	weston_pointer_send_axis_source(grab->pointer, source);
+}
+
+static void
+pointer_default_grab_frame(struct weston_pointer_grab *grab)
+{
+	weston_pointer_send_frame(grab->pointer);
+}
+
+static void
 move_grab_update(struct move_grab *move, wl_fixed_t pointer[2])
 {
 	struct timespec timestamp = {0};
@@ -1474,6 +1494,9 @@ static const struct weston_pointer_grab_interface pointer_move_grab_workspace_in
 	pointer_move_grab_motion,
 	pointer_move_workspace_grab_button,
 	pointer_default_grab_axis,
+	pointer_default_grab_axis_discrete,
+	pointer_default_grab_axis_source,
+	pointer_default_grab_frame,
 	pointer_move_workspace_grab_cancel
 };
 
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index a819867..f2c5251 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_frame(void *data, struct wl_pointer *pointer)
+{
+	struct wayland_input *input = data;
+
+	notify_pointer_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,
+			   uint32_t axis, int32_t discrete)
+{
+	struct wayland_input *input = data;
+
+	notify_axis_discrete(&input->base, axis, 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_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 ccb7867..b399a35 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -1082,32 +1082,48 @@ 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,
+					     WL_POINTER_AXIS_VERTICAL_SCROLL,
+					     -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,
+					     WL_POINTER_AXIS_VERTICAL_SCROLL,
+					     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,
+					     WL_POINTER_AXIS_HORIZONTAL_SCROLL,
+					     -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,
+					     WL_POINTER_AXIS_HORIZONTAL_SCROLL,
+					     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;
@@ -1118,6 +1134,7 @@ x11_backend_deliver_button_event(struct x11_backend *b,
 		      weston_compositor_get_time(), button,
 		      state ? WL_POINTER_BUTTON_STATE_PRESSED :
 			      WL_POINTER_BUTTON_STATE_RELEASED);
+	notify_pointer_frame(&b->core_seat);
 }
 
 static void
@@ -1142,6 +1159,7 @@ x11_backend_deliver_motion_event(struct x11_backend *b,
 
 	notify_motion(&b->core_seat, weston_compositor_get_time(),
 		      x - b->prev_x, y - b->prev_y);
+	notify_pointer_frame(&b->core_seat);
 
 	b->prev_x = x;
 	b->prev_y = y;
@@ -1169,6 +1187,7 @@ x11_backend_deliver_enter_event(struct x11_backend *b,
 					   wl_fixed_from_int(enter_notify->event_y), &x, &y);
 
 	notify_pointer_focus(&b->core_seat, &output->base, x, y);
+	notify_pointer_frame(&b->core_seat);
 
 	b->prev_x = x;
 	b->prev_y = y;
@@ -1322,6 +1341,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
 
 		case XCB_ENTER_NOTIFY:
 			x11_backend_deliver_enter_event(b, event);
+			notify_pointer_frame(&b->core_seat);
 			break;
 
 		case XCB_LEAVE_NOTIFY:
@@ -1331,6 +1351,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
 			if (!b->has_xkb)
 				update_xkb_state_from_core(b, enter_notify->state);
 			notify_pointer_focus(&b->core_seat, NULL, 0, 0);
+			notify_pointer_frame(&b->core_seat);
 			break;
 
 		case XCB_CLIENT_MESSAGE:
diff --git a/src/compositor.h b/src/compositor.h
index f3e0075..e9c6daf 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -249,6 +249,10 @@ struct weston_pointer_grab_interface {
 		       uint32_t time, uint32_t button, uint32_t state);
 	void (*axis)(struct weston_pointer_grab *grab,
 		     uint32_t time, uint32_t axis, wl_fixed_t value);
+	void (*axis_discrete)(struct weston_pointer_grab *grab,
+			      uint32_t axis, int32_t value);
+	void (*axis_source)(struct weston_pointer_grab *grab, uint32_t source);
+	void (*frame)(struct weston_pointer_grab *grab);
 	void (*cancel)(struct weston_pointer_grab *grab);
 };
 
@@ -374,6 +378,15 @@ void
 weston_pointer_send_axis(struct weston_pointer *pointer,
 			 uint32_t time, uint32_t axis, wl_fixed_t value);
 void
+weston_pointer_send_axis_discrete(struct weston_pointer *pointer,
+				  uint32_t axis, wl_fixed_t value);
+void
+weston_pointer_send_axis_source(struct weston_pointer *pointer,
+				uint32_t source);
+void
+weston_pointer_send_frame(struct weston_pointer *pointer);
+
+void
 weston_pointer_set_focus(struct weston_pointer *pointer,
 			 struct weston_view *view,
 			 wl_fixed_t sx, wl_fixed_t sy);
@@ -1112,6 +1125,17 @@ 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, uint32_t axis,
+		     int32_t discrete);
+
+void
+notify_axis_source(struct weston_seat *seat, uint32_t source);
+
+void
+notify_pointer_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/data-device.c b/src/data-device.c
index 66c4c7a..bee6599 100644
--- a/src/data-device.c
+++ b/src/data-device.c
@@ -417,6 +417,22 @@ drag_grab_axis(struct weston_pointer_grab *grab,
 }
 
 static void
+drag_grab_axis_discrete(struct weston_pointer_grab *grab,
+			uint32_t axis, int32_t value)
+{
+}
+
+static void
+drag_grab_axis_source(struct weston_pointer_grab *grab, uint32_t source)
+{
+}
+
+static void
+drag_grab_frame(struct weston_pointer_grab *grab)
+{
+}
+
+static void
 drag_grab_cancel(struct weston_pointer_grab *grab)
 {
 	struct weston_pointer_drag *drag =
@@ -433,6 +449,9 @@ static const struct weston_pointer_grab_interface pointer_drag_grab_interface =
 	drag_grab_motion,
 	drag_grab_button,
 	drag_grab_axis,
+	drag_grab_axis_discrete,
+	drag_grab_axis_source,
+	drag_grab_frame,
 	drag_grab_cancel,
 };
 
diff --git a/src/input.c b/src/input.c
index 09d12de..b75be56 100644
--- a/src/input.c
+++ b/src/input.c
@@ -241,7 +241,57 @@ weston_pointer_send_axis(struct weston_pointer *pointer,
 
 	resource_list = &pointer->focus_resource_list;
 	wl_resource_for_each(resource, resource_list)
-		wl_pointer_send_axis(resource, time, axis, value);
+		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
+weston_pointer_send_axis_discrete(struct weston_pointer *pointer,
+				  uint32_t axis, wl_fixed_t value)
+{
+	struct wl_resource *resource;
+	struct wl_list *resource_list;
+
+	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, axis, value);
+		}
+	}
+}
+
+WL_EXPORT void
+weston_pointer_send_axis_source(struct weston_pointer *pointer, uint32_t source)
+{
+	struct wl_resource *resource;
+	struct wl_list *resource_list;
+
+	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
+weston_pointer_send_frame(struct weston_pointer *pointer)
+{
+	struct wl_resource *resource;
+	struct wl_list *resource_list;
+
+	resource_list = &pointer->focus_resource_list;
+	wl_resource_for_each(resource, resource_list) {
+		if (wl_resource_get_version(resource) >=
+		    WL_POINTER_FRAME_SINCE_VERSION) {
+			wl_pointer_send_frame(resource);
+		}
+	}
 }
 
 static void
@@ -252,6 +302,26 @@ default_grab_pointer_axis(struct weston_pointer_grab *grab,
 }
 
 static void
+default_grab_pointer_axis_discrete(struct weston_pointer_grab *grab,
+				   uint32_t axis, wl_fixed_t value)
+{
+	weston_pointer_send_axis_discrete(grab->pointer, axis, value);
+}
+
+static void
+default_grab_pointer_axis_source(struct weston_pointer_grab *grab,
+				 uint32_t source)
+{
+	weston_pointer_send_axis_source(grab->pointer, source);
+}
+
+static void
+default_grab_pointer_frame(struct weston_pointer_grab *grab)
+{
+	weston_pointer_send_frame(grab->pointer);
+}
+
+static void
 default_grab_pointer_cancel(struct weston_pointer_grab *grab)
 {
 }
@@ -262,6 +332,9 @@ static const struct weston_pointer_grab_interface
 	default_grab_pointer_motion,
 	default_grab_pointer_button,
 	default_grab_pointer_axis,
+	default_grab_pointer_axis_discrete,
+	default_grab_pointer_axis_source,
+	default_grab_pointer_frame,
 	default_grab_pointer_cancel,
 };
 
@@ -707,6 +780,7 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
 		wl_resource_for_each(resource, focus_resource_list) {
 			wl_pointer_send_leave(resource, serial,
 					      pointer->focus->surface->resource);
+			wl_pointer_send_frame(resource);
 		}
 
 		move_resources(&pointer->resource_list, focus_resource_list);
@@ -733,6 +807,7 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
 					      serial,
 					      view->surface->resource,
 					      sx, sy);
+			wl_pointer_send_frame(resource);
 		}
 
 		pointer->focus_serial = serial;
@@ -1118,9 +1193,6 @@ 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;
@@ -1128,6 +1200,41 @@ notify_axis(struct weston_seat *seat, uint32_t time, uint32_t axis,
 	pointer->grab->interface->axis(pointer->grab, time, axis, value);
 }
 
+WL_EXPORT void
+notify_axis_discrete(struct weston_seat *seat, uint32_t axis,
+		     int32_t discrete)
+{
+	struct weston_compositor *compositor = seat->compositor;
+	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+	weston_compositor_wake(compositor);
+
+	pointer->grab->interface->axis_discrete(pointer->grab, axis,
+						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);
+
+	weston_compositor_wake(compositor);
+
+	pointer->grab->interface->axis_source(pointer->grab, source);
+}
+
+WL_EXPORT void
+notify_pointer_frame(struct weston_seat *seat)
+{
+	struct weston_compositor *compositor = seat->compositor;
+	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+	weston_compositor_wake(compositor);
+
+	pointer->grab->interface->frame(pointer->grab);
+}
+
 WL_EXPORT int
 weston_keyboard_set_locks(struct weston_keyboard *keyboard,
 			  uint32_t mask, uint32_t value)
@@ -1809,6 +1916,7 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
 				      pointer->focus_serial,
 				      pointer->focus->surface->resource,
 				      sx, sy);
+		wl_pointer_send_frame(cr);
 	}
 }
 
@@ -1984,7 +2092,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);
@@ -2387,7 +2495,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 69dcbf8..ef76825 100644
--- a/src/libinput-device.c
+++ b/src/libinput-device.c
@@ -80,7 +80,7 @@ handle_keyboard_key(struct libinput_device *libinput_device,
 		   STATE_UPDATE_AUTOMATIC);
 }
 
-static void
+static bool
 handle_pointer_motion(struct libinput_device *libinput_device,
 		      struct libinput_event_pointer *pointer_event)
 {
@@ -94,9 +94,11 @@ handle_pointer_motion(struct libinput_device *libinput_device,
 		      libinput_event_pointer_get_time(pointer_event),
 		      dx,
 		      dy);
+
+	return true;
 }
 
-static void
+static bool
 handle_pointer_motion_absolute(
 	struct libinput_device *libinput_device,
 	struct libinput_event_pointer *pointer_event)
@@ -109,7 +111,7 @@ handle_pointer_motion_absolute(
 	uint32_t width, height;
 
 	if (!output)
-		return;
+		return false;
 
 	time = libinput_event_pointer_get_time(pointer_event);
 	width = device->output->current_mode->width;
@@ -124,9 +126,11 @@ handle_pointer_motion_absolute(
 
 	weston_output_transform_coordinate(device->output, x, y, &x, &y);
 	notify_motion_absolute(device->seat, time, x, y);
+
+	return true;
 }
 
-static void
+static bool
 handle_pointer_button(struct libinput_device *libinput_device,
 		      struct libinput_event_pointer *pointer_event)
 {
@@ -142,21 +146,21 @@ handle_pointer_button(struct libinput_device *libinput_device,
 	     seat_button_count != 1) ||
 	    (button_state == LIBINPUT_BUTTON_STATE_RELEASED &&
 	     seat_button_count != 0))
-		return;
+		return false;
 
 	notify_button(device->seat,
 		      libinput_event_pointer_get_time(pointer_event),
 		      libinput_event_pointer_get_button(pointer_event),
 		      libinput_event_pointer_get_button_state(pointer_event));
+	return true;
 }
 
 static double
 normalize_scroll(struct libinput_event_pointer *pointer_event,
 		 enum libinput_pointer_axis axis)
 {
-	static int warned;
 	enum libinput_pointer_axis_source source;
-	double value;
+	double value = 0.0;
 
 	source = libinput_event_pointer_get_axis_source(pointer_event);
 	/* libinput < 0.8 sent wheel click events with value 10. Since 0.8
@@ -175,45 +179,112 @@ normalize_scroll(struct libinput_event_pointer *pointer_event,
 		value = libinput_event_pointer_get_axis_value(pointer_event,
 							      axis);
 		break;
-	default:
-		value = 0;
-		if (warned < 5) {
-			weston_log("Unknown scroll source %d. Event discarded\n",
-				   source);
-			warned++;
-		}
-		break;
 	}
 
 	return value;
 }
 
-static void
+static int32_t
+get_axis_discrete(struct libinput_event_pointer *pointer_event,
+		  enum libinput_pointer_axis axis)
+{
+	enum libinput_pointer_axis_source source;
+
+	source = libinput_event_pointer_get_axis_source(pointer_event);
+
+	if (source != LIBINPUT_POINTER_AXIS_SOURCE_WHEEL)
+		return 0.0;
+
+	return libinput_event_pointer_get_axis_value_discrete(pointer_event,
+							      axis);
+}
+
+static bool
 handle_pointer_axis(struct libinput_device *libinput_device,
 		    struct libinput_event_pointer *pointer_event)
 {
+	static int warned;
 	struct evdev_device *device =
 		libinput_device_get_user_data(libinput_device);
-	double value;
+	double vert, horiz;
+	int32_t vert_discrete, horiz_discrete;
 	enum libinput_pointer_axis axis;
+	enum libinput_pointer_axis_source source;
+	uint32_t wl_axis_source;
+	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 false;
+
+	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:
+		if (warned < 5) {
+			weston_log("Unknown scroll source %d.\n", source);
+			warned++;
+		}
+		return false;
+	}
 
 	axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
+	vert = 0;
+	vert_discrete = 0;
 	if (libinput_event_pointer_has_axis(pointer_event, axis)) {
-		value = normalize_scroll(pointer_event, axis);
-		notify_axis(device->seat,
-			    libinput_event_pointer_get_time(pointer_event),
-			    WL_POINTER_AXIS_VERTICAL_SCROLL,
-			    wl_fixed_from_double(value));
+		vert_discrete = get_axis_discrete(pointer_event, axis);
+		vert = normalize_scroll(pointer_event, axis);
 	}
 
 	axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
+	horiz = 0;
+	horiz_discrete = 0;
 	if (libinput_event_pointer_has_axis(pointer_event, axis)) {
-		value = normalize_scroll(pointer_event, axis);
+		horiz_discrete = get_axis_discrete(pointer_event, axis);
+		horiz = normalize_scroll(pointer_event, axis);
+	}
+
+	if (vert == 0.0 && vert_discrete == 0 &&
+	    horiz == 0.0 && horiz_discrete == 0)
+		return false;
+
+	notify_axis_source(device->seat, wl_axis_source);
+
+	/* if we have a discrete value, we must send an normal axis
+	 * event, even if the axis value is 0 */
+	if (vert_discrete != 0)
+		notify_axis_discrete(device->seat,
+				     WL_POINTER_AXIS_VERTICAL_SCROLL,
+				     vert_discrete);
+	if (vert != 0.0 || vert_discrete != 0)
+		notify_axis(device->seat,
+			    libinput_event_pointer_get_time(pointer_event),
+			    WL_POINTER_AXIS_VERTICAL_SCROLL,
+			    wl_fixed_from_double(vert));
+
+	if (horiz_discrete != 0)
+		notify_axis_discrete(device->seat,
+				     WL_POINTER_AXIS_HORIZONTAL_SCROLL,
+				     horiz_discrete);
+	if (horiz != 0 || horiz_discrete != 0)
 		notify_axis(device->seat,
 			    libinput_event_pointer_get_time(pointer_event),
 			    WL_POINTER_AXIS_HORIZONTAL_SCROLL,
-			    wl_fixed_from_double(value));
-	}
+			    wl_fixed_from_double(horiz));
+
+	return true;
 }
 
 static void
@@ -290,7 +361,10 @@ evdev_device_process_event(struct libinput_event *event)
 {
 	struct libinput_device *libinput_device =
 		libinput_event_get_device(event);
+	struct evdev_device *device =
+		libinput_device_get_user_data(libinput_device);
 	int handled = 1;
+	bool need_frame = false;
 
 	switch (libinput_event_get_type(event)) {
 	case LIBINPUT_EVENT_KEYBOARD_KEY:
@@ -298,21 +372,22 @@ evdev_device_process_event(struct libinput_event *event)
 				    libinput_event_get_keyboard_event(event));
 		break;
 	case LIBINPUT_EVENT_POINTER_MOTION:
-		handle_pointer_motion(libinput_device,
+		need_frame = handle_pointer_motion(libinput_device,
 				      libinput_event_get_pointer_event(event));
 		break;
 	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
-		handle_pointer_motion_absolute(
-			libinput_device,
-			libinput_event_get_pointer_event(event));
+		need_frame = handle_pointer_motion_absolute(
+				libinput_device,
+				libinput_event_get_pointer_event(event));
 		break;
 	case LIBINPUT_EVENT_POINTER_BUTTON:
-		handle_pointer_button(libinput_device,
+		need_frame = handle_pointer_button(libinput_device,
 				      libinput_event_get_pointer_event(event));
 		break;
 	case LIBINPUT_EVENT_POINTER_AXIS:
-		handle_pointer_axis(libinput_device,
-				    libinput_event_get_pointer_event(event));
+		need_frame = handle_pointer_axis(
+				 libinput_device,
+				 libinput_event_get_pointer_event(event));
 		break;
 	case LIBINPUT_EVENT_TOUCH_DOWN:
 		handle_touch_down(libinput_device,
@@ -336,6 +411,9 @@ evdev_device_process_event(struct libinput_event *event)
 			   libinput_event_get_type(event));
 	}
 
+	if (need_frame)
+		notify_pointer_frame(device->seat);
+
 	return handled;
 }
 
diff --git a/tests/weston-test-client-helper.c b/tests/weston-test-client-helper.c
index 16786d9..97c4395 100644
--- a/tests/weston-test-client-helper.c
+++ b/tests/weston-test-client-helper.c
@@ -197,12 +197,44 @@ pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
 		axis, wl_fixed_to_double(value));
 }
 
+static void
+pointer_handle_frame(void *data, struct wl_pointer *wl_pointer)
+{
+	fprintf(stderr, "test-client: got pointer frame\n");
+}
+
+static void
+pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer,
+			     uint32_t source)
+{
+	fprintf(stderr, "test-client: got pointer axis source %u\n", source);
+}
+
+static void
+pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
+			 uint32_t time, uint32_t axis)
+{
+	fprintf(stderr, "test-client: got pointer axis stop\n");
+}
+
+static void
+pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer,
+			     uint32_t axis, int32_t value)
+{
+	fprintf(stderr, "test-client: got pointer axis discrete %u %d\n",
+		axis, value);
+}
+
 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,
+	pointer_handle_axis_source,
+	pointer_handle_axis_stop,
+	pointer_handle_axis_discrete,
 };
 
 static void
-- 
2.4.3



More information about the wayland-devel mailing list