Wayland: Translate tool axes in motion events

On wayland, such axes are per-tool, we must update device capabilities
on the fly as new tools enter proximity, first the slave device so
it matches the current tool, and then the master device so it looks
the same than the current slave device.
This commit is contained in:
Stephen Chandler Paul 2015-06-22 18:02:50 +02:00 committed by Carlos Garnacho
parent 72884a274c
commit 0f6be24e28

View File

@ -125,6 +125,9 @@ struct _GdkWaylandTabletData
GdkWaylandPointerData pointer_info;
GdkWaylandTabletToolData *current_tool;
gint axis_indices[GDK_AXIS_LAST];
gdouble *axes;
};
struct _GdkWaylandSeat
@ -2452,6 +2455,9 @@ _gdk_wayland_seat_remove_tablet (GdkWaylandSeat *seat,
if (tablet->pointer_info.focus)
g_object_unref (tablet->pointer_info.focus);
if (tablet->axes)
g_free (tablet->axes);
wl_surface_destroy (tablet->pointer_info.pointer_surface);
g_object_unref (tablet->master);
g_object_unref (tablet->stylus_device);
@ -2924,10 +2930,18 @@ gdk_wayland_tablet_flush_frame_event (GdkWaylandTabletData *tablet,
{
case GDK_MOTION_NOTIFY:
event->motion.time = time;
event->motion.axes =
g_memdup (tablet->axes,
sizeof (gdouble) *
gdk_device_get_n_axes (tablet->current_device));
break;
case GDK_BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
event->button.time = time;
event->button.axes =
g_memdup (tablet->axes,
sizeof (gdouble) *
gdk_device_get_n_axes (tablet->current_device));
break;
case GDK_PROXIMITY_IN:
case GDK_PROXIMITY_OUT:
@ -2963,6 +2977,89 @@ gdk_wayland_tablet_get_frame_event (GdkWaylandTabletData *tablet,
return tablet->pointer_info.frame.event;
}
static void
gdk_wayland_device_tablet_clone_tool_axes (GdkWaylandTabletData *tablet,
GdkDeviceTool *tool)
{
gint axis_pos;
g_object_freeze_notify (G_OBJECT (tablet->current_device));
_gdk_device_reset_axes (tablet->current_device);
_gdk_device_add_axis (tablet->current_device, GDK_NONE, GDK_AXIS_X, 0, 0, 0);
_gdk_device_add_axis (tablet->current_device, GDK_NONE, GDK_AXIS_Y, 0, 0, 0);
if (tool->tool_axes & (GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT))
{
axis_pos = _gdk_device_add_axis (tablet->current_device, GDK_NONE,
GDK_AXIS_XTILT, -9000, 9000, 0);
tablet->axis_indices[GDK_AXIS_XTILT] = axis_pos;
axis_pos = _gdk_device_add_axis (tablet->current_device, GDK_NONE,
GDK_AXIS_YTILT, -9000, 9000, 0);
tablet->axis_indices[GDK_AXIS_YTILT] = axis_pos;
}
if (tool->tool_axes & GDK_AXIS_FLAG_DISTANCE)
{
axis_pos = _gdk_device_add_axis (tablet->current_device, GDK_NONE,
GDK_AXIS_DISTANCE, 0, 65535, 0);
tablet->axis_indices[GDK_AXIS_DISTANCE] = axis_pos;
}
if (tool->tool_axes & GDK_AXIS_FLAG_PRESSURE)
{
axis_pos = _gdk_device_add_axis (tablet->current_device, GDK_NONE,
GDK_AXIS_PRESSURE, 0, 65535, 0);
tablet->axis_indices[GDK_AXIS_PRESSURE] = axis_pos;
}
if (tool->tool_axes & GDK_AXIS_FLAG_ROTATION)
{
axis_pos = _gdk_device_add_axis (tablet->current_device, GDK_NONE,
GDK_AXIS_ROTATION, 0, 36000, 0);
tablet->axis_indices[GDK_AXIS_ROTATION] = axis_pos;
}
if (tool->tool_axes & GDK_AXIS_FLAG_SLIDER)
{
axis_pos = _gdk_device_add_axis (tablet->current_device, GDK_NONE,
GDK_AXIS_SLIDER, -65535, 65535, 0);
tablet->axis_indices[GDK_AXIS_SLIDER] = axis_pos;
}
if (tablet->axes)
g_free(tablet->axes);
tablet->axes =
g_new0 (gdouble, gdk_device_get_n_axes (tablet->current_device));
g_object_thaw_notify (G_OBJECT (tablet->current_device));
}
static void
gdk_wayland_mimic_device_axes (GdkDevice *master,
GdkDevice *slave)
{
gdouble axis_min, axis_max, axis_resolution;
GdkAtom axis_label;
GdkAxisUse axis_use;
gint axis_count;
gint i;
g_object_freeze_notify (G_OBJECT (master));
_gdk_device_reset_axes (master);
axis_count = gdk_device_get_n_axes (slave);
for (i = 0; i < axis_count; i++)
{
_gdk_device_get_axis_info (slave, i, &axis_label, &axis_use, &axis_min,
&axis_max, &axis_resolution);
_gdk_device_add_axis (master, axis_label, axis_use, axis_min,
axis_max, axis_resolution);
}
g_object_thaw_notify (G_OBJECT (master));
}
static void
tablet_tool_handle_proximity_in (void *data,
struct zwp_tablet_tool_v1 *wp_tablet_tool,
@ -2993,6 +3090,8 @@ tablet_tool_handle_proximity_in (void *data,
tablet_select_device_for_tool (tablet, tool->tool);
gdk_device_update_tool (tablet->current_device, tool->tool);
gdk_wayland_device_tablet_clone_tool_axes (tablet, tool->tool);
gdk_wayland_mimic_device_axes (tablet->master, tablet->current_device);
event = gdk_wayland_tablet_get_frame_event (tablet, GDK_PROXIMITY_IN);
event->proximity.window = g_object_ref (tablet->pointer_info.focus);
@ -3071,6 +3170,105 @@ tablet_tool_handle_motion (void *data,
&event->motion.y_root);
}
static void
tablet_tool_handle_pressure (void *data,
struct zwp_tablet_tool_v1 *wp_tablet_tool,
uint32_t pressure)
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint axis_index = tablet->axis_indices[GDK_AXIS_PRESSURE];
_gdk_device_translate_axis (tablet->current_device, axis_index,
pressure, &tablet->axes[axis_index]);
GDK_NOTE (EVENTS,
g_message ("tablet tool %d pressure %d",
gdk_device_tool_get_tool_type (tool->tool), pressure));
}
static void
tablet_tool_handle_distance (void *data,
struct zwp_tablet_tool_v1 *wp_tablet_tool,
uint32_t distance)
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint axis_index = tablet->axis_indices[GDK_AXIS_DISTANCE];
_gdk_device_translate_axis (tablet->current_device, axis_index,
distance, &tablet->axes[axis_index]);
GDK_NOTE (EVENTS,
g_message ("tablet tool %d distance %d",
gdk_device_tool_get_tool_type (tool->tool), distance));
}
static void
tablet_tool_handle_tilt (void *data,
struct zwp_tablet_tool_v1 *wp_tablet_tool,
int32_t xtilt,
int32_t ytilt)
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint xtilt_axis_index = tablet->axis_indices[GDK_AXIS_XTILT];
gint ytilt_axis_index = tablet->axis_indices[GDK_AXIS_YTILT];
_gdk_device_translate_axis (tablet->current_device, xtilt_axis_index,
xtilt, &tablet->axes[xtilt_axis_index]);
_gdk_device_translate_axis (tablet->current_device, ytilt_axis_index,
ytilt, &tablet->axes[ytilt_axis_index]);
GDK_NOTE (EVENTS,
g_message ("tablet tool %d tilt %d/%d",
gdk_device_tool_get_tool_type (tool->tool),
xtilt, ytilt));
}
static void
tablet_tool_handle_rotation (void *data,
struct zwp_tablet_tool_v1 *wp_tablet_tool,
int32_t degrees)
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint axis_index = tablet->axis_indices[GDK_AXIS_ROTATION];
_gdk_device_translate_axis (tablet->current_device, axis_index,
degrees, &tablet->axes[axis_index]);
GDK_NOTE (EVENTS,
g_message ("tablet tool %d rotation %d",
gdk_device_tool_get_tool_type (tool->tool), degrees));
}
static void
tablet_tool_handle_slider (void *data,
struct zwp_tablet_tool_v1 *wp_tablet_tool,
int32_t position)
{
GdkWaylandTabletToolData *tool = data;
GdkWaylandTabletData *tablet = tool->current_tablet;
gint axis_index = tablet->axis_indices[GDK_AXIS_SLIDER];
_gdk_device_translate_axis (tablet->current_device, axis_index,
position, &tablet->axes[axis_index]);
GDK_NOTE (EVENTS,
g_message ("tablet tool %d slider %d",
gdk_device_tool_get_tool_type (tool->tool), position));
}
static void
tablet_tool_handle_wheel (void *data,
struct zwp_tablet_tool_v1 *wp_tablet_tool,
int32_t degrees,
int32_t clicks)
{
/* FIXME: Handle wheel */
}
static void
tablet_tool_handle_frame (void *data,
struct zwp_tablet_tool_v1 *wl_tablet_tool,
@ -3112,12 +3310,12 @@ static const struct zwp_tablet_tool_v1_listener tablet_tool_listener = {
tablet_handler_placeholder, /* down */
tablet_handler_placeholder, /* up */
tablet_tool_handle_motion,
tablet_handler_placeholder, /* pressure */
tablet_handler_placeholder, /* distance */
tablet_handler_placeholder, /* tilt */
tablet_handler_placeholder, /* rotation */
tablet_handler_placeholder, /* slider */
tablet_handler_placeholder, /* wheel */
tablet_tool_handle_pressure,
tablet_tool_handle_distance,
tablet_tool_handle_tilt,
tablet_tool_handle_rotation,
tablet_tool_handle_slider,
tablet_tool_handle_wheel,
tablet_handler_placeholder, /* button_state */
tablet_tool_handle_frame,
};