Commit graph

643 commits

Author SHA1 Message Date
Erik Jensen
1152c038ee Specify MODIFIERS to be sent for any state change.
Updates protocol and API documentation to specify that the modifiers
event should be sent by the EIS implementation every time the modifier
or group state changes, including when the change is triggered by key
events on the emulated keyboard.

The previous approach of expecting the client to track modifier state
using xkb_state_update_key() for injected keys resulted in multiple
opportunities for the client and server to get out of sync (both due to
unavoidable race conditions and due the client not having access to the
complete state used by the server to calculate state changes), with no
way for the client to ensure it had a correct modifier map short of
unbinding and rebinding the seat.

The new approach allows the client to track state solely by applying
modifiers events with xkb_state_update_mask(), simplifying client
implementation. Because the event is sent for all changes, the client
can use ei_connection.sync / ei_ping() to ensure that it has received
the latest state incorporating all key requests sent prior to the sync
request (along with any externally-caused modifier state changes that
may have occured up to the time the sync message was received).

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/318>
2024-12-18 04:41:11 +00:00
Peter Hutterer
564f14a739 ei: add EI_EVENT_SYNC as opaque event to correctly schedule callbacks
See the corresponding eis commit for details.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00: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
a278c7b371 ei: add ei_ping() and the matching EI_EVENT_PONG
This wraps around ei_connection.sync 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
2cc5e56e28 eis: revamp the internal sync callback
Identical to "ei: revamp the internal sync callback" but for libeis.

In prep work for exposing some of this to the caller, this adds a new
object that carries the our callbacks including the user data (if any).
This is an internal system only and is only used in the handshake
implementation where we don't have userdata anyway.

The new approach is: the callback has an object with a done() and
destroy() callback and the user data, done() is called when we receive
the message from the protocol, destroy() on destroy regardless whether
we got done() first.

This allows a caller to clean up user data even where the callback was
not triggered because we got disconnected first.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
95eb3c4bb3 ei: revamp the internal sync callback
In prep work for exposing some of this to the caller, this adds a new
object that carries the our callbacks including the user data (if any).
This is an internal system only and is only used in the handshake
implementation where we don't have userdata anyway.

The new approach is: the callback has an object with a done() and
destroy() callback and the user data, done() is called when we receive
the message from the protocol, destroy() on destroy regardless whether
we got done() first.

This allows a caller to clean up user data even where the callback was
not triggered because we got disconnected first.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
91e0b8961b doc: specifically mention that unknown events must be unref'd
And document the event type enums as non-exhaustive.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/322>
2024-12-17 16:00:59 +10:00
Peter Hutterer
9c35a57cfe doc: fix some linewrapping issues
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/322>
2024-12-17 15:59:02 +10: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
561cfd009e doc: unwinding state before stop_emulating is the caller's responsibility
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/308>
2024-12-11 10:09:34 +10:00
Peter Hutterer
beb1de6292 ei: indentation fix
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/321>
2024-12-10 09:37:45 +10:00
Peter Hutterer
0cf12a889d eis: remove pending events on eis_device_remove()
This fixes a memleak caused by anything having a device ref when
ei_device_remove() is called. This can happen e.g. if there is a pending
event that hasn't been flushed with a ei_device.frame yet.

Example Sequence:
- client sends an event, event is queued to pending with a ref to the
  device
- next event causes a client disconnect, queuing an emulated seat bind
  of 0
- server calls eis_device_remove()
- client calls eis_device_unref()

One ref is still held in the pending event that was never visible to the
server, preventing the device from being freed.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/317>
2024-12-06 16:48:48 +10:00
Peter Hutterer
62ae6f5edf ei: make ei_disconnect() public
Previously the only way to disconnect from the EIS implementation was
to call ei_unref() and release all resources. This makes it more
difficult for shared cleanup code - clients already have code in place
to deal with DEVICE_REMOVED, SEAT_REMOVED, etc. but that code has to
be triggered manually before ei_unref() is called.

OTOH where the server disconnects us, libei already unwound the state
so we would artificially generate these removed events, allowing the
client to clean up.

Make life easier for client by allowing them to ei_disconnect() and
get the benefits of our state unwinding. ei_disconnect() was already
used internally to disconnect on any error so this merely makes this
function public.

Closes #67

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/311>
2024-12-05 02:44:56 +00:00
Peter Hutterer
b33317cda0 util: Add the trace() debugging macro
Copied from libinput but pushed into util-macros with the color escape
codes expanded for simplicity.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/315>
2024-12-03 05:25:33 +00:00
Peter Hutterer
1f0cc83548 ei: declare struct ei_touch
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/313>
2024-12-02 10:28:19 +10:00
Peter Hutterer
247b6acd3c meson.build: allow disabling libei and libeis
This is primarily a development feature because it makes it easier to
develop a new feature for just one library without having to worry
about build errors in the other library (e.g. when new protocol parts
are added).

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/310>
2024-12-02 00:23:14 +00:00
Peter Hutterer
80bbcc67ed libei: fix an error message, spurious 'd'
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/312>
2024-11-29 12:27:48 +10:00
Peter Hutterer
d593127c18 Revert "util: silence out-of-bounds read warning"
(t < &start_test_function_section) is never true so this commit ended up
disabling the unit tests altogether. That may shut up -fanalyze but
is somewhat of a regression in functionality...

This reverts commit 22c94fd916.
2024-11-26 15:33:36 +10:00
Peter Hutterer
a5826424f1 util: correct the fd validity check
Unlikely but the fd returned may be 0
2024-09-11 12:27:38 +10:00
Peter Hutterer
96609f82a0 util: do an allocation null check in strstrip 2024-09-11 12:27:38 +10:00
Peter Hutterer
55fe9303fb oeffis: rewrite sender_name to make the analyzer happy
Technically we need to check allocation failure of sender after xstrdup
but in doing so we might as well xalloc it and copy chars over
one-by-one.

No functional changes.
2024-09-11 12:27:38 +10:00
Peter Hutterer
005c4ac493 util: use xalloc instead of calloc to avoid NULL checks 2024-09-11 12:27:38 +10:00
Peter Hutterer
bbc1f8de1c util: fix a leaking fd in a test 2024-09-11 12:27:38 +10:00
Peter Hutterer
e3091a1802 util: fix a comment to use the right decimal marker for english 2024-09-11 12:27:38 +10:00
Peter Hutterer
22c94fd916 util: silence out-of-bounds read warning
gcc -fanalyze complains because it doesn't know the __stop section is
always greater than the __start section so it complains that we're
eventually reading past our __start section. Let's silence that with a
simple check.
2024-09-11 12:26:59 +10:00
Peter Hutterer
ec031bc4bf test: add a few non-null checks to make the static analyzer happy 2024-09-11 12:26:40 +10:00
Peter Hutterer
bf03c56300 Add a few missing va_end
Found by gcc -fanalyze
2024-09-11 12:25:41 +10:00
Peter Hutterer
37cc857a52 doc: demote the socket backend in the documentation
The socket backend is useful for debugging and testing but not for real
user-cases where the fd negotiation should be handled by the caller
(e.g. passing it down through the portal). Let's demote the socket
backend in favour of the fd backend.

Related https://gitlab.freedesktop.org/libinput/libei/-/issues/63
2024-09-03 04:00:33 +00:00
Peter Hutterer
e411b85a33 Print the event type name for invalid events 2024-08-07 10:47:25 +10:00
David Redondo
e8a844355f oeffis: Make ConnectToEIS call async
A blocking call can be  problematic when done from inside Xwayland
to the compositor as the compositor could be doing a blocking X call
at the same time. In this instance we found it's likely to happen
because this call will happen shortly after the user accepted the
This is not a problem for the other calls because the portal API
is async for these via request response signalling.
2024-07-31 07:05:48 +00:00
Peter Hutterer
865d7152e0 util: replace a strncpy with a memcpy
We know exactly the lengths of everything involved here so let's use
memcpy. This way we don't need the stringop-truncation warning (a pragma
clang doesn't support anyway).
2024-07-29 05:15:53 +00:00
Peter Hutterer
6ea468c823 util/memfile: use MAP_SHARED to create the map
Using MAP_PRIVATE means copy-on-write so our data written into the map
immediately disappears again. This leads to a empty string when sending
a keymap to a client.
2024-07-29 14:48:34 +10:00
Peter Hutterer
dc153c50ed util/memfile: include stddef for size_t 2024-07-29 14:48:34 +10:00
Peter Hutterer
c4ac084159 util/memmap: add a helper wrapper around mmap
Makes this easier to use with our unref functions.
2024-07-29 14:48:34 +10:00
Peter Hutterer
a424458f03 Devices without regions pass coordinates as-is
If a device doesn't have a region (e.g. physical device) the answer to
"is this in the region" is always yes.

Closes #56
2024-07-25 01:17:39 +00:00
Peter Hutterer
0f81114544 Fix region check for devices with multiple regions
Use the ei(s)_device_in_region() to check for any region.

Closes #56
2024-07-25 01:17:39 +00:00
David Redondo
23f056433d Fix API docs for EIS_EVENT_CLIENT_CONNECT
The functions with event in their name don't exist.
2024-04-09 06:39:13 +00:00
Peter Hutterer
d29778658a oeffis: OEFFIS_DEVICE_ALL_DEVICES should translate to "all"
As the portal documentation [1] says:
  Bitmask of what device types to request remote controlling of. Default is all.

The default is only triggered if we do not submit the types at all, the
current behavior of sending a value of 0 means "none". Fix this by
skipping the "types" key if we try to select for all devices.

[1] https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.impl.portal.RemoteDesktop.html
2023-12-14 00:58:18 +00:00
Peter Hutterer
38132d6fc5 ei: improve debug messages for keymap failures
Let's be more informative about what failed.

Fixes #48
2023-11-09 12:55:56 +10:00
Peter Hutterer
924341e174 ei: keep a cache of defunct objects to avoid spamming the log
Because of the asynchronous protocol, we may get this interaction

   server sends A->destroyed()
       client sends A->foo()
       client receives A->destroyed()
   server receives A->foo()
   server sends invalid_object_id(A)
       client receives invalid_object_id(A)

Previously we dropped the object after destroyed() and were thus
guaranteed to warn about the invalid object id for that same object
later.

Fix this by keeping a cache of defunct object IDs that we know about and
ignoring errors for recently dropped objects.

Every 20 ei_dispatch() calls we drop any defunct objects that were
unregistered more than 5 seconds ago.

Fixes #49
2023-11-09 12:47:06 +10:00
Peter Hutterer
4e634aa76c test: add the ability to add offsets to ei_now()
Build a separate libei-eierpecken.so that is identical to libei.so but
allows adding an offset to ei_now() for the eierpecken tests. That
offset is added to the return value of ei_now(), removing the real-time
dependency of the tests.

In other words, we can call peck_ei_add_time_offset(peck, s2us(5)) to
add 5 seconds to the time and continue the test as if that time has
elapsed.
2023-11-09 12:47:06 +10:00
Peter Hutterer
34c83370be eis: fix a typo 2023-11-08 23:24:45 +00:00
Peter Hutterer
d31b5a1ccf eis: only queue a seat bind event if the caps change
This triggered an internal bug message in test_ei_seat_bind_unbind_immediately.

If a client unbinds all capabilities this triggers an EIS_SEAT_BIND with
zero caps. peck would call eis_seat_remove() which calls eis_seat_drop().
That queued another EIS_EVENT_SEAT_BIND with zero capabilities, leading
peck to call eis_seat_remove() again on an already removed seat.
2023-11-08 23:24:45 +00:00
Peter Hutterer
f558eedae2 util: add a global setup option to our munit wrapper
This allows us to handle/manipulate argv and/or pass a userdata to the
tests. Same ELF section approach as we already have with the MUNIT_TEST
macro but this time it's for a global setup.

Note that for the generated __start and __stop section variables we have
to have at least one entry in that section which we do with one
hardcoded (and ignored) one.
2023-10-24 18:25:25 +10:00
Peter Hutterer
6758b9970d util: add helper macros for the ELF section handling 2023-10-24 18:25:25 +10:00
Peter Hutterer
19c949a46b util: retry posix_fallocate() if it fails
We block SIGALRM since d4bf8840a4 so any
remaining EINTR is something we should probably retry with.
2023-10-24 18:25:25 +10:00
Peter Hutterer
a3c801097d util: don't check for EINTR on close()
See https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/261#note_2131802
2023-10-24 18:25:25 +10:00
Peter Hutterer
cdbd1d9eaf util: replace most of SIGALRM blocks with EINTR checks
SIGALRM *should* not really be an issue for us, most of our IO shouldn't
take long (posix_fallocate is the exception) so we can just retry it
instead of blocking someone's use of SIGALRM.

Doing it here mostly means that the rest of libei doesn't have to care
about EINTR, it'll just be handled transparently (just like before with
the SIGALRM blocks).
2023-10-24 18:25:25 +10:00
Peter Hutterer
5dcdc696fb ei: remove the source if we get disconnected
If we get disconnected there's no point sending anything anymore, the
server may have already closed the connection.

Otherwise this produces a confusing warning  in the log:

 18:37:31 | INFO | Disconnected by EIS
      ... | WARN | failed to send message: Broken pipe

See https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/262#note_2132619
2023-10-19 14:18:57 +10:00