Commit graph

78 commits

Author SHA1 Message Date
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
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
Peter Hutterer
db786c7822 protocol: add a ei_connection_setup interface
This replaces the connect/connect_done and version/get_version requests.
Immediately after connecting, the server sends an ei_protocol_setup
event to the client with the ID of the object and the server's highest
supported version number (of this object).

This is a one-shot object that the client can use to configure its name
and whether it is a sender or receiver context. Once .done is sent, the
object is discarded.

The server version is sent along to the client to allow for requests to
be added to this object in the future.

As a fixme left: the client now assumes to be connected as soon as the
.done request is sent and the following sync event is received. The
EIS implementation will not have actually eis_client_connect()ed the
client yet, but it's good enough for now.

Arguably, the CONNECTED event is superfluous anyway since *any* event
other than DISCONNECTED indicates connected status. CONNECTED is a
leftover from when the client created devices and needed to know if it's
worth doing so.
2023-03-03 11:20:42 +10:00
Peter Hutterer
9cbce95326 protocol: add a sync request and the ei_callback interface
Directly copied from wayland. Note that while the wayland protocol
specifies the data is the last event serial in our case here it's just
0 since we don't have any event serials (yet).

The sync request is currently triggered after connection, merely to
ensure it works, it's not actually needed.
2023-03-03 11:20:42 +10:00
Peter Hutterer
d0e6c251b6 protocol: rename the ei core interface to ei_connection
In the protocol this is a simple rename but in the implementation we can
now separate the protocol object out from the ei/ei-client context
itself by having the ei_connection objects.
2023-03-03 11:20:42 +10:00
Peter Hutterer
b02b4f0901 Drop protobuf in favour of a custom protocol
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.
2023-03-03 11:20:42 +10:00
Peter Hutterer
e3c34830db ei: rename ei_set_connection to ei_set_socket
Current plans are to use the "connection" term for the ei_connection
interface in the (future) protocol, so let's rename this to avoid
clashes.
2023-03-03 11:20:42 +10:00
Peter Hutterer
8973101313 ei: divide the headers up across multiple files
libei-private.h was getting unwieldly, so let's split this up so
(most) anything ei_foo goes into libei-foo.h.
2023-02-13 14:01:08 +10:00
Peter Hutterer
d1282b3681 Add some extra getters for the context and the eis_client
These are all noops but this way we can ensure that get_context() and
get_client works on all objects - useful for (upcoming) generated code.
2023-02-13 14:00:19 +10:00
Peter Hutterer
ff9830c122 Add a sequence number to START_EMULATING
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".
2023-02-09 11:48:29 +10:00
Peter Hutterer
a5cc87c837 Purge the properties from the protocol
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.
2023-02-09 11:48:29 +10:00
Peter Hutterer
5535692ee0 proto: allow the client to set the protocol version
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".
2022-09-07 09:42:59 +10:00
Peter Hutterer
08a4ce4aac proto: add a version exchange prior to connect
Add a new protocol message "GetVersion" and the matching reply from the
server with "Version" that can be sent at any time. The server always
replies with the highest protocol version it supports, allowing the
client to choose the protocol version it wants.

These two messages also have a fixed string to make the protocol easy to
identify in hexdumps.

To avoid roundtrips on connection, libeis immediately sends the Version
message. Ideally and by the time the client actually starts, that
version is already available and we can continue without requiring a
full roundtrip.

This patch only adds the version exchange with the server, it does not
yet add the bits for the client to actually set the version.
2022-09-07 09:30:39 +10:00
Peter Hutterer
48bf74a5b9 Add a pending event queue for incoming device events
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).
2022-05-17 15:31:20 +10:00
Peter Hutterer
8e95e8994b ei: expose ei_event_get_context() internally 2022-05-17 15:31:20 +10:00
Peter Hutterer
d99e42b808 Add timestamps to frame events
Currently only implemented for frame events, the vague plan for the
future is to merely queue the device events internally and "release"
them once a frame event was received, retrofitting the timestamp to the
C event struct (i.e. making ei_event_get_time() available on all device
events).

Meanwhile, the frame event it is.
2022-05-17 07:18:41 +10:00
Peter Hutterer
f0605b5e53 Add a filter for empty frames on the receiver side 2022-05-05 13:41:36 +10:00
Peter Hutterer
a4dde7c35f Filter empty frame events
We only need frame events after device events (pointer, touch,
keyboard). In some cases, the library prevents an event from being
written to the wire, e.g. if the coordinates are out of region, but the
client will still call ei_device_frame() for that now-filtered event.

Keep a boolean to remember if we have sent something that requires a
frame event and filter accordingly.

Note that this currently filters the *sender* side only, not the
receiver side. A sender that gets an empty frame event onto the wire
will still get that into the other side.

This also doesn't handle the flushing of frame events before other
events, ideally we should enforce a frame event before e.g. stop
emulating.
2022-04-29 11:38:07 +10:00
Peter Hutterer
f35be22d2c Rename ei active/passive to sender/receiver
This is more explicit in what it actually does, making it easier to
immediately understand the code.
2022-04-04 15:42:27 +10:00
Peter Hutterer
fa091d7ac4 Differentiate between physical and virtual devices
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)
2022-04-04 05:28:36 +00:00
Peter Hutterer
9d85b1289d Change to allow dynamic binding of capabilities
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.
2022-04-04 05:24:16 +00:00
Peter Hutterer
541dcb415d ei: require the client to confirm capabilities rather than drop them
Our API requires a client to know which capability to pass into the
drop_capabilities function. This doesn't work for capabilities newer
than the client's version so they do not get disabled. The client will
thus receive devices it didn't ask for and doesn't know how to handle.

Let's invert the requirement and require the caller to confirm the
capabilities it wants - all others are dropped.

This is an API break but also requires updates of all clients, the
previous simple case of just calling ei_seat_bind() will now result in
zero capabilities.
2022-03-07 11:02:35 +10:00
Peter Hutterer
faa9500afe Add concept of active/passive libei contexts
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>
2022-03-04 14:04:33 +10:00
Peter Hutterer
46681e2855 Add SPDX identifiers to all source files
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-03-03 00:27:36 +00:00
Peter Hutterer
bbbf2ff0f2 ei: add a helper function to create an event from a device
Just cuts down on duplication/room for error

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2022-02-28 02:23:40 +00:00
Peter Hutterer
1225bcb0e1 Add a property API for generic key/value exchanges
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>
2021-08-25 13:35:36 +10:00
Peter Hutterer
a03f547989 proto: add a start/stop emulating message pair
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>
2021-08-24 13:14:20 +10:00
Peter Hutterer
1884785a8a Add a scroll stop/cancel event
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>
2021-08-24 09:21:05 +10:00
Peter Hutterer
55594cd09c Add a frame event to logically group events together
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>
2021-08-24 09:21:05 +10:00
Peter Hutterer
6f70e97cce Implement key modifier mask events similar to Wayland
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>
2021-08-23 15:03:15 +10:00
Peter Hutterer
b08ec3cea4 ei: split event handling into its own source file
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-08-23 12:26:07 +10:00
Peter Hutterer
e247ffe824 ei: remove non-existing ei_client reference
Copy/paste-o from the EIS bits

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-08-23 12:26:07 +10:00
Peter Hutterer
fa7b624f93 Rename suspend to pause to indicate it's a "lighter" form of suspending
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>
2021-08-23 08:34:44 +10:00
Peter Hutterer
0991660820 Add user data to keymaps
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-08-12 15:39:26 +10:00
Peter Hutterer
e3fd50bae7 ei: abstract the requests into an interface struct too
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-08-11 11:06:07 +10:00
Peter Hutterer
3abf13742a Restructure keymap handling to server-side only
This keeps most of the current structure but gets rid of client-side
keymaps (which have been broken since the server-side devices anyway).
The new approach: clients get a keymap (or NULL) from the server, if
they don't like it they will have to do transformation on their side.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-08-11 09:29:55 +10:00
Peter Hutterer
15316dd2ab Add two convenience methods for region point conversion
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-07-26 15:45:08 +10:00
Peter Hutterer
6095a0d99f Add a physical scale factor for the regions
This isn't something that libei itself uses but clients like synergy
need to know about this to be able to map relative pointer motion from
one host into the right physical pixel on another host.

This is required for mutter in the x11-compat mode where a 4k screen is
logically twice the size of a 2k screen, despite having the same
physical size.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-07-23 15:06:01 +10:00
Peter Hutterer
56b82c2b8f Add DeviceRegions to replace the pointer/touch ranges
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>
2021-07-23 15:06:01 +10:00
Peter Hutterer
12b04fdeb0 Add a DeviceAddedDone message to the protocol
Similar to wayland's done message, this signals the end of the device
configuration.

Signed-off-by:	Peter Hutterer <peter.hutterer@who-t.net>
2021-07-23 14:26:38 +10:00
Peter Hutterer
c0f9e40282 Pass the file/line/func information through to the ei/eis loggers
This is useful for debugging, let's pass it through and let the log
handler decide whether to use it or not.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-07-22 13:09:39 +10:00
Peter Hutterer
3e66c87e81 ei: make the device refcounting a bit easier to follow
Once a device is removed, it is moved to the seat's devices_removed
list and the seat's ref is dropped - meaning the seat no longer keeps
the device alive. Once the caller's refcounts drop, the device can be
destroyed.

The device still keeps the seat alive though through a ref.

Signed-off-by:	Peter Hutterer <peter.hutterer@who-t.net>
2021-07-21 11:02:54 +10:00
Peter Hutterer
2bb846696f Change to use server-created devices
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>
2021-07-21 11:02:54 +10:00
David Redondo
27e7823029 Implement support for scroll events
The interfaces were declared on both client and server  side but not
implemented.

Signed-off-by: David Redondo <kde@david-redondo.de>
2021-07-16 08:40:07 +02:00
Peter Hutterer
c317de742b libei: immediately remove devices added for a removed seat
Once the SEAT_REMOVED event has been processed, adding new devices is
pointless. But we do promise a DEVICE_REMOVED event for any device added with
ei_device_add(), so let's immediately queue an event and mark the device as
dead.

Since the SEAT_REMOVED event may still be pending in the queue (i.e. not yet
read by the client), we need to prepend the event to the queue. Note that
client that immediately add a device when a device is removed will cause
an infinite loop.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-10-29 14:10:47 +10:00
Peter Hutterer
eef9c51df3 libei: fix the device/seat ref handling once again
Previously we didn't always clean up properly, especially where unexpected
removals happened. So the new approach is:
- the device always has a ref to the seat, we must not remove the seat until
  even not-yet-added devices are released
- the seat has a ref to the device *after* it was added. this is a circular
  ref so we need to make sure the device is manually removed from the seat
  so we can actually reach a refcount 1

This is made slightly more complicated by us calling ei_disconnect() whenever
we fail to write on the fd. The result is re-entrant functions that we need to
protect against inadvertent changes. The best option here is probably to mark
the context as degraded and clean up once we finished whatever we were really
doing - that's a larger rework though.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-10-29 11:28:29 +10:00
Peter Hutterer
683ff5cca0 Fix double device removal
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>
2020-10-27 11:35:06 +10:00
Peter Hutterer
ff6633db97 libei: Improve function namespacing
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-10-21 10:47:47 +10:00
Peter Hutterer
93b96e42ad Add an EIS-controlled seat to the hierarchy
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>
2020-10-21 10:47:47 +10:00