proto: replace pointer/keyboard/touchscreen with a generic "interface" event

Since these events are merely notifications of a single object, we can make
this more generic. This allows us to introduce future capabilities without
having to bump the seat.
This commit is contained in:
Peter Hutterer 2023-03-06 11:14:19 +10:00
parent 4b77664dc1
commit 5b1b5aec1a
7 changed files with 65 additions and 99 deletions

View file

@ -67,14 +67,14 @@ sequenceDiagram
EIS-->>client: ei_device.name(some name)
EIS-->>client: ei_device.device_type()
EIS-->>client: ei_device.capabilities(some name)
EIS-->>client: ei_device.pointer(new_id, version)
EIS-->>client: ei_device.keyboard(new_id, version)
EIS-->>client: ei_device.interface(new_id, "ei_pointer", version)
EIS-->>client: ei_device.interface(new_id, "ei_keyboard", version)
EIS-->>client: ei_seat.device(new_id, version)
EIS-->>client: ei_device.name(some name)
EIS-->>client: ei_device.device_type()
EIS-->>client: ei_device.capabilities(some name)
EIS-->>client: ei_device.region()
EIS-->>client: ei_device.touchscreen(new_id, version)
EIS-->>client: ei_device.interface(new_id, "ei_touchscreen", version)
EIS-->>client: ei_device.resume()
EIS-->>client: ei_device.resume()

View file

@ -13,6 +13,8 @@ In that protocol specification:
- an argument with an XML attribute `enum` carries a value of the corresponding enum
- an argument with an XML attribute `interface` attribute indicates that an object in the same message is
of that interface type
- an argument with an XML attribute `interface_arg` attribute indicates that an object in the same message is
of the interface given in the named argument.
- an enum with an XML attribute `bitfield` indicates a single-bit value.
- each request, event or enum has an XML attribute `since` to indicate the
interface version this request, event or enum was introduced in

View file

@ -28,6 +28,7 @@
<!ATTLIST arg type CDATA #REQUIRED>
<!ATTLIST arg summary CDATA #IMPLIED>
<!ATTLIST arg interface CDATA #IMPLIED>
<!ATTLIST arg interface_arg CDATA #IMPLIED>
<!ATTLIST arg allow-null CDATA #IMPLIED>
<!ATTLIST arg enum CDATA #IMPLIED>
<!ELEMENT description (#PCDATA)>

View file

@ -784,64 +784,28 @@
<arg name="scale" type="float" summary="the physical scale for this region"/>
</event>
<event name="pointer" since="1">
<description summary="device pointer interface notification">
Notification that a new device has a pointer interface.
<event name="interface" since="1">
<description summary="device capability notification">
Notification that a new device has a sub-interface.
This event is only sent if the device has the
ei_device.capabilities.pointer or
ei_device.capabilities.pointer_absolute capability.
This event may be sent for the
- "ei_pointer" interface if the device has the
ei_device.capabilities.pointer or
ei_device.capabilities.pointer_absolute capability.
- "ei_keyboard" interface if the device has the
ei_device.capabilities.keyboard capability
- "ei_touchscreen" interface if the device has the
ei_device.capabilities.touchscreen capability
This event is only sent if the client announced support for the
"ei_pointer" interface in ei_handshake.interface_version.
The interface version is equal or less to the client-supported
version in ei_handshake.interface_version for the "ei_pointer"
interface.
version in ei_handshake.interface_version for the respective interface.
This event is optional and sent immediately after object creation.
This event is optional and sent immediately after object creation
and at most once per interface.
It is a protocol violation to send this event after the ei_device.done event.
</description>
<arg name="pointer" type="new_id" interface="ei_pointer"/>
<arg name="version" type="uint32" summary="the interface version"/>
</event>
<event name="keyboard" since="1">
<description summary="device pointer interface notification">
Notification that a new device has a keyboard interface.
This event is only sent if the device has the
ei_device.capabilities.keyboard.
This event is only sent if the client announced support for the
"ei_keyboard" interface in ei_handshake.interface_version.
The interface version is equal or less to the client-supported
version in ei_handshake.interface_version for the "ei_keyboard"
interface.
This event is optional and sent immediately after object creation.
It is a protocol violation to send this event after the ei_device.done event.
</description>
<arg name="keyboard" type="new_id" interface="ei_keyboard"/>
<arg name="version" type="uint32" summary="the interface version"/>
</event>
<event name="touchscreen" since="1">
<description summary="device touchscreen interface notification">
Notification that a new device has a touchscreen interface.
This event is only sent if the device has the
ei_device.capabilities.touchscreen.
This event is only sent if the client announced support for the
"ei_touchscreen" interface in ei_handshake.interface_version.
The interface version is equal or less to the client-supported
version in ei_handshake.interface_version for the "ei_touchscreen"
interface.
This event is optional and sent immediately after object creation.
It is a protocol violation to send this event after the ei_device.done event.
</description>
<arg name="touchscreen" type="new_id" interface="ei_touchscreen"/>
<arg name="object" type="new_id" interface_arg="interface_name" />
<arg name="interface_name" type="string" summary="the interface name" />
<arg name="version" type="uint32" summary="the interface version"/>
</event>

View file

@ -388,44 +388,32 @@ handle_msg_frame(struct ei_device *device, uint32_t serial, uint64_t time)
}
static struct brei_result *
handle_msg_pointer(struct ei_device *device, object_id_t id, uint32_t version)
handle_msg_interface(struct ei_device *device, object_id_t id, const char *name,
uint32_t version)
{
DISCONNECT_IF_INVALID_ID(device, id);
if (device->pointer)
if (streq(name, "ei_pointer")) {
if (device->pointer)
return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Duplicate ei_pointer interface object on device");
device->pointer = ei_pointer_new(device, id, version);
} else if (streq(name, "ei_keyboard")) {
if (device->keyboard)
return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Duplicate ei_keyboard interface object on device");
device->keyboard = ei_keyboard_new(device, id, version);
} else if (streq(name, "ei_touchscreen")) {
if (device->touchscreen)
return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Duplicate ei_touchscreen interface object on device");
device->touchscreen = ei_touchscreen_new(device, id, version);
} else {
return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Duplicate ei_pointer interface object on device");
device->pointer = ei_pointer_new(device, id, version);
return NULL;
}
static struct brei_result *
handle_msg_keyboard(struct ei_device *device, object_id_t id, uint32_t version)
{
DISCONNECT_IF_INVALID_ID(device, id);
if (device->keyboard)
return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Duplicate ei_keyboard interface object on device");
device->keyboard = ei_keyboard_new(device, id, version);
return NULL;
}
static struct brei_result *
handle_msg_touchscreen(struct ei_device *device, object_id_t id, uint32_t version)
{
DISCONNECT_IF_INVALID_ID(device, id);
if (device->touchscreen)
return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Duplicate ei_touchscreen interface object on device");
device->touchscreen = ei_touchscreen_new(device, id, version);
"Unsupported interface '%s' on device", name);
}
return NULL;
}
@ -442,9 +430,7 @@ static const struct ei_device_interface interface = {
.start_emulating = handle_msg_start_emulating,
.stop_emulating = handle_msg_stop_emulating,
.frame = handle_msg_frame,
.pointer = handle_msg_pointer,
.keyboard = handle_msg_keyboard,
.touchscreen = handle_msg_touchscreen,
.interface = handle_msg_interface,
};
const struct ei_device_interface *

View file

@ -765,15 +765,15 @@ eis_device_add(struct eis_device *device)
if (eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER) ||
eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
device->pointer = eis_pointer_new(device);
rc = eis_device_event_pointer(device, eis_pointer_get_id(device->pointer),
eis_pointer_get_version(device->pointer));
rc = eis_device_event_interface(device, eis_pointer_get_id(device->pointer),
"ei_pointer", eis_pointer_get_version(device->pointer));
if (rc < 0)
goto out;
}
if (eis_device_has_capability(device, EIS_DEVICE_CAP_KEYBOARD)) {
device->keyboard = eis_keyboard_new(device);
rc = eis_device_event_keyboard(device, eis_keyboard_get_id(device->keyboard),
eis_keyboard_get_version(device->keyboard));
rc = eis_device_event_interface(device, eis_keyboard_get_id(device->keyboard),
"ei_keyboard", eis_keyboard_get_version(device->keyboard));
if (rc < 0)
goto out;
@ -785,8 +785,8 @@ eis_device_add(struct eis_device *device)
}
if (eis_device_has_capability(device, EIS_DEVICE_CAP_TOUCH)) {
device->touchscreen = eis_touchscreen_new(device);
rc = eis_device_event_touchscreen(device, eis_touchscreen_get_id(device->touchscreen),
eis_touchscreen_get_version(device->touchscreen));
rc = eis_device_event_interface(device, eis_touchscreen_get_id(device->touchscreen),
"ei_touchscreen", eis_touchscreen_get_version(device->touchscreen));
if (rc < 0)
goto out;
}

View file

@ -232,6 +232,14 @@ class Interface:
def connect(self, event: str, callback: Callable):
self.callbacks[event] = callback
@classmethod
def lookup(cls, name: str) -> "Interface":
return {
{% for interface in interfaces %}
"{{interface.name}}": {{interface.camel_name}},
{% endfor %}
}[name]
{% for interface in interfaces %}
@attr.s
@ -256,8 +264,13 @@ class {{interface.camel_name}}(Interface):
new_objects = {
{% for arg in incoming.arguments %}
{% if arg.signature == "n" %}
{# Note: this only works while the version argument is always called version #}
{% if arg.interface %}
{# Note: this only works while the version argument is always called version #}
"{{arg.name}}": {{arg.interface.camel_name}}.create({{arg.name}}, version),
{% else %}
{# Note: this only works while the argument is called interface_name #}
"{{arg.name}}": Interface.lookup(interface_name).create({{arg.name}}, version),
{% endif %}
{% endif %}
{% endfor %}
}