A lot of the protocol tests have enforced timeouts because we need to
wait for the server to do something (or not). Running the protocol tests
with xdist means we can run those in parallel, which on my local box
roughly halves the time required to run all protocol tests.
Of course, this is all terrible. The only way to tell pytest to use
xdist is with `pytest -n <jobcount>`. But -n is only available if xdist
is installed. Dynamically adding commandline options is supposed to
be possible with `pytest_load_initial_conftests` in conftest.py, but
that doesn't actually work unless we're configuring a setuptool plugin.
Which we don't. What would work is `pytest_cmdline_preparse` but that
has been deprecated.
So we work around this by having meson check if xdist is available and
append `-n auto` for us.
In the CI let's be nice and only use the FDI_CI_CONCURRENT number of
jobs rather than hogging everything available. And, continuation from
"all is terrible": pytest complains if you have a hook that's unknown.
So if xdist is not available, you must not have the hook in conftest.py.
Which means we have to do it within an import + ImportError clause.
But yay, now we're saving literally seconds!
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.
Now that we have 64 bit integers on the wire and 64 bit object IDs,
we're already different to the Wayland protocol. So we might as well get
the full length and split message length and opcode again to make header
parsing and composing simpler.
This effectively reverts commit bf45a7182cb2f4c13f11e141fc846244d3ac6212.
Previously, we'd send one interface_version event for "ei_handshake"
immediately but all others after the client requests handshake.finish.
This was too confusing to document and not clear how it would work, so
let's make this simpler by splitting it up.
There is now a handshake_version event from the server, sent immediately
on connection that denotes the maximum version number for the interface.
And a handshake_version request from the client which must be the first
one by the client.
This tests the protocol layer which is hard to test using libei/libeis.
Similar to the generated C bindings we compile a eiproto.py file that is
then used in the test to talk protocol directly to the eis-demo-server
that we start up.
By sending the specific messages and checking things happen as we expect
on the socket we can verify that the EIS implementation is correct (and
robust enough).
In theory this could also be used to test some other binary with an EIS
implementation and the scaffolding is there to set LIBEI_TEST_SERVER to
that binary. Wether this works is untested though...
This protocol is wayland-like though it uses a slightly different
message format. The XML file uses the same structure, except for the
"fixed" type which is "float" here.
The scanner uses a jinja template to generate source and header files
for ei and eis which are now used instead of the protobuf-generated
objects. Note that the scanner is a minimal working version, some
features like enum value checks are not yet implemented.
Unlike wayland we do not need to generate the libwayland-like library,
we only need the wire protocol parser - some shortcuts can thus be taken.
To keep the changes simple, the protocol currently is a flat protocol
with only one interface and all messages copied over from the previous
ei.proto file. In future commits, this will be moved to the respective
interfaces instead.
The check is currently missing from a number of libeis APIs but in most
cases we can blame the EIS implementation and say "don't do this".
Device removal is an exception since that is still required.
With the planned switch to a protocol supporting multiple interfaces
(a la wayland), a single version number is no longer useful. Remove this
API, we can add something more specific later if we need to.
This makes it easier to correlate a particular input transaction
(whether there are events or not) with out-of-band information like the
planned portal InputCapture::Activated signal's "activation-id".
The primary use-case for these properties in libei itself was to send
some fixed information (pid, cmdline and conection type). In the portal
case, these can be obtained out-of-band via the portal. In the
non-portal case these can be obtained from the socket itself (fetch pid,
look up /proc/pid/cmdline) which is just as reliable as trusting
whatever libei sends.
The only other use-case for the properties was the activation id in the
InputCapture::Activated portal signal. This can be achieved with a
serial in the START_EMULATING event.
libreis was intended for an intermediary to set some information that
the libei client cannot be entrusted with. In particular this was the
application name, the allowed capabilities, and some properties that -
once set - the client could no longer change (appid as probably the only
really useful one). The price for this was a rather complicated version
negotiation dance before the initial CONNECT request.
Now that we have a clear view of what's going to happen -
RemoteDesktop.ConnectToEIS and the InputCapture portal - there is no
longer any need for libreis. The extra information that libreis would've
sent is communicated out-of-band in both portals and are known to the
compositor at the time the connection is being established.
So we can simply drop this, it's no longer required and dropping it
makes the protocol significantly simpler anyway.
The default behaviour of a peck context is to handle the CONNECT event.
Let's disable that.
No effect on the test, the client cannot receive the connect event until
it's been accepted, but it's better form anyway.
libei used to have direct portal support code (see the git history) but:
- that code was a custom proposed portal that never went anywhere
- libei has slowly changed to be more an input event transport layer since
it is now also used sending events *to* a libei context
- a number of libei users will never need the DBus code, either because they
don't want it or because they talk Dbus themselves na ddon't need this
abstraction.
Luckily, it's quite easy to move this into a separate library with a
simple API that does, effectively, the same trick as the old portal backend.
This API is aiming to be as simple as possible because the tools that
require anything more complex should talk to DBus directly.
An example tool that uses the API to retrieve an EIS fd over the
RemoteDesktop portal is included in this patch.
"Öffis" is a German word meaning public transport. It also sounds like the
French Œuf, the word for egg.
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Let the client set the version number it wants on Connect. There is new
public API to query the client/server's version as set once the connect
finished (eis_client_get_version() and ei_get_version()) but there is
currently no public API for the client to select the version it actually
wants, other than whatever both support. IOW, it's not possible for the
client to say "I want version 8 but if that's not supported, use version
5".
For all but the simplest loggers, the current approach of "this is a
continuation of the previous message" doesn't work well. The caller
cannot know whether the *current* message is complete until it receives
the next message - but that message may never come.
Drop this approach, if we need to compile multiple messages into one,
we can handle this internally and then pass it all as one message to the
caller.
The basic set of functions and macros to have access to a libreis
context for our to-be-client.
Since we connect the ei context to a backend during peck_new(), we need
a new function for the case where we do want to have libreis in the
mix.
All we do here is decide whether the connect event gets handled, clients
are always effectively connected (i.e. the client does send the connect
request) since we set up the backend during init.
Incoming device events are now added to a device-internal queue. Once
the frame event comes in, that queue is shuffled over to the main event
queue. For libei/the EIS implementation this means that device events
are seen only once the frame event appears from the sender (or it is
emulated by other means).