With passive libei contexts receiving events sent by the EIS
implementation, the type of device changes significantly. While a
relative input device could still send data in logical pixels,
absolute devices may not have that luxury.
Best example here is an external tablet (think: Wacom Intuos): that
tablet has no built-in mapping to a screen and thus cannot capture input
events in logical pixels.
Address this by adding a device type, either virtual or physical.
In terms of functionality, the device's type decides:
- only virtual devices have regions
- only physical devices have a size
The event API remains as-is but the event data not represents either
logical pixels (virtual devices) or mm (physical device).
An EIS implementation connected to a passive libei context would likely
create:
- a virtual relative device (sending deltas in logical pixels)
- one or more physical absolute devices (sending deltas in mm)
Previously, a client could only bind to a capability immediately after
SEAT_ADDED and with a rather awkward API to confirm the capabilities.
Change this to allow for dynamic binding of capabilities, i.e. a client
calls ei_bind_capability() or ei_unbind_capability() whenever it feels
like, causing the respective devices of this capabilty to be added or
removed.
This allows for clients that are temporarily disinterested in a
capability but may require said capability later.
The default function takes one capability, a helper for enable/disable
multiple capabilities in one go is provided as well. On the protocol,
only the "bind" request exists which always represents the currently
wanted set of capabilities.
Note that the helper functions for multiple capabilities require NULL
(not zero) as sentinel, thanks to gcc.
This is a leftover from an earlier implementation that didn't get
removed in time. This extends to a macro that was using the context flag
(rather than the client flag) and in turn caused a bunch of false
positives on the tests.
A libei context can be initialized as active or passive context -
an "active" context sends events, a "passive" context receives events.
The EIS context supports both simultaneously, it is up to the
implementation to disconnect libei clients that it does not want to
suppport.
For example, the xdotool use-case creates an active libei context. The
EIS implementation controls and sets up the devices, but libei
sends the events.
In an input-capturing use-case, the EIS implementation controls
and sets up the devices **and** sends the events. libei is merely the
receiver for any event, it cannot send events. Thus this use-case
requires a passive libei context.
Most of this code is copy/paste with minor modifications - libei already
had the code to send events, libeis had the code to receive events, so
the vast majority of this patch is copying the code into the respective
other library, swap "ei" and "eis" and then apply the various minor
modifications needed to hook into the existing library.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
One macro that also defines the cleanup function, one macro that only
defines the unref. This is required for any place where we want to
use cleanup from multiple source files - like the test suite.
If we get EPROTO or EINVAL on the connection, all we do is disconnect
(ourselves or the client). So let's drain the fd so there's no other
data to be parsed by accident and then continue with actually
disconnecting.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
We will need eis_device_foo() for the actual event API soon, so let's
move the internal handlers out of the way by namespacing them.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Previous sequence reproducible with the eis-demo-server and
ei-demo-client:
- ctrl+c the client
- eis client dispatch fails with an rc < 0 due to the socket being closed
- eis calls eis_client_disconnect() which calls eis_seat_removed()
- that triggers an event for `SEAT_UNBIND`
- seat is set to REMOVE
- eis-demo-server gets the `SEAT_UNBIND` event and (correctly) calls
eis_seat_remove() since it doesn't know the client is disconnected
yet. That is due to the library unwinding the state transparently.
Fix this by splitting out the calls: eis_drop_seat() is the internally
used one that sets it to a new state of REMOVED_INTERNALLY, and then
eis_seat_remove merely updates the state.
Fixes#10
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
If we have libreis setting properties on the connection, this looks to
the server like they're coming from the ei connection. But libreis is a
different context than the libei context later, so when libei
initializes, it may set the same properties again. Since the libei
context doesn't know about the properties, it can't filter internally
and will send the properties to the server.
So we need to do all the permissions checks in the server to make sure
we don't overwrite values that we're not allowed to overwrite.
There are no real restrictions on changing properties from within the
eis implementation (other than not being able to set the reserved
namespaces).
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Pass the fd into the original context creation, then write any changes
to the wire immediately. For the capabilities that means we can't build
them up as before anymore, so change the API to have a vararg function
and require the allowed capabilities to be passed in.
There's likely little use for the previous allow-vs-deny policy etc, so
let's not make things more complicated an they have to be.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
There is data that libei and the EIS implementation will want to
exchange that is not covered by the immediate API.
To avoid having to add APIs for all of these, let's provide a generic
property API that both server and client can use to exchange this info.
The property API provides read/write/delete permissions but those only
apply to the client, not the server. The idea is that a server can
create (or restrict) properties that the client can read but not modify
and/or delete. A special-case are properties filled in automatically by
libei: ei.application.pid and ei.application.cmdline. These could be
used by e.g. the portal implementation to match permissions.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This allows us to transmit extra information about the client before the
server has to decide on whether it wants to connect us.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This effectively provides the EIS implementation with a notification
that the client will actually send events in the near future. To be used
by e.g. synergy-like clients when the pointer enters the logical screen
so that the EIS implementation can flash a warning or something.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This allows a client to trigger kinetic scrolling (or prevent it).
For compositors implementing EIS, the only realistic scroll source is
continuous which allows for scroll stop events. So let's give the client
the opportunity to trigger those on demand.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Already present in e.g. libinput and wayland, this event allows us to
group several events together to denote them as a logical group.
Required for multi-touch but as we've learned with Wayland it's also
required to group other events (scroll events in the case of Wayland).
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Since the server controls the keymap, and that keymap is likely merged
with some other device let's add the events so we notify the client of
things like numlock-is-down etc.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
There's nothing in the protocol to modify the client device state from
the server, so a pause/resume cycle must leave the client with the
same(-ish) state. Pause is really just that, a short "no event now
please". Anything that would require e.g. modifying the device state by
releasing keys or buttons should result in the device being removed and
re-added.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This is required for supporting synergy/barrier and similar clients.
Replacing the touch and pointer range we now have server-defined
rectangular regions that specify the active zones for this device.
For example, a dual-monitor EIS server would create two touch devices
with one region each for the respective monitors - libei-generated
touches would thus fall on the right area of the monitor. Or just one
device with one region if the second screen should be inaccessible.
A relative device may have multiple regions since it can reach all
screens in the layout.
This leaks the screen layout to libei but that is necessary for the
functionality to work. A libei client may need to control devices
through absolute coordinates and it needs to know where screen
transitions from one to the next screen happen:
+-----------++----------------+
| || |
| B||Q |
| |+----------------+
| |
| A|P
+-----------+
In the above example, position P is unreachable and a client that
controls input on both screens must know that it cannot transition from
A to P but it can transition from B to Q.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
If our client binds to a seat and then disconnects, insert an unbind
event in the EIS queue to unwind correctly.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This changes the protocol so that it is the EIS implementation that
creates devices within a seat.
A client now "binds" to a seat and the EIS implementation creates
devices matching the requested capabilities. A client can close a device
if it no longer wants those but otherwise everything (including pointer
ranges) is handled by the server.
This is one giant patch because changes at the protocol level cannot
easily be broken out into smaller patches. Some FIXMEs are left which
will be handled in follow-up patches, e.g. the keymap handling is
basically broken right now.
Fixes#7
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Removing a seat could cause two device remove events to happen. Fix this by
splitting the removal up into two bits: removed by server and removed by
client. Only once both bits are set, remove the device.
This needs to happen in libei and libeis.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
To cut down on the boilerplate, an unref-able struct variable can now be
declared as
_unref_(type) *name = NULL;
which is the equivalent of
_cleanup_(type_unrefp) struct type *name = NULL;
Let's see how that style ends up reading.
This means we can get rid of the custom _cleanup_foo_ functions everywhere, no
need for all the extra #defines etc. A somewhat special case is systemd which
defines the various unrefp functions for us in the headers, so we can use them
directly.
OBJECT_IMPLEMENT_UNREF now also creates the unrefp function for this object -
this of course conflicts where DECLARE_UNREF_CLEANUP_FUNC is in scope. Not a
problem so far, let's see how we go.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
After CONNECT, the EIS implementation needs to add one or more seats. The
libei client can only create devices within those seats. This mirrors the
wayland hierarchy as well as the X.Org one.
The seat has a set of allowed capabilities, so the client knows ahead of time
when it may not be possible to create a specific device.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Client-side the approach is a managed touch object rather than passing the
touchid around. This is intentional, it allows for a stackable API in the
future if we need to add things like pressure or major/minor to it.
On the server side the touches are managed through the event object anyway, so
we don't need the same abstraction there.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Because events may be in-transit when a client removes the device, we need to
make this a full roundtrip to the server. Otherwise the client may assume a
device is removed, releases all references and then gets the original device
added event for that device. Better to have this as a round-trip instead.
This requires the server to call eis_device_disconnect() on the removed
notifications but we do so during eis_event_unref() anyway in case the server
forgets.
And it changes some of the API behaviors, so adjust the tests for that.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This is the proto parser and it'll know when we need an fd on the message, so
let's make sure we have everything in place to fetch the fd.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>