From d46586e383e0f15027b3bafebe3822fef4fe8ca0 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 28 Oct 2015 11:50:52 +0100 Subject: [PATCH] wayland: Implement wl_tablet_tool device event emission This takes care of the emission of motion/down/up/button, in addition to the extra distance/pressure/tilt axes. --- src/wayland/meta-wayland-tablet-tool.c | 289 +++++++++++++++++++++++++ src/wayland/meta-wayland-tablet-tool.h | 2 + 2 files changed, 291 insertions(+) diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c index 0d031566a..da17bd732 100644 --- a/src/wayland/meta-wayland-tablet-tool.c +++ b/src/wayland/meta-wayland-tablet-tool.c @@ -26,6 +26,7 @@ #include "config.h" #include +#include #include #include "tablet-unstable-v1-server-protocol.h" @@ -35,6 +36,15 @@ #include "meta-wayland-tablet-seat.h" #include "meta-wayland-tablet-tool.h" +#ifdef HAVE_NATIVE_BACKEND +#include "backends/native/meta-backend-native.h" +#endif + +#define TABLET_AXIS_MAX 65535 +#define DEGREES_PRECISION 100 /* wl_tablet_tool.tilt and .rotation define + * angles in hundreths of a degree + */ + static void unbind_resource (struct wl_resource *resource) { @@ -66,6 +76,45 @@ move_resources_for_client (struct wl_list *destination, } } +static uint32_t +input_device_get_capabilities (ClutterInputDevice *device) +{ + ClutterInputAxis axis; + guint32 capabilities = 0, i; + + for (i = 0; i < clutter_input_device_get_n_axes (device); i++) + { + axis = clutter_input_device_get_axis (device, i); + + switch (axis) + { + case CLUTTER_INPUT_AXIS_PRESSURE: + capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_PRESSURE; + break; + case CLUTTER_INPUT_AXIS_DISTANCE: + capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_DISTANCE; + break; + case CLUTTER_INPUT_AXIS_XTILT: + case CLUTTER_INPUT_AXIS_YTILT: + capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_TILT; + break; + case CLUTTER_INPUT_AXIS_ROTATION: + capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_ROTATION; + break; + case CLUTTER_INPUT_AXIS_WHEEL: + capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_WHEEL; + break; + case CLUTTER_INPUT_AXIS_SLIDER: + capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_SLIDER; + break; + default: + break; + } + } + + return capabilities; +} + static void broadcast_proximity_in (MetaWaylandTabletTool *tool) { @@ -338,6 +387,239 @@ repick_for_event (MetaWaylandTabletTool *tool, sync_focus_surface (tool, for_event); } +static void +meta_wayland_tablet_tool_get_relative_coordinates (MetaWaylandTabletTool *tool, + ClutterInputDevice *device, + MetaWaylandSurface *surface, + wl_fixed_t *sx, + wl_fixed_t *sy) +{ + float xf = 0.0f, yf = 0.0f; + ClutterPoint pos; + + clutter_input_device_get_coords (device, NULL, &pos); + clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)), + pos.x, pos.y, &xf, &yf); + + *sx = wl_fixed_from_double (xf) / surface->scale; + *sy = wl_fixed_from_double (yf) / surface->scale; +} + +static void +broadcast_motion (MetaWaylandTabletTool *tool, + const ClutterEvent *event) +{ + struct wl_resource *resource; + ClutterInputDevice *device; + wl_fixed_t sx, sy; + + device = clutter_event_get_source_device (event); + meta_wayland_tablet_tool_get_relative_coordinates (tool, device, + tool->focus_surface, + &sx, &sy); + + wl_resource_for_each (resource, &tool->focus_resource_list) + { + zwp_tablet_tool_v1_send_motion (resource, sx, sy); + } +} + +static void +broadcast_down (MetaWaylandTabletTool *tool, + const ClutterEvent *event) +{ + struct wl_resource *resource; + + tool->down_serial = wl_display_next_serial (tool->seat->manager->wl_display); + + wl_resource_for_each (resource, &tool->focus_resource_list) + { + zwp_tablet_tool_v1_send_down (resource, tool->down_serial); + } +} + +static void +broadcast_up (MetaWaylandTabletTool *tool, + const ClutterEvent *event) +{ + struct wl_resource *resource; + + wl_resource_for_each (resource, &tool->focus_resource_list) + { + zwp_tablet_tool_v1_send_up (resource); + } +} + +static void +broadcast_button (MetaWaylandTabletTool *tool, + const ClutterEvent *event) +{ + struct wl_resource *resource; + guint32 button; + + tool->button_serial = wl_display_next_serial (tool->seat->manager->wl_display); + +#ifdef HAVE_NATIVE_BACKEND + MetaBackend *backend = meta_get_backend (); + if (META_IS_BACKEND_NATIVE (backend)) + button = clutter_evdev_event_get_event_code (event); + else +#endif + { + /* We can't do much better here, there's several + * different BTN_ ranges to cover. + */ + button = event->button.button; + } + + + wl_resource_for_each (resource, &tool->focus_resource_list) + { + zwp_tablet_tool_v1_send_button (resource, tool->button_serial, button, + event->type == CLUTTER_BUTTON_PRESS ? + ZWP_TABLET_TOOL_V1_BUTTON_STATE_PRESSED : + ZWP_TABLET_TOOL_V1_BUTTON_STATE_RELEASED); + } +} + +static void +broadcast_axis (MetaWaylandTabletTool *tool, + const ClutterEvent *event, + ClutterInputAxis axis) +{ + struct wl_resource *resource; + ClutterInputDevice *source; + uint32_t value; + gdouble val; + + source = clutter_event_get_source_device (event); + + if (!clutter_input_device_get_axis_value (source, event->motion.axes, axis, &val)) + return; + + value = val * TABLET_AXIS_MAX; + + wl_resource_for_each (resource, &tool->focus_resource_list) + { + switch (axis) + { + case CLUTTER_INPUT_AXIS_PRESSURE: + zwp_tablet_tool_v1_send_pressure (resource, value); + break; + case CLUTTER_INPUT_AXIS_DISTANCE: + zwp_tablet_tool_v1_send_distance (resource, value); + break; + case CLUTTER_INPUT_AXIS_SLIDER: + zwp_tablet_tool_v1_send_slider (resource, value); + break; + default: + break; + } + } +} + +static void +broadcast_tilt (MetaWaylandTabletTool *tool, + const ClutterEvent *event) +{ + struct wl_resource *resource; + ClutterInputDevice *source; + gdouble xtilt, ytilt; + + source = clutter_event_get_source_device (event); + + if (!clutter_input_device_get_axis_value (source, event->motion.axes, + CLUTTER_INPUT_AXIS_XTILT, &xtilt) || + !clutter_input_device_get_axis_value (source, event->motion.axes, + CLUTTER_INPUT_AXIS_YTILT, &ytilt)) + return; + + wl_resource_for_each (resource, &tool->focus_resource_list) + { + zwp_tablet_tool_v1_send_tilt (resource, + (int32_t) (xtilt * DEGREES_PRECISION), + (int32_t) (ytilt * DEGREES_PRECISION)); + } +} + +static void +broadcast_rotation (MetaWaylandTabletTool *tool, + const ClutterEvent *event) +{ + struct wl_resource *resource; + ClutterInputDevice *source; + gdouble rotation; + + source = clutter_event_get_source_device (event); + + if (!clutter_input_device_get_axis_value (source, event->motion.axes, + CLUTTER_INPUT_AXIS_ROTATION, + &rotation)) + return; + + wl_resource_for_each (resource, &tool->focus_resource_list) + { + zwp_tablet_tool_v1_send_rotation (resource, + (int32_t) rotation * DEGREES_PRECISION); + } +} + +static void +broadcast_axes (MetaWaylandTabletTool *tool, + const ClutterEvent *event) +{ + ClutterInputDevice *device; + guint32 capabilities; + + if (!event->motion.axes) + return; + + device = clutter_event_get_source_device (event); + capabilities = input_device_get_capabilities (device); + + if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_PRESSURE)) + broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_PRESSURE); + if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_DISTANCE)) + broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_DISTANCE); + if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_TILT)) + broadcast_tilt (tool, event); + if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_ROTATION)) + broadcast_rotation (tool, event); + if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_SLIDER)) + broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_SLIDER); + + /* FIXME: Missing wp_tablet_tool.wheel */ +} + +static void +handle_motion_event (MetaWaylandTabletTool *tool, + const ClutterEvent *event) +{ + if (!tool->focus_surface) + return; + + broadcast_motion (tool, event); + broadcast_axes (tool, event); + broadcast_frame (tool, event); +} + +static void +handle_button_event (MetaWaylandTabletTool *tool, + const ClutterEvent *event) +{ + if (!tool->focus_surface) + return; + + if (event->type == CLUTTER_BUTTON_PRESS && event->button.button == 1) + broadcast_down (tool, event); + else if (event->type == CLUTTER_BUTTON_RELEASE && event->button.button == 1) + broadcast_up (tool, event); + else + broadcast_button (tool, event); + + broadcast_frame (tool, event); +} + void meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool, const ClutterEvent *event) @@ -377,6 +659,13 @@ meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool, case CLUTTER_PROXIMITY_OUT: meta_wayland_tablet_tool_set_focus (tool, NULL, event); break; + case CLUTTER_MOTION: + handle_motion_event (tool, event); + break; + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + handle_button_event (tool, event); + break; default: return CLUTTER_EVENT_PROPAGATE; } diff --git a/src/wayland/meta-wayland-tablet-tool.h b/src/wayland/meta-wayland-tablet-tool.h index 12510c4dc..fbbe85a7c 100644 --- a/src/wayland/meta-wayland-tablet-tool.h +++ b/src/wayland/meta-wayland-tablet-tool.h @@ -44,6 +44,8 @@ struct _MetaWaylandTabletTool guint32 pressed_buttons; guint32 proximity_serial; + guint32 down_serial; + guint32 button_serial; MetaWaylandTablet *current_tablet; };