Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
---
Changes to v2:
- don't send frames after focus events, notify_pointer_focus() takes
  care of that
- add frame events to screen-share

 clients/eventdemo.c               |  57 ++++++++++++++++-
 clients/window.c                  |  97 ++++++++++++++++++++++++++++-
 clients/window.h                  |  31 +++++++++
 desktop-shell/exposay.c           |  12 ++++
 desktop-shell/shell.c             |  33 ++++++++++
 ivi-shell/hmi-controller.c        |  15 +++++
 src/compositor-rdp.c              |  20 ++++--
 src/compositor-wayland.c          |  84 ++++++++++++++++++++++++-
 src/compositor-x11.c              |  10 +++
 src/compositor.h                  |  16 +++++
 src/data-device.c                 |  12 ++++
 src/input.c                       |  93 ++++++++++++++++++++++++---
 src/libinput-device.c             | 128 ++++++++++++++++++++++++++++----------
 src/screen-share.c                |   4 ++
 tests/weston-test-client-helper.c |  32 ++++++++++
 15 files changed, 596 insertions(+), 48 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 5d69116..7d45acd 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -282,6 +282,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;
@@ -1930,6 +1934,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);
 
@@ -2780,12 +2804,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
@@ -5178,7 +5273,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 b92d10c..ba843cc 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 *
@@ -516,6 +537,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 f837859..7aa7630 100644
--- a/desktop-shell/exposay.c
+++ b/desktop-shell/exposay.c
@@ -392,6 +392,16 @@ exposay_axis(struct weston_pointer_grab *grab,
 }
 
 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 +415,8 @@ static const struct weston_pointer_grab_interface 
exposay_ptr_grab = {
        exposay_motion,
        exposay_button,
        exposay_axis,
+       exposay_axis_source,
+       exposay_frame,
        exposay_pointer_grab_cancel,
 };
 
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 6e74655..5ae83ef 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -1603,6 +1603,17 @@ noop_grab_axis(struct weston_pointer_grab *grab,
 }
 
 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;
@@ -1686,6 +1697,8 @@ static const struct weston_pointer_grab_interface 
move_grab_interface = {
        move_grab_motion,
        move_grab_button,
        noop_grab_axis,
+       noop_grab_axis_source,
+       noop_grab_frame,
        move_grab_cancel,
 };
 
@@ -1851,6 +1864,8 @@ static const struct weston_pointer_grab_interface 
resize_grab_interface = {
        resize_grab_motion,
        resize_grab_button,
        noop_grab_axis,
+       noop_grab_axis_source,
+       noop_grab_frame,
        resize_grab_cancel,
 };
 
@@ -2016,6 +2031,8 @@ 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_source,
+       noop_grab_frame,
        busy_cursor_grab_cancel,
 };
 
@@ -3214,6 +3231,18 @@ popup_grab_axis(struct weston_pointer_grab *grab,
 }
 
 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);
@@ -3224,6 +3253,8 @@ static const struct weston_pointer_grab_interface 
popup_grab_interface = {
        popup_grab_motion,
        popup_grab_button,
        popup_grab_axis,
+       popup_grab_axis_source,
+       popup_grab_frame,
        popup_grab_cancel,
 };
 
@@ -4923,6 +4954,8 @@ static const struct weston_pointer_grab_interface 
rotate_grab_interface = {
        rotate_grab_motion,
        rotate_grab_button,
        noop_grab_axis,
+       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 c21b9e0..8da3d3c 100644
--- a/ivi-shell/hmi-controller.c
+++ b/ivi-shell/hmi-controller.c
@@ -1518,6 +1518,19 @@ pointer_default_grab_axis(struct weston_pointer_grab 
*grab,
 }
 
 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};
@@ -1664,6 +1677,8 @@ 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_source,
+       pointer_default_grab_frame,
        pointer_move_workspace_grab_cancel
 };
 
diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c
index d6d2fa1..3526ad1 100644
--- a/src/compositor-rdp.c
+++ b/src/compositor-rdp.c
@@ -70,7 +70,7 @@
 #include "pixman-renderer.h"
 
 #define MAX_FREERDP_FDS 32
-#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10)
+#define DEFAULT_AXIS_STEP_DISTANCE 10
 #define RDP_MODE_FREQ 60 * 1000
 
 struct rdp_backend_config {
@@ -942,10 +942,11 @@ static BOOL xf_peer_post_connect(freerdp_peer *client)
 static FREERDP_CB_RET_TYPE
 xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
 {
-       wl_fixed_t wl_x, wl_y, axis;
+       wl_fixed_t wl_x, wl_y;
        RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
        struct rdp_output *output;
        uint32_t button = 0;
+       bool need_frame = false;
 
        if (flags & PTR_FLAGS_MOVE) {
                output = peerContext->rdpBackend->output;
@@ -954,6 +955,7 @@ xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, 
UINT16 y)
                        wl_y = wl_fixed_from_int((int)y);
                        notify_motion_absolute(&peerContext->item.seat, 
weston_compositor_get_time(),
                                        wl_x, wl_y);
+                       need_frame = true;
                }
        }
 
@@ -968,10 +970,12 @@ xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, 
UINT16 y)
                notify_button(&peerContext->item.seat, 
weston_compositor_get_time(), button,
                        (flags & PTR_FLAGS_DOWN) ? 
WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED
                );
+               need_frame = true;
        }
 
        if (flags & PTR_FLAGS_WHEEL) {
                struct weston_pointer_axis_event weston_event;
+               double value;
 
                /* DEFAULT_AXIS_STEP_DISTANCE is stolen from compositor-x11.c
                 * The RDP specs says the lower bits of flags contains the "the 
number of rotation
@@ -979,17 +983,23 @@ xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, 
UINT16 y)
                 *
                 * 
https://blogs.msdn.microsoft.com/oldnewthing/20130123-00/?p=5473 explains the 
120 value
                 */
-               axis = (DEFAULT_AXIS_STEP_DISTANCE * (flags & 0xff)) / 120;
+               value = (flags & 0xff) / 120.0;
                if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
-                       axis = -axis;
+                       value = -value;
 
                weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
-               weston_event.value = axis;
+               weston_event.value = 
wl_fixed_from_double(DEFAULT_AXIS_STEP_DISTANCE * value);
+               weston_event.discrete = (int)value;
+               weston_event.has_discrete = true;
 
                notify_axis(&peerContext->item.seat, 
weston_compositor_get_time(),
                            &weston_event);
+               need_frame = true;
        }
 
+       if (need_frame)
+               notify_pointer_frame(&peerContext->item.seat);
+
        FREERDP_CB_RETURN(TRUE);
 }
 
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 48636fe..d1c020d 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -185,6 +185,8 @@ struct wayland_input {
        struct wayland_output *output;
        struct wayland_output *touch_focus;
        struct wayland_output *keyboard_focus;
+
+       struct weston_pointer_axis_event vert, horiz;
 };
 
 struct gl_renderer_interface *gl_renderer;
@@ -1340,6 +1342,7 @@ input_handle_motion(void *data, struct wl_pointer 
*pointer,
        struct wayland_input *input = data;
        int32_t fx, fy;
        enum theme_location location;
+       bool want_frame = false;
 
        if (!input->output)
                return;
@@ -1364,16 +1367,23 @@ input_handle_motion(void *data, struct wl_pointer 
*pointer,
                input_set_cursor(input);
                notify_pointer_focus(&input->base, NULL, 0, 0);
                input->has_focus = false;
+               want_frame = true;
        } else if (!input->has_focus &&
                   location == THEME_LOCATION_CLIENT_AREA) {
                wl_pointer_set_cursor(input->parent.pointer,
                                      input->enter_serial, NULL, 0, 0);
                notify_pointer_focus(&input->base, &input->output->base, x, y);
                input->has_focus = true;
+               want_frame = true;
        }
 
-       if (location == THEME_LOCATION_CLIENT_AREA)
+       if (location == THEME_LOCATION_CLIENT_AREA) {
                notify_motion_absolute(&input->base, time, x, y);
+               want_frame = true;
+       }
+
+       if (want_frame && input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
+               notify_pointer_frame(&input->base);
 }
 
 static void
@@ -1422,8 +1432,11 @@ input_handle_button(void *data, struct wl_pointer 
*pointer,
                location = THEME_LOCATION_CLIENT_AREA;
        }
 
-       if (location == THEME_LOCATION_CLIENT_AREA)
+       if (location == THEME_LOCATION_CLIENT_AREA) {
                notify_button(&input->base, time, button, state);
+               if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
+                       notify_pointer_frame(&input->base);
+       }
 }
 
 static void
@@ -1436,7 +1449,67 @@ input_handle_axis(void *data, struct wl_pointer *pointer,
        weston_event.axis = axis;
        weston_event.value = value;
 
+       if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL &&
+           input->vert.has_discrete) {
+               weston_event.has_discrete = true;
+               weston_event.discrete = input->vert.discrete;
+               input->vert.has_discrete = false;
+       } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL &&
+                  input->horiz.has_discrete) {
+               weston_event.has_discrete = true;
+               weston_event.discrete = input->horiz.discrete;
+               input->horiz.has_discrete = false;
+       }
+
        notify_axis(&input->base, time, &weston_event);
+
+       if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
+               notify_pointer_frame(&input->base);
+}
+
+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;
+       struct weston_pointer_axis_event weston_event;
+
+       weston_event.axis = axis;
+       weston_event.value = 0;
+
+       notify_axis(&input->base, time, &weston_event);
+}
+
+static void
+input_handle_axis_discrete(void *data, struct wl_pointer *pointer,
+                          uint32_t axis, int32_t discrete)
+{
+       struct wayland_input *input = data;
+
+       if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
+               input->vert.has_discrete = true;
+               input->vert.discrete = discrete;
+       } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
+               input->horiz.has_discrete = true;
+               input->horiz.discrete = discrete;
+       }
 }
 
 static const struct wl_pointer_listener pointer_listener = {
@@ -1445,6 +1518,10 @@ static const struct wl_pointer_listener pointer_listener 
= {
        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
@@ -1851,6 +1928,9 @@ display_add_seat(struct wayland_backend *b, uint32_t id, 
uint32_t available_vers
 
        input->parent.cursor.surface =
                wl_compositor_create_surface(b->parent.compositor);
+
+       input->vert.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
+       input->horiz.axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
 }
 
 static void
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 93018da..b70c119 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -1085,6 +1085,8 @@ x11_backend_deliver_button_event(struct x11_backend *b,
                 * steps. Therefore move the axis by some pixels every step. */
                if (state) {
                        weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE;
+                       weston_event.discrete = -1;
+                       weston_event.has_discrete = true;
                        weston_event.axis =
                                WL_POINTER_AXIS_VERTICAL_SCROLL;
                        notify_axis(&b->core_seat,
@@ -1095,6 +1097,8 @@ x11_backend_deliver_button_event(struct x11_backend *b,
        case 5:
                if (state) {
                        weston_event.value = DEFAULT_AXIS_STEP_DISTANCE;
+                       weston_event.discrete = 1;
+                       weston_event.has_discrete = true;
                        weston_event.axis =
                                WL_POINTER_AXIS_VERTICAL_SCROLL;
                        notify_axis(&b->core_seat,
@@ -1105,6 +1109,8 @@ x11_backend_deliver_button_event(struct x11_backend *b,
        case 6:
                if (state) {
                        weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE;
+                       weston_event.discrete = -1;
+                       weston_event.has_discrete = true;
                        weston_event.axis =
                                WL_POINTER_AXIS_HORIZONTAL_SCROLL;
                        notify_axis(&b->core_seat,
@@ -1115,6 +1121,8 @@ x11_backend_deliver_button_event(struct x11_backend *b,
        case 7:
                if (state) {
                        weston_event.value = DEFAULT_AXIS_STEP_DISTANCE;
+                       weston_event.discrete = 1;
+                       weston_event.has_discrete = true;
                        weston_event.axis =
                                WL_POINTER_AXIS_HORIZONTAL_SCROLL;
                        notify_axis(&b->core_seat,
@@ -1131,6 +1139,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
@@ -1162,6 +1171,7 @@ x11_backend_deliver_motion_event(struct x11_backend *b,
 
        notify_motion(&b->core_seat, weston_compositor_get_time(),
                      &motion_event);
+       notify_pointer_frame(&b->core_seat);
 
        b->prev_x = x;
        b->prev_y = y;
diff --git a/src/compositor.h b/src/compositor.h
index ddcafc6..5970e57 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -254,6 +254,8 @@ struct weston_pointer_motion_event {
 struct weston_pointer_axis_event {
        uint32_t axis;
        wl_fixed_t value;
+       bool has_discrete;
+       int32_t discrete;
 };
 
 struct weston_pointer_grab;
@@ -266,6 +268,8 @@ struct weston_pointer_grab_interface {
        void (*axis)(struct weston_pointer_grab *grab,
                     uint32_t time,
                     struct weston_pointer_axis_event *event);
+       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);
 };
 
@@ -404,6 +408,12 @@ weston_pointer_send_axis(struct weston_pointer *pointer,
                         uint32_t time,
                         struct weston_pointer_axis_event *event);
 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);
@@ -1143,6 +1153,12 @@ void
 notify_axis(struct weston_seat *seat, uint32_t time,
            struct weston_pointer_axis_event *event);
 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,
           enum weston_key_state_update update_state);
diff --git a/src/data-device.c b/src/data-device.c
index 4a1c1b8..545a895 100644
--- a/src/data-device.c
+++ b/src/data-device.c
@@ -417,6 +417,16 @@ drag_grab_axis(struct weston_pointer_grab *grab,
 }
 
 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 +443,8 @@ static const struct weston_pointer_grab_interface 
pointer_drag_grab_interface =
        drag_grab_motion,
        drag_grab_button,
        drag_grab_axis,
+       drag_grab_axis_source,
+       drag_grab_frame,
        drag_grab_cancel,
 };
 
diff --git a/src/input.c b/src/input.c
index 9382bb1..f321801 100644
--- a/src/input.c
+++ b/src/input.c
@@ -343,9 +343,51 @@ weston_pointer_send_axis(struct weston_pointer *pointer,
                return;
 
        resource_list = &pointer->focus_client->pointer_resources;
-       wl_resource_for_each(resource, resource_list)
-               wl_pointer_send_axis(resource, time,
-                                    event->axis, event->value);
+       wl_resource_for_each(resource, resource_list) {
+               if (event->has_discrete &&
+                   wl_resource_get_version(resource) >=
+                   WL_POINTER_AXIS_DISCRETE_SINCE_VERSION)
+                       wl_pointer_send_axis_discrete(resource, event->axis,
+                                                     event->discrete);
+
+               if (event->value)
+                       wl_pointer_send_axis(resource, time,
+                                            event->axis, event->value);
+               else if (wl_resource_get_version(resource) >=
+                        WL_POINTER_AXIS_STOP_SINCE_VERSION)
+                       wl_pointer_send_axis_stop(resource, time,
+                                                 event->axis);
+       }
+}
+
+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_client->pointer_resources;
+       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_client->pointer_resources;
+       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
@@ -357,6 +399,19 @@ default_grab_pointer_axis(struct weston_pointer_grab *grab,
 }
 
 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)
 {
 }
@@ -367,6 +422,8 @@ static const struct weston_pointer_grab_interface
        default_grab_pointer_motion,
        default_grab_pointer_button,
        default_grab_pointer_axis,
+       default_grab_pointer_axis_source,
+       default_grab_pointer_frame,
        default_grab_pointer_cancel,
 };
 
@@ -830,6 +887,7 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
                        wl_resource_for_each(resource, focus_resource_list) {
                                wl_pointer_send_leave(resource, serial,
                                                      surface_resource);
+                               wl_pointer_send_frame(resource);
                        }
                }
 
@@ -856,6 +914,7 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
                                              serial,
                                              view->surface->resource,
                                              sx, sy);
+                       wl_pointer_send_frame(resource);
                }
 
                pointer->focus_serial = serial;
@@ -1277,9 +1336,6 @@ notify_axis(struct weston_seat *seat, uint32_t time,
 
        weston_compositor_wake(compositor);
 
-       if (!event->value)
-               return;
-
        if (weston_compositor_run_axis_binding(compositor, pointer,
                                               time, event))
                return;
@@ -1287,6 +1343,28 @@ notify_axis(struct weston_seat *seat, uint32_t time,
        pointer->grab->interface->axis(pointer->grab, time, event);
 }
 
+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)
@@ -1979,6 +2057,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);
        }
 }
 
@@ -2557,7 +2636,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 9860d6e..99b2916 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)
 {
@@ -97,9 +97,11 @@ handle_pointer_motion(struct libinput_device 
*libinput_device,
        notify_motion(device->seat,
                      libinput_event_pointer_get_time(pointer_event),
                      &event);
+
+       return true;
 }
 
-static void
+static bool
 handle_pointer_motion_absolute(
        struct libinput_device *libinput_device,
        struct libinput_event_pointer *pointer_event)
@@ -112,7 +114,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;
@@ -127,9 +129,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)
 {
@@ -145,21 +149,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
@@ -178,48 +182,101 @@ 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;
+
+       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;
        struct weston_pointer_axis_event weston_event;
+       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;
+       }
+
+       notify_axis_source(device->seat, wl_axis_source);
+
+       if (has_vert) {
+               axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
+               vert_discrete = get_axis_discrete(pointer_event, axis);
+               vert = normalize_scroll(pointer_event, axis);
 
-       axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
-       if (libinput_event_pointer_has_axis(pointer_event, axis)) {
-               value = normalize_scroll(pointer_event, axis);
-               weston_event.value = wl_fixed_from_double(value);
                weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
+               weston_event.value = wl_fixed_from_double(vert);
+               weston_event.discrete = vert_discrete;
+               weston_event.has_discrete = (vert_discrete != 0);
+
                notify_axis(device->seat,
                            libinput_event_pointer_get_time(pointer_event),
                            &weston_event);
        }
 
-       axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
-       if (libinput_event_pointer_has_axis(pointer_event, axis)) {
-               value = normalize_scroll(pointer_event, axis);
-               weston_event.value = wl_fixed_from_double(value);
+       if (has_horiz) {
+               axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
+               horiz_discrete = get_axis_discrete(pointer_event, axis);
+               horiz = normalize_scroll(pointer_event, axis);
+
                weston_event.axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
+               weston_event.value = wl_fixed_from_double(horiz);
+               weston_event.discrete = horiz_discrete;
+               weston_event.has_discrete = (horiz_discrete != 0);
+
                notify_axis(device->seat,
                            libinput_event_pointer_get_time(pointer_event),
                            &weston_event);
        }
+
+       return true;
 }
 
 static void
@@ -296,7 +353,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:
@@ -304,21 +364,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,
@@ -342,6 +403,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/src/screen-share.c b/src/screen-share.c
index ab649e3..9b5154b 100644
--- a/src/screen-share.c
+++ b/src/screen-share.c
@@ -143,6 +143,7 @@ ss_seat_handle_motion(void *data, struct wl_pointer 
*pointer,
         * always receiving the input in the same coordinates as the output. */
 
        notify_motion_absolute(&seat->base, time, x, y);
+       notify_pointer_frame(&seat->base);
 }
 
 static void
@@ -153,6 +154,7 @@ ss_seat_handle_button(void *data, struct wl_pointer 
*pointer,
        struct ss_seat *seat = data;
 
        notify_button(&seat->base, time, button, state);
+       notify_pointer_frame(&seat->base);
 }
 
 static void
@@ -164,8 +166,10 @@ ss_seat_handle_axis(void *data, struct wl_pointer *pointer,
 
        weston_event.axis = axis;
        weston_event.value = value;
+       weston_event.has_discrete = false;
 
        notify_axis(&seat->base, time, &weston_event);
+       notify_pointer_frame(&seat->base);
 }
 
 static const struct wl_pointer_listener ss_seat_pointer_listener = {
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.5.0

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to