Discussion:
[PATCH wayland-protocols] Add the tablet protocol
(too old to reply)
Peter Hutterer
2015-11-06 04:24:44 UTC
Permalink
Signed-off-by: Peter Hutterer <***@who-t.net>
---
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.

Makefile.am | 1 +
unstable/tablet/README | 4 +
unstable/tablet/tablet-unstable-v1.xml | 588 +++++++++++++++++++++++++++++++++
3 files changed, 593 insertions(+)
create mode 100644 unstable/tablet/README
create mode 100644 unstable/tablet/tablet-unstable-v1.xml

diff --git a/Makefile.am b/Makefile.am
index 4bcab32..588cb2c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,6 +6,7 @@ protocols = \
unstable/text-input/text-input-unstable-v1.xml \
unstable/input-method/input-method-unstable-v1.xml \
unstable/xdg-shell/xdg-shell-unstable-v5.xml \
+ unstable/tablet/tablet-unstable-v1.xml \
$(NULL)

nobase_dist_pkgdata_DATA = $(protocols)
diff --git a/unstable/tablet/README b/unstable/tablet/README
new file mode 100644
index 0000000..7ba8e77
--- /dev/null
+++ b/unstable/tablet/README
@@ -0,0 +1,4 @@
+Tablet protocol
+
+Maintainers:
+Peter Hutterer <***@who-t.net>
diff --git a/unstable/tablet/tablet-unstable-v1.xml b/unstable/tablet/tablet-unstable-v1.xml
new file mode 100644
index 0000000..b07eccb
--- /dev/null
+++ b/unstable/tablet/tablet-unstable-v1.xml
@@ -0,0 +1,588 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland_tablet_unstable_v1">
+ <description summary="Wayland protocol for graphics tablets">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
+
+ The wp_tablet_seat sends a "tablet added" for each tablet connected.
+ That event is followed by descriptive events about the hardware;
+ currently that includes events for name, vid/pid and
+ internal/external/display type, and a wp_tablet.path event that
+ describes a local path. This path can be used to uniquely identify a
+ tablet, or get more information through libwacom. Emulated or nested
+ tablets can skip any of those, e.g. a virtual tablet may not have a
+ vid/pid. The sequence of descriptive events is terminated by a
+ wp_tablet.done event to signal that a client may now finalize any
+ initialization for that tablet.
+
+ Events from tablets require a tool in proximity. Tools are also managed
+ by the tablet seat, a "tool added" is sent whenever a tool is new to
+ the compositor. That event is followed by a number of descriptive events
+ about the hardware; currently that includes capabilities, serial id,
+ hardware serial and tool type. Similar to the tablet interface, a
+ wp_tablet_tool.done event is sent to terminate that initial sequence.
+
+ Any event from a tool happens on the wp_tablet_tool interface. When the
+ tool gets into proximity of the tablet, a proximity_in event is sent on
+ the wp_tablet_tool interface, listing the tablet and the surface. That
+ event is followed by a motion event with the coordinates. After that,
+ it's the usual motion, axis, button, etc. events.
+ The protocol's serialisation means events are grouped by by
+ wp_tablet_tool.frame events.
+
+ Two special events (that don't exist in X) are down and up. They signal
+ "tip touching the surface". For tablets without real proximity
+ detection, the sequence is: proximity_in, motion, down, frame.
+
+ When the tool leaves proximity, a proximity_out event is sent, followed
+ by button release events for any button still down. This signals to
+ the client that the buttons were held when the tool left proximity.
+ Those events are all sent within the same frame.
+
+ If the tool moves out of the surface but stays in proximity (i.e.
+ between windows), compositor-specific grab policies apply. This usually
+ means that the proximity-out is delayed until all buttons are released.
+
+ Moving a tool physically from one tablet to the other has no real effect
+ on the protocol, since we already have the tool object from the "tool
+ added" event. All the information is already there and the proximity_in
+ is all a client needs to reconstruct what happened.
+
+ Any extra axis is normalized, i.e. the client knows the range as
+ specified in the protocol (e.g. [0, 65535]), the granularity however is
+ unknown. The current axes are pressure, tilt (both x/y required) and
+ distance, the most common set.
+
+ Since tablets work independently of the pointer controlled by the mouse,
+ the focus handling is independent too and controlled by proximity.
+ The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
+ This cursor surface may be the same as the mouse cursor, and it may be
+ the same across tools but it is possible to be more fine-grained. For
+ example, a client may set different cursors for the pen and eraser.
+
+ Tools are generally independent of tablets and it is
+ compositor-specific policy when a tool can removed. Common approaches
+ will likely include some form of removing a tool when all tablets the
+ tool was used on is removed.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+ </description>
+ <copyright>
+ Copyright 2014 © Stephen "Lyude" Chandler Paul
+ Copyright 2015 © Red Hat, Inc.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ </copyright>
+ <interface name="zwp_tablet_manager1" version="1">
+ <description summary="controller object for graphic tablet devices">
+ An object that provides access to the graphics tablets available on this
+ system. Any tablet is associated with a seat, to get access to the
+ actual tablets, use wp_tablet_manager.get_tablet_seat.
+ </description>
+
+ <request name="get_tablet_seat">
+ <description summary="get the tablet seat">
+ Get the wp_tablet_seat object for the given seat. This object
+ provides access to all graphics tablets in this seat.
+ </description>
+ <arg name="tablet_seat" type="new_id" interface="zwp_tablet_seat1"/>
+ <arg name="seat" type="object" interface="wl_seat" summary="The wl_seat object to retrieve the tablets for" />
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet manager object">
+ This destroys the resources associated with the tablet manager.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="zwp_tablet_seat1" version="1">
+ <description summary="controller object for graphic tablet devices of a seat">
+ An object that provides access to the graphics tablets available on this
+ seat. After binding to this interface, the compositor sends a set of
+ wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet seat object">
+ This destroys the resources associated with the tablet seat.
+ </description>
+ </request>
+
+ <event name="tablet_added">
+ <description summary="new device notification">
+ This event is sent whenever a new tablet becomes available on this
+ seat. This event only provides the object id of the tablet, any
+ static information about the tablet (device name, vid/pid, etc.) is
+ sent through the wp_tablet interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet1" summary="the newly added graphics tablet"/>
+ </event>
+
+ <event name="tool_added">
+ <description summary="a new tool has been used with a tablet">
+ This event is sent whenever a tool that has not previously been used
+ with a tablet comes into use. This event only provides the object id
+ of the tool, any static information about the tool (capabilities,
+ type, et.c) is sent through the wp_tablet_tool interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet_tool1" summary="the newly added tablet tool"/>
+ </event>
+ </interface>
+
+ <interface name="zwp_tablet_tool1" version="1">
+ <description summary="a physical tablet tool">
+ An unique object that represents a physical tool that has been, or is
+ currently in use with a tablet in this seat. Each wp_tablet_tool
+ object stays valid until the client destroys it; the compositor
+ reuses the wp_tablet_tool object to indicate that the object's
+ respective physical tool has come into proximity of a tablet again.
+ A client must not call wp_tablet_tool.destroy until it receives a
+ wp_tablet_tool.release event.
+
+ A wp_tablet_tool object's uniqueness depends on the tablet's ability
+ to report serial numbers. If the tablet doesn't support this
+ capability, then the tool cannot be guaranteed to be unique.
+
+ A tablet tool has a number of static characteristics, e.g. tool type,
+ serial_id and capabilities. These capabilities are sent in an event
+ sequence after the wp_tablet_seat.tool_added event before any actual
+ events from this tool. This initial event sequence is terminated by a
+ wp_tablet_tool.done event.
+
+ Tablet tool events are grouped by wp_tablet_tool.frame events.
+ Any events received before a wp_tablet_tool.frame event should be
+ considered part of the same hardware state change.
+ </description>
+
+ <request name="set_cursor">
+ <description summary="set the tablet tool's surface">
+ Sets the surface of the cursor used for this tool on the given
+ tablet. The surface is only shown when this tool is in proximity of
+ this tablet. If the surface is NULL, the pointer image is hidden
+ completely.
+
+ The parameters hotspot_x and hotspot_y define the position of the
+ pointer surface relative to the pointer location. Its top-left corner
+ is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+ coordinates of the pointer location, in surface local coordinates.
+
+ On surface.attach requests to the pointer surface, hotspot_x and
+ hotspot_y are decremented by the x and y parameters passed to the
+ request. Attach must be confirmed by wl_surface.commit as usual.
+
+ The hotspot can also be updated by passing the currently set pointer
+ surface to this request with new values for hotspot_x and hotspot_y.
+
+ The current and pending input regions of the wl_surface are cleared,
+ and wl_surface.set_input_region is ignored until the wl_surface is no
+ longer used as the cursor. When the use as a cursor ends, the current
+ and pending input regions become undefined, and the wl_surface is
+ unmapped.
+
+ This request gives the surface the role of a cursor. The role
+ assigned by this request is the same as assigned by
+ wl_pointer.set_cursor meaning the same surface can be
+ used both as a wl_pointer cursor and a wp_tablet cursor. If the
+ surface already has another role, it raises a protocol error
+ The surface may be used on multiple tablets and across multiple
+ seats.
+ </description>
+ <arg name="serial" type="uint" summary="serial of the enter event"/>
+ <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+ <arg name="hotspot_x" type="int" summary="x coordinate in surface-relative coordinates"/>
+ <arg name="hotspot_y" type="int" summary="y coordinate in surface-relative coordinates"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tool object">
+ This destroys the client's resource for this tool object.
+
+ A client must not issue this request until it receives a
+ wp_tablet_tool.remove event.
+ </description>
+ </request>
+
+ <enum name="type">
+ <description summary="a physical tool type">
+ Describes the physical type of a tool. The physical type of a tool
+ generally defines its base usage.
+
+ The mouse tool represents a mouse-shaped tool that is not a relative
+ device but bound to the tablet's surface, providing absolute
+ coordinates.
+
+ The lens tool is a mouse-shaped tool with an attached lens to
+ provide precision focus.
+ </description>
+ <entry name="pen" value="0x140" summary="Pen"/>
+ <entry name="eraser" value="0x141" summary="Eraser"/>
+ <entry name="brush" value="0x142" summary="Brush"/>
+ <entry name="pencil" value="0x143" summary="Pencil"/>
+ <entry name="airbrush" value="0x144" summary="Airbrush"/>
+ <entry name="finger" value="0x145" summary="Finger"/>
+ <entry name="mouse" value="0x146" summary="Mouse"/>
+ <entry name="lens" value="0x147" summary="Lens"/>
+ </enum>
+
+ <event name="type">
+ <description summary="tool type">
+ The tool type is the high-level type of the tool and usually decides
+ the interaction expected from this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="tool_type" type="uint" summary="the physical tool type"/>
+ </event>
+
+ <event name="serial_id">
+ <description summary="unique serial number of the tool">
+ If the tool can be identified by a unique 64-bit serial number, this
+ event notifies the client of the serial number.
+
+ If multiple tablets are available in the same seat and the tool is
+ uniquely identifiable by the serial number, that tool may move
+ between tablets.
+
+ Otherwise, if the tool has no serial number and this event is
+ missing, the tool is tied to the tablet it first comes into
+ proximity with. Even if the physical tool is used on multiple
+ tablets, separate wp_tablet_tool objects will be created, one per
+ tablet.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="serial_id_msb" type="uint" summary="the unique serial number of the tool, most significant bits"/>
+ <arg name="serial_id_lsb" type="uint" summary="the unique serial number of the tool, least significant bits"/>
+ </event>
+
+ <enum name="hardware_id_format">
+ <description summary="the hardware id format">
+ Specifies the format of the hardware id in the
+ wp_tablet_tool.hardware_id event.
+
+ A wacom_stylus_id format indicates a hardware id as the id used by
+ graphics tablet made by Wacom Inc. For example, on Wacom tablets the
+ hardware id of a Grip Pen (a stylus) is 0x802.
+ </description>
+ <entry name="wacom_stylus_id" value="0" />
+ </enum>
+
+ <event name="hardware_id">
+ <description summary="hardware id notification">
+ This event notifies the client of a hardware id available on this tool.
+
+ The hardware id is a device-specific 64-bit id that provides extra
+ information about the tool in use, beyond the wl_tool.type
+ enumeration. The format of the id is device-specific.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="format" type="uint" summary="the type of the id" />
+ <arg name="hardware_id_msb" type="uint" summary="the hardware id, most significant bits"/>
+ <arg name="hardware_id_lsb" type="uint" summary="the hardware id, least significant bits"/>
+ </event>
+
+
+ <enum name="capability">
+ <description summary="capability flags for a tool">
+ Describes extra capabilities on a tablet.
+
+ Any tool must provide x and y values, extra axes are
+ device-specific.
+ </description>
+ <entry name="tilt" value="1" summary="Tilt axes"/>
+ <entry name="pressure" value="2" summary="Pressure axis"/>
+ <entry name="distance" value="3" summary="Distance axis"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="tool capability notification">
+ This event notifies the client of any capabilities of this tool,
+ beyond the main set of x/y axes and tip up/down detection.
+
+ One event is sent for each extra capability available on this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="capability" type="uint" summary="the capability"/>
+ </event>
+
+ <event name="done">
+ <description summary="tool description events sequence complete">
+ This event signals the end of the initial burst of descriptive
+ events. A client may consider the static description of the tool to
+ be complete and finalize initialization of the tool.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tool removed">
+ This event is sent when the tool is removed from the system. The client
+ should not expect the resource it currently has associated with the
+ tool to be used again if the tool comes back into proximity later.
+
+ It is compositor-dependent when a tool is removed. Some tools are
+ associated with a single tablet only and may get removed when the
+ respective tablet is removed. Other tools may be used on multiple
+ tablets and removing a tablet may not remove this tool.
+
+ When this event is received, the client must wp_tablet_tool.destroy
+ the object.
+ </description>
+ </event>
+
+ <event name="proximity_in">
+ <description summary="proximity in event">
+ Notification that this tool is focused on a certain surface.
+
+ This event can be received when the tool has moved from one surface to
+ another, or when the tool has come back into proximity above the
+ surface.
+
+ Any button events sent within the same wp_tablet.frame as a
+ proximity_in event indicate the button state of the tool at the time
+ of proximity in.
+ </description>
+ <arg name="serial" type="uint"/>
+ <arg name="tablet" type="object" interface="zwp_tablet1" summary="The tablet the tool is in proximity of"/>
+ <arg name="surface" type="object" interface="wl_surface" summary="The current surface the tablet tool is over"/>
+ </event>
+
+ <event name="proximity_out">
+ <description summary="proximity out event">
+ Notification that this tool has either left proximity, or is no
+ longer focused on a certain surface.
+
+ When the tablet tool leaves proximity of the tablet, button release
+ events are sent for each button that was held down at the time of
+ leaving proximity. These events are sent in the same wp_tablet.frame
+ of the proximity_out event.
+
+ If the tool stays within proximity of the tablet, but the focus
+ changes from one surface to another, a button release event may not
+ be sent until the button is actually released or the tool leaves the
+ proximity of the tablet.
+ </description>
+ </event>
+
+ <event name="down">
+ <description summary="tablet tool is making contact">
+ Sent whenever the tablet tool comes in contact with the surface of the
+ tablet. If the tablet tool moves out of a region while in contact with
+ the surface of the tablet, the client owning said region will receive a
+ wp_tablet::up event, followed by a wp_tablet::proximity_out event and a
+ wp_tablet::frame event.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
+
+ <event name="up">
+ <description summary="tablet tool is no longer making contact">
+ Sent whenever the tablet tool stops making contact with the surface of
+ the tablet, or when the tablet tool moves off of a surface while it was
+ making contact with the tablet's surface.
+ </description>
+ </event>
+
+ <event name="motion">
+ <description summary="motion event">
+ Sent whenever a tablet tool moves.
+ </description>
+ <arg name="x" type="fixed" summary="surface-relative x coordinate"/>
+ <arg name="y" type="fixed" summary="surface-relative y coordinate"/>
+ </event>
+
+ <event name="pressure">
+ <description summary="pressure change event">
+ Sent whenever the pressure axis on a tool changes. The value of this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="pressure" type="uint" summary="The current pressure value"/>
+ </event>
+
+ <event name="distance">
+ <description summary="distance change event">
+ Sent whenever the distance axis on a tool changes. The value of this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="distance" type="uint" summary="The current distance value"/>
+ </event>
+
+ <event name="tilt">
+ <description summary="tilt change event">
+ Sent whenever one or both of the tilt axes on a tool change. Each tilt
+ value is normalized between -65535 and 65535.
+ </description>
+ <arg name="tilt_x" type="int" summary="The current value of the X tilt axis"/>
+ <arg name="tilt_y" type="int" summary="The current value of the Y tilt axis"/>
+ </event>
+
+ <enum name="button_state">
+ <description summary="physical button state">
+ Describes the physical state of a button which provoked the button event
+ </description>
+ <entry name="released" value="0" summary="button is not pressed"/>
+ <entry name="pressed" value="1" summary="button is pressed"/>
+ </enum>
+
+ <event name="button">
+ <description summary="button event">
+ Sent whenever a button on the stylus is pressed or released.
+ </description>
+
+ <arg name="serial" type="uint"/>
+ <arg name="button" type="uint" summary="The button whose state has changed"/>
+ <arg name="state" type="uint" summary="Whether the button was pressed or released"/>
+ </event>
+
+ <event name="frame">
+ <description summary="frame event">
+ Marks the end of a series of axis and/or button updates from the
+ tablet. The wayland protocol requires axis updates to be sent
+ sequentially, however all events within a frame should be considered
+ one hardware event.
+ </description>
+ <arg name="time" type="uint" summary="The time of the event with millisecond granularity"/>
+ </event>
+
+ <enum name="error">
+ <entry name="role" value="0" summary="given wl_surface has another role"/>
+ </enum>
+ </interface>
+
+ <interface name="zwp_tablet1" version="1">
+ <description summary="graphics tablet device">
+ The wp_tablet interface represents one graphics tablet device. The
+ tablet interface itself does not generate events, all events are
+ generated by wp_tablet_tool objects when in proximity above a tablet.
+
+ A tablet has a number of static characteristics, e.g. device name and
+ pid/vid. These capabilities are sent in an event sequence after the
+ wp_tablet_seat.tablet_added event. This initial event sequence is
+ terminated by a wp_tablet.done event.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tablet object">
+ This destroys the client's resource for this tablet object.
+
+ A client must not issue this request until it receives a
+ wp_tablet.remove event.
+ </description>
+ </request>
+
+ <event name="name">
+ <description summary="tablet device name">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="name" type="string" summary="the device name"/>
+ </event>
+
+ <event name="id">
+ <description summary="tablet device vid/pid">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="vid" type="uint" summary="vendor id"/>
+ <arg name="pid" type="uint" summary="product id"/>
+ </event>
+
+ <enum name="type">
+ <description summary="tablet type">
+ Describes the type of tablet
+ </description>
+
+ <entry name="external" value="0" summary="The tablet is an external tablet, such as an Intuos"/>
+ <entry name="internal" value="1" summary="The tablet is a built-in tablet, usually in a laptop"/>
+ <entry name="display" value="2" summary="The tablet is a display tablet, such as a Cintiq"/>
+ </enum>
+
+ <event name="type">
+ <description summary="the tablet type">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="type" type="uint" summary="the tablet type (internal, external, ...)"/>
+ </event>
+
+ <event name="path">
+ <description summary="path to the device">
+ A system-specific device path that indicates which device is behind
+ this wp_tablet. This information may be used to gather additional
+ information about the device, e.g. through libwacom.
+
+ A device may have more than one device path, if so, multiple
+ wp_tablet.path events are sent. A device may be emulated and not
+ have a device path, in that case this event will not be sent.
+
+ The format of the path is unspecified, it may be a device node, a
+ sysfs path, or some other identifier. It is up to the client to
+ identify the string provided.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="path" type="string" summary="path to local device"/>
+ </event>
+
+ <event name="done">
+ <description summary="tablet description events sequence complete">
+ This event is sent immediately to signal the end of the initial
+ burst of descriptive events. A client may consider the static
+ description of the tablet to be complete and finalize initialization
+ of the tablet.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tablet removed event">
+ Sent when the tablet has been removed from the system. When a tablet
+ is removed, some tools may be removed.
+
+ When this event is received, the client must wp_tablet.destroy
+ the object.
+ </description>
+ </event>
+ </interface>
+</protocol>
--
2.4.3
Peter Hutterer
2015-11-06 04:31:08 UTC
Permalink
This set adds support for graphics tablets to weston. It's not fully
complete, there are a couple of fixmes in it but the patchset is getting a
bit unwieldly. And there are some discussions on how to do things anyway.

Note: This needs the tablet-support branch from libinput to work. And it is
on top of Jonas's wip/wayland-protocols github branch (ff0452cea150c).

Tablet events are sent serially, terminated by a frame event. A toolkit
should accumulate them and then pass them on as one struct to the client. We
don't do that atm, it may be beyond libtoytoolkit's scope to really
integrate this properly.

The tablet has a separate cursor. That's a conscious decision since the
focus handling on tablets closer to an absolute touch screen than a mouse,
but unlike touch you usually want a cursor shape to indicate the precise
position.

The rest is fairly straightforward, though as said above, some details are
missing. Implementing this also showed that libinput needs a few extra
things added to it.

Cheers,
Peter
Peter Hutterer
2015-11-06 04:31:09 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Introduces two new structs, weston_tablet and weston_tablet_tool with the
respective information as it's used on the protocol.

Note that tools are independent of tablets, many tools can be used across
multiple tablets.

The nesting on the protocol level requires a global tablet manager, a tablet
seat nested into weston_seat. The list of tablets and tools are also part of
the weston_seat.

Most functions are stubs except for the actual tablet and tablet tool
creation and removal.

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
Makefile.am | 13 +-
src/compositor.c | 1 +
src/compositor.h | 99 +++++++++++++
src/input.c | 390 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/libinput-device.c | 205 ++++++++++++++++++++++++++
src/libinput-device.h | 4 +-
6 files changed, 708 insertions(+), 4 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index e7feebd..4f2110d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -126,7 +126,9 @@ nodist_weston_SOURCES = \
protocol/scaler-protocol.c \
protocol/scaler-server-protocol.h \
protocol/linux-dmabuf-unstable-v1-protocol.c \
- protocol/linux-dmabuf-unstable-v1-server-protocol.h
+ protocol/linux-dmabuf-unstable-v1-server-protocol.h \
+ protocol/tablet-unstable-v1-protocol.c \
+ protocol/tablet-unstable-v1-server-protocol.h

BUILT_SOURCES += $(nodist_weston_SOURCES)

@@ -555,7 +557,9 @@ nodist_libtoytoolkit_la_SOURCES = \
protocol/xdg-shell-unstable-v5-protocol.c \
protocol/xdg-shell-unstable-v5-client-protocol.h \
protocol/ivi-application-protocol.c \
- protocol/ivi-application-client-protocol.h
+ protocol/ivi-application-client-protocol.h \
+ protocol/tablet-unstable-v1-protocol.c \
+ protocol/tablet-unstable-v1-client-protocol.h

BUILT_SOURCES += $(nodist_libtoytoolkit_la_SOURCES)

@@ -764,7 +768,10 @@ BUILT_SOURCES += \
protocol/ivi-hmi-controller-protocol.c \
protocol/ivi-hmi-controller-client-protocol.h \
protocol/ivi-application-protocol.c \
- protocol/ivi-application-client-protocol.h
+ protocol/ivi-application-client-protocol.h \
+ protocol/tablet-unstable-v1-protocol.c \
+ protocol/tablet-unstable-v1-client-protocol.h
+

westondatadir = $(datadir)/weston
dist_westondata_DATA = \
diff --git a/src/compositor.c b/src/compositor.c
index 80cd983..8eadf8c 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -4518,6 +4518,7 @@ weston_compositor_create(struct wl_display *display, void *user_data)
wl_list_init(&ec->touch_binding_list);
wl_list_init(&ec->axis_binding_list);
wl_list_init(&ec->debug_binding_list);
+ wl_list_init(&ec->tablet_manager_resource_list);

weston_plane_init(&ec->primary_plane, ec, 0, 0);
weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);
diff --git a/src/compositor.h b/src/compositor.h
index f3e0075..50c7034 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -38,6 +38,7 @@ extern "C" {

#define WL_HIDE_DEPRECATED
#include <wayland-server.h>
+#include <tablet-unstable-v1-server-protocol.h>

#include "version.h"
#include "matrix.h"
@@ -366,6 +367,35 @@ struct weston_touch {
uint32_t grab_time;
};

+struct weston_tablet_tool {
+ struct weston_seat *seat;
+ enum zwp_tablet_tool1_type type;
+
+ struct wl_list resource_list;
+
+ struct wl_list link;
+
+ uint64_t serial;
+ uint64_t hwid;
+ uint32_t capabilities;
+};
+
+struct weston_tablet {
+ struct weston_seat *seat;
+ struct evdev_device *device;
+
+ struct wl_list resource_list;
+
+ struct wl_list link;
+
+ char *name;
+ enum zwp_tablet1_type type;
+ uint32_t vid;
+ uint32_t pid;
+ const char *path;
+ struct weston_output *output;
+};
+
struct weston_pointer *
weston_pointer_create(struct weston_seat *seat);
void
@@ -427,6 +457,16 @@ weston_touch_start_grab(struct weston_touch *device,
void
weston_touch_end_grab(struct weston_touch *touch);

+struct weston_tablet *
+weston_tablet_create(void);
+void
+weston_tablet_destroy(struct weston_tablet *tablet);
+
+struct weston_tablet_tool *
+weston_tablet_tool_create(void);
+void
+weston_tablet_tool_destroy(struct weston_tablet_tool *tool);
+
void
wl_data_device_set_keyboard_focus(struct weston_seat *seat);

@@ -513,6 +553,8 @@ struct weston_seat {
struct weston_pointer *pointer_state;
struct weston_keyboard *keyboard_state;
struct weston_touch *touch_state;
+ struct wl_list tablet_list;
+ struct wl_list tablet_tool_list;
int pointer_device_count;
int keyboard_device_count;
int touch_device_count;
@@ -539,6 +581,8 @@ struct weston_seat {
uint32_t slot_map;
struct input_method *input_method;
char *seat_name;
+
+ struct wl_list tablet_seat_resource_list;
};

enum {
@@ -736,6 +780,9 @@ struct weston_compositor {

void *user_data;
void (*exit)(struct weston_compositor *c);
+
+ struct wl_global *tablet_manager;
+ struct wl_list tablet_manager_resource_list;
};

struct weston_buffer {
@@ -1136,6 +1183,47 @@ void
notify_touch_frame(struct weston_seat *seat);

void
+notify_tablet_added(struct weston_tablet *tablet);
+
+void
+notify_tablet_tool_added(struct weston_tablet_tool *tool);
+
+void
+notify_tablet_tool_proximity_in(struct weston_tablet_tool *tool,
+ uint32_t time,
+ struct weston_tablet *tablet);
+void
+notify_tablet_tool_proximity_out(struct weston_tablet_tool *tool,
+ uint32_t time);
+void
+notify_tablet_tool_motion(struct weston_tablet_tool *tool,
+ uint32_t time,
+ wl_fixed_t x, wl_fixed_t y);
+void
+notify_tablet_tool_pressure(struct weston_tablet_tool *tool,
+ uint32_t time, uint32_t pressure);
+void
+notify_tablet_tool_distance(struct weston_tablet_tool *tool,
+ uint32_t time, uint32_t distance);
+void
+notify_tablet_tool_tilt(struct weston_tablet_tool *tool,
+ uint32_t time, int32_t tilt_x, int32_t tilt_y);
+void
+notify_tablet_tool_button(struct weston_tablet_tool *tool,
+ uint32_t time,
+ uint32_t button,
+ enum zwp_tablet_tool1_button_state state);
+void
+notify_tablet_tool_up(struct weston_tablet_tool *tool,
+ uint32_t time);
+void
+notify_tablet_tool_down(struct weston_tablet_tool *tool,
+ uint32_t time);
+void
+notify_tablet_tool_frame(struct weston_tablet_tool *tool,
+ uint32_t time);
+
+void
weston_layer_entry_insert(struct weston_layer_entry *list,
struct weston_layer_entry *entry);
void
@@ -1452,6 +1540,14 @@ void
weston_seat_init_touch(struct weston_seat *seat);
void
weston_seat_release_touch(struct weston_seat *seat);
+struct weston_tablet *
+weston_seat_add_tablet(struct weston_seat *seat);
+struct weston_tablet_tool *
+weston_seat_add_tablet_tool(struct weston_seat *seat);
+void
+weston_seat_release_tablet_tool(struct weston_tablet_tool *tablet_tool);
+void
+weston_seat_release_tablet(struct weston_tablet *tablet);
void
weston_seat_repick(struct weston_seat *seat);
void
@@ -1465,6 +1561,9 @@ weston_compositor_xkb_init(struct weston_compositor *ec,
void
weston_compositor_xkb_destroy(struct weston_compositor *ec);

+void
+weston_tablet_manager_init(struct weston_compositor *ec);
+
/* String literal of spaces, the same width as the timestamp. */
#define STAMP_SPACE " "

diff --git a/src/input.c b/src/input.c
index 09d12de..8814d34 100644
--- a/src/input.c
+++ b/src/input.c
@@ -643,6 +643,60 @@ weston_touch_destroy(struct weston_touch *touch)
free(touch);
}

+WL_EXPORT struct weston_tablet *
+weston_tablet_create(void)
+{
+ struct weston_tablet *tablet;
+
+ tablet = zalloc(sizeof *tablet);
+ if (tablet == NULL)
+ return NULL;
+
+ wl_list_init(&tablet->resource_list);
+
+ return tablet;
+}
+
+WL_EXPORT void
+weston_tablet_destroy(struct weston_tablet *tablet)
+{
+ struct wl_resource *resource;
+
+ wl_resource_for_each(resource, &tablet->resource_list)
+ zwp_tablet1_send_removed(resource);
+
+ wl_list_remove(&tablet->link);
+ free(tablet->name);
+ free(tablet);
+}
+
+WL_EXPORT struct weston_tablet_tool *
+weston_tablet_tool_create(void)
+{
+ struct weston_tablet_tool *tool;
+
+ tool = zalloc(sizeof *tool);
+ if (tool == NULL)
+ return NULL;
+
+ wl_list_init(&tool->resource_list);
+
+ return tool;
+}
+
+WL_EXPORT void
+weston_tablet_tool_destroy(struct weston_tablet_tool *tool)
+{
+ struct wl_resource *resource, *tmp;
+
+ wl_resource_for_each_safe(resource, tmp, &tool->resource_list)
+ zwp_tablet_tool1_send_removed(resource);
+
+ wl_list_remove(&tool->link);
+ free(tool);
+}
+
+
static void
seat_send_updated_caps(struct weston_seat *seat)
{
@@ -1659,6 +1713,186 @@ pointer_cursor_surface_get_label(struct weston_surface *surface,
}

static void
+tablet_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct zwp_tablet1_interface tablet_interface = {
+ tablet_destroy,
+};
+
+static void
+send_tablet_added(struct weston_tablet *tablet,
+ struct wl_resource *tablet_seat_resource,
+ struct wl_resource *tablet_resource)
+{
+ zwp_tablet_seat1_send_tablet_added(tablet_seat_resource, tablet_resource);
+ zwp_tablet1_send_name(tablet_resource, tablet->name);
+ zwp_tablet1_send_id(tablet_resource, tablet->vid, tablet->pid);
+ zwp_tablet1_send_type(tablet_resource, tablet->type);
+ zwp_tablet1_send_path(tablet_resource, tablet->path);
+ zwp_tablet1_send_done(tablet_resource);
+}
+
+WL_EXPORT void
+notify_tablet_added(struct weston_tablet *tablet)
+{
+ struct wl_resource *resource;
+ struct weston_seat *seat = tablet->seat;
+
+ wl_resource_for_each(resource, &seat->tablet_seat_resource_list) {
+ struct wl_resource *tablet_resource =
+ wl_resource_create(wl_resource_get_client(resource),
+ &zwp_tablet1_interface,
+ 1, 0);
+
+ wl_list_insert(&tablet->resource_list,
+ wl_resource_get_link(tablet_resource));
+ wl_resource_set_implementation(tablet_resource,
+ &tablet_interface,
+ tablet,
+ unbind_resource);
+
+ wl_resource_set_user_data(tablet_resource, tablet);
+ send_tablet_added(tablet, resource, tablet_resource);
+ }
+}
+
+static void
+tablet_tool_set_cursor(struct wl_client *client, struct wl_resource *resource,
+ uint32_t serial, struct wl_resource *surface_resource,
+ int32_t hotspot_x, int32_t hotspot_y)
+{
+}
+
+static void
+tablet_tool_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct zwp_tablet_tool1_interface tablet_tool_interface = {
+ tablet_tool_set_cursor,
+ tablet_tool_destroy,
+};
+
+static void
+send_tool_added(struct weston_tablet_tool *tool,
+ struct wl_resource *tool_seat_resource,
+ struct wl_resource *tool_resource)
+{
+ uint32_t caps, cap;
+ zwp_tablet_seat1_send_tool_added(tool_seat_resource, tool_resource);
+ zwp_tablet_tool1_send_type(tool_resource, tool->type);
+ zwp_tablet_tool1_send_serial_id(tool_resource,
+ tool->serial >> 32,
+ tool->serial & 0xFFFFFFFF);
+ zwp_tablet_tool1_send_hardware_id(tool_resource,
+ ZWP_TABLET_TOOL1_HARDWARE_ID_FORMAT_WACOM_STYLUS_ID,
+ tool->hwid >> 32,
+ tool->hwid & 0xFFFFFFFF);
+ caps = tool->capabilities;
+ while (caps != 0) {
+ cap = ffs(caps) - 1;
+ zwp_tablet_tool1_send_capability(tool_resource, cap);
+ caps &= ~(1 << cap);
+ }
+
+ zwp_tablet_tool1_send_done(tool_resource);
+ /* FIXME: hw id, not supported by libinput yet */
+}
+
+WL_EXPORT void
+notify_tablet_tool_added(struct weston_tablet_tool *tool)
+{
+ struct wl_resource *resource;
+ struct weston_seat *seat = tool->seat;
+
+ wl_resource_for_each(resource, &seat->tablet_seat_resource_list) {
+ struct wl_resource *tool_resource =
+ wl_resource_create(wl_resource_get_client(resource),
+ &zwp_tablet_tool1_interface,
+ 1, 0);
+
+ wl_list_insert(&tool->resource_list,
+ wl_resource_get_link(tool_resource));
+ wl_resource_set_implementation(tool_resource,
+ &tablet_tool_interface,
+ tool,
+ unbind_resource);
+
+ wl_resource_set_user_data(tool_resource, tool);
+ send_tool_added(tool, resource, tool_resource);
+ }
+}
+
+WL_EXPORT void
+notify_tablet_tool_proximity_in(struct weston_tablet_tool *tool,
+ uint32_t time,
+ struct weston_tablet *tablet)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_proximity_out(struct weston_tablet_tool *tool,
+ uint32_t time)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_motion(struct weston_tablet_tool *tool,
+ uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_pressure(struct weston_tablet_tool *tool,
+ uint32_t time, uint32_t pressure)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_distance(struct weston_tablet_tool *tool,
+ uint32_t time, uint32_t distance)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_tilt(struct weston_tablet_tool *tool,
+ uint32_t time, int32_t tilt_x, int32_t tilt_y)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_button(struct weston_tablet_tool *tool,
+ uint32_t time,
+ uint32_t button,
+ enum zwp_tablet_tool1_button_state state)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_down(struct weston_tablet_tool *tool,
+ uint32_t time)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_up(struct weston_tablet_tool *tool,
+ uint32_t time)
+{
+}
+
+WL_EXPORT void
+notify_tablet_tool_frame(struct weston_tablet_tool *tool,
+ uint32_t time)
+{
+}
+
+
+static void
pointer_cursor_surface_configure(struct weston_surface *es,
int32_t dx, int32_t dy)
{
@@ -2340,6 +2574,19 @@ weston_seat_release_pointer(struct weston_seat *seat)
}

WL_EXPORT void
+weston_seat_release_tablet_tool(struct weston_tablet_tool *tool)
+{
+ /* FIXME: nothing is calling this function yet, tools are only
+ released on shutdown when the seat goes away */
+}
+
+WL_EXPORT void
+weston_seat_release_tablet(struct weston_tablet *tablet)
+{
+ weston_tablet_destroy(tablet);
+}
+
+WL_EXPORT void
weston_seat_init_touch(struct weston_seat *seat)
{
struct weston_touch *touch;
@@ -2362,6 +2609,39 @@ weston_seat_init_touch(struct weston_seat *seat)
seat_send_updated_caps(seat);
}

+WL_EXPORT struct weston_tablet *
+weston_seat_add_tablet(struct weston_seat *seat)
+{
+ struct weston_tablet *tablet;
+
+ weston_tablet_manager_init(seat->compositor);
+
+ tablet = weston_tablet_create();
+ if (tablet == NULL)
+ return NULL;
+
+ tablet->seat = seat;
+
+ return tablet;
+}
+
+WL_EXPORT struct weston_tablet_tool *
+weston_seat_add_tablet_tool(struct weston_seat *seat)
+{
+ struct weston_tablet_tool *tool;
+
+ weston_tablet_manager_init(seat->compositor);
+
+ tool = weston_tablet_tool_create();
+ if (tool == NULL)
+ return NULL;
+
+ wl_list_init(&tool->resource_list);
+ tool->seat = seat;
+
+ return tool;
+}
+
WL_EXPORT void
weston_seat_release_touch(struct weston_seat *seat)
{
@@ -2386,6 +2666,9 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
wl_list_init(&seat->drag_resource_list);
wl_signal_init(&seat->destroy_signal);
wl_signal_init(&seat->updated_caps_signal);
+ wl_list_init(&seat->tablet_seat_resource_list);
+ wl_list_init(&seat->tablet_list);
+ wl_list_init(&seat->tablet_tool_list);

seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 4,
seat, bind_seat);
@@ -2404,6 +2687,9 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
WL_EXPORT void
weston_seat_release(struct weston_seat *seat)
{
+ struct weston_tablet *tablet, *tmp;
+ struct weston_tablet_tool *tool, *tmp_tool;
+
wl_list_remove(&seat->link);

if (seat->saved_kbd_focus)
@@ -2415,6 +2701,10 @@ weston_seat_release(struct weston_seat *seat)
weston_keyboard_destroy(seat->keyboard_state);
if (seat->touch_state)
weston_touch_destroy(seat->touch_state);
+ wl_list_for_each_safe(tablet, tmp, &seat->tablet_list, link)
+ weston_tablet_destroy(tablet);
+ wl_list_for_each_safe(tool, tmp_tool, &seat->tablet_tool_list, link)
+ weston_tablet_tool_destroy(tool);

free (seat->seat_name);

@@ -2488,3 +2778,103 @@ weston_seat_get_touch(struct weston_seat *seat)

return NULL;
}
+
+static void
+tablet_seat_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+}
+
+static const struct zwp_tablet_seat1_interface tablet_seat_interface = {
+ tablet_seat_destroy,
+};
+
+static void
+tablet_manager_get_tablet_seat(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id, struct wl_resource *seat_resource)
+{
+ struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
+ struct wl_resource *cr;
+ struct weston_tablet *tablet;
+ struct weston_tablet_tool *tool;
+
+ cr = wl_resource_create(client, &zwp_tablet_seat1_interface,
+ wl_resource_get_version(resource), id);
+ if (cr == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ /* store the resource in the weston_seat */
+ wl_list_insert(&seat->tablet_seat_resource_list, wl_resource_get_link(cr));
+ wl_resource_set_implementation(cr, &tablet_seat_interface, seat,
+ unbind_resource);
+
+ /* Notify the client of all tablets currently connected to the system */
+ wl_list_for_each(tablet, &seat->tablet_list, link) {
+ struct wl_resource *tablet_resource =
+ wl_resource_create(client, &zwp_tablet1_interface, 1, 0);
+
+ wl_resource_set_implementation(tablet_resource,
+ &tablet_interface, tablet,
+ unbind_resource);
+ wl_resource_set_user_data(tablet_resource, tablet);
+
+ wl_list_insert(&tablet->resource_list,
+ wl_resource_get_link(tablet_resource));
+
+ send_tablet_added(tablet, cr, tablet_resource);
+ }
+
+ /* Notify the client of all tools already known */
+ wl_list_for_each(tool, &seat->tablet_tool_list, link) {
+ struct wl_resource *tool_resource =
+ wl_resource_create(client, &zwp_tablet_tool1_interface, 1, 0);
+
+ wl_resource_set_implementation(tool_resource,
+ &tablet_tool_interface, tool,
+ unbind_resource);
+ wl_resource_set_user_data(tool_resource, tool);
+
+ wl_list_insert(&tool->resource_list,
+ wl_resource_get_link(tool_resource));
+ send_tool_added(tool, cr, tool_resource);
+ }
+}
+
+static void
+tablet_manager_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+
+}
+
+static const struct zwp_tablet_manager1_interface tablet_manager_interface = {
+ tablet_manager_get_tablet_seat,
+ tablet_manager_destroy,
+};
+
+static void
+bind_tablet_manager(struct wl_client *client, void *data, uint32_t version,
+ uint32_t id)
+{
+ struct weston_compositor *compositor = data;
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(client, &zwp_tablet_manager1_interface,
+ MIN(version, 1), id);
+ wl_resource_set_implementation(resource, &tablet_manager_interface,
+ data, unbind_resource);
+ wl_list_insert(&compositor->tablet_manager_resource_list,
+ wl_resource_get_link(resource));
+}
+
+WL_EXPORT void
+weston_tablet_manager_init(struct weston_compositor *compositor)
+{
+ if (compositor->tablet_manager)
+ return;
+
+ compositor->tablet_manager = wl_global_create(compositor->wl_display,
+ &zwp_tablet_manager1_interface,
+ 1, compositor,
+ bind_tablet_manager);
+}
diff --git a/src/libinput-device.c b/src/libinput-device.c
index 69dcbf8..262c485 100644
--- a/src/libinput-device.c
+++ b/src/libinput-device.c
@@ -40,6 +40,14 @@
#include "libinput-device.h"
#include "shared/helpers.h"

+struct tablet_output_listener {
+ struct wl_listener base;
+ struct wl_list tablet_list;
+};
+
+static bool
+tablet_bind_output(struct weston_tablet *tablet, struct weston_output *output);
+
void
evdev_led_update(struct evdev_device *device, enum weston_led weston_leds)
{
@@ -285,6 +293,84 @@ handle_touch_frame(struct libinput_device *libinput_device,
notify_touch_frame(seat);
}

+static void
+handle_tablet_proximity(struct libinput_device *libinput_device,
+ struct libinput_event_tablet *proximity_event)
+{
+ struct evdev_device *device;
+ struct weston_tablet *tablet;
+ struct weston_tablet_tool *tool;
+ struct libinput_tool *libinput_tool;
+ enum libinput_tool_type libinput_tool_type;
+ uint32_t serial, type;
+ uint32_t time;
+ bool create = true;
+
+ device = libinput_device_get_user_data(libinput_device);
+ time = libinput_event_tablet_get_time(proximity_event);
+ libinput_tool = libinput_event_tablet_get_tool(proximity_event);
+ serial = libinput_tool_get_serial(libinput_tool);
+ libinput_tool_type = libinput_tool_get_type(libinput_tool);
+
+ tool = libinput_tool_get_user_data(libinput_tool);
+ tablet = device->tablet;
+
+ if (libinput_event_tablet_get_proximity_state(proximity_event) ==
+ LIBINPUT_TOOL_PROXIMITY_OUT) {
+ notify_tablet_tool_proximity_out(tool, time);
+ return;
+ }
+
+ switch (libinput_tool_type) {
+ case LIBINPUT_TOOL_PEN:
+ type = ZWP_TABLET_TOOL1_TYPE_PEN;
+ break;
+ case LIBINPUT_TOOL_ERASER:
+ type = ZWP_TABLET_TOOL1_TYPE_ERASER;
+ break;
+ default:
+ fprintf(stderr, "Unknown libinput tool type %d\n",
+ libinput_tool_type);
+ return;
+ }
+
+ wl_list_for_each(tool, &device->seat->tablet_tool_list, link) {
+ if (tool->serial == serial && tool->type == type) {
+ create = false;
+ break;
+ }
+ }
+
+ if (create) {
+ tool = weston_seat_add_tablet_tool(device->seat);
+ tool->serial = serial;
+ tool->hwid = libinput_tool_get_tool_id(libinput_tool);
+ tool->type = type;
+ tool->capabilities = 0;
+
+ if (libinput_tool_has_axis(libinput_tool,
+ LIBINPUT_TABLET_AXIS_DISTANCE))
+ tool->capabilities |= 1 << ZWP_TABLET_TOOL1_CAPABILITY_DISTANCE;
+ if (libinput_tool_has_axis(libinput_tool,
+ LIBINPUT_TABLET_AXIS_PRESSURE))
+ tool->capabilities |= 1 << ZWP_TABLET_TOOL1_CAPABILITY_PRESSURE;
+ if (libinput_tool_has_axis(libinput_tool,
+ LIBINPUT_TABLET_AXIS_TILT_X) &&
+ libinput_tool_has_axis(libinput_tool,
+ LIBINPUT_TABLET_AXIS_TILT_Y))
+ tool->capabilities |= 1 << ZWP_TABLET_TOOL1_CAPABILITY_TILT;
+
+ wl_list_insert(&device->seat->tablet_tool_list, &tool->link);
+ notify_tablet_tool_added(tool);
+
+ libinput_tool_set_user_data(libinput_tool, tool);
+ }
+
+ notify_tablet_tool_proximity_in(tool, time, tablet);
+ /* FIXME: we should send axis updates here */
+ notify_tablet_tool_frame(tool, time);
+}
+
int
evdev_device_process_event(struct libinput_event *event)
{
@@ -330,6 +416,10 @@ evdev_device_process_event(struct libinput_event *event)
handle_touch_frame(libinput_device,
libinput_event_get_touch_event(event));
break;
+ case LIBINPUT_EVENT_TABLET_PROXIMITY:
+ handle_tablet_proximity(libinput_device,
+ libinput_event_get_tablet_event(event));
+ break;
default:
handled = 0;
weston_log("unknown libinput event %d\n",
@@ -482,6 +572,115 @@ configure_device(struct evdev_device *device)
evdev_device_set_calibration(device);
}

+static void
+bind_unbound_tablets(struct wl_listener *listener_base, void *data)
+{
+ struct tablet_output_listener *listener =
+ wl_container_of(listener_base, listener, base);
+ struct weston_tablet *tablet, *tmp;
+
+ wl_list_for_each_safe(tablet, tmp, &listener->tablet_list, link) {
+ if (tablet_bind_output(tablet, data)) {
+ wl_list_remove(&tablet->link);
+ wl_list_insert(&tablet->seat->tablet_list,
+ &tablet->link);
+ tablet->device->seat_caps |= EVDEV_SEAT_TABLET;
+ notify_tablet_added(tablet);
+ }
+ }
+
+ if (wl_list_empty(&listener->tablet_list)) {
+ wl_list_remove(&listener_base->link);
+ free(listener);
+ }
+}
+
+static bool
+tablet_bind_output(struct weston_tablet *tablet, struct weston_output *output)
+{
+ struct wl_list *output_list = &tablet->seat->compositor->output_list;
+ struct weston_compositor *compositor = tablet->seat->compositor;
+ struct tablet_output_listener *listener;
+ struct wl_listener *listener_base;
+
+ /* TODO: Properly bind tablets with built-in displays */
+ switch (tablet->type) {
+ case ZWP_TABLET1_TYPE_EXTERNAL:
+ case ZWP_TABLET1_TYPE_INTERNAL:
+ case ZWP_TABLET1_TYPE_DISPLAY:
+ if (output) {
+ tablet->output = output;
+ } else {
+ if (wl_list_empty(output_list))
+ break;
+
+ /* Find the first available display */
+ wl_list_for_each(output, output_list, link)
+ break;
+ tablet->output = output;
+ }
+ break;
+ }
+
+ if (tablet->output)
+ return true;
+
+ listener_base = wl_signal_get(&compositor->output_created_signal,
+ bind_unbound_tablets);
+ if (listener_base == NULL) {
+ listener = zalloc(sizeof(*listener));
+
+ wl_list_init(&listener->tablet_list);
+
+ listener_base = &listener->base;
+ listener_base->notify = bind_unbound_tablets;
+
+ wl_signal_add(&compositor->output_created_signal,
+ listener_base);
+ } else {
+ listener = wl_container_of(listener_base, listener, base);
+ }
+
+ wl_list_insert(&listener->tablet_list, &tablet->link);
+ return false;
+}
+
+static void
+evdev_device_init_tablet(struct evdev_device *device,
+ struct libinput_device *libinput_device,
+ struct weston_seat *seat)
+{
+ struct weston_tablet *tablet;
+ struct udev_device *udev_device;
+
+ tablet = weston_seat_add_tablet(seat);
+ tablet->name = strdup(libinput_device_get_name(libinput_device));
+ tablet->vid = libinput_device_get_id_vendor(libinput_device);
+ tablet->pid = libinput_device_get_id_product(libinput_device);
+
+ /* FIXME: we need libwacom to get this information */
+ tablet->type = ZWP_TABLET1_TYPE_EXTERNAL;
+
+ udev_device = libinput_device_get_udev_device(libinput_device);
+ if (udev_device) {
+ tablet->path = udev_device_get_devnode(udev_device);
+ udev_device_unref(udev_device);
+ }
+
+ /* If we can successfully bind the tablet to an output, then
+ * it's ready to get added to the seat's tablet list, otherwise
+ * it will get added when an appropriate output is available */
+ if (tablet_bind_output(tablet, NULL)) {
+ wl_list_insert(&seat->tablet_list, &tablet->link);
+ device->seat_caps |= EVDEV_SEAT_TABLET;
+
+ notify_tablet_added(tablet);
+ }
+
+ device->tablet = tablet;
+ tablet->device = device;
+}
+
struct evdev_device *
evdev_device_create(struct libinput_device *libinput_device,
struct weston_seat *seat)
@@ -511,6 +710,10 @@ evdev_device_create(struct libinput_device *libinput_device,
weston_seat_init_touch(seat);
device->seat_caps |= EVDEV_SEAT_TOUCH;
}
+ if (libinput_device_has_capability(libinput_device,
+ LIBINPUT_DEVICE_CAP_TABLET)) {
+ evdev_device_init_tablet(device, libinput_device, seat);
+ }

libinput_device_set_user_data(libinput_device, device);
libinput_device_ref(libinput_device);
@@ -529,6 +732,8 @@ evdev_device_destroy(struct evdev_device *device)
weston_seat_release_keyboard(device->seat);
if (device->seat_caps & EVDEV_SEAT_TOUCH)
weston_seat_release_touch(device->seat);
+ if (device->seat_caps & EVDEV_SEAT_TABLET)
+ weston_seat_release_tablet(device->tablet);

if (device->output)
wl_list_remove(&device->output_destroy_listener.link);
diff --git a/src/libinput-device.h b/src/libinput-device.h
index a3848ca..e082291 100644
--- a/src/libinput-device.h
+++ b/src/libinput-device.h
@@ -37,7 +37,8 @@
enum evdev_device_seat_capability {
EVDEV_SEAT_POINTER = (1 << 0),
EVDEV_SEAT_KEYBOARD = (1 << 1),
- EVDEV_SEAT_TOUCH = (1 << 2)
+ EVDEV_SEAT_TOUCH = (1 << 2),
+ EVDEV_SEAT_TABLET = (1 << 3)
};

struct evdev_device {
@@ -47,6 +48,7 @@ struct evdev_device {
struct wl_list link;
struct weston_output *output;
struct wl_listener output_destroy_listener;
+ struct weston_tablet *tablet;
char *devnode;
char *output_name;
int fd;
--
2.4.3
Peter Hutterer
2015-11-06 04:31:10 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Closely modelled after the pointer focus handling

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
src/compositor.h | 10 +++++++
src/input.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 92 insertions(+)

diff --git a/src/compositor.h b/src/compositor.h
index 50c7034..7725c27 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -370,8 +370,14 @@ struct weston_touch {
struct weston_tablet_tool {
struct weston_seat *seat;
enum zwp_tablet_tool1_type type;
+ struct weston_tablet *current_tablet;

struct wl_list resource_list;
+ struct wl_list focus_resource_list;
+ struct weston_view *focus;
+ struct wl_listener focus_view_listener;
+ struct wl_listener focus_resource_listener;
+ uint32_t focus_serial;

struct wl_list link;

@@ -466,6 +472,10 @@ struct weston_tablet_tool *
weston_tablet_tool_create(void);
void
weston_tablet_tool_destroy(struct weston_tablet_tool *tool);
+void
+weston_tablet_tool_set_focus(struct weston_tablet_tool *tool,
+ struct weston_view *view,
+ uint32_t time);

void
wl_data_device_set_keyboard_focus(struct weston_seat *seat);
diff --git a/src/input.c b/src/input.c
index 8814d34..e9688c5 100644
--- a/src/input.c
+++ b/src/input.c
@@ -126,6 +126,26 @@ touch_focus_resource_destroyed(struct wl_listener *listener, void *data)
}

static void
+tablet_tool_focus_view_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_tablet_tool *tool =
+ container_of(listener, struct weston_tablet_tool,
+ focus_view_listener);
+
+ weston_tablet_tool_set_focus(tool, NULL, 0);
+}
+
+static void
+tablet_tool_focus_resource_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_tablet_tool *tool =
+ container_of(listener, struct weston_tablet_tool,
+ focus_resource_listener);
+
+ weston_tablet_tool_set_focus(tool, NULL, 0);
+}
+
+static void
move_resources(struct wl_list *destination, struct wl_list *source)
{
wl_list_insert_list(destination, source);
@@ -670,6 +690,61 @@ weston_tablet_destroy(struct weston_tablet *tablet)
free(tablet);
}

+WL_EXPORT void
+weston_tablet_tool_set_focus(struct weston_tablet_tool *tool,
+ struct weston_view *view,
+ uint32_t time)
+{
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+ struct weston_seat *seat = tool->seat;
+
+ focus_resource_list = &tool->focus_resource_list;
+ if (tool->focus && !wl_list_empty(focus_resource_list)) {
+ wl_resource_for_each(resource, focus_resource_list) {
+ zwp_tablet_tool1_send_proximity_out(resource);
+ zwp_tablet_tool1_send_frame(resource, time);
+ }
+
+ move_resources(&tool->resource_list, focus_resource_list);
+ }
+
+ if (find_resource_for_view(&tool->resource_list, view)) {
+ struct wl_client *surface_client =
+ wl_resource_get_client(view->surface->resource);
+
+ move_resources_for_client(focus_resource_list,
+ &tool->resource_list,
+ surface_client);
+
+ tool->focus_serial = wl_display_next_serial(seat->compositor->wl_display);
+ wl_resource_for_each(resource, focus_resource_list) {
+ struct wl_resource *tr;
+
+ tr = wl_resource_find_for_client(&tool->current_tablet->resource_list,
+ surface_client);
+
+ zwp_tablet_tool1_send_proximity_in(resource, tool->focus_serial,
+ tr, view->surface->resource);
+ zwp_tablet_tool1_send_frame(resource, time);
+ }
+ }
+
+ wl_list_remove(&tool->focus_view_listener.link);
+ wl_list_init(&tool->focus_view_listener.link);
+ wl_list_remove(&tool->focus_resource_listener.link);
+ wl_list_init(&tool->focus_resource_listener.link);
+
+ if (view)
+ wl_signal_add(&view->destroy_signal,
+ &tool->focus_view_listener);
+ if (view && view->surface->resource)
+ wl_resource_add_destroy_listener(view->surface->resource,
+ &tool->focus_resource_listener);
+ tool->focus = view;
+ tool->focus_view_listener.notify = tablet_tool_focus_view_destroyed;
+}
+
WL_EXPORT struct weston_tablet_tool *
weston_tablet_tool_create(void)
{
@@ -680,6 +755,13 @@ weston_tablet_tool_create(void)
return NULL;

wl_list_init(&tool->resource_list);
+ wl_list_init(&tool->focus_resource_list);
+
+ wl_list_init(&tool->focus_view_listener.link);
+ tool->focus_view_listener.notify = tablet_tool_focus_view_destroyed;
+
+ wl_list_init(&tool->focus_resource_listener.link);
+ tool->focus_resource_listener.notify = tablet_tool_focus_resource_destroyed;

return tool;
}
--
2.4.3
Bill Spitzak
2015-11-06 23:27:41 UTC
Permalink
I don't think it should be possible for the tablet focus to be different
than the pointer focus, so most of this should not be necessary.
Post by Peter Hutterer
Closely modelled after the pointer focus handling
---
src/compositor.h | 10 +++++++
src/input.c | 82
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 92 insertions(+)
diff --git a/src/compositor.h b/src/compositor.h
index 50c7034..7725c27 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -370,8 +370,14 @@ struct weston_touch {
struct weston_tablet_tool {
struct weston_seat *seat;
enum zwp_tablet_tool1_type type;
+ struct weston_tablet *current_tablet;
struct wl_list resource_list;
+ struct wl_list focus_resource_list;
+ struct weston_view *focus;
+ struct wl_listener focus_view_listener;
+ struct wl_listener focus_resource_listener;
+ uint32_t focus_serial;
struct wl_list link;
@@ -466,6 +472,10 @@ struct weston_tablet_tool *
weston_tablet_tool_create(void);
void
weston_tablet_tool_destroy(struct weston_tablet_tool *tool);
+void
+weston_tablet_tool_set_focus(struct weston_tablet_tool *tool,
+ struct weston_view *view,
+ uint32_t time);
void
wl_data_device_set_keyboard_focus(struct weston_seat *seat);
diff --git a/src/input.c b/src/input.c
index 8814d34..e9688c5 100644
--- a/src/input.c
+++ b/src/input.c
@@ -126,6 +126,26 @@ touch_focus_resource_destroyed(struct wl_listener
*listener, void *data)
}
static void
+tablet_tool_focus_view_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_tablet_tool *tool =
+ container_of(listener, struct weston_tablet_tool,
+ focus_view_listener);
+
+ weston_tablet_tool_set_focus(tool, NULL, 0);
+}
+
+static void
+tablet_tool_focus_resource_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_tablet_tool *tool =
+ container_of(listener, struct weston_tablet_tool,
+ focus_resource_listener);
+
+ weston_tablet_tool_set_focus(tool, NULL, 0);
+}
+
+static void
move_resources(struct wl_list *destination, struct wl_list *source)
{
wl_list_insert_list(destination, source);
@@ -670,6 +690,61 @@ weston_tablet_destroy(struct weston_tablet *tablet)
free(tablet);
}
+WL_EXPORT void
+weston_tablet_tool_set_focus(struct weston_tablet_tool *tool,
+ struct weston_view *view,
+ uint32_t time)
+{
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+ struct weston_seat *seat = tool->seat;
+
+ focus_resource_list = &tool->focus_resource_list;
+ if (tool->focus && !wl_list_empty(focus_resource_list)) {
+ wl_resource_for_each(resource, focus_resource_list) {
+ zwp_tablet_tool1_send_proximity_out(resource);
+ zwp_tablet_tool1_send_frame(resource, time);
+ }
+
+ move_resources(&tool->resource_list, focus_resource_list);
+ }
+
+ if (find_resource_for_view(&tool->resource_list, view)) {
+ struct wl_client *surface_client =
+ wl_resource_get_client(view->surface->resource);
+
+ move_resources_for_client(focus_resource_list,
+ &tool->resource_list,
+ surface_client);
+
+ tool->focus_serial =
wl_display_next_serial(seat->compositor->wl_display);
+ wl_resource_for_each(resource, focus_resource_list) {
+ struct wl_resource *tr;
+
+ tr =
wl_resource_find_for_client(&tool->current_tablet->resource_list,
+ surface_client);
+
+ zwp_tablet_tool1_send_proximity_in(resource,
tool->focus_serial,
+ tr,
view->surface->resource);
+ zwp_tablet_tool1_send_frame(resource, time);
+ }
+ }
+
+ wl_list_remove(&tool->focus_view_listener.link);
+ wl_list_init(&tool->focus_view_listener.link);
+ wl_list_remove(&tool->focus_resource_listener.link);
+ wl_list_init(&tool->focus_resource_listener.link);
+
+ if (view)
+ wl_signal_add(&view->destroy_signal,
+ &tool->focus_view_listener);
+ if (view && view->surface->resource)
+ wl_resource_add_destroy_listener(view->surface->resource,
+
&tool->focus_resource_listener);
+ tool->focus = view;
+ tool->focus_view_listener.notify =
tablet_tool_focus_view_destroyed;
+}
+
WL_EXPORT struct weston_tablet_tool *
weston_tablet_tool_create(void)
{
@@ -680,6 +755,13 @@ weston_tablet_tool_create(void)
return NULL;
wl_list_init(&tool->resource_list);
+ wl_list_init(&tool->focus_resource_list);
+
+ wl_list_init(&tool->focus_view_listener.link);
+ tool->focus_view_listener.notify =
tablet_tool_focus_view_destroyed;
+
+ wl_list_init(&tool->focus_resource_listener.link);
+ tool->focus_resource_listener.notify =
tablet_tool_focus_resource_destroyed;
return tool;
}
--
2.4.3
_______________________________________________
wayland-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Peter Hutterer
2015-11-06 04:31:11 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
src/compositor.h | 53 ++++++++++++
src/input.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 306 insertions(+)

diff --git a/src/compositor.h b/src/compositor.h
index 7725c27..ce084c8 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -297,6 +297,47 @@ struct weston_touch_grab {
struct weston_touch *touch;
};

+struct weston_tablet;
+struct weston_tablet_tool;
+struct weston_tablet_tool_grab;
+struct weston_tablet_tool_grab_interface {
+ void (*proximity_in)(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ struct weston_tablet *tablet);
+ void (*proximity_out)(struct weston_tablet_tool_grab *grab,
+ uint32_t time);
+ void (*motion)(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ wl_fixed_t x,
+ wl_fixed_t y);
+ void (*down)(struct weston_tablet_tool_grab *grab,
+ uint32_t time);
+ void (*up)(struct weston_tablet_tool_grab *grab,
+ uint32_t time);
+ void (*pressure)(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ uint32_t pressure);
+ void (*distance)(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ uint32_t distance);
+ void (*tilt)(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ int32_t tilt_x,
+ int32_t tilt_y);
+ void (*button)(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ uint32_t button,
+ enum zwp_tablet_tool1_button_state state);
+ void (*frame)(struct weston_tablet_tool_grab *grab,
+ uint32_t time);
+ void (*cancel)(struct weston_tablet_tool_grab *grab);
+};
+
+struct weston_tablet_tool_grab {
+ const struct weston_tablet_tool_grab_interface *interface;
+ struct weston_tablet_tool *tool;
+};
+
struct weston_data_offer {
struct wl_resource *resource;
struct weston_data_source *source;
@@ -378,12 +419,19 @@ struct weston_tablet_tool {
struct wl_listener focus_view_listener;
struct wl_listener focus_resource_listener;
uint32_t focus_serial;
+ uint32_t grab_serial;

struct wl_list link;

uint64_t serial;
uint64_t hwid;
uint32_t capabilities;
+
+ struct weston_tablet_tool_grab *grab;
+ struct weston_tablet_tool_grab default_grab;
+
+ int button_count;
+ bool tip_is_down;
};

struct weston_tablet {
@@ -476,6 +524,11 @@ void
weston_tablet_tool_set_focus(struct weston_tablet_tool *tool,
struct weston_view *view,
uint32_t time);
+void
+weston_tablet_tool_start_grab(struct weston_tablet_tool *tool,
+ struct weston_tablet_tool_grab *grab);
+void
+weston_tablet_tool_end_grab(struct weston_tablet_tool *tool);

void
wl_data_device_set_keyboard_focus(struct weston_seat *seat);
diff --git a/src/input.c b/src/input.c
index e9688c5..6139b31 100644
--- a/src/input.c
+++ b/src/input.c
@@ -702,6 +702,9 @@ weston_tablet_tool_set_focus(struct weston_tablet_tool *tool,
focus_resource_list = &tool->focus_resource_list;
if (tool->focus && !wl_list_empty(focus_resource_list)) {
wl_resource_for_each(resource, focus_resource_list) {
+ if (tool->tip_is_down)
+ zwp_tablet_tool1_send_up(resource);
+
zwp_tablet_tool1_send_proximity_out(resource);
zwp_tablet_tool1_send_frame(resource, time);
}
@@ -726,6 +729,11 @@ weston_tablet_tool_set_focus(struct weston_tablet_tool *tool,

zwp_tablet_tool1_send_proximity_in(resource, tool->focus_serial,
tr, view->surface->resource);
+
+ if (tool->tip_is_down)
+ zwp_tablet_tool1_send_down(resource,
+ tool->focus_serial);
+
zwp_tablet_tool1_send_frame(resource, time);
}
}
@@ -745,6 +753,186 @@ weston_tablet_tool_set_focus(struct weston_tablet_tool *tool,
tool->focus_view_listener.notify = tablet_tool_focus_view_destroyed;
}

+WL_EXPORT void
+weston_tablet_tool_start_grab(struct weston_tablet_tool *tool,
+ struct weston_tablet_tool_grab *grab)
+{
+ tool->grab = grab;
+ grab->tool = tool;
+}
+
+WL_EXPORT void
+weston_tablet_tool_end_grab(struct weston_tablet_tool *tool)
+{
+ tool->grab = &tool->default_grab;
+}
+
+static void
+default_grab_tablet_tool_proximity_in(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ struct weston_tablet *tablet)
+{
+ struct weston_tablet_tool *tool = grab->tool;
+
+ tool->current_tablet = tablet;
+}
+
+static void
+default_grab_tablet_tool_proximity_out(struct weston_tablet_tool_grab *grab,
+ uint32_t time)
+{
+ weston_tablet_tool_set_focus(grab->tool, NULL, time);
+}
+
+static void
+default_grab_tablet_tool_motion(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct weston_tablet_tool *tool = grab->tool;
+ struct weston_view *current_view;
+ wl_fixed_t sx, sy;
+ struct wl_resource *resource;
+ struct wl_list *resource_list = &tool->focus_resource_list;
+
+ current_view = weston_compositor_pick_view(tool->seat->compositor,
+ x, y, &sx, &sy);
+ if (current_view != tool->focus)
+ weston_tablet_tool_set_focus(tool, current_view, time);
+
+ if (!wl_list_empty(resource_list)) {
+ wl_resource_for_each(resource, resource_list)
+ zwp_tablet_tool1_send_motion(resource, sx, sy);
+ }
+}
+
+static void
+default_grab_tablet_tool_down(struct weston_tablet_tool_grab *grab,
+ uint32_t time)
+{
+ struct weston_tablet_tool *tool = grab->tool;
+ struct wl_resource *resource;
+ struct wl_list *resource_list = &tool->focus_resource_list;
+
+ if (!wl_list_empty(resource_list)) {
+ wl_resource_for_each(resource, resource_list)
+ zwp_tablet_tool1_send_down(resource, tool->grab_serial);
+ }
+}
+
+static void
+default_grab_tablet_tool_up(struct weston_tablet_tool_grab *grab,
+ uint32_t time)
+{
+ struct weston_tablet_tool *tool = grab->tool;
+ struct wl_resource *resource;
+ struct wl_list *resource_list = &tool->focus_resource_list;
+
+ if (!wl_list_empty(resource_list)) {
+ wl_resource_for_each(resource, resource_list)
+ zwp_tablet_tool1_send_up(resource);
+ }
+}
+
+static void
+default_grab_tablet_tool_pressure(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ uint32_t pressure)
+{
+ struct weston_tablet_tool *tool = grab->tool;
+ struct wl_resource *resource;
+ struct wl_list *resource_list = &tool->focus_resource_list;
+
+ if (!wl_list_empty(resource_list)) {
+ wl_resource_for_each(resource, resource_list)
+ zwp_tablet_tool1_send_pressure(resource, pressure);
+ }
+}
+
+static void
+default_grab_tablet_tool_distance(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ uint32_t distance)
+{
+ struct weston_tablet_tool *tool = grab->tool;
+ struct wl_resource *resource;
+ struct wl_list *resource_list = &tool->focus_resource_list;
+
+ if (!wl_list_empty(resource_list)) {
+ wl_resource_for_each(resource, resource_list)
+ zwp_tablet_tool1_send_pressure(resource, distance);
+ }
+}
+
+static void
+default_grab_tablet_tool_tilt(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ int32_t tilt_x,
+ int32_t tilt_y)
+{
+ struct weston_tablet_tool *tool = grab->tool;
+ struct wl_resource *resource;
+ struct wl_list *resource_list = &tool->focus_resource_list;
+
+ if (!wl_list_empty(resource_list)) {
+ wl_resource_for_each(resource, resource_list)
+ zwp_tablet_tool1_send_tilt(resource, tilt_x, tilt_y);
+ }
+}
+
+static void
+default_grab_tablet_tool_button(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ uint32_t button,
+ enum zwp_tablet_tool1_button_state state)
+{
+ struct weston_tablet_tool *tool = grab->tool;
+ struct wl_resource *resource;
+ struct wl_list *resource_list = &tool->focus_resource_list;
+
+ if (!wl_list_empty(resource_list)) {
+ wl_resource_for_each(resource, resource_list) {
+ zwp_tablet_tool1_send_button(resource, tool->grab_serial,
+ button, state);
+ }
+ }
+}
+
+static void
+default_grab_tablet_tool_frame(struct weston_tablet_tool_grab *grab,
+ uint32_t time)
+{
+ struct wl_resource *resource;
+ struct wl_list *resource_list = &grab->tool->focus_resource_list;
+
+ if (!wl_list_empty(resource_list)) {
+ wl_resource_for_each(resource, resource_list)
+ zwp_tablet_tool1_send_frame(resource, time);
+ }
+}
+
+
+static void
+default_grab_tablet_tool_cancel(struct weston_tablet_tool_grab *grab)
+{
+}
+
+
+static struct weston_tablet_tool_grab_interface default_tablet_tool_grab_interface = {
+ default_grab_tablet_tool_proximity_in,
+ default_grab_tablet_tool_proximity_out,
+ default_grab_tablet_tool_motion,
+ default_grab_tablet_tool_down,
+ default_grab_tablet_tool_up,
+ default_grab_tablet_tool_pressure,
+ default_grab_tablet_tool_distance,
+ default_grab_tablet_tool_tilt,
+ default_grab_tablet_tool_button,
+ default_grab_tablet_tool_frame,
+ default_grab_tablet_tool_cancel,
+};
+
WL_EXPORT struct weston_tablet_tool *
weston_tablet_tool_create(void)
{
@@ -763,6 +951,10 @@ weston_tablet_tool_create(void)
wl_list_init(&tool->focus_resource_listener.link);
tool->focus_resource_listener.notify = tablet_tool_focus_resource_destroyed;

+ tool->default_grab.interface = &default_tablet_tool_grab_interface;
+ tool->default_grab.tool = tool;
+ tool->grab = &tool->default_grab;
+
return tool;
}

@@ -1914,12 +2106,18 @@ notify_tablet_tool_proximity_in(struct weston_tablet_tool *tool,
uint32_t time,
struct weston_tablet *tablet)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+
+ grab->interface->proximity_in(grab, time, tablet);
}

WL_EXPORT void
notify_tablet_tool_proximity_out(struct weston_tablet_tool *tool,
uint32_t time)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+
+ grab->interface->proximity_out(grab, time);
}

WL_EXPORT void
@@ -1927,24 +2125,44 @@ notify_tablet_tool_motion(struct weston_tablet_tool *tool,
uint32_t time,
wl_fixed_t x, wl_fixed_t y)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+
+ weston_compositor_wake(tool->seat->compositor);
+
+ grab->interface->motion(grab, time, x, y);
}

WL_EXPORT void
notify_tablet_tool_pressure(struct weston_tablet_tool *tool,
uint32_t time, uint32_t pressure)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+
+ weston_compositor_wake(tool->seat->compositor);
+
+ grab->interface->pressure(grab, time, pressure);
}

WL_EXPORT void
notify_tablet_tool_distance(struct weston_tablet_tool *tool,
uint32_t time, uint32_t distance)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+
+ weston_compositor_wake(tool->seat->compositor);
+
+ grab->interface->distance(grab, time, distance);
}

WL_EXPORT void
notify_tablet_tool_tilt(struct weston_tablet_tool *tool,
uint32_t time, int32_t tilt_x, int32_t tilt_y)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+
+ weston_compositor_wake(tool->seat->compositor);
+
+ grab->interface->tilt(grab, time, tilt_x, tilt_y);
}

WL_EXPORT void
@@ -1953,24 +2171,59 @@ notify_tablet_tool_button(struct weston_tablet_tool *tool,
uint32_t button,
enum zwp_tablet_tool1_button_state state)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+ struct weston_compositor *compositor = tool->seat->compositor;
+
+ if (state == ZWP_TABLET_TOOL1_BUTTON_STATE_PRESSED) {
+ tool->button_count++;
+ if (tool->button_count == 1)
+ weston_compositor_idle_inhibit(compositor);
+ } else {
+ tool->button_count--;
+ if (tool->button_count == 1)
+ weston_compositor_idle_release(compositor);
+ }
+
+ tool->grab_serial = wl_display_next_serial(compositor->wl_display);
+ grab->interface->button(grab, time, button, state);
}

WL_EXPORT void
notify_tablet_tool_down(struct weston_tablet_tool *tool,
uint32_t time)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+ struct weston_compositor *compositor = tool->seat->compositor;
+
+ weston_compositor_idle_inhibit(compositor);
+
+ tool->tip_is_down = true;
+ tool->grab_serial = wl_display_get_serial(compositor->wl_display);
+
+ grab->interface->down(grab, time);
}

WL_EXPORT void
notify_tablet_tool_up(struct weston_tablet_tool *tool,
uint32_t time)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+ struct weston_compositor *compositor = tool->seat->compositor;
+
+ weston_compositor_idle_release(compositor);
+
+ tool->tip_is_down = false;
+
+ grab->interface->up(grab, time);
}

WL_EXPORT void
notify_tablet_tool_frame(struct weston_tablet_tool *tool,
uint32_t time)
{
+ struct weston_tablet_tool_grab *grab = tool->grab;
+
+ grab->interface->frame(grab, time);
}
--
2.4.3
Peter Hutterer
2015-11-06 04:31:12 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
src/libinput-device.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 112 insertions(+)

diff --git a/src/libinput-device.c b/src/libinput-device.c
index 262c485..ba89410 100644
--- a/src/libinput-device.c
+++ b/src/libinput-device.c
@@ -371,6 +371,110 @@ handle_tablet_proximity(struct libinput_device *libinput_device,
notify_tablet_tool_frame(tool, time);
}

+static void
+handle_tablet_axis(struct libinput_device *libinput_device,
+ struct libinput_event_tablet *axis_event)
+{
+ struct evdev_device *device =
+ libinput_device_get_user_data(libinput_device);
+ struct weston_tablet_tool *tool;
+ struct weston_tablet *tablet = device->tablet;
+ struct libinput_tool *libinput_tool;
+ uint32_t time;
+ const int NORMALIZED_AXIS_MAX = 65535;
+
+ libinput_tool = libinput_event_tablet_get_tool(axis_event);
+ tool = libinput_tool_get_user_data(libinput_tool);
+ time = libinput_event_tablet_get_time(axis_event);
+
+ if (libinput_event_tablet_axis_has_changed(axis_event,
+ LIBINPUT_TABLET_AXIS_X) ||
+ libinput_event_tablet_axis_has_changed(axis_event,
+ LIBINPUT_TABLET_AXIS_Y)) {
+ double x, y;
+ uint32_t width, height;
+
+ width = tablet->output->current_mode->width;
+ height = tablet->output->current_mode->height;
+ x = libinput_event_tablet_get_x_transformed(axis_event, width);
+ y = libinput_event_tablet_get_y_transformed(axis_event, height);
+
+ notify_tablet_tool_motion(tool, time,
+ wl_fixed_from_double(x),
+ wl_fixed_from_double(y));
+ }
+
+ if (libinput_event_tablet_axis_has_changed(axis_event,
+ LIBINPUT_TABLET_AXIS_PRESSURE)) {
+ double pressure;
+
+ pressure = libinput_event_tablet_get_axis_value(axis_event,
+ LIBINPUT_TABLET_AXIS_PRESSURE);
+ /* convert axis range [0.0, 1.0] to [0, 65535] */
+ pressure *= NORMALIZED_AXIS_MAX;
+ notify_tablet_tool_pressure(tool, time, pressure);
+ }
+
+ if (libinput_event_tablet_axis_has_changed(axis_event,
+ LIBINPUT_TABLET_AXIS_DISTANCE)) {
+ double distance;
+
+ distance = libinput_event_tablet_get_axis_value(axis_event,
+ LIBINPUT_TABLET_AXIS_PRESSURE);
+ /* convert axis range [0.0, 1.0] to [0, 65535] */
+ distance *= NORMALIZED_AXIS_MAX;
+ notify_tablet_tool_distance(tool, time, distance);
+ }
+
+ if (libinput_event_tablet_axis_has_changed(axis_event,
+ LIBINPUT_TABLET_AXIS_TILT_X) ||
+ libinput_event_tablet_axis_has_changed(axis_event,
+ LIBINPUT_TABLET_AXIS_TILT_Y)) {
+ double tx, ty;
+
+ tx = libinput_event_tablet_get_axis_value(axis_event,
+ LIBINPUT_TABLET_AXIS_TILT_X);
+ ty = libinput_event_tablet_get_axis_value(axis_event,
+ LIBINPUT_TABLET_AXIS_TILT_Y);
+ /* convert axis range [-1.0, 1.0] to [-65535, 65535] */
+ tx *= NORMALIZED_AXIS_MAX;
+ ty *= NORMALIZED_AXIS_MAX;
+ notify_tablet_tool_tilt(tool, time, tx, ty);
+ }
+
+ notify_tablet_tool_frame(tool, time);
+}
+
+static void
+handle_tablet_button(struct libinput_device *libinput_device,
+ struct libinput_event_tablet *button_event)
+{
+ struct weston_tablet_tool *tool;
+ struct libinput_tool *libinput_tool;
+ uint32_t time, button;
+ enum zwp_tablet_tool1_button_state state;
+
+ libinput_tool = libinput_event_tablet_get_tool(button_event);
+ tool = libinput_tool_get_user_data(libinput_tool);
+ time = libinput_event_tablet_get_time(button_event);
+ button = libinput_event_tablet_get_button(button_event);
+ if (libinput_event_tablet_get_button_state(button_event) ==
+ LIBINPUT_BUTTON_STATE_PRESSED)
+ state = ZWP_TABLET_TOOL1_BUTTON_STATE_PRESSED;
+ else
+ state = ZWP_TABLET_TOOL1_BUTTON_STATE_RELEASED;
+
+ if (button == BTN_TOUCH) {
+ if (state == ZWP_TABLET_TOOL1_BUTTON_STATE_PRESSED)
+ notify_tablet_tool_down(tool, time);
+ else
+ notify_tablet_tool_up(tool, time);
+
+ } else {
+ notify_tablet_tool_button(tool, time, button, state);
+ }
+}
+
int
evdev_device_process_event(struct libinput_event *event)
{
@@ -420,6 +524,14 @@ evdev_device_process_event(struct libinput_event *event)
handle_tablet_proximity(libinput_device,
libinput_event_get_tablet_event(event));
break;
+ case LIBINPUT_EVENT_TABLET_AXIS:
+ handle_tablet_axis(libinput_device,
+ libinput_event_get_tablet_event(event));
+ break;
+ case LIBINPUT_EVENT_TABLET_BUTTON:
+ handle_tablet_button(libinput_device,
+ libinput_event_get_tablet_event(event));
+ break;
default:
handled = 0;
weston_log("unknown libinput event %d\n",
--
2.4.3
Peter Hutterer
2015-11-06 04:31:13 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

The tablet is given a separate cursor. Most tablet interaction is an absolute
interaction and shouldn't need a cursor at all, but usually the cursor is used
to indicate the type of virtual tool currently assigned.

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
src/compositor.c | 6 +++
src/compositor.h | 13 +++++
src/input.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 175 insertions(+), 1 deletion(-)

diff --git a/src/compositor.c b/src/compositor.c
index 8eadf8c..7777291 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1759,6 +1759,7 @@ weston_view_unmap(struct weston_view *view)
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
+ struct weston_tablet_tool *tool;

if (keyboard && keyboard->focus == view->surface)
weston_keyboard_set_focus(keyboard, NULL);
@@ -1766,6 +1767,11 @@ weston_view_unmap(struct weston_view *view)
weston_pointer_clear_focus(pointer);
if (touch && touch->focus == view)
weston_touch_set_focus(touch, NULL);
+
+ wl_list_for_each(tool, &seat->tablet_tool_list, link) {
+ if (tool->focus == view)
+ weston_tablet_tool_set_focus(tool, NULL, 0);
+ }
}
}

diff --git a/src/compositor.h b/src/compositor.h
index ce084c8..2eaadf4 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -432,6 +432,12 @@ struct weston_tablet_tool {

int button_count;
bool tip_is_down;
+
+ int32_t hotspot_x, hotspot_y;
+ struct weston_view *sprite;
+ struct wl_listener sprite_destroy_listener;
+
+ wl_fixed_t x, y;
};

struct weston_tablet {
@@ -531,6 +537,13 @@ void
weston_tablet_tool_end_grab(struct weston_tablet_tool *tool);

void
+weston_tablet_tool_clamp(struct weston_tablet_tool *tool,
+ wl_fixed_t *fx, wl_fixed_t *fy);
+void
+weston_tablet_tool_cursor_move(struct weston_tablet_tool *tool,
+ wl_fixed_t x, wl_fixed_t y);
+
+void
wl_data_device_set_keyboard_focus(struct weston_seat *seat);

int
diff --git a/src/input.c b/src/input.c
index 6139b31..69806e2 100644
--- a/src/input.c
+++ b/src/input.c
@@ -781,7 +781,13 @@ static void
default_grab_tablet_tool_proximity_out(struct weston_tablet_tool_grab *grab,
uint32_t time)
{
- weston_tablet_tool_set_focus(grab->tool, NULL, time);
+ struct weston_tablet_tool *tool = grab->tool;
+
+ weston_tablet_tool_set_focus(tool, NULL, time);
+
+ /* Hide the cursor */
+ if (weston_surface_is_mapped(tool->sprite->surface))
+ weston_surface_unmap(tool->sprite->surface);
}

static void
@@ -796,6 +802,8 @@ default_grab_tablet_tool_motion(struct weston_tablet_tool_grab *grab,
struct wl_resource *resource;
struct wl_list *resource_list = &tool->focus_resource_list;

+ weston_tablet_tool_cursor_move(tool, x, y);
+
current_view = weston_compositor_pick_view(tool->seat->compositor,
x, y, &sx, &sy);
if (current_view != tool->focus)
@@ -933,6 +941,29 @@ static struct weston_tablet_tool_grab_interface default_tablet_tool_grab_interfa
default_grab_tablet_tool_cancel,
};

+static void
+tablet_tool_unmap_sprite(struct weston_tablet_tool *tool)
+{
+ if (weston_surface_is_mapped(tool->sprite->surface))
+ weston_surface_unmap(tool->sprite->surface);
+
+ wl_list_remove(&tool->sprite_destroy_listener.link);
+ tool->sprite->surface->configure = NULL;
+ tool->sprite->surface->configure_private = NULL;
+ weston_view_destroy(tool->sprite);
+ tool->sprite = NULL;
+}
+
+static void
+tablet_tool_handle_sprite_destroy(struct wl_listener *listener, void *data)
+{
+ struct weston_tablet_tool *tool =
+ container_of(listener, struct weston_tablet_tool,
+ sprite_destroy_listener);
+
+ tool->sprite = NULL;
+}
+
WL_EXPORT struct weston_tablet_tool *
weston_tablet_tool_create(void)
{
@@ -945,6 +976,9 @@ weston_tablet_tool_create(void)
wl_list_init(&tool->resource_list);
wl_list_init(&tool->focus_resource_list);

+ wl_list_init(&tool->sprite_destroy_listener.link);
+ tool->sprite_destroy_listener.notify = tablet_tool_handle_sprite_destroy;
+
wl_list_init(&tool->focus_view_listener.link);
tool->focus_view_listener.notify = tablet_tool_focus_view_destroyed;

@@ -963,6 +997,9 @@ weston_tablet_tool_destroy(struct weston_tablet_tool *tool)
{
struct wl_resource *resource, *tmp;

+ if (tool->sprite)
+ tablet_tool_unmap_sprite(tool);
+
wl_resource_for_each_safe(resource, tmp, &tool->resource_list)
zwp_tablet_tool1_send_removed(resource);

@@ -970,6 +1007,48 @@ weston_tablet_tool_destroy(struct weston_tablet_tool *tool)
free(tool);
}

+WL_EXPORT void
+weston_tablet_tool_clamp(struct weston_tablet_tool *tool,
+ wl_fixed_t *fx, wl_fixed_t *fy)
+{
+ struct weston_output *output = tool->current_tablet->output;
+ int x, y;
+
+ x = wl_fixed_to_int(*fx);
+ y = wl_fixed_to_int(*fy);
+
+ if (x < output->x)
+ *fx = wl_fixed_from_int(output->x);
+ else if (x >= output->x + output->width)
+ *fx = wl_fixed_from_int(output->x + output->width - 1);
+
+ if (y < output->y)
+ *fy = wl_fixed_from_int(output->y);
+ else if (y >= output->y + output->height)
+ *fy = wl_fixed_from_int(output->y + output->height - 1);
+}
+
+WL_EXPORT void
+weston_tablet_tool_cursor_move(struct weston_tablet_tool *tool,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ int32_t ix, iy;
+
+ weston_tablet_tool_clamp(tool, &x, &y);
+ tool->x = x;
+ tool->y = y;
+
+ ix = wl_fixed_to_int(x);
+ iy = wl_fixed_to_int(y);
+
+ if (tool->sprite) {
+ weston_view_set_position(tool->sprite,
+ ix - tool->hotspot_x,
+ iy - tool->hotspot_y);
+ weston_view_schedule_repaint(tool->sprite);
+ }
+}

static void
seat_send_updated_caps(struct weston_seat *seat)
@@ -2034,10 +2113,86 @@ notify_tablet_added(struct weston_tablet *tablet)
}

static void
+tablet_tool_cursor_surface_configure(struct weston_surface *es,
+ int32_t dx, int32_t dy)
+{
+ struct weston_tablet_tool *tool = es->configure_private;
+ int x, y;
+
+ if (es->width == 0)
+ return;
+
+ assert(es == tool->sprite->surface);
+
+ tool->hotspot_x -= dx;
+ tool->hotspot_y -= dy;
+
+ x = wl_fixed_to_int(tool->x) - tool->hotspot_x;
+ y = wl_fixed_to_int(tool->y) - tool->hotspot_y;
+
+ weston_view_set_position(tool->sprite, x, y);
+
+ empty_region(&es->pending.input);
+ empty_region(&es->input);
+
+ if (!weston_surface_is_mapped(es)) {
+ weston_layer_entry_insert(
+ &es->compositor->cursor_layer.view_list,
+ &tool->sprite->layer_link);
+ weston_view_update_transform(tool->sprite);
+ }
+}
+
+static void
tablet_tool_set_cursor(struct wl_client *client, struct wl_resource *resource,
uint32_t serial, struct wl_resource *surface_resource,
int32_t hotspot_x, int32_t hotspot_y)
{
+ struct weston_tablet_tool *tool = wl_resource_get_user_data(resource);
+ struct weston_surface *surface = NULL;
+
+ if (surface_resource)
+ surface = wl_resource_get_user_data(surface_resource);
+
+ if (tool->focus == NULL)
+ return;
+
+ /* tablet->focus->surface->resource can be NULL. Surfaces like the
+ * black_surface used in shell.c for fullscreen don't have
+ * a resource, but can still have focus */
+ if (tool->focus->surface->resource == NULL)
+ return;
+
+ if (wl_resource_get_client(tool->focus->surface->resource) != client)
+ return;
+
+ if (tool->focus_serial - serial > UINT32_MAX / 2)
+ return;
+
+ if (surface && tool->sprite && surface != tool->sprite->surface &&
+ surface->configure) {
+ wl_resource_post_error(surface->resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "surface->configure already set");
+ return;
+ }
+
+ if (tool->sprite)
+ tablet_tool_unmap_sprite(tool);
+
+ if (!surface)
+ return;
+
+ wl_signal_add(&surface->destroy_signal,
+ &tool->sprite_destroy_listener);
+ surface->configure = tablet_tool_cursor_surface_configure;
+ surface->configure_private = tool;
+ tool->sprite = weston_view_create(surface);
+ tool->hotspot_x = hotspot_x;
+ tool->hotspot_y = hotspot_y;
+
+ if (surface->buffer_ref.buffer)
+ tablet_tool_cursor_surface_configure(surface, 0, 0);
}

static void
--
2.4.3
Bill Spitzak
2015-11-06 23:24:37 UTC
Permalink
This looks like you are having the compositor maintain several cursors per
seat, and switching them when different tools are used.

That is wrong. The client is responsible for setting the cursor. Any cursor
changes by the compositor will only lead to flashing or blinking or other
incorrect renderings, in cases where the compositor chooses a cursor that
is not equal to the current cursor and also not equal to the cursor the
client actually wants. That is why wayland does not set cursors on enter
events, and why it should not set the cursor here either.

Strong NAK
Post by Peter Hutterer
The tablet is given a separate cursor. Most tablet interaction is an absolute
interaction and shouldn't need a cursor at all, but usually the cursor is used
to indicate the type of virtual tool currently assigned.
---
src/compositor.c | 6 +++
src/compositor.h | 13 +++++
src/input.c | 157
++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 175 insertions(+), 1 deletion(-)
diff --git a/src/compositor.c b/src/compositor.c
index 8eadf8c..7777291 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1759,6 +1759,7 @@ weston_view_unmap(struct weston_view *view)
struct weston_pointer *pointer =
weston_seat_get_pointer(seat);
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
+ struct weston_tablet_tool *tool;
if (keyboard && keyboard->focus == view->surface)
weston_keyboard_set_focus(keyboard, NULL);
@@ -1766,6 +1767,11 @@ weston_view_unmap(struct weston_view *view)
weston_pointer_clear_focus(pointer);
if (touch && touch->focus == view)
weston_touch_set_focus(touch, NULL);
+
+ wl_list_for_each(tool, &seat->tablet_tool_list, link) {
+ if (tool->focus == view)
+ weston_tablet_tool_set_focus(tool, NULL,
0);
+ }
}
}
diff --git a/src/compositor.h b/src/compositor.h
index ce084c8..2eaadf4 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -432,6 +432,12 @@ struct weston_tablet_tool {
int button_count;
bool tip_is_down;
+
+ int32_t hotspot_x, hotspot_y;
+ struct weston_view *sprite;
+ struct wl_listener sprite_destroy_listener;
+
+ wl_fixed_t x, y;
};
struct weston_tablet {
@@ -531,6 +537,13 @@ void
weston_tablet_tool_end_grab(struct weston_tablet_tool *tool);
void
+weston_tablet_tool_clamp(struct weston_tablet_tool *tool,
+ wl_fixed_t *fx, wl_fixed_t *fy);
+void
+weston_tablet_tool_cursor_move(struct weston_tablet_tool *tool,
+ wl_fixed_t x, wl_fixed_t y);
+
+void
wl_data_device_set_keyboard_focus(struct weston_seat *seat);
int
diff --git a/src/input.c b/src/input.c
index 6139b31..69806e2 100644
--- a/src/input.c
+++ b/src/input.c
@@ -781,7 +781,13 @@ static void
default_grab_tablet_tool_proximity_out(struct weston_tablet_tool_grab *grab,
uint32_t time)
{
- weston_tablet_tool_set_focus(grab->tool, NULL, time);
+ struct weston_tablet_tool *tool = grab->tool;
+
+ weston_tablet_tool_set_focus(tool, NULL, time);
+
+ /* Hide the cursor */
+ if (weston_surface_is_mapped(tool->sprite->surface))
+ weston_surface_unmap(tool->sprite->surface);
}
static void
@@ -796,6 +802,8 @@ default_grab_tablet_tool_motion(struct
weston_tablet_tool_grab *grab,
struct wl_resource *resource;
struct wl_list *resource_list = &tool->focus_resource_list;
+ weston_tablet_tool_cursor_move(tool, x, y);
+
current_view = weston_compositor_pick_view(tool->seat->compositor,
x, y, &sx, &sy);
if (current_view != tool->focus)
@@ -933,6 +941,29 @@ static struct weston_tablet_tool_grab_interface
default_tablet_tool_grab_interfa
default_grab_tablet_tool_cancel,
};
+static void
+tablet_tool_unmap_sprite(struct weston_tablet_tool *tool)
+{
+ if (weston_surface_is_mapped(tool->sprite->surface))
+ weston_surface_unmap(tool->sprite->surface);
+
+ wl_list_remove(&tool->sprite_destroy_listener.link);
+ tool->sprite->surface->configure = NULL;
+ tool->sprite->surface->configure_private = NULL;
+ weston_view_destroy(tool->sprite);
+ tool->sprite = NULL;
+}
+
+static void
+tablet_tool_handle_sprite_destroy(struct wl_listener *listener, void *data)
+{
+ struct weston_tablet_tool *tool =
+ container_of(listener, struct weston_tablet_tool,
+ sprite_destroy_listener);
+
+ tool->sprite = NULL;
+}
+
WL_EXPORT struct weston_tablet_tool *
weston_tablet_tool_create(void)
{
@@ -945,6 +976,9 @@ weston_tablet_tool_create(void)
wl_list_init(&tool->resource_list);
wl_list_init(&tool->focus_resource_list);
+ wl_list_init(&tool->sprite_destroy_listener.link);
+ tool->sprite_destroy_listener.notify =
tablet_tool_handle_sprite_destroy;
+
wl_list_init(&tool->focus_view_listener.link);
tool->focus_view_listener.notify =
tablet_tool_focus_view_destroyed;
@@ -963,6 +997,9 @@ weston_tablet_tool_destroy(struct weston_tablet_tool *tool)
{
struct wl_resource *resource, *tmp;
+ if (tool->sprite)
+ tablet_tool_unmap_sprite(tool);
+
wl_resource_for_each_safe(resource, tmp, &tool->resource_list)
zwp_tablet_tool1_send_removed(resource);
@@ -970,6 +1007,48 @@ weston_tablet_tool_destroy(struct weston_tablet_tool *tool)
free(tool);
}
+WL_EXPORT void
+weston_tablet_tool_clamp(struct weston_tablet_tool *tool,
+ wl_fixed_t *fx, wl_fixed_t *fy)
+{
+ struct weston_output *output = tool->current_tablet->output;
+ int x, y;
+
+ x = wl_fixed_to_int(*fx);
+ y = wl_fixed_to_int(*fy);
+
+ if (x < output->x)
+ *fx = wl_fixed_from_int(output->x);
+ else if (x >= output->x + output->width)
+ *fx = wl_fixed_from_int(output->x + output->width - 1);
+
+ if (y < output->y)
+ *fy = wl_fixed_from_int(output->y);
+ else if (y >= output->y + output->height)
+ *fy = wl_fixed_from_int(output->y + output->height - 1);
+}
+
+WL_EXPORT void
+weston_tablet_tool_cursor_move(struct weston_tablet_tool *tool,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ int32_t ix, iy;
+
+ weston_tablet_tool_clamp(tool, &x, &y);
+ tool->x = x;
+ tool->y = y;
+
+ ix = wl_fixed_to_int(x);
+ iy = wl_fixed_to_int(y);
+
+ if (tool->sprite) {
+ weston_view_set_position(tool->sprite,
+ ix - tool->hotspot_x,
+ iy - tool->hotspot_y);
+ weston_view_schedule_repaint(tool->sprite);
+ }
+}
static void
seat_send_updated_caps(struct weston_seat *seat)
@@ -2034,10 +2113,86 @@ notify_tablet_added(struct weston_tablet *tablet)
}
static void
+tablet_tool_cursor_surface_configure(struct weston_surface *es,
+ int32_t dx, int32_t dy)
+{
+ struct weston_tablet_tool *tool = es->configure_private;
+ int x, y;
+
+ if (es->width == 0)
+ return;
+
+ assert(es == tool->sprite->surface);
+
+ tool->hotspot_x -= dx;
+ tool->hotspot_y -= dy;
+
+ x = wl_fixed_to_int(tool->x) - tool->hotspot_x;
+ y = wl_fixed_to_int(tool->y) - tool->hotspot_y;
+
+ weston_view_set_position(tool->sprite, x, y);
+
+ empty_region(&es->pending.input);
+ empty_region(&es->input);
+
+ if (!weston_surface_is_mapped(es)) {
+ weston_layer_entry_insert(
+ &es->compositor->cursor_layer.view_list,
+ &tool->sprite->layer_link);
+ weston_view_update_transform(tool->sprite);
+ }
+}
+
+static void
tablet_tool_set_cursor(struct wl_client *client, struct wl_resource *resource,
uint32_t serial, struct wl_resource
*surface_resource,
int32_t hotspot_x, int32_t hotspot_y)
{
+ struct weston_tablet_tool *tool =
wl_resource_get_user_data(resource);
+ struct weston_surface *surface = NULL;
+
+ if (surface_resource)
+ surface = wl_resource_get_user_data(surface_resource);
+
+ if (tool->focus == NULL)
+ return;
+
+ /* tablet->focus->surface->resource can be NULL. Surfaces like the
+ * black_surface used in shell.c for fullscreen don't have
+ * a resource, but can still have focus */
+ if (tool->focus->surface->resource == NULL)
+ return;
+
+ if (wl_resource_get_client(tool->focus->surface->resource) !=
client)
+ return;
+
+ if (tool->focus_serial - serial > UINT32_MAX / 2)
+ return;
+
+ if (surface && tool->sprite && surface != tool->sprite->surface &&
+ surface->configure) {
+ wl_resource_post_error(surface->resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "surface->configure already set");
+ return;
+ }
+
+ if (tool->sprite)
+ tablet_tool_unmap_sprite(tool);
+
+ if (!surface)
+ return;
+
+ wl_signal_add(&surface->destroy_signal,
+ &tool->sprite_destroy_listener);
+ surface->configure = tablet_tool_cursor_surface_configure;
+ surface->configure_private = tool;
+ tool->sprite = weston_view_create(surface);
+ tool->hotspot_x = hotspot_x;
+ tool->hotspot_y = hotspot_y;
+
+ if (surface->buffer_ref.buffer)
+ tablet_tool_cursor_surface_configure(surface, 0, 0);
}
static void
--
2.4.3
_______________________________________________
wayland-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Peter Hutterer
2015-11-06 04:31:14 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
clients/window.c | 472 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
clients/window.h | 78 +++++++++
2 files changed, 550 insertions(+)

diff --git a/clients/window.c b/clients/window.c
index f9797a2..25be12f 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -70,6 +70,7 @@ typedef void *EGLContext;
#include "shared/helpers.h"
#include "xdg-shell-unstable-v5-client-protocol.h"
#include "text-cursor-position-client-protocol.h"
+#include "tablet-unstable-v1-client-protocol.h"
#include "shared/os-compatibility.h"

#include "window.h"
@@ -96,6 +97,7 @@ struct display {
struct wl_data_device_manager *data_device_manager;
struct text_cursor_position *text_cursor_position;
struct xdg_shell *xdg_shell;
+ struct zwp_tablet_manager1 *tablet_manager;
struct ivi_application *ivi_application; /* ivi style shell */
EGLDisplay dpy;
EGLConfig argb_config;
@@ -138,6 +140,34 @@ struct display {
int data_device_manager_version;
};

+struct tablet {
+ struct zwp_tablet1 *tablet;
+ char *name;
+ int32_t vid;
+ int32_t pid;
+ enum zwp_tablet1_type type;
+
+ void *user_data;
+
+ struct wl_list link;
+};
+
+struct tablet_tool {
+ struct zwp_tablet_tool1 *tool;
+ struct input *input;
+ void *user_data;
+ struct wl_list link;
+ struct tablet *current_tablet;
+ struct window *focus;
+ struct widget *focus_widget;
+
+ enum zwp_tablet_tool1_type type;
+ uint64_t serial;
+ uint64_t hwid;
+
+ double sx, sy;
+};
+
struct window_output {
struct output *output;
struct wl_list link;
@@ -282,6 +312,16 @@ 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_tablet_tool_motion_handler_t tablet_tool_motion_handler;
+ widget_tablet_tool_up_handler_t tablet_tool_up_handler;
+ widget_tablet_tool_down_handler_t tablet_tool_down_handler;
+ widget_tablet_tool_pressure_handler_t tablet_tool_pressure_handler;
+ widget_tablet_tool_distance_handler_t tablet_tool_distance_handler;
+ widget_tablet_tool_tilt_handler_t tablet_tool_tilt_handler;
+ widget_tablet_tool_proximity_in_handler_t tablet_tool_prox_in_handler;
+ widget_tablet_tool_proximity_out_handler_t tablet_tool_prox_out_handler;
+ widget_tablet_tool_button_handler_t tablet_tool_button_handler;
+ widget_tablet_tool_frame_handler_t tablet_tool_frame_handler;
void *user_data;
int opaque;
int tooltip_count;
@@ -357,6 +397,10 @@ struct input {
uint32_t repeat_key;
uint32_t repeat_time;
int seat_version;
+
+ struct zwp_tablet_seat1 *tablet_seat;
+ struct wl_list tablet_list;
+ struct wl_list tablet_tool_list;
};

struct output {
@@ -1930,6 +1974,72 @@ widget_set_axis_handler(struct widget *widget,
widget->axis_handler = handler;
}

+void
+widget_set_tablet_tool_motion_handler(struct widget *widget,
+ widget_tablet_tool_motion_handler_t handler)
+{
+ widget->tablet_tool_motion_handler = handler;
+}
+
+void
+widget_set_tablet_tool_up_handler(struct widget *widget,
+ widget_tablet_tool_up_handler_t handler)
+{
+ widget->tablet_tool_up_handler = handler;
+
+}
+
+void
+widget_set_tablet_tool_down_handler(struct widget *widget,
+ widget_tablet_tool_down_handler_t handler)
+{
+ widget->tablet_tool_down_handler = handler;
+}
+
+void
+widget_set_tablet_tool_pressure_handler(struct widget *widget,
+ widget_tablet_tool_pressure_handler_t handler)
+{
+ widget->tablet_tool_pressure_handler = handler;
+}
+
+void
+widget_set_tablet_tool_distance_handler(struct widget *widget,
+ widget_tablet_tool_distance_handler_t handler)
+{
+ widget->tablet_tool_distance_handler = handler;
+}
+
+void
+widget_set_tablet_tool_tilt_handler(struct widget *widget,
+ widget_tablet_tool_tilt_handler_t handler)
+{
+ widget->tablet_tool_tilt_handler = handler;
+}
+
+void
+widget_set_tablet_tool_proximity_handlers(struct widget *widget,
+ widget_tablet_tool_proximity_in_handler_t in_handler,
+ widget_tablet_tool_proximity_out_handler_t out_handler)
+{
+ widget->tablet_tool_prox_in_handler = in_handler;
+ widget->tablet_tool_prox_out_handler = out_handler;
+}
+
+void
+widget_set_tablet_tool_button_handler(struct widget *widget,
+ widget_tablet_tool_button_handler_t handler)
+{
+ widget->tablet_tool_button_handler = handler;
+}
+
+void
+widget_set_tablet_tool_frame_handler(struct widget *widget,
+ widget_tablet_tool_frame_handler_t handler)
+{
+ widget->tablet_tool_frame_handler = handler;
+}
+
static void
window_schedule_redraw_task(struct window *window);

@@ -5199,6 +5309,9 @@ display_add_input(struct display *d, uint32_t id, int display_seat_version)
wl_list_init(&input->touch_point_list);
wl_list_insert(d->input_list.prev, &input->link);

+ wl_list_init(&input->tablet_list);
+ wl_list_init(&input->tablet_tool_list);
+
wl_seat_add_listener(input->seat, &seat_listener, input);
wl_seat_set_user_data(input->seat, input);

@@ -5302,6 +5415,363 @@ static_assert(XDG_VERSION == XDG_SHELL_VERSION_CURRENT,
#endif

static void
+tablet_handle_name(void *data, struct zwp_tablet1 *zwp_tablet1, const char *name)
+{
+ struct tablet *tablet = data;
+
+ tablet->name = xstrdup(name);
+}
+
+static void
+tablet_handle_id(void *data, struct zwp_tablet1 *zwp_tablet1,
+ uint32_t vid, uint32_t pid)
+{
+ struct tablet *tablet = data;
+
+ tablet->vid = vid;
+ tablet->pid = pid;
+}
+
+static void
+tablet_handle_type(void *data, struct zwp_tablet1 *zwp_tablet1, uint32_t type)
+{
+ struct tablet *tablet = data;
+
+ tablet->type = type;
+}
+
+static void
+tablet_handle_path(void *data, struct zwp_tablet1 *zwp_tablet1, const char *path)
+{
+}
+
+static void
+tablet_handle_done(void *data, struct zwp_tablet1 *zwp_tablet1)
+{
+}
+
+static void
+tablet_handle_removed(void *data, struct zwp_tablet1 *zwp_tablet1)
+{
+ struct tablet *tablet = data;
+
+ zwp_tablet1_destroy(zwp_tablet1);
+
+ wl_list_remove(&tablet->link);
+ free(tablet->name);
+ free(tablet);
+}
+
+static const struct zwp_tablet1_listener tablet_listener = {
+ tablet_handle_name,
+ tablet_handle_id,
+ tablet_handle_type,
+ tablet_handle_path,
+ tablet_handle_done,
+ tablet_handle_removed,
+};
+
+static void
+tablet_added(void *data, struct zwp_tablet_seat1 *zwp_tablet_seat1,
+ struct zwp_tablet1 *id)
+{
+ struct input *input = data;
+ struct tablet *tablet;
+
+ tablet = zalloc(sizeof *tablet);
+
+ zwp_tablet1_add_listener(id, &tablet_listener, tablet);
+ wl_list_insert(&input->tablet_list, &tablet->link);
+ zwp_tablet1_set_user_data(id, tablet);
+}
+
+enum zwp_tablet_tool1_type
+tablet_tool_get_type(struct tablet_tool *tool)
+{
+ return tool->type;
+}
+
+uint64_t
+tablet_tool_get_serial(struct tablet_tool *tool)
+{
+ return tool->serial;
+}
+
+uint64_t
+tablet_tool_get_hwid(struct tablet_tool *tool)
+{
+ return tool->hwid;
+}
+
+static void
+tablet_tool_handle_type(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t tool_type)
+{
+ struct tablet_tool *tool = data;
+
+ tool->type = tool_type;
+}
+
+static void
+tablet_tool_handle_serialid(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t serial_msb, uint32_t serial_lsb)
+{
+ struct tablet_tool *tool = data;
+
+ tool->serial = ((uint64_t)serial_msb << 32) | serial_lsb;
+}
+
+static void
+tablet_tool_handle_hwid(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t format, uint32_t hwid_msb, uint32_t hwid_lsb)
+{
+ struct tablet_tool *tool = data;
+
+ tool->serial = ((uint64_t)hwid_msb << 32) | hwid_lsb;
+}
+
+static void
+tablet_tool_handle_capability(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t capability)
+{
+}
+
+static void
+tablet_tool_handle_done(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1)
+{
+}
+
+static void
+tablet_tool_handle_removed(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1)
+{
+ zwp_tablet_tool1_destroy(zwp_tablet_tool1);
+}
+
+static void
+tablet_tool_set_focus_widget(struct tablet_tool *tool, struct window *window,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ struct widget *widget, *old;
+
+ widget = window_find_widget(window, sx, sy);
+ if (tool->focus_widget == widget)
+ return;
+
+ old = tool->focus_widget;
+ if (old && old->tablet_tool_prox_out_handler)
+ old->tablet_tool_prox_out_handler(old, tool,
+ widget_get_user_data(old));
+
+ if (widget && widget->tablet_tool_prox_in_handler)
+ widget->tablet_tool_prox_in_handler(widget, tool,
+ tool->current_tablet,
+ widget_get_user_data(widget));
+
+ tool->focus_widget = widget;
+}
+
+static void
+tablet_tool_handle_proximity_in(void *data,
+ struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t serial,
+ struct zwp_tablet1 *zwp_tablet1,
+ struct wl_surface *surface)
+{
+ struct tablet_tool *tool = data;
+ struct tablet *tablet = zwp_tablet1_get_user_data(zwp_tablet1);
+ struct window *window;
+
+ window = wl_surface_get_user_data(surface);
+ if (surface != window->main_surface->surface)
+ return;
+
+ tool->focus = window;
+ tool->current_tablet = tablet;
+}
+
+static void
+tablet_tool_handle_proximity_out(void *data,
+ struct zwp_tablet_tool1 *zwp_tablet_tool1)
+{
+ struct tablet_tool *tool = data;
+
+ tool->focus = NULL;
+ tool->current_tablet = NULL;
+}
+
+static void
+tablet_tool_handle_down(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t serial)
+{
+ struct tablet_tool *tool = data;
+ struct widget *focus = tool->focus_widget;
+
+ tool->input->display->serial = serial;
+
+ if (focus && focus->tablet_tool_down_handler)
+ focus->tablet_tool_down_handler(focus, tool, focus->user_data);
+}
+
+static void
+tablet_tool_handle_up(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1)
+{
+ struct tablet_tool *tool = data;
+ struct widget *focus = tool->focus_widget;
+
+ if (focus && focus->tablet_tool_up_handler)
+ focus->tablet_tool_up_handler(focus, tool, focus->user_data);
+}
+
+static void
+tablet_tool_handle_motion(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct tablet_tool *tool = data;
+ double sx = wl_fixed_to_double(x);
+ double sy = wl_fixed_to_double(y);
+ struct window *window = tool->focus;
+ struct widget *widget;
+
+ if (!window)
+ return;
+
+ tool->sx = sx;
+ tool->sy = sy;
+
+ if (sx > window->main_surface->allocation.width ||
+ sy > window->main_surface->allocation.height)
+ return;
+
+ tablet_tool_set_focus_widget(tool, window, sx, sy);
+ widget = tool->focus_widget;
+ if (widget && widget->tablet_tool_motion_handler) {
+ widget->tablet_tool_motion_handler(widget, tool, sx, sy,
+ widget->user_data);
+ }
+}
+
+static void
+tablet_tool_handle_pressure(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t pressure)
+{
+ struct tablet_tool *tool = data;
+ struct widget *widget = tool->focus_widget;
+
+ if (widget && widget->tablet_tool_pressure_handler)
+ widget->tablet_tool_pressure_handler(widget, tool, pressure,
+ widget->user_data);
+}
+
+static void
+tablet_tool_handle_distance(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t distance)
+{
+ struct tablet_tool *tool = data;
+ struct widget *widget = tool->focus_widget;
+
+ if (widget && widget->tablet_tool_distance_handler)
+ widget->tablet_tool_distance_handler(widget, tool,
+ distance,
+ widget->user_data);
+}
+
+static void
+tablet_tool_handle_tilt(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ int32_t tilt_x, int32_t tilt_y)
+{
+ struct tablet_tool *tool = data;
+ struct widget *widget = tool->focus_widget;
+
+ if (widget && widget->tablet_tool_tilt_handler)
+ widget->tablet_tool_tilt_handler(widget, tool,
+ tilt_x, tilt_y,
+ widget->user_data);
+}
+
+static void
+tablet_tool_handle_button(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t serial, uint32_t button, uint32_t state)
+{
+ struct tablet_tool *tool = data;
+ struct widget *focus = tool->focus_widget;
+
+ tool->input->display->serial = serial;
+
+ if (focus && focus->tablet_tool_button_handler)
+ focus->tablet_tool_button_handler(focus, tool, button, state,
+ focus->user_data);
+}
+
+static void
+tablet_tool_handle_frame(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
+ uint32_t time)
+{
+ struct tablet_tool *tool = data;
+ struct widget *widget = tool->focus_widget;
+
+ if (widget && widget->tablet_tool_frame_handler)
+ widget->tablet_tool_frame_handler(widget, tool, time,
+ widget->user_data);
+}
+
+static const struct zwp_tablet_tool1_listener tablet_tool_listener = {
+ tablet_tool_handle_type,
+ tablet_tool_handle_serialid,
+ tablet_tool_handle_hwid,
+ tablet_tool_handle_capability,
+ tablet_tool_handle_done,
+ tablet_tool_handle_removed,
+ tablet_tool_handle_proximity_in,
+ tablet_tool_handle_proximity_out,
+ tablet_tool_handle_down,
+ tablet_tool_handle_up,
+ tablet_tool_handle_motion,
+ tablet_tool_handle_pressure,
+ tablet_tool_handle_distance,
+ tablet_tool_handle_tilt,
+ tablet_tool_handle_button,
+ tablet_tool_handle_frame,
+};
+
+static void
+tablet_tool_added(void *data, struct zwp_tablet_seat1 *zwp_tablet_seat1,
+ struct zwp_tablet_tool1 *id)
+{
+ struct input *input = data;
+ struct tablet_tool *tool;
+
+ tool = zalloc(sizeof *tool);
+ zwp_tablet_tool1_add_listener(id, &tablet_tool_listener, tool);
+ wl_list_insert(&input->tablet_tool_list, &tool->link);
+
+ tool->tool = id;
+ tool->input = input;
+}
+
+static const struct zwp_tablet_seat1_listener tablet_seat_listener = {
+ tablet_added,
+ tablet_tool_added,
+};
+
+static void
+display_bind_tablets(struct display *d, uint32_t id)
+{
+ struct input *input;
+
+ d->tablet_manager = wl_registry_bind(d->registry, id,
+ &zwp_tablet_manager1_interface, 1);
+
+ wl_list_for_each(input, &d->input_list, link) {
+ input->tablet_seat =
+ zwp_tablet_manager1_get_tablet_seat(d->tablet_manager,
+ input->seat);
+ zwp_tablet_seat1_add_listener(input->tablet_seat,
+ &tablet_seat_listener,
+ input);
+ }
+}
+
+static void
registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
{
@@ -5348,6 +5818,8 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
d->ivi_application =
wl_registry_bind(registry, id,
&ivi_application_interface, 1);
+ } else if (strcmp(interface, "zwp_tablet_manager1") == 0) {
+ display_bind_tablets(d, id);
}

if (d->global_handler)
diff --git a/clients/window.h b/clients/window.h
index b61a62a..a09851f 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -28,6 +28,7 @@

#include <xkbcommon/xkbcommon.h>
#include <wayland-client.h>
+#include <tablet-unstable-v1-client-protocol.h>
#include <cairo.h>
#include "shared/config-parser.h"
#include "shared/zalloc.h"
@@ -38,6 +39,8 @@ struct widget;
struct display;
struct input;
struct output;
+struct tablet;
+struct tablet_tool;

struct task {
void (*run)(struct task *task, uint32_t events);
@@ -266,6 +269,44 @@ typedef void (*widget_axis_handler_t)(struct widget *widget,
uint32_t axis,
wl_fixed_t value,
void *data);
+typedef void (*widget_tablet_tool_motion_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ float x, float y,
+ void *data);
+typedef void (*widget_tablet_tool_down_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ void *data);
+typedef void (*widget_tablet_tool_up_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ void *data);
+typedef void (*widget_tablet_tool_pressure_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ uint32_t pressure,
+ void *data);
+typedef void (*widget_tablet_tool_distance_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ uint32_t distance,
+ void *data);
+typedef void (*widget_tablet_tool_tilt_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ int32_t tilt_x, int32_t tilt_y,
+ void *data);
+typedef void (*widget_tablet_tool_proximity_in_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ struct tablet *tablet,
+ void *data);
+typedef void (*widget_tablet_tool_proximity_out_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ void *data);
+typedef void (*widget_tablet_tool_button_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ uint32_t button,
+ enum zwp_tablet_tool1_button_state state,
+ void *data);
+typedef void (*widget_tablet_tool_frame_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ uint32_t time,
+ void *data);

struct window *
window_create(struct display *display);
@@ -520,6 +561,34 @@ void
widget_set_axis_handler(struct widget *widget,
widget_axis_handler_t handler);
void
+widget_set_tablet_tool_motion_handler(struct widget *widget,
+ widget_tablet_tool_motion_handler_t handler);
+void
+widget_set_tablet_tool_up_handler(struct widget *widget,
+ widget_tablet_tool_up_handler_t handler);
+void
+widget_set_tablet_tool_down_handler(struct widget *widget,
+ widget_tablet_tool_down_handler_t handler);
+void
+widget_set_tablet_tool_pressure_handler(struct widget *widget,
+ widget_tablet_tool_pressure_handler_t handler);
+void
+widget_set_tablet_tool_distance_handler(struct widget *widget,
+ widget_tablet_tool_distance_handler_t handler);
+void
+widget_set_tablet_tool_tilt_handler(struct widget *widget,
+ widget_tablet_tool_tilt_handler_t handler);
+void
+widget_set_tablet_tool_proximity_handlers(struct widget *widget,
+ widget_tablet_tool_proximity_in_handler_t in_handler,
+ widget_tablet_tool_proximity_out_handler_t out_handler);
+void
+widget_set_tablet_tool_button_handler(struct widget *widget,
+ widget_tablet_tool_button_handler_t handler);
+void
+widget_set_tablet_tool_frame_handler(struct widget *widget,
+ widget_tablet_tool_frame_handler_t handler);
+void
widget_schedule_redraw(struct widget *widget);
void
widget_set_use_cairo(struct widget *widget, int use_cairo);
@@ -629,4 +698,13 @@ xkb_mod_mask_t
keysym_modifiers_get_mask(struct wl_array *modifiers_map,
const char *name);

+enum zwp_tablet_tool1_type
+tablet_tool_get_type(struct tablet_tool *tool);
+
+uint64_t
+tablet_tool_get_serial(struct tablet_tool *tool);
+
+uint64_t
+tablet_tool_get_hwid(struct tablet_tool *tool);
+
#endif
--
2.4.3
Peter Hutterer
2015-11-06 04:31:15 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Again, a lot of this is code that has been reused from the cursor code
for pointers.

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
clients/window.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
clients/window.h | 13 ++++--
2 files changed, 145 insertions(+), 6 deletions(-)

diff --git a/clients/window.c b/clients/window.c
index 25be12f..8ef831f 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -160,6 +160,12 @@ struct tablet_tool {
struct tablet *current_tablet;
struct window *focus;
struct widget *focus_widget;
+ uint32_t enter_serial;
+ uint32_t cursor_serial;
+ int current_cursor;
+ struct wl_surface *cursor_surface;
+ uint32_t cursor_anim_start;
+ struct wl_callback *cursor_frame_cb;

enum zwp_tablet_tool1_type type;
uint64_t serial;
@@ -326,6 +332,7 @@ struct widget {
int opaque;
int tooltip_count;
int default_cursor;
+ int default_tablet_cursor;
/* If this is set to false then no cairo surface will be
* created before redrawing the surface. This is useful if the
* redraw handler is going to do completely custom rendering
@@ -1654,6 +1661,7 @@ widget_create(struct window *window, struct surface *surface, void *data)
widget->tooltip = NULL;
widget->tooltip_count = 0;
widget->default_cursor = CURSOR_LEFT_PTR;
+ widget->default_tablet_cursor = CURSOR_LEFT_PTR;
widget->use_cairo = 1;

return widget;
@@ -1712,6 +1720,12 @@ widget_set_default_cursor(struct widget *widget, int cursor)
}

void
+widget_set_default_tablet_cursor(struct widget *widget, int cursor)
+{
+ widget->default_tablet_cursor = cursor;
+}
+
+void
widget_get_allocation(struct widget *widget, struct rectangle *allocation)
{
*allocation = widget->allocation;
@@ -5547,6 +5561,117 @@ tablet_tool_handle_removed(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1
zwp_tablet_tool1_destroy(zwp_tablet_tool1);
}

+static const struct wl_callback_listener tablet_tool_cursor_surface_listener;
+
+static void
+tablet_tool_set_cursor_image_index(struct tablet_tool *tool, int index)
+{
+ struct wl_buffer *buffer;
+ struct wl_cursor *cursor;
+ struct wl_cursor_image *image;
+
+ cursor = tool->input->display->cursors[tool->current_cursor];
+ if (index >= (int)cursor->image_count) {
+ fprintf(stderr, "cursor index out of range\n");
+ return;
+ }
+
+ image = cursor->images[index];
+ buffer = wl_cursor_image_get_buffer(image);
+ if (!buffer)
+ return;
+
+ wl_surface_attach(tool->cursor_surface, buffer, 0, 0);
+ wl_surface_damage(tool->cursor_surface, 0, 0,
+ image->width, image->height);
+ wl_surface_commit(tool->cursor_surface);
+ zwp_tablet_tool1_set_cursor(tool->tool, tool->enter_serial,
+ tool->cursor_surface,
+ image->hotspot_x, image->hotspot_y);
+}
+
+static void
+tablet_tool_surface_frame_callback(void *data, struct wl_callback *callback,
+ uint32_t time)
+{
+ struct tablet_tool *tool = data;
+ struct wl_cursor *cursor;
+ int i;
+
+ if (callback) {
+ assert(callback == tool->cursor_frame_cb);
+ wl_callback_destroy(callback);
+ tool->cursor_frame_cb = NULL;
+ }
+
+ if (tool->current_cursor == CURSOR_BLANK) {
+ zwp_tablet_tool1_set_cursor(tool->tool, tool->enter_serial,
+ NULL, 0, 0);
+ return;
+ }
+
+ if (tool->current_cursor == CURSOR_UNSET)
+ return;
+
+ cursor = tool->input->display->cursors[tool->current_cursor];
+ if (!cursor)
+ return;
+
+ /* FIXME We don't have the current time on the first call so we set
+ * the animation start to the time of the first frame callback. */
+ if (time == 0)
+ tool->cursor_anim_start = 0;
+ else if (tool->cursor_anim_start == 0)
+ tool->cursor_anim_start = time;
+
+ if (time == 0 || tool->cursor_anim_start == 0)
+ i = 0;
+ else
+ i = wl_cursor_frame(cursor, time - tool->cursor_anim_start);
+
+ if (cursor->image_count > 1) {
+ tool->cursor_frame_cb =
+ wl_surface_frame(tool->cursor_surface);
+ wl_callback_add_listener(tool->cursor_frame_cb,
+ &tablet_tool_cursor_surface_listener,
+ tool);
+ }
+
+ tablet_tool_set_cursor_image_index(tool, i);
+}
+
+static const struct wl_callback_listener tablet_tool_cursor_surface_listener = {
+ tablet_tool_surface_frame_callback,
+};
+
+void
+tablet_tool_set_cursor_image(struct tablet_tool *tool, int cursor)
+{
+ bool force = false;
+
+ if (tool->enter_serial > tool->cursor_serial)
+ force = true;
+
+ if (!force && cursor == tool->current_cursor)
+ return;
+
+ tool->current_cursor = cursor;
+ tool->cursor_serial = tool->enter_serial;
+
+ if (!tool->cursor_frame_cb)
+ tablet_tool_surface_frame_callback(tool, NULL, 0);
+ else if (force) {
+ /* The current frame callback may be stuck if, for instance,
+ * the set cursor request was processed by the server after
+ * this client lost the focus. In this case the cursor surface
+ * might not be mapped and the frame callback wouldn't ever
+ * complete. Send a set_cursor and attach to try to map the
+ * cursor surface again so that the callback will finish
+ */
+ tablet_tool_set_cursor_image_index(tool, 0);
+ }
+}
+
static void
tablet_tool_set_focus_widget(struct tablet_tool *tool, struct window *window,
wl_fixed_t sx, wl_fixed_t sy)
@@ -5587,6 +5712,7 @@ tablet_tool_handle_proximity_in(void *data,

tool->focus = window;
tool->current_tablet = tablet;
+ tool->enter_serial = serial;
}

static void
@@ -5631,6 +5757,7 @@ tablet_tool_handle_motion(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
double sy = wl_fixed_to_double(y);
struct window *window = tool->focus;
struct widget *widget;
+ int cursor;

if (!window)
return;
@@ -5645,9 +5772,14 @@ tablet_tool_handle_motion(void *data, struct zwp_tablet_tool1 *zwp_tablet_tool1,
tablet_tool_set_focus_widget(tool, window, sx, sy);
widget = tool->focus_widget;
if (widget && widget->tablet_tool_motion_handler) {
- widget->tablet_tool_motion_handler(widget, tool, sx, sy,
- widget->user_data);
+ cursor = widget->tablet_tool_motion_handler(widget, tool,
+ sx, sy,
+ widget->user_data);
+ } else {
+ cursor = widget->default_tablet_cursor;
}
+
+ tablet_tool_set_cursor_image(tool, cursor);
}

static void
@@ -5746,6 +5878,8 @@ tablet_tool_added(void *data, struct zwp_tablet_seat1 *zwp_tablet_seat1,

tool->tool = id;
tool->input = input;
+ tool->cursor_surface =
+ wl_compositor_create_surface(input->display->compositor);
}

static const struct zwp_tablet_seat1_listener tablet_seat_listener = {
diff --git a/clients/window.h b/clients/window.h
index a09851f..f1188b4 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -269,10 +269,10 @@ typedef void (*widget_axis_handler_t)(struct widget *widget,
uint32_t axis,
wl_fixed_t value,
void *data);
-typedef void (*widget_tablet_tool_motion_handler_t)(struct widget *widget,
- struct tablet_tool *tool,
- float x, float y,
- void *data);
+typedef int (*widget_tablet_tool_motion_handler_t)(struct widget *widget,
+ struct tablet_tool *tool,
+ float x, float y,
+ void *data);
typedef void (*widget_tablet_tool_down_handler_t)(struct widget *widget,
struct tablet_tool *tool,
void *data);
@@ -497,6 +497,8 @@ widget_destroy(struct widget *widget);
void
widget_set_default_cursor(struct widget *widget, int cursor);
void
+widget_set_default_tablet_cursor(struct widget *widget, int cursor);
+void
widget_get_allocation(struct widget *widget, struct rectangle *allocation);

void
@@ -707,4 +709,7 @@ tablet_tool_get_serial(struct tablet_tool *tool);
uint64_t
tablet_tool_get_hwid(struct tablet_tool *tool);

+void
+tablet_tool_set_cursor_image(struct tablet_tool *tool, int cursor);
+
#endif
--
2.4.3
Peter Hutterer
2015-11-06 04:31:16 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

When it comes to a window frame, a tablet tool and cursor act almost
identical; they click things, drag things, etc. The tool type and extra
axes don't serve any use in the context of a window frame, so tablet
pointers share the frame_pointer structures used for the mouse pointer.

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
clients/window.c | 20 ++++++++++++++++++++
shared/cairo-util.h | 4 ++++
shared/frame.c | 38 ++++++++++++++++++++++++++++++++++++++
3 files changed, 62 insertions(+)

diff --git a/clients/window.c b/clients/window.c
index 8ef831f..abfc223 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -2580,6 +2580,24 @@ frame_touch_up_handler(struct widget *widget,
frame_handle_status(frame, input, time, THEME_LOCATION_CLIENT_AREA);
}

+static int
+frame_tablet_tool_motion_handler(struct widget *widget,
+ struct tablet_tool *tool,
+ float x, float y,
+ void *data)
+{
+ struct window_frame *frame = data;
+ enum theme_location location;
+
+ location = frame_tablet_tool_motion(frame->frame, tool, x, y);
+ if (frame_status(frame->frame) & FRAME_STATUS_REPAINT)
+ widget_schedule_redraw(frame->widget);
+
+ frame_get_pointer_image_for_location(data, location);
+
+ return CURSOR_DEFAULT;
+}
+
struct widget *
window_frame_create(struct window *window, void *data)
{
@@ -2607,6 +2625,8 @@ window_frame_create(struct window *window, void *data)
widget_set_button_handler(frame->widget, frame_button_handler);
widget_set_touch_down_handler(frame->widget, frame_touch_down_handler);
widget_set_touch_up_handler(frame->widget, frame_touch_up_handler);
+ widget_set_tablet_tool_motion_handler(frame->widget,
+ frame_tablet_tool_motion_handler);

window->frame = frame;

diff --git a/shared/cairo-util.h b/shared/cairo-util.h
index 019424e..0150927 100644
--- a/shared/cairo-util.h
+++ b/shared/cairo-util.h
@@ -227,6 +227,10 @@ frame_double_touch_down(struct frame *frame, void *data, int32_t id,
void
frame_double_touch_up(struct frame *frame, void *data, int32_t id);

+/* May set FRAME_STATUS_REPAINT */
+enum theme_location
+frame_tablet_tool_motion(struct frame *frame, void *pointer, int x, int y);
+
void
frame_repaint(struct frame *frame, cairo_t *cr);

diff --git a/shared/frame.c b/shared/frame.c
index 4179b0a..28f53e8 100644
--- a/shared/frame.c
+++ b/shared/frame.c
@@ -920,6 +920,44 @@ frame_double_touch_up(struct frame *frame, void *data, int32_t id)
}
}

+enum theme_location
+frame_tablet_tool_motion(struct frame *frame, void *data, int x, int y)
+{
+ struct frame_pointer *tool_pointer = frame_pointer_get(frame, data);
+ struct frame_button *button,
+ *prev_button = tool_pointer->hover_button;
+ enum theme_location location;
+
+ location = theme_get_location(frame->theme, tool_pointer->x,
+ tool_pointer->y, frame->width,
+ frame->height,
+ frame->flags & FRAME_FLAG_MAXIMIZED ?
+ THEME_FRAME_MAXIMIZED : 0);
+
+ if (!tool_pointer)
+ return location;
+
+ tool_pointer->x = x;
+ tool_pointer->y = y;
+
+ button = frame_find_button(frame, x, y);
+
+ if (prev_button) {
+ if (prev_button == button)
+ /* The button hasn't changed so we're done here */
+ return location;
+ else
+ frame_button_leave(prev_button, tool_pointer);
+ }
+
+ if (button)
+ frame_button_enter(button);
+
+ tool_pointer->hover_button = button;
+
+ return location;
+}
+
void
frame_repaint(struct frame *frame, cairo_t *cr)
{
--
2.4.3
Peter Hutterer
2015-11-06 04:31:17 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Changing the pointer to the appropriate image while moving the stylus
around isn't supported yet.

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
clients/window.c | 32 ++++++
desktop-shell/shell.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/compositor.h | 6 ++
src/input.c | 11 +++
4 files changed, 316 insertions(+)

diff --git a/clients/window.c b/clients/window.c
index abfc223..d5454b5 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -2598,6 +2598,36 @@ frame_tablet_tool_motion_handler(struct widget *widget,
return CURSOR_DEFAULT;
}

+static void
+frame_tablet_tool_down_handler(struct widget *widget,
+ struct tablet_tool *tool,
+ void *data)
+{
+ struct window_frame *frame = data;
+ enum theme_location location;
+ uint32_t time = 0; /* FIXME: we should be doing this in the frame
+ handler where we have the timestamp */
+
+ /* Map a stylus touch to the left mouse button */
+ location = frame_pointer_button(frame->frame, tool, BTN_LEFT, 1);
+ frame_handle_status(frame, tool->input, time, location);
+}
+
+static void
+frame_tablet_tool_up_handler(struct widget *widget, struct tablet_tool *tool,
+ void *data)
+{
+ struct window_frame *frame = data;
+ enum theme_location location;
+ uint32_t time = 0; /* FIXME: we should be doing this in the frame
+ handler where we have the timestamp */
+
+ /* Map the stylus leaving contact with the tablet as releasing the left
+ * mouse button */
+ location = frame_pointer_button(frame->frame, tool, BTN_LEFT, 0);
+ frame_handle_status(frame, tool->input, time, location);
+}
+
struct widget *
window_frame_create(struct window *window, void *data)
{
@@ -2627,6 +2657,8 @@ window_frame_create(struct window *window, void *data)
widget_set_touch_up_handler(frame->widget, frame_touch_up_handler);
widget_set_tablet_tool_motion_handler(frame->widget,
frame_tablet_tool_motion_handler);
+ widget_set_tablet_tool_down_handler(frame->widget, frame_tablet_tool_down_handler);
+ widget_set_tablet_tool_up_handler(frame->widget, frame_tablet_tool_up_handler);

window->frame = frame;

diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 352ab23..5b604a5 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -195,6 +195,13 @@ struct shell_touch_grab {
struct weston_touch *touch;
};

+struct shell_tablet_tool_grab {
+ struct weston_tablet_tool_grab grab;
+ struct shell_surface *shsurf;
+ struct wl_listener shsurf_destroy_listener;
+ struct weston_tablet_tool *tool;
+};
+
struct weston_move_grab {
struct shell_grab base;
wl_fixed_t dx, dy;
@@ -207,6 +214,11 @@ struct weston_touch_move_grab {
wl_fixed_t dx, dy;
};

+struct weston_tablet_tool_move_grab {
+ struct shell_tablet_tool_grab base;
+ wl_fixed_t dx, dy;
+};
+
struct rotate_grab {
struct shell_grab base;
struct weston_matrix rotation;
@@ -224,6 +236,7 @@ struct shell_seat {
struct wl_listener caps_changed_listener;
struct wl_listener pointer_focus_listener;
struct wl_listener keyboard_focus_listener;
+ struct wl_listener tablet_tool_added_listener;

struct {
struct weston_pointer_grab grab;
@@ -235,6 +248,11 @@ struct shell_seat {
} popup_grab;
};

+struct tablet_tool_listener {
+ struct wl_listener base;
+ struct wl_listener removed_listener;
+};
+
struct shell_client {
struct wl_resource *resource;
struct wl_client *client;
@@ -595,6 +613,43 @@ shell_touch_grab_end(struct shell_touch_grab *grab)
}

static void
+shell_tablet_tool_grab_start(struct shell_tablet_tool_grab *grab,
+ const struct weston_tablet_tool_grab_interface *interface,
+ struct shell_surface *shsurf,
+ struct weston_tablet_tool *tool)
+{
+ struct desktop_shell *shell = shsurf->shell;
+
+ if (tool->seat->pointer_state)
+ popup_grab_end(tool->seat->pointer_state);
+
+ grab->grab.interface = interface;
+ grab->shsurf = shsurf;
+ grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
+ wl_signal_add(&shsurf->destroy_signal, &grab->shsurf_destroy_listener);
+
+ grab->tool = tool;
+ shsurf->grabbed = 1;
+
+ weston_tablet_tool_start_grab(tool, &grab->grab);
+ if (shell->child.desktop_shell)
+ weston_tablet_tool_set_focus(tool,
+ get_default_view(shell->grab_surface),
+ 0);
+}
+
+static void
+shell_tablet_tool_grab_end(struct shell_tablet_tool_grab *grab)
+{
+ if (grab->shsurf) {
+ wl_list_remove(&grab->shsurf_destroy_listener.link);
+ grab->shsurf->grabbed = 0;
+ }
+
+ weston_tablet_tool_end_grab(grab->tool);
+}
+
+static void
center_on_output(struct weston_view *view,
struct weston_output *output);

@@ -1716,6 +1771,138 @@ surface_move(struct shell_surface *shsurf, struct weston_pointer *pointer,
}

static void
+tablet_tool_noop_grab_proximity_in(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ struct weston_tablet *tablet)
+{
+}
+
+static void
+tablet_tool_move_grab_proximity_out(struct weston_tablet_tool_grab *grab, uint32_t time)
+{
+ struct weston_tablet_tool_move_grab *move =
+ (struct weston_tablet_tool_move_grab *)grab;
+
+ shell_tablet_tool_grab_end(&move->base);
+ free(grab);
+}
+
+static void
+tablet_tool_move_grab_up(struct weston_tablet_tool_grab *grab, uint32_t time)
+{
+ struct weston_tablet_tool_move_grab *move =
+ (struct weston_tablet_tool_move_grab *)grab;
+
+ shell_tablet_tool_grab_end(&move->base);
+ free(grab);
+}
+
+static void
+tablet_tool_noop_grab_down(struct weston_tablet_tool_grab *grab, uint32_t time)
+{
+}
+
+static void
+tablet_tool_move_grab_motion(struct weston_tablet_tool_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct weston_tablet_tool_move_grab *move =
+ (struct weston_tablet_tool_move_grab *)grab;
+ struct shell_surface *shsurf = move->base.shsurf;
+
+ if (!shsurf)
+ return;
+
+ weston_tablet_tool_cursor_move(grab->tool, x, y);
+ weston_view_set_position(shsurf->view,
+ wl_fixed_to_double(x + move->dx),
+ wl_fixed_to_double(y + move->dy));
+ weston_compositor_schedule_repaint(shsurf->surface->compositor);
+}
+
+static void
+tablet_tool_noop_grab_pressure(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ uint32_t pressure)
+{
+}
+
+static void
+tablet_tool_noop_grab_distance(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ uint32_t distance)
+{
+}
+
+static void
+tablet_tool_noop_grab_tilt(struct weston_tablet_tool_grab *grab,
+ uint32_t time,
+ int32_t tilt_x, int32_t tilt_y)
+{
+}
+
+static void tablet_tool_noop_grab_button(struct weston_tablet_tool_grab *grab,
+ uint32_t time, uint32_t button,
+ enum zwp_tablet_tool1_button_state state)
+{
+}
+
+static void
+tablet_tool_noop_grab_frame(struct weston_tablet_tool_grab *grab,
+ uint32_t time)
+{
+}
+
+static void
+tablet_tool_move_grab_cancel(struct weston_tablet_tool_grab *grab)
+{
+ struct weston_tablet_tool_move_grab *move =
+ (struct weston_tablet_tool_move_grab *)grab;
+
+ shell_tablet_tool_grab_end(&move->base);
+ free(grab);
+}
+
+static struct weston_tablet_tool_grab_interface tablet_tool_move_grab_interface = {
+ tablet_tool_noop_grab_proximity_in,
+ tablet_tool_move_grab_proximity_out,
+ tablet_tool_move_grab_motion,
+ tablet_tool_noop_grab_down,
+ tablet_tool_move_grab_up,
+ tablet_tool_noop_grab_pressure,
+ tablet_tool_noop_grab_distance,
+ tablet_tool_noop_grab_tilt,
+ tablet_tool_noop_grab_button,
+ tablet_tool_noop_grab_frame,
+ tablet_tool_move_grab_cancel,
+};
+
+static int
+surface_tablet_tool_move(struct shell_surface *shsurf, struct weston_tablet_tool *tool)
+{
+ struct weston_tablet_tool_move_grab *move;
+
+ if (!shsurf)
+ return -1;
+
+ if (shsurf->state.fullscreen || shsurf->state.maximized)
+ return 0;
+
+ move = malloc(sizeof(*move));
+ if (!move)
+ return -1;
+
+ move->dx = wl_fixed_from_double(shsurf->view->geometry.x) - tool->grab_x;
+ move->dy = wl_fixed_from_double(shsurf->view->geometry.y) - tool->grab_y;
+
+ shell_tablet_tool_grab_start(&move->base, &tablet_tool_move_grab_interface,
+ shsurf, tool);
+
+ return 0;
+}
+
+
+static void
common_surface_move(struct wl_resource *resource,
struct wl_resource *seat_resource, uint32_t serial)
{
@@ -1740,6 +1927,18 @@ common_surface_move(struct wl_resource *resource,
if ((surface == shsurf->surface) &&
(surface_touch_move(shsurf, touch) < 0))
wl_resource_post_no_memory(resource);
+ } else if (!wl_list_empty(&seat->tablet_tool_list)) {
+ struct weston_tablet_tool *tool;
+
+ wl_list_for_each(tool, &seat->tablet_tool_list, link) {
+ if (tool->focus && tool->grab_serial == serial) {
+ surface = weston_surface_get_main_surface(
+ tool->focus->surface);
+ if (surface == shsurf->surface &&
+ surface_tablet_tool_move(shsurf, tool) < 0)
+ wl_resource_post_no_memory(resource);
+ }
+ }
}
}

@@ -2146,6 +2345,22 @@ handle_pointer_focus(struct wl_listener *listener, void *data)
}

static void
+handle_tablet_tool_focus(struct wl_listener *listener, void *data)
+{
+ struct weston_tablet_tool *tool = data;
+ struct weston_view *view = tool->focus;
+ struct weston_compositor *compositor;
+ uint32_t serial;
+
+ if (!view)
+ return;
+
+ compositor = view->surface->compositor;
+ serial = wl_display_next_serial(compositor->wl_display);
+ ping_handler(view->surface, serial);
+}
+
+static void
shell_surface_lose_keyboard_focus(struct shell_surface *shsurf)
{
if (--shsurf->focus_count == 0)
@@ -3020,6 +3235,37 @@ shell_interface_resize(struct shell_surface *shsurf,
static const struct weston_pointer_grab_interface popup_grab_interface;

static void
+destroy_tablet_tool_listener(struct wl_listener *listener, void *data)
+{
+ struct tablet_tool_listener *tool_listener =
+ container_of(listener, struct tablet_tool_listener, removed_listener);
+
+ wl_list_remove(&tool_listener->removed_listener.link);
+ wl_list_remove(&tool_listener->base.link);
+ free(tool_listener);
+}
+
+static void
+handle_tablet_tool_added(struct wl_listener *listener, void *data)
+{
+ struct weston_tablet_tool *tool = data;
+ struct tablet_tool_listener *tool_listener;
+
+ tool_listener = malloc(sizeof *tool_listener);
+ if (!tool_listener) {
+ weston_log("no memory to allocate to shell seat tablet listener\n");
+ return;
+ }
+
+ tool_listener->removed_listener.notify = destroy_tablet_tool_listener;
+ wl_signal_add(&tool->removed_signal,
+ &tool_listener->removed_listener);
+
+ tool_listener->base.notify = handle_tablet_tool_focus;
+ wl_signal_add(&tool->focus_signal, &tool_listener->base);
+}
+
+static void
destroy_shell_seat(struct wl_listener *listener, void *data)
{
struct shell_seat *shseat =
@@ -3040,6 +3286,7 @@ destroy_shell_seat(struct wl_listener *listener, void *data)
}

wl_list_remove(&shseat->seat_destroy_listener.link);
+ wl_list_remove(&shseat->tablet_tool_added_listener.link);
free(shseat);
}

@@ -3077,6 +3324,7 @@ static struct shell_seat *
create_shell_seat(struct weston_seat *seat)
{
struct shell_seat *shseat;
+ struct weston_tablet_tool *tool;

shseat = calloc(1, sizeof *shseat);
if (!shseat) {
@@ -3097,6 +3345,25 @@ create_shell_seat(struct weston_seat *seat)
shseat->pointer_focus_listener.notify = handle_pointer_focus;
wl_list_init(&shseat->pointer_focus_listener.link);

+ shseat->tablet_tool_added_listener.notify = handle_tablet_tool_added;
+ wl_list_init(&shseat->tablet_tool_added_listener.link);
+
+ wl_list_for_each(tool, &seat->tablet_tool_list, link) {
+ struct tablet_tool_listener *listener = malloc(sizeof *listener);
+
+ if (!listener) {
+ weston_log("no memory to allocate to shell seat tablet listener\n");
+ break;
+ }
+
+ listener->removed_listener.notify = destroy_tablet_tool_listener;
+ wl_signal_add(&tool->removed_signal,
+ &listener->removed_listener);
+
+ listener->base.notify = handle_tablet_tool_focus;
+ wl_signal_add(&tool->focus_signal, &listener->base);
+ }
+
shseat->caps_changed_listener.notify = shell_seat_caps_changed;
wl_signal_add(&seat->updated_caps_signal,
&shseat->caps_changed_listener);
diff --git a/src/compositor.h b/src/compositor.h
index 2eaadf4..4da6bc5 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -438,6 +438,11 @@ struct weston_tablet_tool {
struct wl_listener sprite_destroy_listener;

wl_fixed_t x, y;
+
+ struct wl_signal focus_signal;
+ struct wl_signal removed_signal;
+
+ wl_fixed_t grab_x, grab_y;
};

struct weston_tablet {
@@ -659,6 +664,7 @@ struct weston_seat {
char *seat_name;

struct wl_list tablet_seat_resource_list;
+ struct wl_signal tablet_tool_added_signal;
};

enum {
diff --git a/src/input.c b/src/input.c
index 69806e2..145defd 100644
--- a/src/input.c
+++ b/src/input.c
@@ -751,6 +751,8 @@ weston_tablet_tool_set_focus(struct weston_tablet_tool *tool,
&tool->focus_resource_listener);
tool->focus = view;
tool->focus_view_listener.notify = tablet_tool_focus_view_destroyed;
+
+ wl_signal_emit(&tool->focus_signal, tool);
}

WL_EXPORT void
@@ -989,6 +991,9 @@ weston_tablet_tool_create(void)
tool->default_grab.tool = tool;
tool->grab = &tool->default_grab;

+ wl_signal_init(&tool->focus_signal);
+ wl_signal_init(&tool->removed_signal);
+
return tool;
}

@@ -2354,6 +2359,8 @@ notify_tablet_tool_down(struct weston_tablet_tool *tool,

tool->tip_is_down = true;
tool->grab_serial = wl_display_get_serial(compositor->wl_display);
+ tool->grab_x = tool->x;
+ tool->grab_y = tool->y;

grab->interface->down(grab, time);
}
@@ -3068,6 +3075,7 @@ weston_seat_release_tablet_tool(struct weston_tablet_tool *tool)
{
/* FIXME: nothing is calling this function yet, tools are only
released on shutdown when the seat goes away */
+ wl_signal_emit(&tool->removed_signal, tool);
}

WL_EXPORT void
@@ -3126,6 +3134,8 @@ weston_seat_add_tablet_tool(struct weston_seat *seat)
if (tool == NULL)
return NULL;

+ wl_signal_emit(&seat->tablet_tool_added_signal, tool);
+
wl_list_init(&tool->resource_list);
tool->seat = seat;

@@ -3159,6 +3169,7 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
wl_list_init(&seat->tablet_seat_resource_list);
wl_list_init(&seat->tablet_list);
wl_list_init(&seat->tablet_tool_list);
+ wl_signal_init(&seat->tablet_tool_added_signal);

seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 4,
seat, bind_seat);
--
2.4.3
Peter Hutterer
2015-11-06 04:31:18 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
clients/desktop-shell.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 6ab76dc..898b060 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -331,6 +331,55 @@ panel_launcher_touch_up_handler(struct widget *widget, struct input *input,
}

static void
+panel_launcher_tablet_tool_proximity_in_handler(struct widget *widget,
+ struct tablet_tool *tool,
+ struct tablet *tablet, void *data)
+{
+ struct panel_launcher *launcher;
+
+ launcher = widget_get_user_data(widget);
+ launcher->focused = 1;
+ widget_schedule_redraw(widget);
+}
+
+static void
+panel_launcher_tablet_tool_proximity_out_handler(struct widget *widget,
+ struct tablet_tool *tool, void *data)
+{
+ struct panel_launcher *launcher;
+
+ launcher = widget_get_user_data(widget);
+ launcher->focused = 0;
+ widget_schedule_redraw(widget);
+}
+
+static void
+panel_launcher_tablet_tool_up_handler(struct widget *widget,
+ struct tablet_tool *tool,
+ void *data)
+{
+ struct panel_launcher *launcher;
+
+ launcher = widget_get_user_data(widget);
+ panel_launcher_activate(launcher);
+}
+
+static void
+panel_launcher_tablet_tool_button_handler(struct widget *widget,
+ struct tablet_tool *tool,
+ uint32_t button,
+ enum zwp_tablet_tool1_button_state state,
+ void *data)
+{
+ struct panel_launcher *launcher;
+
+ launcher = widget_get_user_data(widget);
+
+ if (state == ZWP_TABLET_TOOL1_BUTTON_STATE_RELEASED)
+ panel_launcher_activate(launcher);
+}
+
+static void
clock_func(struct task *task, uint32_t events)
{
struct panel_clock *clock =
@@ -638,6 +687,13 @@ panel_add_launcher(struct panel *panel, const char *icon, const char *path)
panel_launcher_touch_down_handler);
widget_set_touch_up_handler(launcher->widget,
panel_launcher_touch_up_handler);
+ widget_set_tablet_tool_up_handler(launcher->widget,
+ panel_launcher_tablet_tool_up_handler);
+ widget_set_tablet_tool_proximity_handlers(launcher->widget,
+ panel_launcher_tablet_tool_proximity_in_handler,
+ panel_launcher_tablet_tool_proximity_out_handler);
+ widget_set_tablet_tool_button_handler(launcher->widget,
+ panel_launcher_tablet_tool_button_handler);
widget_set_redraw_handler(launcher->widget,
panel_launcher_redraw_handler);
widget_set_motion_handler(launcher->widget,
--
2.4.3
Peter Hutterer
2015-11-06 04:31:19 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
desktop-shell/shell.c | 14 ++++++++++++++
src/bindings.c | 39 ++++++++++++++++++++++++++++++++++++++-
src/compositor.c | 1 +
src/compositor.h | 16 ++++++++++++++++
src/input.c | 6 ++++++
5 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 5b604a5..d70f48f 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -5406,6 +5406,18 @@ touch_to_activate_binding(struct weston_touch *touch, uint32_t time,
}

static void
+tablet_tool_activate_binding(struct weston_tablet_tool *tool,
+ uint32_t button, void *data)
+{
+ if (tool->grab != &tool->default_grab)
+ return;
+ if (tool->focus == NULL)
+ return;
+
+ activate_binding(tool->seat, data, tool->focus);
+}
+
+static void
unfocus_all_seats(struct desktop_shell *shell)
{
struct weston_seat *seat, *next;
@@ -6688,6 +6700,8 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
weston_compositor_add_touch_binding(ec, 0,
touch_to_activate_binding,
shell);
+ weston_compositor_add_tablet_tool_binding(ec, BTN_TOUCH, 0,
+ tablet_tool_activate_binding, shell);
weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
MODIFIER_SUPER | MODIFIER_ALT,
surface_opacity_binding, NULL);
diff --git a/src/bindings.c b/src/bindings.c
index 234c034..a3c142d 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -135,6 +135,24 @@ weston_compositor_add_touch_binding(struct weston_compositor *compositor,
}

WL_EXPORT struct weston_binding *
+weston_compositor_add_tablet_tool_binding(struct weston_compositor *compositor,
+ uint32_t button, uint32_t modifier,
+ weston_tablet_tool_binding_handler_t handler,
+ void *data)
+{
+ struct weston_binding *binding;
+
+ binding = weston_compositor_add_binding(compositor, 0, button, 0,
+ modifier, handler, data);
+ if (binding == NULL)
+ return NULL;
+
+ wl_list_insert(compositor->tablet_tool_binding_list.prev, &binding->link);
+
+ return binding;
+}
+
+WL_EXPORT struct weston_binding *
weston_compositor_add_axis_binding(struct weston_compositor *compositor,
uint32_t axis, uint32_t modifier,
weston_axis_binding_handler_t handler,
@@ -387,7 +405,26 @@ weston_compositor_run_touch_binding(struct weston_compositor *compositor,
}
}

-int
+WL_EXPORT void
+weston_compositor_run_tablet_tool_binding(struct weston_compositor *compositor,
+ struct weston_tablet_tool *tool,
+ uint32_t button,
+ enum zwp_tablet_tool1_button_state state)
+{
+ struct weston_binding *b;
+
+ if (state != ZWP_TABLET_TOOL1_BUTTON_STATE_PRESSED)
+ return;
+
+ wl_list_for_each(b, &compositor->tablet_tool_binding_list, link) {
+ if (b->modifier == tool->seat->modifier_state) {
+ weston_tablet_tool_binding_handler_t handler = b->handler;
+ handler(tool, button, b->data);
+ }
+ }
+}
+
+WL_EXPORT int
weston_compositor_run_axis_binding(struct weston_compositor *compositor,
struct weston_pointer *pointer,
uint32_t time, uint32_t axis,
diff --git a/src/compositor.c b/src/compositor.c
index 7777291..652872b 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -4522,6 +4522,7 @@ weston_compositor_create(struct wl_display *display, void *user_data)
wl_list_init(&ec->modifier_binding_list);
wl_list_init(&ec->button_binding_list);
wl_list_init(&ec->touch_binding_list);
+ wl_list_init(&ec->tablet_tool_binding_list);
wl_list_init(&ec->axis_binding_list);
wl_list_init(&ec->debug_binding_list);
wl_list_init(&ec->tablet_manager_resource_list);
diff --git a/src/compositor.h b/src/compositor.h
index 4da6bc5..8cc3cee 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -821,6 +821,7 @@ struct weston_compositor {
struct wl_list modifier_binding_list;
struct wl_list button_binding_list;
struct wl_list touch_binding_list;
+ struct wl_list tablet_tool_binding_list;
struct wl_list axis_binding_list;
struct wl_list debug_binding_list;

@@ -1401,6 +1402,16 @@ weston_compositor_add_touch_binding(struct weston_compositor *compositor,
weston_touch_binding_handler_t binding,
void *data);

+typedef void (*weston_tablet_tool_binding_handler_t)(struct weston_tablet_tool *tool,
+ uint32_t button,
+ void *data);
+struct weston_binding *
+weston_compositor_add_tablet_tool_binding(struct weston_compositor *compositor,
+ uint32_t button,
+ enum weston_keyboard_modifier modifier,
+ weston_tablet_tool_binding_handler_t binding,
+ void *data);
+
typedef void (*weston_axis_binding_handler_t)(struct weston_pointer *pointer,
uint32_t time, uint32_t axis,
wl_fixed_t value, void *data);
@@ -1446,6 +1457,11 @@ void
weston_compositor_run_touch_binding(struct weston_compositor *compositor,
struct weston_touch *touch, uint32_t time,
int touch_type);
+void
+weston_compositor_run_tablet_tool_binding(struct weston_compositor *compositor,
+ struct weston_tablet_tool *tool,
+ uint32_t button,
+ enum zwp_tablet_tool1_button_state state);
int
weston_compositor_run_axis_binding(struct weston_compositor *compositor,
struct weston_pointer *pointer, uint32_t time,
diff --git a/src/input.c b/src/input.c
index 145defd..b4e6c14 100644
--- a/src/input.c
+++ b/src/input.c
@@ -33,6 +33,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
+#include <linux/input.h>

#include "shared/helpers.h"
#include "shared/os-compatibility.h"
@@ -2345,6 +2346,9 @@ notify_tablet_tool_button(struct weston_tablet_tool *tool,
}

tool->grab_serial = wl_display_next_serial(compositor->wl_display);
+
+ weston_compositor_run_tablet_tool_binding(compositor, tool, button, state);
+
grab->interface->button(grab, time, button, state);
}

@@ -2362,6 +2366,8 @@ notify_tablet_tool_down(struct weston_tablet_tool *tool,
tool->grab_x = tool->x;
tool->grab_y = tool->y;

+ weston_compositor_run_tablet_tool_binding(compositor, tool, BTN_TOUCH,
+ ZWP_TABLET_TOOL1_BUTTON_STATE_PRESSED);
grab->interface->down(grab, time);
}
--
2.4.3
Peter Hutterer
2015-11-06 04:31:20 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Note that this application does not follow best practices for handling tablet
events. The events are grouped by frame, all processing should be done in the
frame instead of the respective handler.

A good toolkit would accumulate the data in the events and provide them as one
event to the actual client once the frame is received. toytoolkit just hooks
up the handler one-by-one, so we're doing this here as well.

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
.gitignore | 1 +
Makefile.am | 7 +-
clients/tablet.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 257 insertions(+), 1 deletion(-)
create mode 100644 clients/tablet.c

diff --git a/.gitignore b/.gitignore
index 11d23da..2045fb8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -74,6 +74,7 @@ weston-simple-damage
weston-smoke
weston-stacking
weston-subsurfaces
+weston-tablet
weston-transformed
weston-view

diff --git a/Makefile.am b/Makefile.am
index 4f2110d..2f06538 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -469,7 +469,8 @@ demo_clients += \
weston-simple-damage \
weston-simple-touch \
weston-presentation-shm \
- weston-multi-resource
+ weston-multi-resource \
+ weston-tablet

weston_simple_shm_SOURCES = clients/simple-shm.c
nodist_weston_simple_shm_SOURCES = \
@@ -617,6 +618,10 @@ weston_scaler_SOURCES = clients/scaler.c
weston_scaler_LDADD = libtoytoolkit.la
weston_scaler_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)

+weston_tablet_SOURCES = clients/tablet.c
+weston_tablet_LDADD = libtoytoolkit.la
+weston_tablet_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
if HAVE_CAIRO_GLESV2
demo_clients += weston-nested weston-nested-client

diff --git a/clients/tablet.c b/clients/tablet.c
new file mode 100644
index 0000000..9b79891
--- /dev/null
+++ b/clients/tablet.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright © 2014 Lyude
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE
+ */
+#include "config.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cairo.h>
+#include <math.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#include <linux/input.h>
+#include <wayland-client.h>
+
+#include "window.h"
+#include "tablet-unstable-v1-client-protocol.h"
+
+struct display *display;
+struct window *window;
+struct widget *widget;
+
+cairo_surface_t *draw_buffer;
+
+int old_x, old_y;
+int current_x, current_y;
+enum zwp_tablet_tool1_type tool_type;
+
+bool tablet_is_down;
+
+double current_pressure;
+
+#define WL_TABLET_AXIS_MAX 65535
+
+static void
+redraw_handler(struct widget *widget, void *data)
+{
+ cairo_surface_t *surface;
+ cairo_t *window_cr, *drawing_cr;
+ struct rectangle allocation;
+
+ widget_get_allocation(widget, &allocation);
+
+ surface = window_get_surface(window);
+
+ /* Setup the background */
+ window_cr = cairo_create(surface);
+ cairo_set_operator(window_cr, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle(window_cr,
+ allocation.x,
+ allocation.y,
+ allocation.width,
+ allocation.height);
+ cairo_set_source_rgba(window_cr, 0, 0, 0, 0.8);
+ cairo_fill(window_cr);
+
+ /* Update the drawing buffer */
+ if (tablet_is_down) {
+ if (old_x != -1 && old_y != -1) {
+ drawing_cr = cairo_create(draw_buffer);
+ if (tool_type == ZWP_TABLET_TOOL1_TYPE_PEN) {
+ cairo_set_source_rgb(drawing_cr, 1, 1, 1);
+ cairo_set_line_width(drawing_cr,
+ current_pressure /
+ WL_TABLET_AXIS_MAX * 7 + 1);
+ } else if (tool_type == ZWP_TABLET_TOOL1_TYPE_ERASER) {
+ cairo_set_operator(drawing_cr, CAIRO_OPERATOR_CLEAR);
+ cairo_set_source_rgb(drawing_cr, 0, 0, 0);
+ cairo_set_line_width(drawing_cr,
+ current_pressure /
+ WL_TABLET_AXIS_MAX * 30 + 10);
+ }
+
+ cairo_set_line_cap(drawing_cr, CAIRO_LINE_CAP_ROUND);
+
+ cairo_translate(drawing_cr,
+ -allocation.x,
+ -allocation.y);
+ cairo_move_to(drawing_cr, old_x, old_y);
+ cairo_line_to(drawing_cr, current_x, current_y);
+ cairo_stroke(drawing_cr);
+
+ cairo_destroy(drawing_cr);
+ }
+
+ old_x = current_x;
+ old_y = current_y;
+ }
+
+ /* Squash the drawing buffer onto the window's buffer */
+ cairo_set_source_surface(window_cr,
+ draw_buffer,
+ allocation.x,
+ allocation.y);
+ cairo_set_operator(window_cr, CAIRO_OPERATOR_ADD);
+ cairo_rectangle(window_cr,
+ allocation.x,
+ allocation.y,
+ allocation.width,
+ allocation.height);
+ cairo_clip(window_cr);
+ cairo_paint(window_cr);
+
+ cairo_destroy(window_cr);
+
+ cairo_surface_destroy(surface);
+}
+
+static void
+resize_handler(struct widget *widget,
+ int32_t width, int32_t height,
+ void *data)
+{
+ cairo_surface_t *tmp_buffer;
+ cairo_t *cr;
+
+ tmp_buffer = draw_buffer;
+ draw_buffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ width, height);
+ cr = cairo_create(draw_buffer);
+ cairo_set_source_rgba(cr, 0, 0, 0, 0);
+ cairo_rectangle(cr, 0, 0, width, height);
+ cairo_fill(cr);
+
+ if (tmp_buffer) {
+ cairo_set_source_surface(cr, tmp_buffer, 0, 0);
+ cairo_rectangle(cr, 0, 0, width, height);
+ cairo_clip(cr);
+ cairo_paint(cr);
+ }
+
+ cairo_destroy(cr);
+
+ cairo_surface_destroy(tmp_buffer);
+}
+
+static void
+proximity_in_handler(struct widget *widget, struct tablet_tool *tool,
+ struct tablet *tablet, void *data)
+{
+ tool_type = tablet_tool_get_type(tool);
+}
+
+static void
+pressure_handler(struct widget *widget, struct tablet_tool *tool,
+ uint32_t pressure, void *data)
+{
+ current_pressure = pressure;
+}
+
+static int
+tablet_motion_handler(struct widget *widget, struct tablet_tool *tool,
+ float x, float y, void *data)
+{
+ int cursor;
+
+ current_x = x;
+ current_y = y;
+
+ if (tablet_is_down) {
+ widget_schedule_redraw(widget);
+ cursor = CURSOR_HAND1;
+ } else
+ cursor = CURSOR_LEFT_PTR;
+
+ return cursor;
+}
+
+static void
+tablet_down_handler(struct widget *widget, struct tablet_tool *tool, void *data)
+{
+ tablet_is_down = true;
+}
+
+static void
+tablet_up_handler(struct widget *widget, struct tablet_tool *tool, void *data)
+{
+ tablet_is_down = false;
+ old_x = -1;
+ old_y = -1;
+}
+
+static void
+init_globals(void)
+{
+ window = window_create(display);
+ widget = window_frame_create(window, NULL);
+ window_set_title(window, "Wayland Tablet Demo");
+ old_x = -1;
+ old_y = -1;
+
+ widget_set_tablet_tool_motion_handler(widget, tablet_motion_handler);
+ widget_set_tablet_tool_down_handler(widget, tablet_down_handler);
+ widget_set_tablet_tool_up_handler(widget, tablet_up_handler);
+ widget_set_tablet_tool_pressure_handler(widget, pressure_handler);
+ widget_set_tablet_tool_proximity_handlers(widget,
+ proximity_in_handler,
+ NULL);
+ widget_set_redraw_handler(widget, redraw_handler);
+ widget_set_resize_handler(widget, resize_handler);
+
+ widget_schedule_resize(widget, 1000, 800);
+}
+
+static void
+cleanup(void)
+{
+ widget_destroy(widget);
+ window_destroy(window);
+}
+
+int
+main(int argc, char *argv[])
+{
+ display = display_create(&argc, argv);
+ if (display == NULL) {
+ fprintf(stderr, "failed to create display: %m\n");
+ return -1;
+ }
+
+ init_globals();
+
+ display_run(display);
+
+ cleanup();
+
+ display_destroy(display);
+
+ return 0;
+}
--
2.4.3
Peter Hutterer
2015-11-06 04:31:21 UTC
Permalink
From: Stephen Chandler Paul <***@gmail.com>

Store all tablets that a tool was used on in a list. When the tablet
is removed, remove all tools only seen on this tablet.

Tools without a serial number are only ever bound to one tablet.

Co-authored-by: Peter Hutterer <***@who-t.net>
Signed-off-by: Stephen Chandler Paul <***@gmail.com>
Signed-off-by: Peter Hutterer <***@who-t.net>
---
src/compositor.h | 2 ++
src/input.c | 26 ++++++++++++++++++++++++++
src/libinput-device.c | 27 +++++++++++++++++++++++----
3 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/src/compositor.h b/src/compositor.h
index 8cc3cee..3f563f4 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -421,6 +421,7 @@ struct weston_tablet_tool {
uint32_t focus_serial;
uint32_t grab_serial;

+ struct wl_list tablet_list;
struct wl_list link;

uint64_t serial;
@@ -452,6 +453,7 @@ struct weston_tablet {
struct wl_list resource_list;

struct wl_list link;
+ struct wl_list tool_link;

char *name;
enum zwp_tablet1_type type;
diff --git a/src/input.c b/src/input.c
index b4e6c14..3761239 100644
--- a/src/input.c
+++ b/src/input.c
@@ -682,10 +682,30 @@ WL_EXPORT void
weston_tablet_destroy(struct weston_tablet *tablet)
{
struct wl_resource *resource;
+ struct weston_tablet_tool *tool, *tmp;

wl_resource_for_each(resource, &tablet->resource_list)
zwp_tablet1_send_removed(resource);

+ /* Check all tools whether they're linked with this tablet and break
+ * that link. If the tool is left with no linked tablets after
+ * this, we can destroy it. */
+ wl_list_for_each_safe(tool, tmp, &tablet->seat->tablet_tool_list, link) {
+ struct weston_tablet *t, *tmpt;
+ bool remove_tool = false;
+
+ wl_list_for_each_safe(t, tmpt, &tool->tablet_list, tool_link) {
+ if (t == tablet) {
+ wl_list_remove(&t->tool_link);
+ remove_tool = true;
+ break;
+ }
+ }
+
+ if (remove_tool && wl_list_empty(&tool->tablet_list))
+ weston_tablet_tool_destroy(tool);
+ }
+
wl_list_remove(&tablet->link);
free(tablet->name);
free(tablet);
@@ -978,6 +998,7 @@ weston_tablet_tool_create(void)

wl_list_init(&tool->resource_list);
wl_list_init(&tool->focus_resource_list);
+ wl_list_init(&tool->tablet_list);

wl_list_init(&tool->sprite_destroy_listener.link);
tool->sprite_destroy_listener.notify = tablet_tool_handle_sprite_destroy;
@@ -1003,6 +1024,11 @@ weston_tablet_tool_destroy(struct weston_tablet_tool *tool)
{
struct wl_resource *resource, *tmp;

+ if (!wl_list_empty(&tool->tablet_list)) {
+ weston_log("error: tool still linked to a tablet\n");
+ return;
+ }
+
if (tool->sprite)
tablet_tool_unmap_sprite(tool);

diff --git a/src/libinput-device.c b/src/libinput-device.c
index ba89410..d8643c8 100644
--- a/src/libinput-device.c
+++ b/src/libinput-device.c
@@ -334,10 +334,12 @@ handle_tablet_proximity(struct libinput_device *libinput_device,
return;
}

- wl_list_for_each(tool, &device->seat->tablet_tool_list, link) {
- if (tool->serial == serial && tool->type == type) {
- create = false;
- break;
+ if (serial) {
+ wl_list_for_each(tool, &device->seat->tablet_tool_list, link) {
+ if (tool->serial == serial && tool->type == type) {
+ create = false;
+ break;
+ }
}
}

@@ -361,11 +363,28 @@ handle_tablet_proximity(struct libinput_device *libinput_device,
tool->capabilities |= 1 << ZWP_TABLET_TOOL1_CAPABILITY_TILT;

wl_list_insert(&device->seat->tablet_tool_list, &tool->link);
+ wl_list_insert(&tool->tablet_list, &tablet->tool_link);
+
notify_tablet_tool_added(tool);

libinput_tool_set_user_data(libinput_tool, tool);
}

+ if (serial && !create) {
+ struct weston_tablet *t;
+ bool add = true;
+
+ wl_list_for_each(t, &tool->tablet_list, tool_link) {
+ if (t == tablet) {
+ add = false;
+ break;
+ }
+ }
+
+ if (add)
+ wl_list_insert(&tool->tablet_list, &tablet->tool_link);
+ }
+
notify_tablet_tool_proximity_in(tool, time, tablet);
/* FIXME: we should send axis updates here */
notify_tablet_tool_frame(tool, time);
--
2.4.3
Jason Gerecke
2015-11-06 23:13:46 UTC
Permalink
Post by Peter Hutterer
This set adds support for graphics tablets to weston. It's not fully
complete, there are a couple of fixmes in it but the patchset is getting a
bit unwieldly. And there are some discussions on how to do things anyway.
Note: This needs the tablet-support branch from libinput to work. And it is
on top of Jonas's wip/wayland-protocols github branch (ff0452cea150c).
Tablet events are sent serially, terminated by a frame event. A toolkit
should accumulate them and then pass them on as one struct to the client. We
don't do that atm, it may be beyond libtoytoolkit's scope to really
integrate this properly.
The tablet has a separate cursor. That's a conscious decision since the
focus handling on tablets closer to an absolute touch screen than a mouse,
but unlike touch you usually want a cursor shape to indicate the precise
position.
The rest is fairly straightforward, though as said above, some details are
missing. Implementing this also showed that libinput needs a few extra
things added to it.
Cheers,
Peter
Having trouble getting this patchset to work properly for me. Of the
many times I've launched 'weston-tablet', only once did it work as
expected. The rest of the time I get no response and more often than
not a segfault when the pen leaves proximity (first backtrace). I've
also seen a segfault when simply trying to exit Weston with
CTRL+ALT+BACKSPACE (second backgrace).

Haven't had time to track down the cause; all I know at the moment is
that it seems the demo client's proximity_in_handler isn't actually
being called for some reason...


Program received signal SIGSEGV, Segmentation fault.
0x000000000041596f in default_grab_tablet_tool_proximity_out
(grab=0x20e8388, time=23980253) at src/input.c:812
812 if (weston_surface_is_mapped(tool->sprite->surface))
(gdb) bt
#0 0x000000000041596f in default_grab_tablet_tool_proximity_out
(grab=0x20e8388, time=23980253) at src/input.c:812
#1 0x0000000000418ffb in notify_tablet_tool_proximity_out
(tool=0x20e82d0, time=23980253) at src/input.c:2307
#2 0x00007fe3699a6ce1 in handle_tablet_proximity
(libinput_device=0x1c1d7c0, proximity_event=0x20e0580) at
src/libinput-device.c:320
#3 0x00007fe3699a7587 in evdev_device_process_event (event=0x20e0580)
at src/libinput-device.c:543
#4 0x00007fe3699a5cf3 in process_event (event=0x20e0580) at
src/libinput-seat.c:169
#5 0x00007fe3699a5d14 in process_events (input=0x1b07c88) at
src/libinput-seat.c:179
#6 0x00007fe3699a5d79 in udev_input_dispatch (input=0x1b07c88) at
src/libinput-seat.c:190
#7 0x00007fe3699a5da6 in libinput_source_dispatch (fd=16, mask=1,
data=0x1b07c88) at src/libinput-seat.c:200
#8 0x00007fe36b3bcc72 in wl_event_loop_dispatch (loop=0x1aef220,
timeout=***@entry=-1) at src/event-loop.c:422
#9 0x00007fe36b3bb5e5 in wl_display_run (display=0x1aef190) at
src/wayland-server.c:1004
#10 0x00000000004275c6 in main (argc=1, argv=0x7ffe86bcca88) at src/main.c:871


Program received signal SIGSEGV, Segmentation fault.
0x00007f3f3e63a0e7 in wl_list_remove (elm=0x195a910) at src/wayland-util.c:57
57 elm->prev->next = elm->next;
(gdb) bt
#0 0x00007f3f3e63a0e7 in wl_list_remove (elm=0x195a910) at
src/wayland-util.c:57
#1 0x000000000041550f in weston_tablet_destroy (tablet=0x195a8e0) at
src/input.c:699
#2 0x000000000041a9df in weston_seat_release_tablet
(tablet=0x195a8e0) at src/input.c:3116
#3 0x00007f3f3cc22ff3 in evdev_device_destroy (device=0x19acc80) at
src/libinput-device.c:867
#4 0x00007f3f3cc20bc6 in udev_seat_remove_devices (seat=0x19a8fa0) at
src/libinput-seat.c:126
#5 0x00007f3f3cc21427 in udev_seat_destroy (seat=0x19a8fa0) at
src/libinput-seat.c:397
#6 0x00007f3f3cc211b0 in udev_input_destroy (input=0x1852c88) at
src/libinput-seat.c:333
#7 0x00007f3f3cc1f5f7 in drm_destroy (ec=0x183bfc0) at
src/compositor-drm.c:2712
#8 0x000000000041379f in weston_compositor_destroy
(compositor=0x183bfc0) at src/compositor.c:4780
#9 0x00000000004275f1 in main (argc=1, argv=0x7ffdd6f32308) at src/main.c:882

Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
Peter Hutterer
2015-11-06 23:43:01 UTC
Permalink
Post by Jason Gerecke
Post by Peter Hutterer
This set adds support for graphics tablets to weston. It's not fully
complete, there are a couple of fixmes in it but the patchset is getting a
bit unwieldly. And there are some discussions on how to do things anyway.
Note: This needs the tablet-support branch from libinput to work. And it is
on top of Jonas's wip/wayland-protocols github branch (ff0452cea150c).
Tablet events are sent serially, terminated by a frame event. A toolkit
should accumulate them and then pass them on as one struct to the client. We
don't do that atm, it may be beyond libtoytoolkit's scope to really
integrate this properly.
The tablet has a separate cursor. That's a conscious decision since the
focus handling on tablets closer to an absolute touch screen than a mouse,
but unlike touch you usually want a cursor shape to indicate the precise
position.
The rest is fairly straightforward, though as said above, some details are
missing. Implementing this also showed that libinput needs a few extra
things added to it.
Cheers,
Peter
Having trouble getting this patchset to work properly for me. Of the
many times I've launched 'weston-tablet', only once did it work as
expected. The rest of the time I get no response and more often than
not a segfault when the pen leaves proximity (first backtrace). I've
also seen a segfault when simply trying to exit Weston with
CTRL+ALT+BACKSPACE (second backgrace).
Haven't had time to track down the cause; all I know at the moment is
that it seems the demo client's proximity_in_handler isn't actually
being called for some reason...
I've seen this bug a few times but don't know what the cause of it is
yet. I *think* it may be a libinput bug because the libinput event never
appears in the log. The problem is that once the bug happens it happens
repeatedly, but otherwise it's really hard to trigger. Unplugging the
tablet usually stops it but not always, but I haven't seen it since Wed
now so i'm struggling to reproduce it right now.

Also, fwiw so you don't have to handle the patchset itself:

http://github.com/whot/weston/tree/tablet-support-v3 (f4c8c77)
http://github.com/whot/wayland-protocols/tree/wip/wayland-tablet (8ded9b)
and libinput's tablet-support branch (ab6a409)

Cheers,
Peter
Peter Hutterer
2016-02-03 05:13:47 UTC
Permalink
Post by Jason Gerecke
Post by Peter Hutterer
This set adds support for graphics tablets to weston. It's not fully
complete, there are a couple of fixmes in it but the patchset is getting a
bit unwieldly. And there are some discussions on how to do things anyway.
Note: This needs the tablet-support branch from libinput to work. And it is
on top of Jonas's wip/wayland-protocols github branch (ff0452cea150c).
Tablet events are sent serially, terminated by a frame event. A toolkit
should accumulate them and then pass them on as one struct to the client. We
don't do that atm, it may be beyond libtoytoolkit's scope to really
integrate this properly.
The tablet has a separate cursor. That's a conscious decision since the
focus handling on tablets closer to an absolute touch screen than a mouse,
but unlike touch you usually want a cursor shape to indicate the precise
position.
The rest is fairly straightforward, though as said above, some details are
missing. Implementing this also showed that libinput needs a few extra
things added to it.
Cheers,
Peter
Having trouble getting this patchset to work properly for me. Of the
many times I've launched 'weston-tablet', only once did it work as
expected. The rest of the time I get no response and more often than
not a segfault when the pen leaves proximity (first backtrace). I've
also seen a segfault when simply trying to exit Weston with
CTRL+ALT+BACKSPACE (second backgrace).
Haven't had time to track down the cause; all I know at the moment is
that it seems the demo client's proximity_in_handler isn't actually
being called for some reason...
fwiw, the reason for this bug was:
http://lists.freedesktop.org/archives/wayland-devel/2016-February/026765.html

Cheers,
Peter
Post by Jason Gerecke
Program received signal SIGSEGV, Segmentation fault.
0x000000000041596f in default_grab_tablet_tool_proximity_out
(grab=0x20e8388, time=23980253) at src/input.c:812
812 if (weston_surface_is_mapped(tool->sprite->surface))
(gdb) bt
#0 0x000000000041596f in default_grab_tablet_tool_proximity_out
(grab=0x20e8388, time=23980253) at src/input.c:812
#1 0x0000000000418ffb in notify_tablet_tool_proximity_out
(tool=0x20e82d0, time=23980253) at src/input.c:2307
#2 0x00007fe3699a6ce1 in handle_tablet_proximity
(libinput_device=0x1c1d7c0, proximity_event=0x20e0580) at
src/libinput-device.c:320
#3 0x00007fe3699a7587 in evdev_device_process_event (event=0x20e0580)
at src/libinput-device.c:543
#4 0x00007fe3699a5cf3 in process_event (event=0x20e0580) at
src/libinput-seat.c:169
#5 0x00007fe3699a5d14 in process_events (input=0x1b07c88) at
src/libinput-seat.c:179
#6 0x00007fe3699a5d79 in udev_input_dispatch (input=0x1b07c88) at
src/libinput-seat.c:190
#7 0x00007fe3699a5da6 in libinput_source_dispatch (fd=16, mask=1,
data=0x1b07c88) at src/libinput-seat.c:200
#8 0x00007fe36b3bcc72 in wl_event_loop_dispatch (loop=0x1aef220,
#9 0x00007fe36b3bb5e5 in wl_display_run (display=0x1aef190) at
src/wayland-server.c:1004
#10 0x00000000004275c6 in main (argc=1, argv=0x7ffe86bcca88) at src/main.c:871
Program received signal SIGSEGV, Segmentation fault.
0x00007f3f3e63a0e7 in wl_list_remove (elm=0x195a910) at src/wayland-util.c:57
57 elm->prev->next = elm->next;
(gdb) bt
#0 0x00007f3f3e63a0e7 in wl_list_remove (elm=0x195a910) at
src/wayland-util.c:57
#1 0x000000000041550f in weston_tablet_destroy (tablet=0x195a8e0) at
src/input.c:699
#2 0x000000000041a9df in weston_seat_release_tablet
(tablet=0x195a8e0) at src/input.c:3116
#3 0x00007f3f3cc22ff3 in evdev_device_destroy (device=0x19acc80) at
src/libinput-device.c:867
#4 0x00007f3f3cc20bc6 in udev_seat_remove_devices (seat=0x19a8fa0) at
src/libinput-seat.c:126
#5 0x00007f3f3cc21427 in udev_seat_destroy (seat=0x19a8fa0) at
src/libinput-seat.c:397
#6 0x00007f3f3cc211b0 in udev_input_destroy (input=0x1852c88) at
src/libinput-seat.c:333
#7 0x00007f3f3cc1f5f7 in drm_destroy (ec=0x183bfc0) at
src/compositor-drm.c:2712
#8 0x000000000041379f in weston_compositor_destroy
(compositor=0x183bfc0) at src/compositor.c:4780
#9 0x00000000004275f1 in main (argc=1, argv=0x7ffdd6f32308) at src/main.c:882
Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
Bill Spitzak
2015-11-06 23:32:25 UTC
Permalink
Post by Peter Hutterer
The tablet has a separate cursor. That's a conscious decision since the
focus handling on tablets closer to an absolute touch screen than a mouse,
but unlike touch you usually want a cursor shape to indicate the precise
position.
Very strongly disagree with this!!!!

The tablet should control the seat's pointer. Users do not want to see two
different cursors in most cases. If they do then they can configure the
tablet to be a different seat.

It does not matter that tablets (sometimes) are absolute devices. When the
pen enters the pickup space for the tablet, the cursor will jump to that
location. The fact that the user may have moved it with the mouse
beforehand makes absolutely no difference about the need to support such
jumping.
Jason Gerecke
2015-11-06 23:13:16 UTC
Permalink
Post by Peter Hutterer
---
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Makefile.am | 1 +
unstable/tablet/README | 4 +
unstable/tablet/tablet-unstable-v1.xml | 588 +++++++++++++++++++++++++++++++++
3 files changed, 593 insertions(+)
create mode 100644 unstable/tablet/README
create mode 100644 unstable/tablet/tablet-unstable-v1.xml
diff --git a/Makefile.am b/Makefile.am
index 4bcab32..588cb2c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,6 +6,7 @@ protocols = \
unstable/text-input/text-input-unstable-v1.xml \
unstable/input-method/input-method-unstable-v1.xml \
unstable/xdg-shell/xdg-shell-unstable-v5.xml \
+ unstable/tablet/tablet-unstable-v1.xml \
$(NULL)
nobase_dist_pkgdata_DATA = $(protocols)
diff --git a/unstable/tablet/README b/unstable/tablet/README
new file mode 100644
index 0000000..7ba8e77
--- /dev/null
+++ b/unstable/tablet/README
@@ -0,0 +1,4 @@
+Tablet protocol
+
diff --git a/unstable/tablet/tablet-unstable-v1.xml b/unstable/tablet/tablet-unstable-v1.xml
new file mode 100644
index 0000000..b07eccb
--- /dev/null
+++ b/unstable/tablet/tablet-unstable-v1.xml
@@ -0,0 +1,588 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland_tablet_unstable_v1">
+ <description summary="Wayland protocol for graphics tablets">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
+
+ The wp_tablet_seat sends a "tablet added" for each tablet connected.
+ That event is followed by descriptive events about the hardware;
+ currently that includes events for name, vid/pid and
+ internal/external/display type, and a wp_tablet.path event that
+ describes a local path. This path can be used to uniquely identify a
+ tablet, or get more information through libwacom. Emulated or nested
+ tablets can skip any of those, e.g. a virtual tablet may not have a
+ vid/pid. The sequence of descriptive events is terminated by a
+ wp_tablet.done event to signal that a client may now finalize any
+ initialization for that tablet.
+
+ Events from tablets require a tool in proximity. Tools are also managed
+ by the tablet seat, a "tool added" is sent whenever a tool is new to
+ the compositor. That event is followed by a number of descriptive events
+ about the hardware; currently that includes capabilities, serial id,
+ hardware serial and tool type. Similar to the tablet interface, a
+ wp_tablet_tool.done event is sent to terminate that initial sequence.
+
+ Any event from a tool happens on the wp_tablet_tool interface. When the
+ tool gets into proximity of the tablet, a proximity_in event is sent on
+ the wp_tablet_tool interface, listing the tablet and the surface. That
+ event is followed by a motion event with the coordinates. After that,
+ it's the usual motion, axis, button, etc. events.
+ The protocol's serialisation means events are grouped by by
+ wp_tablet_tool.frame events.
Nitpick: Unnecessary paragraph break here :)
Post by Peter Hutterer
+
+ Two special events (that don't exist in X) are down and up. They signal
+ "tip touching the surface". For tablets without real proximity
+ detection, the sequence is: proximity_in, motion, down, frame.
+
+ When the tool leaves proximity, a proximity_out event is sent, followed
+ by button release events for any button still down. This signals to
+ the client that the buttons were held when the tool left proximity.
+ Those events are all sent within the same frame.
+
+ If the tool moves out of the surface but stays in proximity (i.e.
+ between windows), compositor-specific grab policies apply. This usually
+ means that the proximity-out is delayed until all buttons are released.
+
+ Moving a tool physically from one tablet to the other has no real effect
+ on the protocol, since we already have the tool object from the "tool
+ added" event. All the information is already there and the proximity_in
+ is all a client needs to reconstruct what happened.
+
+ Any extra axis is normalized, i.e. the client knows the range as
+ specified in the protocol (e.g. [0, 65535]), the granularity however is
+ unknown. The current axes are pressure, tilt (both x/y required) and
+ distance, the most common set.
+
+ Since tablets work independently of the pointer controlled by the mouse,
+ the focus handling is independent too and controlled by proximity.
+ The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
+ This cursor surface may be the same as the mouse cursor, and it may be
+ the same across tools but it is possible to be more fine-grained. For
+ example, a client may set different cursors for the pen and eraser.
+
+ Tools are generally independent of tablets and it is
+ compositor-specific policy when a tool can removed. Common approaches
+ will likely include some form of removing a tool when all tablets the
+ tool was used on is removed.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+ </description>
+ <copyright>
+ Copyright 2014 © Stephen "Lyude" Chandler Paul
+ Copyright 2015 © Red Hat, Inc.
Had some issues with the weston failing to build due to mangled
copyright symbols here. Probably just gmail messing things up but just
in case...
Post by Peter Hutterer
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ </copyright>
+ <interface name="zwp_tablet_manager1" version="1">
+ <description summary="controller object for graphic tablet devices">
+ An object that provides access to the graphics tablets available on this
+ system. Any tablet is associated with a seat, to get access to the
+ actual tablets, use wp_tablet_manager.get_tablet_seat.
+ </description>
+
+ <request name="get_tablet_seat">
+ <description summary="get the tablet seat">
+ Get the wp_tablet_seat object for the given seat. This object
+ provides access to all graphics tablets in this seat.
+ </description>
+ <arg name="tablet_seat" type="new_id" interface="zwp_tablet_seat1"/>
+ <arg name="seat" type="object" interface="wl_seat" summary="The wl_seat object to retrieve the tablets for" />
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet manager object">
+ This destroys the resources associated with the tablet manager.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="zwp_tablet_seat1" version="1">
+ <description summary="controller object for graphic tablet devices of a seat">
+ An object that provides access to the graphics tablets available on this
+ seat. After binding to this interface, the compositor sends a set of
+ wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet seat object">
+ This destroys the resources associated with the tablet seat.
+ </description>
+ </request>
+
+ <event name="tablet_added">
+ <description summary="new device notification">
+ This event is sent whenever a new tablet becomes available on this
+ seat. This event only provides the object id of the tablet, any
+ static information about the tablet (device name, vid/pid, etc.) is
+ sent through the wp_tablet interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet1" summary="the newly added graphics tablet"/>
+ </event>
+
+ <event name="tool_added">
+ <description summary="a new tool has been used with a tablet">
+ This event is sent whenever a tool that has not previously been used
+ with a tablet comes into use. This event only provides the object id
+ of the tool, any static information about the tool (capabilities,
+ type, et.c) is sent through the wp_tablet_tool interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet_tool1" summary="the newly added tablet tool"/>
+ </event>
+ </interface>
+
+ <interface name="zwp_tablet_tool1" version="1">
+ <description summary="a physical tablet tool">
+ An unique object that represents a physical tool that has been, or is
+ currently in use with a tablet in this seat. Each wp_tablet_tool
+ object stays valid until the client destroys it; the compositor
+ reuses the wp_tablet_tool object to indicate that the object's
+ respective physical tool has come into proximity of a tablet again.
+ A client must not call wp_tablet_tool.destroy until it receives a
+ wp_tablet_tool.release event.
+
+ A wp_tablet_tool object's uniqueness depends on the tablet's ability
+ to report serial numbers. If the tablet doesn't support this
+ capability, then the tool cannot be guaranteed to be unique.
+
+ A tablet tool has a number of static characteristics, e.g. tool type,
+ serial_id and capabilities. These capabilities are sent in an event
+ sequence after the wp_tablet_seat.tool_added event before any actual
+ events from this tool. This initial event sequence is terminated by a
+ wp_tablet_tool.done event.
+
+ Tablet tool events are grouped by wp_tablet_tool.frame events.
+ Any events received before a wp_tablet_tool.frame event should be
+ considered part of the same hardware state change.
+ </description>
+
+ <request name="set_cursor">
+ <description summary="set the tablet tool's surface">
+ Sets the surface of the cursor used for this tool on the given
+ tablet. The surface is only shown when this tool is in proximity of
+ this tablet. If the surface is NULL, the pointer image is hidden
+ completely.
+
+ The parameters hotspot_x and hotspot_y define the position of the
+ pointer surface relative to the pointer location. Its top-left corner
+ is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+ coordinates of the pointer location, in surface local coordinates.
+
+ On surface.attach requests to the pointer surface, hotspot_x and
+ hotspot_y are decremented by the x and y parameters passed to the
+ request. Attach must be confirmed by wl_surface.commit as usual.
+
+ The hotspot can also be updated by passing the currently set pointer
+ surface to this request with new values for hotspot_x and hotspot_y.
+
+ The current and pending input regions of the wl_surface are cleared,
+ and wl_surface.set_input_region is ignored until the wl_surface is no
+ longer used as the cursor. When the use as a cursor ends, the current
+ and pending input regions become undefined, and the wl_surface is
+ unmapped.
+
+ This request gives the surface the role of a cursor. The role
+ assigned by this request is the same as assigned by
+ wl_pointer.set_cursor meaning the same surface can be
+ used both as a wl_pointer cursor and a wp_tablet cursor. If the
+ surface already has another role, it raises a protocol error
+ The surface may be used on multiple tablets and across multiple
+ seats.
+ </description>
+ <arg name="serial" type="uint" summary="serial of the enter event"/>
+ <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+ <arg name="hotspot_x" type="int" summary="x coordinate in surface-relative coordinates"/>
+ <arg name="hotspot_y" type="int" summary="y coordinate in surface-relative coordinates"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tool object">
+ This destroys the client's resource for this tool object.
+
+ A client must not issue this request until it receives a
+ wp_tablet_tool.remove event.
+ </description>
+ </request>
+
+ <enum name="type">
+ <description summary="a physical tool type">
+ Describes the physical type of a tool. The physical type of a tool
+ generally defines its base usage.
+
+ The mouse tool represents a mouse-shaped tool that is not a relative
+ device but bound to the tablet's surface, providing absolute
+ coordinates.
+
+ The lens tool is a mouse-shaped tool with an attached lens to
+ provide precision focus.
+ </description>
+ <entry name="pen" value="0x140" summary="Pen"/>
+ <entry name="eraser" value="0x141" summary="Eraser"/>
+ <entry name="brush" value="0x142" summary="Brush"/>
+ <entry name="pencil" value="0x143" summary="Pencil"/>
+ <entry name="airbrush" value="0x144" summary="Airbrush"/>
+ <entry name="finger" value="0x145" summary="Finger"/>
+ <entry name="mouse" value="0x146" summary="Mouse"/>
+ <entry name="lens" value="0x147" summary="Lens"/>
+ </enum>
+
+ <event name="type">
+ <description summary="tool type">
+ The tool type is the high-level type of the tool and usually decides
+ the interaction expected from this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="tool_type" type="uint" summary="the physical tool type"/>
+ </event>
+
+ <event name="serial_id">
+ <description summary="unique serial number of the tool">
+ If the tool can be identified by a unique 64-bit serial number, this
+ event notifies the client of the serial number.
+
+ If multiple tablets are available in the same seat and the tool is
+ uniquely identifiable by the serial number, that tool may move
+ between tablets.
+
+ Otherwise, if the tool has no serial number and this event is
+ missing, the tool is tied to the tablet it first comes into
+ proximity with. Even if the physical tool is used on multiple
+ tablets, separate wp_tablet_tool objects will be created, one per
+ tablet.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="serial_id_msb" type="uint" summary="the unique serial number of the tool, most significant bits"/>
+ <arg name="serial_id_lsb" type="uint" summary="the unique serial number of the tool, least significant bits"/>
+ </event>
+
+ <enum name="hardware_id_format">
+ <description summary="the hardware id format">
+ Specifies the format of the hardware id in the
+ wp_tablet_tool.hardware_id event.
+
+ A wacom_stylus_id format indicates a hardware id as the id used by
+ graphics tablet made by Wacom Inc. For example, on Wacom tablets the
+ hardware id of a Grip Pen (a stylus) is 0x802.
+ </description>
+ <entry name="wacom_stylus_id" value="0" />
+ </enum>
+
+ <event name="hardware_id">
+ <description summary="hardware id notification">
+ This event notifies the client of a hardware id available on this tool.
+
+ The hardware id is a device-specific 64-bit id that provides extra
+ information about the tool in use, beyond the wl_tool.type
+ enumeration. The format of the id is device-specific.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="format" type="uint" summary="the type of the id" />
+ <arg name="hardware_id_msb" type="uint" summary="the hardware id, most significant bits"/>
+ <arg name="hardware_id_lsb" type="uint" summary="the hardware id, least significant bits"/>
+ </event>
+
+
+ <enum name="capability">
+ <description summary="capability flags for a tool">
+ Describes extra capabilities on a tablet.
+
+ Any tool must provide x and y values, extra axes are
+ device-specific.
+ </description>
+ <entry name="tilt" value="1" summary="Tilt axes"/>
+ <entry name="pressure" value="2" summary="Pressure axis"/>
+ <entry name="distance" value="3" summary="Distance axis"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="tool capability notification">
+ This event notifies the client of any capabilities of this tool,
+ beyond the main set of x/y axes and tip up/down detection.
+
+ One event is sent for each extra capability available on this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="capability" type="uint" summary="the capability"/>
+ </event>
+
+ <event name="done">
+ <description summary="tool description events sequence complete">
+ This event signals the end of the initial burst of descriptive
+ events. A client may consider the static description of the tool to
+ be complete and finalize initialization of the tool.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tool removed">
+ This event is sent when the tool is removed from the system. The client
+ should not expect the resource it currently has associated with the
+ tool to be used again if the tool comes back into proximity later.
+
+ It is compositor-dependent when a tool is removed. Some tools are
+ associated with a single tablet only and may get removed when the
+ respective tablet is removed. Other tools may be used on multiple
+ tablets and removing a tablet may not remove this tool.
+
+ When this event is received, the client must wp_tablet_tool.destroy
+ the object.
+ </description>
+ </event>
+
+ <event name="proximity_in">
+ <description summary="proximity in event">
+ Notification that this tool is focused on a certain surface.
+
+ This event can be received when the tool has moved from one surface to
+ another, or when the tool has come back into proximity above the
+ surface.
+
+ Any button events sent within the same wp_tablet.frame as a
+ proximity_in event indicate the button state of the tool at the time
+ of proximity in.
+ </description>
+ <arg name="serial" type="uint"/>
+ <arg name="tablet" type="object" interface="zwp_tablet1" summary="The tablet the tool is in proximity of"/>
+ <arg name="surface" type="object" interface="wl_surface" summary="The current surface the tablet tool is over"/>
+ </event>
+
+ <event name="proximity_out">
+ <description summary="proximity out event">
+ Notification that this tool has either left proximity, or is no
+ longer focused on a certain surface.
+
+ When the tablet tool leaves proximity of the tablet, button release
+ events are sent for each button that was held down at the time of
+ leaving proximity. These events are sent in the same wp_tablet.frame
+ of the proximity_out event.
+
+ If the tool stays within proximity of the tablet, but the focus
+ changes from one surface to another, a button release event may not
+ be sent until the button is actually released or the tool leaves the
+ proximity of the tablet.
+ </description>
+ </event>
+
+ <event name="down">
+ <description summary="tablet tool is making contact">
+ Sent whenever the tablet tool comes in contact with the surface of the
+ tablet. If the tablet tool moves out of a region while in contact with
+ the surface of the tablet, the client owning said region will receive a
+ wp_tablet::up event, followed by a wp_tablet::proximity_out event and a
+ wp_tablet::frame event.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
+
+ <event name="up">
+ <description summary="tablet tool is no longer making contact">
+ Sent whenever the tablet tool stops making contact with the surface of
+ the tablet, or when the tablet tool moves off of a surface while it was
+ making contact with the tablet's surface.
+ </description>
+ </event>
+
+ <event name="motion">
+ <description summary="motion event">
+ Sent whenever a tablet tool moves.
+ </description>
+ <arg name="x" type="fixed" summary="surface-relative x coordinate"/>
+ <arg name="y" type="fixed" summary="surface-relative y coordinate"/>
+ </event>
+
+ <event name="pressure">
+ <description summary="pressure change event">
+ Sent whenever the pressure axis on a tool changes. The value of this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="pressure" type="uint" summary="The current pressure value"/>
+ </event>
+
+ <event name="distance">
+ <description summary="distance change event">
+ Sent whenever the distance axis on a tool changes. The value of this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="distance" type="uint" summary="The current distance value"/>
+ </event>
+
+ <event name="tilt">
+ <description summary="tilt change event">
+ Sent whenever one or both of the tilt axes on a tool change. Each tilt
+ value is normalized between -65535 and 65535.
Just as a note to the future, but we may eventually want a way for
clients to discover what real-world values these ranges correspond to.
For now though, it should be safe enough for clients to make use of
hard-coded conversions if necessary.

Reviewed-by: Jason Gerecke <***@wacom.com>


(Aside: the wayland protocols have some weird indenting standards :p)

Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
Post by Peter Hutterer
+ </description>
+ <arg name="tilt_x" type="int" summary="The current value of the X tilt axis"/>
+ <arg name="tilt_y" type="int" summary="The current value of the Y tilt axis"/>
+ </event>
+
+ <enum name="button_state">
+ <description summary="physical button state">
+ Describes the physical state of a button which provoked the button event
+ </description>
+ <entry name="released" value="0" summary="button is not pressed"/>
+ <entry name="pressed" value="1" summary="button is pressed"/>
+ </enum>
+
+ <event name="button">
+ <description summary="button event">
+ Sent whenever a button on the stylus is pressed or released.
+ </description>
+
+ <arg name="serial" type="uint"/>
+ <arg name="button" type="uint" summary="The button whose state has changed"/>
+ <arg name="state" type="uint" summary="Whether the button was pressed or released"/>
+ </event>
+
+ <event name="frame">
+ <description summary="frame event">
+ Marks the end of a series of axis and/or button updates from the
+ tablet. The wayland protocol requires axis updates to be sent
+ sequentially, however all events within a frame should be considered
+ one hardware event.
+ </description>
+ <arg name="time" type="uint" summary="The time of the event with millisecond granularity"/>
+ </event>
+
+ <enum name="error">
+ <entry name="role" value="0" summary="given wl_surface has another role"/>
+ </enum>
+ </interface>
+
+ <interface name="zwp_tablet1" version="1">
+ <description summary="graphics tablet device">
+ The wp_tablet interface represents one graphics tablet device. The
+ tablet interface itself does not generate events, all events are
+ generated by wp_tablet_tool objects when in proximity above a tablet.
+
+ A tablet has a number of static characteristics, e.g. device name and
+ pid/vid. These capabilities are sent in an event sequence after the
+ wp_tablet_seat.tablet_added event. This initial event sequence is
+ terminated by a wp_tablet.done event.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tablet object">
+ This destroys the client's resource for this tablet object.
+
+ A client must not issue this request until it receives a
+ wp_tablet.remove event.
+ </description>
+ </request>
+
+ <event name="name">
+ <description summary="tablet device name">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="name" type="string" summary="the device name"/>
+ </event>
+
+ <event name="id">
+ <description summary="tablet device vid/pid">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="vid" type="uint" summary="vendor id"/>
+ <arg name="pid" type="uint" summary="product id"/>
+ </event>
+
+ <enum name="type">
+ <description summary="tablet type">
+ Describes the type of tablet
+ </description>
+
+ <entry name="external" value="0" summary="The tablet is an external tablet, such as an Intuos"/>
+ <entry name="internal" value="1" summary="The tablet is a built-in tablet, usually in a laptop"/>
+ <entry name="display" value="2" summary="The tablet is a display tablet, such as a Cintiq"/>
+ </enum>
+
+ <event name="type">
+ <description summary="the tablet type">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="type" type="uint" summary="the tablet type (internal, external, ...)"/>
+ </event>
+
+ <event name="path">
+ <description summary="path to the device">
+ A system-specific device path that indicates which device is behind
+ this wp_tablet. This information may be used to gather additional
+ information about the device, e.g. through libwacom.
+
+ A device may have more than one device path, if so, multiple
+ wp_tablet.path events are sent. A device may be emulated and not
+ have a device path, in that case this event will not be sent.
+
+ The format of the path is unspecified, it may be a device node, a
+ sysfs path, or some other identifier. It is up to the client to
+ identify the string provided.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="path" type="string" summary="path to local device"/>
+ </event>
+
+ <event name="done">
+ <description summary="tablet description events sequence complete">
+ This event is sent immediately to signal the end of the initial
+ burst of descriptive events. A client may consider the static
+ description of the tablet to be complete and finalize initialization
+ of the tablet.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tablet removed event">
+ Sent when the tablet has been removed from the system. When a tablet
+ is removed, some tools may be removed.
+
+ When this event is received, the client must wp_tablet.destroy
+ the object.
+ </description>
+ </event>
+ </interface>
+</protocol>
--
2.4.3
Bill Spitzak
2015-11-07 00:11:43 UTC
Permalink
Having read this more carefully, the cursor scheme absolutely will not work.

The main problem is that the client may want to choose a cursor for a tool
based on the location at which it came into proximity. It cannot set this
cursor until after it gets the proximity event. If this desired cursor is
different than the one the tool currently has set then that incorrect
cursor will be seen, at least briefly.

A further problem is that there has to be an easy transition between
clients that don't use the tablet api and those that do. Operation of gui
widgets that work equally well with mouse or tablet should not change just
because the client has decided to enable the tablet interface. The primary
problem is that the pointer position must move to the last tablet tool
positiion whether or not the client is using the tablet interface. This
then means there cannot be more than one cursor (since they would be right
atop each other).

My recommendation:

- Proximity-in jumps the cursor and pointer position to the location but
does not change the cursor. It will however send proximity-in events to the
client (it will also send proximity-out to other clients using the tablet
interface, and normal wl_pointer exit events to clients not using the
tablet interface).

- Client should respond to proximity-in by setting the wl_pointer cursor to
whatever is desired. Notice this is identical to how clients not using the
tablet interface respond to wl_pointer::enter events.

This will 'blink' still, as the current cursor is also possibly not equal
to the desired cursor. This could be fixed, but if so the exact same fix
must be done to enter events or you really are not solving anything. Also
note that hiding the cursor is not acceptable, it will be perceived as a
blink if the cursor was correct and near the location of the proximity-in.

- Proximity-in and enter events "freeze" the cursor at it's current
location, and it does not move until the client sets the cursor image.
Post by Peter Hutterer
---
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Makefile.am | 1 +
unstable/tablet/README | 4 +
unstable/tablet/tablet-unstable-v1.xml | 588
+++++++++++++++++++++++++++++++++
3 files changed, 593 insertions(+)
create mode 100644 unstable/tablet/README
create mode 100644 unstable/tablet/tablet-unstable-v1.xml
diff --git a/Makefile.am b/Makefile.am
index 4bcab32..588cb2c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,6 +6,7 @@ protocols =
\
unstable/text-input/text-input-unstable-v1.xml
\
unstable/input-method/input-method-unstable-v1.xml
\
unstable/xdg-shell/xdg-shell-unstable-v5.xml
\
+ unstable/tablet/tablet-unstable-v1.xml
\
$(NULL)
nobase_dist_pkgdata_DATA = $(protocols)
diff --git a/unstable/tablet/README b/unstable/tablet/README
new file mode 100644
index 0000000..7ba8e77
--- /dev/null
+++ b/unstable/tablet/README
@@ -0,0 +1,4 @@
+Tablet protocol
+
diff --git a/unstable/tablet/tablet-unstable-v1.xml
b/unstable/tablet/tablet-unstable-v1.xml
new file mode 100644
index 0000000..b07eccb
--- /dev/null
+++ b/unstable/tablet/tablet-unstable-v1.xml
@@ -0,0 +1,588 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland_tablet_unstable_v1">
+ <description summary="Wayland protocol for graphics tablets">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
+
+ The wp_tablet_seat sends a "tablet added" for each tablet connected.
+ That event is followed by descriptive events about the hardware;
+ currently that includes events for name, vid/pid and
+ internal/external/display type, and a wp_tablet.path event that
+ describes a local path. This path can be used to uniquely identify a
+ tablet, or get more information through libwacom. Emulated or nested
+ tablets can skip any of those, e.g. a virtual tablet may not have a
+ vid/pid. The sequence of descriptive events is terminated by a
+ wp_tablet.done event to signal that a client may now finalize any
+ initialization for that tablet.
+
+ Events from tablets require a tool in proximity. Tools are also managed
+ by the tablet seat, a "tool added" is sent whenever a tool is new to
+ the compositor. That event is followed by a number of descriptive events
+ about the hardware; currently that includes capabilities, serial id,
+ hardware serial and tool type. Similar to the tablet interface, a
+ wp_tablet_tool.done event is sent to terminate that initial sequence.
+
+ Any event from a tool happens on the wp_tablet_tool interface. When the
+ tool gets into proximity of the tablet, a proximity_in event is sent on
+ the wp_tablet_tool interface, listing the tablet and the surface. That
+ event is followed by a motion event with the coordinates. After that,
+ it's the usual motion, axis, button, etc. events.
+ The protocol's serialisation means events are grouped by by
+ wp_tablet_tool.frame events.
+
+ Two special events (that don't exist in X) are down and up. They signal
+ "tip touching the surface". For tablets without real proximity
+ detection, the sequence is: proximity_in, motion, down, frame.
+
+ When the tool leaves proximity, a proximity_out event is sent, followed
+ by button release events for any button still down. This signals to
+ the client that the buttons were held when the tool left proximity.
+ Those events are all sent within the same frame.
+
+ If the tool moves out of the surface but stays in proximity (i.e.
+ between windows), compositor-specific grab policies apply. This usually
+ means that the proximity-out is delayed until all buttons are released.
+
+ Moving a tool physically from one tablet to the other has no real effect
+ on the protocol, since we already have the tool object from the "tool
+ added" event. All the information is already there and the proximity_in
+ is all a client needs to reconstruct what happened.
+
+ Any extra axis is normalized, i.e. the client knows the range as
+ specified in the protocol (e.g. [0, 65535]), the granularity however is
+ unknown. The current axes are pressure, tilt (both x/y required) and
+ distance, the most common set.
+
+ Since tablets work independently of the pointer controlled by the mouse,
+ the focus handling is independent too and controlled by proximity.
+ The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
+ This cursor surface may be the same as the mouse cursor, and it may be
+ the same across tools but it is possible to be more fine-grained. For
+ example, a client may set different cursors for the pen and eraser.
+
+ Tools are generally independent of tablets and it is
+ compositor-specific policy when a tool can removed. Common approaches
+ will likely include some form of removing a tool when all tablets the
+ tool was used on is removed.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+ </description>
+ <copyright>
+ Copyright 2014 © Stephen "Lyude" Chandler Paul
+ Copyright 2015 © Red Hat, Inc.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ </copyright>
+ <interface name="zwp_tablet_manager1" version="1">
+ <description summary="controller object for graphic tablet devices">
+ An object that provides access to the graphics tablets available on this
+ system. Any tablet is associated with a seat, to get access to the
+ actual tablets, use wp_tablet_manager.get_tablet_seat.
+ </description>
+
+ <request name="get_tablet_seat">
+ <description summary="get the tablet seat">
+ Get the wp_tablet_seat object for the given seat. This object
+ provides access to all graphics tablets in this seat.
+ </description>
+ <arg name="tablet_seat" type="new_id" interface="zwp_tablet_seat1"/>
+ <arg name="seat" type="object" interface="wl_seat" summary="The
wl_seat object to retrieve the tablets for" />
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet manager object">
+ This destroys the resources associated with the tablet manager.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="zwp_tablet_seat1" version="1">
+ <description summary="controller object for graphic tablet devices of a seat">
+ An object that provides access to the graphics tablets available on this
+ seat. After binding to this interface, the compositor sends a set of
+ wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet seat object">
+ This destroys the resources associated with the tablet seat.
+ </description>
+ </request>
+
+ <event name="tablet_added">
+ <description summary="new device notification">
+ This event is sent whenever a new tablet becomes available on this
+ seat. This event only provides the object id of the tablet, any
+ static information about the tablet (device name, vid/pid, etc.) is
+ sent through the wp_tablet interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet1" summary="the
newly added graphics tablet"/>
+ </event>
+
+ <event name="tool_added">
+ <description summary="a new tool has been used with a tablet">
+ This event is sent whenever a tool that has not previously been
used
+ with a tablet comes into use. This event only provides the object
id
+ of the tool, any static information about the tool (capabilities,
+ type, et.c) is sent through the wp_tablet_tool interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet_tool1"
summary="the newly added tablet tool"/>
+ </event>
+ </interface>
+
+ <interface name="zwp_tablet_tool1" version="1">
+ <description summary="a physical tablet tool">
+ An unique object that represents a physical tool that has been, or is
+ currently in use with a tablet in this seat. Each wp_tablet_tool
+ object stays valid until the client destroys it; the compositor
+ reuses the wp_tablet_tool object to indicate that the object's
+ respective physical tool has come into proximity of a tablet again.
+ A client must not call wp_tablet_tool.destroy until it receives a
+ wp_tablet_tool.release event.
+
+ A wp_tablet_tool object's uniqueness depends on the tablet's ability
+ to report serial numbers. If the tablet doesn't support this
+ capability, then the tool cannot be guaranteed to be unique.
+
+ A tablet tool has a number of static characteristics, e.g. tool type,
+ serial_id and capabilities. These capabilities are sent in an event
+ sequence after the wp_tablet_seat.tool_added event before any actual
+ events from this tool. This initial event sequence is terminated by a
+ wp_tablet_tool.done event.
+
+ Tablet tool events are grouped by wp_tablet_tool.frame events.
+ Any events received before a wp_tablet_tool.frame event should be
+ considered part of the same hardware state change.
+ </description>
+
+ <request name="set_cursor">
+ <description summary="set the tablet tool's surface">
+ Sets the surface of the cursor used for this tool on the given
+ tablet. The surface is only shown when this tool is in proximity of
+ this tablet. If the surface is NULL, the pointer image is hidden
+ completely.
+
+ The parameters hotspot_x and hotspot_y define the position of the
+ pointer surface relative to the pointer location. Its top-left
corner
+ is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+ coordinates of the pointer location, in surface local coordinates.
+
+ On surface.attach requests to the pointer surface, hotspot_x and
+ hotspot_y are decremented by the x and y parameters passed to the
+ request. Attach must be confirmed by wl_surface.commit as usual.
+
+ The hotspot can also be updated by passing the currently set
pointer
+ surface to this request with new values for hotspot_x and
hotspot_y.
+
+ The current and pending input regions of the wl_surface are
cleared,
+ and wl_surface.set_input_region is ignored until the wl_surface is
no
+ longer used as the cursor. When the use as a cursor ends, the
current
+ and pending input regions become undefined, and the wl_surface is
+ unmapped.
+
+ This request gives the surface the role of a cursor. The role
+ assigned by this request is the same as assigned by
+ wl_pointer.set_cursor meaning the same surface can be
+ used both as a wl_pointer cursor and a wp_tablet cursor. If the
+ surface already has another role, it raises a protocol error
+ The surface may be used on multiple tablets and across multiple
+ seats.
+ </description>
+ <arg name="serial" type="uint" summary="serial of the enter event"/>
+ <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+ <arg name="hotspot_x" type="int" summary="x coordinate in
surface-relative coordinates"/>
+ <arg name="hotspot_y" type="int" summary="y coordinate in
surface-relative coordinates"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tool object">
+ This destroys the client's resource for this tool object.
+
+ A client must not issue this request until it receives a
+ wp_tablet_tool.remove event.
+ </description>
+ </request>
+
+ <enum name="type">
+ <description summary="a physical tool type">
+ Describes the physical type of a tool. The physical type of a tool
+ generally defines its base usage.
+
+ The mouse tool represents a mouse-shaped tool that is not a
relative
+ device but bound to the tablet's surface, providing absolute
+ coordinates.
+
+ The lens tool is a mouse-shaped tool with an attached lens to
+ provide precision focus.
+ </description>
+ <entry name="pen" value="0x140" summary="Pen"/>
+ <entry name="eraser" value="0x141" summary="Eraser"/>
+ <entry name="brush" value="0x142" summary="Brush"/>
+ <entry name="pencil" value="0x143" summary="Pencil"/>
+ <entry name="airbrush" value="0x144" summary="Airbrush"/>
+ <entry name="finger" value="0x145" summary="Finger"/>
+ <entry name="mouse" value="0x146" summary="Mouse"/>
+ <entry name="lens" value="0x147" summary="Lens"/>
+ </enum>
+
+ <event name="type">
+ <description summary="tool type">
+ The tool type is the high-level type of the tool and usually
decides
+ the interaction expected from this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="tool_type" type="uint" summary="the physical tool type"/>
+ </event>
+
+ <event name="serial_id">
+ <description summary="unique serial number of the tool">
+ If the tool can be identified by a unique 64-bit serial number,
this
+ event notifies the client of the serial number.
+
+ If multiple tablets are available in the same seat and the tool is
+ uniquely identifiable by the serial number, that tool may move
+ between tablets.
+
+ Otherwise, if the tool has no serial number and this event is
+ missing, the tool is tied to the tablet it first comes into
+ proximity with. Even if the physical tool is used on multiple
+ tablets, separate wp_tablet_tool objects will be created, one per
+ tablet.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="serial_id_msb" type="uint" summary="the unique serial
number of the tool, most significant bits"/>
+ <arg name="serial_id_lsb" type="uint" summary="the unique serial
number of the tool, least significant bits"/>
+ </event>
+
+ <enum name="hardware_id_format">
+ <description summary="the hardware id format">
+ Specifies the format of the hardware id in the
+ wp_tablet_tool.hardware_id event.
+
+ A wacom_stylus_id format indicates a hardware id as the id used by
+ graphics tablet made by Wacom Inc. For example, on Wacom tablets
the
+ hardware id of a Grip Pen (a stylus) is 0x802.
+ </description>
+ <entry name="wacom_stylus_id" value="0" />
+ </enum>
+
+ <event name="hardware_id">
+ <description summary="hardware id notification">
+ This event notifies the client of a hardware id available on this
tool.
+
+ The hardware id is a device-specific 64-bit id that provides extra
+ information about the tool in use, beyond the wl_tool.type
+ enumeration. The format of the id is device-specific.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="format" type="uint" summary="the type of the id" />
+ <arg name="hardware_id_msb" type="uint" summary="the hardware id,
most significant bits"/>
+ <arg name="hardware_id_lsb" type="uint" summary="the hardware id,
least significant bits"/>
+ </event>
+
+
+ <enum name="capability">
+ <description summary="capability flags for a tool">
+ Describes extra capabilities on a tablet.
+
+ Any tool must provide x and y values, extra axes are
+ device-specific.
+ </description>
+ <entry name="tilt" value="1" summary="Tilt axes"/>
+ <entry name="pressure" value="2" summary="Pressure axis"/>
+ <entry name="distance" value="3" summary="Distance axis"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="tool capability notification">
+ This event notifies the client of any capabilities of this tool,
+ beyond the main set of x/y axes and tip up/down detection.
+
+ One event is sent for each extra capability available on this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="capability" type="uint" summary="the capability"/>
+ </event>
+
+ <event name="done">
+ <description summary="tool description events sequence complete">
+ This event signals the end of the initial burst of descriptive
+ events. A client may consider the static description of the tool to
+ be complete and finalize initialization of the tool.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tool removed">
+ This event is sent when the tool is removed from the system. The
client
+ should not expect the resource it currently has associated with the
+ tool to be used again if the tool comes back into proximity later.
+
+ It is compositor-dependent when a tool is removed. Some tools are
+ associated with a single tablet only and may get removed when the
+ respective tablet is removed. Other tools may be used on multiple
+ tablets and removing a tablet may not remove this tool.
+
+ When this event is received, the client must wp_tablet_tool.destroy
+ the object.
+ </description>
+ </event>
+
+ <event name="proximity_in">
+ <description summary="proximity in event">
+ Notification that this tool is focused on a certain surface.
+
+ This event can be received when the tool has moved from one
surface to
+ another, or when the tool has come back into proximity above the
+ surface.
+
+ Any button events sent within the same wp_tablet.frame as a
+ proximity_in event indicate the button state of the tool at the
time
+ of proximity in.
+ </description>
+ <arg name="serial" type="uint"/>
+ <arg name="tablet" type="object" interface="zwp_tablet1"
summary="The tablet the tool is in proximity of"/>
+ <arg name="surface" type="object" interface="wl_surface"
summary="The current surface the tablet tool is over"/>
+ </event>
+
+ <event name="proximity_out">
+ <description summary="proximity out event">
+ Notification that this tool has either left proximity, or is no
+ longer focused on a certain surface.
+
+ When the tablet tool leaves proximity of the tablet, button release
+ events are sent for each button that was held down at the time of
+ leaving proximity. These events are sent in the same
wp_tablet.frame
+ of the proximity_out event.
+
+ If the tool stays within proximity of the tablet, but the focus
+ changes from one surface to another, a button release event may not
+ be sent until the button is actually released or the tool leaves
the
+ proximity of the tablet.
+ </description>
+ </event>
+
+ <event name="down">
+ <description summary="tablet tool is making contact">
+ Sent whenever the tablet tool comes in contact with the surface of
the
+ tablet. If the tablet tool moves out of a region while in contact
with
+ the surface of the tablet, the client owning said region will
receive a
+ wp_tablet::up event, followed by a wp_tablet::proximity_out event
and a
+ wp_tablet::frame event.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
+
+ <event name="up">
+ <description summary="tablet tool is no longer making contact">
+ Sent whenever the tablet tool stops making contact with the
surface of
+ the tablet, or when the tablet tool moves off of a surface while
it was
+ making contact with the tablet's surface.
+ </description>
+ </event>
+
+ <event name="motion">
+ <description summary="motion event">
+ Sent whenever a tablet tool moves.
+ </description>
+ <arg name="x" type="fixed" summary="surface-relative x coordinate"/>
+ <arg name="y" type="fixed" summary="surface-relative y coordinate"/>
+ </event>
+
+ <event name="pressure">
+ <description summary="pressure change event">
+ Sent whenever the pressure axis on a tool changes. The value of
this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="pressure" type="uint" summary="The current pressure value"/>
+ </event>
+
+ <event name="distance">
+ <description summary="distance change event">
+ Sent whenever the distance axis on a tool changes. The value of
this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="distance" type="uint" summary="The current distance value"/>
+ </event>
+
+ <event name="tilt">
+ <description summary="tilt change event">
+ Sent whenever one or both of the tilt axes on a tool change. Each
tilt
+ value is normalized between -65535 and 65535.
+ </description>
+ <arg name="tilt_x" type="int" summary="The current value of the X tilt axis"/>
+ <arg name="tilt_y" type="int" summary="The current value of the Y tilt axis"/>
+ </event>
+
+ <enum name="button_state">
+ <description summary="physical button state">
+ Describes the physical state of a button which provoked the button
event
+ </description>
+ <entry name="released" value="0" summary="button is not pressed"/>
+ <entry name="pressed" value="1" summary="button is pressed"/>
+ </enum>
+
+ <event name="button">
+ <description summary="button event">
+ Sent whenever a button on the stylus is pressed or released.
+ </description>
+
+ <arg name="serial" type="uint"/>
+ <arg name="button" type="uint" summary="The button whose state has changed"/>
+ <arg name="state" type="uint" summary="Whether the button was pressed or released"/>
+ </event>
+
+ <event name="frame">
+ <description summary="frame event">
+ Marks the end of a series of axis and/or button updates from the
+ tablet. The wayland protocol requires axis updates to be sent
+ sequentially, however all events within a frame should be
considered
+ one hardware event.
+ </description>
+ <arg name="time" type="uint" summary="The time of the event with
millisecond granularity"/>
+ </event>
+
+ <enum name="error">
+ <entry name="role" value="0" summary="given wl_surface has another role"/>
+ </enum>
+ </interface>
+
+ <interface name="zwp_tablet1" version="1">
+ <description summary="graphics tablet device">
+ The wp_tablet interface represents one graphics tablet device. The
+ tablet interface itself does not generate events, all events are
+ generated by wp_tablet_tool objects when in proximity above a tablet.
+
+ A tablet has a number of static characteristics, e.g. device name and
+ pid/vid. These capabilities are sent in an event sequence after the
+ wp_tablet_seat.tablet_added event. This initial event sequence is
+ terminated by a wp_tablet.done event.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tablet object">
+ This destroys the client's resource for this tablet object.
+
+ A client must not issue this request until it receives a
+ wp_tablet.remove event.
+ </description>
+ </request>
+
+ <event name="name">
+ <description summary="tablet device name">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="name" type="string" summary="the device name"/>
+ </event>
+
+ <event name="id">
+ <description summary="tablet device vid/pid">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="vid" type="uint" summary="vendor id"/>
+ <arg name="pid" type="uint" summary="product id"/>
+ </event>
+
+ <enum name="type">
+ <description summary="tablet type">
+ Describes the type of tablet
+ </description>
+
+ <entry name="external" value="0" summary="The tablet is an external
tablet, such as an Intuos"/>
+ <entry name="internal" value="1" summary="The tablet is a built-in
tablet, usually in a laptop"/>
+ <entry name="display" value="2" summary="The tablet is a display
tablet, such as a Cintiq"/>
+ </enum>
+
+ <event name="type">
+ <description summary="the tablet type">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="type" type="uint" summary="the tablet type (internal, external, ...)"/>
+ </event>
+
+ <event name="path">
+ <description summary="path to the device">
+ A system-specific device path that indicates which device is behind
+ this wp_tablet. This information may be used to gather additional
+ information about the device, e.g. through libwacom.
+
+ A device may have more than one device path, if so, multiple
+ wp_tablet.path events are sent. A device may be emulated and not
+ have a device path, in that case this event will not be sent.
+
+ The format of the path is unspecified, it may be a device node, a
+ sysfs path, or some other identifier. It is up to the client to
+ identify the string provided.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="path" type="string" summary="path to local device"/>
+ </event>
+
+ <event name="done">
+ <description summary="tablet description events sequence complete">
+ This event is sent immediately to signal the end of the initial
+ burst of descriptive events. A client may consider the static
+ description of the tablet to be complete and finalize
initialization
+ of the tablet.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tablet removed event">
+ Sent when the tablet has been removed from the system. When a
tablet
+ is removed, some tools may be removed.
+
+ When this event is received, the client must wp_tablet.destroy
+ the object.
+ </description>
+ </event>
+ </interface>
+</protocol>
--
2.4.3
_______________________________________________
wayland-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Jason Gerecke
2015-11-09 22:33:39 UTC
Permalink
Post by Bill Spitzak
Having read this more carefully, the cursor scheme absolutely will not work.
The main problem is that the client may want to choose a cursor for a tool
based on the location at which it came into proximity. It cannot set this
cursor until after it gets the proximity event. If this desired cursor is
different than the one the tool currently has set then that incorrect cursor
will be seen, at least briefly.
I'm afraid I don't understand what meaningful difference there is
between the scheme here and wl_pointer. As you point out, there is a
brief window of time when the incorrect cursor can be seen with _both_
protocols. Its a simple result of the fact that a client _can't_ know
that it needs to change the cursor until _after_ it receives some kind
of focus event ('enter' or 'proximity_in'). I suppose the client could
provide a reference to the surface over which a particular
'set_cursor' should take effect (and then have the compositor keep
track of all those references) but I'm sure that has its own issues.
Post by Bill Spitzak
A further problem is that there has to be an easy transition between clients
that don't use the tablet api and those that do. Operation of gui widgets
that work equally well with mouse or tablet should not change just because
the client has decided to enable the tablet interface. The primary problem
is that the pointer position must move to the last tablet tool positiion
whether or not the client is using the tablet interface. This then means
there cannot be more than one cursor (since they would be right atop each
other).
While I absolutely agree that GUI widgets should work equally well
with a tablet as a pointer, the "primary problem" is not that the
pointer has to be moved; widgets can work just fine if they're aware
of the tablet protocol. The fundamental problem that prevents things
from "just working" is that tablets don't send wl_pointer events of
any kind.

There's certainly a compatibility benefit to having the tablet
controlling the pointer, but it isn't always appropriate. Although you
can get away with it in the most common case of a non-display tablet
mapped to the entire desktop, it gets annoying _fast_ when a tablet
which is mapped to just a portion of the desktop (e.g. a display
tablet on a multi-head system) since you /don't/ generally want the
mouse cursor to move: you just want the UI elements you click on to
respond. Putting tablets into separate seats might be a solution to
this, but it seems like its ripe for causing other unintended problems
(e.g. clicking on a text box and then not being able to type since the
keyboard focus isn't associated with the same seat as the tablet).

Leaving support for the tablet protocol up to the client gives me
pause, but its less frightening once you consider that practically any
non-toy application will be written with the aid of a toolkit. As long
as the toolkits do the right thing, so will applications built on
them. Its the same situation with touch: authors who don't use a
toolkit can write applications that don't function with a touchscreen,
but most applications will work fine since toolkits know they need to
handle wl_touch.
Post by Bill Spitzak
- Proximity-in jumps the cursor and pointer position to the location but
does not change the cursor. It will however send proximity-in events to the
client (it will also send proximity-out to other clients using the tablet
interface, and normal wl_pointer exit events to clients not using the tablet
interface).
- Client should respond to proximity-in by setting the wl_pointer cursor to
whatever is desired. Notice this is identical to how clients not using the
tablet interface respond to wl_pointer::enter events.
This will 'blink' still, as the current cursor is also possibly not equal to
the desired cursor. This could be fixed, but if so the exact same fix must
be done to enter events or you really are not solving anything. Also note
that hiding the cursor is not acceptable, it will be perceived as a blink if
the cursor was correct and near the location of the proximity-in.
Disagree with these two recommendations as outlined above.
Post by Bill Spitzak
- Proximity-in and enter events "freeze" the cursor at it's current
location, and it does not move until the client sets the cursor image.
Wouldn't this alone solve the issue of the wrong pointer being
displayed for a split-second? I'm not sure if its the compositor's
place to "freeze" the cursor until a client responds (that sounds a
little dicey, especially with hung clients), but it could be an
interesting approach.

Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
Post by Bill Spitzak
Post by Peter Hutterer
---
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Makefile.am | 1 +
unstable/tablet/README | 4 +
unstable/tablet/tablet-unstable-v1.xml | 588
+++++++++++++++++++++++++++++++++
3 files changed, 593 insertions(+)
create mode 100644 unstable/tablet/README
create mode 100644 unstable/tablet/tablet-unstable-v1.xml
diff --git a/Makefile.am b/Makefile.am
index 4bcab32..588cb2c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,6 +6,7 @@ protocols =
\
unstable/text-input/text-input-unstable-v1.xml
\
unstable/input-method/input-method-unstable-v1.xml
\
unstable/xdg-shell/xdg-shell-unstable-v5.xml
\
+ unstable/tablet/tablet-unstable-v1.xml
\
$(NULL)
nobase_dist_pkgdata_DATA = $(protocols)
diff --git a/unstable/tablet/README b/unstable/tablet/README
new file mode 100644
index 0000000..7ba8e77
--- /dev/null
+++ b/unstable/tablet/README
@@ -0,0 +1,4 @@
+Tablet protocol
+
diff --git a/unstable/tablet/tablet-unstable-v1.xml
b/unstable/tablet/tablet-unstable-v1.xml
new file mode 100644
index 0000000..b07eccb
--- /dev/null
+++ b/unstable/tablet/tablet-unstable-v1.xml
@@ -0,0 +1,588 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland_tablet_unstable_v1">
+ <description summary="Wayland protocol for graphics tablets">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
+
+ The wp_tablet_seat sends a "tablet added" for each tablet connected.
+ That event is followed by descriptive events about the hardware;
+ currently that includes events for name, vid/pid and
+ internal/external/display type, and a wp_tablet.path event that
+ describes a local path. This path can be used to uniquely identify a
+ tablet, or get more information through libwacom. Emulated or nested
+ tablets can skip any of those, e.g. a virtual tablet may not have a
+ vid/pid. The sequence of descriptive events is terminated by a
+ wp_tablet.done event to signal that a client may now finalize any
+ initialization for that tablet.
+
+ Events from tablets require a tool in proximity. Tools are also managed
+ by the tablet seat, a "tool added" is sent whenever a tool is new to
+ the compositor. That event is followed by a number of descriptive events
+ about the hardware; currently that includes capabilities, serial id,
+ hardware serial and tool type. Similar to the tablet interface, a
+ wp_tablet_tool.done event is sent to terminate that initial sequence.
+
+ Any event from a tool happens on the wp_tablet_tool interface. When the
+ tool gets into proximity of the tablet, a proximity_in event is sent on
+ the wp_tablet_tool interface, listing the tablet and the surface. That
+ event is followed by a motion event with the coordinates. After that,
+ it's the usual motion, axis, button, etc. events.
+ The protocol's serialisation means events are grouped by by
+ wp_tablet_tool.frame events.
+
+ Two special events (that don't exist in X) are down and up. They signal
+ "tip touching the surface". For tablets without real proximity
+ detection, the sequence is: proximity_in, motion, down, frame.
+
+ When the tool leaves proximity, a proximity_out event is sent, followed
+ by button release events for any button still down. This signals to
+ the client that the buttons were held when the tool left proximity.
+ Those events are all sent within the same frame.
+
+ If the tool moves out of the surface but stays in proximity (i.e.
+ between windows), compositor-specific grab policies apply. This usually
+ means that the proximity-out is delayed until all buttons are released.
+
+ Moving a tool physically from one tablet to the other has no real effect
+ on the protocol, since we already have the tool object from the "tool
+ added" event. All the information is already there and the proximity_in
+ is all a client needs to reconstruct what happened.
+
+ Any extra axis is normalized, i.e. the client knows the range as
+ specified in the protocol (e.g. [0, 65535]), the granularity however is
+ unknown. The current axes are pressure, tilt (both x/y required) and
+ distance, the most common set.
+
+ Since tablets work independently of the pointer controlled by the mouse,
+ the focus handling is independent too and controlled by proximity.
+ The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
+ This cursor surface may be the same as the mouse cursor, and it may be
+ the same across tools but it is possible to be more fine-grained. For
+ example, a client may set different cursors for the pen and eraser.
+
+ Tools are generally independent of tablets and it is
+ compositor-specific policy when a tool can removed. Common approaches
+ will likely include some form of removing a tool when all tablets the
+ tool was used on is removed.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+ </description>
+ <copyright>
+ Copyright 2014 © Stephen "Lyude" Chandler Paul
+ Copyright 2015 © Red Hat, Inc.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ </copyright>
+ <interface name="zwp_tablet_manager1" version="1">
+ <description summary="controller object for graphic tablet devices">
+ An object that provides access to the graphics tablets available on this
+ system. Any tablet is associated with a seat, to get access to the
+ actual tablets, use wp_tablet_manager.get_tablet_seat.
+ </description>
+
+ <request name="get_tablet_seat">
+ <description summary="get the tablet seat">
+ Get the wp_tablet_seat object for the given seat. This object
+ provides access to all graphics tablets in this seat.
+ </description>
+ <arg name="tablet_seat" type="new_id"
interface="zwp_tablet_seat1"/>
+ <arg name="seat" type="object" interface="wl_seat" summary="The
wl_seat object to retrieve the tablets for" />
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet manager object">
+ This destroys the resources associated with the tablet manager.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="zwp_tablet_seat1" version="1">
+ <description summary="controller object for graphic tablet devices of a seat">
+ An object that provides access to the graphics tablets available on this
+ seat. After binding to this interface, the compositor sends a set of
+ wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet seat object">
+ This destroys the resources associated with the tablet seat.
+ </description>
+ </request>
+
+ <event name="tablet_added">
+ <description summary="new device notification">
+ This event is sent whenever a new tablet becomes available on this
+ seat. This event only provides the object id of the tablet, any
+ static information about the tablet (device name, vid/pid, etc.) is
+ sent through the wp_tablet interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet1" summary="the
newly added graphics tablet"/>
+ </event>
+
+ <event name="tool_added">
+ <description summary="a new tool has been used with a tablet">
+ This event is sent whenever a tool that has not previously been
used
+ with a tablet comes into use. This event only provides the object
id
+ of the tool, any static information about the tool (capabilities,
+ type, et.c) is sent through the wp_tablet_tool interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet_tool1"
summary="the newly added tablet tool"/>
+ </event>
+ </interface>
+
+ <interface name="zwp_tablet_tool1" version="1">
+ <description summary="a physical tablet tool">
+ An unique object that represents a physical tool that has been, or is
+ currently in use with a tablet in this seat. Each wp_tablet_tool
+ object stays valid until the client destroys it; the compositor
+ reuses the wp_tablet_tool object to indicate that the object's
+ respective physical tool has come into proximity of a tablet again.
+ A client must not call wp_tablet_tool.destroy until it receives a
+ wp_tablet_tool.release event.
+
+ A wp_tablet_tool object's uniqueness depends on the tablet's ability
+ to report serial numbers. If the tablet doesn't support this
+ capability, then the tool cannot be guaranteed to be unique.
+
+ A tablet tool has a number of static characteristics, e.g. tool type,
+ serial_id and capabilities. These capabilities are sent in an event
+ sequence after the wp_tablet_seat.tool_added event before any actual
+ events from this tool. This initial event sequence is terminated by a
+ wp_tablet_tool.done event.
+
+ Tablet tool events are grouped by wp_tablet_tool.frame events.
+ Any events received before a wp_tablet_tool.frame event should be
+ considered part of the same hardware state change.
+ </description>
+
+ <request name="set_cursor">
+ <description summary="set the tablet tool's surface">
+ Sets the surface of the cursor used for this tool on the given
+ tablet. The surface is only shown when this tool is in proximity of
+ this tablet. If the surface is NULL, the pointer image is hidden
+ completely.
+
+ The parameters hotspot_x and hotspot_y define the position of the
+ pointer surface relative to the pointer location. Its top-left
corner
+ is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+ coordinates of the pointer location, in surface local coordinates.
+
+ On surface.attach requests to the pointer surface, hotspot_x and
+ hotspot_y are decremented by the x and y parameters passed to the
+ request. Attach must be confirmed by wl_surface.commit as usual.
+
+ The hotspot can also be updated by passing the currently set
pointer
+ surface to this request with new values for hotspot_x and
hotspot_y.
+
+ The current and pending input regions of the wl_surface are
cleared,
+ and wl_surface.set_input_region is ignored until the wl_surface is
no
+ longer used as the cursor. When the use as a cursor ends, the
current
+ and pending input regions become undefined, and the wl_surface is
+ unmapped.
+
+ This request gives the surface the role of a cursor. The role
+ assigned by this request is the same as assigned by
+ wl_pointer.set_cursor meaning the same surface can be
+ used both as a wl_pointer cursor and a wp_tablet cursor. If the
+ surface already has another role, it raises a protocol error
+ The surface may be used on multiple tablets and across multiple
+ seats.
+ </description>
+ <arg name="serial" type="uint" summary="serial of the enter event"/>
+ <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+ <arg name="hotspot_x" type="int" summary="x coordinate in
surface-relative coordinates"/>
+ <arg name="hotspot_y" type="int" summary="y coordinate in
surface-relative coordinates"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tool object">
+ This destroys the client's resource for this tool object.
+
+ A client must not issue this request until it receives a
+ wp_tablet_tool.remove event.
+ </description>
+ </request>
+
+ <enum name="type">
+ <description summary="a physical tool type">
+ Describes the physical type of a tool. The physical type of a tool
+ generally defines its base usage.
+
+ The mouse tool represents a mouse-shaped tool that is not a
relative
+ device but bound to the tablet's surface, providing absolute
+ coordinates.
+
+ The lens tool is a mouse-shaped tool with an attached lens to
+ provide precision focus.
+ </description>
+ <entry name="pen" value="0x140" summary="Pen"/>
+ <entry name="eraser" value="0x141" summary="Eraser"/>
+ <entry name="brush" value="0x142" summary="Brush"/>
+ <entry name="pencil" value="0x143" summary="Pencil"/>
+ <entry name="airbrush" value="0x144" summary="Airbrush"/>
+ <entry name="finger" value="0x145" summary="Finger"/>
+ <entry name="mouse" value="0x146" summary="Mouse"/>
+ <entry name="lens" value="0x147" summary="Lens"/>
+ </enum>
+
+ <event name="type">
+ <description summary="tool type">
+ The tool type is the high-level type of the tool and usually
decides
+ the interaction expected from this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="tool_type" type="uint" summary="the physical tool type"/>
+ </event>
+
+ <event name="serial_id">
+ <description summary="unique serial number of the tool">
+ If the tool can be identified by a unique 64-bit serial number,
this
+ event notifies the client of the serial number.
+
+ If multiple tablets are available in the same seat and the tool is
+ uniquely identifiable by the serial number, that tool may move
+ between tablets.
+
+ Otherwise, if the tool has no serial number and this event is
+ missing, the tool is tied to the tablet it first comes into
+ proximity with. Even if the physical tool is used on multiple
+ tablets, separate wp_tablet_tool objects will be created, one per
+ tablet.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="serial_id_msb" type="uint" summary="the unique serial
number of the tool, most significant bits"/>
+ <arg name="serial_id_lsb" type="uint" summary="the unique serial
number of the tool, least significant bits"/>
+ </event>
+
+ <enum name="hardware_id_format">
+ <description summary="the hardware id format">
+ Specifies the format of the hardware id in the
+ wp_tablet_tool.hardware_id event.
+
+ A wacom_stylus_id format indicates a hardware id as the id used by
+ graphics tablet made by Wacom Inc. For example, on Wacom tablets
the
+ hardware id of a Grip Pen (a stylus) is 0x802.
+ </description>
+ <entry name="wacom_stylus_id" value="0" />
+ </enum>
+
+ <event name="hardware_id">
+ <description summary="hardware id notification">
+ This event notifies the client of a hardware id available on this
tool.
+
+ The hardware id is a device-specific 64-bit id that provides extra
+ information about the tool in use, beyond the wl_tool.type
+ enumeration. The format of the id is device-specific.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="format" type="uint" summary="the type of the id" />
+ <arg name="hardware_id_msb" type="uint" summary="the hardware id,
most significant bits"/>
+ <arg name="hardware_id_lsb" type="uint" summary="the hardware id,
least significant bits"/>
+ </event>
+
+
+ <enum name="capability">
+ <description summary="capability flags for a tool">
+ Describes extra capabilities on a tablet.
+
+ Any tool must provide x and y values, extra axes are
+ device-specific.
+ </description>
+ <entry name="tilt" value="1" summary="Tilt axes"/>
+ <entry name="pressure" value="2" summary="Pressure axis"/>
+ <entry name="distance" value="3" summary="Distance axis"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="tool capability notification">
+ This event notifies the client of any capabilities of this tool,
+ beyond the main set of x/y axes and tip up/down detection.
+
+ One event is sent for each extra capability available on this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="capability" type="uint" summary="the capability"/>
+ </event>
+
+ <event name="done">
+ <description summary="tool description events sequence complete">
+ This event signals the end of the initial burst of descriptive
+ events. A client may consider the static description of the tool to
+ be complete and finalize initialization of the tool.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tool removed">
+ This event is sent when the tool is removed from the system. The
client
+ should not expect the resource it currently has associated with the
+ tool to be used again if the tool comes back into proximity later.
+
+ It is compositor-dependent when a tool is removed. Some tools are
+ associated with a single tablet only and may get removed when the
+ respective tablet is removed. Other tools may be used on multiple
+ tablets and removing a tablet may not remove this tool.
+
+ When this event is received, the client must
wp_tablet_tool.destroy
+ the object.
+ </description>
+ </event>
+
+ <event name="proximity_in">
+ <description summary="proximity in event">
+ Notification that this tool is focused on a certain surface.
+
+ This event can be received when the tool has moved from one
surface to
+ another, or when the tool has come back into proximity above the
+ surface.
+
+ Any button events sent within the same wp_tablet.frame as a
+ proximity_in event indicate the button state of the tool at the
time
+ of proximity in.
+ </description>
+ <arg name="serial" type="uint"/>
+ <arg name="tablet" type="object" interface="zwp_tablet1"
summary="The tablet the tool is in proximity of"/>
+ <arg name="surface" type="object" interface="wl_surface"
summary="The current surface the tablet tool is over"/>
+ </event>
+
+ <event name="proximity_out">
+ <description summary="proximity out event">
+ Notification that this tool has either left proximity, or is no
+ longer focused on a certain surface.
+
+ When the tablet tool leaves proximity of the tablet, button release
+ events are sent for each button that was held down at the time of
+ leaving proximity. These events are sent in the same
wp_tablet.frame
+ of the proximity_out event.
+
+ If the tool stays within proximity of the tablet, but the focus
+ changes from one surface to another, a button release event may not
+ be sent until the button is actually released or the tool leaves
the
+ proximity of the tablet.
+ </description>
+ </event>
+
+ <event name="down">
+ <description summary="tablet tool is making contact">
+ Sent whenever the tablet tool comes in contact with the surface of
the
+ tablet. If the tablet tool moves out of a region while in contact
with
+ the surface of the tablet, the client owning said region will
receive a
+ wp_tablet::up event, followed by a wp_tablet::proximity_out event
and a
+ wp_tablet::frame event.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
+
+ <event name="up">
+ <description summary="tablet tool is no longer making contact">
+ Sent whenever the tablet tool stops making contact with the
surface of
+ the tablet, or when the tablet tool moves off of a surface while
it was
+ making contact with the tablet's surface.
+ </description>
+ </event>
+
+ <event name="motion">
+ <description summary="motion event">
+ Sent whenever a tablet tool moves.
+ </description>
+ <arg name="x" type="fixed" summary="surface-relative x
coordinate"/>
+ <arg name="y" type="fixed" summary="surface-relative y
coordinate"/>
+ </event>
+
+ <event name="pressure">
+ <description summary="pressure change event">
+ Sent whenever the pressure axis on a tool changes. The value of
this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="pressure" type="uint" summary="The current pressure value"/>
+ </event>
+
+ <event name="distance">
+ <description summary="distance change event">
+ Sent whenever the distance axis on a tool changes. The value of
this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="distance" type="uint" summary="The current distance value"/>
+ </event>
+
+ <event name="tilt">
+ <description summary="tilt change event">
+ Sent whenever one or both of the tilt axes on a tool change. Each
tilt
+ value is normalized between -65535 and 65535.
+ </description>
+ <arg name="tilt_x" type="int" summary="The current value of the X tilt axis"/>
+ <arg name="tilt_y" type="int" summary="The current value of the Y tilt axis"/>
+ </event>
+
+ <enum name="button_state">
+ <description summary="physical button state">
+ Describes the physical state of a button which provoked the button
event
+ </description>
+ <entry name="released" value="0" summary="button is not pressed"/>
+ <entry name="pressed" value="1" summary="button is pressed"/>
+ </enum>
+
+ <event name="button">
+ <description summary="button event">
+ Sent whenever a button on the stylus is pressed or released.
+ </description>
+
+ <arg name="serial" type="uint"/>
+ <arg name="button" type="uint" summary="The button whose state has changed"/>
+ <arg name="state" type="uint" summary="Whether the button was
pressed or released"/>
+ </event>
+
+ <event name="frame">
+ <description summary="frame event">
+ Marks the end of a series of axis and/or button updates from the
+ tablet. The wayland protocol requires axis updates to be sent
+ sequentially, however all events within a frame should be
considered
+ one hardware event.
+ </description>
+ <arg name="time" type="uint" summary="The time of the event with
millisecond granularity"/>
+ </event>
+
+ <enum name="error">
+ <entry name="role" value="0" summary="given wl_surface has another role"/>
+ </enum>
+ </interface>
+
+ <interface name="zwp_tablet1" version="1">
+ <description summary="graphics tablet device">
+ The wp_tablet interface represents one graphics tablet device. The
+ tablet interface itself does not generate events, all events are
+ generated by wp_tablet_tool objects when in proximity above a tablet.
+
+ A tablet has a number of static characteristics, e.g. device name and
+ pid/vid. These capabilities are sent in an event sequence after the
+ wp_tablet_seat.tablet_added event. This initial event sequence is
+ terminated by a wp_tablet.done event.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tablet object">
+ This destroys the client's resource for this tablet object.
+
+ A client must not issue this request until it receives a
+ wp_tablet.remove event.
+ </description>
+ </request>
+
+ <event name="name">
+ <description summary="tablet device name">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="name" type="string" summary="the device name"/>
+ </event>
+
+ <event name="id">
+ <description summary="tablet device vid/pid">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="vid" type="uint" summary="vendor id"/>
+ <arg name="pid" type="uint" summary="product id"/>
+ </event>
+
+ <enum name="type">
+ <description summary="tablet type">
+ Describes the type of tablet
+ </description>
+
+ <entry name="external" value="0" summary="The tablet is an external
tablet, such as an Intuos"/>
+ <entry name="internal" value="1" summary="The tablet is a built-in
tablet, usually in a laptop"/>
+ <entry name="display" value="2" summary="The tablet is a display
tablet, such as a Cintiq"/>
+ </enum>
+
+ <event name="type">
+ <description summary="the tablet type">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="type" type="uint" summary="the tablet type (internal, external, ...)"/>
+ </event>
+
+ <event name="path">
+ <description summary="path to the device">
+ A system-specific device path that indicates which device is behind
+ this wp_tablet. This information may be used to gather additional
+ information about the device, e.g. through libwacom.
+
+ A device may have more than one device path, if so, multiple
+ wp_tablet.path events are sent. A device may be emulated and not
+ have a device path, in that case this event will not be sent.
+
+ The format of the path is unspecified, it may be a device node, a
+ sysfs path, or some other identifier. It is up to the client to
+ identify the string provided.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="path" type="string" summary="path to local device"/>
+ </event>
+
+ <event name="done">
+ <description summary="tablet description events sequence complete">
+ This event is sent immediately to signal the end of the initial
+ burst of descriptive events. A client may consider the static
+ description of the tablet to be complete and finalize
initialization
+ of the tablet.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tablet removed event">
+ Sent when the tablet has been removed from the system. When a
tablet
+ is removed, some tools may be removed.
+
+ When this event is received, the client must wp_tablet.destroy
+ the object.
+ </description>
+ </event>
+ </interface>
+</protocol>
--
2.4.3
_______________________________________________
wayland-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Peter Hutterer
2015-11-10 02:00:08 UTC
Permalink
Post by Jason Gerecke
Post by Bill Spitzak
Having read this more carefully, the cursor scheme absolutely will not work.
The main problem is that the client may want to choose a cursor for a tool
based on the location at which it came into proximity. It cannot set this
cursor until after it gets the proximity event. If this desired cursor is
different than the one the tool currently has set then that incorrect cursor
will be seen, at least briefly.
I'm afraid I don't understand what meaningful difference there is
between the scheme here and wl_pointer. As you point out, there is a
brief window of time when the incorrect cursor can be seen with _both_
protocols. Its a simple result of the fact that a client _can't_ know
that it needs to change the cursor until _after_ it receives some kind
of focus event ('enter' or 'proximity_in'). I suppose the client could
provide a reference to the surface over which a particular
'set_cursor' should take effect (and then have the compositor keep
track of all those references) but I'm sure that has its own issues.
Post by Bill Spitzak
A further problem is that there has to be an easy transition between clients
that don't use the tablet api and those that do. Operation of gui widgets
that work equally well with mouse or tablet should not change just because
the client has decided to enable the tablet interface. The primary problem
is that the pointer position must move to the last tablet tool positiion
whether or not the client is using the tablet interface. This then means
there cannot be more than one cursor (since they would be right atop each
other).
While I absolutely agree that GUI widgets should work equally well
with a tablet as a pointer, the "primary problem" is not that the
pointer has to be moved; widgets can work just fine if they're aware
of the tablet protocol. The fundamental problem that prevents things
from "just working" is that tablets don't send wl_pointer events of
any kind.
There's certainly a compatibility benefit to having the tablet
controlling the pointer, but it isn't always appropriate.
note that the protocol doesn't *prevent* a compositor from emulating
wl_pointer events for tablet events. the weston implementation here doesn't
do so because I think it's a bad idea (for the reasons you outlined anyway)
but in theory nothing stops anyone from doing so.
Post by Jason Gerecke
Although you
can get away with it in the most common case of a non-display tablet
mapped to the entire desktop, it gets annoying _fast_ when a tablet
which is mapped to just a portion of the desktop (e.g. a display
tablet on a multi-head system) since you /don't/ generally want the
mouse cursor to move: you just want the UI elements you click on to
respond. Putting tablets into separate seats might be a solution to
this, but it seems like its ripe for causing other unintended problems
(e.g. clicking on a text box and then not being able to type since the
keyboard focus isn't associated with the same seat as the tablet).
Leaving support for the tablet protocol up to the client gives me
pause, but its less frightening once you consider that practically any
non-toy application will be written with the aid of a toolkit. As long
as the toolkits do the right thing, so will applications built on
them. Its the same situation with touch: authors who don't use a
toolkit can write applications that don't function with a touchscreen,
but most applications will work fine since toolkits know they need to
handle wl_touch.
Post by Bill Spitzak
- Proximity-in jumps the cursor and pointer position to the location but
does not change the cursor. It will however send proximity-in events to the
client (it will also send proximity-out to other clients using the tablet
interface, and normal wl_pointer exit events to clients not using the tablet
interface).
- Client should respond to proximity-in by setting the wl_pointer cursor to
whatever is desired. Notice this is identical to how clients not using the
tablet interface respond to wl_pointer::enter events.
This will 'blink' still, as the current cursor is also possibly not equal to
the desired cursor. This could be fixed, but if so the exact same fix must
be done to enter events or you really are not solving anything. Also note
that hiding the cursor is not acceptable, it will be perceived as a blink if
the cursor was correct and near the location of the proximity-in.
Disagree with these two recommendations as outlined above.
Post by Bill Spitzak
- Proximity-in and enter events "freeze" the cursor at it's current
location, and it does not move until the client sets the cursor image.
Wouldn't this alone solve the issue of the wrong pointer being
displayed for a split-second? I'm not sure if its the compositor's
place to "freeze" the cursor until a client responds (that sounds a
little dicey, especially with hung clients), but it could be an
interesting approach.
freezing a cursor at a location makes the system look unresponsive as
opposed to just one application not updating a cursor quickly enough.
plus, if a client does not needing a cursor image for the tablet we may
freeze the cursor and wait for a request that never comes.
there's room for a wl_godot protocol, this is not it though :)

Cheers,
Peter
Auke Booij
2015-11-15 23:50:26 UTC
Permalink
Post by Peter Hutterer
---
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Would it be possible to cross-reference <enum> definitions in <arg>s,
as was made possible by the introduction of the enum attribute
recently? E.g.

<arg name="tool_type" type="uint" enum="type" summary="the physical
tool type"/>
...
<arg name="format" type="uint" enum="hardware_id_format" summary="the
type of the id" />
...
<arg name="capability" type="uint" enum="capability" summary="the capability"/>
...
<arg name="state" type="uint" enum="button_state" summary="Whether
the button was pressed or released"/>
...
<arg name="type" type="uint" enum="type" summary="the tablet type
(internal, external, ...)"/>
Peter Hutterer
2015-11-16 03:44:24 UTC
Permalink
Post by Auke Booij
Post by Peter Hutterer
---
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Would it be possible to cross-reference <enum> definitions in <arg>s,
as was made possible by the introduction of the enum attribute
recently? E.g.
<arg name="tool_type" type="uint" enum="type" summary="the physical
tool type"/>
...
<arg name="format" type="uint" enum="hardware_id_format" summary="the
type of the id" />
...
<arg name="capability" type="uint" enum="capability" summary="the capability"/>
...
<arg name="state" type="uint" enum="button_state" summary="Whether
the button was pressed or released"/>
...
<arg name="type" type="uint" enum="type" summary="the tablet type
(internal, external, ...)"/>
thanks, I've added these locally and they'll be in the next revision (except
the last, the tablet type was dropped).

Cheers,
Peter
Peter Hutterer
2015-11-15 21:01:52 UTC
Permalink
Hey,
Post by Peter Hutterer
---
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Makefile.am | 1 +
unstable/tablet/README | 4 +
unstable/tablet/tablet-unstable-v1.xml | 588 +++++++++++++++++++++++++++++++++
3 files changed, 593 insertions(+)
create mode 100644 unstable/tablet/README
create mode 100644 unstable/tablet/tablet-unstable-v1.xml
diff --git a/Makefile.am b/Makefile.am
index 4bcab32..588cb2c 100644
<snip>
Post by Peter Hutterer
+ <enum name="type">
+ <description summary="tablet type">
+ Describes the type of tablet
+ </description>
+
+ <entry name="external" value="0" summary="The tablet is an external tablet, such as an Intuos"/>
+ <entry name="internal" value="1" summary="The tablet is a built-in tablet, usually in a laptop"/>
+ <entry name="display" value="2" summary="The tablet is a display tablet, such as a Cintiq"/>
+ </enum>
+
+ <event name="type">
+ <description summary="the tablet type">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="type" type="uint" summary="the tablet type (internal, external, ...)"/>
+ </event>
I'm tbh wondering whether this is all that useful. I'm seeing the
fixme in your 01/13 weston patch where this is missing a dependency on
libwacom, and I've got a similar fixme in mutter. The protocol already
exports vid/pid and node file, that seems enough to poke libwacom on
the client side, and it's not like many clients need this to implement
different behavior (the only potential user I see on my side is
gnome-control-center).
good point, and makes sense. sounds like a sensible one to drop from the
protocol, if it really is required here we can add it in some later version.
And the weston series really, I could see nothing wrong with it, even
helped me spot a couple of bugs in my mutter branch.
Thanks, the review is much appreciated

Cheers,
Peter
Daniel Stone
2015-11-16 11:21:36 UTC
Permalink
Peter, Stephen,
Post by Peter Hutterer
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Thanks a lot for doing this! Looks really good to me, and I think
getting it in wayland-protocols would be good.

Do you have other implementations, e.g. GTK+/Mutter? If so, a pointer
(ha) to those would be great.
Post by Peter Hutterer
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland_tablet_unstable_v1">
+ <description summary="Wayland protocol for graphics tablets">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
Yes, it turns out the wl_seat.get_* model was probably a pretty bad
anti-pattern. Oh well. To avoid too much object proliferation though,
how about something like:
<interface name="wp_tablet_manager">
<request name="add_seat">
<description summary="Add seat of interest">
Add a seat of interest to this tablet manager. The client will
receive events for all tablets currently on this seat, as well as
tablets added to this seat in future.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
[inline wp_tablet_seat here ...]
</interface>

Then you can just bin wp_tablet_seat.

Not a pattern we've previously employed, but I think it's a good one
that avoids one extra step of indirection, as well as making it a bit
easier for clients to do the right thing.
Post by Peter Hutterer
+ The wp_tablet_seat sends a "tablet added" for each tablet connected.
+ That event is followed by descriptive events about the hardware;
+ currently that includes events for name, vid/pid and
+ internal/external/display type, and a wp_tablet.path event that
+ describes a local path. This path can be used to uniquely identify a
+ tablet, or get more information through libwacom. Emulated or nested
+ tablets can skip any of those, e.g. a virtual tablet may not have a
+ vid/pid. The sequence of descriptive events is terminated by a
+ wp_tablet.done event to signal that a client may now finalize any
+ initialization for that tablet.
Is VID/PID in USB space? (Answers in diff form preferred.)
Post by Peter Hutterer
+ Two special events (that don't exist in X) are down and up. They signal
+ "tip touching the surface". For tablets without real proximity
+ detection, the sequence is: proximity_in, motion, down, frame.
+
+ When the tool leaves proximity, a proximity_out event is sent, followed
+ by button release events for any button still down. This signals to
+ the client that the buttons were held when the tool left proximity.
+ Those events are all sent within the same frame.
Can we please enforce a strict bracketing of down/up occurring in
matched pairs inside of proximity_in/out? So, the total event stream
would be:
- proximity_in
- motion
- down
- motion/motion/button/...
- up
- proximity_out

I assume the implementation does this, but it would be nice to have
encoded in the protocol.
Post by Peter Hutterer
+ If the tool moves out of the surface but stays in proximity (i.e.
+ between windows), compositor-specific grab policies apply. This usually
+ means that the proximity-out is delayed until all buttons are released.
If no buttons are down, we'd _expect_ to just get a proximity_out
immediately, right? It almost seems like we'd want a subtype argument
here, enumerating what happened: did the user lift the tool entirely
(actually out of proximity), or is the tablet still in proximity but
just wandered off to another surface?

The doc for proximity_out also doesn't contradict this, but reading
Post by Peter Hutterer
+ [wp_tablet_tool1::proximity_out]
+ When the tablet tool leaves proximity of the tablet, button release
+ events are sent for each button that was held down at the time of
+ leaving proximity. These events are sent in the same wp_tablet.frame
+ of the proximity_out event.
It'd be nice to have discussion of the two cases - genuinely leaving
proximity vs. retaining proximity but leaving surface focus -
together.
Post by Peter Hutterer
+ Moving a tool physically from one tablet to the other has no real effect
+ on the protocol, since we already have the tool object from the "tool
+ added" event. All the information is already there and the proximity_in
+ is all a client needs to reconstruct what happened.
... also (up+)proximity_out from the old tablet.
Post by Peter Hutterer
+ <interface name="zwp_tablet_tool1" version="1">
+ <description summary="a physical tablet tool">
+ An unique object that represents a physical tool that has been, or is
+ currently in use with a tablet in this seat. Each wp_tablet_tool
+ object stays valid until the client destroys it; the compositor
+ reuses the wp_tablet_tool object to indicate that the object's
+ respective physical tool has come into proximity of a tablet again.
+ A client must not call wp_tablet_tool.destroy until it receives a
+ wp_tablet_tool.release event.
+
+ A wp_tablet_tool object's uniqueness depends on the tablet's ability
+ to report serial numbers. If the tablet doesn't support this
+ capability, then the tool cannot be guaranteed to be unique.
'Unique' is a little confusing - perhaps 'a one-to-one mapping between
tool objects and physical tools' or similar. Also if we're not
providing some kind of tablet caps event, that you can't query this.
It's also pretty contradictory with the first sentence. :) A
'generally' there would be enough to weasel out of it.
Post by Peter Hutterer
+ <request name="set_cursor">
+ <description summary="set the tablet tool's surface">
+ Sets the surface of the cursor used for this tool on the given
+ tablet. The surface is only shown when this tool is in proximity of
+ this tablet. If the surface is NULL, the pointer image is hidden
+ completely.
+
+ The parameters hotspot_x and hotspot_y define the position of the
+ pointer surface relative to the pointer location. Its top-left corner
+ is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+ coordinates of the pointer location, in surface local coordinates.
(Something something transforms on the cursor surface ...)
Post by Peter Hutterer
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tool object">
+ This destroys the client's resource for this tool object.
+
+ A client must not issue this request until it receives a
+ wp_tablet_tool.remove event.
Egads. What happens when a client no longer wants to know about tablet
events (e.g. you have an embedded drawing program in a browser but
then close the tab): it just has to ignore the stream of events
forever? A bit hostile.
Post by Peter Hutterer
+ <enum name="type">
+ <description summary="a physical tool type">
+ Describes the physical type of a tool. The physical type of a tool
+ generally defines its base usage.
+
+ The mouse tool represents a mouse-shaped tool that is not a relative
+ device but bound to the tablet's surface, providing absolute
+ coordinates.
+
+ The lens tool is a mouse-shaped tool with an attached lens to
+ provide precision focus.
+ </description>
+ <entry name="pen" value="0x140" summary="Pen"/>
+ <entry name="eraser" value="0x141" summary="Eraser"/>
+ <entry name="brush" value="0x142" summary="Brush"/>
+ <entry name="pencil" value="0x143" summary="Pencil"/>
+ <entry name="airbrush" value="0x144" summary="Airbrush"/>
+ <entry name="finger" value="0x145" summary="Finger"/>
+ <entry name="mouse" value="0x146" summary="Mouse"/>
+ <entry name="lens" value="0x147" summary="Lens"/>
+ </enum>
*raises eyebrow* - magic numbers from Wacom protocol? (Fine if they are.)
Post by Peter Hutterer
+ <event name="serial_id">
+ <description summary="unique serial number of the tool">
+ If the tool can be identified by a unique 64-bit serial number, this
+ event notifies the client of the serial number.
+
+ If multiple tablets are available in the same seat and the tool is
+ uniquely identifiable by the serial number, that tool may move
+ between tablets.
+
+ Otherwise, if the tool has no serial number and this event is
+ missing, the tool is tied to the tablet it first comes into
+ proximity with. Even if the physical tool is used on multiple
+ tablets, separate wp_tablet_tool objects will be created, one per
+ tablet.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="serial_id_msb" type="uint" summary="the unique serial number of the tool, most significant bits"/>
+ <arg name="serial_id_lsb" type="uint" summary="the unique serial number of the tool, least significant bits"/>
+ </event>
Would be really nice to not use 'serial' in the name, though using it
in the description absolutely makes sense. Just want to avoid
confusion with serial-as-place-in-event-stream-identifier ...
Post by Peter Hutterer
+ <enum name="capability">
+ <description summary="capability flags for a tool">
+ Describes extra capabilities on a tablet.
+
+ Any tool must provide x and y values, extra axes are
+ device-specific.
+ </description>
+ <entry name="tilt" value="1" summary="Tilt axes"/>
+ <entry name="pressure" value="2" summary="Pressure axis"/>
+ <entry name="distance" value="3" summary="Distance axis"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="tool capability notification">
+ This event notifies the client of any capabilities of this tool,
+ beyond the main set of x/y axes and tip up/down detection.
+
+ One event is sent for each extra capability available on this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="capability" type="uint" summary="the capability"/>
+ </event>
Bitmask?
Post by Peter Hutterer
+ <event name="down">
+ <description summary="tablet tool is making contact">
+ Sent whenever the tablet tool comes in contact with the surface of the
+ tablet. If the tablet tool moves out of a region while in contact with
+ the surface of the tablet, the client owning said region will receive a
+ wp_tablet::up event, followed by a wp_tablet::proximity_out event and a
+ wp_tablet::frame event.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
Inconsistent use of protocol::event here, with protocol.event
elsewhere in the docs.
Post by Peter Hutterer
+ <event name="distance">
+ <description summary="distance change event">
+ Sent whenever the distance axis on a tool changes. The value of this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="distance" type="uint" summary="The current distance value"/>
+ </event>
Units?
Post by Peter Hutterer
+ <enum name="button_state">
+ <description summary="physical button state">
+ Describes the physical state of a button which provoked the button event
+ </description>
+ <entry name="released" value="0" summary="button is not pressed"/>
+ <entry name="pressed" value="1" summary="button is pressed"/>
+ </enum>
Imperative is better here: 'button pressed', 'button released'. Also
happens to match the doc in the button event itself. ;)
Post by Peter Hutterer
+ <event name="button">
+ <description summary="button event">
+ Sent whenever a button on the stylus is pressed or released.
+ </description>
+
+ <arg name="serial" type="uint"/>
+ <arg name="button" type="uint" summary="The button whose state has changed"/>
+ <arg name="state" type="uint" summary="Whether the button was pressed or released"/>
+ </event>
+ <event name="id">
+ <description summary="tablet device vid/pid">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="vid" type="uint" summary="vendor id"/>
+ <arg name="pid" type="uint" summary="product id"/>
+ </event>
VID/PID space ... ?
Post by Peter Hutterer
+ <enum name="type">
+ <description summary="tablet type">
+ Describes the type of tablet
+ </description>
Full stop
Post by Peter Hutterer
+ <entry name="external" value="0" summary="The tablet is an external tablet, such as an Intuos"/>
+ <entry name="internal" value="1" summary="The tablet is a built-in tablet, usually in a laptop"/>
+ <entry name="display" value="2" summary="The tablet is a display tablet, such as a Cintiq"/>
+ </enum>
+
+ <event name="type">
+ <description summary="the tablet type">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="type" type="uint" summary="the tablet type (internal, external, ...)"/>
+ </event>
Are these two not redundant?
Post by Peter Hutterer
+ <event name="path">
+ <description summary="path to the device">
+ A system-specific device path that indicates which device is behind
+ this wp_tablet. This information may be used to gather additional
+ information about the device, e.g. through libwacom.
+
+ A device may have more than one device path, if so, multiple
+ wp_tablet.path events are sent. A device may be emulated and not
+ have a device path, in that case this event will not be sent.
+
+ The format of the path is unspecified, it may be a device node, a
+ sysfs path, or some other identifier. It is up to the client to
+ identify the string provided.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="path" type="string" summary="path to local device"/>
+ </event>
Mm, device path isn't really a good idea with logind. Should just be
sysfs path or nothing, I think.

Anyway, none of these are particularly fundamental to the protocol;
the biggest change is the wp_tablet_seat thing, but given that's not a
pattern we've previously used, it could go either way. So, with as
many or few of these comments addressed as you feel makes sense:
Reviewed-by: Daniel Stone <***@collabora.com>

Cheers,
Daniel
Jonas Ådahl
2015-11-16 11:59:35 UTC
Permalink
Post by Daniel Stone
Peter, Stephen,
Post by Peter Hutterer
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Thanks a lot for doing this! Looks really good to me, and I think
getting it in wayland-protocols would be good.
Do you have other implementations, e.g. GTK+/Mutter? If so, a pointer
(ha) to those would be great.
Post by Peter Hutterer
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland_tablet_unstable_v1">
+ <description summary="Wayland protocol for graphics tablets">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
Yes, it turns out the wl_seat.get_* model was probably a pretty bad
anti-pattern. Oh well. To avoid too much object proliferation though,
<interface name="wp_tablet_manager">
<request name="add_seat">
<description summary="Add seat of interest">
Add a seat of interest to this tablet manager. The client will
receive events for all tablets currently on this seat, as well as
tablets added to this seat in future.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
[inline wp_tablet_seat here ...]
</interface>
Then you can just bin wp_tablet_seat.
Not a pattern we've previously employed, but I think it's a good one
that avoids one extra step of indirection, as well as making it a bit
easier for clients to do the right thing.
How would it be easier for clients to do the right thing? It'd just make
it easy to mix different seats' tools and tablets as there would be no
more separation (except if one would bind a tablet manager per seat). Or
should tools and tablets be considered on the same "super seat", i.e.
would it be possible to see tool A from seat X on tablet V on seat Y?

Seems to me that making it possible to shove all seats in one pile is
more error prone than having them clearly separated.
Post by Daniel Stone
Post by Peter Hutterer
+ The wp_tablet_seat sends a "tablet added" for each tablet connected.
+ That event is followed by descriptive events about the hardware;
+ currently that includes events for name, vid/pid and
+ internal/external/display type, and a wp_tablet.path event that
+ describes a local path. This path can be used to uniquely identify a
+ tablet, or get more information through libwacom. Emulated or nested
+ tablets can skip any of those, e.g. a virtual tablet may not have a
+ vid/pid. The sequence of descriptive events is terminated by a
+ wp_tablet.done event to signal that a client may now finalize any
+ initialization for that tablet.
Is VID/PID in USB space? (Answers in diff form preferred.)
Post by Peter Hutterer
+ Two special events (that don't exist in X) are down and up. They signal
+ "tip touching the surface". For tablets without real proximity
+ detection, the sequence is: proximity_in, motion, down, frame.
+
+ When the tool leaves proximity, a proximity_out event is sent, followed
+ by button release events for any button still down. This signals to
+ the client that the buttons were held when the tool left proximity.
+ Those events are all sent within the same frame.
Can we please enforce a strict bracketing of down/up occurring in
matched pairs inside of proximity_in/out? So, the total event stream
- proximity_in
- motion
- down
- motion/motion/button/...
- up
- proximity_out
I assume the implementation does this, but it would be nice to have
encoded in the protocol.
Post by Peter Hutterer
+ If the tool moves out of the surface but stays in proximity (i.e.
+ between windows), compositor-specific grab policies apply. This usually
+ means that the proximity-out is delayed until all buttons are released.
If no buttons are down, we'd _expect_ to just get a proximity_out
immediately, right? It almost seems like we'd want a subtype argument
here, enumerating what happened: did the user lift the tool entirely
(actually out of proximity), or is the tablet still in proximity but
just wandered off to another surface?
The doc for proximity_out also doesn't contradict this, but reading
Post by Peter Hutterer
+ [wp_tablet_tool1::proximity_out]
+ When the tablet tool leaves proximity of the tablet, button release
+ events are sent for each button that was held down at the time of
+ leaving proximity. These events are sent in the same wp_tablet.frame
+ of the proximity_out event.
It'd be nice to have discussion of the two cases - genuinely leaving
proximity vs. retaining proximity but leaving surface focus -
together.
Post by Peter Hutterer
+ Moving a tool physically from one tablet to the other has no real effect
+ on the protocol, since we already have the tool object from the "tool
+ added" event. All the information is already there and the proximity_in
+ is all a client needs to reconstruct what happened.
... also (up+)proximity_out from the old tablet.
Post by Peter Hutterer
+ <interface name="zwp_tablet_tool1" version="1">
+ <description summary="a physical tablet tool">
+ An unique object that represents a physical tool that has been, or is
+ currently in use with a tablet in this seat. Each wp_tablet_tool
+ object stays valid until the client destroys it; the compositor
+ reuses the wp_tablet_tool object to indicate that the object's
+ respective physical tool has come into proximity of a tablet again.
+ A client must not call wp_tablet_tool.destroy until it receives a
+ wp_tablet_tool.release event.
+
+ A wp_tablet_tool object's uniqueness depends on the tablet's ability
+ to report serial numbers. If the tablet doesn't support this
+ capability, then the tool cannot be guaranteed to be unique.
'Unique' is a little confusing - perhaps 'a one-to-one mapping between
tool objects and physical tools' or similar. Also if we're not
providing some kind of tablet caps event, that you can't query this.
It's also pretty contradictory with the first sentence. :) A
'generally' there would be enough to weasel out of it.
Post by Peter Hutterer
+ <request name="set_cursor">
+ <description summary="set the tablet tool's surface">
+ Sets the surface of the cursor used for this tool on the given
+ tablet. The surface is only shown when this tool is in proximity of
+ this tablet. If the surface is NULL, the pointer image is hidden
+ completely.
+
+ The parameters hotspot_x and hotspot_y define the position of the
+ pointer surface relative to the pointer location. Its top-left corner
+ is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+ coordinates of the pointer location, in surface local coordinates.
(Something something transforms on the cursor surface ...)
Post by Peter Hutterer
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tool object">
+ This destroys the client's resource for this tool object.
+
+ A client must not issue this request until it receives a
+ wp_tablet_tool.remove event.
Egads. What happens when a client no longer wants to know about tablet
events (e.g. you have an embedded drawing program in a browser but
then close the tab): it just has to ignore the stream of events
forever? A bit hostile.
Yea, it seems reasonable to allow clients to destroy at will.
Especially if it's about to do stop its tablet feature it probably want
to destroy its objects without having to wait for remove events.


Jonas
Post by Daniel Stone
Post by Peter Hutterer
+ <enum name="type">
+ <description summary="a physical tool type">
+ Describes the physical type of a tool. The physical type of a tool
+ generally defines its base usage.
+
+ The mouse tool represents a mouse-shaped tool that is not a relative
+ device but bound to the tablet's surface, providing absolute
+ coordinates.
+
+ The lens tool is a mouse-shaped tool with an attached lens to
+ provide precision focus.
+ </description>
+ <entry name="pen" value="0x140" summary="Pen"/>
+ <entry name="eraser" value="0x141" summary="Eraser"/>
+ <entry name="brush" value="0x142" summary="Brush"/>
+ <entry name="pencil" value="0x143" summary="Pencil"/>
+ <entry name="airbrush" value="0x144" summary="Airbrush"/>
+ <entry name="finger" value="0x145" summary="Finger"/>
+ <entry name="mouse" value="0x146" summary="Mouse"/>
+ <entry name="lens" value="0x147" summary="Lens"/>
+ </enum>
*raises eyebrow* - magic numbers from Wacom protocol? (Fine if they are.)
Post by Peter Hutterer
+ <event name="serial_id">
+ <description summary="unique serial number of the tool">
+ If the tool can be identified by a unique 64-bit serial number, this
+ event notifies the client of the serial number.
+
+ If multiple tablets are available in the same seat and the tool is
+ uniquely identifiable by the serial number, that tool may move
+ between tablets.
+
+ Otherwise, if the tool has no serial number and this event is
+ missing, the tool is tied to the tablet it first comes into
+ proximity with. Even if the physical tool is used on multiple
+ tablets, separate wp_tablet_tool objects will be created, one per
+ tablet.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="serial_id_msb" type="uint" summary="the unique serial number of the tool, most significant bits"/>
+ <arg name="serial_id_lsb" type="uint" summary="the unique serial number of the tool, least significant bits"/>
+ </event>
Would be really nice to not use 'serial' in the name, though using it
in the description absolutely makes sense. Just want to avoid
confusion with serial-as-place-in-event-stream-identifier ...
Post by Peter Hutterer
+ <enum name="capability">
+ <description summary="capability flags for a tool">
+ Describes extra capabilities on a tablet.
+
+ Any tool must provide x and y values, extra axes are
+ device-specific.
+ </description>
+ <entry name="tilt" value="1" summary="Tilt axes"/>
+ <entry name="pressure" value="2" summary="Pressure axis"/>
+ <entry name="distance" value="3" summary="Distance axis"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="tool capability notification">
+ This event notifies the client of any capabilities of this tool,
+ beyond the main set of x/y axes and tip up/down detection.
+
+ One event is sent for each extra capability available on this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="capability" type="uint" summary="the capability"/>
+ </event>
Bitmask?
Post by Peter Hutterer
+ <event name="down">
+ <description summary="tablet tool is making contact">
+ Sent whenever the tablet tool comes in contact with the surface of the
+ tablet. If the tablet tool moves out of a region while in contact with
+ the surface of the tablet, the client owning said region will receive a
+ wp_tablet::up event, followed by a wp_tablet::proximity_out event and a
+ wp_tablet::frame event.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
Inconsistent use of protocol::event here, with protocol.event
elsewhere in the docs.
Post by Peter Hutterer
+ <event name="distance">
+ <description summary="distance change event">
+ Sent whenever the distance axis on a tool changes. The value of this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="distance" type="uint" summary="The current distance value"/>
+ </event>
Units?
Post by Peter Hutterer
+ <enum name="button_state">
+ <description summary="physical button state">
+ Describes the physical state of a button which provoked the button event
+ </description>
+ <entry name="released" value="0" summary="button is not pressed"/>
+ <entry name="pressed" value="1" summary="button is pressed"/>
+ </enum>
Imperative is better here: 'button pressed', 'button released'. Also
happens to match the doc in the button event itself. ;)
Post by Peter Hutterer
+ <event name="button">
+ <description summary="button event">
+ Sent whenever a button on the stylus is pressed or released.
+ </description>
+
+ <arg name="serial" type="uint"/>
+ <arg name="button" type="uint" summary="The button whose state has changed"/>
+ <arg name="state" type="uint" summary="Whether the button was pressed or released"/>
+ </event>
+ <event name="id">
+ <description summary="tablet device vid/pid">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="vid" type="uint" summary="vendor id"/>
+ <arg name="pid" type="uint" summary="product id"/>
+ </event>
VID/PID space ... ?
Post by Peter Hutterer
+ <enum name="type">
+ <description summary="tablet type">
+ Describes the type of tablet
+ </description>
Full stop
Post by Peter Hutterer
+ <entry name="external" value="0" summary="The tablet is an external tablet, such as an Intuos"/>
+ <entry name="internal" value="1" summary="The tablet is a built-in tablet, usually in a laptop"/>
+ <entry name="display" value="2" summary="The tablet is a display tablet, such as a Cintiq"/>
+ </enum>
+
+ <event name="type">
+ <description summary="the tablet type">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="type" type="uint" summary="the tablet type (internal, external, ...)"/>
+ </event>
Are these two not redundant?
Post by Peter Hutterer
+ <event name="path">
+ <description summary="path to the device">
+ A system-specific device path that indicates which device is behind
+ this wp_tablet. This information may be used to gather additional
+ information about the device, e.g. through libwacom.
+
+ A device may have more than one device path, if so, multiple
+ wp_tablet.path events are sent. A device may be emulated and not
+ have a device path, in that case this event will not be sent.
+
+ The format of the path is unspecified, it may be a device node, a
+ sysfs path, or some other identifier. It is up to the client to
+ identify the string provided.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="path" type="string" summary="path to local device"/>
+ </event>
Mm, device path isn't really a good idea with logind. Should just be
sysfs path or nothing, I think.
Anyway, none of these are particularly fundamental to the protocol;
the biggest change is the wp_tablet_seat thing, but given that's not a
pattern we've previously used, it could go either way. So, with as
Cheers,
Daniel
Daniel Stone
2015-11-16 12:07:12 UTC
Permalink
Hi Jonas,
Post by Jonas Ådahl
Post by Daniel Stone
Post by Peter Hutterer
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
Yes, it turns out the wl_seat.get_* model was probably a pretty bad
anti-pattern. Oh well. To avoid too much object proliferation though,
<interface name="wp_tablet_manager">
<request name="add_seat">
<description summary="Add seat of interest">
Add a seat of interest to this tablet manager. The client will
receive events for all tablets currently on this seat, as well as
tablets added to this seat in future.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
[inline wp_tablet_seat here ...]
</interface>
Then you can just bin wp_tablet_seat.
Not a pattern we've previously employed, but I think it's a good one
that avoids one extra step of indirection, as well as making it a bit
easier for clients to do the right thing.
How would it be easier for clients to do the right thing? It'd just make
it easy to mix different seats' tools and tablets as there would be no
more separation (except if one would bind a tablet manager per seat). Or
should tools and tablets be considered on the same "super seat", i.e.
would it be possible to see tool A from seat X on tablet V on seat Y?
It makes it easier, because right now we expect them to hold a
wp_tablet_manager, respond to new seats by creating a new
wp_tablet_seat, and having them respond to events on that as well. We
already make people hold absolute piles of objects, so one less seems
like it could be a good thing.
Post by Jonas Ådahl
Seems to me that making it possible to shove all seats in one pile is
more error prone than having them clearly separated.
Possibly. I guess it depends on the failure mode. I can see it either way.

Cheers,
Daniel
Peter Hutterer
2015-11-16 21:48:21 UTC
Permalink
Post by Daniel Stone
Hi Jonas,
Post by Jonas Ådahl
Post by Daniel Stone
Post by Peter Hutterer
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
Yes, it turns out the wl_seat.get_* model was probably a pretty bad
anti-pattern. Oh well. To avoid too much object proliferation though,
<interface name="wp_tablet_manager">
<request name="add_seat">
<description summary="Add seat of interest">
Add a seat of interest to this tablet manager. The client will
receive events for all tablets currently on this seat, as well as
tablets added to this seat in future.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
[inline wp_tablet_seat here ...]
</interface>
Then you can just bin wp_tablet_seat.
Not a pattern we've previously employed, but I think it's a good one
that avoids one extra step of indirection, as well as making it a bit
easier for clients to do the right thing.
How would it be easier for clients to do the right thing? It'd just make
it easy to mix different seats' tools and tablets as there would be no
more separation (except if one would bind a tablet manager per seat). Or
should tools and tablets be considered on the same "super seat", i.e.
would it be possible to see tool A from seat X on tablet V on seat Y?
It makes it easier, because right now we expect them to hold a
wp_tablet_manager, respond to new seats by creating a new
wp_tablet_seat, and having them respond to events on that as well. We
already make people hold absolute piles of objects, so one less seems
like it could be a good thing.
I have to say it sounds a lot worse in the protocol than it is in the
implementation. But this was the easiest bit of the implementation, clients
already have some wrapper object for the wl_seat anyway, this just adds one
pointer for the tablet seat to that object, plus one global one for the
tablet manager. [1] And that too is just adding one more pointer to existing
infrastructure.

And the effective cost is minimal - how many wl_seats do we expect in the
worst case? 10? In the 99% case we only have one and that's what IMO we
should optimise for (and the code would look identical anyway since in the
client it'll all hang off the struct seat_something). I think that the
potential confusion of mixing tablets from different seats is a lot worse
than the extra objects here.

Cheers,
Peter

[1]
https://github.com/whot/weston/commit/64dc64a4dbabd7fbe1b6b80a2a08ff2cc8c0c288#diff-87a1da5a7e6453c81e19091e66a9015dR5757
Post by Daniel Stone
Post by Jonas Ådahl
Seems to me that making it possible to shove all seats in one pile is
more error prone than having them clearly separated.
Possibly. I guess it depends on the failure mode. I can see it either way.
Carlos Garnacho
2015-11-16 13:27:35 UTC
Permalink
Hey :),
Post by Daniel Stone
Peter, Stephen,
Post by Peter Hutterer
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Thanks a lot for doing this! Looks really good to me, and I think
getting it in wayland-protocols would be good.
Do you have other implementations, e.g. GTK+/Mutter? If so, a pointer
(ha) to those would be great.
The branch in mutter corresponding to this last version is:
https://git.gnome.org/browse/mutter/log/?h=wip/tablet-protocol-v3

There's also:
https://git.gnome.org/browse/gtk+/log/?h=wip/wayland-tablet

For GTK+, but that one hasn't caught up yet with wayland-protocols
Post by Daniel Stone
Post by Peter Hutterer
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland_tablet_unstable_v1">
+ <description summary="Wayland protocol for graphics tablets">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
Yes, it turns out the wl_seat.get_* model was probably a pretty bad
anti-pattern. Oh well. To avoid too much object proliferation though,
<interface name="wp_tablet_manager">
<request name="add_seat">
<description summary="Add seat of interest">
Add a seat of interest to this tablet manager. The client will
receive events for all tablets currently on this seat, as well as
tablets added to this seat in future.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
[inline wp_tablet_seat here ...]
</interface>
Then you can just bin wp_tablet_seat.
Not a pattern we've previously employed, but I think it's a good one
that avoids one extra step of indirection, as well as making it a bit
easier for clients to do the right thing.
Post by Peter Hutterer
+ The wp_tablet_seat sends a "tablet added" for each tablet connected.
+ That event is followed by descriptive events about the hardware;
+ currently that includes events for name, vid/pid and
+ internal/external/display type, and a wp_tablet.path event that
+ describes a local path. This path can be used to uniquely identify a
+ tablet, or get more information through libwacom. Emulated or nested
+ tablets can skip any of those, e.g. a virtual tablet may not have a
+ vid/pid. The sequence of descriptive events is terminated by a
+ wp_tablet.done event to signal that a client may now finalize any
+ initialization for that tablet.
Is VID/PID in USB space? (Answers in diff form preferred.)
Post by Peter Hutterer
+ Two special events (that don't exist in X) are down and up. They signal
+ "tip touching the surface". For tablets without real proximity
+ detection, the sequence is: proximity_in, motion, down, frame.
+
+ When the tool leaves proximity, a proximity_out event is sent, followed
+ by button release events for any button still down. This signals to
+ the client that the buttons were held when the tool left proximity.
+ Those events are all sent within the same frame.
Can we please enforce a strict bracketing of down/up occurring in
matched pairs inside of proximity_in/out? So, the total event stream
- proximity_in
- motion
- down
- motion/motion/button/...
- up
- proximity_out
I assume the implementation does this, but it would be nice to have
encoded in the protocol.
It is worth noting that stylus button events can be obtained while in
proximity regardless of down/up state, so that'd roughly be:

- proximity_in
- motion/button/...
- down
- motion/button/...
- up
- motion/button/...
- proximity_out

Cheers,
Carlos
Daniel Stone
2015-11-16 13:35:24 UTC
Permalink
Hi,
Post by Carlos Garnacho
Post by Daniel Stone
Can we please enforce a strict bracketing of down/up occurring in
matched pairs inside of proximity_in/out? So, the total event stream
- proximity_in
- motion
- down
- motion/motion/button/...
- up
- proximity_out
I assume the implementation does this, but it would be nice to have
encoded in the protocol.
It is worth noting that stylus button events can be obtained while in
- proximity_in
- motion/button/...
- down
- motion/button/...
- up
- motion/button/...
- proximity_out
Oh sure, that's fine, just as long as down/up is strictly bracketed
such that you can't just get proximity_in -> down -> proximity_out ->
[nothing].

Cheers,
Daniel
Bill Spitzak
2015-11-16 18:46:24 UTC
Permalink
There is a need to distinguish proximity-out from exit events. It is quite
possible to move the stylus so that the focus enters another client without
doing a proximity-out. Clients are interested in distinguishing these.

I really feel the best method is to say a "seat" has a keyboard focus and a
pointer focus, and let the stylus manipulate the pointer focus. Thus the
client will get enter/exit events as the stylus is moved around above the
tablet, and proximity in/out when it is moved toward/away from the tablet
(it may also get a fake proximity-in event on enter).

I really feel the cursor stuff is a huge mistake. It adds lots of
complexity for almost no actual gain. Witness how much code you had to add
to toytoolkit to support it. It adds complexity to clients as the client
has to pass which tool to subroutines for no reason other than to allow
them to change the correct cursor. The clients cannot assume the tool has
the "right" cursor and therefore they are required to have code to change
it, so this removes no complexity from clients. It is also hugely
inconsistent with how normal pointer enter events are handled in Wayland.

I would change this so the cursor remains the wl_pointer cursor, and
exactly the same code is used by the client to change the cursor as it does
for wl_pointer. The fact that you need to use the wl_pointer interface to
deal with stylus events can be considered a historical artefact, they
should have been on the wl_seat.

The only argument you had was that the cursor is more likely to be correct,
so when the proximity-in event happens, the cursor that appears has a
higher chance of being the same as the one the client sets and there will
be less blinking. However this can be implemented by the compositor without
any client api. Just have the compositor remember what cursor was used and
set that as a guess on the enter event. The client can remain completely
unaware of whether a cursor is remembered per-tool, or per-surface, or per
tool*surface, or whatever.
Daniel Stone
2015-11-16 19:04:39 UTC
Permalink
Bill,
Post by Bill Spitzak
There is a need to distinguish proximity-out from exit events. It is quite
possible to move the stylus so that the focus enters another client without
doing a proximity-out. Clients are interested in distinguishing these.
This is true, hence my suggestion.
Post by Bill Spitzak
I really feel the best method is to say a "seat" has a keyboard focus and
a pointer focus, and let the stylus manipulate the pointer focus. Thus the
client will get enter/exit events as the stylus is moved around above the
tablet, and proximity in/out when it is moved toward/away from the tablet
(it may also get a fake proximity-in event on enter).
Pointer and tablet/touch are separate. X11 integrated them, and _that_ was
a huge mistake. From our point of view, this is a closed topic.

We've been over it time and time again, we've seen the ways the alternate
model - though it seems attractive at first, which is why we did it for X11
- fails, and we're not going back there.
Post by Bill Spitzak
I really feel the cursor stuff is a huge mistake. It adds lots of
complexity for almost no actual gain. Witness how much code you had to add
to toytoolkit to support it. It adds complexity to clients as the client
has to pass which tool to subroutines for no reason other than to allow
them to change the correct cursor. The clients cannot assume the tool has
the "right" cursor and therefore they are required to have code to change
it, so this removes no complexity from clients. It is also hugely
inconsistent with how normal pointer enter events are handled in Wayland.
It's not 'no actual gain', it's integral to the model.
Post by Bill Spitzak
The only argument you had was that the cursor is more likely to be
correct, so when the proximity-in event happens, the cursor that appears
has a higher chance of being the same as the one the client sets and there
will be less blinking. However this can be implemented by the compositor
without any client api. Just have the compositor remember what cursor was
used and set that as a guess on the enter event. The client can remain
completely unaware of whether a cursor is remembered per-tool, or
per-surface, or per tool*surface, or whatever.
The reason the protocol does not do this, is because when the cursor is
different, you go from the other-surface cursor, to the old new-surface
cursor, to the new new-surface cursor, very rapidly. It's ugly, and a
bandaid for clients not responding quickly enough.

This line has been discussed to death, and we won't be pursuing it any
further. I've enjoyed some of your more constructive contributions over the
past year or so, but am sad to see you regress back into suggesting
rewriting the entire protocol - overriding considered discussion made at
the time - because you prefer the superficial aspects of an alternate
approach. Please don't make a habit of this.

Cheers,
Daniel
Carlos Garnacho
2015-11-16 19:55:37 UTC
Permalink
Hey,
Post by Daniel Stone
Bill,
Post by Bill Spitzak
There is a need to distinguish proximity-out from exit events. It is quite
possible to move the stylus so that the focus enters another client without
doing a proximity-out. Clients are interested in distinguishing these.
This is true, hence my suggestion.
Post by Bill Spitzak
I really feel the best method is to say a "seat" has a keyboard focus and
a pointer focus, and let the stylus manipulate the pointer focus. Thus the
client will get enter/exit events as the stylus is moved around above the
tablet, and proximity in/out when it is moved toward/away from the tablet
(it may also get a fake proximity-in event on enter).
Pointer and tablet/touch are separate. X11 integrated them, and _that_ was a
huge mistake. From our point of view, this is a closed topic.
We've been over it time and time again, we've seen the ways the alternate
model - though it seems attractive at first, which is why we did it for X11
- fails, and we're not going back there.
Post by Bill Spitzak
I really feel the cursor stuff is a huge mistake. It adds lots of
complexity for almost no actual gain. Witness how much code you had to add
to toytoolkit to support it. It adds complexity to clients as the client has
to pass which tool to subroutines for no reason other than to allow them to
change the correct cursor. The clients cannot assume the tool has the
"right" cursor and therefore they are required to have code to change it, so
this removes no complexity from clients. It is also hugely inconsistent with
how normal pointer enter events are handled in Wayland.
It's not 'no actual gain', it's integral to the model.
Post by Bill Spitzak
The only argument you had was that the cursor is more likely to be
correct, so when the proximity-in event happens, the cursor that appears has
a higher chance of being the same as the one the client sets and there will
be less blinking. However this can be implemented by the compositor without
any client api. Just have the compositor remember what cursor was used and
set that as a guess on the enter event. The client can remain completely
unaware of whether a cursor is remembered per-tool, or per-surface, or per
tool*surface, or whatever.
The reason the protocol does not do this, is because when the cursor is
different, you go from the other-surface cursor, to the old new-surface
cursor, to the new new-surface cursor, very rapidly. It's ugly, and a
bandaid for clients not responding quickly enough.
It's probably worth pointing out that his concerns are moot, there is
no blinking, or rather, has an easy solution in compositors.

When a tool physically enters in proximity over a surface, the cursor
should be effectively invisible, the client below it will emit
wp_tablet_tool.set_cursor in response to proximity_in, and it will be
set accordingly from the previous invisible state. If the tool moves
across surfaces, the cursor won't be modified until the new focus
surface calls wp_tablet_tool.set_cursor, just like it happens with
wl_pointer.set_cursor and wl_pointer.enter. When the tool physically
leaves proximity, the cursor would be made invisible, destroyed, or
whatnot.

Compositors may of course want to set a default cursor if the
proximity_in happened outside a surface, so that there's something
visible until the tool enters a surface, but this is easy enough to
detect before even showing the cursor. AFAICS the only source of
"blinking" would be compositors invariably setting a visible cursor
before the client has an opportunity to do so, that sounds somewhat
sloppy though.

Cheers,
Carlos
Bill Spitzak
2015-11-16 20:33:45 UTC
Permalink
Post by Carlos Garnacho
It's probably worth pointing out that his concerns are moot, there is
no blinking, or rather, has an easy solution in compositors.
When a tool physically enters in proximity over a surface, the cursor
should be effectively invisible, the client below it will emit
wp_tablet_tool.set_cursor in response to proximity_in, and it will be
set accordingly from the previous invisible state. If the tool moves
across surfaces, the cursor won't be modified until the new focus
surface calls wp_tablet_tool.set_cursor, just like it happens with
wl_pointer.set_cursor and wl_pointer.enter. When the tool physically
leaves proximity, the cursor would be made invisible, destroyed, or
whatnot.
Compositors may of course want to set a default cursor if the
proximity_in happened outside a surface, so that there's something
visible until the tool enters a surface, but this is easy enough to
detect before even showing the cursor. AFAICS the only source of
"blinking" would be compositors invariably setting a visible cursor
before the client has an opportunity to do so, that sounds somewhat
sloppy though.
I'm not sure why you think I am arguing for an old point, as Carlos
describes exactly the same thing I am thinking of.

His proposal removes the need for there to be a per-tool cursor in the
client api. The client only sets the cursor for the most recent tool, and
the user can only see one cursor. IMHO this can be done in the easiest way
by reusing the wl_pointer api, rather than adding new api that clients will
just be forced to select between because only one of the api's works at any
time.

He is proposing the "strong" version of what I said, which is that the
cursor is actually frozen (not moving or changing) until a cursor-set is
received from the client that has focus. If this is a good idea it probably
should be done for normal pointer enter events as well. The benifit of this
is that it obeys the "every frame is perfect" rule of Wayland.

I was assuming a "soft" version that works like the current pointer enter
events, where the cursor does not change but follows the pointer without
waiting for the client to set the image. The cursor image is thus a "guess"
by the compositor. IMHO the best "guess" is to leave the cursor unchanged
from whatever it is now, as this will reduce the number of transitions when
the guess is wrong, and it is how enter events work currently. However a
compositor could try to save a "guess" that tracks the cursor per-tool,
per-surface, or even per tool+surface combination. None of that should be
visible in the client api however.

Changing the cursor on proximity-in outside any client is an interesting
problem. I think the compositor should be entirely in charge of this,
though "guessing" that it is the same as the most-recent client, which
seems to be the proposal here, may be reasonable. The compositor is still
going to need an image to use if no client has gotten a proximity-in yet,
so this does not remove the need for it to supply something without client
help.

I also have no idea what you mean by this being a repeat of some mistake
done by X11. I am not changing in any way what events are being received by
the client compared to the current proposal, therefore if my idea is wrong,
so is the current proposal.
Peter Hutterer
2015-11-16 23:49:15 UTC
Permalink
Hi Daniel,

Thanks for the review. I'll reply to a few select pieces, anything skipped
is something I'll just fold into the next diff.
Post by Daniel Stone
Peter, Stephen,
Post by Peter Hutterer
This is the revamped version of the tablet protocol for graphics tablets
(e.g. Wacom tablets). Too many changes from the last version (a year ago or
so), so I won't detail them, best to look at it with fresh eyes.
Thanks a lot for doing this! Looks really good to me, and I think
getting it in wayland-protocols would be good.
Do you have other implementations, e.g. GTK+/Mutter? If so, a pointer
(ha) to those would be great.
Post by Peter Hutterer
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland_tablet_unstable_v1">
+ <description summary="Wayland protocol for graphics tablets">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
Yes, it turns out the wl_seat.get_* model was probably a pretty bad
anti-pattern. Oh well. To avoid too much object proliferation though,
<interface name="wp_tablet_manager">
<request name="add_seat">
<description summary="Add seat of interest">
Add a seat of interest to this tablet manager. The client will
receive events for all tablets currently on this seat, as well as
tablets added to this seat in future.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
[inline wp_tablet_seat here ...]
</interface>
Then you can just bin wp_tablet_seat.
Not a pattern we've previously employed, but I think it's a good one
that avoids one extra step of indirection, as well as making it a bit
easier for clients to do the right thing.
Post by Peter Hutterer
+ The wp_tablet_seat sends a "tablet added" for each tablet connected.
+ That event is followed by descriptive events about the hardware;
+ currently that includes events for name, vid/pid and
+ internal/external/display type, and a wp_tablet.path event that
+ describes a local path. This path can be used to uniquely identify a
+ tablet, or get more information through libwacom. Emulated or nested
+ tablets can skip any of those, e.g. a virtual tablet may not have a
+ vid/pid. The sequence of descriptive events is terminated by a
+ wp_tablet.done event to signal that a client may now finalize any
+ initialization for that tablet.
Is VID/PID in USB space? (Answers in diff form preferred.)
Post by Peter Hutterer
+ Two special events (that don't exist in X) are down and up. They signal
+ "tip touching the surface". For tablets without real proximity
+ detection, the sequence is: proximity_in, motion, down, frame.
+
+ When the tool leaves proximity, a proximity_out event is sent, followed
+ by button release events for any button still down. This signals to
+ the client that the buttons were held when the tool left proximity.
+ Those events are all sent within the same frame.
Can we please enforce a strict bracketing of down/up occurring in
matched pairs inside of proximity_in/out? So, the total event stream
- proximity_in
- motion
- down
- motion/motion/button/...
- up
- proximity_out
I assume the implementation does this, but it would be nice to have
encoded in the protocol.
the original plan was to have the proximity out event sent before the button
event iff the tool goes out of proximity with the button still pressed. the
frame events (similar to SYN_REPORT) group them together, so as long as you
process those correctly you still know the state. so the order would be,
and I'm using button event here rather than the tip event because that is
actually likely to happen:

- proximity_in
- motion
- frame
- button down
- frame
- proximity out
- button up
- frame

The above signals that the button was still down during proximity.
but you're right, it be easier to pair them symmetrically and any sensible
client that handles frame events correctly will do exactly the right thing.
So the above would turn into:

- proximity_in
- motion
- frame
- button down
- frame
- button up
- proximity out
- frame

I'll reword that.
Post by Daniel Stone
Post by Peter Hutterer
+ If the tool moves out of the surface but stays in proximity (i.e.
+ between windows), compositor-specific grab policies apply. This usually
+ means that the proximity-out is delayed until all buttons are released.
If no buttons are down, we'd _expect_ to just get a proximity_out
immediately, right? It almost seems like we'd want a subtype argument
here, enumerating what happened: did the user lift the tool entirely
(actually out of proximity), or is the tablet still in proximity but
just wandered off to another surface?
The doc for proximity_out also doesn't contradict this, but reading
Post by Peter Hutterer
+ [wp_tablet_tool1::proximity_out]
+ When the tablet tool leaves proximity of the tablet, button release
+ events are sent for each button that was held down at the time of
+ leaving proximity. These events are sent in the same wp_tablet.frame
+ of the proximity_out event.
It'd be nice to have discussion of the two cases - genuinely leaving
proximity vs. retaining proximity but leaving surface focus -
together.
iirc we had that at some point early on and decided to drop the separate
enter/leave event. I can't think of a good use-case where you need to know
the difference between enter/leave vs proximity in/out.

The physical hardware's distance detection is fairly unpredictable so it's
quite common to leave physical proximity when moving across a tablet (i.e.
one window to the other).

if you have a good case here why we need to differ the two I'm all ears, I
just haven't been able to come up with one yet.
Post by Daniel Stone
Post by Peter Hutterer
+ Moving a tool physically from one tablet to the other has no real effect
+ on the protocol, since we already have the tool object from the "tool
+ added" event. All the information is already there and the proximity_in
+ is all a client needs to reconstruct what happened.
... also (up+)proximity_out from the old tablet.
Post by Peter Hutterer
+ <interface name="zwp_tablet_tool1" version="1">
+ <description summary="a physical tablet tool">
+ An unique object that represents a physical tool that has been, or is
+ currently in use with a tablet in this seat. Each wp_tablet_tool
+ object stays valid until the client destroys it; the compositor
+ reuses the wp_tablet_tool object to indicate that the object's
+ respective physical tool has come into proximity of a tablet again.
+ A client must not call wp_tablet_tool.destroy until it receives a
+ wp_tablet_tool.release event.
+
+ A wp_tablet_tool object's uniqueness depends on the tablet's ability
+ to report serial numbers. If the tablet doesn't support this
+ capability, then the tool cannot be guaranteed to be unique.
'Unique' is a little confusing - perhaps 'a one-to-one mapping between
tool objects and physical tools' or similar. Also if we're not
providing some kind of tablet caps event, that you can't query this.
It's also pretty contradictory with the first sentence. :) A
'generally' there would be enough to weasel out of it.
that's just a mixup in wording. the object is unique either way, whether
it's mapped to the same physical tool depends on the serial id. I'll just
reword that.
Post by Daniel Stone
Post by Peter Hutterer
+ <request name="set_cursor">
+ <description summary="set the tablet tool's surface">
+ Sets the surface of the cursor used for this tool on the given
+ tablet. The surface is only shown when this tool is in proximity of
+ this tablet. If the surface is NULL, the pointer image is hidden
+ completely.
+
+ The parameters hotspot_x and hotspot_y define the position of the
+ pointer surface relative to the pointer location. Its top-left corner
+ is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+ coordinates of the pointer location, in surface local coordinates.
(Something something transforms on the cursor surface ...)
Post by Peter Hutterer
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tool object">
+ This destroys the client's resource for this tool object.
+
+ A client must not issue this request until it receives a
+ wp_tablet_tool.remove event.
Egads. What happens when a client no longer wants to know about tablet
events (e.g. you have an embedded drawing program in a browser but
then close the tab): it just has to ignore the stream of events
forever? A bit hostile.
you can drop the tablet manager and re-bind. I think filtering specific
devices at the protocol level is a bit of a niche usecase and better handled
in the toolkit.
Post by Daniel Stone
Post by Peter Hutterer
+ <enum name="type">
+ <description summary="a physical tool type">
+ Describes the physical type of a tool. The physical type of a tool
+ generally defines its base usage.
+
+ The mouse tool represents a mouse-shaped tool that is not a relative
+ device but bound to the tablet's surface, providing absolute
+ coordinates.
+
+ The lens tool is a mouse-shaped tool with an attached lens to
+ provide precision focus.
+ </description>
+ <entry name="pen" value="0x140" summary="Pen"/>
+ <entry name="eraser" value="0x141" summary="Eraser"/>
+ <entry name="brush" value="0x142" summary="Brush"/>
+ <entry name="pencil" value="0x143" summary="Pencil"/>
+ <entry name="airbrush" value="0x144" summary="Airbrush"/>
+ <entry name="finger" value="0x145" summary="Finger"/>
+ <entry name="mouse" value="0x146" summary="Mouse"/>
+ <entry name="lens" value="0x147" summary="Lens"/>
+ </enum>
*raises eyebrow* - magic numbers from Wacom protocol? (Fine if they are.)
linux/input.h, actually (BTN_TOOL_PEN, etc.), not that it really matters, we
could use 1-7 just as well :)
Post by Daniel Stone
Post by Peter Hutterer
+ <event name="serial_id">
+ <description summary="unique serial number of the tool">
+ If the tool can be identified by a unique 64-bit serial number, this
+ event notifies the client of the serial number.
+
+ If multiple tablets are available in the same seat and the tool is
+ uniquely identifiable by the serial number, that tool may move
+ between tablets.
+
+ Otherwise, if the tool has no serial number and this event is
+ missing, the tool is tied to the tablet it first comes into
+ proximity with. Even if the physical tool is used on multiple
+ tablets, separate wp_tablet_tool objects will be created, one per
+ tablet.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="serial_id_msb" type="uint" summary="the unique serial number of the tool, most significant bits"/>
+ <arg name="serial_id_lsb" type="uint" summary="the unique serial number of the tool, least significant bits"/>
+ </event>
Would be really nice to not use 'serial' in the name, though using it
in the description absolutely makes sense. Just want to avoid
confusion with serial-as-place-in-event-stream-identifier ...
hwserial? it's referred to as serial number in most other instances, so I'm
out of ideas on how else to name it. I'm aware of the clash (hence
"serial_id") but unsure how to avoid it.
Post by Daniel Stone
Post by Peter Hutterer
+ <enum name="capability">
+ <description summary="capability flags for a tool">
+ Describes extra capabilities on a tablet.
+
+ Any tool must provide x and y values, extra axes are
+ device-specific.
+ </description>
+ <entry name="tilt" value="1" summary="Tilt axes"/>
+ <entry name="pressure" value="2" summary="Pressure axis"/>
+ <entry name="distance" value="3" summary="Distance axis"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="tool capability notification">
+ This event notifies the client of any capabilities of this tool,
+ beyond the main set of x/y axes and tip up/down detection.
+
+ One event is sent for each extra capability available on this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="capability" type="uint" summary="the capability"/>
+ </event>
Bitmask?
tbh, the way we send events, I don't see any specific benefit a bitmask
would give us. we could send a single capability event with a bitmask but
tbh it's less flexible and virtually the same work in the client.
Post by Daniel Stone
Post by Peter Hutterer
+ <event name="down">
+ <description summary="tablet tool is making contact">
+ Sent whenever the tablet tool comes in contact with the surface of the
+ tablet. If the tablet tool moves out of a region while in contact with
+ the surface of the tablet, the client owning said region will receive a
+ wp_tablet::up event, followed by a wp_tablet::proximity_out event and a
+ wp_tablet::frame event.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
Inconsistent use of protocol::event here, with protocol.event
elsewhere in the docs.
Post by Peter Hutterer
+ <event name="distance">
+ <description summary="distance change event">
+ Sent whenever the distance axis on a tool changes. The value of this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="distance" type="uint" summary="The current distance value"/>
+ </event>
Units?
Post by Peter Hutterer
+ <enum name="button_state">
+ <description summary="physical button state">
+ Describes the physical state of a button which provoked the button event
+ </description>
+ <entry name="released" value="0" summary="button is not pressed"/>
+ <entry name="pressed" value="1" summary="button is pressed"/>
+ </enum>
Imperative is better here: 'button pressed', 'button released'. Also
happens to match the doc in the button event itself. ;)
Post by Peter Hutterer
+ <event name="button">
+ <description summary="button event">
+ Sent whenever a button on the stylus is pressed or released.
+ </description>
+
+ <arg name="serial" type="uint"/>
+ <arg name="button" type="uint" summary="The button whose state has changed"/>
+ <arg name="state" type="uint" summary="Whether the button was pressed or released"/>
+ </event>
+ <event name="id">
+ <description summary="tablet device vid/pid">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="vid" type="uint" summary="vendor id"/>
+ <arg name="pid" type="uint" summary="product id"/>
+ </event>
VID/PID space ... ?
Post by Peter Hutterer
+ <enum name="type">
+ <description summary="tablet type">
+ Describes the type of tablet
+ </description>
Full stop
Post by Peter Hutterer
+ <entry name="external" value="0" summary="The tablet is an external tablet, such as an Intuos"/>
+ <entry name="internal" value="1" summary="The tablet is a built-in tablet, usually in a laptop"/>
+ <entry name="display" value="2" summary="The tablet is a display tablet, such as a Cintiq"/>
+ </enum>
+
+ <event name="type">
+ <description summary="the tablet type">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="type" type="uint" summary="the tablet type (internal, external, ...)"/>
+ </event>
Are these two not redundant?
fwiw, the type event/enum has been dropped since (see Carlos' comments elsewhere)
Post by Daniel Stone
Post by Peter Hutterer
+ <event name="path">
+ <description summary="path to the device">
+ A system-specific device path that indicates which device is behind
+ this wp_tablet. This information may be used to gather additional
+ information about the device, e.g. through libwacom.
+
+ A device may have more than one device path, if so, multiple
+ wp_tablet.path events are sent. A device may be emulated and not
+ have a device path, in that case this event will not be sent.
+
+ The format of the path is unspecified, it may be a device node, a
+ sysfs path, or some other identifier. It is up to the client to
+ identify the string provided.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="path" type="string" summary="path to local device"/>
+ </event>
Mm, device path isn't really a good idea with logind. Should just be
sysfs path or nothing, I think.
I specifically left this open because we can't predict what it'll be (see
the third paragraph). A client will have to strcmp for /sys or /dev, but I
think that's still better than dictating one specific path type.
Post by Daniel Stone
Anyway, none of these are particularly fundamental to the protocol;
the biggest change is the wp_tablet_seat thing, but given that's not a
pattern we've previously used, it could go either way. So, with as
thanks, much appreciated

Cheers,
Peter
Peter Hutterer
2015-12-08 02:50:01 UTC
Permalink
Signed-off-by: Peter Hutterer <***@who-t.net>
Reviewed-by: Jason Gerecke <***@gmail.com>
Reviewed-by: Daniel Stone <***@fooishbar.org>
---
Changes to v1:
- drop the display type event, mostly useless in the protocol. clients that
need it can get it through pid/vid + libwacom
- add the enum references
- extra clarification for the button-state-on-proximity event ordering
- extra clarification about the uniqueness of a tool
- rename tool_serial to hwserial
- rename msb/lsb to hi/lo to match other protocols
- clarify vid/pid
- rename to new wp_.*_v1 interface versioning

Makefile.am | 1 +
unstable/tablet/README | 4 +
unstable/tablet/tablet-unstable-v1.xml | 574 +++++++++++++++++++++++++++++++++
3 files changed, 579 insertions(+)
create mode 100644 unstable/tablet/README
create mode 100644 unstable/tablet/tablet-unstable-v1.xml

diff --git a/Makefile.am b/Makefile.am
index fb00ebe..49433ea 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,6 +5,7 @@ unstable_protocols = \
unstable/text-input/text-input-unstable-v1.xml \
unstable/input-method/input-method-unstable-v1.xml \
unstable/xdg-shell/xdg-shell-unstable-v5.xml \
+ unstable/tablet/tablet-unstable-v1.xml \
$(NULL)

nobase_dist_pkgdata_DATA = \
diff --git a/unstable/tablet/README b/unstable/tablet/README
new file mode 100644
index 0000000..7ba8e77
--- /dev/null
+++ b/unstable/tablet/README
@@ -0,0 +1,4 @@
+Tablet protocol
+
+Maintainers:
+Peter Hutterer <***@who-t.net>
diff --git a/unstable/tablet/tablet-unstable-v1.xml b/unstable/tablet/tablet-unstable-v1.xml
new file mode 100644
index 0000000..84c2934
--- /dev/null
+++ b/unstable/tablet/tablet-unstable-v1.xml
@@ -0,0 +1,574 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland_tablet_unstable_v1">
+ <description summary="Wayland protocol for graphics tablets">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ More than one tablet may exist, and device-specifics matter. Tablets are
+ not represented by a single virtual device like wl_pointer. A client
+ binds to the tablet manager object which is just a proxy object. From
+ that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+ and that returns the actual interface that has all the tablets. With
+ this indirection, we can avoid merging wp_tablet into the actual wayland
+ protocol, a long-term benefit.
+
+ The wp_tablet_seat sends a "tablet added" for each tablet connected.
+ That event is followed by descriptive events about the hardware;
+ currently that includes events for name, vid/pid and
+ a wp_tablet.path event that describes a local path. This path can be
+ used to uniquely identify a tablet, or get more information through
+ libwacom. Emulated or nested tablets can skip any of those, e.g. a
+ virtual tablet may not have a vid/pid. The sequence of descriptive
+ events is terminated by a wp_tablet.done event to signal that a client
+ may now finalize any initialization for that tablet.
+
+ Events from tablets require a tool in proximity. Tools are also managed
+ by the tablet seat, a "tool added" is sent whenever a tool is new to
+ the compositor. That event is followed by a number of descriptive events
+ about the hardware; currently that includes capabilities, serial id,
+ hardware serial and tool type. Similar to the tablet interface, a
+ wp_tablet_tool.done event is sent to terminate that initial sequence.
+
+ Any event from a tool happens on the wp_tablet_tool interface. When the
+ tool gets into proximity of the tablet, a proximity_in event is sent on
+ the wp_tablet_tool interface, listing the tablet and the surface. That
+ event is followed by a motion event with the coordinates. After that,
+ it's the usual motion, axis, button, etc. events.
+ The protocol's serialisation means events are grouped by by
+ wp_tablet_tool.frame events.
+
+ Two special events (that don't exist in X) are down and up. They signal
+ "tip touching the surface". For tablets without real proximity
+ detection, the sequence is: proximity_in, motion, down, frame.
+
+ When the tool leaves proximity, a proximity_out event is sent. If any
+ button is still down, a button release event is sent before this
+ proximity event. These button events are sent in the same frame as the
+ proximity event to signal to the client that the buttons were held when
+ the tool left proximity.
+
+ If the tool moves out of the surface but stays in proximity (i.e.
+ between windows), compositor-specific grab policies apply. This usually
+ means that the proximity-out is delayed until all buttons are released.
+
+ Moving a tool physically from one tablet to the other has no real effect
+ on the protocol, since we already have the tool object from the "tool
+ added" event. All the information is already there and the proximity
+ events on both tablets is all a client needs to reconstruct what
+ happened.
+
+ Any extra axis is normalized, i.e. the client knows the range as
+ specified in the protocol (e.g. [0, 65535]), the granularity however is
+ unknown. The current axes are pressure, tilt (both x/y required) and
+ distance, the most common set.
+
+ Since tablets work independently of the pointer controlled by the mouse,
+ the focus handling is independent too and controlled by proximity.
+ The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
+ This cursor surface may be the same as the mouse cursor, and it may be
+ the same across tools but it is possible to be more fine-grained. For
+ example, a client may set different cursors for the pen and eraser.
+
+ Tools are generally independent of tablets and it is
+ compositor-specific policy when a tool can removed. Common approaches
+ will likely include some form of removing a tool when all tablets the
+ tool was used on is removed.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+ </description>
+ <copyright>
+ Copyright 2014 © Stephen "Lyude" Chandler Paul
+ Copyright 2015 © Red Hat, Inc.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ </copyright>
+ <interface name="zwp_tablet_manager_v1" version="1">
+ <description summary="controller object for graphic tablet devices">
+ An object that provides access to the graphics tablets available on this
+ system. Any tablet is associated with a seat, to get access to the
+ actual tablets, use wp_tablet_manager.get_tablet_seat.
+ </description>
+
+ <request name="get_tablet_seat">
+ <description summary="get the tablet seat">
+ Get the wp_tablet_seat object for the given seat. This object
+ provides access to all graphics tablets in this seat.
+ </description>
+ <arg name="tablet_seat" type="new_id" interface="zwp_tablet_seat1"/>
+ <arg name="seat" type="object" interface="wl_seat" summary="The wl_seat object to retrieve the tablets for" />
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet manager object">
+ This destroys the resources associated with the tablet manager.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="zwp_tablet_seat1" version="1">
+ <description summary="controller object for graphic tablet devices of a seat">
+ An object that provides access to the graphics tablets available on this
+ seat. After binding to this interface, the compositor sends a set of
+ wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="release the memory for the tablet seat object">
+ This destroys the resources associated with the tablet seat.
+ </description>
+ </request>
+
+ <event name="tablet_added">
+ <description summary="new device notification">
+ This event is sent whenever a new tablet becomes available on this
+ seat. This event only provides the object id of the tablet, any
+ static information about the tablet (device name, vid/pid, etc.) is
+ sent through the wp_tablet interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet_v1" summary="the newly added graphics tablet"/>
+ </event>
+
+ <event name="tool_added">
+ <description summary="a new tool has been used with a tablet">
+ This event is sent whenever a tool that has not previously been used
+ with a tablet comes into use. This event only provides the object id
+ of the tool, any static information about the tool (capabilities,
+ type, et.c) is sent through the wp_tablet_tool interface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_tablet_tool_v1" summary="the newly added tablet tool"/>
+ </event>
+ </interface>
+
+ <interface name="zwp_tablet_tool_v1" version="1">
+ <description summary="a physical tablet tool">
+ An object that represents a physical tool that has been, or is
+ currently in use with a tablet in this seat. Each wp_tablet_tool
+ object stays valid until the client destroys it; the compositor
+ reuses the wp_tablet_tool object to indicate that the object's
+ respective physical tool has come into proximity of a tablet again.
+ A client must not call wp_tablet_tool.destroy until it receives a
+ wp_tablet_tool.release event.
+
+ A wp_tablet_tool object's relation to a physical tool depends on the
+ tablet's ability to report serial numbers. If the tablet supports
+ this capability, then the object represents a specific physical tool
+ and can be identified even when used on multiple tablets.
+
+ A tablet tool has a number of static characteristics, e.g. tool type,
+ serial_id and capabilities. These capabilities are sent in an event
+ sequence after the wp_tablet_seat.tool_added event before any actual
+ events from this tool. This initial event sequence is terminated by a
+ wp_tablet_tool.done event.
+
+ Tablet tool events are grouped by wp_tablet_tool.frame events.
+ Any events received before a wp_tablet_tool.frame event should be
+ considered part of the same hardware state change.
+ </description>
+
+ <request name="set_cursor">
+ <description summary="set the tablet tool's surface">
+ Sets the surface of the cursor used for this tool on the given
+ tablet. This request only takes effect if the tool is in proximity
+ of one of the requesting client's surfaces or the surface parameter
+ is the current pointer surface. If there was a previous surface set
+ with this request it is replaced. If surface is NULL, the cursor
+ image is hidden.
+
+ The parameters hotspot_x and hotspot_y define the position of the
+ pointer surface relative to the pointer location. Its top-left corner
+ is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+ coordinates of the pointer location, in surface local coordinates.
+
+ On surface.attach requests to the pointer surface, hotspot_x and
+ hotspot_y are decremented by the x and y parameters passed to the
+ request. Attach must be confirmed by wl_surface.commit as usual.
+
+ The hotspot can also be updated by passing the currently set pointer
+ surface to this request with new values for hotspot_x and hotspot_y.
+
+ The current and pending input regions of the wl_surface are cleared,
+ and wl_surface.set_input_region is ignored until the wl_surface is no
+ longer used as the cursor. When the use as a cursor ends, the current
+ and pending input regions become undefined, and the wl_surface is
+ unmapped.
+
+ This request gives the surface the role of a cursor. The role
+ assigned by this request is the same as assigned by
+ wl_pointer.set_cursor meaning the same surface can be
+ used both as a wl_pointer cursor and a wp_tablet cursor. If the
+ surface already has another role, it raises a protocol error
+ The surface may be used on multiple tablets and across multiple
+ seats.
+ </description>
+ <arg name="serial" type="uint" summary="serial of the enter event"/>
+ <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+ <arg name="hotspot_x" type="int" summary="x coordinate in surface-relative coordinates"/>
+ <arg name="hotspot_y" type="int" summary="y coordinate in surface-relative coordinates"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tool object">
+ This destroys the client's resource for this tool object.
+
+ A client must not issue this request until it receives a
+ wp_tablet_tool.remove event.
+ </description>
+ </request>
+
+ <enum name="type">
+ <description summary="a physical tool type">
+ Describes the physical type of a tool. The physical type of a tool
+ generally defines its base usage.
+
+ The mouse tool represents a mouse-shaped tool that is not a relative
+ device but bound to the tablet's surface, providing absolute
+ coordinates.
+
+ The lens tool is a mouse-shaped tool with an attached lens to
+ provide precision focus.
+ </description>
+ <entry name="pen" value="0x140" summary="Pen"/>
+ <entry name="eraser" value="0x141" summary="Eraser"/>
+ <entry name="brush" value="0x142" summary="Brush"/>
+ <entry name="pencil" value="0x143" summary="Pencil"/>
+ <entry name="airbrush" value="0x144" summary="Airbrush"/>
+ <entry name="finger" value="0x145" summary="Finger"/>
+ <entry name="mouse" value="0x146" summary="Mouse"/>
+ <entry name="lens" value="0x147" summary="Lens"/>
+ </enum>
+
+ <event name="type">
+ <description summary="tool type">
+ The tool type is the high-level type of the tool and usually decides
+ the interaction expected from this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="tool_type" type="uint" enum="type" summary="the physical tool type"/>
+ </event>
+
+ <event name="hwserial">
+ <description summary="unique hardware serial number of the tool">
+ If the physical tool can be identified by a unique 64-bit serial
+ number, this event notifies the client of this serial number.
+
+ If multiple tablets are available in the same seat and the tool is
+ uniquely identifiable by the serial number, that tool may move
+ between tablets.
+
+ Otherwise, if the tool has no serial number and this event is
+ missing, the tool is tied to the tablet it first comes into
+ proximity with. Even if the physical tool is used on multiple
+ tablets, separate wp_tablet_tool objects will be created, one per
+ tablet.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="hardware_serial_hi" type="uint" summary="the unique serial number of the tool, most significant bits"/>
+ <arg name="hardware_serial_lo" type="uint" summary="the unique serial number of the tool, least significant bits"/>
+ </event>
+
+ <enum name="hardware_id_format">
+ <description summary="the hardware id format">
+ Specifies the format of the hardware id in the
+ wp_tablet_tool.hardware_id event.
+
+ A wacom_stylus_id format indicates a hardware id as the id used by
+ graphics tablet made by Wacom Inc. For example, on Wacom tablets the
+ hardware id of a Grip Pen (a stylus) is 0x802.
+ </description>
+ <entry name="wacom_stylus_id" value="0" />
+ </enum>
+
+ <event name="hardware_id">
+ <description summary="hardware id notification">
+ This event notifies the client of a hardware id available on this tool.
+
+ The hardware id is a device-specific 64-bit id that provides extra
+ information about the tool in use, beyond the wl_tool.type
+ enumeration. The format of the id is device-specific.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="format" type="uint" enum="hardware_id_format" summary="the type of the id" />
+ <arg name="hardware_id_hi" type="uint" summary="the hardware id, most significant bits"/>
+ <arg name="hardware_id_lo" type="uint" summary="the hardware id, least significant bits"/>
+ </event>
+
+
+ <enum name="capability">
+ <description summary="capability flags for a tool">
+ Describes extra capabilities on a tablet.
+
+ Any tool must provide x and y values, extra axes are
+ device-specific.
+ </description>
+ <entry name="tilt" value="1" summary="Tilt axes"/>
+ <entry name="pressure" value="2" summary="Pressure axis"/>
+ <entry name="distance" value="3" summary="Distance axis"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="tool capability notification">
+ This event notifies the client of any capabilities of this tool,
+ beyond the main set of x/y axes and tip up/down detection.
+
+ One event is sent for each extra capability available on this tool.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet_tool.done event.
+ </description>
+ <arg name="capability" type="uint" enum="capability" summary="the capability"/>
+ </event>
+
+ <event name="done">
+ <description summary="tool description events sequence complete">
+ This event signals the end of the initial burst of descriptive
+ events. A client may consider the static description of the tool to
+ be complete and finalize initialization of the tool.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tool removed">
+ This event is sent when the tool is removed from the system. The client
+ should not expect the resource it currently has associated with the
+ tool to be used again if the tool comes back into proximity later.
+
+ It is compositor-dependent when a tool is removed. Some tools are
+ associated with a single tablet only and may get removed when the
+ respective tablet is removed. Other tools may be used on multiple
+ tablets and removing a tablet may not remove this tool.
+
+ When this event is received, the client must wp_tablet_tool.destroy
+ the object.
+ </description>
+ </event>
+
+ <event name="proximity_in">
+ <description summary="proximity in event">
+ Notification that this tool is focused on a certain surface.
+
+ This event can be received when the tool has moved from one surface to
+ another, or when the tool has come back into proximity above the
+ surface.
+
+ If any button is logically down when the tool comes into proximity,
+ the respective button event is sent after the proximity_in event but
+ within the same frame as the proximity_in event.
+ </description>
+ <arg name="serial" type="uint"/>
+ <arg name="tablet" type="object" interface="zwp_tablet_v1" summary="The tablet the tool is in proximity of"/>
+ <arg name="surface" type="object" interface="wl_surface" summary="The current surface the tablet tool is over"/>
+ </event>
+
+ <event name="proximity_out">
+ <description summary="proximity out event">
+ Notification that this tool has either left proximity, or is no
+ longer focused on a certain surface.
+
+ When the tablet tool leaves proximity of the tablet, button release
+ events are sent for each button that was held down at the time of
+ leaving proximity. These events are sent before the proximity_out
+ event but within the same wp_tablet.frame.
+
+ If the tool stays within proximity of the tablet, but the focus
+ changes from one surface to another, a button release event may not
+ be sent until the button is actually released or the tool leaves the
+ proximity of the tablet.
+ </description>
+ </event>
+
+ <event name="down">
+ <description summary="tablet tool is making contact">
+ Sent whenever the tablet tool comes in contact with the surface of the
+ tablet. If the tablet tool moves out of a region while in contact with
+ the surface of the tablet, the client owning said region will receive a
+ wp_tablet.up event, followed by a wp_tablet.proximity_out event and a
+ wp_tablet.frame event.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
+
+ <event name="up">
+ <description summary="tablet tool is no longer making contact">
+ Sent whenever the tablet tool stops making contact with the surface of
+ the tablet, or when the tablet tool moves off of a surface while it was
+ making contact with the tablet's surface.
+ </description>
+ </event>
+
+ <event name="motion">
+ <description summary="motion event">
+ Sent whenever a tablet tool moves.
+ </description>
+ <arg name="x" type="fixed" summary="surface-relative x coordinate"/>
+ <arg name="y" type="fixed" summary="surface-relative y coordinate"/>
+ </event>
+
+ <event name="pressure">
+ <description summary="pressure change event">
+ Sent whenever the pressure axis on a tool changes. The value of this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="pressure" type="uint" summary="The current pressure value"/>
+ </event>
+
+ <event name="distance">
+ <description summary="distance change event">
+ Sent whenever the distance axis on a tool changes. The value of this
+ event is normalized to a value between 0 and 65535.
+ </description>
+ <arg name="distance" type="uint" summary="The current distance value"/>
+ </event>
+
+ <event name="tilt">
+ <description summary="tilt change event">
+ Sent whenever one or both of the tilt axes on a tool change. Each tilt
+ value is normalized between -65535 and 65535.
+ </description>
+ <arg name="tilt_x" type="int" summary="The current value of the X tilt axis"/>
+ <arg name="tilt_y" type="int" summary="The current value of the Y tilt axis"/>
+ </event>
+
+ <enum name="button_state">
+ <description summary="physical button state">
+ Describes the physical state of a button which provoked the button event
+ </description>
+ <entry name="released" value="0" summary="button is not pressed"/>
+ <entry name="pressed" value="1" summary="button is pressed"/>
+ </enum>
+
+ <event name="button">
+ <description summary="button event">
+ Sent whenever a button on the stylus is pressed or released.
+ </description>
+
+ <arg name="serial" type="uint"/>
+ <arg name="button" type="uint" summary="The button whose state has changed"/>
+ <arg name="state" type="uint" enum="button_state" summary="Whether the button was pressed or released"/>
+ </event>
+
+ <event name="frame">
+ <description summary="frame event">
+ Marks the end of a series of axis and/or button updates from the
+ tablet. The wayland protocol requires axis updates to be sent
+ sequentially, however all events within a frame should be considered
+ one hardware event.
+ </description>
+ <arg name="time" type="uint" summary="The time of the event with millisecond granularity"/>
+ </event>
+
+ <enum name="error">
+ <entry name="role" value="0" summary="given wl_surface has another role"/>
+ </enum>
+ </interface>
+
+ <interface name="zwp_tablet_v11" version="1">
+ <description summary="graphics tablet device">
+ The wp_tablet interface represents one graphics tablet device. The
+ tablet interface itself does not generate events, all events are
+ generated by wp_tablet_tool objects when in proximity above a tablet.
+
+ A tablet has a number of static characteristics, e.g. device name and
+ pid/vid. These capabilities are sent in an event sequence after the
+ wp_tablet_seat.tablet_added event. This initial event sequence is
+ terminated by a wp_tablet.done event.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the tablet object">
+ This destroys the client's resource for this tablet object.
+
+ A client must not issue this request until it receives a
+ wp_tablet.remove event.
+ </description>
+ </request>
+
+ <event name="name">
+ <description summary="tablet device name">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="name" type="string" summary="the device name"/>
+ </event>
+
+ <event name="id">
+ <description summary="tablet device USB vendor/product id">
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="vid" type="uint" summary="USB vendor id"/>
+ <arg name="pid" type="uint" summary="USB product id"/>
+ </event>
+
+ <event name="path">
+ <description summary="path to the device">
+ A system-specific device path that indicates which device is behind
+ this wp_tablet. This information may be used to gather additional
+ information about the device, e.g. through libwacom.
+
+ A device may have more than one device path, if so, multiple
+ wp_tablet.path events are sent. A device may be emulated and not
+ have a device path, in that case this event will not be sent.
+
+ The format of the path is unspecified, it may be a device node, a
+ sysfs path, or some other identifier. It is up to the client to
+ identify the string provided.
+
+ This event is sent in the initial burst of events before the
+ wp_tablet.done event.
+ </description>
+ <arg name="path" type="string" summary="path to local device"/>
+ </event>
+
+ <event name="done">
+ <description summary="tablet description events sequence complete">
+ This event is sent immediately to signal the end of the initial
+ burst of descriptive events. A client may consider the static
+ description of the tablet to be complete and finalize initialization
+ of the tablet.
+ </description>
+ </event>
+
+ <event name="removed">
+ <description summary="tablet removed event">
+ Sent when the tablet has been removed from the system. When a tablet
+ is removed, some tools may be removed.
+
+ When this event is received, the client must wp_tablet.destroy
+ the object.
+ </description>
+ </event>
+ </interface>
+</protocol>
--
2.5.0
Peter Hutterer
2015-12-08 05:31:43 UTC
Permalink
Post by Peter Hutterer
+<protocol name="wayland_tablet_unstable_v1">
the protocol name should just be "tablet", i.e. tablet_unstable_v1 in this case.
Post by Peter Hutterer
+ <interface name="zwp_tablet_seat1" version="1">
this should be ...seat_v1
Post by Peter Hutterer
+ <interface name="zwp_tablet_v11" version="1">
this should be v1

These are all fixed locally now.

Cheers,
Peter
Peter Hutterer
2015-12-08 22:00:39 UTC
Permalink
What is the plan for using a tablet in "relative" mode? This is pretty
common if the tablet is smaller than the screen, as many modern ones are.
I would love to hear where you get this information from, because the one
thing we're suffering from is not knowing how our users use the tablet.
Relative mode is common (and default) in the wacom driver for the lens/puck
tool but few users have that one. Relative mode for the stylus is available,
but we have little to no data on who's using it.

So, please tell me how you know this, because we desparately need this type
of information and I want to figure out more usage data.

That aside, relative mode is handled by the compositor, it's not something
exposed on the protocol. A client always gets absolute coordinates,
regardless of the input mode.
My guess is that you plan to deliver screen/surface coordinates, and that
the client is unaware of the actual size of the tablet. However it is not
clear from this.
Please suggest a rewording that makes this clearer.

Cheers,
Peter
Post by Peter Hutterer
Post by Peter Hutterer
+<protocol name="wayland_tablet_unstable_v1">
the protocol name should just be "tablet", i.e. tablet_unstable_v1 in this case.
Post by Peter Hutterer
+ <interface name="zwp_tablet_seat1" version="1">
this should be ...seat_v1
Post by Peter Hutterer
+ <interface name="zwp_tablet_v11" version="1">
this should be v1
These are all fixed locally now.
Cheers,
Peter
Bill Spitzak
2015-12-12 20:15:02 UTC
Permalink
Post by Peter Hutterer
What is the plan for using a tablet in "relative" mode? This is pretty
common if the tablet is smaller than the screen, as many modern ones are.
I would love to hear where you get this information from, because the one
thing we're suffering from is not knowing how our users use the tablet.
Relative mode is common (and default) in the wacom driver for the lens/puck
tool but few users have that one. Relative mode for the stylus is available,
but we have little to no data on who's using it.
I am using a Wacom Inutos 6x8 tablet. This is a professional and expensive
device (I got it from the bankruptcy auction for Rhythm & Hues, every
artist used these things except for a very small number that had the much
larger 16x16 (?) ones).

My screens are a 4x3 and a 16x9 screen arranged next to each other. Mapping
the tablet area to the entire display results in a horizontal magnification
between physical stylus movement and on-screen movement of about 6 and
vertical scale of about 2. This is too large for me to use on sketching or
3D modelling unless the model is zoomed in so much that I lose any context.
In addition motion of the stylus is distorted by 2.33 times more
horizontally than vertically, which I find very disconcerting. Mapping to
only one screen reduces both of these problems, but not enough imho, and
makes it impossible to use the stylus on one of the screens.

I am also using this on an IMac which has a screen that is closer to 4/3 so
there is no distortion, but I still found the scale much too large to use
on photoshop work.

For these reasons I use the tablet in relative mode for all the tools.

I find it hard to believe that my hardware setup is uncommon. It was used
this way at R&H, and Linux and Windows and Mac all have the ability to set
it.

Linux support is quite broken and refuses to produce a square aspect ratio
of the motion unless you send xsetwacom commands. Previous versions had
weird bugs where the commands depended on the size of the outputs, but
these seem to be fixed. Here is the cryptic commands I am using (a further
bug is that I have to run this each time after the machine sleeps):

xsetwacom --set "Wacom Intuos3 6x8 stylus" Mode Relative
xsetwacom --set "Wacom Intuos3 6x8 stylus" Area "0 0 162560 121920"
xsetwacom --set "Wacom Intuos3 6x8 eraser" Mode Relative
xsetwacom --set "Wacom Intuos3 6x8 eraser" Area "0 0 162560 121920"

I would say that Mac is not much better. It produces a square aspect but
you have no control over the scale. Windows (well the Wacom-supplied
driver) is much better with a scale control.

I personally believe that what the user wants is to limit the magnification
and distortion of motion, and would use absolute mode if possible without
violating these constraints. Therefore instead of the controls being
whether relative motion is used or not, the controls are a range of
magnification and distortion that the user accepts. This will allow the
tablet to switch automatically between modes if the area is changed (for
instance if a client is able to restrict the tablet to it's own surface).

Looking at my settings I seem to have a physical magnification very close
to 1:1 (I have to move the stylus very slow so that acceleration does not
change the dimension). I also know that a distortion of 4/3 horizontally is
outside my limits. I suspect also that if I had a third tool I would have
to add a line for it, an easy way to set all tools without knowing what
they are would be nice.

Relative mode uses acceleration just like a mouse. This does not have any
detrimental effect on using it for painting as far as I can tell.
Post by Peter Hutterer
That aside, relative mode is handled by the compositor, it's not something
exposed on the protocol. A client always gets absolute coordinates,
regardless of the input mode.
My guess is that you plan to deliver screen/surface coordinates, and that
the client is unaware of the actual size of the tablet. However it is not
clear from this.
Please suggest a rewording that makes this clearer.
No it is ok, a bit of thought will show that the coordinates *must* be in
surface coordinates, therefore relative motion must have been handled
already by the compositor before the client gets these events.
Bill Spitzak
2015-12-14 02:13:32 UTC
Permalink
I should point out that a big surprise for me was discovering that
acceleration was applied to the relative motion of the tool. I
discovered that while trying to draw rectangles to determine the scale
and realized that only if I moved really slowly would I get the same
size every time.

I had been using this pretty naturally for sketching and I would have
thought that acceleration would mess this up, but obviously it does not
and I was not even aware it was happening.

Acceleration means some simple ideas about reusing absolute mode code
and just moving the tablet->screen mapping rectangle on each
proximity-in will not work, as that would have no acceleration.

I need to test the Mac and Windows drivers to see what they do, and also
see if acceleration is necessary by turning it off. Possibly it is not
needed.

Despite this I found that I had adjusted it so that the size on-screen
of the slowest motion is almost exactly the same as the distance the
stylus moves.
Post by Peter Hutterer
What is the plan for using a tablet in "relative" mode? This is pretty
common if the tablet is smaller than the screen, as many modern ones are.
I would love to hear where you get this information from, because the one
thing we're suffering from is not knowing how our users use the tablet.
Relative mode is common (and default) in the wacom driver for the lens/puck
tool but few users have that one. Relative mode for the stylus is available,
but we have little to no data on who's using it.
I am using a Wacom Inutos 6x8 tablet. This is a professional and
expensive device (I got it from the bankruptcy auction for Rhythm &
Hues, every artist used these things except for a very small number that
had the much larger 16x16 (?) ones).
My screens are a 4x3 and a 16x9 screen arranged next to each other.
Mapping the tablet area to the entire display results in a horizontal
magnification between physical stylus movement and on-screen movement of
about 6 and vertical scale of about 2. This is too large for me to use
on sketching or 3D modelling unless the model is zoomed in so much that
I lose any context. In addition motion of the stylus is distorted by
2.33 times more horizontally than vertically, which I find very
disconcerting. Mapping to only one screen reduces both of these
problems, but not enough imho, and makes it impossible to use the stylus
on one of the screens.
I am also using this on an IMac which has a screen that is closer to 4/3
so there is no distortion, but I still found the scale much too large to
use on photoshop work.
For these reasons I use the tablet in relative mode for all the tools.
I find it hard to believe that my hardware setup is uncommon. It was
used this way at R&H, and Linux and Windows and Mac all have the ability
to set it.
Linux support is quite broken and refuses to produce a square aspect
ratio of the motion unless you send xsetwacom commands. Previous
versions had weird bugs where the commands depended on the size of the
outputs, but these seem to be fixed. Here is the cryptic commands I am
using (a further bug is that I have to run this each time after the
xsetwacom --set "Wacom Intuos3 6x8 stylus" Mode Relative
xsetwacom --set "Wacom Intuos3 6x8 stylus" Area "0 0 162560 121920"
xsetwacom --set "Wacom Intuos3 6x8 eraser" Mode Relative
xsetwacom --set "Wacom Intuos3 6x8 eraser" Area "0 0 162560 121920"
I would say that Mac is not much better. It produces a square aspect but
you have no control over the scale. Windows (well the Wacom-supplied
driver) is much better with a scale control.
I personally believe that what the user wants is to limit the
magnification and distortion of motion, and would use absolute mode if
possible without violating these constraints. Therefore instead of the
controls being whether relative motion is used or not, the controls are
a range of magnification and distortion that the user accepts. This will
allow the tablet to switch automatically between modes if the area is
changed (for instance if a client is able to restrict the tablet to it's
own surface).
Looking at my settings I seem to have a physical magnification very
close to 1:1 (I have to move the stylus very slow so that acceleration
does not change the dimension). I also know that a distortion of 4/3
horizontally is outside my limits. I suspect also that if I had a third
tool I would have to add a line for it, an easy way to set all tools
without knowing what they are would be nice.
Relative mode uses acceleration just like a mouse. This does not have
any detrimental effect on using it for painting as far as I can tell.
That aside, relative mode is handled by the compositor, it's not something
exposed on the protocol. A client always gets absolute coordinates,
regardless of the input mode.
My guess is that you plan to deliver screen/surface coordinates, and that
the client is unaware of the actual size of the tablet. However it is not
clear from this.
Please suggest a rewording that makes this clearer.
No it is ok, a bit of thought will show that the coordinates *must* be
in surface coordinates, therefore relative motion must have been handled
already by the compositor before the client gets these events.
Continue reading on narkive:
Loading...