mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-02-05 00:40:28 +01:00
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.
This commit is contained in:
parent
49c329e0de
commit
b02b4f0901
20 changed files with 1602 additions and 515 deletions
|
|
@ -15,7 +15,7 @@ tab_width = 4
|
|||
indent_style = space
|
||||
tab_width = 4
|
||||
|
||||
[*.{c,h}]
|
||||
[*.{c,h,tmpl}]
|
||||
indent_style = tab
|
||||
tab_width = 8
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ indent_style = space
|
|||
indent_size = 4
|
||||
charset = utf-8
|
||||
|
||||
[*.{yaml,yml,tmpl}]
|
||||
[*.{yaml,yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
|
|
|
|||
|
|
@ -32,14 +32,14 @@ variables:
|
|||
# See the documentation here: #
|
||||
# https://wayland.freedesktop.org/libinput/doc/latest/building_libinput.html #
|
||||
###############################################################################
|
||||
FEDORA_PACKAGES: 'git diffutils gcc gcc-c++ pkgconf-pkg-config meson systemd-devel protobuf-c-devel libxkbcommon-devel doxygen python3-attrs python3-pytest python3-dbusmock '
|
||||
FEDORA_PACKAGES: 'git diffutils gcc gcc-c++ pkgconf-pkg-config meson systemd-devel libxkbcommon-devel doxygen python3-attrs python3-pytest python3-dbusmock python3-jinja2 '
|
||||
############################ end of package lists #############################
|
||||
|
||||
# these tags should be updated each time the list of packages is updated
|
||||
# changing these will force rebuilding the associated image
|
||||
# Note: these tags have no meaning and are not tied to a particular
|
||||
# libinput version
|
||||
FEDORA_TAG: '2022-12-05.1'
|
||||
FEDORA_TAG: '2023-02-02.0'
|
||||
|
||||
FDO_UPSTREAM_REPO: libinput/libei
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
|
||||
# We're happy to rebuild all containers when one changes.
|
||||
.default_tag: &default_tag '2022-12-05.1'
|
||||
.default_tag: &default_tag '2023-02-02.0'
|
||||
|
||||
distributions:
|
||||
- name: fedora
|
||||
|
|
@ -19,12 +19,12 @@ distributions:
|
|||
- pkgconf-pkg-config
|
||||
- meson
|
||||
- systemd-devel
|
||||
- protobuf-c-devel
|
||||
- libxkbcommon-devel
|
||||
- doxygen
|
||||
- python3-attrs
|
||||
- python3-pytest
|
||||
- python3-dbusmock
|
||||
- python3-jinja2
|
||||
|
||||
pages:
|
||||
distro: fedora
|
||||
|
|
|
|||
13
meson.build
13
meson.build
|
|
@ -79,15 +79,14 @@ src_libei = files(
|
|||
'src/libei-event.c',
|
||||
'src/libei-fd.c',
|
||||
'src/libei-log.c',
|
||||
'src/libei-proto.c',
|
||||
'src/libei-region.c',
|
||||
'src/libei-region.c',
|
||||
'src/libei-seat.c',
|
||||
'src/libei-socket.c',
|
||||
) + [proto_headers]
|
||||
) + [ei_proto_headers, ei_proto_sources]
|
||||
|
||||
deps_libei = [
|
||||
dep_libutil,
|
||||
dep_protobuf,
|
||||
]
|
||||
|
||||
lib_libei = shared_library('ei',
|
||||
|
|
@ -95,6 +94,7 @@ lib_libei = shared_library('ei',
|
|||
dependencies: deps_libei,
|
||||
include_directories: [inc_proto],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
include_directories: ['src'],
|
||||
install: true
|
||||
)
|
||||
install_headers('src/libei.h')
|
||||
|
|
@ -122,16 +122,15 @@ src_libeis = files(
|
|||
'src/libeis-event.c',
|
||||
'src/libeis-fd.c',
|
||||
'src/libeis-log.c',
|
||||
'src/libeis-proto.c',
|
||||
'src/libeis-region.c',
|
||||
'src/libeis-seat.c',
|
||||
'src/libeis-socket.c',
|
||||
) + [proto_headers]
|
||||
) + [eis_proto_headers, eis_proto_sources]
|
||||
|
||||
lib_libeis = shared_library('eis',
|
||||
src_libeis,
|
||||
dependencies: [dep_libutil, dep_protobuf],
|
||||
include_directories: [inc_proto],
|
||||
dependencies: [dep_libutil],
|
||||
include_directories: [inc_proto, inc_src],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
install: true
|
||||
)
|
||||
|
|
|
|||
137
proto/ei-proto.c.tmpl
Normal file
137
proto/ei-proto.c.tmpl
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* GENERATED FILE, DO NOT EDIT
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
{#- this is a jinja template, warning above is for the generated file
|
||||
|
||||
Non-obvious variables set by the scanner that are used in this template:
|
||||
- target: because eis is actually eis_client in the code, the target points to
|
||||
either "ei" or "eis_client". The various attributes on target resolve
|
||||
accordingly.
|
||||
- request.fqdn/event.fqdn - the full name of a request/event with the
|
||||
interface name prefixed, "ei_foo_request_bar" or "ei_foo_event_bar"
|
||||
- incoming/outgoing: points to the list of requests or events, depending
|
||||
which one is the outgoing one from the perspective of the file we're
|
||||
generating (ei or eis)
|
||||
#}
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include "brei-shared.h"
|
||||
|
||||
{% if headerfile %}
|
||||
#include "{{headerfile}}"
|
||||
{% endif %}
|
||||
|
||||
/**
|
||||
* Forward declarations. This file is intended to be compile-able without including
|
||||
* any of the actual implementation files.
|
||||
*/
|
||||
struct {{target.name}};
|
||||
|
||||
/**
|
||||
* The function that converts the given arguments into a wire format and sends it.
|
||||
* This function must be provided by the implementation, it is called by all
|
||||
* message sending functions (requests for libei, events for libeis).
|
||||
*/
|
||||
extern int {{target.name}}_send_message(
|
||||
{{target.as_arg}}, uint32_t object_id, uint32_t opcode,
|
||||
const char *signature, size_t nargs, ...
|
||||
);
|
||||
|
||||
{% for interface in interfaces %}
|
||||
/***************************************************************************
|
||||
* Interface: {{interface.name.ljust(60)}} *
|
||||
***************************************************************************/
|
||||
|
||||
/* returns the protocol interface from the given struct, see the dispatcher */
|
||||
const struct {{interface.name}}_interface *{{target.name}}_get_interface({{target.as_arg}});
|
||||
|
||||
/* returns the message sending context from the given struct */
|
||||
{{target.ctype}} {{target.name}}_get_{{target.context}}({{target.as_arg}});
|
||||
|
||||
/* Returns the protocol object id from the given struct */
|
||||
const struct brei_object *
|
||||
{{target.name}}_get_proto_object({{target.as_arg}});
|
||||
|
||||
/* request opcodes */
|
||||
{% for request in interface.requests %}
|
||||
#define {{request.fqdn.upper().ljust(45)}} {{request.opcode}}
|
||||
{% endfor %}
|
||||
|
||||
/* event opcodes */
|
||||
{% for event in interface.events %}
|
||||
#define {{event.fqdn.upper().ljust(45)}} {{event.opcode}}
|
||||
{% endfor %}
|
||||
|
||||
/* Message sender functions */
|
||||
{% for outgoing in interface.outgoing %}
|
||||
int
|
||||
{{outgoing.fqdn}}({{target.as_arg}}{%- for arg in outgoing.arguments %}, {{arg.as_arg}}{% endfor %})
|
||||
{
|
||||
const struct brei_object *obj = {{target.name}}_get_proto_object({{target.name}});
|
||||
{{target.ctype}} ctx = {{target.name}}_get_{{target.context}}({{target.name}});
|
||||
return {{target.name}}_send_message(
|
||||
ctx, obj->id, {{outgoing.fqdn.upper()}}, "{{outgoing.signature}}",
|
||||
{{outgoing.arguments|length}}{%- for arg in outgoing.arguments %}, {{arg.name}}{% endfor -%}
|
||||
);
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
/**
|
||||
* The dispatcher for the {{interface.name}} interface is the function called by
|
||||
* brei with the messages parsed from the wire.
|
||||
*/
|
||||
static int
|
||||
{{interface.name}}_dispatcher(
|
||||
{{target.as_arg}},
|
||||
uint32_t opcode,
|
||||
size_t nargs,
|
||||
union brei_arg *args
|
||||
) {
|
||||
{% if interface.incoming|length %}
|
||||
const struct {{interface.name}}_interface *interface = {{target.name}}_get_interface({{target.name}});
|
||||
switch (opcode) {
|
||||
{% for incoming in interface.incoming %}
|
||||
case {{incoming.fqdn.upper()}}:
|
||||
assert(interface->{{incoming.name}} != NULL);
|
||||
return interface->{{incoming.name}}({{target.name}}{% for arg in incoming.arguments %}, (args + {{loop.index - 1}})->{{arg.argtype}}{% endfor %});
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct brei_message {{interface.name}}_requests[] = {
|
||||
{% for request in interface.requests %}
|
||||
{ "{{request.name}}", "{{request.signature}}" },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
static const struct brei_message {{interface.name}}_events[] = {
|
||||
{% for event in interface.events %}
|
||||
{ "{{event.name}}", "{{event.signature}}" },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
static const struct brei_message {{interface.name}}_incoming[] = {
|
||||
{% for msg in interface.incoming %}
|
||||
{ "{{msg.name}}", "{{msg.signature}}" },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
const struct brei_interface {{interface.name}}_proto_interface = {
|
||||
.name = "{{interface.name}}", .version = {{interface.version}},
|
||||
.nrequests = {{interface.requests|length}}, .requests = {{interface.name}}_requests,
|
||||
.nevents = {{interface.events|length}}, .events = {{interface.name}}_events,
|
||||
.nincoming = {{interface.incoming|length}}, .incoming = {{interface.name}}_incoming,
|
||||
.dispatcher = (brei_event_dispatcher){{interface.name}}_dispatcher,
|
||||
};
|
||||
|
||||
{% endfor %}
|
||||
|
||||
88
proto/ei-proto.h.tmpl
Normal file
88
proto/ei-proto.h.tmpl
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* GENERATED FILE, DO NOT EDIT
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
{# this is a jinja template, warning above is for the generated file
|
||||
|
||||
Non-obvious variables set by the scanner that are used in this template:
|
||||
- target: because eis is actually eis_client in the code, the target points to
|
||||
either "ei" or "eis_client"
|
||||
- request.fqdn/event.fqdn - the full name of a request/event with the
|
||||
interface name prefixed, "ei_foo_request_bar" or "ei_foo_event_bar"
|
||||
- incoming/outgoing: points to the list of requests or events, depending
|
||||
which one is the outgoing one from the perspective of the file we're
|
||||
generating (ei or eis)
|
||||
#}
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Forward declarations. This file is intended to be compile-able without including
|
||||
* any of the actual sources files.
|
||||
*/
|
||||
|
||||
typedef uint32_t new_id_t;
|
||||
typedef uint32_t object_id_t;
|
||||
|
||||
struct {{target.name}};
|
||||
|
||||
/* Interface declarations */
|
||||
{% for interface in interfaces %}
|
||||
struct {{interface.name}};
|
||||
{% endfor %}
|
||||
|
||||
{% for interface in interfaces %}
|
||||
extern const struct brei_interface {{interface.name}}_proto_interface;
|
||||
{% endfor %}
|
||||
|
||||
{% for interface in interfaces %}
|
||||
|
||||
/** {{interface.name}} **/
|
||||
|
||||
{% for request in interface.requests %}
|
||||
#define {{request.fqdn.upper()}}_SINCE_VERSION {{request.since}}
|
||||
{% endfor %}
|
||||
|
||||
{% for event in interface.events %}
|
||||
#define {{event.fqdn.upper()}}_SINCE_VERSION {{event.since}}
|
||||
{% endfor %}
|
||||
|
||||
{% for enum in interface.enums %}
|
||||
enum {{enum.fqdn}} {
|
||||
{% for entry in enum.entries %}
|
||||
{{enum.fqdn.upper()}}_{{entry.name.upper()}} = {{entry.value}},
|
||||
{% endfor %}
|
||||
};
|
||||
{% endfor %}
|
||||
|
||||
/* Message sender functions */
|
||||
{% for outgoing in interface.outgoing %}
|
||||
extern int
|
||||
{{outgoing.fqdn}}({{target.as_arg}}{%- for arg in outgoing.arguments %}, {{arg.as_arg}}{% endfor %});
|
||||
|
||||
{% endfor %}
|
||||
|
||||
/**
|
||||
* Interface to handle incoming messages for objects of type {{interface.name}}.
|
||||
*
|
||||
* After parsing the wire message, the data is dispatched into the functions below.
|
||||
*/
|
||||
struct {{interface.name}}_interface {
|
||||
{% for incoming in interface.incoming %}
|
||||
int (*{{incoming.name}})({{target.as_arg}}{%- for arg in incoming.arguments %}, {{arg.as_arg}}{% endfor %});
|
||||
{% endfor %}
|
||||
};
|
||||
{% endfor %}
|
||||
|
||||
#ifdef _cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
292
proto/ei.proto
292
proto/ei.proto
|
|
@ -1,292 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
/**
|
||||
* EI Protocol Specification
|
||||
*
|
||||
* This protocol is an internal implementation detail and subject to change
|
||||
* at any time. This specification is for developers of libei only.
|
||||
*
|
||||
* ClientMessage → sent from the client to the server
|
||||
* ServerMessage → sent from the server to the client
|
||||
*
|
||||
* A normal sequence consists of:
|
||||
* [1. - client establishes connection to server
|
||||
* 2. - client sends "Connect"
|
||||
* 2.a - server replies with "Connected" or
|
||||
* 2.b - server replies with "Disconnected" and closes its end of the socket
|
||||
* 3. - server sends "AddSeat" (once or multiple times)
|
||||
* 4. - client sends "BindSeat" for each seat
|
||||
* 5. - server sends "DeviceAdded" for any device on this seat
|
||||
* 6. - server sends "DeviceResumed"
|
||||
* 7. - client sends "StartEmulating" to notify the server emulation starts
|
||||
* 8. - client sends "PointerRelative" or any other event
|
||||
* 9. - client sends "StopEmulating" to notify the server emulation starts
|
||||
* 10. - client sends "CloseDevice"
|
||||
* 11. - client sends "Disconnect" and closes its end of the socket
|
||||
*
|
||||
* The server may send Disconnect at any time.
|
||||
* The server may send SeatRemoved for a device at any time.
|
||||
* The server may send DeviceSuspended for any currently resumed device at any time.
|
||||
* The server may send DeviceRemoved for a device at any time.
|
||||
*
|
||||
* Where a connection error occurs, the library (libei or libeis) will
|
||||
* unroll the state as seen from the API.
|
||||
*/
|
||||
|
||||
/* Request the server version. This request MAY be sent at any time and/or
|
||||
* multiple times and the server always replies with the server's highest
|
||||
* supported version, see Version.
|
||||
*
|
||||
* To avoid roundtrips during the initial connection, an EIS implementation
|
||||
* *SHOULD* send a Version message immediately. A client thus may not need to
|
||||
* request the version.
|
||||
*
|
||||
* The "ei" field is the constant string "EI" and helps identifying
|
||||
* this connection in debugging tools.
|
||||
*/
|
||||
message GetVersion {
|
||||
string ei = 1; /* always "EI" */
|
||||
}
|
||||
|
||||
message Connect {
|
||||
fixed32 version = 1; /* Must be equal or less to the server's GetVersion response */
|
||||
string name = 2;
|
||||
bool is_sender = 3;
|
||||
}
|
||||
|
||||
message ConnectDone {
|
||||
}
|
||||
|
||||
message Disconnect {
|
||||
}
|
||||
|
||||
message BindSeat {
|
||||
fixed32 seatid = 1;
|
||||
fixed32 capabilities = 2;
|
||||
}
|
||||
|
||||
message CloseDevice {
|
||||
fixed32 deviceid = 1;
|
||||
}
|
||||
|
||||
message PointerRelative {
|
||||
fixed32 deviceid = 1;
|
||||
double x = 2;
|
||||
double y = 3;
|
||||
}
|
||||
|
||||
message PointerAbsolute {
|
||||
fixed32 deviceid = 1;
|
||||
double x = 2;
|
||||
double y = 3;
|
||||
}
|
||||
|
||||
message PointerScroll {
|
||||
fixed32 deviceid = 1;
|
||||
double x = 2;
|
||||
double y = 3;
|
||||
}
|
||||
|
||||
message PointerScrollDiscrete {
|
||||
fixed32 deviceid = 1;
|
||||
double x = 2;
|
||||
double y = 3;
|
||||
}
|
||||
|
||||
message PointerScrollStop {
|
||||
fixed32 deviceid = 1;
|
||||
bool x = 2;
|
||||
bool y = 3;
|
||||
bool is_cancel = 4;
|
||||
}
|
||||
|
||||
message PointerButton {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 button = 2;
|
||||
bool state = 3;
|
||||
}
|
||||
|
||||
message KeyboardKey {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 key = 2;
|
||||
bool state = 3;
|
||||
}
|
||||
|
||||
message TouchDown {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 touchid = 2;
|
||||
double x = 5;
|
||||
double y = 6;
|
||||
}
|
||||
|
||||
message TouchMotion {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 touchid = 2;
|
||||
double x = 5;
|
||||
double y = 6;
|
||||
}
|
||||
|
||||
message TouchUp {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 touchid = 2;
|
||||
}
|
||||
|
||||
message StartEmulating {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 sequence = 2;
|
||||
}
|
||||
|
||||
message StopEmulating {
|
||||
fixed32 deviceid = 1;
|
||||
}
|
||||
|
||||
message Frame {
|
||||
fixed32 deviceid = 1;
|
||||
uint64 timestamp = 2;
|
||||
}
|
||||
|
||||
message ClientMessage {
|
||||
oneof msg {
|
||||
/* Client setup and configuration */
|
||||
Connect connect = 1;
|
||||
ConnectDone connect_done = 2;
|
||||
Disconnect disconnect = 3;
|
||||
BindSeat bind_seat = 4;
|
||||
CloseDevice close_device = 6;
|
||||
GetVersion get_version = 10;
|
||||
|
||||
/* Events */
|
||||
StartEmulating start_emulating = 20;
|
||||
StopEmulating stop_emulating = 21;
|
||||
PointerRelative pointer_relative = 22;
|
||||
PointerAbsolute pointer_absolute = 23;
|
||||
PointerScroll pointer_scroll = 24;
|
||||
PointerScrollDiscrete pointer_scroll_discrete = 25;
|
||||
PointerScrollStop pointer_scroll_stop = 26;
|
||||
PointerButton pointer_button = 27;
|
||||
KeyboardKey keyboard_key = 28;
|
||||
TouchDown touch_down = 29;
|
||||
TouchMotion touch_motion = 30;
|
||||
TouchUp touch_up = 31;
|
||||
Frame frame = 32;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The highest version number supported by the server. This message SHOULD be
|
||||
* sent by the EIS implementation immediately after a socket is
|
||||
* created/obtained. This avoids roundtrips between the server and the client
|
||||
* on connection.
|
||||
*
|
||||
* This message MAY be sent at any other time.
|
||||
* This message MUST be sent in response to a GetVersion request.
|
||||
*
|
||||
* The "eis" field is the constant string "EIS" and helps identifying
|
||||
* this connection in debugging tools.
|
||||
*
|
||||
* The content of this message never changes.
|
||||
*/
|
||||
message Version {
|
||||
fixed32 version = 1;
|
||||
string eis = 2; /* always "EIS" */
|
||||
}
|
||||
|
||||
message Connected {
|
||||
}
|
||||
|
||||
message Disconnected {
|
||||
}
|
||||
|
||||
message SeatAdded {
|
||||
fixed32 seatid = 1;
|
||||
fixed32 capabilities = 2;
|
||||
string name = 3;
|
||||
}
|
||||
|
||||
message SeatRemoved {
|
||||
fixed32 seatid = 1;
|
||||
}
|
||||
|
||||
message DeviceAdded {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 capabilities = 2;
|
||||
string name = 6;
|
||||
fixed32 seatid = 7;
|
||||
fixed32 type = 8;
|
||||
fixed32 width = 9;
|
||||
fixed32 height = 10;
|
||||
}
|
||||
|
||||
message DeviceKeymap {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 keymap_type = 2;
|
||||
fixed32 keymap_size = 3;
|
||||
/* keymap itself is passed as fd */
|
||||
}
|
||||
|
||||
message DeviceRegion {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 offset_x = 2;
|
||||
fixed32 offset_y = 3;
|
||||
fixed32 width = 4;
|
||||
fixed32 height = 5;
|
||||
double scale = 6;
|
||||
}
|
||||
|
||||
message DeviceDone {
|
||||
fixed32 deviceid = 1;
|
||||
}
|
||||
|
||||
message DeviceRemoved {
|
||||
fixed32 deviceid = 1;
|
||||
}
|
||||
|
||||
message DeviceResumed {
|
||||
fixed32 deviceid = 1;
|
||||
}
|
||||
|
||||
message DevicePaused {
|
||||
fixed32 deviceid = 1;
|
||||
}
|
||||
|
||||
message KeyboardModifiers {
|
||||
fixed32 deviceid = 1;
|
||||
fixed32 depressed = 2;
|
||||
fixed32 locked = 3;
|
||||
fixed32 latched = 4;
|
||||
fixed32 group = 5;
|
||||
}
|
||||
|
||||
message ServerMessage {
|
||||
oneof msg {
|
||||
/* Server setup and configuration */
|
||||
Connected connected = 2;
|
||||
Disconnected disconnected = 3;
|
||||
SeatAdded seat_added = 4;
|
||||
SeatRemoved seat_removed = 5;
|
||||
DeviceAdded device_added = 6;
|
||||
DeviceRegion device_region = 7;
|
||||
DeviceKeymap device_keymap = 8;
|
||||
DeviceDone device_done = 9;
|
||||
DeviceRemoved device_removed = 10;
|
||||
DeviceResumed device_resumed = 11;
|
||||
DevicePaused device_paused = 12;
|
||||
KeyboardModifiers keyboard_modifiers = 13;
|
||||
Version version = 15;
|
||||
|
||||
/* Events */
|
||||
StartEmulating start_emulating = 20;
|
||||
StopEmulating stop_emulating = 21;
|
||||
PointerRelative pointer_relative = 22;
|
||||
PointerAbsolute pointer_absolute = 23;
|
||||
PointerScroll pointer_scroll = 24;
|
||||
PointerScrollDiscrete pointer_scroll_discrete = 25;
|
||||
PointerScrollStop pointer_scroll_stop = 26;
|
||||
PointerButton pointer_button = 27;
|
||||
KeyboardKey keyboard_key = 28;
|
||||
TouchDown touch_down = 29;
|
||||
TouchMotion touch_motion = 30;
|
||||
TouchUp touch_up = 31;
|
||||
Frame frame = 32;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,21 @@
|
|||
dep_protobuf = dependency('libprotobuf-c')
|
||||
protoc = find_program('protoc')
|
||||
proto_headers = custom_target('proto-headers',
|
||||
input: 'ei.proto',
|
||||
output: ['ei.pb-c.c', 'ei.pb-c.h'],
|
||||
command: [protoc,
|
||||
'--proto_path=@0@'.format(meson.current_source_dir()),
|
||||
'--c_out=@0@'.format(meson.current_build_dir()),
|
||||
'ei.proto'])
|
||||
proto_c_template = files('ei-proto.c.tmpl')
|
||||
proto_h_template = files('ei-proto.h.tmpl')
|
||||
|
||||
scanner = find_program('scanner.py')
|
||||
protocol_xml = files('protocol.xml')
|
||||
ei_proto_headers = custom_target('ei-proto-headers',
|
||||
input: protocol_xml,
|
||||
output: ['ei-proto.h'],
|
||||
command: [scanner, '--component=ei', '--output=@OUTPUT@', '@INPUT@', proto_h_template])
|
||||
ei_proto_sources = custom_target('ei-proto-sources',
|
||||
input: protocol_xml,
|
||||
output: ['ei-proto.c'],
|
||||
command: [scanner, '--component=ei', '--output=@OUTPUT@', '@INPUT@', proto_c_template])
|
||||
eis_proto_headers = custom_target('eis-proto-headers',
|
||||
input: protocol_xml,
|
||||
output: ['eis-proto.h'],
|
||||
command: [scanner, '--component=eis', '--output=@OUTPUT@', '@INPUT@', proto_h_template])
|
||||
eis_proto_sources = custom_target('eis-proto-sources',
|
||||
input: protocol_xml,
|
||||
output: ['eis-proto.c'],
|
||||
command: [scanner, '--component=eis', '--output=@OUTPUT@', '@INPUT@', proto_c_template])
|
||||
|
|
|
|||
315
proto/protocol.xml
Normal file
315
proto/protocol.xml
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="ei">
|
||||
|
||||
<copyright>
|
||||
Copyright © 2008-2011 Kristian Høgsberg
|
||||
Copyright © 2010-2011 Intel Corporation
|
||||
Copyright © 2012-2013 Collabora, Ltd.
|
||||
Copyright © 2023 Red Hat, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the
|
||||
next paragraph) shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<!--
|
||||
|
||||
Protocol wire format: [length, sender-id, opcode, ...]
|
||||
Where:
|
||||
- length, sender-id and opcode are 32-bit integers in the
|
||||
EIS implementation's native byte order.
|
||||
- length is the length of the message in bytes, including the 12 header bytes
|
||||
- sender-id is the id of the object sending the request/event. The sender-id
|
||||
0 is reserved for the special "ei" object.
|
||||
- opcode is the event or requeset-specific opcode, starting at 0
|
||||
requests and events have overlapping opcode ranges, i.e. the first request
|
||||
and the first event both have opcode 0.
|
||||
- arguments is a variable number of arguments specific to the message.
|
||||
|
||||
Types:
|
||||
- 'uint': a 32-bit unsigned integer
|
||||
- 'uint': a 32-bit signed integer
|
||||
- 'float': a 32-bit IEEE-754 float
|
||||
- 'fd': a file descriptor. Zero bytes in the message itself, transmitted
|
||||
in the overhead
|
||||
- 'string': a length-prefix zero-terminated string. Encoded as
|
||||
one 32-bit unsigned integer for the length followed by the string.
|
||||
The string is padded to the nearest 4-byte units, for example the string
|
||||
"hello" is of length 6 but is zero-padded to 8 bytes. Full (le) encoding:
|
||||
[0x06, 0x00, 0x00, 0x00, 'h', 'e', 'l', 'l', 'o', '\0', '\0\, '\0']
|
||||
|
||||
-->
|
||||
|
||||
<interface name="ei" version="1">
|
||||
<description summary="core global object">
|
||||
The core global object. This is a special singleton object. It
|
||||
is used for internal ei protocol features.
|
||||
</description>
|
||||
|
||||
<request name="get_version">
|
||||
</request>
|
||||
|
||||
<request name="connect">
|
||||
<arg name="version" type="uint"/>
|
||||
<arg name="name" type="string"/>
|
||||
<arg name="is_sender" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="connect_done">
|
||||
</request>
|
||||
|
||||
<request name="disconnect">
|
||||
</request>
|
||||
|
||||
<request name="bind_seat">
|
||||
<arg name="seat_id" type="uint"/>
|
||||
<arg name="capabilities" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="close_device">
|
||||
<arg name="device_id" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="pointer_relative">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</request>
|
||||
|
||||
<request name="pointer_absolute">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</request>
|
||||
|
||||
<request name="pointer_scroll">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</request>
|
||||
|
||||
<request name="pointer_scroll_discrete">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
</request>
|
||||
|
||||
<request name="pointer_scroll_stop">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="uint"/>
|
||||
<arg name="y" type="uint"/>
|
||||
<arg name="is_cancel" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="pointer_button">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="button" type="uint"/>
|
||||
<arg name="state" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="keyboard_key">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="key" type="uint"/>
|
||||
<arg name="state" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="touch_down">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="touchid" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</request>
|
||||
|
||||
<request name="touch_motion">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="touchid" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</request>
|
||||
|
||||
<request name="touch_up">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="touchid" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="start_emulating">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="sequence" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="stop_emulating">
|
||||
<arg name="device_id" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="frame">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="timestamp" type="uint"/>
|
||||
<arg name="micros" type="uint"/>
|
||||
</request>
|
||||
|
||||
<event name="version">
|
||||
<arg name="version" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="connected">
|
||||
</event>
|
||||
|
||||
<event name="disconnected">
|
||||
</event>
|
||||
|
||||
<event name="seat_added">
|
||||
<arg name="seat_id" type="uint"/>
|
||||
<arg name="capabilities" type="uint"/>
|
||||
<arg name="name" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="seat_removed">
|
||||
<arg name="seat_id" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="device_added">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="capabilities" type="uint"/>
|
||||
<arg name="name" type="string"/>
|
||||
<arg name="seat_id" type="uint"/>
|
||||
<arg name="type" type="uint"/>
|
||||
<arg name="width" type="uint"/>
|
||||
<arg name="height" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="device_keymap">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="keymap_type" type="uint"/>
|
||||
<arg name="keymap_size" type="uint"/>
|
||||
<arg name="keymap" type="fd"/>
|
||||
</event>
|
||||
|
||||
<event name="device_region">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="offset_x" type="uint"/>
|
||||
<arg name="offset_y" type="uint"/>
|
||||
<arg name="width" type="uint"/>
|
||||
<arg name="hight" type="uint"/>
|
||||
<arg name="scale" type="float"/>
|
||||
</event>
|
||||
|
||||
<event name="device_done">
|
||||
<arg name="device_id" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="device_removed">
|
||||
<arg name="device_id" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="device_resumed">
|
||||
<arg name="device_id" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="device_paused">
|
||||
<arg name="device_id" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="pointer_relative">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</event>
|
||||
|
||||
<event name="pointer_absolute">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</event>
|
||||
|
||||
<event name="pointer_scroll">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</event>
|
||||
|
||||
<event name="pointer_scroll_discrete">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
</event>
|
||||
|
||||
<event name="pointer_scroll_stop">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="x" type="uint"/>
|
||||
<arg name="y" type="uint"/>
|
||||
<arg name="is_cancel" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="pointer_button">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="button" type="uint"/>
|
||||
<arg name="state" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="keyboard_key">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="key" type="uint"/>
|
||||
<arg name="state" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="keyboard_modifiers">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="depressed" type="uint"/>
|
||||
<arg name="locked" type="uint"/>
|
||||
<arg name="latched" type="uint"/>
|
||||
<arg name="group" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="touch_down">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="touchid" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</event>
|
||||
|
||||
<event name="touch_motion">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="touchid" type="uint"/>
|
||||
<arg name="x" type="float"/>
|
||||
<arg name="y" type="float"/>
|
||||
</event>
|
||||
|
||||
<event name="touch_up">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="touchid" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="start_emulating">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="sequence" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="stop_emulating">
|
||||
<arg name="device_id" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="frame">
|
||||
<arg name="device_id" type="uint"/>
|
||||
<arg name="timestamp" type="uint"/>
|
||||
<arg name="micros" type="uint"/>
|
||||
</event>
|
||||
</interface>
|
||||
</protocol>
|
||||
|
||||
405
proto/scanner.py
Executable file
405
proto/scanner.py
Executable file
|
|
@ -0,0 +1,405 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from typing import Optional, Union
|
||||
from pathlib import Path
|
||||
|
||||
import argparse
|
||||
import attr
|
||||
import jinja2
|
||||
import jinja2.environment
|
||||
import os
|
||||
import sys
|
||||
import xml.sax
|
||||
import xml.sax.handler
|
||||
import xml.sax._exceptions
|
||||
|
||||
|
||||
def proto_to_type(proto: str) -> Optional[str]:
|
||||
"""
|
||||
Conversion of protocol types to the signatures we use in the code
|
||||
"""
|
||||
|
||||
return {
|
||||
"uint": "u",
|
||||
"int": "i",
|
||||
"float": "f",
|
||||
"fd": "h",
|
||||
"new_id": "n",
|
||||
"object": "o",
|
||||
"string": "s",
|
||||
}.get(proto)
|
||||
|
||||
|
||||
@attr.s
|
||||
class Target:
|
||||
"""
|
||||
Defines the target struct for the base "ei" interface.
|
||||
|
||||
In libei we have a `struct ei` but in libeis the equivalent
|
||||
level is `struct eis_client`. This target type maps those two.
|
||||
"""
|
||||
|
||||
name: str = attr.ib()
|
||||
context: str = attr.ib()
|
||||
|
||||
@property
|
||||
def ctype(self) -> str:
|
||||
return f"struct {self.name} *"
|
||||
|
||||
@property
|
||||
def as_param(self) -> str:
|
||||
return f"struct {self.name}* {self.name}"
|
||||
|
||||
@property
|
||||
def as_arg(self) -> str:
|
||||
return self.as_param
|
||||
|
||||
@classmethod
|
||||
def create(cls, name: str, context: str) -> "Target":
|
||||
return cls(name=name, context=context)
|
||||
|
||||
|
||||
@attr.s
|
||||
class Argument:
|
||||
"""
|
||||
Argument to a request or a reply
|
||||
"""
|
||||
|
||||
name: str = attr.ib()
|
||||
signature: str = attr.ib(converter=proto_to_type)
|
||||
summary: str = attr.ib()
|
||||
|
||||
@property
|
||||
def as_arg(self) -> str:
|
||||
return f"{self.ctype} {self.name}"
|
||||
|
||||
@property
|
||||
def ctype(self) -> str:
|
||||
return {
|
||||
"u": "uint32_t",
|
||||
"i": "int32_t",
|
||||
"s": "const char *",
|
||||
"h": "int",
|
||||
"f": "float",
|
||||
"o": "object_id_t",
|
||||
"n": "new_id_t",
|
||||
}[self.signature]
|
||||
|
||||
@property
|
||||
def argtype(self) -> str:
|
||||
return {
|
||||
"u": "u32",
|
||||
"i": "i32",
|
||||
"s": "str",
|
||||
"h": "fd",
|
||||
"f": "f32",
|
||||
"o": "obj",
|
||||
"n": "obj",
|
||||
}[self.signature]
|
||||
|
||||
@signature.validator # type: ignore
|
||||
def _validate_signature(self, attribute, value):
|
||||
types = "iufhnos"
|
||||
assert value in types, f"Failed to parse signature {value}"
|
||||
|
||||
@classmethod
|
||||
def create(cls, name: str, signature: str, summary: str = "") -> "Argument":
|
||||
# FIXME: enum value checks
|
||||
return cls(name, signature, summary)
|
||||
|
||||
|
||||
@attr.s
|
||||
class Message:
|
||||
"""
|
||||
Parent class for the wire message (Request or Event).
|
||||
"""
|
||||
|
||||
name: str = attr.ib()
|
||||
since: int = attr.ib()
|
||||
opcode: int = attr.ib()
|
||||
interface: "Interface" = attr.ib()
|
||||
|
||||
arguments: list[Argument] = attr.ib(init=False, factory=list)
|
||||
|
||||
def add_argument(self, arg: Argument) -> None:
|
||||
self.arguments.append(arg)
|
||||
|
||||
@property
|
||||
def num_arguments(self) -> int:
|
||||
return len(self.arguments)
|
||||
|
||||
@property
|
||||
def signature(self) -> str:
|
||||
return "".join([a.signature for a in self.arguments])
|
||||
|
||||
|
||||
@attr.s
|
||||
class Request(Message):
|
||||
@classmethod
|
||||
def create(
|
||||
cls, name: str, opcode: int, interface: "Interface", since: int = 1
|
||||
) -> "Request":
|
||||
return cls(name=name, opcode=opcode, since=since, interface=interface)
|
||||
|
||||
@property
|
||||
def fqdn(self):
|
||||
return f"{self.interface.name}_request_{self.name}"
|
||||
|
||||
|
||||
@attr.s
|
||||
class Event(Message):
|
||||
@classmethod
|
||||
def create(
|
||||
cls, name: str, opcode: int, interface: "Interface", since: int = 1
|
||||
) -> "Event":
|
||||
return cls(name=name, opcode=opcode, since=since, interface=interface)
|
||||
|
||||
@property
|
||||
def fqdn(self):
|
||||
return f"{self.interface.name}_event_{self.name}"
|
||||
|
||||
|
||||
@attr.s
|
||||
class Entry:
|
||||
"""
|
||||
An enum entry
|
||||
"""
|
||||
|
||||
name: str = attr.ib()
|
||||
value: int = attr.ib()
|
||||
summary: str = attr.ib()
|
||||
|
||||
@classmethod
|
||||
def create(cls, name: str, value: int, summary: str = "") -> "Entry":
|
||||
return cls(name=name, value=value, summary=summary)
|
||||
|
||||
|
||||
@attr.s
|
||||
class Enum:
|
||||
name: str = attr.ib()
|
||||
since: int = attr.ib()
|
||||
interface: "Interface" = attr.ib()
|
||||
|
||||
entries: list[Entry] = attr.ib(init=False, factory=list)
|
||||
|
||||
@classmethod
|
||||
def create(cls, name: str, interface: "Interface", since: int = 1) -> "Enum":
|
||||
return cls(name=name, since=since, interface=interface)
|
||||
|
||||
def add_entry(self, entry: Entry) -> None:
|
||||
self.entries.append(entry)
|
||||
|
||||
@property
|
||||
def fqdn(self):
|
||||
return f"{self.interface.name}_{self.name}"
|
||||
|
||||
|
||||
@attr.s
|
||||
class Interface:
|
||||
name: str = attr.ib()
|
||||
version: int = attr.ib()
|
||||
|
||||
requests: list[Request] = attr.ib(init=False, factory=list)
|
||||
events: list[Event] = attr.ib(init=False, factory=list)
|
||||
enums: list[Enum] = attr.ib(init=False, factory=list)
|
||||
|
||||
mode: str = attr.ib() # "ei" or "eis"
|
||||
|
||||
def add_request(self, request: Request) -> None:
|
||||
self.requests.append(request)
|
||||
|
||||
def add_event(self, event: Event) -> None:
|
||||
self.events.append(event)
|
||||
|
||||
def add_enum(self, enum: Enum) -> None:
|
||||
self.enums.append(enum)
|
||||
|
||||
@property
|
||||
def outgoing(self) -> list[Message]:
|
||||
"""
|
||||
Returns the list of messages outgoing from this implementation.
|
||||
|
||||
We use the same class for both ei and eis. To make the
|
||||
template simpler, the class maps requests/events to
|
||||
incoming/outgoing as correct relative to the implementation.
|
||||
"""
|
||||
if self.mode == "ei":
|
||||
return self.requests # type: ignore
|
||||
else:
|
||||
return self.events # type: ignore
|
||||
|
||||
@property
|
||||
def incoming(self) -> list[Message]:
|
||||
"""
|
||||
Returns the list of messages incoming to this implementation.
|
||||
|
||||
We use the same class for both ei and eis. To make the
|
||||
template simpler, the class maps requests/events to
|
||||
incoming/outgoing as correct relative to the implementation.
|
||||
"""
|
||||
if self.mode == "ei":
|
||||
return self.events # type: ignore
|
||||
else:
|
||||
return self.requests # type: ignore
|
||||
|
||||
@classmethod
|
||||
def create(cls, name: str, version: int, mode: str = "ei") -> "Interface":
|
||||
assert mode in ["ei", "eis"]
|
||||
return cls(name=name, version=version, mode=mode)
|
||||
|
||||
|
||||
@attr.s
|
||||
class Protocol(xml.sax.handler.ContentHandler):
|
||||
component: str = attr.ib()
|
||||
interfaces: list[Interface] = attr.ib(factory=list)
|
||||
|
||||
current_interface: Optional[Interface] = attr.ib(init=False, default=None)
|
||||
current_message: Optional[Union[Message, Enum]] = attr.ib(init=False, default=None)
|
||||
|
||||
def startElement(self, element: str, attrs: dict):
|
||||
if element == "interface":
|
||||
assert self.current_interface is None
|
||||
name = attrs["name"]
|
||||
if name.startswith("ei"):
|
||||
name = f"{self.component}{name[2:]}"
|
||||
version = attrs["version"]
|
||||
intf = Interface.create(name=name, version=version, mode=self.component)
|
||||
self.current_interface = intf
|
||||
self.interfaces.append(intf)
|
||||
elif element == "request":
|
||||
assert self.current_interface is not None
|
||||
assert self.current_message is None
|
||||
name = attrs["name"]
|
||||
since = attrs.get("since", 1)
|
||||
opcode = len(self.current_interface.requests)
|
||||
request = Request.create(
|
||||
name=name, since=since, opcode=opcode, interface=self.current_interface
|
||||
)
|
||||
self.current_interface.add_request(request)
|
||||
self.current_message = request
|
||||
elif element == "event":
|
||||
assert self.current_interface is not None
|
||||
assert self.current_message is None
|
||||
|
||||
name = attrs["name"]
|
||||
since = attrs.get("since", 1)
|
||||
opcode = len(self.current_interface.events)
|
||||
event = Event.create(
|
||||
name=name, since=since, opcode=opcode, interface=self.current_interface
|
||||
)
|
||||
self.current_interface.add_event(event)
|
||||
self.current_message = event
|
||||
elif element == "enum":
|
||||
assert self.current_interface is not None
|
||||
assert self.current_message is None
|
||||
name = attrs["name"]
|
||||
since = attrs.get("since", 1)
|
||||
enum = Enum.create(name=name, since=since, interface=self.current_interface)
|
||||
self.current_interface.add_enum(enum)
|
||||
self.current_message = enum
|
||||
elif element == "arg":
|
||||
assert self.current_interface is not None
|
||||
assert isinstance(self.current_message, Message)
|
||||
name = attrs["name"]
|
||||
sig = attrs["type"]
|
||||
summary = attrs.get("summary", "")
|
||||
arg = Argument.create(name=name, signature=sig, summary=summary)
|
||||
self.current_message.add_argument(arg)
|
||||
elif element == "entry":
|
||||
assert self.current_interface is not None
|
||||
assert isinstance(self.current_message, Enum)
|
||||
name = attrs["name"]
|
||||
value = attrs["value"]
|
||||
summary = attrs.get("summary", "")
|
||||
entry = Entry.create(name=name, value=value, summary=summary)
|
||||
self.current_message.add_entry(entry)
|
||||
|
||||
def endElement(self, name):
|
||||
if name == "interface":
|
||||
assert self.current_interface is not None
|
||||
self.current_interface = None
|
||||
elif name == "request":
|
||||
assert isinstance(self.current_message, Request)
|
||||
self.current_message = None
|
||||
elif name == "event":
|
||||
assert isinstance(self.current_message, Event)
|
||||
self.current_message = None
|
||||
elif name == "enum":
|
||||
assert isinstance(self.current_message, Enum)
|
||||
self.current_message = None
|
||||
|
||||
def characters(self, content):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def create(cls, component: str) -> "Protocol":
|
||||
h = cls(component=component)
|
||||
return h
|
||||
|
||||
|
||||
def parse(protofile: Path, component: str) -> Protocol:
|
||||
proto = Protocol.create(component=component)
|
||||
xml.sax.parse(os.fspath(protofile), proto)
|
||||
return proto
|
||||
|
||||
|
||||
def generate_source(
|
||||
proto: Protocol, headerfile: Optional[str], template: Path, component: str
|
||||
) -> jinja2.environment.TemplateStream:
|
||||
assert component in ["ei", "eis"]
|
||||
target = {
|
||||
"ei": Target.create("ei", context="context"),
|
||||
"eis": Target.create("eis_client", context="client"),
|
||||
}[component]
|
||||
|
||||
data = {}
|
||||
data["target"] = target
|
||||
data["interfaces"] = proto.interfaces
|
||||
if headerfile:
|
||||
data["headerfile"] = headerfile
|
||||
|
||||
env = jinja2.Environment(
|
||||
loader=jinja2.FileSystemLoader(os.fspath(template.parent)),
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
)
|
||||
jtemplate = env.get_template(template.name)
|
||||
return jtemplate.stream(data)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--component", type=str, choices=["ei", "eis"], default="ei")
|
||||
parser.add_argument(
|
||||
"--output", type=str, default="-", help="Output file to write to"
|
||||
)
|
||||
parser.add_argument("protocol", type=Path, help="The protocol XML file")
|
||||
parser.add_argument("template", type=Path, help="The template file")
|
||||
|
||||
ns = parser.parse_args()
|
||||
assert ns.template.exists()
|
||||
assert ns.protocol.exists()
|
||||
|
||||
try:
|
||||
proto = parse(
|
||||
protofile=ns.protocol,
|
||||
component=ns.component,
|
||||
)
|
||||
except xml.sax._exceptions.SAXParseException as e:
|
||||
print(f"Parser error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
headerfile = f"{Path(ns.output).stem}.h" if ns.output != "-" else None
|
||||
|
||||
stream = generate_source(
|
||||
proto=proto, headerfile=headerfile, template=ns.template, component=ns.component
|
||||
)
|
||||
|
||||
file = sys.stdout if ns.output == "-" else open(ns.output, "w")
|
||||
stream.dump(file)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -29,7 +29,6 @@
|
|||
#include "util-mem.h"
|
||||
#include "util-io.h"
|
||||
|
||||
#include "ei.pb-c.h"
|
||||
#include "brei-shared.h"
|
||||
|
||||
struct brei_message_private {
|
||||
|
|
@ -47,9 +46,155 @@ brei_message_take_fd(struct brei_message *m)
|
|||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of int32s required to store count bytes.
|
||||
*/
|
||||
static inline uint32_t
|
||||
bytes_to_int32(uint32_t count)
|
||||
{
|
||||
return (uint32_t)(((uint64_t)count + 3)/4);
|
||||
}
|
||||
|
||||
static int
|
||||
brei_demarshal(struct iobuf *buf, const char *signature, union brei_arg **args_out)
|
||||
{
|
||||
size_t nargs = strlen(signature);
|
||||
if (nargs > 256)
|
||||
return -EPROTO;
|
||||
|
||||
/* This over-allocates if we have more than one char per type but meh */
|
||||
_cleanup_free_ union brei_arg *args = xalloc(nargs * sizeof(*args));
|
||||
|
||||
const char *s = signature;
|
||||
union brei_arg *arg = args;
|
||||
uint32_t *p = (uint32_t*)iobuf_data(buf);
|
||||
uint32_t *end = (uint32_t*)iobuf_data_end(buf);
|
||||
|
||||
nargs = 0;
|
||||
while (*s) {
|
||||
switch (*s) {
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'f':
|
||||
case 'o':
|
||||
case 'n':
|
||||
arg->u32 = *p++;
|
||||
break;
|
||||
case 'h':
|
||||
arg->fd = iobuf_take_fd(buf);
|
||||
break;
|
||||
case 's': {
|
||||
size_t slen = *p++; /* string length includes \0 */
|
||||
if (slen == 0) {
|
||||
arg->str = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t slen32 = bytes_to_int32(slen);
|
||||
if (end - p < slen32) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const char *str = (char*)p;
|
||||
|
||||
/* strings must be null-terminated */
|
||||
if (slen && str[slen - 1] != '\0')
|
||||
return -EINVAL;
|
||||
|
||||
arg->str = str;
|
||||
p += slen32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
arg++;
|
||||
s++;
|
||||
nargs++;
|
||||
}
|
||||
|
||||
*args_out = steal(&args);
|
||||
|
||||
return nargs;
|
||||
}
|
||||
|
||||
static int
|
||||
brei_marshal(struct iobuf *buf, const char *signature, size_t nargs, va_list args)
|
||||
{
|
||||
const char *s = signature;
|
||||
int32_t i;
|
||||
uint32_t u;
|
||||
float f;
|
||||
int fd;
|
||||
|
||||
while (*s) {
|
||||
switch (*s) {
|
||||
case 'i':
|
||||
i = va_arg(args, int32_t);
|
||||
iobuf_append(buf, (const char*)(&i), 4);
|
||||
break;
|
||||
case 'u':
|
||||
case 'o':
|
||||
case 'n':
|
||||
u = va_arg(args, uint32_t);
|
||||
iobuf_append(buf, (const char*)(&u), 4);
|
||||
break;
|
||||
case 'f':
|
||||
f = va_arg(args, double);
|
||||
iobuf_append(buf, (const char*)(&f), 4);
|
||||
break;
|
||||
case 'h':
|
||||
fd = va_arg(args, int);
|
||||
iobuf_append_fd(buf, fd);
|
||||
break;
|
||||
case 's': {
|
||||
static const char zeroes[4] = {0};
|
||||
const char *str = va_arg(args, const char*);
|
||||
|
||||
/* FIXME: nullable strings */
|
||||
size_t slen = str ? strlen(str) + 1 : 0;
|
||||
iobuf_append(buf, (const char*)&slen, 4);
|
||||
if (slen > 0) {
|
||||
iobuf_append(buf, str, slen);
|
||||
if (slen % 4)
|
||||
iobuf_append(buf, zeroes, 4 - slen % 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
brei_send_message(int fd,
|
||||
uint32_t id,
|
||||
uint32_t opcode,
|
||||
const char *signature,
|
||||
size_t nargs,
|
||||
va_list args)
|
||||
{
|
||||
uint32_t message_len = 0; /* we'll overwrite this later */
|
||||
|
||||
_cleanup_iobuf_ struct iobuf *buf = iobuf_new(128);
|
||||
iobuf_append(buf, (const char *)&message_len, 4);
|
||||
iobuf_append(buf, (const char *)&id, 4);
|
||||
iobuf_append(buf, (const char *)&opcode, 4);
|
||||
|
||||
int rc = brei_marshal(buf, signature, nargs, args);
|
||||
|
||||
if (rc == 0) {
|
||||
/* now write the actual message length, including header */
|
||||
*(uint32_t*)iobuf_data(buf) = iobuf_len(buf);
|
||||
rc = iobuf_send(buf, fd);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
brei_dispatch(int fd,
|
||||
int (*callback)(struct brei_message *m, void *user_data),
|
||||
int (*lookup_object)(uint32_t object_id, struct brei_object **object, void *user_data),
|
||||
void *user_data)
|
||||
{
|
||||
_cleanup_iobuf_ struct iobuf *buf = iobuf_new(64);
|
||||
|
|
@ -62,44 +207,58 @@ brei_dispatch(int fd,
|
|||
return rc;
|
||||
}
|
||||
|
||||
_cleanup_close_ int recvfd = -1;
|
||||
size_t idx = 0;
|
||||
while (true) {
|
||||
const char *data = iobuf_data(buf) + idx;
|
||||
size_t len = iobuf_len(buf) - idx;
|
||||
int consumed = 0;
|
||||
uint32_t *data = (uint32_t*)iobuf_data(buf);
|
||||
size_t len = iobuf_len(buf);
|
||||
|
||||
if (len == 0)
|
||||
const size_t headersize = 12; /* length, object id, opcode */
|
||||
|
||||
if (len < headersize)
|
||||
break;
|
||||
|
||||
uint32_t msglen = *(uint32_t*)data;
|
||||
const char *msgdata = data + sizeof(msglen);
|
||||
size_t msglen = data[0]; /* 4 bytes message length */
|
||||
if (len < msglen)
|
||||
break;
|
||||
|
||||
assert(len >= msglen);
|
||||
uint32_t object_id = data[1]; /* 4 bytes for object id */
|
||||
uint32_t opcode = data[2]; /* 4 bytes for opcode */
|
||||
|
||||
/* This is a bit messy because it's just blu tacked on.
|
||||
* Our protocol passes maximum of one fd per message. We
|
||||
* take whatever next fd is and pass it along. Where the
|
||||
* parser takes it (brei_message_take_fd()) it gets set to
|
||||
* -1 and we take the next fd for the next message.
|
||||
*/
|
||||
if (recvfd == -1)
|
||||
recvfd = iobuf_take_fd(buf);
|
||||
/* Find the object, it is stored in the ei/eis context */
|
||||
struct brei_object *object = NULL;
|
||||
rc = lookup_object(object_id, &object, user_data);
|
||||
if (rc < 0)
|
||||
goto error;
|
||||
|
||||
struct brei_message_private msg = {
|
||||
.base.data = msgdata,
|
||||
.base.len = msglen,
|
||||
.fd = &recvfd,
|
||||
};
|
||||
assert(object);
|
||||
|
||||
/* Actual message parsing is done by the caller */
|
||||
consumed = callback(&msg.base, user_data);
|
||||
assert(consumed != 0);
|
||||
if (consumed < 0) {
|
||||
rc = consumed;
|
||||
/* We know the object's interface, now find the event we
|
||||
* need to parse */
|
||||
const struct brei_interface *interface = object->interface;
|
||||
assert(interface);
|
||||
|
||||
if (opcode >= interface->nincoming) {
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
idx += consumed + sizeof(msglen);
|
||||
|
||||
iobuf_pop(buf, headersize);
|
||||
|
||||
/* Demarshal the protocol into a set of arguments */
|
||||
_cleanup_free_ union brei_arg * args = NULL;
|
||||
const char *signature = interface->incoming[opcode].signature;
|
||||
int nargs = brei_demarshal(buf, signature, &args);
|
||||
if (nargs < 0) {
|
||||
rc = nargs;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Success! Let's pass this on to the
|
||||
* context to process */
|
||||
rc = interface->dispatcher(object->implementation, opcode, nargs, args);
|
||||
if (rc < 0)
|
||||
goto error;
|
||||
|
||||
iobuf_pop(buf, msglen - headersize);
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
|
@ -122,30 +281,50 @@ brei_drain_fd(int fd)
|
|||
#include "util-munit.h"
|
||||
|
||||
static int
|
||||
brei_dispatch_cb(struct brei_message *msg,
|
||||
void *user_data)
|
||||
brei_marshal_va(struct iobuf *buf, const char *signature, size_t nargs, ...)
|
||||
{
|
||||
char *buf = user_data;
|
||||
va_list args;
|
||||
|
||||
memcpy(buf, msg->data, msg->len);
|
||||
|
||||
return msg->len;
|
||||
va_start(args, nargs);
|
||||
int rc = brei_marshal(buf, signature, nargs, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline void
|
||||
send_data(int fd, const char *data, size_t data_size)
|
||||
MUNIT_TEST(test_brei_marshal)
|
||||
{
|
||||
/* note: data is null-terminated, we copy all of it but only use
|
||||
datalen to check truncation works */
|
||||
unsigned char buf[1024] = {0};
|
||||
*(uint32_t*)buf = data_size;
|
||||
memcpy(buf + 4, data, strlen(data)); /* intentionally strlen */
|
||||
_cleanup_iobuf_ struct iobuf *buf = iobuf_new(64);
|
||||
const char *str = "eierspeise";
|
||||
|
||||
int rc = xsend(fd, buf, 4 + data_size);
|
||||
munit_assert_int(rc, ==, 4 + data_size);
|
||||
int rc = brei_marshal_va(buf, "noiusf", 5, 0xab, 0xcd, -13, 0xfffd, str, 1.45);
|
||||
munit_assert_int(rc, ==, 0);
|
||||
|
||||
_cleanup_free_ union brei_arg *args;
|
||||
rc = brei_demarshal(buf, "noiusf", &args);
|
||||
munit_assert_int(rc, ==, 6);
|
||||
|
||||
munit_assert_int(args[0].obj, ==, 0xab);
|
||||
munit_assert_int(args[1].obj, ==, 0xcd);
|
||||
munit_assert_int(args[2].i32, ==, -13);
|
||||
munit_assert_int(args[3].u32, ==, 0xfffd);
|
||||
munit_assert_string_equal(args[4].str, str);
|
||||
munit_assert_double_equal(args[5].f32, 1.45, 3 /* precision */);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
MUNIT_TEST(test_brei_dispatch)
|
||||
static int
|
||||
brei_send_message_va(int fd, uint32_t id, uint32_t opcode,
|
||||
const char *signature, size_t nargs, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, nargs);
|
||||
int rc = brei_send_message(fd, id, opcode, signature, nargs, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
|
||||
MUNIT_TEST(test_brei_send_message)
|
||||
{
|
||||
int sv[2];
|
||||
int rc = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, sv);
|
||||
|
|
@ -155,32 +334,145 @@ MUNIT_TEST(test_brei_dispatch)
|
|||
int sock_write = sv[1];
|
||||
|
||||
{
|
||||
/* Packet one: just an 'x' */
|
||||
char return_buffer[1024] = {0};
|
||||
send_data(sock_write, "x", 1);
|
||||
int rc = brei_dispatch(sock_read, brei_dispatch_cb, return_buffer);
|
||||
munit_assert_int(rc, ==, 0);
|
||||
munit_assert_string_equal(return_buffer, "x");
|
||||
const int msglen = 20; /* 12 header + 2 * 4 bytes */
|
||||
uint32_t id = 1;
|
||||
uint32_t opcode = 2;
|
||||
const char *signature = "uu";
|
||||
int rc = brei_send_message_va(sock_write, id, opcode, signature, 2, 0xff, 0xdddd);
|
||||
munit_assert_int(rc, ==, msglen);
|
||||
|
||||
uint32_t buf[64];
|
||||
int len = read(sock_read, buf, sizeof(buf));
|
||||
munit_assert_int(len, ==, msglen);
|
||||
munit_assert_int(buf[0], ==, msglen);
|
||||
munit_assert_int(buf[1], ==, id);
|
||||
munit_assert_int(buf[2], ==, opcode);
|
||||
munit_assert_int(buf[3], ==, 0xff);
|
||||
munit_assert_int(buf[4], ==, 0xdddd);
|
||||
}
|
||||
{
|
||||
const int msglen = 20; /* 12 header + 2 * 4 bytes */
|
||||
uint32_t id = 1;
|
||||
uint32_t opcode = 2;
|
||||
const char *signature = "fi";
|
||||
int rc = brei_send_message_va(sock_write, id, opcode, signature, 2, 1.234, -12);
|
||||
munit_assert_int(rc, ==, msglen);
|
||||
|
||||
uint32_t buf[64];
|
||||
int len = read(sock_read, buf, sizeof(buf));
|
||||
union {
|
||||
uint32_t bytes;
|
||||
float f;
|
||||
} ufloat;
|
||||
munit_assert_int(len, ==, msglen);
|
||||
munit_assert_int(buf[0], ==, msglen);
|
||||
munit_assert_int(buf[1], ==, id);
|
||||
munit_assert_int(buf[2], ==, opcode);
|
||||
ufloat.bytes = buf[3];
|
||||
munit_assert_double_equal(ufloat.f, 1.234, 4/* precision */);
|
||||
munit_assert_int(buf[4], ==, -12);
|
||||
}
|
||||
|
||||
{
|
||||
/* Packet two: 'foobar' */
|
||||
char return_buffer[1024] = {0};
|
||||
send_data(sock_write, "foobar", 6);
|
||||
int rc = brei_dispatch(sock_read, brei_dispatch_cb, return_buffer);
|
||||
munit_assert_int(rc, ==, 0);
|
||||
munit_assert_string_equal(return_buffer, "foobar");
|
||||
const char string[12] = "hello wor"; /* tests padding too */
|
||||
int slen = bytes_to_int32(strlen(string) + 1) * 4;
|
||||
munit_assert_int(slen, ==, sizeof(string));
|
||||
|
||||
const int msglen = 28 + slen; /* 12 header + 3 * 4 bytes + 4 bytes slen + string length */
|
||||
uint32_t id = 2;
|
||||
uint32_t opcode = 3;
|
||||
const char *signature = "ison";
|
||||
int rc = brei_send_message_va(sock_write, id, opcode, signature, 4,
|
||||
-42, string, 0xab, 0xcdef);
|
||||
munit_assert_int(rc, ==, msglen);
|
||||
|
||||
uint32_t buf[64];
|
||||
int len = read(sock_read, buf, sizeof(buf));
|
||||
munit_assert_int(len, ==, msglen);
|
||||
munit_assert_int(buf[0], ==, msglen);
|
||||
munit_assert_int(buf[1], ==, id);
|
||||
munit_assert_int(buf[2], ==, opcode);
|
||||
munit_assert_int(buf[3], ==, -42);
|
||||
munit_assert_int(buf[4], ==, strlen(string) + 1);
|
||||
munit_assert_string_equal((const char*)&buf[5], string);
|
||||
munit_assert_int(memcmp(&buf[5], string, slen), ==, 0);
|
||||
|
||||
munit_assert_int(buf[5 + slen/4], ==, 0xab);
|
||||
munit_assert_int(buf[6 + slen/4], ==, 0xcdef);
|
||||
}
|
||||
|
||||
{
|
||||
/* Packet three: 'foobar' but last char truncated */
|
||||
char return_buffer[1024] = {0};
|
||||
send_data(sock_write, "foobar", 5); /* truncated */
|
||||
int rc = brei_dispatch(sock_read, brei_dispatch_cb, return_buffer);
|
||||
const char string1[12] = "hello wor"; /* tests padding too */
|
||||
const char string2[8] = "barba"; /* tests padding too */
|
||||
|
||||
const int msglen = 20 + sizeof(string1) + sizeof(string2); /* 12 header + 2 * 4 bytes slen + string lengths */
|
||||
uint32_t id = 2;
|
||||
uint32_t opcode = 3;
|
||||
const char *signature = "ss";
|
||||
int rc = brei_send_message_va(sock_write, id, opcode, signature, 2, string1, string2);
|
||||
munit_assert_int(rc, ==, msglen);
|
||||
|
||||
uint32_t buf[64];
|
||||
int len = read(sock_read, buf, sizeof(buf));
|
||||
munit_assert_int(len, ==, msglen);
|
||||
munit_assert_int(buf[0], ==, msglen);
|
||||
munit_assert_int(buf[1], ==, id);
|
||||
munit_assert_int(buf[2], ==, opcode);
|
||||
munit_assert_int(buf[3], ==, strlen(string1) + 1);
|
||||
munit_assert_string_equal((const char*)&buf[4], string1);
|
||||
munit_assert_int(buf[7], ==, strlen(string2) + 1);
|
||||
munit_assert_string_equal((const char*)&buf[8], string2);
|
||||
}
|
||||
|
||||
{
|
||||
int fds[2];
|
||||
int rc = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, fds);
|
||||
munit_assert_int(rc, ==, 0);
|
||||
munit_assert_string_equal(return_buffer, "fooba");
|
||||
_cleanup_close_ int left = fds[0];
|
||||
_cleanup_close_ int right = fds[1];
|
||||
|
||||
/* actual message data to be sent */
|
||||
char data[] = "some data\n";
|
||||
|
||||
const int msglen = 20; /* 12 header, 2 unsigned, fd is not in data */
|
||||
uint32_t id = 2;
|
||||
uint32_t opcode = 3;
|
||||
const char *signature = "uhu";
|
||||
rc = brei_send_message_va(sock_write, id, opcode, signature, 3, 0xab, right, 0xcd);
|
||||
munit_assert_int(rc, ==, msglen);
|
||||
|
||||
/* We passed it down, can close it now */
|
||||
close(right);
|
||||
right = -1;
|
||||
|
||||
/* receive the brei message */
|
||||
_cleanup_iobuf_ struct iobuf *recv = iobuf_new(64);
|
||||
int len = iobuf_recv_from_fd(recv, sock_read);
|
||||
|
||||
uint32_t *buf = (uint32_t*)iobuf_data(recv);
|
||||
munit_assert_int(len, ==, msglen);
|
||||
munit_assert_int(buf[0], ==, msglen);
|
||||
munit_assert_int(buf[1], ==, id);
|
||||
munit_assert_int(buf[2], ==, opcode);
|
||||
munit_assert_int(buf[3], ==, 0xab);
|
||||
/* fd is not in data */
|
||||
munit_assert_int(buf[4], ==, 0xcd);
|
||||
|
||||
_cleanup_close_ int fd = iobuf_take_fd(recv);
|
||||
munit_assert_int(fd, !=, -1);
|
||||
munit_assert_int(iobuf_take_fd(recv), ==, -1); /* only one fd */
|
||||
|
||||
/* send some data down the dup'd fd */
|
||||
rc = xsend(fd, data, sizeof(data));
|
||||
munit_assert_int(rc, ==, sizeof(data));
|
||||
|
||||
char recvbuf[64] = {0};
|
||||
rc = xread(left, recvbuf, sizeof(recvbuf));
|
||||
munit_assert_int(rc, ==, sizeof(data));
|
||||
munit_assert_string_equal(recvbuf, data);
|
||||
}
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -27,12 +27,60 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
struct brei_interface;
|
||||
struct brei_message;
|
||||
struct brei_object;
|
||||
|
||||
union brei_arg {
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
float f32;
|
||||
int fd;
|
||||
const char *str;
|
||||
uint32_t obj;
|
||||
};
|
||||
|
||||
struct brei_message {
|
||||
const char *data;
|
||||
size_t len;
|
||||
const char *name; /* request/event name */
|
||||
const char *signature;
|
||||
const struct brei_interface **types;
|
||||
};
|
||||
|
||||
typedef int (*brei_event_dispatcher)(void *object, uint32_t opcode,
|
||||
size_t nargs, union brei_arg *args);
|
||||
|
||||
struct brei_interface {
|
||||
const char *name;
|
||||
uint32_t version;
|
||||
uint32_t nrequests;
|
||||
const struct brei_message *requests;
|
||||
uint32_t nevents;
|
||||
const struct brei_message *events;
|
||||
|
||||
uint32_t nincoming;
|
||||
const struct brei_message *incoming;
|
||||
|
||||
brei_event_dispatcher dispatcher;
|
||||
};
|
||||
|
||||
struct brei_object {
|
||||
const struct brei_interface *interface;
|
||||
void *implementation; /* pointer to the actual object */
|
||||
uint32_t id; /* protocol object id */
|
||||
uint32_t version; /* protocol object interface version */
|
||||
};
|
||||
|
||||
int
|
||||
brei_send_message(int fd,
|
||||
uint32_t id,
|
||||
uint32_t opcode,
|
||||
const char *signature,
|
||||
size_t nargs,
|
||||
va_list args);
|
||||
|
||||
/**
|
||||
* Return the first file descriptor passed along with this message, or -1.
|
||||
* You must only call this when a message is supposed to have an fd.
|
||||
|
|
@ -56,7 +104,7 @@ brei_message_take_fd(struct brei_message *b);
|
|||
*/
|
||||
int
|
||||
brei_dispatch(int fd,
|
||||
int (*callback)(struct brei_message *msg, void *userdata),
|
||||
int (*lookup_object)(uint32_t object_id, struct brei_object **object, void *user_data),
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "util-object.h"
|
||||
|
||||
#include "libei.h"
|
||||
#include "brei-shared.h"
|
||||
#include "util-list.h"
|
||||
#include "util-sources.h"
|
||||
#include "util-structs.h"
|
||||
|
|
@ -55,6 +56,8 @@ enum ei_state {
|
|||
|
||||
struct ei {
|
||||
struct object object;
|
||||
struct brei_object proto_object;
|
||||
|
||||
void *user_data;
|
||||
struct sink *sink;
|
||||
struct source *source;
|
||||
|
|
@ -70,22 +73,30 @@ struct ei {
|
|||
enum ei_log_priority priority;
|
||||
} log;
|
||||
|
||||
const struct ei_proto_requests *requests;
|
||||
|
||||
bool is_sender;
|
||||
uint32_t server_version;
|
||||
uint32_t client_version;
|
||||
};
|
||||
|
||||
const struct ei_interface *
|
||||
ei_get_interface(struct ei *ei);
|
||||
|
||||
int
|
||||
ei_set_socket(struct ei *ei, int fd);
|
||||
|
||||
void
|
||||
ei_disconnect(struct ei *ei);
|
||||
|
||||
const struct brei_object *
|
||||
ei_get_proto_object(struct ei *ei);
|
||||
|
||||
struct ei *
|
||||
ei_get_context(struct ei *ei);
|
||||
|
||||
int
|
||||
ei_send_message(struct ei *ei, uint32_t object_id,
|
||||
uint32_t opcode, const char *signature, size_t nargs, ...);
|
||||
|
||||
int
|
||||
ei_send_seat_bind(struct ei_seat *seat, uint32_t capabilities);
|
||||
|
||||
|
|
|
|||
149
src/libei.c
149
src/libei.c
|
|
@ -42,8 +42,8 @@
|
|||
|
||||
#include "libei.h"
|
||||
#include "libei-private.h"
|
||||
#include "libei-proto.h"
|
||||
#include "brei-shared.h"
|
||||
#include "ei-proto.h"
|
||||
|
||||
_Static_assert(sizeof(enum ei_device_capability) == sizeof(int), "Invalid enum size");
|
||||
_Static_assert(sizeof(enum ei_keymap_type) == sizeof(int), "Invalid enum size");
|
||||
|
|
@ -110,6 +110,13 @@ OBJECT_IMPLEMENT_GETTER(ei, user_data, void *);
|
|||
DEFINE_UNREF_CLEANUP_FUNC(ei_device);
|
||||
DEFINE_UNREF_CLEANUP_FUNC(ei_region);
|
||||
|
||||
|
||||
const struct brei_object *
|
||||
ei_get_proto_object(struct ei *ei)
|
||||
{
|
||||
return &ei->proto_object;
|
||||
}
|
||||
|
||||
struct ei *
|
||||
ei_get_context(struct ei *ei)
|
||||
{
|
||||
|
|
@ -122,7 +129,9 @@ ei_create_context(bool is_sender, void *user_data)
|
|||
_unref_(ei) *ei = ei_create(NULL);
|
||||
|
||||
ei->state = EI_STATE_NEW;
|
||||
ei->requests = ei_proto_get_requests();
|
||||
ei->proto_object.id = 0;
|
||||
ei->proto_object.implementation = ei;
|
||||
ei->proto_object.interface = &ei_proto_interface;
|
||||
list_init(&ei->event_queue);
|
||||
list_init(&ei->seats);
|
||||
|
||||
|
|
@ -571,7 +580,7 @@ ei_disconnect(struct ei *ei)
|
|||
}
|
||||
|
||||
if (state != EI_STATE_NEW) {
|
||||
ei->requests->disconnect(ei);
|
||||
ei_request_disconnect(ei);
|
||||
}
|
||||
queue_disconnect_event(ei);
|
||||
ei->state = EI_STATE_DISCONNECTED;
|
||||
|
|
@ -664,7 +673,7 @@ handle_msg_device_added(struct ei *ei, uint32_t deviceid, uint32_t capabilities,
|
|||
static int
|
||||
handle_msg_device_keymap(struct ei *ei, uint32_t deviceid,
|
||||
enum ei_keymap_type keymap_type,
|
||||
size_t keymap_sz, int keymap_fd)
|
||||
uint32_t keymap_sz, int keymap_fd)
|
||||
{
|
||||
log_debug(ei, "Adding keymap for %#x", deviceid);
|
||||
|
||||
|
|
@ -708,7 +717,7 @@ static int
|
|||
handle_msg_device_region(struct ei *ei, uint32_t deviceid,
|
||||
uint32_t x, uint32_t y,
|
||||
uint32_t w, uint32_t h,
|
||||
double scale)
|
||||
float scale)
|
||||
{
|
||||
log_debug(ei, "Adding device region for %#x", deviceid);
|
||||
|
||||
|
|
@ -803,7 +812,7 @@ ei_send_close_device(struct ei_device *device)
|
|||
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
int rc = ei->requests->close_device(device);
|
||||
int rc = ei_request_close_device(ei, device->id);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -817,7 +826,7 @@ ei_send_start_emulating(struct ei_device *device, uint32_t sequence)
|
|||
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
int rc = ei->requests->start_emulating(device, sequence);
|
||||
int rc = ei_request_start_emulating(ei, device->id, sequence);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -831,7 +840,7 @@ ei_send_stop_emulating(struct ei_device *device)
|
|||
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
int rc = ei->requests->stop_emulating(device);
|
||||
int rc = ei_request_stop_emulating(ei, device->id);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -845,7 +854,7 @@ ei_send_seat_bind(struct ei_seat *seat, uint32_t capabilities)
|
|||
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
int rc = ei->requests->bind_seat(seat, capabilities);
|
||||
int rc = ei_request_bind_seat(ei, seat->id, capabilities);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -864,7 +873,7 @@ ei_send_frame(struct ei_device *device, uint64_t time)
|
|||
|
||||
device->send_frame_event = false;
|
||||
|
||||
int rc = ei->requests->frame(device, time);
|
||||
int rc = ei_request_frame(ei, device->id, us2ms(time), time % 1000);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -880,7 +889,7 @@ ei_send_pointer_rel(struct ei_device *device, double x, double y)
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->rel(device, x, y);
|
||||
int rc = ei_request_pointer_relative(ei, device->id, x, y);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -896,7 +905,7 @@ ei_send_pointer_abs(struct ei_device *device, double x, double y)
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->abs(device, x, y);
|
||||
int rc = ei_request_pointer_absolute(ei, device->id, x, y);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -912,7 +921,7 @@ ei_send_pointer_button(struct ei_device *device, uint32_t button, bool is_press)
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->button(device, button, is_press);
|
||||
int rc = ei_request_pointer_button(ei, device->id, button, is_press);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -927,7 +936,7 @@ int ei_send_pointer_scroll(struct ei_device *device, double x, double y)
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->scroll(device, x, y);
|
||||
int rc = ei_request_pointer_scroll(ei, device->id, x, y);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -942,7 +951,7 @@ int ei_send_pointer_scroll_stop(struct ei_device *device, double x, double y)
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->scroll_stop(device, x, y);
|
||||
int rc = ei_request_pointer_scroll_stop(ei, device->id, x, y, false);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -957,7 +966,7 @@ int ei_send_pointer_scroll_cancel(struct ei_device *device, double x, double y)
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->scroll_cancel(device, x, y);
|
||||
int rc = ei_request_pointer_scroll_stop(ei, device->id, x, y, true);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -973,7 +982,7 @@ int ei_send_pointer_scroll_discrete(struct ei_device *device, int32_t x, int32_t
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->scroll_discrete(device, x, y);
|
||||
int rc = ei_request_pointer_scroll_discrete(ei, device->id, x, y);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -989,7 +998,7 @@ ei_send_keyboard_key(struct ei_device *device, uint32_t key, bool is_press)
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->key(device, key, is_press);
|
||||
int rc = ei_request_keyboard_key(ei, device->id, key, is_press);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -1006,7 +1015,7 @@ ei_send_touch_down(struct ei_device *device, uint32_t tid,
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->touch_down(device, tid, x, y);
|
||||
int rc = ei_request_touch_down(ei, device->id, tid, x, y);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -1023,7 +1032,7 @@ ei_send_touch_motion(struct ei_device *device, uint32_t tid,
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->touch_motion(device, tid, x, y);
|
||||
int rc = ei_request_touch_motion(ei, device->id, tid, x, y);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -1039,7 +1048,7 @@ ei_send_touch_up(struct ei_device *device, uint32_t tid)
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
int rc = ei->requests->touch_up(device, tid);
|
||||
int rc = ei_request_touch_up(ei, device->id, tid);
|
||||
if (rc)
|
||||
ei_disconnect(ei);
|
||||
return rc;
|
||||
|
|
@ -1111,21 +1120,20 @@ handle_msg_stop_emulating(struct ei *ei, uint32_t deviceid)
|
|||
}
|
||||
|
||||
static int
|
||||
handle_msg_frame(struct ei *ei, uint32_t deviceid, uint64_t time)
|
||||
handle_msg_frame(struct ei *ei, uint32_t deviceid, uint32_t time, uint32_t micros)
|
||||
{
|
||||
DISCONNECT_IF_SENDER_CONTEXT(ei);
|
||||
|
||||
struct ei_device *device = ei_find_device(ei, deviceid);
|
||||
|
||||
if (device)
|
||||
return ei_device_event_frame(device, time);
|
||||
return ei_device_event_frame(device, ms2us(time) + micros);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_pointer_rel(struct ei *ei, uint32_t deviceid,
|
||||
double x, double y)
|
||||
handle_msg_pointer_rel(struct ei *ei, uint32_t deviceid, float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_SENDER_CONTEXT(ei);
|
||||
|
||||
|
|
@ -1138,8 +1146,7 @@ handle_msg_pointer_rel(struct ei *ei, uint32_t deviceid,
|
|||
}
|
||||
|
||||
static int
|
||||
handle_msg_pointer_abs(struct ei *ei, uint32_t deviceid,
|
||||
double x, double y)
|
||||
handle_msg_pointer_abs(struct ei *ei, uint32_t deviceid, float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_SENDER_CONTEXT(ei);
|
||||
|
||||
|
|
@ -1153,21 +1160,20 @@ handle_msg_pointer_abs(struct ei *ei, uint32_t deviceid,
|
|||
|
||||
static int
|
||||
handle_msg_pointer_button(struct ei *ei, uint32_t deviceid,
|
||||
uint32_t button, bool state)
|
||||
uint32_t button, uint32_t state)
|
||||
{
|
||||
DISCONNECT_IF_SENDER_CONTEXT(ei);
|
||||
|
||||
struct ei_device *device = ei_find_device(ei, deviceid);
|
||||
|
||||
if (device)
|
||||
return ei_device_event_pointer_button(device, button, state);
|
||||
return ei_device_event_pointer_button(device, button, !!state);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_pointer_scroll(struct ei *ei, uint32_t deviceid,
|
||||
double x, double y)
|
||||
handle_msg_pointer_scroll(struct ei *ei, uint32_t deviceid, float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_SENDER_CONTEXT(ei);
|
||||
|
||||
|
|
@ -1195,7 +1201,7 @@ handle_msg_pointer_scroll_discrete(struct ei *ei, uint32_t deviceid,
|
|||
|
||||
static int
|
||||
handle_msg_pointer_scroll_stop(struct ei *ei, uint32_t deviceid,
|
||||
bool x, bool y, bool is_cancel)
|
||||
uint32_t x, uint32_t y, uint32_t is_cancel)
|
||||
{
|
||||
DISCONNECT_IF_SENDER_CONTEXT(ei);
|
||||
|
||||
|
|
@ -1203,9 +1209,9 @@ handle_msg_pointer_scroll_stop(struct ei *ei, uint32_t deviceid,
|
|||
|
||||
if (device) {
|
||||
if (is_cancel)
|
||||
return ei_device_event_pointer_scroll_cancel(device, x, y);
|
||||
return ei_device_event_pointer_scroll_cancel(device, !!x, !!y);
|
||||
else
|
||||
return ei_device_event_pointer_scroll_stop(device, x, y);
|
||||
return ei_device_event_pointer_scroll_stop(device, !!x, !!y);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
|
@ -1213,21 +1219,21 @@ handle_msg_pointer_scroll_stop(struct ei *ei, uint32_t deviceid,
|
|||
|
||||
static int
|
||||
handle_msg_keyboard_key(struct ei *ei, uint32_t deviceid,
|
||||
uint32_t key, bool state)
|
||||
uint32_t key, uint32_t state)
|
||||
{
|
||||
DISCONNECT_IF_SENDER_CONTEXT(ei);
|
||||
|
||||
struct ei_device *device = ei_find_device(ei, deviceid);
|
||||
|
||||
if (device)
|
||||
return ei_device_event_keyboard_key(device, key, state);
|
||||
return ei_device_event_keyboard_key(device, key, !!state);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_touch_down(struct ei *ei, uint32_t deviceid,
|
||||
uint32_t touchid, double x, double y)
|
||||
uint32_t touchid, float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_SENDER_CONTEXT(ei);
|
||||
|
||||
|
|
@ -1241,7 +1247,7 @@ handle_msg_touch_down(struct ei *ei, uint32_t deviceid,
|
|||
|
||||
static int
|
||||
handle_msg_touch_motion(struct ei *ei, uint32_t deviceid,
|
||||
uint32_t touchid, double x, double y)
|
||||
uint32_t touchid, float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_SENDER_CONTEXT(ei);
|
||||
|
||||
|
|
@ -1298,25 +1304,25 @@ handle_msg_version_during_connection(struct ei *ei, uint32_t version)
|
|||
return ei_finish_set_socket(ei, ei->client_version);
|
||||
}
|
||||
|
||||
static const struct ei_proto_interface intf_state_backend = {
|
||||
static const struct ei_interface intf_state_backend = {
|
||||
.version = handle_msg_version_during_connection,
|
||||
/* Everything triggers -EPROTO */
|
||||
.connected = NULL,
|
||||
};
|
||||
|
||||
static const struct ei_proto_interface intf_state_version_query = {
|
||||
static const struct ei_interface intf_state_version_query = {
|
||||
.version = handle_msg_version_during_connection,
|
||||
/* Everything else triggers -EPROTO */
|
||||
.connected = NULL,
|
||||
};
|
||||
|
||||
static const struct ei_proto_interface intf_state_connecting = {
|
||||
static const struct ei_interface intf_state_connecting = {
|
||||
.connected = handle_msg_connected,
|
||||
.disconnected = handle_msg_disconnected,
|
||||
.version = handle_msg_version,
|
||||
};
|
||||
|
||||
static const struct ei_proto_interface intf_state_connected = {
|
||||
static const struct ei_interface intf_state_connected = {
|
||||
.disconnected = handle_msg_disconnected,
|
||||
.seat_added = handle_msg_seat_added,
|
||||
.seat_removed = handle_msg_seat_removed,
|
||||
|
|
@ -1333,20 +1339,20 @@ static const struct ei_proto_interface intf_state_connected = {
|
|||
/* events */
|
||||
.start_emulating = handle_msg_start_emulating,
|
||||
.stop_emulating = handle_msg_stop_emulating,
|
||||
.rel = handle_msg_pointer_rel,
|
||||
.abs = handle_msg_pointer_abs,
|
||||
.button = handle_msg_pointer_button,
|
||||
.scroll = handle_msg_pointer_scroll,
|
||||
.scroll_stop = handle_msg_pointer_scroll_stop,
|
||||
.scroll_discrete = handle_msg_pointer_scroll_discrete,
|
||||
.key = handle_msg_keyboard_key,
|
||||
.pointer_relative = handle_msg_pointer_rel,
|
||||
.pointer_absolute = handle_msg_pointer_abs,
|
||||
.pointer_button = handle_msg_pointer_button,
|
||||
.pointer_scroll = handle_msg_pointer_scroll,
|
||||
.pointer_scroll_stop = handle_msg_pointer_scroll_stop,
|
||||
.pointer_scroll_discrete = handle_msg_pointer_scroll_discrete,
|
||||
.keyboard_key = handle_msg_keyboard_key,
|
||||
.touch_down = handle_msg_touch_down,
|
||||
.touch_motion = handle_msg_touch_motion,
|
||||
.touch_up = handle_msg_touch_up,
|
||||
.frame = handle_msg_frame,
|
||||
};
|
||||
|
||||
static const struct ei_proto_interface *interfaces[] = {
|
||||
static const struct ei_interface *interfaces[] = {
|
||||
[EI_STATE_NEW] = NULL,
|
||||
[EI_STATE_BACKEND] = &intf_state_backend,
|
||||
[EI_STATE_VERSION_QUERY] = &intf_state_version_query,
|
||||
|
|
@ -1356,15 +1362,23 @@ static const struct ei_proto_interface *interfaces[] = {
|
|||
[EI_STATE_DISCONNECTED] = NULL,
|
||||
};
|
||||
|
||||
|
||||
const struct ei_interface *
|
||||
ei_get_interface(struct ei *ei)
|
||||
{
|
||||
assert(ei->state < ARRAY_LENGTH(interfaces));
|
||||
return interfaces[ei->state];
|
||||
}
|
||||
|
||||
static int
|
||||
connection_message_callback(struct brei_message *bmsg, void *userdata)
|
||||
lookup_object(uint32_t object_id, struct brei_object **object, void *userdata)
|
||||
{
|
||||
struct ei *ei = userdata;
|
||||
|
||||
assert(ei->state < ARRAY_LENGTH(interfaces));
|
||||
const struct ei_proto_interface *intf = interfaces[ei->state];
|
||||
assert(object_id == 0); /* We only have one object atm */
|
||||
|
||||
return ei_proto_handle_message(ei, intf, bmsg);
|
||||
*object = &ei->proto_object;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1373,7 +1387,7 @@ connection_dispatch(struct source *source, void *userdata)
|
|||
struct ei *ei = userdata;
|
||||
enum ei_state old_state = ei->state;
|
||||
|
||||
int rc = brei_dispatch(source_get_fd(source), connection_message_callback, ei);
|
||||
int rc = brei_dispatch(source_get_fd(source), lookup_object, ei);
|
||||
if (rc < 0) {
|
||||
brei_drain_fd(source_get_fd(source));
|
||||
ei_disconnect(ei);
|
||||
|
|
@ -1398,6 +1412,21 @@ connection_dispatch(struct source *source, void *userdata)
|
|||
states[ei->state]);
|
||||
}
|
||||
|
||||
int
|
||||
ei_send_message(struct ei *ei, uint32_t object_id,
|
||||
uint32_t opcode, const char *signature, size_t nargs, ...)
|
||||
{
|
||||
int fd = source_get_fd(ei->source);
|
||||
|
||||
log_debug(ei, "sending: %#x:%u signature '%s'", object_id, opcode, signature);
|
||||
|
||||
va_list args;
|
||||
va_start(args, nargs);
|
||||
int rc = brei_send_message(fd, object_id, opcode, signature, nargs, args);
|
||||
va_end(args);
|
||||
return rc < 0 ? rc : 0;
|
||||
}
|
||||
|
||||
int
|
||||
ei_set_socket(struct ei *ei, int fd)
|
||||
{
|
||||
|
|
@ -1416,23 +1445,23 @@ ei_set_socket(struct ei *ei, int fd)
|
|||
|
||||
if (ei->state == EI_STATE_BACKEND) {
|
||||
/* The server didn't send the version number, so request it. */
|
||||
rc = ei->requests->get_version(ei);
|
||||
rc = ei_request_get_version(ei);
|
||||
ei->state = EI_STATE_VERSION_QUERY;
|
||||
}
|
||||
}
|
||||
|
||||
source_unref(source);
|
||||
|
||||
return rc;
|
||||
return rc < 0 ? rc : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ei_finish_set_socket(struct ei *ei, uint32_t version)
|
||||
{
|
||||
int rc = ei->requests->connect(ei, version);
|
||||
int rc = ei_request_connect(ei, version, ei->name, ei->is_sender);
|
||||
|
||||
if (rc == 0) {
|
||||
rc = ei->requests->connect_done(ei);
|
||||
rc = ei_request_connect_done(ei);
|
||||
}
|
||||
if (rc == 0) {
|
||||
ei->state = EI_STATE_CONNECTING;
|
||||
|
|
@ -1442,7 +1471,7 @@ ei_finish_set_socket(struct ei *ei, uint32_t version)
|
|||
ei_disconnect(ei);
|
||||
}
|
||||
|
||||
return rc;
|
||||
return rc < 0 ? rc : 0;
|
||||
}
|
||||
|
||||
_public_ void
|
||||
|
|
|
|||
|
|
@ -37,10 +37,12 @@
|
|||
#include "util-strings.h"
|
||||
#include "util-structs.h"
|
||||
#include "util-tristate.h"
|
||||
#include "util-time.h"
|
||||
|
||||
#include "libeis-private.h"
|
||||
#include "libeis-proto.h"
|
||||
#include "brei-shared.h"
|
||||
#include "eis-proto.h"
|
||||
|
||||
DEFINE_TRISTATE(started, finished, connected);
|
||||
|
||||
|
|
@ -77,6 +79,12 @@ eis_client_get_context(struct eis_client *client)
|
|||
return eis_client_parent(client);
|
||||
}
|
||||
|
||||
const struct brei_object *
|
||||
eis_client_get_proto_object(struct eis_client *client)
|
||||
{
|
||||
return &client->proto_object;
|
||||
}
|
||||
|
||||
struct eis_client *
|
||||
eis_client_get_client(struct eis_client *client)
|
||||
{
|
||||
|
|
@ -136,89 +144,100 @@ eis_client_find_seat(struct eis_client *client, uint32_t seatid)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
eis_client_send_message(struct eis_client *client, uint32_t object_id,
|
||||
uint32_t opcode, const char *signature, size_t nargs, ...)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
int fd = source_get_fd(client->source);
|
||||
|
||||
log_debug(eis, "sending: %#x:%u signature '%s'", object_id, opcode, signature);
|
||||
|
||||
va_list args;
|
||||
va_start(args, nargs);
|
||||
int rc = brei_send_message(fd, object_id, opcode, signature, nargs, args);
|
||||
va_end(args);
|
||||
return rc < 0 ? rc : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_version(struct eis_client *client, uint32_t version)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
return eis->requests->version(client, version);
|
||||
return eis_event_version(client, version);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_disconnect(struct eis_client *client)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
return eis->requests->disconnected(client);
|
||||
return eis_event_disconnected(client);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_connect(struct eis_client *client)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
return eis->requests->connected(client);
|
||||
return eis_event_connected(client);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_seat_added(struct eis_client *client, struct eis_seat *seat)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
return eis->requests->seat_added(seat);
|
||||
return eis_event_seat_added(client, seat->id, seat->capabilities_mask, seat->name);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_seat_removed(struct eis_client *client, struct eis_seat *seat)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
return eis->requests->seat_removed(seat);
|
||||
return eis_event_seat_removed(client, seat->id);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_device_added(struct eis_client *client, struct eis_device *device)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
int rc = eis->requests->device_added(device);
|
||||
struct eis_seat *seat = eis_device_get_seat(device);
|
||||
int rc = eis_event_device_added(client, device->id, device->capabilities,
|
||||
device->name, seat->id,
|
||||
device->type, device->width, device->height);
|
||||
|
||||
if (rc >= 0 && device->keymap)
|
||||
rc = eis->requests->device_keymap(device);
|
||||
rc = eis_event_device_keymap(client, device->id, device->keymap->type, device->keymap->size, device->keymap->fd);
|
||||
|
||||
if (rc >= 0 && device->type == EIS_DEVICE_TYPE_VIRTUAL) {
|
||||
struct eis_region *r;
|
||||
list_for_each(r, &device->regions, link) {
|
||||
rc = eis->requests->device_region(device, r);
|
||||
rc = eis_event_device_region(client, device->id, r->x, r->y, r->width, r->height, r->physical_scale);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc >= 0)
|
||||
rc = eis->requests->device_done(device);
|
||||
rc = eis_event_device_done(client, device->id);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_device_removed(struct eis_client *client, struct eis_device *device)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
return eis->requests->device_removed(device);
|
||||
return eis_event_device_removed(client, device->id);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_device_paused(struct eis_client *client, struct eis_device *device)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
return eis->requests->device_paused(device);
|
||||
return eis_event_device_paused(client, device->id);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_device_resumed(struct eis_client *client, struct eis_device *device)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
return eis->requests->device_resumed(device);
|
||||
return eis_event_device_resumed(client, device->id);
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_keyboard_modifiers(struct eis_client *client, struct eis_device *device,
|
||||
const struct eis_xkb_modifiers *mods)
|
||||
{
|
||||
struct eis *eis = eis_client_get_context(client);
|
||||
return eis->requests->keyboard_modifiers(device, mods);
|
||||
return eis_event_keyboard_modifiers(client, device->id,
|
||||
mods->depressed, mods->locked,
|
||||
mods->latched, mods->group);
|
||||
}
|
||||
|
||||
_public_ void
|
||||
|
|
@ -329,21 +348,21 @@ client_msg_stop_emulating(struct eis_client *client, uint32_t deviceid)
|
|||
}
|
||||
|
||||
static int
|
||||
client_msg_frame(struct eis_client *client, uint32_t deviceid, uint64_t time)
|
||||
client_msg_frame(struct eis_client *client, uint32_t deviceid, uint32_t time, uint32_t micros)
|
||||
{
|
||||
DISCONNECT_IF_RECEIVER_CONTEXT(client);
|
||||
|
||||
struct eis_device *device = eis_client_find_device(client, deviceid);
|
||||
|
||||
if (device)
|
||||
return eis_device_event_frame(device, time);
|
||||
return eis_device_event_frame(device, ms2us(time) + micros);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_pointer_rel(struct eis_client *client, uint32_t deviceid,
|
||||
double x, double y)
|
||||
float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_RECEIVER_CONTEXT(client);
|
||||
|
||||
|
|
@ -357,7 +376,7 @@ client_msg_pointer_rel(struct eis_client *client, uint32_t deviceid,
|
|||
|
||||
static int
|
||||
client_msg_pointer_abs(struct eis_client *client, uint32_t deviceid,
|
||||
double x, double y)
|
||||
float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_RECEIVER_CONTEXT(client);
|
||||
|
||||
|
|
@ -371,21 +390,21 @@ client_msg_pointer_abs(struct eis_client *client, uint32_t deviceid,
|
|||
|
||||
static int
|
||||
client_msg_pointer_button(struct eis_client *client, uint32_t deviceid,
|
||||
uint32_t button, bool state)
|
||||
uint32_t button, uint32_t state)
|
||||
{
|
||||
DISCONNECT_IF_RECEIVER_CONTEXT(client);
|
||||
|
||||
struct eis_device *device = eis_client_find_device(client, deviceid);
|
||||
|
||||
if (device)
|
||||
return eis_device_event_pointer_button(device, button, state);
|
||||
return eis_device_event_pointer_button(device, button, !!state);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_pointer_scroll(struct eis_client *client, uint32_t deviceid,
|
||||
double x, double y)
|
||||
float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_RECEIVER_CONTEXT(client);
|
||||
|
||||
|
|
@ -413,7 +432,7 @@ client_msg_pointer_scroll_discrete(struct eis_client *client, uint32_t deviceid,
|
|||
|
||||
static int
|
||||
client_msg_pointer_scroll_stop(struct eis_client *client, uint32_t deviceid,
|
||||
bool x, bool y, bool is_cancel)
|
||||
uint32_t x, uint32_t y, uint32_t is_cancel)
|
||||
{
|
||||
DISCONNECT_IF_RECEIVER_CONTEXT(client);
|
||||
|
||||
|
|
@ -421,9 +440,9 @@ client_msg_pointer_scroll_stop(struct eis_client *client, uint32_t deviceid,
|
|||
|
||||
if (device) {
|
||||
if (is_cancel)
|
||||
return eis_device_event_pointer_scroll_cancel(device, x, y);
|
||||
return eis_device_event_pointer_scroll_cancel(device, !!x, !!y);
|
||||
else
|
||||
return eis_device_event_pointer_scroll_stop(device, x, y);
|
||||
return eis_device_event_pointer_scroll_stop(device, !!x, !!y);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
|
@ -431,21 +450,21 @@ client_msg_pointer_scroll_stop(struct eis_client *client, uint32_t deviceid,
|
|||
|
||||
static int
|
||||
client_msg_keyboard_key(struct eis_client *client, uint32_t deviceid,
|
||||
uint32_t key, bool state)
|
||||
uint32_t key, uint32_t state)
|
||||
{
|
||||
DISCONNECT_IF_RECEIVER_CONTEXT(client);
|
||||
|
||||
struct eis_device *device = eis_client_find_device(client, deviceid);
|
||||
|
||||
if (device)
|
||||
return eis_device_event_keyboard_key(device, key, state);
|
||||
return eis_device_event_keyboard_key(device, key, !!state);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
client_msg_touch_down(struct eis_client *client, uint32_t deviceid,
|
||||
uint32_t touchid, double x, double y)
|
||||
uint32_t touchid, float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_RECEIVER_CONTEXT(client);
|
||||
|
||||
|
|
@ -459,7 +478,7 @@ client_msg_touch_down(struct eis_client *client, uint32_t deviceid,
|
|||
|
||||
static int
|
||||
client_msg_touch_motion(struct eis_client *client, uint32_t deviceid,
|
||||
uint32_t touchid, double x, double y)
|
||||
uint32_t touchid, float x, float y)
|
||||
{
|
||||
DISCONNECT_IF_RECEIVER_CONTEXT(client);
|
||||
|
||||
|
|
@ -486,7 +505,7 @@ client_msg_touch_up(struct eis_client *client, uint32_t deviceid, uint32_t touch
|
|||
|
||||
static int
|
||||
client_msg_connect(struct eis_client *client, uint32_t version,
|
||||
const char *name, bool is_sender)
|
||||
const char *name, uint32_t is_sender)
|
||||
{
|
||||
if (client->version > EIS_PROTOCOL_VERSION)
|
||||
return -EPROTO;
|
||||
|
|
@ -496,7 +515,7 @@ client_msg_connect(struct eis_client *client, uint32_t version,
|
|||
if (client->name == NULL)
|
||||
client->name = xstrdup(name);
|
||||
|
||||
client->is_sender = is_sender;
|
||||
client->is_sender = !!is_sender;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -522,7 +541,7 @@ client_msg_get_version(struct eis_client *client)
|
|||
return client_send_version(client, EI_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
static const struct eis_proto_interface intf_state_new = {
|
||||
static const struct eis_interface intf_state_new = {
|
||||
.connect = client_msg_connect,
|
||||
.connect_done = client_msg_connect_done,
|
||||
.disconnect = client_msg_disconnect,
|
||||
|
|
@ -530,12 +549,12 @@ static const struct eis_proto_interface intf_state_new = {
|
|||
};
|
||||
|
||||
/* Client is waiting for us, shouldn't send anything except disconnect */
|
||||
static const struct eis_proto_interface intf_state_connecting = {
|
||||
static const struct eis_interface intf_state_connecting = {
|
||||
.disconnect = client_msg_disconnect,
|
||||
.get_version = client_msg_get_version,
|
||||
};
|
||||
|
||||
static const struct eis_proto_interface intf_state_connected = {
|
||||
static const struct eis_interface intf_state_connected = {
|
||||
.disconnect = client_msg_disconnect,
|
||||
.bind_seat = client_msg_bind_seat,
|
||||
.close_device = client_msg_close_device,
|
||||
|
|
@ -544,35 +563,42 @@ static const struct eis_proto_interface intf_state_connected = {
|
|||
/* events */
|
||||
.start_emulating = client_msg_start_emulating,
|
||||
.stop_emulating = client_msg_stop_emulating,
|
||||
.rel = client_msg_pointer_rel,
|
||||
.abs = client_msg_pointer_abs,
|
||||
.button = client_msg_pointer_button,
|
||||
.scroll = client_msg_pointer_scroll,
|
||||
.scroll_stop = client_msg_pointer_scroll_stop,
|
||||
.scroll_discrete = client_msg_pointer_scroll_discrete,
|
||||
.key = client_msg_keyboard_key,
|
||||
.pointer_relative = client_msg_pointer_rel,
|
||||
.pointer_absolute = client_msg_pointer_abs,
|
||||
.pointer_button = client_msg_pointer_button,
|
||||
.pointer_scroll = client_msg_pointer_scroll,
|
||||
.pointer_scroll_stop = client_msg_pointer_scroll_stop,
|
||||
.pointer_scroll_discrete = client_msg_pointer_scroll_discrete,
|
||||
.keyboard_key = client_msg_keyboard_key,
|
||||
.touch_down = client_msg_touch_down,
|
||||
.touch_motion = client_msg_touch_motion,
|
||||
.touch_up = client_msg_touch_up,
|
||||
.frame = client_msg_frame,
|
||||
};
|
||||
|
||||
static const struct eis_proto_interface *interfaces[] = {
|
||||
static const struct eis_interface *interfaces[] = {
|
||||
[EIS_CLIENT_STATE_NEW] = &intf_state_new,
|
||||
[EIS_CLIENT_STATE_CONNECTING] = &intf_state_connecting,
|
||||
[EIS_CLIENT_STATE_CONNECTED] = &intf_state_connected,
|
||||
[EIS_CLIENT_STATE_DISCONNECTED] = NULL,
|
||||
};
|
||||
|
||||
const struct eis_interface *
|
||||
eis_client_get_interface(struct eis_client *client)
|
||||
{
|
||||
assert(client->state < ARRAY_LENGTH(interfaces));
|
||||
return interfaces[client->state];
|
||||
}
|
||||
|
||||
static int
|
||||
client_message_callback(struct brei_message *bmsg, void *userdata)
|
||||
lookup_object(uint32_t object_id, struct brei_object **object, void *userdata)
|
||||
{
|
||||
struct eis_client *client = userdata;
|
||||
|
||||
assert(client->state < ARRAY_LENGTH(interfaces));
|
||||
const struct eis_proto_interface *intf = interfaces[client->state];
|
||||
assert(object_id == 0); /* We only have one object atm */
|
||||
|
||||
return eis_proto_handle_message(client, intf, bmsg);
|
||||
*object = &client->proto_object;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -581,7 +607,7 @@ client_dispatch(struct source *source, void *userdata)
|
|||
_unref_(eis_client) *client = eis_client_ref(userdata);
|
||||
enum eis_client_state old_state = client->state;
|
||||
|
||||
int rc = brei_dispatch(source_get_fd(source), client_message_callback, client);
|
||||
int rc = brei_dispatch(source_get_fd(source), lookup_object, client);
|
||||
if (rc < 0) {
|
||||
brei_drain_fd(source_get_fd(source));
|
||||
eis_client_disconnect(client);
|
||||
|
|
@ -616,6 +642,10 @@ eis_client_new(struct eis *eis, int fd)
|
|||
static uint32_t client_id;
|
||||
struct eis_client *client = eis_client_create(&eis->object);
|
||||
|
||||
client->proto_object.id = 0;
|
||||
client->proto_object.implementation = client;
|
||||
client->proto_object.interface = &eis_proto_interface;
|
||||
|
||||
client->is_sender = true;
|
||||
client->id = ++client_id;
|
||||
list_init(&client->seats);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "libeis.h"
|
||||
#include "brei-shared.h"
|
||||
|
||||
#include "util-object.h"
|
||||
#include "util-list.h"
|
||||
|
|
@ -38,6 +39,8 @@ enum eis_client_state {
|
|||
|
||||
struct eis_client {
|
||||
struct object object;
|
||||
struct brei_object proto_object;
|
||||
|
||||
void *user_data;
|
||||
struct list link;
|
||||
struct source *source;
|
||||
|
|
@ -62,9 +65,19 @@ eis_client_new(struct eis *eis, int fd);
|
|||
struct eis_client *
|
||||
eis_client_get_client(struct eis_client *client);
|
||||
|
||||
const struct eis_interface *
|
||||
eis_client_get_interface(struct eis_client *client);
|
||||
|
||||
const struct brei_object *
|
||||
eis_client_get_proto_object(struct eis_client *client);
|
||||
|
||||
void
|
||||
eis_add_client(struct eis *eis, struct eis_client *client);
|
||||
|
||||
int
|
||||
eis_client_send_message(struct eis_client *client, uint32_t object_id,
|
||||
uint32_t opcode, const char *signature, size_t nargs, ...);
|
||||
|
||||
void
|
||||
eis_client_add_seat(struct eis_client *client, struct eis_seat *seat);
|
||||
void
|
||||
|
|
|
|||
|
|
@ -29,9 +29,10 @@
|
|||
#include "util-macros.h"
|
||||
#include "util-bits.h"
|
||||
#include "util-io.h"
|
||||
#include "util-time.h"
|
||||
|
||||
#include "libeis-private.h"
|
||||
#include "libeis-proto.h"
|
||||
#include "eis-proto.h"
|
||||
|
||||
_public_
|
||||
OBJECT_IMPLEMENT_REF(eis_keymap);
|
||||
|
|
@ -309,13 +310,13 @@ eis_device_has_capability(struct eis_device *device,
|
|||
}
|
||||
|
||||
#define handle_request_noargs(device_, func_) { \
|
||||
struct eis *eis = eis_device_get_context(device); \
|
||||
eis->requests->func_(device_, device->id); \
|
||||
struct eis_client *client = eis_device_get_client(device); \
|
||||
eis_event_##func_(client, device->id); \
|
||||
}
|
||||
|
||||
#define handle_request(device_, func_, ...) { \
|
||||
struct eis *eis = eis_device_get_context(device); \
|
||||
eis->requests->func_(device_, device->id, __VA_ARGS__); \
|
||||
struct eis_client *client = eis_device_get_client(device); \
|
||||
eis_event_##func_(client, device->id, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -378,7 +379,7 @@ eis_device_pointer_motion(struct eis_device *device,
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
handle_request(device, rel, x, y);
|
||||
handle_request(device, pointer_relative, x, y);
|
||||
}
|
||||
|
||||
_public_ void
|
||||
|
|
@ -403,7 +404,7 @@ eis_device_pointer_motion_absolute(struct eis_device *device,
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
handle_request(device, abs, x, y);
|
||||
handle_request(device, pointer_absolute, x, y);
|
||||
}
|
||||
|
||||
_public_ void
|
||||
|
|
@ -429,7 +430,7 @@ eis_device_pointer_button(struct eis_device *device,
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
handle_request(device, button, button, is_press);
|
||||
handle_request(device, pointer_button, button, is_press);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -462,7 +463,7 @@ eis_device_pointer_scroll(struct eis_device *device,
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
handle_request(device, scroll, x, y);
|
||||
handle_request(device, pointer_scroll, x, y);
|
||||
}
|
||||
|
||||
_public_ void
|
||||
|
|
@ -489,7 +490,7 @@ eis_device_pointer_scroll_stop(struct eis_device *device, bool x, bool y)
|
|||
|
||||
if (x || y) {
|
||||
device->send_frame_event = true;
|
||||
handle_request(device, scroll_stop, x, y, false);
|
||||
handle_request(device, pointer_scroll_stop, x, y, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -521,7 +522,7 @@ eis_device_pointer_scroll_cancel(struct eis_device *device, bool x, bool y)
|
|||
|
||||
if (x || y) {
|
||||
device->send_frame_event = true;
|
||||
handle_request(device, scroll_stop, x, y, true);
|
||||
handle_request(device, pointer_scroll_stop, x, y, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -542,7 +543,7 @@ eis_device_pointer_scroll_discrete(struct eis_device *device,
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
handle_request(device, scroll_discrete, x, y);
|
||||
handle_request(device, pointer_scroll_discrete, x, y);
|
||||
}
|
||||
|
||||
_public_ void
|
||||
|
|
@ -560,7 +561,7 @@ eis_device_keyboard_key(struct eis_device *device,
|
|||
|
||||
device->send_frame_event = true;
|
||||
|
||||
handle_request(device, key, key, is_press);
|
||||
handle_request(device, keyboard_key, key, is_press);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -683,7 +684,7 @@ eis_device_frame(struct eis_device *device, uint64_t time)
|
|||
device->send_frame_event = false;
|
||||
|
||||
|
||||
handle_request(device, frame, time);
|
||||
handle_request(device, frame, us2ms(time), time % 1000);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "util-object.h"
|
||||
|
||||
#include "libeis.h"
|
||||
#include "brei-shared.h"
|
||||
#include "util-macros.h"
|
||||
#include "util-list.h"
|
||||
#include "util-sources.h"
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@
|
|||
#include "util-time.h"
|
||||
|
||||
#include "libeis.h"
|
||||
#include "libeis-proto.h"
|
||||
#include "libeis-private.h"
|
||||
#include "eis-proto.h"
|
||||
|
||||
_Static_assert(sizeof(enum eis_device_capability) == sizeof(int), "Invalid enum size");
|
||||
_Static_assert(sizeof(enum eis_keymap_type) == sizeof(int), "Invalid enum size");
|
||||
|
|
@ -78,8 +78,6 @@ eis_new(void *user_data)
|
|||
{
|
||||
_unref_(eis) *eis = eis_create(NULL);
|
||||
|
||||
eis->requests = eis_proto_get_requests();
|
||||
|
||||
list_init(&eis->clients);
|
||||
list_init(&eis->event_queue);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ test('unit-tests-eis',
|
|||
src_libeis,
|
||||
include_directories: [inc_src, inc_proto, inc_builddir],
|
||||
c_args: ['-D_enable_tests_'],
|
||||
dependencies: [dep_unittest, dep_libutil, dep_protobuf]))
|
||||
dependencies: [dep_unittest, dep_libutil]))
|
||||
|
||||
if build_oeffis
|
||||
test('unit-tests-oeffis',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue