Signed-off-by: Peter Hutterer <peter.hutte...@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.

 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

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

Reply via email to