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