Commit graph

165 commits

Author SHA1 Message Date
Peter Hutterer
2c85e2bd9c Revert "Add support for swipe, pinch and hold gestures"
This reverts commit ff9e8905a0.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/386>
2026-04-23 14:19:29 +10:00
Peter Hutterer
ff9e8905a0 Add support for swipe, pinch and hold gestures
On the protocol level these are implemented as three separate interfaces
for swipe, pinch and hold, each interface has the begin/update/end
sequence and effectively matches the wayland pointer-gestures protocol.

Notably, only one of each gesture may be active at any time though the
protocol allows for separate gestures to be active (i.e. swipe while
pinching).

On the library side the gestures match the touch interface so the
sequence for a sender is:

  swipe = ei_device_new_swipe(device, finger_count);
  ei_swipe_begin(swipe);
  ei_swipe_update(swipe, dx, dy);
  ei_swipe_end(swipe);

with the corresponding APIs for pinch and hold.

On the receiver side the event types are separated for BEGIN/UPDATE/END
for all three gestures and thus match the libinput interface.

The notable difference however: there is only one CAP_GESTURES (similar
to libinput) and it is set if any gesture is available on the caller.
Creating a swipe gesture if the remote end does not support it will
return NULL though.

Co-Authored-by: Claude Code <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/309>
2026-04-21 11:12:29 +10:00
Peter Hutterer
1f9be0fd0a Add a new text interface for sending keysyms and utf8 text
The text capability allows for two types of events on that interface:
- XKB keysym events, e.g. XK_ssharp (0x00df) with a press/release state
- UTF8 strings

Keysym events are useful for scenarious where the hardware keycode is
unsuitable due to potentially different key mappings on the client and
server side and/or the client just not wanting to worry about those
mappings. For example a client may want to send Ctrl+C instead of
what effectively is now keycodes for what may or may not be a C key.

UTF8 strings take this a step further and provide a full string (with
implementation-defined size limits to avoid OOM). Unlike e.g. the
wayland text input protocols the assumption is here that the
interaction required to generate that string has already been
performed before the final string is sent over the wire.

Closes #73

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/355>
2026-04-02 05:09:37 +00:00
Peter Hutterer
a6028a7b87 Format the code with clang-format
clang-format taken from libinput, except for
  ColumnLimit: 100
and some macro definitions (which don't all have an effect anyway...)

It's not perfect but good enough and at least consistent.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/383>
2026-03-12 13:55:19 +10:00
Peter Hutterer
5f9e181073 proto: add support for requesting devices
Add support for a client to request the creation of a new device
from the EIS implementation. This is necessary in situations where the
devices created by the EIS implementation are not (or no longer)
suitable for the client to function correctly.

The primary use-case of this is the upcoming tablet tool support where a
client may need to create multiple tablet tools in response to a new
physical tool brought into proximity locally.

Other use-cases include a client closing a device but requiring that
device (or one with similar capabilities) later.

The implementation in libei is straightforward
- on the client side we have a new function to request the new device:
  ei_seat_request_device_with_capabilities()
- on the server side we have a new event EIS_EVENT_SEAT_DEVICE_REQUESTED
  that can make use of the existing eis_event_seat_has_capability() API

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/345>
2026-01-06 04:50:46 +00:00
Peter Hutterer
26e671f192 Swap the object id logging order
This gives us a same-sized prefix for messages, making visual parsing of
logs a bit easier.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/366>
2025-12-12 16:20:03 +10:00
Peter Hutterer
39a222868f proto: add a device ready request
The protocol currently supports a ei_device.done event to notify
the ei client that the initial description of the device is complete.
For some future use-cases the client may need to futher negotiate
properties of the device. For example for tablet tools the client may
narrow down capabilities of the tool.

The sequence with the new request is thus e.g.
     -> ei_seat.device
     -> ei_device.name
     -> ei_device.interface
     -> ei_device.interface
     -> ei_device.done
     <- ei_device.ready
     -> ei_device.resumed

In libei the request is sent automatically on unref of
the DEVICE_ADDED event. This makes clients immediately compatible
and for the typical (future) use-case of device configuration. Said
configuration will likely be handled in response to the DEVICE_ADDED
event anyway.

In libeis, a new EIS_EVENT_DEVICE_READY event that is sent when the client
sends that same event on the protocol, informing the EIS implementation
that this device is ready. For clients that do not support that version
the event is emulated immediately after sending ei_device.done.

This requires a flag bit to be long-term maintainable. The typical
EIS implementation currently calls eis_device_add() immediately
followed by eis_device_resume(). This doesn't leave any room to
wait for the client's ei_device.ready request.

One backwards-compatible solution could be to buffer the
eis_device_resume() until the ei_device.ready has been received but this
is fraught with hairy corner cases, e.g. if the client is a receiver
context we would also have to buffer all events immediately sent to the
client.

So instead, we have a flag in the context and if set by the caller, we
change the internal behavior to match ei_device interface version 3.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/346>
2025-10-17 13:38:47 +10:00
Peter Hutterer
edc8ea045a eis: don't warn about EPIPE, just debug-log it
While it's not the friendliest way of a client to exit, we do need to
expect clients to disconnect any time and that shouldn't trigger
warnings, it's somewhat expected behavior.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/337>
2025-06-16 11:20:21 +10:00
Peter Hutterer
daba46a2ae eis: if a client is slow, queue up messages for future delivery
If a receiver client stops calling ei_dispatch for a while eventually
we fill up the send buffer, causing messages to be quietly dropped.
When the client resumes the message stream resumes with whatever we send
next but that can leave the client in an inconsistent state.

deskflow hit this in the server-side where our event sequence of pointer
motion+frames eventually filled up the buffer, causing
eis_device_stop_emulating() to be silently dropped. On the next
InputCapture sequence eis_device_start_emulating() was sent to an
already emulating client (as seen by the client).

This patch adds a secondary queue, if we fail to send a message with
EAGAIN queue it up and flush that queue whenever the next message is
sent. Meanwhile any newly added messages go straight into that queue.

The caveat here: a nonresponding client will eventually trigger OOM,
there is no upper limit on the messages yet

This is the libeis version of
commit 69e973e6b3 ("ei: queue unsent messages for later delivery if our buffer is full")

Closes: #79
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/331>
2025-05-02 15:40:47 +10:00
Peter Hutterer
73e0e8d339 eis: add EI_EVENT_SYNC as opaque event to correctly schedule callbacks
This event is required to fix an issue with the current
ei_callback.done handling in libeis: previously we would imediately send
the ei_callback.done upon receiving ei_connection.sync from the client.
This results in incorrect behavior as we may have events in the queue
(and/or pending a frame) that the EIS implementation hasn't seen yet.
For example a client sending:
- ei_pointer.motion
- ei_connection.sync
- ei_device.frame
- ei_connection.sync

Will queue a motion + frame event on the EIS side during eis_dispatch()
but immediately receive done events for both sync requests.

This could be handled purely internally by keeping the sync event in the
queue but hidden to the caller - and automatically calling done when
it's that events turn, i.e. something like:

```
  struct eis_event *eis_get_event(struct eis) {
      struct eis_event *e = first_event(eis);
      if (e == EIS_EVENT_SYNC) {
           eis_callback_send_done(e);
           eis_event_unref(e);
           e = next_event(eis);
      }
      return e;
  }
```

but that opens us up to a set of potential bugs detailed in
https://gitlab.freedesktop.org/libinput/libei/-/issues/71#note_2694603

So let's go the easy route by having a new event type that does nothing
other than eis_event_unref() in the EIS implementation. This way we can
queue the event and have everything behave in-order and as expected.

Closes #71

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
e40796402b eis: add eis_ping() and the matching EIS_EVENT_PONG
Identical to "ei: add ei_ping() and the matching EI_EVENT_PONG" but for
libeis.

This wraps around ei_connection.ping to allow a C API user to add
synchronization points.

Closes #69

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
b1c1c5d579 Add the ei_touchscreen.cancel event and ei_touch_cancel()
In the protocol it's a new request/event that is sent instead of the
touch up event.

In the library this is implemented as ei_touch_cancel() which
transparently sends cancel() or up depending on the EIS implementation
support. This is mirrored for the EIS implementation.

Where touch cancel is received as an event it is presented
as EI_EVENT_TOUCH_UP with an ei_event_touch_is_cancel() flag to
check if it was a cancel. This is required for backwards compatbility,
we cannot replace the TOUCH_UP event with a TOUCH_CANCEL event without
breaking existing callers. To add a new event type we would need clients
announcing support for those event types but that's an effort that's
better postponed until we have a stronger need for it (see #68).

Closes #60

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/308>
2024-12-17 15:12:56 +10:00
Peter Hutterer
76652350cc Add a mapping_id to the regions
This allows a caller to match up a region with other data, e.g. in the
remote desktop case the same mapping_id can be assigned to the pipewire
stream that represents that output.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-08-30 09:18:26 +10:00
Peter Hutterer
1aedabe7c7 libeis: check incoming objects' version for correctness
If the server sends a protocol version higher than we support, fail.
2023-05-26 19:16:15 +10:00
Peter Hutterer
f081e8e79f proto: add a version argument to ei_connection.sync
This is the only request that creates a new object but doesn't specify
the version for that object, courtesy of copy/paste from the wayland
protocol. In libei/libeis this a bit was hidden away so it didn't get
noticed - but it was already buggy: libei would always hardcode to
version 1 but libeis would take whichever ei_callback version was agreed
upon during handshake. This version could be higher than 1.

This is a protocol break but we're still pre-1.0, there are very few
people that will be affected by this and it's better than having to
carry this bug around for years.

Fixes #35
2023-05-26 07:01:19 +00:00
Peter Hutterer
3aed761f3d eis: don't log a warning for a disconnecting client that's disconnected
A client that does ei_disconnect() sends out the 'disconnect' protocol
message before closing the fd. On the libeis side, this will cause a
Connection error when reading past that message. Logging that as error
looks bad when this is normal behavior.

The 'disconnect' protocol message changes the client into the
REQUEST_DISCONNECT state. If we get a transport error when the client is
in that state, don't log an error - the client wanted to be disconnected
anyway and even if it's a legitimate socket failure there isn't anything
we can do about it anyway.
2023-05-19 05:10:58 +00:00
Peter Hutterer
e21f14d69f Log a connection error before disconnecting
This makes the debug logs easier to read - previously we'd get an error
and disconnect. That causes unwinding of the state internally
(including lots of debug messages) and then eventually the actual error
that caused the disconnect.

Reshuffle this, so we see the "Connection error" first before all the
unwiding of the state, making it easier to spot what caused the actual
error.
2023-05-19 05:10:58 +00:00
Peter Hutterer
408a3a9462 eis: drop the vestiges of client restrictions
Leftover from 479bda259a (and possibly
others). This dates back to when a client could have restrictions
configured on the same fd. This is now all out-of-band (portals!) so the
compositor knows what the client is allowed to set up anyway.

No need for this (read-only) API here.
2023-05-08 13:38:40 +10:00
Peter Hutterer
e6954b76d3 eis: change the API to match the protocol interfaces closer
Same as the corresponding ei change a few commits ago, this one does all
the EIS renaming in the same manner.

As with the libei changes, an EIS implementation must now handle the
EIS_DEVICE_CAP_BUTTON and EI_DEVICE_CAP_SCROLL capabilities. In
virtually all cases, clients will likely expect that a device with the
pointer or absolute pointer capabilities will also have button and
scroll capabilities.
2023-05-05 14:04:17 +10:00
Peter Hutterer
bf88b34918 Split the ei_pointer interface up into its components
Split the ei_pointer protocol interface into ei_pointer,
ei_pointer_absolute, ei_scroll and ei_button.

This gets rid of the slightly awkward pointer vs pointer absolute
handling. Those were two different capabilities but tied to the same
interface.

Plus it paves the way for devices that are keyboards with scroll
buttons, etc.
2023-05-02 05:53:25 +00:00
Peter Hutterer
5f9bfe7b7b client: drop seats when destroying the client
This *should* have happened when the client got disconnected but in some
race conditions a seat may be added after the client gets disconnected.
Reproducible (sometimes) by test_invalid_object_id with the
eis-demo-server:
- client connects, sends invalid object ID, gets disconnected
- server sees CONNECTED, adds a seat, then sees DISCONNECTED and drops
  the client.

From the demo-server's POV the seat is handled by the client, so it
expects the client to destroy it.
2023-03-03 11:27:01 +10:00
Peter Hutterer
9b390f5703 eis: don't send a disconnected event when the client requests disconnect
As the protocol spec says, EIS should treat this as already disconnected
and not touch the connection.

This fixes a memleak if a client connects and immediately disconnects -
when EIS processes the EIS_EVENT_CLIENT_CONNECT it may set up a bunch of
things like seats (the eis-demo-server does this). Then, later, when
the EIS_EVENTE_CLIENT_DISCONNECT is processed, it calls
eis_client_disconnect() but we were already in the disconnected state
and the seats would not get released.
2023-03-03 11:27:01 +10:00
Peter Hutterer
1a64b4963d Check incoming ids for validity
In libei we just check the range is correct.
In libeis we also check that the client is monotonically increasing the
id.
2023-03-03 11:27:01 +10:00
Peter Hutterer
329db61bee eis: remove now-unused macro 2023-03-03 11:27:01 +10:00
Peter Hutterer
ba51f434a6 proto: switch object ids to 64 bits 2023-03-03 11:27:01 +10:00
Peter Hutterer
1e0796f432 Remove now-obsolete proto files 2023-03-03 11:27:01 +10:00
Peter Hutterer
b309798bf1 Switch object ids to use the object_id_t typedef 2023-03-03 11:27:01 +10:00
Peter Hutterer
8ea6b81f40 Change the ei_device_capability values to match the protocol
In the protocol this is a bitmask, let's make it the same in the
interface to avoid confusion in the implementation.
2023-03-03 11:27:01 +10:00
Peter Hutterer
35f5fa102c proto: rename ei_connection_setup to ei_handshake
This is a better name for the initial handshake and easier to
distinguish from the ei_connection this way too.

Suggested by Jonas Ådahl.
2023-03-03 11:27:01 +10:00
Peter Hutterer
38dc5dc72f proto: shift the capabilities down by one
These were previously (1 << cap) for convenience but that results in the
capability mask on the wire starting at 2 - which is a bit awkward.

Lets shift them down by one so we start the mask at 1.
2023-03-03 11:27:01 +10:00
Peter Hutterer
1c9ce9b680 Add serial numbers to the protocol
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-03-03 11:27:01 +10:00
Peter Hutterer
403e40597d Replace remaining errno-based errors to proper brei_results 2023-03-03 11:27:01 +10:00
Peter Hutterer
1846223991 eis: add eis_client_disconnect_with_reason
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-03-03 11:22:09 +10:00
Peter Hutterer
e67a0a7777 brei: add the brei_result object and bubble it up as error case
Add a new simple object "brei_result" that maps to the protocol-type
reason + explanation. That object is now returned instead of the errno,
giving us better debugging options.

This changes the dispatcher functions from returning an int to returning
a brei_result instead (default NULL for success). A helper function for
converting a neg errno to a result is provided for convenience for now,
eventually all these paths should deal with things correctly.
2023-03-03 11:22:08 +10:00
Peter Hutterer
5631b54b96 eis: pass the disconnect reason around when disconnecting a client
No real functional changes right now, but allows for future multiple errors
2023-03-03 11:21:26 +10:00
Peter Hutterer
6ed610e30e Split the ping/pong request into its own interface
Leave the ei_callback as-is and instead add ei_pingpong for the same
thing initiated by the server. The interface is otherwise identical but
for the direction it is supposed to flow.

This reduces the possibility of a client accidentally sending a
request when it is supposed to handle an event or vice versa.
2023-03-03 11:21:26 +10:00
Peter Hutterer
f41cc91599 proto: add a ping/pong request
This is effectively the same as connection.sync, but goes the other way.
This adds the ei_callback.done request.

In libeis this is (currently) enforced immediately after sending the
connection object. Not required there and makes the code a bit messier
but this way we can ensure that any client library handles that part of
the code.
2023-03-03 11:21:26 +10:00
Peter Hutterer
8c85b8fc1f protocol: add ei_connection.invalid_object
This event is to notify the client that an object used in a request was
unknown. This allows the client to work around race conditions like
binding to a seat that was removed.

This is currently the server-side only which is probably enough for now.
The only client-side created objects we have are the callbacks.
2023-03-03 11:21:26 +10:00
Peter Hutterer
2e4d984819 eis: don't send seat events unless the client supports ei_seat 2023-03-03 11:21:26 +10:00
Peter Hutterer
58b430039a eis: destroy the eis_connection immediately after sending disconnect
Requests the client sent on the connection after disconnect
will thus be ignored.
2023-03-03 11:21:26 +10:00
Peter Hutterer
da51bc095f brei: add a brei context object
Having debugging in the brei code is useful, the only way we can do this
is by passing the log handler down.
2023-03-03 11:21:26 +10:00
Peter Hutterer
0a347f433f protocol: make the connection setup the zero object with a proper handover
This changes the initial connection negotiation to have the
ei_connection_setup as the pre-existing object id 0. Once the client has
sent all the data to set up the connection, the EIS implementation
replies with a new object ID that is the ei_connection protocol object,
i.e. the main object.

This allows for version negotiation of our main protocol object.
2023-03-03 11:21:26 +10:00
Peter Hutterer
4d9ca1796d protocol: move pointer/keyboard/touch into separate interfaces
This allows us to have a device support multiple interfaces and evolve
those interfaces individually, e.g. add things to the keyboard interface
without having to bump the touchscreen interface.

Note that due to a name clash with the existing struct ei_touch public
API the protocol interface is named touchscreen.
2023-03-03 11:21:26 +10:00
Peter Hutterer
964bb76c60 protocol: move the frame event into the device interface 2023-03-03 11:21:26 +10:00
Peter Hutterer
3fc1bdf07a protocol: move start/stop emulating into the device 2023-03-03 11:21:26 +10:00
Peter Hutterer
fadc1853c9 protocol: add the ei_device interface
Sitting nested below the ei_seat, the client gets a notification for a
device through the ei_seat.device event.
2023-03-03 11:21:26 +10:00
Peter Hutterer
01a2ff2d72 brei: pass the proto object through to send_message
Makes for easier debugging since we can print names instead of just
ids/opcodes.
2023-03-03 11:21:26 +10:00
Peter Hutterer
2a8661f7ad protocol: move the seat bind to the seat object
Needs documentation but we can do this when we're done with everything.
2023-03-03 11:21:26 +10:00
Peter Hutterer
bcece3d3c1 eis: make sure our connection setup has the right version too 2023-03-03 11:20:42 +10:00
Peter Hutterer
aaf72f9263 protocol: add a seat interface
Incomplete, only supports the initial seat setup but binding to a seat
is still outside this interface.
2023-03-03 11:20:42 +10:00