mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-01-04 23:40:14 +01:00
protocol: make the connection setup the zero object with a proper handover
This changes the initial connection negotiation to have the ei_connection_setup as the pre-existing object id 0. Once the client has sent all the data to set up the connection, the EIS implementation replies with a new object ID that is the ei_connection protocol object, i.e. the main object. This allows for version negotiation of our main protocol object.
This commit is contained in:
parent
23433d3aff
commit
0a347f433f
12 changed files with 302 additions and 213 deletions
|
|
@ -37,7 +37,7 @@
|
|||
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.
|
||||
0 is reserved for the special "ei_connection_setup" 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.
|
||||
|
|
@ -45,125 +45,42 @@
|
|||
|
||||
Types:
|
||||
- 'uint': a 32-bit unsigned integer
|
||||
- 'uint': a 32-bit signed integer
|
||||
- 'int': 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:
|
||||
"hello" is of length 6 but is zero-padded to 8 bytes and with the 4-byte
|
||||
length field thus takes 12 bytes in total. Full (le) encoding:
|
||||
[0x06, 0x00, 0x00, 0x00, 'h', 'e', 'l', 'l', 'o', '\0', '\0\, '\0']
|
||||
- 'new_id': an object id allocated by the caller. Client-allocated IDs begin
|
||||
at 1 and must be less than 0xff000000.
|
||||
IDs allocated by the EIS implementation start at and must not be less
|
||||
than 0xff000000.
|
||||
- 'object_id': a previously allocated object id
|
||||
|
||||
The initial connection is a two-step process:
|
||||
An ei_connection_setup object with the special ID 0 is guaranteed to
|
||||
exists. The client must send the appropriate requests to set up
|
||||
its connection, followed by the .done request. The server replies
|
||||
by creating the ei_connection object with the client-requested version
|
||||
(or any lower version) that is the connection for the remainder of this
|
||||
client.
|
||||
|
||||
-->
|
||||
|
||||
<interface name="ei_connection" 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="sync" since="1">
|
||||
<description summary="asynchronous roundtrip">
|
||||
The sync request asks the EIS implementation to emit the 'done' event
|
||||
on the returned ei_callback object. Since requests are
|
||||
handled in-order and events are delivered in-order, this can
|
||||
be used as a synchronization point to ensure all previous requests and the
|
||||
resulting events have been handled.
|
||||
|
||||
The object returned by this request will be destroyed by the
|
||||
EIS implementation after the callback is fired and as such the client must not
|
||||
attempt to use it after that point.
|
||||
|
||||
<!-- FIXME: this needs to be something useful, but we don't have anything
|
||||
useful to send yet -->
|
||||
The callback_data passed in the callback is always zero.
|
||||
</description>
|
||||
<arg name="callback" type="new_id" interface="ei_callback"
|
||||
summary="callback object for the sync request"/>
|
||||
</request>
|
||||
|
||||
<request name="disconnect">
|
||||
</request>
|
||||
|
||||
<event name="connection_setup">
|
||||
<description summary="initial connection setup">
|
||||
Provides the client with an object to initialize and setup the connection.
|
||||
This event is sent immediately after the client connects to the EIS
|
||||
implementation.
|
||||
|
||||
A client should configure itself through that object, if applicable,
|
||||
and complete this configuration with the ei_connection_setup.done event.
|
||||
The object returned by this request will be destroyed by the
|
||||
EIS implementation after that done event and a client must not
|
||||
attempt to use it after that point.
|
||||
|
||||
The version sent by the server is the highest supported version
|
||||
of the connection setup interface. A client must only use
|
||||
requests supported by that version (or any lower version).
|
||||
</description>
|
||||
<arg name="setup" type="new_id" interface="ei_connection_setup"
|
||||
summary="the connection setup object" />
|
||||
<arg name="version" type="uint" summary="the version of the connection setup object"/>
|
||||
</event>
|
||||
|
||||
<enum name="disconnect_reason">
|
||||
<description summary="disconnection reason">
|
||||
A reason why a client was disconnected.
|
||||
</description>
|
||||
<entry name="disconnected" value="0" help="client was purposely disconnected"/>
|
||||
<entry name="error" value="1" help="an error caused the disconnection"/>
|
||||
</enum>
|
||||
|
||||
<event name="disconnected">
|
||||
<description summary="disconnection event">
|
||||
This event may be sent by the EIS implementation immediately before
|
||||
the client is disconnected.
|
||||
|
||||
Where a client is disconnected by EIS directly, the reason is
|
||||
disconnect_reason.disconnected and the explanation is NULL.
|
||||
|
||||
Where a client is disconnected due to some invalid request or other
|
||||
protocol error, the reason is disconnect_reason.error and
|
||||
explanation may contain a string explaining why. This string is
|
||||
intended to help debugging only and is not guaranteed to stay constant.
|
||||
|
||||
There is no guarantee this event is sent - the connection may be closed
|
||||
without a disconnection event.
|
||||
</description>
|
||||
<arg name="reason" type="uint" enum="disconnect_reason"/>
|
||||
<arg name="explanation" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="seat" since="1">
|
||||
<description summary="Seat presence notification">
|
||||
Notification that a new seat has been added.
|
||||
|
||||
The interface version is equal or less to the client-supported
|
||||
version in ei_connection_setup.interface for the "ei_seat"
|
||||
interface.
|
||||
</description>
|
||||
<arg name="seat" type="new_id" interface="ei_seat"/>
|
||||
<arg name="version" type="uint" summary="the interface version"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="ei_callback" version="1">
|
||||
<description summary="callback object">
|
||||
Clients can handle the 'done' event to get notified when
|
||||
the related request is done.
|
||||
</description>
|
||||
|
||||
<event name="done" type="destructor">
|
||||
<description summary="done event">
|
||||
Notify the client when the related request is done.
|
||||
</description>
|
||||
<arg name="callback_data" type="uint" summary="request-specific data for the callback"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="ei_connection_setup" version="1">
|
||||
<description summary="connection setup object">
|
||||
This is a special interface to setup the client as seen by the EIS
|
||||
implementation. The object for this interface has the fixed object
|
||||
id 0 and only exists until the connection has been set up, see the
|
||||
ei_connection_setup.connection event.
|
||||
|
||||
Once set up, the connection setup hands over to the main
|
||||
ei_connection object which is the top-level object for all future
|
||||
requests and events.
|
||||
</description>
|
||||
|
||||
<request name="done" since="1">
|
||||
|
|
@ -220,6 +137,129 @@
|
|||
<arg name="name" type="string" summary="the interface name"/>
|
||||
<arg name="version" type="uint" summary="the interface version"/>
|
||||
</request>
|
||||
|
||||
<event name="version" since="1">
|
||||
<description summary="the connection setup version">
|
||||
The highest supported version of this interface
|
||||
by the EIS implementation. Any requests
|
||||
send by the client must be provided in this version
|
||||
or any lower version.
|
||||
|
||||
This event is sent immediately after connection. A client
|
||||
should not issue any requests until processing this version.
|
||||
|
||||
Note that the EIS implementation assumes that the supported
|
||||
client version of this interface is 1 until the client announces
|
||||
a higher version of this interface in the
|
||||
ei_connection_setup.interface request.
|
||||
</description>
|
||||
<arg name="version" type="uint"
|
||||
summary="the highest version supported by the EIS implementation"/>
|
||||
</event>
|
||||
|
||||
<event name="connection">
|
||||
<description summary="the core connection object">
|
||||
Provides the client with the connection object that is the top-level
|
||||
object for all future requests and events.
|
||||
This event is sent immediately after the client sends the
|
||||
ei_connection_setup.done request to the EIS implementation.
|
||||
|
||||
The ei_connection_setup object will be destroyed by the
|
||||
EIS implementation immediately after this event has been sent, a
|
||||
client must not attempt to use it after that point.
|
||||
|
||||
The version sent by the server is the version of the ei_connection
|
||||
interface as announced by ei_connection_setup.interface, or any
|
||||
lower version.
|
||||
</description>
|
||||
<arg name="connection" type="new_id" interface="ei_connection"
|
||||
summary="the connection object" />
|
||||
<arg name="version" type="uint" summary="the version of the connection object"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="ei_connection" 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="sync" since="1">
|
||||
<description summary="asynchronous roundtrip">
|
||||
The sync request asks the EIS implementation to emit the 'done' event
|
||||
on the returned ei_callback object. Since requests are
|
||||
handled in-order and events are delivered in-order, this can
|
||||
be used as a synchronization point to ensure all previous requests and the
|
||||
resulting events have been handled.
|
||||
|
||||
The object returned by this request will be destroyed by the
|
||||
EIS implementation after the callback is fired and as such the client must not
|
||||
attempt to use it after that point.
|
||||
|
||||
<!-- FIXME: this needs to be something useful, but we don't have anything
|
||||
useful to send yet -->
|
||||
The callback_data passed in the callback is always zero.
|
||||
</description>
|
||||
<arg name="callback" type="new_id" interface="ei_callback"
|
||||
summary="callback object for the sync request"/>
|
||||
</request>
|
||||
|
||||
<request name="disconnect">
|
||||
</request>
|
||||
|
||||
<enum name="disconnect_reason">
|
||||
<description summary="disconnection reason">
|
||||
A reason why a client was disconnected.
|
||||
</description>
|
||||
<entry name="disconnected" value="0" help="client was purposely disconnected"/>
|
||||
<entry name="error" value="1" help="an error caused the disconnection"/>
|
||||
</enum>
|
||||
|
||||
<event name="disconnected">
|
||||
<description summary="disconnection event">
|
||||
This event may be sent by the EIS implementation immediately before
|
||||
the client is disconnected.
|
||||
|
||||
Where a client is disconnected by EIS directly, the reason is
|
||||
disconnect_reason.disconnected and the explanation is NULL.
|
||||
|
||||
Where a client is disconnected due to some invalid request or other
|
||||
protocol error, the reason is disconnect_reason.error and
|
||||
explanation may contain a string explaining why. This string is
|
||||
intended to help debugging only and is not guaranteed to stay constant.
|
||||
|
||||
There is no guarantee this event is sent - the connection may be closed
|
||||
without a disconnection event.
|
||||
</description>
|
||||
<arg name="reason" type="uint" enum="disconnect_reason"/>
|
||||
<arg name="explanation" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="seat" since="1">
|
||||
<description summary="Seat presence notification">
|
||||
Notification that a new seat has been added.
|
||||
|
||||
The interface version is equal or less to the client-supported
|
||||
version in ei_connection_setup.interface for the "ei_seat"
|
||||
interface.
|
||||
</description>
|
||||
<arg name="seat" type="new_id" interface="ei_seat"/>
|
||||
<arg name="version" type="uint" summary="the interface version"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="ei_callback" version="1">
|
||||
<description summary="callback object">
|
||||
Clients can handle the 'done' event to get notified when
|
||||
the related request is done.
|
||||
</description>
|
||||
|
||||
<event name="done" type="destructor">
|
||||
<description summary="done event">
|
||||
Notify the client when the related request is done.
|
||||
</description>
|
||||
<arg name="callback_data" type="uint" summary="request-specific data for the callback"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="ei_seat" version="1">
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "util-mem.h"
|
||||
#include "util-io.h"
|
||||
#include "util-strings.h"
|
||||
#include "util-version.h"
|
||||
|
||||
#include "libei-private.h"
|
||||
#include "ei-proto.h"
|
||||
|
|
@ -67,8 +68,82 @@ ei_connection_setup_get_version(struct ei_connection_setup *connection_setup)
|
|||
return connection_setup->proto_object.version;
|
||||
}
|
||||
|
||||
static int
|
||||
ei_connection_setup_initialize(struct ei_connection_setup *setup, uint32_t version)
|
||||
{
|
||||
struct ei *ei = ei_connection_setup_get_context(setup);
|
||||
|
||||
if (version >= EI_CONNECTION_SETUP_REQUEST_TYPE_SINCE_VERSION)
|
||||
ei_connection_setup_request_type(setup,
|
||||
ei->is_sender ?
|
||||
EI_CONNECTION_SETUP_CONTEXT_TYPE_SENDER :
|
||||
EI_CONNECTION_SETUP_CONTEXT_TYPE_RECEIVER);
|
||||
|
||||
if (version >= EI_CONNECTION_SETUP_REQUEST_NAME_SINCE_VERSION)
|
||||
ei_connection_setup_request_name(setup, ei->name);
|
||||
|
||||
if (version >= EI_CONNECTION_SETUP_REQUEST_INTERFACE_SINCE_VERSION) {
|
||||
ei_connection_setup_request_interface(setup, "ei_connection_setup", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_connection", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_callback", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_seat", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_device", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_pointer", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_keyboard", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_touchscreen", VERSION_V(1));
|
||||
}
|
||||
|
||||
ei_connection_setup_request_done(setup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_version(struct ei_connection_setup *setup, uint32_t version)
|
||||
{
|
||||
uint32_t min_version = min(version, setup->proto_object.version);
|
||||
setup->proto_object.version = min_version;
|
||||
|
||||
/* Now send all the bits we need to send */
|
||||
ei_connection_setup_initialize(setup, version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
connected(struct ei_connection *connection, void *user_data)
|
||||
{
|
||||
struct ei *ei = ei_connection_get_context(connection);
|
||||
|
||||
/* If we get here, the server didn't immediately disconnect us */
|
||||
if (ei->state == EI_STATE_DISCONNECTED)
|
||||
return;
|
||||
|
||||
ei_connected(ei);
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_connection(struct ei_connection_setup *setup, uint32_t id, uint32_t version)
|
||||
{
|
||||
struct ei *ei = ei_connection_setup_get_context(setup);
|
||||
assert(setup == ei->connection_setup);
|
||||
/* we're done with our connection setup, drop it */
|
||||
ei_connection_setup_unref(steal(&ei->connection_setup));
|
||||
|
||||
ei->connection = ei_connection_new(ei, id, version);
|
||||
ei->state = EI_STATE_CONNECTING;
|
||||
|
||||
/* Send a sync on the connection - EIS should immediately send a
|
||||
* disconnect event where applicable, so if we get through to our
|
||||
* sync callback, we didn't immediately get disconnected */
|
||||
ei_connection_sync(ei->connection, connected, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ei_connection_setup_interface interface = {
|
||||
/* no events */
|
||||
.version = handle_msg_version,
|
||||
.connection = handle_msg_connection,
|
||||
};
|
||||
|
||||
const struct ei_connection_setup_interface *
|
||||
|
|
@ -77,11 +152,12 @@ ei_connection_setup_get_interface(struct ei_connection_setup *connection_setup)
|
|||
}
|
||||
|
||||
struct ei_connection_setup *
|
||||
ei_connection_setup_new(struct ei *ei, uint32_t id, uint32_t version)
|
||||
ei_connection_setup_new(struct ei *ei, uint32_t version)
|
||||
{
|
||||
struct ei_connection_setup *connection_setup = ei_connection_setup_create(&ei->object);
|
||||
|
||||
connection_setup->proto_object.id = id;
|
||||
connection_setup->proto_object.id = ei_get_new_id(ei);
|
||||
assert(connection_setup->proto_object.id == 0); /* Special object */
|
||||
connection_setup->proto_object.implementation = connection_setup;
|
||||
connection_setup->proto_object.interface = &ei_connection_setup_proto_interface;
|
||||
connection_setup->proto_object.version = version;
|
||||
|
|
|
|||
|
|
@ -52,4 +52,4 @@ OBJECT_DECLARE_REF(ei_connection_setup);
|
|||
OBJECT_DECLARE_UNREF(ei_connection_setup);
|
||||
|
||||
struct ei_connection_setup *
|
||||
ei_connection_setup_new(struct ei *ei, uint32_t id, uint32_t version);
|
||||
ei_connection_setup_new(struct ei *ei, uint32_t version);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,18 @@ static
|
|||
OBJECT_IMPLEMENT_PARENT(ei_connection, ei);
|
||||
OBJECT_IMPLEMENT_GETTER_AS_REF(ei_connection, proto_object, const struct brei_object*);
|
||||
|
||||
uint32_t
|
||||
ei_connection_get_version(struct ei_connection *connection)
|
||||
{
|
||||
return connection->proto_object.version;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ei_connection_get_id(struct ei_connection *connection)
|
||||
{
|
||||
return connection->proto_object.id;
|
||||
}
|
||||
|
||||
struct ei*
|
||||
ei_connection_get_context(struct ei_connection *connection)
|
||||
{
|
||||
|
|
@ -74,17 +86,14 @@ ei_connection_get_interface(struct ei_connection *connection) {
|
|||
}
|
||||
|
||||
struct ei_connection *
|
||||
ei_connection_new(struct ei *ei)
|
||||
ei_connection_new(struct ei *ei, uint32_t id, uint32_t version)
|
||||
{
|
||||
struct ei_connection *connection = ei_connection_create(&ei->object);
|
||||
|
||||
connection->proto_object.id = ei_get_new_id(ei);
|
||||
/* This is a special object and must have id 0 */
|
||||
assert(connection->proto_object.id == 0);
|
||||
|
||||
connection->proto_object.id = id;
|
||||
connection->proto_object.implementation = connection;
|
||||
connection->proto_object.interface = &ei_connection_proto_interface;
|
||||
connection->proto_object.version = VERSION_V(1);
|
||||
connection->proto_object.version = version;
|
||||
ei_register_object(ei, &connection->proto_object);
|
||||
|
||||
list_init(&connection->pending_callbacks);
|
||||
|
|
|
|||
|
|
@ -41,13 +41,15 @@ struct ei_connection {
|
|||
};
|
||||
|
||||
OBJECT_DECLARE_GETTER(ei_connection, context, struct ei*);
|
||||
OBJECT_DECLARE_GETTER(ei_connection, version, uint32_t);
|
||||
OBJECT_DECLARE_GETTER(ei_connection, id, uint32_t);
|
||||
OBJECT_DECLARE_GETTER(ei_connection, proto_object, const struct brei_object*);
|
||||
OBJECT_DECLARE_GETTER(ei_connection, interface, const struct ei_connection_interface *);
|
||||
OBJECT_DECLARE_REF(ei_connection);
|
||||
OBJECT_DECLARE_UNREF(ei_connection);
|
||||
|
||||
struct ei_connection *
|
||||
ei_connection_new(struct ei *ei);
|
||||
ei_connection_new(struct ei *ei, uint32_t id, uint32_t version);
|
||||
|
||||
/**
|
||||
* Called when the ei_callback.done event is received after
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ struct ei {
|
|||
struct object object;
|
||||
|
||||
struct ei_connection *connection;
|
||||
struct ei_connection_setup *connection_setup;
|
||||
struct list proto_objects; /* brei_object list */
|
||||
uint32_t next_object_id;
|
||||
|
||||
|
|
@ -117,6 +118,12 @@ ei_send_message(struct ei *ei, const struct brei_object *object,
|
|||
void
|
||||
ei_add_seat(struct ei_seat *seat);
|
||||
|
||||
void
|
||||
ei_connected(struct ei *ei);
|
||||
|
||||
void
|
||||
ei_queue_connect_event(struct ei *ei);
|
||||
|
||||
void
|
||||
ei_queue_device_removed_event(struct ei_device *device);
|
||||
|
||||
|
|
|
|||
96
src/libei.c
96
src/libei.c
|
|
@ -62,6 +62,7 @@ ei_destroy(struct ei *ei)
|
|||
if (ei->backend_interface.destroy)
|
||||
ei->backend_interface.destroy(ei, ei->backend);
|
||||
ei->backend = NULL;
|
||||
ei_connection_setup_unref(ei->connection_setup);
|
||||
ei_connection_unref(ei->connection);
|
||||
sink_unref(ei->sink);
|
||||
free(ei->name);
|
||||
|
|
@ -98,7 +99,7 @@ ei_create_context(bool is_sender, void *user_data)
|
|||
list_init(&ei->seats);
|
||||
list_init(&ei->proto_objects);
|
||||
|
||||
ei->connection = ei_connection_new(ei);
|
||||
ei->connection_setup = ei_connection_setup_new(ei, VERSION_V(1));
|
||||
ei->next_object_id = 1;
|
||||
|
||||
ei_log_set_handler(ei, NULL);
|
||||
|
|
@ -259,8 +260,8 @@ insert_event(struct ei *ei, struct ei_event *event)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
queue_connect_event(struct ei *ei)
|
||||
void
|
||||
ei_queue_connect_event(struct ei *ei)
|
||||
{
|
||||
struct ei_event *e = ei_event_new(ei);
|
||||
e->type = EI_EVENT_CONNECT;
|
||||
|
|
@ -580,9 +581,13 @@ static int
|
|||
handle_msg_seat(struct ei_connection *connection, uint32_t seat_id, uint32_t version)
|
||||
{
|
||||
struct ei *ei = ei_connection_get_context(connection);
|
||||
|
||||
struct ei_seat *seat = ei_seat_new(ei, seat_id, version);
|
||||
|
||||
/* We might get the seat event before our callback finished, so make sure
|
||||
* we know we're connected
|
||||
*/
|
||||
ei_connected(ei);
|
||||
|
||||
/* seats list owns the ref */
|
||||
list_append(&ei->seats, &seat->link);
|
||||
|
||||
|
|
@ -629,6 +634,15 @@ ei_peek_event(struct ei *ei)
|
|||
return ei_event_ref(e);
|
||||
}
|
||||
|
||||
void
|
||||
ei_connected(struct ei *ei)
|
||||
{
|
||||
if (ei->state == EI_STATE_CONNECTING) {
|
||||
ei->state = EI_STATE_CONNECTED;
|
||||
ei_queue_connect_event(ei);
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_msg_disconnected(struct ei_connection *connection, uint32_t reason, const char *explanation)
|
||||
{
|
||||
struct ei *ei = ei_connection_get_context(connection);
|
||||
|
|
@ -648,80 +662,15 @@ static int handle_msg_disconnected(struct ei_connection *connection, uint32_t re
|
|||
} \
|
||||
} while(0)
|
||||
|
||||
static void
|
||||
connected(struct ei_connection *connection, void *user_data)
|
||||
{
|
||||
struct ei *ei = ei_connection_get_context(connection);
|
||||
|
||||
/* FIXME: the connected event *should* mean that the server
|
||||
* has accepted us but we don't currently have any event
|
||||
* for this to hook onto. So let's just assume "connected" means
|
||||
* the server has seen our messages.
|
||||
*/
|
||||
ei->state = EI_STATE_CONNECTED;
|
||||
queue_connect_event(ei);
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_connection_setup(struct ei_connection *connection, uint32_t new_id, uint32_t version)
|
||||
{
|
||||
struct ei *ei = ei_connection_get_context(connection);
|
||||
|
||||
struct ei_connection_setup *setup = ei_connection_setup_new(ei, new_id, version);
|
||||
if (version >= EI_CONNECTION_SETUP_REQUEST_TYPE_SINCE_VERSION)
|
||||
ei_connection_setup_request_type(setup, ei->is_sender ? EI_CONNECTION_SETUP_CONTEXT_TYPE_SENDER : EI_CONNECTION_SETUP_CONTEXT_TYPE_RECEIVER);
|
||||
if (version >= EI_CONNECTION_SETUP_REQUEST_NAME_SINCE_VERSION)
|
||||
ei_connection_setup_request_name(setup, ei->name);
|
||||
if (version >= EI_CONNECTION_SETUP_REQUEST_INTERFACE_SINCE_VERSION) {
|
||||
ei_connection_setup_request_interface(setup, "ei_connection", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_callback", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_seat", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_device", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_pointer", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_keyboard", VERSION_V(1));
|
||||
ei_connection_setup_request_interface(setup, "ei_touchscreen", VERSION_V(1));
|
||||
}
|
||||
ei_connection_setup_request_done(setup);
|
||||
ei_connection_setup_unref(setup);
|
||||
|
||||
ei->state = EI_STATE_CONNECTING;
|
||||
|
||||
ei_connection_sync(ei->connection, connected, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ei_connection_interface intf_state_backend = {
|
||||
.connection_setup = handle_msg_connection_setup,
|
||||
/* Everything triggers -EPROTO */
|
||||
};
|
||||
|
||||
static const struct ei_connection_interface intf_state_connecting = {
|
||||
.connection_setup = handle_msg_connection_setup,
|
||||
.disconnected = handle_msg_disconnected,
|
||||
};
|
||||
|
||||
static const struct ei_connection_interface intf_state_connected = {
|
||||
.connection_setup = NULL, /* EPROTO */
|
||||
static const struct ei_connection_interface interface = {
|
||||
.disconnected = handle_msg_disconnected,
|
||||
.seat = handle_msg_seat,
|
||||
};
|
||||
|
||||
static const struct ei_connection_interface *interfaces[] = {
|
||||
[EI_STATE_NEW] = NULL,
|
||||
[EI_STATE_BACKEND] = &intf_state_backend,
|
||||
[EI_STATE_CONNECTING] = &intf_state_connecting,
|
||||
[EI_STATE_CONNECTED] = &intf_state_connected,
|
||||
[EI_STATE_DISCONNECTING] = NULL,
|
||||
[EI_STATE_DISCONNECTED] = NULL,
|
||||
};
|
||||
|
||||
|
||||
const struct ei_connection_interface *
|
||||
ei_get_interface(struct ei *ei)
|
||||
{
|
||||
assert(ei->state < ARRAY_LENGTH(interfaces));
|
||||
return interfaces[ei->state];
|
||||
return &interface;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -803,8 +752,9 @@ ei_set_socket(struct ei *ei, int fd)
|
|||
ei->source = source_ref(source);
|
||||
ei->state = EI_STATE_BACKEND;
|
||||
|
||||
/* The server SHOULD have already sent the connection setup, let's
|
||||
* process that. If not ready, it'll happen in the next dispatch.
|
||||
/* The server SHOULD have already sent the connection setup
|
||||
* version, let's process that. If not ready, it'll happen
|
||||
* in the next dispatch.
|
||||
*
|
||||
* FIXME: this will block if O_NONBLOCK is missing
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -163,14 +163,6 @@ eis_client_send_message(struct eis_client *client, const struct brei_object *obj
|
|||
return rc < 0 ? rc : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_connection_setup(struct eis_client *client, struct eis_connection_setup *setup)
|
||||
{
|
||||
return eis_connection_event_connection_setup(client->connection,
|
||||
eis_connection_setup_get_id(setup),
|
||||
eis_connection_setup_get_version(setup));
|
||||
}
|
||||
|
||||
static int
|
||||
client_send_disconnect(struct eis_client *client, const char *reason)
|
||||
{
|
||||
|
|
@ -382,9 +374,6 @@ eis_client_new(struct eis *eis, int fd)
|
|||
.ei_keyboard = VERSION_V(1),
|
||||
.ei_touchscreen = VERSION_V(1),
|
||||
};
|
||||
|
||||
client->connection = eis_connection_new(client);
|
||||
|
||||
struct source *s = source_new(fd, client_dispatch, client);
|
||||
int rc = sink_add_source(eis->sink, s);
|
||||
|
||||
|
|
@ -405,11 +394,7 @@ eis_client_new(struct eis *eis, int fd)
|
|||
|
||||
source_unref(s);
|
||||
|
||||
/* Send the event for the connection setup interface */
|
||||
struct eis_connection_setup *setup = eis_connection_setup_new(client, eis_client_get_new_id(client),
|
||||
&client->interface_versions);
|
||||
client_send_connection_setup(client, setup);
|
||||
client->setup = setup;
|
||||
client->setup = eis_connection_setup_new(client, &client->interface_versions);
|
||||
|
||||
return client;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@ client_msg_done(struct eis_connection_setup *setup)
|
|||
rc = 0;
|
||||
}
|
||||
|
||||
|
||||
client->connection = eis_connection_new(client);
|
||||
eis_connection_setup_event_connection(setup, eis_connection_get_id(client->connection),
|
||||
eis_connection_get_version(client->connection));
|
||||
eis_connection_setup_unref(setup);
|
||||
|
||||
return rc;
|
||||
|
|
@ -175,21 +179,23 @@ eis_connection_setup_get_interface(struct eis_connection_setup *setup) {
|
|||
}
|
||||
|
||||
struct eis_connection_setup *
|
||||
eis_connection_setup_new(struct eis_client *client, uint32_t new_id,
|
||||
eis_connection_setup_new(struct eis_client *client,
|
||||
const struct eis_client_interface_versions *versions)
|
||||
{
|
||||
struct eis_connection_setup *setup = eis_connection_setup_create(&client->object);
|
||||
|
||||
setup->proto_object.id = new_id;
|
||||
setup->proto_object.id = 0;
|
||||
setup->proto_object.implementation = setup;
|
||||
setup->proto_object.interface = &eis_connection_setup_proto_interface;
|
||||
setup->proto_object.version = versions->ei_connection_setup;
|
||||
/* This object is always v1 until the client tells us otherwise */
|
||||
setup->proto_object.version = VERSION_V(1);
|
||||
list_init(&setup->proto_object.link);
|
||||
|
||||
setup->version = VERSION_V(1); /* our ei-connection-setup version */
|
||||
setup->server_versions = *versions;
|
||||
|
||||
eis_client_register_object(client, &setup->proto_object);
|
||||
eis_connection_setup_event_version(setup, versions->ei_connection_setup);
|
||||
|
||||
return setup; /* ref owned by caller */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,5 +55,5 @@ OBJECT_DECLARE_REF(eis_connection_setup);
|
|||
OBJECT_DECLARE_UNREF(eis_connection_setup);
|
||||
|
||||
struct eis_connection_setup *
|
||||
eis_connection_setup_new(struct eis_client *client, uint32_t new_id,
|
||||
eis_connection_setup_new(struct eis_client *client,
|
||||
const struct eis_client_interface_versions *versions);
|
||||
|
|
|
|||
|
|
@ -53,6 +53,18 @@ OBJECT_IMPLEMENT_CREATE(eis_connection);
|
|||
static
|
||||
OBJECT_IMPLEMENT_PARENT(eis_connection, eis_client);
|
||||
|
||||
uint32_t
|
||||
eis_connection_get_version(struct eis_connection *connection)
|
||||
{
|
||||
return connection->proto_object.version;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
eis_connection_get_id(struct eis_connection *connection)
|
||||
{
|
||||
return connection->proto_object.id;
|
||||
}
|
||||
|
||||
struct eis_client*
|
||||
eis_connection_get_client(struct eis_connection *connection)
|
||||
{
|
||||
|
|
@ -80,7 +92,7 @@ eis_connection_new(struct eis_client *client)
|
|||
connection->proto_object.id = eis_client_get_new_id(client);
|
||||
connection->proto_object.implementation = connection;
|
||||
connection->proto_object.interface = &eis_connection_proto_interface;
|
||||
connection->proto_object.version = VERSION_V(1);
|
||||
connection->proto_object.version = client->interface_versions.ei_connection;
|
||||
eis_client_register_object(client, &connection->proto_object);
|
||||
|
||||
return connection; /* ref owned by caller */
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ struct eis_connection {
|
|||
};
|
||||
|
||||
OBJECT_DECLARE_GETTER(eis_connection, context, struct eis *);
|
||||
OBJECT_DECLARE_GETTER(eis_connection, id, uint32_t);
|
||||
OBJECT_DECLARE_GETTER(eis_connection, version, uint32_t);
|
||||
OBJECT_DECLARE_GETTER(eis_connection, client, struct eis_client *);
|
||||
OBJECT_DECLARE_GETTER(eis_connection, proto_object, const struct brei_object *);
|
||||
OBJECT_DECLARE_GETTER(eis_connection, interface, const struct eis_connection_interface *);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue